0x1 开篇

  区块链,时下最火的技术。一篇《A blockchain in 200 lines of code》更是在技术圈里刷屏。在读过 Lauri Hartikka 写的这篇文章和代码后,我愈发对区块链兴趣浓厚。   纸上得来终觉浅,要深入了解一门技术,终究是需要自己造一次轮子。于是,我着手用 Go 语言仿造着实现了一个 naivechain

0x2 区块数据结构

  和 Lauri Hartikka 一样,数据结构上我们一切从简,只使用 IndexPreviousHashTimestampDataHash 这几个必要的字段。

1
2
3
4
5
6
7
type Block struct {
	Index        int64  `json:"index"`        // 区块索引
	PreviousHash string `json:"previousHash"` // 前块哈希
	Timestamp    int64  `json:"timestamp"`    // 时间戳
	Data         string `json:"data"`         // 区块数据
	Hash         string `json:"hash"`         // 区块哈希
}

0x3 区块哈希

  区块哈希用于验证区块数据的完整性,使用 SHA-256 算法生成IndexPreviousHashTimestampData 拼接字符串的摘要。

1
2
3
4
5
6
func calculateHashForBlock(b *Block) string {
	return fmt.Sprintf("%x",
		sha256.Sum256(
			[]byte(fmt.Sprintf("%d%s%d%s",
				b.Index, b.PreviousHash, b.Timestamp, b.Data))))
}

0x4 创建新区块

  为了生成新区块,我们需要知道前区块和新区块的必要数据(IndexHashTimestampData);区块数据由终端用户提供。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
func generateNextBlock(data string) (nb *Block) {
	var previousBlock = getLatestBlock()
	nb = &Block{
		Data:         data,
		PreviousHash: previousBlock.Hash,
		Index:        previousBlock.Index + 1,
		Timestamp:    time.Now().Unix(),
	}
	nb.Hash = calculateHashForBlock(nb)
	return
}

0x5 创世块

  区块链的第一个区块被称之为创世块,被硬编码在程序内。

1
2
3
4
5
6
7
var genesisBlock = &Block{
	Index:        0,
	PreviousHash: "0",
	Timestamp:    1465154705,
	Data:         "my genesis block!!",
	Hash: "816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7",
}

0x6 区块存储

  这里使用 Go 语言的 Slice 存储区块。区块链是有序 List,为了保证有序性,需要对内存中保存区块的数组进行排序。定义按 Index 排序的结构体 ByIndex,并实现 sort.Interface

1
2
3
4
5
type ByIndex []*Block

func (b ByIndex) Len() int           { return len(b) }
func (b ByIndex) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b ByIndex) Less(i, j int) bool { return b[i].Index < b[j].Index }

0x7 区块完整性验证

1
2
3
4
5
6
7
8
func isValidNewBlock(nb, pb *Block) (ok bool) {
	if nb.Hash == calculateHashForBlock(nb) &&
		pb.Index+1 == nb.Index &&
		pb.Hash == nb.PreviousHash {
		ok = true
	}
	return
}

0x8 节点通讯

  每个节点在启动时监听一个端口(由 -p2p 参数指定),使用 websocket 协议和其它节点通讯。

0x9 节点控制

  没个节点在启动时监听一个端口(由 -api 参数指定),接收 HTTP 协议的 JSON 控制命令。使用示例:

  • 查看区块

    1
    
    curl http://localhost:3001/blocks
    
  • 创建区块

    1
    
    curl -H "Content-type:application/json" --data '{"data" : "Some data to the first block"}' http://localhost:3001/mine_block
    
  • 添加节点

    1
    
    curl -H "Content-type:application/json" --data '{"peer" : "ws://localhost:6002"}' http://localhost:3001/add_peer
    
  • 查看节点

    1
    
    curl http://localhost:3001/peers
    

0xA 结语

  这是一个最简单的区块链实现,用于学习区块链的工作原理,因为没用实现工作量证明这一类的挖矿算法,不适宜在公共网络使用。更多的细节请访问 Github: https://github.com/kofj/naivechain