查询余额(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
有疑问加站长微信联系(非本文作者)