用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存储库以获取更多技术详细信息。

什么是区块链?