CryptocurrencyTechBitcoin

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

2018-02-04  本文已影响16人  qishuai

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

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

这让理解区块链变成了非常困难的事情,但区块链本质上没有这么复杂。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');
    }
};

节点通信

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

节点管理

通过搭建一个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团队 戚帅翻译,转载无需授权。

上一篇下一篇

猜你喜欢

热点阅读