From 09286bb82a6e307d8333ab94284de16888cebb6b Mon Sep 17 00:00:00 2001 From: Richard Liu Date: Sat, 4 Aug 2018 23:46:23 -0700 Subject: [PATCH] add outpoint --- blockchain/blockchain.go | 18 +++++++------- blockchain/transaction.go | 51 ++++++++++++++++++++++++++++++--------- blockchain/utxopool.go | 40 +++++++++++++++--------------- client/btctxgen/main.go | 4 +-- client/txgen/main.go | 10 ++++---- 5 files changed, 76 insertions(+), 47 deletions(-) diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 2f2e8b91f..b9f4d01cf 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -51,8 +51,8 @@ func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction { for _, txInput := range tx.TxInput { if address == txInput.Address { - ID := hex.EncodeToString(txInput.TxID[:]) - spentTXOs[ID] = append(spentTXOs[ID], txInput.TxOutputIndex) + ID := hex.EncodeToString(txInput.PreviousOutPoint.Hash[:]) + spentTXOs[ID] = append(spentTXOs[ID], txInput.PreviousOutPoint.Index) } } } @@ -103,7 +103,7 @@ Work: } // NewUTXOTransaction creates a new transaction -func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int, shardId uint32) *Transaction { +func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int, shardID uint32) *Transaction { var inputs []TXInput var outputs []TXOutput @@ -120,18 +120,18 @@ func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int, shardId ui return nil } - txId := [32]byte{} - copy(txId[:], id[:]) + txID := Hash{} + copy(txID[:], id[:]) for _, out := range outs { - input := TXInput{txId, out, from, shardId} - inputs = append(inputs, input) + input := NewTXInput(NewOutPoint(&txID, out), from, shardID) + inputs = append(inputs, *input) } } // Build a list of outputs - outputs = append(outputs, TXOutput{amount, to, shardId}) + outputs = append(outputs, TXOutput{amount, to, shardID}) if acc > amount { - outputs = append(outputs, TXOutput{acc - amount, from, shardId}) // a change + outputs = append(outputs, TXOutput{acc - amount, from, shardID}) // a change } tx := Transaction{[32]byte{}, inputs, outputs, nil} diff --git a/blockchain/transaction.go b/blockchain/transaction.go index 23e888032..a1840e9e0 100644 --- a/blockchain/transaction.go +++ b/blockchain/transaction.go @@ -25,12 +25,41 @@ type TXOutput struct { ShardId uint32 // The Id of the shard where this UTXO belongs } +type Hash = [32]byte + +// Output defines a data type that is used to track previous +// transaction outputs. +// Hash is the transaction id +// Index is the index of the transaction ouput in the previous transaction +type OutPoint struct { + Hash Hash + Index int +} + +// NewOutPoint returns a new transaction outpoint point with the +// provided hash and index. +func NewOutPoint(hash *Hash, index int) *OutPoint { + return &OutPoint{ + Hash: *hash, + Index: index, + } +} + // TXInput is the struct of transaction input (a UTXO) in a transaction. type TXInput struct { - TxID [32]byte - TxOutputIndex int - Address string - ShardId uint32 // The Id of the shard where this UTXO belongs + PreviousOutPoint OutPoint + Address string + ShardID uint32 // The Id of the shard where this UTXO belongs +} + +// NewTXInput returns a new transaction input with the provided +// previous outpoint point, output address and shardID +func NewTXInput(prevOut *OutPoint, address string, shardID uint32) *TXInput { + return &TXInput{ + PreviousOutPoint: *prevOut, + Address: address, + ShardID: shardID, + } } // The proof of accept or reject in the cross shard transaction locking phase. @@ -68,24 +97,24 @@ func (tx *Transaction) SetID() { } // NewCoinbaseTX creates a new coinbase transaction -func NewCoinbaseTX(to, data string, shardId uint32) *Transaction { +func NewCoinbaseTX(to, data string, shardID uint32) *Transaction { if data == "" { data = fmt.Sprintf("Reward to '%s'", to) } - txin := TXInput{[32]byte{}, -1, data, shardId} - txout := TXOutput{DefaultCoinbaseValue, to, shardId} - tx := Transaction{[32]byte{}, []TXInput{txin}, []TXOutput{txout}, nil} + txin := NewTXInput(nil, to, shardID) + txout := TXOutput{DefaultCoinbaseValue, to, shardID} + tx := Transaction{[32]byte{}, []TXInput{*txin}, []TXOutput{txout}, nil} tx.SetID() return &tx } // Used for debuging. func (txInput *TXInput) String() string { - res := fmt.Sprintf("TxID: %v, ", hex.EncodeToString(txInput.TxID[:])) - res += fmt.Sprintf("TxOutputIndex: %v, ", txInput.TxOutputIndex) + res := fmt.Sprintf("TxID: %v, ", hex.EncodeToString(txInput.PreviousOutPoint.Hash[:])) + res += fmt.Sprintf("TxOutputIndex: %v, ", txInput.PreviousOutPoint.Index) res += fmt.Sprintf("Address: %v, ", txInput.Address) - res += fmt.Sprintf("Shard Id: %v", txInput.ShardId) + res += fmt.Sprintf("Shard Id: %v", txInput.ShardID) return res } diff --git a/blockchain/utxopool.go b/blockchain/utxopool.go index 0adcebf9b..0be9bd0cf 100644 --- a/blockchain/utxopool.go +++ b/blockchain/utxopool.go @@ -57,13 +57,13 @@ func (utxoPool *UTXOPool) VerifyOneTransaction(tx *Transaction, spentTXOs *map[s // Calculate the sum of TxInput for _, in := range tx.TxInput { // Only check the input for my own shard. - if in.ShardId != utxoPool.ShardId { + if in.ShardID != utxoPool.ShardId { crossShard = true continue } - inTxID := hex.EncodeToString(in.TxID[:]) - index := in.TxOutputIndex + inTxID := hex.EncodeToString(in.PreviousOutPoint.Hash[:]) + index := in.PreviousOutPoint.Index // Check if the transaction with the addres is spent or not. if val, ok := (*spentTXOs)[in.Address][inTxID][index]; ok { if val { @@ -150,7 +150,7 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { isCrossShard := false // check whether it's a cross shard tx. for _, in := range tx.TxInput { - if in.ShardId != utxoPool.ShardId { + if in.ShardID != utxoPool.ShardId { isCrossShard = true break } @@ -161,11 +161,11 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { // Check whether for this shard this cross transaction is valid or not. for _, in := range tx.TxInput { // Only check the input for my own shard. - if in.ShardId != utxoPool.ShardId { + if in.ShardID != utxoPool.ShardId { continue } - inTxID := hex.EncodeToString(in.TxID[:]) - if _, ok := utxoPool.UtxoMap[in.Address][inTxID][in.TxOutputIndex]; !ok { + inTxID := hex.EncodeToString(in.PreviousOutPoint.Hash[:]) + if _, ok := utxoPool.UtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index]; !ok { isValidCrossShard = false } } @@ -181,17 +181,17 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { if isValidCrossShard { for _, in := range tx.TxInput { // Only check the input for my own shard. - if in.ShardId != utxoPool.ShardId { + if in.ShardID != utxoPool.ShardId { continue } // NOTE: for the locking phase of cross tx, the utxo is simply removed from the pool. - inTxID := hex.EncodeToString(in.TxID[:]) - value := utxoPool.UtxoMap[in.Address][inTxID][in.TxOutputIndex] - utxoPool.DeleteOneUtxo(in.Address, inTxID, in.TxOutputIndex) + inTxID := hex.EncodeToString(in.PreviousOutPoint.Hash[:]) + value := utxoPool.UtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index] + utxoPool.DeleteOneUtxo(in.Address, inTxID, in.PreviousOutPoint.Index) if isCrossShard { // put the delete (locked) utxo into a separate locked utxo pool - inTxID := hex.EncodeToString(in.TxID[:]) + 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) @@ -199,7 +199,7 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { if _, ok := utxoPool.LockedUtxoMap[in.Address][inTxID]; !ok { utxoPool.LockedUtxoMap[in.Address][inTxID] = make(map[int]int) } - utxoPool.LockedUtxoMap[in.Address][inTxID][in.TxOutputIndex] = value + utxoPool.LockedUtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index] = value } } } @@ -212,12 +212,12 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { // unlock-to-abort, bring back (unlock) the utxo input for _, in := range tx.TxInput { // Only unlock the input for my own shard. - if in.ShardId != utxoPool.ShardId { + if in.ShardID != utxoPool.ShardId { continue } // Simply bring back the locked (removed) utxo - inTxID := hex.EncodeToString(in.TxID[:]) + 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) @@ -225,10 +225,10 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) { if _, ok := utxoPool.UtxoMap[in.Address][inTxID]; !ok { utxoPool.UtxoMap[in.Address][inTxID] = make(map[int]int) } - value := utxoPool.LockedUtxoMap[in.Address][inTxID][in.TxOutputIndex] - utxoPool.UtxoMap[in.Address][inTxID][in.TxOutputIndex] = value + value := utxoPool.LockedUtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index] + utxoPool.UtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index] = value - utxoPool.DeleteOneLockedUtxo(in.Address, inTxID, in.TxOutputIndex) + utxoPool.DeleteOneLockedUtxo(in.Address, inTxID, in.PreviousOutPoint.Index) } } } else { @@ -319,10 +319,10 @@ func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transact return selected, unselected, crossShardTxs } -func getShardTxInput(transaction *Transaction, shardId uint32) []TXInput { +func getShardTxInput(transaction *Transaction, shardID uint32) []TXInput { result := []TXInput{} for _, txInput := range transaction.TxInput { - if txInput.ShardId == shardId { + if txInput.ShardID == shardID { result = append(result, txInput) } } diff --git a/client/btctxgen/main.go b/client/btctxgen/main.go index d7495e6f6..b89c9f221 100644 --- a/client/btctxgen/main.go +++ b/client/btctxgen/main.go @@ -78,7 +78,7 @@ LOOP: isCrossShardTx := false if btcTx.IsCoinBase() { // TODO: merge txID with txIndex in TxInput - tx.TxInput = []blockchain.TXInput{blockchain.TXInput{[32]byte{}, -1, "", nodeShardID}} + tx.TxInput = []blockchain.TXInput{*blockchain.NewTXInput(nil, "", 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.TXInput{txRef.txID, int(btcTXI.Input.Vout), "", txRef.shardID}) + tx.TxInput = append(tx.TxInput, *blockchain.NewTXInput(blockchain.NewOutPoint(&txRef.txID, int(btcTXI.Input.Vout)), "", txRef.shardID)) } } diff --git a/client/txgen/main.go b/client/txgen/main.go index 0a7423bd6..584a8d969 100644 --- a/client/txgen/main.go +++ b/client/txgen/main.go @@ -145,7 +145,7 @@ func generateCrossShardTx(txInfo *TxInfo) { for crossShardIndex, crossShardValue := range crossShardUtxos { crossUtxoValue = crossShardValue - crossTxin = &blockchain.TXInput{crossTxId, crossShardIndex, txInfo.address, uint32(crossShardId)} + crossTxin = blockchain.NewTXInput(blockchain.NewOutPoint(&crossTxId, crossShardIndex), txInfo.address, uint32(crossShardId)) break } if crossTxin != nil { @@ -154,8 +154,8 @@ func generateCrossShardTx(txInfo *TxInfo) { } // Add the utxo from current shard - txin := blockchain.TXInput{txInfo.id, txInfo.index, txInfo.address, nodeShardID} - txInputs := []blockchain.TXInput{txin} + txIn := blockchain.NewTXInput(blockchain.NewOutPoint(&txInfo.id, txInfo.index), txInfo.address, nodeShardID) + txInputs := []blockchain.TXInput{*txIn} // Add the utxo from the other shard, if any if crossTxin != nil { // This means the ratio of cross shard tx could be lower than 1/3 @@ -183,11 +183,11 @@ func generateCrossShardTx(txInfo *TxInfo) { func generateSingleShardTx(txInfo *TxInfo) { nodeShardID := txInfo.dataNodes[txInfo.shardID].Consensus.ShardID // Add the utxo as new tx input - txin := blockchain.TXInput{txInfo.id, txInfo.index, txInfo.address, nodeShardID} + txin := blockchain.NewTXInput(blockchain.NewOutPoint(&txInfo.id, txInfo.index), txInfo.address, nodeShardID) // Spend the utxo to a random address in [0 - N) txout := blockchain.TXOutput{txInfo.value, strconv.Itoa(rand.Intn(setting.numOfAddress)), nodeShardID} - tx := blockchain.Transaction{[32]byte{}, []blockchain.TXInput{txin}, []blockchain.TXOutput{txout}, nil} + tx := blockchain.Transaction{[32]byte{}, []blockchain.TXInput{*txin}, []blockchain.TXOutput{txout}, nil} tx.SetID() txInfo.txs = append(txInfo.txs, &tx)