parent
93bbce28d8
commit
d65fb29835
@ -1,8 +1,88 @@ |
|||||||
package blockchain |
package blockchain |
||||||
|
|
||||||
|
import "encoding/hex" |
||||||
|
|
||||||
// UTXOPool stores transactions and balance associated with each address.
|
// UTXOPool stores transactions and balance associated with each address.
|
||||||
type UTXOPool struct { |
type UTXOPool struct { |
||||||
// Mapping from address to a map of transaction id to that balance.
|
// 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.
|
// The assumption here is that one address only appears once output array in a transaction.
|
||||||
utxo map[string]map[string]int |
utxo map[string]map[string]int |
||||||
} |
} |
||||||
|
|
||||||
|
// VerifyTransactions verifies if a list of transactions valid.
|
||||||
|
func (utxopool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool { |
||||||
|
spentTXOs := make(map[string]map[string]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) |
||||||
|
// Check if the transaction with the addres is spent or not.
|
||||||
|
if val, ok := spentTXOs[in.Address][inTxID]; 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 |
||||||
|
} |
||||||
|
|
||||||
|
// Sum the balance up to the inTotal.
|
||||||
|
if val, ok := utxopool.utxo[in.Address][inTxID]; ok { |
||||||
|
inTotal += val |
||||||
|
} else { |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
outTotal := 0 |
||||||
|
// Calculate the sum of TxOutput
|
||||||
|
for _, out := range tx.TxOutput { |
||||||
|
outTotal += out.Value |
||||||
|
} |
||||||
|
if inTotal != outTotal { |
||||||
|
return false |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
// VerifyAndUpdate verifies a list of transactions and update utxoPool.
|
||||||
|
func (utxopool *UTXOPool) VerifyAndUpdate(transactions []*Transaction) bool { |
||||||
|
if utxopool.VerifyTransactions(transactions) { |
||||||
|
utxopool.Update(transactions) |
||||||
|
return true |
||||||
|
} |
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// Update utxo balances with a list of new transactions.
|
||||||
|
func (utxopool *UTXOPool) Update(transactions []*Transaction) { |
||||||
|
if utxopool != nil { |
||||||
|
for _, tx := range transactions { |
||||||
|
curTxID := hex.EncodeToString(tx.ID) |
||||||
|
|
||||||
|
// Remove
|
||||||
|
for _, in := range tx.TxInput { |
||||||
|
inTxID := hex.EncodeToString(in.TxID) |
||||||
|
delete(utxopool.utxo[in.Address], inTxID) |
||||||
|
} |
||||||
|
|
||||||
|
// 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 |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
@ -0,0 +1,11 @@ |
|||||||
|
package blockchain |
||||||
|
|
||||||
|
import ( |
||||||
|
"testing" |
||||||
|
) |
||||||
|
|
||||||
|
func TestVerifyTransactions(t *testing.T) { |
||||||
|
if cbtx, utxoPool := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil || utxoPool == nil { |
||||||
|
t.Errorf("failed to create a coinbase transaction.") |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue