|
|
|
@ -14,7 +14,20 @@ const ( |
|
|
|
|
type UTXOPool struct { |
|
|
|
|
// Mapping from address to a map of transaction id to a map of the index of output
|
|
|
|
|
// array in that transaction to that balance.
|
|
|
|
|
utxo map[string]map[string]map[int]int |
|
|
|
|
/* |
|
|
|
|
The 3-d map's structure: |
|
|
|
|
address - [ |
|
|
|
|
txId1 - [ |
|
|
|
|
outputIndex1 - value1 |
|
|
|
|
outputIndex2 - value2 |
|
|
|
|
] |
|
|
|
|
txId2 - [ |
|
|
|
|
outputIndex1 - value1 |
|
|
|
|
outputIndex2 - value2 |
|
|
|
|
] |
|
|
|
|
] |
|
|
|
|
*/ |
|
|
|
|
UtxoMap map[string]map[string]map[int]int |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// VerifyTransactions verifies if a list of transactions valid.
|
|
|
|
@ -43,7 +56,7 @@ func (utxoPool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool { |
|
|
|
|
spentTXOs[in.Address][inTxID][index] = true |
|
|
|
|
|
|
|
|
|
// Sum the balance up to the inTotal.
|
|
|
|
|
if val, ok := utxoPool.utxo[in.Address][inTxID][index]; ok { |
|
|
|
|
if val, ok := utxoPool.UtxoMap[in.Address][inTxID][index]; ok { |
|
|
|
|
inTotal += val |
|
|
|
|
} else { |
|
|
|
|
return false |
|
|
|
@ -73,7 +86,7 @@ func (utxoPool *UTXOPool) VerifyOneTransaction(tx *Transaction) bool { |
|
|
|
|
inTxID := hex.EncodeToString(in.TxID) |
|
|
|
|
index := in.TxOutputIndex |
|
|
|
|
// Check if the transaction with the addres is spent or not.
|
|
|
|
|
if val, ok := utxoPool.utxo[in.Address][inTxID][index]; ok { |
|
|
|
|
if val, ok := utxoPool.UtxoMap[in.Address][inTxID][index]; ok { |
|
|
|
|
inTotal += val |
|
|
|
|
} else { |
|
|
|
|
return false |
|
|
|
@ -113,19 +126,19 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { |
|
|
|
|
// Remove
|
|
|
|
|
for _, in := range tx.TxInput { |
|
|
|
|
inTxID := hex.EncodeToString(in.TxID) |
|
|
|
|
delete(utxoPool.utxo[in.Address][inTxID], in.TxOutputIndex) |
|
|
|
|
delete(utxoPool.UtxoMap[in.Address][inTxID], in.TxOutputIndex) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update
|
|
|
|
|
for index, out := range tx.TxOutput { |
|
|
|
|
if _, ok := utxoPool.utxo[out.Address]; !ok { |
|
|
|
|
utxoPool.utxo[out.Address] = make(map[string]map[int]int) |
|
|
|
|
utxoPool.utxo[out.Address][txID] = make(map[int]int) |
|
|
|
|
if _, ok := utxoPool.UtxoMap[out.Address]; !ok { |
|
|
|
|
utxoPool.UtxoMap[out.Address] = make(map[string]map[int]int) |
|
|
|
|
utxoPool.UtxoMap[out.Address][txID] = make(map[int]int) |
|
|
|
|
} |
|
|
|
|
if _, ok := utxoPool.utxo[out.Address][txID]; !ok { |
|
|
|
|
utxoPool.utxo[out.Address][txID] = make(map[int]int) |
|
|
|
|
if _, ok := utxoPool.UtxoMap[out.Address][txID]; !ok { |
|
|
|
|
utxoPool.UtxoMap[out.Address][txID] = make(map[int]int) |
|
|
|
|
} |
|
|
|
|
utxoPool.utxo[out.Address][txID][index] = out.Value |
|
|
|
|
utxoPool.UtxoMap[out.Address][txID][index] = out.Value |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -149,7 +162,7 @@ func (utxoPool *UTXOPool) VerifyAndUpdate(transactions []*Transaction) bool { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update utxo balances with a list of new transactions.
|
|
|
|
|
// Update Utxo balances with a list of new transactions.
|
|
|
|
|
func (utxoPool *UTXOPool) Update(transactions []*Transaction) { |
|
|
|
|
if utxoPool != nil { |
|
|
|
|
for _, tx := range transactions { |
|
|
|
@ -158,38 +171,38 @@ func (utxoPool *UTXOPool) Update(transactions []*Transaction) { |
|
|
|
|
// Remove
|
|
|
|
|
for _, in := range tx.TxInput { |
|
|
|
|
inTxID := hex.EncodeToString(in.TxID) |
|
|
|
|
delete(utxoPool.utxo[in.Address][inTxID], in.TxOutputIndex) |
|
|
|
|
delete(utxoPool.UtxoMap[in.Address][inTxID], in.TxOutputIndex) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update
|
|
|
|
|
for index, out := range tx.TxOutput { |
|
|
|
|
if _, ok := utxoPool.utxo[out.Address]; !ok { |
|
|
|
|
utxoPool.utxo[out.Address] = make(map[string]map[int]int) |
|
|
|
|
utxoPool.utxo[out.Address][curTxID] = make(map[int]int) |
|
|
|
|
if _, ok := utxoPool.UtxoMap[out.Address]; !ok { |
|
|
|
|
utxoPool.UtxoMap[out.Address] = make(map[string]map[int]int) |
|
|
|
|
utxoPool.UtxoMap[out.Address][curTxID] = make(map[int]int) |
|
|
|
|
} |
|
|
|
|
if _, ok := utxoPool.utxo[out.Address][curTxID]; !ok { |
|
|
|
|
utxoPool.utxo[out.Address][curTxID] = make(map[int]int) |
|
|
|
|
if _, ok := utxoPool.UtxoMap[out.Address][curTxID]; !ok { |
|
|
|
|
utxoPool.UtxoMap[out.Address][curTxID] = make(map[int]int) |
|
|
|
|
} |
|
|
|
|
utxoPool.utxo[out.Address][curTxID][index] = out.Value |
|
|
|
|
utxoPool.UtxoMap[out.Address][curTxID][index] = out.Value |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// CreateUTXOPoolFromTransaction a utxo pool from a genesis transaction.
|
|
|
|
|
// CreateUTXOPoolFromTransaction a Utxo pool from a genesis transaction.
|
|
|
|
|
func CreateUTXOPoolFromTransaction(tx *Transaction) *UTXOPool { |
|
|
|
|
var utxoPool UTXOPool |
|
|
|
|
txID := hex.EncodeToString(tx.ID) |
|
|
|
|
utxoPool.utxo = make(map[string]map[string]map[int]int) |
|
|
|
|
utxoPool.UtxoMap = make(map[string]map[string]map[int]int) |
|
|
|
|
for index, out := range tx.TxOutput { |
|
|
|
|
utxoPool.utxo[out.Address] = make(map[string]map[int]int) |
|
|
|
|
utxoPool.utxo[out.Address][txID] = make(map[int]int) |
|
|
|
|
utxoPool.utxo[out.Address][txID][index] = out.Value |
|
|
|
|
utxoPool.UtxoMap[out.Address] = make(map[string]map[int]int) |
|
|
|
|
utxoPool.UtxoMap[out.Address][txID] = make(map[int]int) |
|
|
|
|
utxoPool.UtxoMap[out.Address][txID][index] = out.Value |
|
|
|
|
} |
|
|
|
|
return &utxoPool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// CreateUTXOPoolFromGenesisBlockChain a utxo pool from a genesis blockchain.
|
|
|
|
|
// CreateUTXOPoolFromGenesisBlockChain a Utxo pool from a genesis blockchain.
|
|
|
|
|
func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool { |
|
|
|
|
tx := bc.Blocks[0].Transactions[0] |
|
|
|
|
return CreateUTXOPoolFromTransaction(tx) |
|
|
|
@ -211,7 +224,7 @@ func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transact |
|
|
|
|
// Used for debugging.
|
|
|
|
|
func (utxoPool *UTXOPool) String() string { |
|
|
|
|
res := "" |
|
|
|
|
for address, v1 := range utxoPool.utxo { |
|
|
|
|
for address, v1 := range utxoPool.UtxoMap { |
|
|
|
|
for txid, v2 := range v1 { |
|
|
|
|
for index, value := range v2 { |
|
|
|
|
res += fmt.Sprintf("address: %v, tx id: %v, index: %v, value: %v\n", address, txid, index, value) |
|
|
|
|