区块链的基本概念非常简单:一个存储不断增加的有序记录的分布式数据库。然而,当我们谈论区块链时,我们很容易将其与区块链要解决的问题混淆,比如误解为流行的,基于区块链的,像比特币和以太坊一样的项目。术语“区块链”通常与交易,智能合约或加密货币等概念紧密相关。
这必然使得理解区块链变成一项更艰巨的任务,特别是清楚地理解源代码。接下来我将介绍一个我用200行Javascript代码完成的超级简单的区块链:NaiveChain。
区块结构
第一个步骤是确定区块的结构。为了让事情尽可能简单,区块结构只包含最必要的部分:索引,时间戳,数据,散列值(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(); } }
生成区块散列值
区块需要散列值以保持数据的完整性。可以使用SHA-256算法生成这个值。应该指出,这个散列值与“ 挖掘 ” 无关,因为不需要去解决工作证明问题。
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数组在内存中存储区块链。区块链的第一个区块总是一个所谓的“创世纪区块”,内容是固定的。
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'); } };
与其他节点通信
区块链节点的一个重要任务是与其他节点共享和同步区块链。以下规则用于保持网络同步。
- 当一个节点产生一个新块时,要将这个区块广播到网络中。
- 当一个节点连接到一个新的对等节点时,要查询最新的区块。
- 当一个节点遇到一个索引大于当前已知块的块时,将该块添加到当前链中,或者查询完整区块链。
不自动发现对等的节点,必须手动添加对等节点的位置(=网址)。
控制节点
用户必须能够以某种方式控制节点。可以通过设置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:
#从节点获取所有区块 curl http://localhost:3001/blocks
架构
应该注意的是,每个节点实际上公开了两个Web服务器:一个用于控制节点(HTTP服务器),一个用于节点之间的对等通信(Websocket HTTP服务器)
总结
NaiveChain是为演示和学习目的而创建的。因为它不具有“ 挖掘 ”算法(工作证明(PoW)的股权证明(PoS)),它不可以在公共网络中使用。尽管如此,它仍然实现了区块链的基本功能。
您可以从Github存储库获取更多技术细节。
如果您想了解更多区块链的知识,我建议您查看Naivecoin:构建加密货币的教程。在这个教程中,我们将详细讨论如采矿(工作证明),交易和钱包这样的概念。
原文发布时间为:2018-03-15
本文作者:Mr.Crypto
本文来源:腾讯云 云+社区,如需转载请联系原作者。