美文网首页CryptocurrencyTechBitcoin
[译]200行代码就能写出区块链

[译]200行代码就能写出区块链

作者: qishuai | 来源:发表于2018-02-04 13:42 被阅读16次

    从本质上看,区块链远没有你想象的那么难!

    区块链的基本概念是非常简单的:一个维护不断增长的有序数据的分布式数据库。然而当我们讨论使用区块链解决具体问题的时候,很容易把他们混为一体,比如当前非常有名的比特币和以太坊,它们往往和交易、智能合约、加密货币等概念绑在一起。

    这让理解区块链变成了非常困难的事情,但区块链本质上没有这么复杂。Lauri Hartikka使用200行js代码实现一个简单的区块链,称为NaiveChain

    区块结构

    第一个逻辑步骤就是定义区块结构。为了让这个区块链尽可能的简单,在这个区块链中只包含一些必需元素,包括:区块索引、时间戳、区块数据、当前区块Hash、上一个区块的Hash block
    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和挖矿没有关系,因为这里没有工作量证明的问题需要解决。

    var calculateHash = (index, previousHash, timestamp, data) => {
        return CryptoJS.SHA256(index + previousHash + timestamp + data).toString();
    };
    

    生成区块

    为了打包一个区块,除了知道上一个区块的hash值以外,还需要得到当前区块的索引、hash、数据,以及当前的时间戳。区块数据有使用者提供。

    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);
    };
    

    存储区块

    在这里使用js的数组将区块存储在内存中。第一个区块通过硬编码完成,通常被称为创始区块。

    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的区块),那么当前节点会选择最长链。 longest chain
    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');
        }
    };
    

    节点通信

    一个区块的必要模块就是同其他节点分享和同步区块链。为了保持区块链在网络中的同步,节点需要遵守以下规则:

    • 当一个节点完成打包一个区块之后,要广播到网络

    • 当一个节点连接到另一个节点之后,需要查询最新区块

    • 当一个节点接收到一个大于当前区块索引的区块之后,需要将这个区块添加到当前区块之后,或者查询整个区块链


      sync

      这里没有节点发现的功能,需要手动添加节点地址

    节点管理

    通过搭建一个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服务器:一个用户管理当前节点,一个用于区块之间的p2p通信(Websocket HTTP server)

    Architecture

    总结

    这个区块链(NaiveChain)是为了演示和学习区块链。它不能在实践中的使用,因为他没有PoS或PoW挖矿算法,然而它实现了区块链的基本特性。你可以通过 Github 仓库获取更多的技术细节。

    你可以通过a tutorial for building a cryptocurrency深入理解区块链,在那里你会获得关于工作量证明、交易、钱包等相关知识。

    引用

    原文链接: https://medium.com/@lhartikk/a-blockchain-in-200-lines-of-code-963cc1cc0e54


    本文由 Copernicus团队 戚帅翻译,转载无需授权。

    相关文章

      网友评论

        本文标题:[译]200行代码就能写出区块链

        本文链接:https://www.haomeiwen.com/subject/siemzxtx.html