我的区块链技术学习笔记(十七):UTXO集介绍 [复制链接]

903
 
8btm.com-新币圈 8btm.com-新币圈 8btm.com-新币圈attachments-2018-01-GtnbXZqU5a700888ac204. 8btm.com-新币圈 8btm.com-新币圈 8btm.com-新币圈作者: Ivan Kuznetsov  吴寿鹤等
8btm.com-新币圈 8btm.com-新币圈著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
8btm.com-新币圈 8btm.com-新币圈

8btm.com-新币圈 8btm.com-新币圈之前在持久化和命令行接口 中,我们研究了 Bitcoin Core 是如何在一个数据库中存储块的,并且了解到区块被存储在 blocks 数据库,交易输出被存储在 chainstate 数据库。会回顾一下 chainstate 的机构:
8btm.com-新币圈 8btm.com-新币圈

    8btm.com-新币圈 8btm.com-新币圈
  • c + 32 字节的交易哈希 -> 该笔交易的未花费交易输出记录
    8btm.com-新币圈 8btm.com-新币圈
  • B + 32 字节的块哈希 -> 未花费交易输出的块哈希
    8btm.com-新币圈 8btm.com-新币圈
在之前那篇文章中,虽然我们已经实现了交易,但是并没有使用 chainstate 来存储交易的输出。所以,接下来我们继续完成这部分。
8btm.com-新币圈 8btm.com-新币圈chainstate 不存储交易。它所存储的是 UTXO 集,也就是未花费交易输出的集合。除此以外,它还存储了“数据库表示的未花费交易输出的块哈希”,不过我们会暂时略过块哈希这一点,因为我们还没有用到块高度(但是我们会在接下来的文章中继续改进)。
8btm.com-新币圈 8btm.com-新币圈那么,我们为什么需要 UTXO 集呢?
8btm.com-新币圈 8btm.com-新币圈来思考一下我们早先实现的 Blockchain.FindUnspentTransactions 方法:
8btm.com-新币圈 8btm.com-新币圈func (bc *Blockchain) FindUnspentTransactions(pubKeyHash []byte) []Transaction { ... bci := bc.Iterator() for { block := bci.Next() for _, tx := range block.Transactions { ... } if len(block.PrevBlockHash) == 0 { break } } ...}这个函数找到有未花费输出的交易。由于交易被保存在区块中,所以它会对区块链里面的每一个区块进行迭代,检查里面的每一笔交易。截止 2017 年 9 月 18 日,在比特币中已经有 485,860 个块,整个数据库所需磁盘空间超过 140 Gb。这意味着一个人如果想要验证交易,必须要运行一个全节点。此外,验证交易将会需要在许多块上进行迭代。
8btm.com-新币圈 8btm.com-新币圈整个问题的解决方案是有一个仅有未花费输出的索引,这就是 UTXO 集要做的事情:这是一个从所有区块链交易中构建(对区块进行迭代,但是只须做一次)而来的缓存,然后用它来计算余额和验证新的交易。截止 2017 年 9 月,UTXO 集大概有 2.7 Gb。
8btm.com-新币圈 8btm.com-新币圈好了,让我们来想一下实现 UTXO 集的话需要作出哪些改变。目前,找到交易用到了以下一些方法:
8btm.com-新币圈 8btm.com-新币圈

    8btm.com-新币圈 8btm.com-新币圈
  • Blockchain.FindUnspentTransactions - 找到有未花费输出交易的主要函数。也是在这个函数里面会对所有区块进行迭代。
    8btm.com-新币圈 8btm.com-新币圈
  • Blockchain.FindSpendableOutputs - 这个函数用于当一个新的交易创建的时候。如果找到有所需数量的输出。使用 Blockchain.FindUnspentTransactions.
    8btm.com-新币圈 8btm.com-新币圈
  • Blockchain.FindUTXO - 找到一个公钥哈希的未花费输出,然后用来获取余额。使用 Blockchain.FindUnspentTransactions.
    8btm.com-新币圈 8btm.com-新币圈
  • Blockchain.FindTransation - 根据 ID 在区块链中找到一笔交易。它会在所有块上进行迭代直到找到它。
    8btm.com-新币圈 8btm.com-新币圈
可以看到,所有方法都对数据库中的所有块进行迭代。但是目前我们还没有改进所有方法,因为 UTXO 集没法存储所有交易,只会存储那些有未花费输出的交易。因此,它无法用于 Blockchain.FindTransaction。
8btm.com-新币圈 8btm.com-新币圈所以,我们想要以下方法:
8btm.com-新币圈 8btm.com-新币圈

    8btm.com-新币圈 8btm.com-新币圈
  • Blockchain.FindUTXO - 通过对区块进行迭代找到所有未花费输出。
    8btm.com-新币圈 8btm.com-新币圈
  • UTXOSet.Reindex - 使用 UTXO 找到未花费输出,然后在数据库中进行存储。这里就是缓存的地方。
    8btm.com-新币圈 8btm.com-新币圈
  • UTXOSet.FindSpendableOutputs - 类似 Blockchain.FindSpendableOutputs,但是使用 UTXO 集。
    8btm.com-新币圈 8btm.com-新币圈
  • UTXOSet.FindUTXO - 类似 Blockchain.FindUTXO,但是使用 UTXO 集。
    8btm.com-新币圈 8btm.com-新币圈
  • Blockchain.FindTransaction 跟之前一样。
    8btm.com-新币圈 8btm.com-新币圈
因此,从现在开始,两个最常用的函数将会使用 cache!来开始写代码吧。
8btm.com-新币圈 8btm.com-新币圈type UTXOSet struct { Blockchain *Blockchain}我们将会使用一个单一数据库,但是我们会将 UTXO 集从存储在不同的 bucket 中。因此,UTXOSet 跟 Blockchain 一起。
8btm.com-新币圈 8btm.com-新币圈func (u UTXOSet) Reindex() { db := u.Blockchain.db bucketName := []byte(utxoBucket) err := db.Update(func(tx *bolt.Tx) error { err := tx.DeleteBucket(bucketName) _, err = tx.CreateBucket(bucketName) }) UTXO := u.Blockchain.FindUTXO() err = db.Update(func(tx *bolt.Tx) error { b := tx.Bucket(bucketName) for txID, outs := range UTXO { key, err := hex.DecodeString(txID) err = b.Put(key, outs.Serialize()) } })}这个方法初始化了 UTXO 集。首先,如果 bucket 存在就先移除,然后从区块链中获取所有的未花费输出,最终将输出保存到 bucket 中。
8btm.com-新币圈 8btm.com-新币圈Blockchain.FindUTXO 几乎跟 Blockchain.FindUnspentTransactions 一模一样,但是现在它返回了一个 TransactionID -> TransactionOutputs 的 map。
8btm.com-新币圈 8btm.com-新币圈现在,UTXO 集可以用于发送币:
8btm.com-新币圈 8btm.com-新币圈func (u UTXOSet) FindSpendableOutputs(pubkeyHash []byte, amount int) (int, map[string][]int) { unspentOutputs := make(map[string][]int) accumulated := 0 db := u.Blockchain.db err := db.View(func(tx *bolt.Tx) error { b := tx.Bucket([]byte(utxoBucket)) c := b.Cursor() for k, v := c.First(); k != nil; k, v = c.Next() { txID := hex.EncodeToString(k) outs := DeserializeOutputs(v) for outIdx, out := range outs.Outputs { if out.IsLockedWithKey(pubkeyHash) && accumulated <span style="font-size:inherit;color:rgb(199,107,41);">

本版积分规则

发表主题 回复
mailtopia,把去中心化做到极致!

(c) 2015-2018 8BTM Inc. M链、₥币 All Rights Reserved 区块链金融合作:福建反身投资管理有限公司

网站备案证书号: 闽ICP备18010811号  Ƀ猫商城 IoT&BlockChain:微物联(福州)网络科技有限公司 SiteMap