-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathblockchain_utxo.go
143 lines (116 loc) · 3.48 KB
/
blockchain_utxo.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package main
import "encoding/hex"
// FindUTXO finds all unspent transaction outputs and returns transactions with spent outputs removed
func (bc *Blockchain) FindUTXO() map[string]TXOutputs {
UTXO := make(map[string]TXOutputs)
spentTXOs := make(map[string][]int)
bci := bc.Iterator()
for {
block := bci.Next()
for _, tx := range block.Transactions {
txID := hex.EncodeToString(tx.ID)
Outputs:
for outIdx, out := range tx.Vout {
// Was the output spent?
if spentTXOs[txID] != nil {
for _, spentOutIdx := range spentTXOs[txID] {
if spentOutIdx == outIdx {
continue Outputs
}
}
}
outs := UTXO[txID]
outs.Outputs = append(outs.Outputs, out)
UTXO[txID] = outs
}
if tx.IsCoinbase() == false {
for _, in := range tx.Vin {
inTxID := hex.EncodeToString(in.Txid)
spentTXOs[inTxID] = append(spentTXOs[inTxID], in.Vout)
}
}
}
if len(block.PrevBlockHash) == 0 {
break
}
}
return UTXO
}
// FindUnspentTransactions returns a list of transactions containing unspent outputs
//查询未花费的交易,非常经典
func (bc *Blockchain) FindUnspentTransactions(pubKeyHash []byte) []Transaction {
var unspentTXs []Transaction
spentTXOs := make(map[string][]int)
bci := bc.Iterator()
//循环每个区块,从最后一个区块到创世区块,最后一个区块的输出一定是没有花费的。
for {
block := bci.Next()
//循环区块中每个交易
for _, tx := range block.Transactions {
txID := hex.EncodeToString(tx.ID)
Outputs:
//循环每个交易中的输出,如果这些输出未花费,并且能够解锁,那么既可以
for outIdx, out := range tx.Vout {
// Was the output spent?
if spentTXOs[txID] != nil {
for _, spentOut := range spentTXOs[txID] {
if spentOut == outIdx {
continue Outputs
}
}
}
if out.CanBeUnlockedWith(pubKeyHash) {
unspentTXs = append(unspentTXs, *tx)
}
}
//如果不是coinbase交易,则遍历输入,加入到已经花费的数组spentTXOs中
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)
}
}
}
}
if len(block.PrevBlockHash) == 0 {
break
}
}
return unspentTXs
}
// FindUTXO finds and returns all unspent transaction outputs
//返回为花费的所有输出结构体TXOutput
func (bc *Blockchain) FindUTXObypubkeyhash(pubKeyHash []byte) []TXOutput {
var UTXOs []TXOutput
unspentTransactions := bc.FindUnspentTransactions(pubKeyHash)
for _, tx := range unspentTransactions {
for _, out := range tx.Vout {
if out.CanBeUnlockedWith(pubKeyHash) {
UTXOs = append(UTXOs, out)
}
}
}
return UTXOs
}
// FindSpendableOutputs finds and returns unspent outputs to reference in inputs
//返回地址address可用的金额amount的交易数组
func (bc *Blockchain) FindSpendableOutputs(pubKeyHash []byte, amount int) (int, map[string][]int) {
unspentOutputs := make(map[string][]int)
unspentTXs := bc.FindUnspentTransactions(pubKeyHash)
accumulated := 0
Work:
for _, tx := range unspentTXs {
txID := hex.EncodeToString(tx.ID)
for outIdx, out := range tx.Vout {
if out.CanBeUnlockedWith(pubKeyHash) && accumulated < amount {
accumulated += out.Value
unspentOutputs[txID] = append(unspentOutputs[txID], outIdx)
if accumulated >= amount {
break Work
}
}
}
}
return accumulated, unspentOutputs
}