区块链的基础概念很简单:一个分布式数据库,存储一个不断加长的 list,list 中包含着许多有序的记录。然而,在通常情况下,当我们谈到区块链的时候也会谈起使用区块链来解决的问题,这两者很容易混淆。像流行的比特币和以太坊这样基于区块链的项目就是这样。“区块链”这个术语通常和像交易、智能合约、加密货币这样的概念紧紧联系在一起。
这就令理解区块链变得不必要得复杂起来,特别是当你想理解源码的时候。下面我将通过 200 行 JS 实现的超级简单的区块链来帮助大家理解它,我给这段代码起名为 NaiveChain。
块结构
第一个逻辑步骤是决定块结构。为了保证事情尽可能的简单,我们只选择最必要的部分:index(下标)、timestamp(时间戳)、data(数据)、hash(哈希值)和 previous hash(前置哈希值)。
The basic concept of the block chain is simple: a distributed database containing a growing list of serials contains many orderly records. However, when we talk about the block chain, the question of using the block chain is often easily confused. This is the case with popular bitcoins and block chain-based projects such as Ether. The term “block chain” is usually closely linked to concepts such as transactions, smart contracts, encrypted currencies.
>, which makes it unnecessary to complicate the understanding of the block chain, especially when you want to understand the source code. Next, I will use the 200-line JS super-simple block chain to help people understand it.
这个块中必须能找到前一个块的哈希值,以此来保证整条链的完整性。
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();
}
}
块哈希
为了保存完整的数据,必须哈希区块。SHA-256会对块的内容进行加密,记录这个值应该和“挖矿”毫无关系,因为这里不需要解决工作量证明的问题。
var calculateHash=(index, previousHash, timestamp, data)=> {
return CryptoJS.SHA256(index + previousHash + timestamp + data).toString();
};
In this block, the integrity of the entire chain must be assured by the availability of the previous section.
this=timestamp, data, hash) {br/>this=previousHash.index=index;
this.previousHash=previousHash.tostring();
this.timestamp=timeamp;
this.data=data;
this=hash.thash.string;
> > > ; SHA-256 should be encrypted; the value should be recorded; br/ br/ br/ strr/ hrrr/
块的生成
要生成一个块,必须知道前一个块的哈希值,然后创造其余所需的内容(=index, hash, data and timestamp)。块的data部分是由终端用户所提供的。
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数组被用于存储区块链。区块链的第一个块通常被称为“起源块”,是硬编码的。
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号块时),会选择有最大数目的块的链。
generation of block(s) to generate a block(s) that must know the original block(s) and then create the remaining content (=index, hash, data and timestamp).
(br/>vargenerateNextBlock=(blockData)=>
previousBlock=getLestBlockBlock();
nextIndex=paviotBrebrock_brain;
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');
}
};
与其他结点的通信
结点的本质是和其他结点共享和同步区块链,下面的规则能保证网络同步。
当一个结点生成一个新块时,它会在网络上散布这个块。
当一个节点连接新peer时,它会查询最新的block。
当一个结点遇到一个块,其index大于当前所有块的index时,它会添加这个块到它当前的链中,或者到整个区块链中查询这个块。
{br/>consolegen=(newBlocks)= > {br/>if (isValidchain(newBlocks) & & newBlocks.lenth & gt; blockchain.lenth) {br/>consolelog(#39; Received blockchain is valid. Replacing crerent blockchain with received blockchain#39;
blocks & gt;
responteestMsg() > ;
如图为当节点遵循前文所述协议时会发生的一些典型通信场景
我没有采用自动发现peer的工具。peers的位置(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));
};
用户可以用下面的方法和结点互动:
列出所有的块
用用户提供的内容创建一个新的块
列出或者新增peers
下面这个Curl的例子就是最直接的控制结点的方法:
(b) >(b) >(b) >(b) >(b) >(b) >(b)(b)(b) nodes control (b) (b) >(b) >(br) >(b) > (b)TP server(b)
(btt) > );
(bt) > ;
注册有任何问题请添加 微信:MVIP619 拉你进入群
打开微信扫一扫
添加客服
进入交流群
发表评论