|
|
|
@ -6,36 +6,38 @@ import ( |
|
|
|
|
|
|
|
|
|
// UTXOPool stores transactions and balance associated with each address.
|
|
|
|
|
type UTXOPool struct { |
|
|
|
|
// Mapping from address to a map of transaction id to that balance.
|
|
|
|
|
// The assumption here is that one address only appears once output array in a transaction.
|
|
|
|
|
utxo map[string]map[string]int |
|
|
|
|
// 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 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// VerifyTransactions verifies if a list of transactions valid.
|
|
|
|
|
func (utxopool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool { |
|
|
|
|
spentTXOs := make(map[string]map[string]bool) |
|
|
|
|
spentTXOs := make(map[string]map[string]map[int]bool) |
|
|
|
|
if utxopool != nil { |
|
|
|
|
for _, tx := range transactions { |
|
|
|
|
inTotal := 0 |
|
|
|
|
// Calculate the sum of TxInput
|
|
|
|
|
for _, in := range tx.TxInput { |
|
|
|
|
inTxID := hex.EncodeToString(in.TxID) |
|
|
|
|
index := in.TxOutputIndex |
|
|
|
|
// Check if the transaction with the addres is spent or not.
|
|
|
|
|
if val, ok := spentTXOs[in.Address][inTxID]; ok { |
|
|
|
|
if val, ok := spentTXOs[in.Address][inTxID][index]; ok { |
|
|
|
|
if val { |
|
|
|
|
return false |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Mark the transactions with the addres spent.
|
|
|
|
|
if _, ok := spentTXOs[in.Address]; ok { |
|
|
|
|
spentTXOs[in.Address][inTxID] = true |
|
|
|
|
} else { |
|
|
|
|
spentTXOs[in.Address] = make(map[string]bool) |
|
|
|
|
spentTXOs[in.Address][inTxID] = true |
|
|
|
|
// Mark the transactions with the address and index spent.
|
|
|
|
|
if _, ok := spentTXOs[in.Address]; !ok { |
|
|
|
|
spentTXOs[in.Address] = make(map[string]map[int]bool) |
|
|
|
|
} |
|
|
|
|
if _, ok := spentTXOs[in.Address][inTxID]; !ok { |
|
|
|
|
spentTXOs[in.Address][inTxID] = make(map[int]bool) |
|
|
|
|
} |
|
|
|
|
spentTXOs[in.Address][inTxID][index] = true |
|
|
|
|
|
|
|
|
|
// Sum the balance up to the inTotal.
|
|
|
|
|
if val, ok := utxopool.utxo[in.Address][inTxID]; ok { |
|
|
|
|
if val, ok := utxopool.utxo[in.Address][inTxID][index]; ok { |
|
|
|
|
inTotal += val |
|
|
|
|
} else { |
|
|
|
|
return false |
|
|
|
@ -73,18 +75,39 @@ func (utxopool *UTXOPool) Update(transactions []*Transaction) { |
|
|
|
|
// Remove
|
|
|
|
|
for _, in := range tx.TxInput { |
|
|
|
|
inTxID := hex.EncodeToString(in.TxID) |
|
|
|
|
delete(utxopool.utxo[in.Address], inTxID) |
|
|
|
|
delete(utxopool.utxo[in.Address][inTxID], in.TxOutputIndex) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Update
|
|
|
|
|
for _, out := range tx.TxOutput { |
|
|
|
|
if _, ok := utxopool.utxo[out.Address]; ok { |
|
|
|
|
utxopool.utxo[out.Address][curTxID] = out.Value |
|
|
|
|
} else { |
|
|
|
|
utxopool.utxo[out.Address] = make(map[string]int) |
|
|
|
|
utxopool.utxo[out.Address][curTxID] = out.Value |
|
|
|
|
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.utxo[out.Address][curTxID]; !ok { |
|
|
|
|
utxopool.utxo[out.Address][curTxID] = make(map[int]int) |
|
|
|
|
} |
|
|
|
|
utxopool.utxo[out.Address][curTxID][index] = out.Value |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 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) |
|
|
|
|
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 |
|
|
|
|
} |
|
|
|
|
return &utxoPool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// CreateUTXOPoolFromGenesisBlockChain a utxo pool from a genesis blockchain.
|
|
|
|
|
func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool { |
|
|
|
|
tx := bc.blocks[0].Transactions[0] |
|
|
|
|
return CreateUTXOPoolFromTransaction(tx) |
|
|
|
|
} |
|
|
|
|