Hi 游客

更多精彩,请登录!

比特池塘 区块链技术 正文

JavaScript开发区块链只需200行代码

ranbluer
148 0 0
JavaScript开发一个简单的区块链只需200行代码。通过JavaScript的开发实现过程,你将理解区块链是什么:区块链就是一个分布式数据库,存储结构是一个不断增长的链表,链表中包含着许多有序的记录。- @( X. }" ~! I7 [3 e$ n& a
然而,在通常情况下,当我们谈到区块链的时候也会谈起使用区块链来解决的问题,这两者很容易混淆。/ ?% f4 k4 a$ D' ~
像流行的比特币和以太坊这样基于区块链的项目就是这样。“区块链”这个术语通常和像交易、智能合约、加密货币这样的概念紧紧联系在一起。
4 N" D% [# D! t7 O2 ?这就令理解区块链变得不必要得复杂起来,特别是当你想理解源码的时候。下面我将通过 200 行 JS 实现的超级简单的区块链来帮助大家理解它,我给这段代码起名为 NaiveChain。你可以在Github(https://github.com/lhartikk/naivechain)查看更多的技术细节。% u1 e8 H7 B2 M) V
块结构
# m& ~# D  u4 t/ q# H& a第一个逻辑步骤是决定块结构。为了保证事情尽可能的简单,我们只选择最必要的部分:index(下标)、timestamp(时间戳)、data(数据)、hash(哈希值)和 previous hash(前置哈希值)。
1 A8 L# w6 b3 d( q3 p/ h; s/ a2 h* x8 J* M9 _
这个块中必须能找到前一个块的哈希值,以此来保证整条链的完整性,JavaScript代码如下:
9 q" c; `' p1 Y+ m; g! Tclass Block {
/ `' s. y* Z: ]( H    constructor(index, previousHash, timestamp, data, hash) {
. a# c) C" `, {7 g: |: m% B        this.index = index;( K# y1 Q6 e4 p& r0 l) `" Y" o
        this.previousHash = previousHash.toString();
' ?7 ~  T9 z8 R6 j* O8 \" L3 j        this.timestamp = timestamp;6 S& f* q" J" }8 ]( f
        this.data = data;9 }0 d, V% z4 l& F. G
        this.hash = hash.toString();
( M5 A  ]+ J* ]4 F/ ^3 Z# f    }
/ {; }9 X7 M1 Z4 c6 q}
+ u, I: v* Q# k& S3 }5 e" w块哈希. G9 U, r! {; r0 D7 B
为了保存完整的数据,必须哈希区块。SHA-256会对块的内容进行加密,记录这个值应该和“挖矿”毫无关系,因为这里不需要解决工作量证明的问题。JavaScript代码如下:  n6 P* c; i+ I; ^; D1 ~
var calculateHash = (index, previousHash, timestamp, data) => {
% v9 [5 c9 C$ X: ]    return CryptoJS.SHA256(index + previousHash + timestamp + data).toString();
" }8 l2 c% W" |7 v};" v! O4 `  R5 D1 e2 r( Z
块的生成, ~6 Q4 a( Q6 g
要生成一个块,必须知道前一个块的哈希值,然后创造其余所需的内容(= index, hash, data and timestamp)。
9 M3 r, [+ @" y9 P7 E; y9 P块的data部分是由终端用户所提供的。JavaScript代码如下:( k: h, p* ]/ u' i, ~8 K7 A6 p
var generateNextBlock = (blockData) => {5 W- B2 I) ^$ U8 Q' H
    var previousBlock = getLatestBlock();. P( Z% Q' }5 T. l
    var nextIndex = previousBlock.index + 1;
8 M3 b% ?( X# h. U    var nextTimestamp = new Date().getTime() / 1000;
: L6 S$ o# j1 V* R1 J0 V    var nextHash = calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData);7 i2 a9 l8 E3 _7 }0 Z! P
    return new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash);
4 n$ ~! I! I/ ]8 N5 V};
8 n, Q5 l$ ~- s/ p块的存储* D' }* P* o! _8 e. ]
内存中的Javascript数组被用于存储区块链。区块链的第一个块通常被称为“起源块”,是硬编码的。JavaScript代码如下:+ q3 U  e( A( I- C  g8 Q7 }
var getGenesisBlock = () => {: H) C. H- W; u& I5 j" Q! r' [
    return new Block(0, "0", 1465154705, "my genesis block!!", "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7");  T* ~8 f2 c! P# O, T
};
2 z( t' a9 M/ s
! W; ~5 y  m9 _" Z* j- Ovar blockchain = [getGenesisBlock()];: g* U0 V. ?$ g9 Q: m
确认块的完整性
6 @1 R; t* x8 ?* P: l在任何时候都必须能确认一个区块或者一整条链的区块是否完整。在我们从其他节点接收到新的区块,并需要决定接受或拒绝它们时,这一点尤为重要。JavaScript代码如下:5 R3 |# N4 N2 i( c2 {9 s' F. v& v8 b  C
var isValidNewBlock = (newBlock, previousBlock) => {/ W( t7 I0 T$ A4 A
    if (previousBlock.index + 1 !== newBlock.index) {- t2 p  R$ b% v" f# c" M
        console.log('invalid index');. F; Y2 z  C2 h" ~) u; u
        return false;+ O! s* a9 K" f; A8 D
    } else if (previousBlock.hash !== newBlock.previousHash) {& M# A1 J7 H" F* O3 Q2 {
        console.log('invalid previoushash');
" w/ O& E3 Q( v+ y0 K        return false;' G2 M4 l+ D/ ?$ o, H! N; a6 V. j
    } else if (calculateHashForBlock(newBlock) !== newBlock.hash) {# h8 L3 _# c" r# x! T  a
        console.log('invalid hash: ' + calculateHashForBlock(newBlock) + ' ' + newBlock.hash);
% ?0 s* ]9 t" P# o/ c1 S4 F" r5 H3 ^        return false;
7 L- w) o9 [/ {; N7 b5 c    }
/ l+ e! y1 k" o' A6 L. |% ]    return true;
5 Q8 c% Q6 ]8 E2 X};# a# y# ^$ J' d
选择最长的区块链
8 Q% B3 p1 D& `! R% c5 ^5 @" H6 V- \
5 i6 M( J6 ]5 }. N* E$ t0 r, ]3 }任何时候在链中都应该只有一组明确的块。万一冲突了(例如:两个结点都生成了72号块时),会选择有最大数目的块的链。JavaScript代码如下:8 `% ?3 s' h; A+ J! @
var replaceChain = (newBlocks) => {- O# k( a( {0 E0 p3 A( P% f: U
    if (isValidChain(newBlocks) && newBlocks.length > blockchain.length) {
; a! A3 x  h4 I; E        console.log('Received blockchain is valid. Replacing current blockchain with received blockchain');0 a  u5 [( y" P+ `& q8 u
        blockchain = newBlocks;" G1 Z0 T9 i4 O0 X6 {
        broadcast(responseLatestMsg());/ J% c1 t- w' _& H% U
    } else {
) h/ d/ H3 Z& v' Q# z5 I8 Q7 ~+ r        console.log('Received blockchain invalid');
' }6 c& q  Y1 B: a: o# c    }1 ~7 J+ F- ~: h9 l% R5 z1 P0 f
};
$ ]: C9 g$ E; k3 W( W与其他结点的通信! \- O  Z' {1 u" i% O9 o; I
结点的本质是和其他结点共享和同步区块链,下面的规则能保证网络同步。4 A/ X: u  o0 h
: r& `! u/ N. r1 K: x" w$ E
当一个结点生成一个新块时,它会在网络上散布这个块。
8 z4 i9 X2 t1 h# l* W, s9 p  w2 b9 s当一个节点连接新peer时,它会查询最新的block。
5 l4 D0 ~0 H' m当一个结点遇到一个块,其index大于当前所有块的index时,它会添加这个块到它当前的链中,  或者到整个区块链中查询这个块。8 |$ o  \' j: D: l/ ^: ?' v
我没有采用自动发现peer的工具。peers的位置(URL)必须是手动添加的。; b+ X) Y" U& k, j
节点控制
- N& B/ m; F0 T0 L1 m在某种程度上用户必须能够控制节点。这一点通过搭建一个HTTP服务器可以实现。JavaScript代码如下:8 w' j% b& r. Q) A3 w7 R& r
var initHttpServer = () => {
( x9 v' Q+ |; y: A( [. J    var app = express();
4 K4 m% s& r4 M    app.use(bodyParser.json());
% U7 M: S1 G9 P8 o; y4 N3 `    app.get('/blocks', (req, res) => res.send(JSON.stringify(blockchain)));. Y/ U% F  r& H/ A1 y" n
    app.post('/mineBlock', (req, res) => {7 \4 s. G. b1 v! _3 C4 `. Y: p
        var newBlock = generateNextBlock(req.body.data);' C/ Y/ X) W! }! _
        addBlock(newBlock);
  U2 Y; F: @, L. _8 D% Q        broadcast(responseLatestMsg());* ?$ M& ]' s0 P. z5 u
        console.log('block added: ' + JSON.stringify(newBlock));) v1 j  q0 w$ A$ @7 p. ?
        res.send();
  I1 {! g) I& d5 ]4 _& W    });+ F  E. q2 O1 a2 o/ A) u' t9 o
    app.get('/peers', (req, res) => {
7 u. b; t2 A2 l        res.send(sockets.map(s => s._socket.remoteAddress + ':' + s._socket.remotePort));1 r( b( M. p- c- T2 M( c8 x
    });
/ ]# G: p4 T; U, g    app.post('/addPeer', (req, res) => {
$ h% x0 B* p7 b; F7 r        connectToPeers([req.body.peer]);
7 S4 i# E% n* }# ?% N        res.send();& Z/ L: M3 O# T/ y
    });
5 p+ g9 t; Z! x  n    app.listen(http_port, () => console.log('Listening http on port: ' + http_port));
) P" A% A$ `) V: v" \* A};
# B; v! _, S+ P9 a* x6 n( w& x1 ]用户可以用下面的方法和节点互动:
; k8 w- {1 S% |列出所有的块用户提供的内容创建一个新的块列出或者新增peers5 Q  V' y& a* x( S6 F+ Z8 D( g
1 x' u& K1 P# k  O
下面这个Curl的例子就是最直接的控制节点的方法:% ]7 W( D8 ~/ B% x- e+ o
#get all blocks from the node
; j  V7 `" M# \( y! I) Bcurl http://localhost:3001/blocks
* x8 ^: N( @+ J2 A- {, i" C! X系统架构( j% M1 Z* K! V, Q
需要指出的是,节点实际上展现了两个web服务器:一个(HTTP服务器)是让用户控制节点,另一个(Websocket HTTP服务器)。
! M/ P) z" I- i0 V* ^6 W* g; h' C3 b# K8 j/ c* \
总结6 N& [4 E4 S1 R
创造 NaiveChain 的目的是为了示范和学习,因为它并没有“挖矿”算法(PoS或PoW),不能被用于公用网络,但是它实现了区块链运作的基本特性。
BitMere.com 比特池塘系信息发布平台,比特池塘仅提供信息存储空间服务。
声明:该文观点仅代表作者本人,本文不代表比特池塘立场,且不构成建议,请谨慎对待。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

成为第一个吐槽的人

ranbluer 小学生
  • 粉丝

    0

  • 关注

    0

  • 主题

    1