源码参考
https://github.com/huangzhenshi/BuildBitCoinSystemGo/tree/master/blockchain_learn/chapter5
参考博客
https://www.jianshu.com/p/cb25c768b3b7
根据Address查询余额
因为这里和之前不一样,以前Output里面存的是账户名称,现在输出里面存的是 PublicKeyHash
总体实现思路
- 通过Address转换为pubKeyHash
- 根据pubKeyHash查找所有的未花费的Output
- Sum(output.value)得出总余额
func (cli *CLI) getBalance(address string) {
pubKeyHash := Base58Decode([]byte(address))
pubKeyHash = pubKeyHash[1 : len(pubKeyHash)-4]
//unspentTranstionOutPuts
UTXOs := bc.FindUTXO(pubKeyHash)
for _, out := range UTXOs {
balance += out.Value
}
fmt.Printf("Balance of '%s': %d\n", address, balance)
}
查询余额是通过先调用公用方法,找到所有的包含未花费的output的交易集合,再遍历集合获取属于该用户的 Output
func (bc *Blockchain) FindUTXO(pubKeyHash []byte) []TXOutput {
unspentTransactions := bc.FindUnspentTransactions(pubKeyHash)
//通过pubKeyHash匹配是否是该用户的
for _, tx := range unspentTransactions {
for _, out := range tx.Vout {
if out.IsLockedWithKey(pubKeyHash) {
UTXOs = append(UTXOs, out)
}
}
}
return UTXOs
}
通过pubKeyHash获取该用户的未花费的output的交易集合,需要沿着比特币链,倒序遍历,创建一个数组,把所有归属于该用户的开销记录维护一个 交易ID的数组,再统计除去这些花费交易的其它入账交易。这里涉及到pubKeyHash和 入账output的pubKeyHash进行compare,以及以input为消费记录里面的 HashPubKey(pubKey)方法
for outIdx, out := range tx.Vout {
if spentTXOs[txID] != nil {
for _, spentOutIdx := range spentTXOs[txID] {
if spentOutIdx == outIdx {
continue Outputs
}
}
}
if out.IsLockedWithKey(pubKeyHash) {
unspentTXs = append(unspentTXs, *tx)
}
}
if tx.IsCoinbase() == false {
for _, in := range tx.Vin {
if in.UsesKey(pubKeyHash) {
inTxID := hex.EncodeToString(in.Txid)
spentTXOs[inTxID] = append(spentTXOs[inTxID], in.Vout)
}
}
}