2020 区块链 golang 版本(8)

zidea · · 875 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

封面

查询余额(UTXO)

上面代码实现 Alice 通过挖矿得到她的第一笔交易 12.5 比特币奖励,现在我们需要实现可以查询 Alice 余额(UTXO)的方法。


我们可以通过追踪 John 交易来计算其 UTXO,如图

  • 蓝色表示交易输入
  • 黄色和绿色表示交易输出,其中绿色表示没有被话费的输出
    那么我们在统计某一个用户UTXO 不仅要看和他相关输出,还要看和他相关输入,以便确认某一笔输出是否被使用,如果被使用我们就可以跳过该输入对应输出,这里大家可能对输入和输出还不算理解,这里输入和输出可以理解对象,输入就是用户花费的,而输出用户得到比特币。这个方法我们写到区块链(BlockChain)下命名为 FindUTXOs。我先把代码抛出来
func (bc *BlockChain) FindUTXOs(address string) []TXOutput {
    //定义 UTXO 然后将每一笔UTXO都写入这个数组
    var UTXO []TXOutput

    //定义 map 来保存消费过的output key ouput 所在交易id value 这个交易索引的数组
    // map[交易id][]int64
    spentOutputsMap := make(map[string][]int64)

    //获取 blockchain 的迭代器
    it := bc.NewIterator()
    for {
        //1. 遍历区块
        block := it.Next()

        //2 遍历交易
        for _, tx := range block.Transactions {
            //输出当前交易 TXID
            fmt.Printf("current txid: %x\n", tx.TXID)
            //3 遍历 output 找到和用户相关的 UTXO (在添加 output 到数组 UTXO 之前,需要检查一下是否已经使用过该 output)
        OUTPUT:
            for i, output := range tx.TXOutputs {
                fmt.Printf("current index: %d\n", i)
                //在这里做一个过滤,将所有消耗过的 outputs 和当前的所即将添加 output 对比一下
                //如果当前这个 output 相同跳过,否则添加

                //如果当前的交易 id 存在我们已经标识的 map 说明这个交易中有消耗过的
                if spentOutputsMap[string(tx.TXID)] != nil {

                    for _, j := range spentOutputsMap[string(tx.TXID)] {
                        if int64(i) == j {
                            //当前准备添加output已经消耗过
                            continue OUTPUT
                        }
                    }

                }

                //判断地址是否想要查询用户,通过 address ,如果 output 的 PubKeyHash 和 address 相同,则添加到返回集合 UTXO 数组中
                if output.PubKeyHash == address {
                    UTXO = append(UTXO, output)
                }
            }
            // 如果当前交易是挖矿交易 那么不做遍历直接跳过
            if !tx.IsCoinbase() {
                //4 遍历 input 找到目标用户话费过的 UTXO 集合(把自己话费过的标识出来)
                //还需要遍历每一个区块 input 看其有没有和目标用户的相关交易记录
                for _, input := range tx.TXInputs {
                    //判断当前一下当前input和目标用户是否一致,如果相同,就添加添加的哦消耗的output
                    if input.Sig == address {
                        indexArray := spentOutputsMap[string(input.TXid)]
                        indexArray = append(indexArray, input.Index)
                    }
                }
            } else {
                fmt.Printf("this is coinbase jumpout iteration\n")
            }

        }
        //完成对区块链的遍历
        if len(block.PrevHash) == 0 {
            fmt.Printf("block iteratoration finished ")
            break
        }
    }

    return UTXO
}

先整理一下思路,我们分别遍历区块、遍历交易然后遍历ouput和input

  • 遍历 ouput, 找到和用户相关 utxo,在添加ouput之前检查是否已经使用过
  • 遍历 input, 找到用户花费过的 utxo 的集合,标识用户使用过的ouput

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:zidea

查看原文:2020 区块链 golang 版本(8)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

875 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传