用Javasctipt代码简单模拟解释区块链概念
本文试图用简单200行代码来解析区块链的基本原理。
区块链基本概念很简单:它其实是一个分布式数据库,维护一个不断增长的有序的记录列表。“区块链”术语通常与诸如交易,智能合约或加密货币等概念密切相关。涉及这么多概念使得理解区块链变成一个艰巨的任务。这里将通过一个称为NaiveChain库包使用200行的Javascript实现超简单的blockchain。
块结构
第一个逻辑步骤是决定块结构。为了使事情尽可能简单,我们仅包含最必要的:index,timestamp,data,hash和previous hash。
必须在块中找到前一个块的Hash,以保持链的完整性,代码如下:
class Block {
constructor(index, previousHash, timestamp, data, hash) {
this.index = index;
this.previousHash = previousHash.toString();
this.timestamp = timestamp;
this.data = data;
this.hash = hash.toString();
}
}
块Hash散列
块需要实行Hash以保持数据的完整性。算法使用SHA-256。应该注意,这个Hash与“ 挖掘 ” 无关,因为不需要解决Proof Of Work工作证明问题。
var calculateHash = (index, previousHash, timestamp, data) => {
return CryptoJS.SHA256(index + previousHash + timestamp + data).toString();
};
生成块
为了生成一个块,我们必须知道前一个块的哈希,并创建所需内容的其余部分(=索引,散列,数据和时间戳),块数据是由最终用户提供的。
var generateNextBlock = (blockData) => {
var previousBlock = getLatestBlock();
var nextIndex = previousBlock.index + 1;
var nextTimestamp = new Date().getTime() / 1000;
var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData);
return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash);
};
存储块
内存中的Javascript数组用于存储区块链。区块链的第一块总是一个所谓的“基因块genesis-block”,它是硬编码的。
var getGenesisBlock = () =>{
return new Block(0,"0",1465154705,"my genesis block!!",
"816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7");
};
var blockchain=[getGenesisBlock()];
验证块的完整性
在任何指定时间,我们必须能够验证块或块链在完整性方面是否有效。特别是当我们从其他节点接收新块,并必须决定是否接受他们时。
var isValidNewBlock = (newBlock, previousBlock) =>
{
if (previousBlock.index + 1 !== newBlock.index) {
console.log('invalid index');
return false;
} else if (previousBlock.hash !== newBlock.previousHash) {
console.log('invalid previoushash');
return false;
} else if (calculateHashForBlock(newBlock) !== newBlock.hash) {
console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash);
return false;
}
return true;
};
选择最长的链
在指定时间链中应该总是只有一个显式块。在冲突的情况下(例如,两个节点都生成块号72),我们选择具有最长块数的链。
var replaceChain = (newBlocks) =>
{
if (isValidChain(newBlocks) && newBlocks.length > blockchain.length) {
console.log('Received blockchain is valid. Replacing current blockchain with received blockchain');
blockchain = newBlocks;
broadcast(responseLatestMsg());
} else {
console.log('Received blockchain invalid');
}
};
与其他节点通信
节点的一个重要部分是与其他节点共享和同步区块链。以下规则用于保持网络同步。
- 当节点生成新块时,它将其广播到网络
- 当节点连接到新的对等体时,它查询最新的块
- 当节点遇到具有大于当前已知块的索引的块时,它将块添加到其当前链或查询整个区块链。
上图是当节点服从所描述的协议时遵循的一些典型的通信场景
不使用自动对等体发现。对等体的位置(= URL)就必须手动添加。
控制节点
用户必须能够以某种方式控制节点。这是通过设置HTTP服务器来完成的。
var initHttpServer = () =
>
{
var app = express();
app.use(bodyParser.json());
app.get('/blocks', (req, res) = > res.send(JSON.stringify(blockchain))
)
;
app.post('/mineBlock', (req, res) = > {
var newBlock = generateNextBlock(req.body.data);
addBlock(newBlock);
broadcast(responseLatestMsg());
console.log('block added: ' + JSON.stringify(newBlock));
res.send();
});
app.get('/peers', (req, res) = > {
res.send(sockets.map(s = > s._socket.remoteAddress + ':' + s._socket.remotePort)
);
});
app.post('/addPeer', (req, res) = > {
connectToPeers([req.body.peer]);
res.send();
});
app.listen(http_port, () = > console.log('Listening http on port: ' + http_port)
);
}
;
如代码所示,用户能够以以下方式与节点交互:
- 列出所有块
- 创建由用户提供内容的新块
- 列出或添加对等体
控制节点的最直接的方法是例如使用Curl:
#get所有节点的块
curl http://localhost:3001/blocks
架构
应该注意,一个节点实际上暴露了两个Web服务器:一个用于用户控制节点(HTTP服务器),一个用于节点之间的对等通信(Websocket HTTP服务器)
NaiveChain的主要组件
结论
NaiveChain是为了演示和学习区块链而创建的。由于它没有“ 挖掘 ”算法(PoS的PoW),它不能在公共网络中使用。它仍然实现了功能区块链的基本特征。
您可以检查Github存储库以获取更多技术详细信息。