From 5ad778781ef9cf498808c2d37c9fcaa186c90d20 Mon Sep 17 00:00:00 2001 From: Richard Liu Date: Sun, 5 Aug 2018 01:12:31 -0700 Subject: [PATCH] fixed null outpoint issue; make outpoint.index uint32. --- blockchain/blockchain.go | 10 ++++---- blockchain/transaction.go | 15 ++++++++---- blockchain/utxopool.go | 50 +++++++++++++++++++-------------------- client/btctxgen/main.go | 6 ++--- client/txgen/main.go | 2 +- 5 files changed, 45 insertions(+), 38 deletions(-) diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index b9f4d01cf..cb71620e2 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -23,7 +23,7 @@ func (bc *Blockchain) GetLatestBlock() *Block { // FindUnspentTransactions returns a list of transactions containing unspent outputs func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction { var unspentTXs []Transaction - spentTXOs := make(map[string][]int) + spentTXOs := make(map[string][]uint32) for index := len(bc.Blocks) - 1; index >= 0; index-- { block := bc.Blocks[index] @@ -37,7 +37,7 @@ func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction { idx = 0 } for outIdx, txOutput := range tx.TxOutput { - if idx >= 0 && spentTXOs[txID][idx] == outIdx { + if idx >= 0 && spentTXOs[txID][idx] == uint32(outIdx) { idx++ continue } @@ -78,8 +78,8 @@ func (bc *Blockchain) FindUTXO(address string) []TXOutput { } // FindSpendableOutputs finds and returns unspent outputs to reference in inputs -func (bc *Blockchain) FindSpendableOutputs(address string, amount int) (int, map[string][]int) { - unspentOutputs := make(map[string][]int) +func (bc *Blockchain) FindSpendableOutputs(address string, amount int) (int, map[string][]uint32) { + unspentOutputs := make(map[string][]uint32) unspentTXs := bc.FindUnspentTransactions(address) accumulated := 0 @@ -90,7 +90,7 @@ Work: for outIdx, txOutput := range tx.TxOutput { if txOutput.Address == address && accumulated < amount { accumulated += txOutput.Value - unspentOutputs[txID] = append(unspentOutputs[txID], outIdx) + unspentOutputs[txID] = append(unspentOutputs[txID], uint32(outIdx)) if accumulated >= amount { break Work diff --git a/blockchain/transaction.go b/blockchain/transaction.go index a1840e9e0..494e75500 100644 --- a/blockchain/transaction.go +++ b/blockchain/transaction.go @@ -7,9 +7,16 @@ import ( "encoding/hex" "fmt" "log" + "math" +) + +var ( + // zeroHash is the zero value for a Hash and is defined as + // a package level variable to avoid the need to create a new instance + // every time a check is needed. + zeroHash Hash ) -// Transaction represents a Bitcoin transaction type Transaction struct { ID [32]byte // 32 byte hash TxInput []TXInput @@ -33,12 +40,12 @@ type Hash = [32]byte // Index is the index of the transaction ouput in the previous transaction type OutPoint struct { Hash Hash - Index int + Index uint32 } // NewOutPoint returns a new transaction outpoint point with the // provided hash and index. -func NewOutPoint(hash *Hash, index int) *OutPoint { +func NewOutPoint(hash *Hash, index uint32) *OutPoint { return &OutPoint{ Hash: *hash, Index: index, @@ -102,7 +109,7 @@ func NewCoinbaseTX(to, data string, shardID uint32) *Transaction { data = fmt.Sprintf("Reward to '%s'", to) } - txin := NewTXInput(nil, to, shardID) + txin := NewTXInput(NewOutPoint(&Hash{}, math.MaxUint32), to, shardID) txout := TXOutput{DefaultCoinbaseValue, to, shardID} tx := Transaction{[32]byte{}, []TXInput{*txin}, []TXOutput{txout}, nil} tx.SetID() diff --git a/blockchain/utxopool.go b/blockchain/utxopool.go index 0be9bd0cf..b91dc0a86 100644 --- a/blockchain/utxopool.go +++ b/blockchain/utxopool.go @@ -25,15 +25,15 @@ type UTXOPool struct { ] ] */ - UtxoMap map[string]map[string]map[int]int - LockedUtxoMap map[string]map[string]map[int]int + UtxoMap map[string]map[string]map[uint32]int + LockedUtxoMap map[string]map[string]map[uint32]int ShardId uint32 mutex sync.Mutex } // VerifyTransactions verifies if a list of transactions valid for this shard. func (utxoPool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool { - spentTXOs := make(map[string]map[string]map[int]bool) + spentTXOs := make(map[string]map[string]map[uint32]bool) if utxoPool != nil { for _, tx := range transactions { if valid, crossShard := utxoPool.VerifyOneTransaction(tx, &spentTXOs); !crossShard && !valid { @@ -45,13 +45,13 @@ func (utxoPool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool { } // VerifyOneTransaction verifies if a list of transactions valid. -func (utxoPool *UTXOPool) VerifyOneTransaction(tx *Transaction, spentTXOs *map[string]map[string]map[int]bool) (valid, crossShard bool) { +func (utxoPool *UTXOPool) VerifyOneTransaction(tx *Transaction, spentTXOs *map[string]map[string]map[uint32]bool) (valid, crossShard bool) { if len(tx.Proofs) != 0 { return utxoPool.VerifyUnlockTransaction(tx) } if spentTXOs == nil { - spentTXOs = &map[string]map[string]map[int]bool{} + spentTXOs = &map[string]map[string]map[uint32]bool{} } inTotal := 0 // Calculate the sum of TxInput @@ -72,10 +72,10 @@ func (utxoPool *UTXOPool) VerifyOneTransaction(tx *Transaction, spentTXOs *map[s } // Mark the transactions with the address and index spent. if _, ok := (*spentTXOs)[in.Address]; !ok { - (*spentTXOs)[in.Address] = make(map[string]map[int]bool) + (*spentTXOs)[in.Address] = make(map[string]map[uint32]bool) } if _, ok := (*spentTXOs)[in.Address][inTxID]; !ok { - (*spentTXOs)[in.Address][inTxID] = make(map[int]bool) + (*spentTXOs)[in.Address][inTxID] = make(map[uint32]bool) } (*spentTXOs)[in.Address][inTxID][index] = true @@ -193,11 +193,11 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { // put the delete (locked) utxo into a separate locked utxo pool inTxID := hex.EncodeToString(in.PreviousOutPoint.Hash[:]) if _, ok := utxoPool.LockedUtxoMap[in.Address]; !ok { - utxoPool.LockedUtxoMap[in.Address] = make(map[string]map[int]int) - utxoPool.LockedUtxoMap[in.Address][inTxID] = make(map[int]int) + utxoPool.LockedUtxoMap[in.Address] = make(map[string]map[uint32]int) + utxoPool.LockedUtxoMap[in.Address][inTxID] = make(map[uint32]int) } if _, ok := utxoPool.LockedUtxoMap[in.Address][inTxID]; !ok { - utxoPool.LockedUtxoMap[in.Address][inTxID] = make(map[int]int) + utxoPool.LockedUtxoMap[in.Address][inTxID] = make(map[uint32]int) } utxoPool.LockedUtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index] = value } @@ -219,11 +219,11 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { // Simply bring back the locked (removed) utxo inTxID := hex.EncodeToString(in.PreviousOutPoint.Hash[:]) if _, ok := utxoPool.UtxoMap[in.Address]; !ok { - utxoPool.UtxoMap[in.Address] = make(map[string]map[int]int) - utxoPool.UtxoMap[in.Address][inTxID] = make(map[int]int) + utxoPool.UtxoMap[in.Address] = make(map[string]map[uint32]int) + utxoPool.UtxoMap[in.Address][inTxID] = make(map[uint32]int) } if _, ok := utxoPool.UtxoMap[in.Address][inTxID]; !ok { - utxoPool.UtxoMap[in.Address][inTxID] = make(map[int]int) + utxoPool.UtxoMap[in.Address][inTxID] = make(map[uint32]int) } value := utxoPool.LockedUtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index] utxoPool.UtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index] = value @@ -239,13 +239,13 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { continue } 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) + utxoPool.UtxoMap[out.Address] = make(map[string]map[uint32]int) + utxoPool.UtxoMap[out.Address][txID] = make(map[uint32]int) } if _, ok := utxoPool.UtxoMap[out.Address][txID]; !ok { - utxoPool.UtxoMap[out.Address][txID] = make(map[int]int) + utxoPool.UtxoMap[out.Address][txID] = make(map[uint32]int) } - utxoPool.UtxoMap[out.Address][txID][index] = out.Value + utxoPool.UtxoMap[out.Address][txID][uint32(index)] = out.Value } } } // If it's a cross shard locking Tx, then don't update so the input UTXOs are locked (removed), and the money is not spendable until unlock-to-commit or unlock-to-abort @@ -275,12 +275,12 @@ func (utxoPool *UTXOPool) VerifyAndUpdate(transactions []*Transaction) bool { func CreateUTXOPoolFromTransaction(tx *Transaction, shardId uint32) *UTXOPool { var utxoPool UTXOPool txID := hex.EncodeToString(tx.ID[:]) - utxoPool.UtxoMap = make(map[string]map[string]map[int]int) - utxoPool.LockedUtxoMap = make(map[string]map[string]map[int]int) + utxoPool.UtxoMap = make(map[string]map[string]map[uint32]int) + utxoPool.LockedUtxoMap = make(map[string]map[string]map[uint32]int) for index, out := range tx.TxOutput { - 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 + utxoPool.UtxoMap[out.Address] = make(map[string]map[uint32]int) + utxoPool.UtxoMap[out.Address][txID] = make(map[uint32]int) + utxoPool.UtxoMap[out.Address][txID][uint32(index)] = out.Value } utxoPool.ShardId = shardId return &utxoPool @@ -296,7 +296,7 @@ func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool { // SelectTransactionsForNewBlock returns a list of index of valid transactions for the new block. func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transaction, maxNumTxs int) ([]*Transaction, []*Transaction, []*CrossShardTxAndProof) { selected, unselected, crossShardTxs := []*Transaction{}, []*Transaction{}, []*CrossShardTxAndProof{} - spentTXOs := make(map[string]map[string]map[int]bool) + spentTXOs := make(map[string]map[string]map[uint32]bool) for _, tx := range transactions { valid, crossShard := utxoPool.VerifyOneTransaction(tx, &spentTXOs) @@ -330,7 +330,7 @@ func getShardTxInput(transaction *Transaction, shardID uint32) []TXInput { } // DeleteOneBalanceItem deletes one balance item of UTXOPool and clean up if possible. -func (utxoPool *UTXOPool) DeleteOneUtxo(address, txID string, index int) { +func (utxoPool *UTXOPool) DeleteOneUtxo(address, txID string, index uint32) { delete(utxoPool.UtxoMap[address][txID], index) if len(utxoPool.UtxoMap[address][txID]) == 0 { delete(utxoPool.UtxoMap[address], txID) @@ -341,7 +341,7 @@ func (utxoPool *UTXOPool) DeleteOneUtxo(address, txID string, index int) { } // DeleteOneBalanceItem deletes one balance item of UTXOPool and clean up if possible. -func (utxoPool *UTXOPool) DeleteOneLockedUtxo(address, txID string, index int) { +func (utxoPool *UTXOPool) DeleteOneLockedUtxo(address, txID string, index uint32) { delete(utxoPool.LockedUtxoMap[address][txID], index) if len(utxoPool.LockedUtxoMap[address][txID]) == 0 { delete(utxoPool.LockedUtxoMap[address], txID) diff --git a/client/btctxgen/main.go b/client/btctxgen/main.go index b89c9f221..c0fb40be6 100644 --- a/client/btctxgen/main.go +++ b/client/btctxgen/main.go @@ -12,6 +12,7 @@ import ( "harmony-benchmark/node" "harmony-benchmark/p2p" proto_node "harmony-benchmark/proto/node" + "math" "sync" "time" @@ -77,8 +78,7 @@ LOOP: tx := blockchain.Transaction{} isCrossShardTx := false if btcTx.IsCoinBase() { - // TODO: merge txID with txIndex in TxInput - tx.TxInput = []blockchain.TXInput{*blockchain.NewTXInput(nil, "", nodeShardID)} + tx.TxInput = []blockchain.TXInput{*blockchain.NewTXInput(blockchain.NewOutPoint(&blockchain.Hash{}, math.MaxUint32), "", nodeShardID)} } else { for _, btcTXI := range btcTx.TxIn { btcTXIDStr := btc.NewUint256(btcTXI.Input.Hash[:]).String() @@ -86,7 +86,7 @@ LOOP: if txRef.shardID != nodeShardID { isCrossShardTx = true } - tx.TxInput = append(tx.TxInput, *blockchain.NewTXInput(blockchain.NewOutPoint(&txRef.txID, int(btcTXI.Input.Vout)), "", txRef.shardID)) + tx.TxInput = append(tx.TxInput, *blockchain.NewTXInput(blockchain.NewOutPoint(&txRef.txID, btcTXI.Input.Vout), "", txRef.shardID)) } } diff --git a/client/txgen/main.go b/client/txgen/main.go index 584a8d969..1d59a19ac 100644 --- a/client/txgen/main.go +++ b/client/txgen/main.go @@ -35,7 +35,7 @@ type TxInfo struct { dataNodes []*node.Node // Temp Input id [32]byte - index int + index uint32 value int address string // Output