From 31472956d5bc80508bfd5ebecc2fa552bb69104d Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Mon, 18 Jun 2018 21:22:53 -0700 Subject: [PATCH] add verification/selection a set of valid transactions --- blockchain/utxopool.go | 90 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/blockchain/utxopool.go b/blockchain/utxopool.go index cb198c054..e79e88f62 100644 --- a/blockchain/utxopool.go +++ b/blockchain/utxopool.go @@ -4,6 +4,10 @@ import ( "encoding/hex" ) +const ( + MaxNumberOfTransactions = 100 +) + // UTXOPool stores transactions and balance associated with each address. type UTXOPool struct { // Mapping from address to a map of transaction id to a map of the index of output @@ -57,6 +61,80 @@ func (utxopool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool { return true } +// VerifyOneTransactionAndUpdate verifies if a list of transactions valid. +func (utxopool *UTXOPool) VerifyOneTransaction(tx *Transaction) bool { + spentTXOs := make(map[string]map[string]map[int]bool) + txID := hex.EncodeToString(tx.ID) + 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 := utxopool.utxo[in.Address][inTxID][index]; ok { + if spentTXOs[in.Address][inTxID][index] { + return false + } + inTotal += val + } else { + return false + } + // 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 + } + + outTotal := 0 + // Calculate the sum of TxOutput + for index, out := range tx.TxOutput { + if val, ok := spentTXOs[out.Address][txID][index]; ok { + return false + } + outTotal += out.Value + } + if inTotal != outTotal { + return false + } + return true +} + +func (utxopool *UTXOPool) Update(tx* Transaction) { + if utxopool != nil { + txID := hex.EncodeToString(tx.ID) + + // Remove + for _, in := range tx.TxInput { + inTxID := hex.EncodeToString(in.TxID) + delete(utxopool.utxo[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.utxo[out.Address][txID]; !ok { + utxopool.utxo[out.Address][txID] = make(map[int]int) + } + utxopool.utxo[out.Address][txID][index] = out.Value + } + } +} + +func (utxopool *UTXOPool) VerifyOneTransactionAndUpdate(tx *Transaction) bool { + if utxopool.VerifyOneTransaction(tx) { + utxopool.Update(tx) + return true + } + retur false +} + // VerifyAndUpdate verifies a list of transactions and update utxoPool. func (utxopool *UTXOPool) VerifyAndUpdate(transactions []*Transaction) bool { if utxopool.VerifyTransactions(transactions) { @@ -111,3 +189,15 @@ func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool { tx := bc.blocks[0].Transactions[0] return CreateUTXOPoolFromTransaction(tx) } + +// SelectTransactionsForNewBlock returns a list of index of valid transactions for the new block. +func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transaction) (selected, unselected []*Transaction) { + selected, unselected = []*Transaction{}, []*Transaction{} + for id, tx := range transactions { + if len(selected) < MaxNumberOfTransactions && utxoPool.VerifyOneTransactionAndUpdate(tx) { + append(selected, tx) + } else { + append(unselected, tx) + } + } +}