GO语言--区块链数据如何遍历

221 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情

区块链数据如何遍历

要想做到区块链数据遍历,就应该搞清楚数据的存储形式。我们知道,可以从最新的块hash值获得该区块数据,在区块数据内可以找到前一块的hash值,然后以此类推,就可以一直遍历到创世块。

1、利用gob将区块数据还原

利用gon.NewDecoder来构造解码器,将之前序列化数据传入就可以还原为区块数据

//区块数据还原为Block
func DeserializeBlock(d []byte) *Block {
	var block Block
	//创建解码器
	decoder := gob.NewDecoder(bytes.NewReader(d))
	//解析区块数据
	decoder.Decode(&block)
	return &block
}

2、设计迭代器

因为遍历时涉及数据赋值变化,为了避免遍历对整个区块链影响,增加一个迭代器实现遍历。

//迭代器
type BlockchainIterator struct {
	currentHash []byte   //当区块hash
	db          *bolt.DB //已经打开的数据库
}

//通过Blockchain构造迭代器
func (bc *Blockchain) Iterator() *BlockchainIterator {
	bci := &BlockchainIterator{bc.tip, bc.db}

	return bci
}

3、使用迭代获取区块并将hash指向前一区块

实现PreBlock方法,获取当前区块的值,并告知是否还有前块

//获取前一个区块hash,返回当区块数据
func (i *BlockchainIterator) PreBlock() (*Block, bool) {
	var block *Block
	//根据hash获取块数据
	i.db.View(func(tx *bolt.Tx) error {
		b := tx.Bucket([]byte(blocksBucket))
		encodedBlock := b.Get(i.currentHash)
		//解码当前块数据
		block = DeserializeBlock(encodedBlock)

		return nil
	})
	//当前hash变更为前块hash
	i.currentHash = block.PrevBlockHash
	//返回区块
	return block, len(i.currentHash) > 0
}

main函数开始遍历

准备完成,在main函数中添加代码开始遍历。

bci := bc.Iterator()
	for {
		block, next := bci.PreBlock()
		fmt.Printf("Prev. hash: %x\n", block.PrevBlockHash)
		fmt.Printf("Data: %s\n", block.Transactions[0].Vin[0].FromAddr)
		fmt.Printf("Hash: %x\n", block.Hash)
		fmt.Printf("Nonce: %d\n", block.Nonce)
		pow := NewProofOfWork(block)
		fmt.Printf("Pow: %t\n", pow.Validate())
		fmt.Println()
		if !next {
			//next为假代表已经到创世块了
			break
		}
	}

总结

我们可以在网上搜一下区块链持久化的示意图,这能够更深层次的帮助我们理解。