什么是区块链blockchain


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


从CRUD编程切换到事件溯源和区块链编程

更多区块链专题