Merge pull request #54 from simple-rules/ricl-utxo

Ricl utxo
pull/55/head
Richard Liu 6 years ago committed by GitHub
commit 26cfe7b1e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      blockchain/blockchain.go
  2. 62
      blockchain/transaction.go
  3. 102
      blockchain/utxopool.go
  4. 6
      blockchain/utxopool_test.go
  5. 6
      client/btctxgen/main.go
  6. 12
      client/txgen/main.go

@ -23,7 +23,7 @@ func (bc *Blockchain) GetLatestBlock() *Block {
// FindUnspentTransactions returns a list of transactions containing unspent outputs // FindUnspentTransactions returns a list of transactions containing unspent outputs
func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction { func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction {
var unspentTXs []Transaction var unspentTXs []Transaction
spentTXOs := make(map[string][]int) spentTXOs := make(map[string][]uint32)
for index := len(bc.Blocks) - 1; index >= 0; index-- { for index := len(bc.Blocks) - 1; index >= 0; index-- {
block := bc.Blocks[index] block := bc.Blocks[index]
@ -37,7 +37,7 @@ func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction {
idx = 0 idx = 0
} }
for outIdx, txOutput := range tx.TxOutput { for outIdx, txOutput := range tx.TxOutput {
if idx >= 0 && spentTXOs[txID][idx] == outIdx { if idx >= 0 && spentTXOs[txID][idx] == uint32(outIdx) {
idx++ idx++
continue continue
} }
@ -51,8 +51,8 @@ func (bc *Blockchain) FindUnspentTransactions(address string) []Transaction {
for _, txInput := range tx.TxInput { for _, txInput := range tx.TxInput {
if address == txInput.Address { if address == txInput.Address {
ID := hex.EncodeToString(txInput.TxID[:]) ID := hex.EncodeToString(txInput.PreviousOutPoint.TxID[:])
spentTXOs[ID] = append(spentTXOs[ID], txInput.TxOutputIndex) spentTXOs[ID] = append(spentTXOs[ID], txInput.PreviousOutPoint.Index)
} }
} }
} }
@ -78,8 +78,8 @@ func (bc *Blockchain) FindUTXO(address string) []TXOutput {
} }
// FindSpendableOutputs finds and returns unspent outputs to reference in inputs // FindSpendableOutputs finds and returns unspent outputs to reference in inputs
func (bc *Blockchain) FindSpendableOutputs(address string, amount int) (int, map[string][]int) { func (bc *Blockchain) FindSpendableOutputs(address string, amount int) (int, map[string][]uint32) {
unspentOutputs := make(map[string][]int) unspentOutputs := make(map[string][]uint32)
unspentTXs := bc.FindUnspentTransactions(address) unspentTXs := bc.FindUnspentTransactions(address)
accumulated := 0 accumulated := 0
@ -90,7 +90,7 @@ Work:
for outIdx, txOutput := range tx.TxOutput { for outIdx, txOutput := range tx.TxOutput {
if txOutput.Address == address && accumulated < amount { if txOutput.Address == address && accumulated < amount {
accumulated += txOutput.Value accumulated += txOutput.Value
unspentOutputs[txID] = append(unspentOutputs[txID], outIdx) unspentOutputs[txID] = append(unspentOutputs[txID], uint32(outIdx))
if accumulated >= amount { if accumulated >= amount {
break Work break Work
@ -103,7 +103,7 @@ Work:
} }
// NewUTXOTransaction creates a new transaction // 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 inputs []TXInput
var outputs []TXOutput var outputs []TXOutput
@ -120,18 +120,18 @@ func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int, shardId ui
return nil return nil
} }
txId := [32]byte{} txID := TxID{}
copy(txId[:], id[:]) copy(txID[:], id[:])
for _, out := range outs { for _, out := range outs {
input := TXInput{txId, out, from, shardId} input := NewTXInput(NewOutPoint(&txID, out), from, shardID)
inputs = append(inputs, input) inputs = append(inputs, *input)
} }
} }
// Build a list of outputs // Build a list of outputs
outputs = append(outputs, TXOutput{amount, to, shardId}) outputs = append(outputs, TXOutput{amount, to, shardID})
if acc > amount { 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} tx := Transaction{[32]byte{}, inputs, outputs, nil}

@ -7,9 +7,16 @@ import (
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"log" "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 TxID
) )
// Transaction represents a Bitcoin transaction
type Transaction struct { type Transaction struct {
ID [32]byte // 32 byte hash ID [32]byte // 32 byte hash
TxInput []TXInput TxInput []TXInput
@ -22,15 +29,44 @@ type Transaction struct {
type TXOutput struct { type TXOutput struct {
Value int Value int
Address string Address string
ShardId uint32 // The Id of the shard where this UTXO belongs ShardID uint32 // The Id of the shard where this UTXO belongs
}
type TxID = [32]byte
// Output defines a data type that is used to track previous
// transaction outputs.
// TxID is the transaction id
// Index is the index of the transaction ouput in the previous transaction
type OutPoint struct {
TxID TxID
Index uint32
}
// NewOutPoint returns a new transaction outpoint point with the
// provided txID and index.
func NewOutPoint(txID *TxID, index uint32) *OutPoint {
return &OutPoint{
TxID: *txID,
Index: index,
}
} }
// TXInput is the struct of transaction input (a UTXO) in a transaction. // TXInput is the struct of transaction input (a UTXO) in a transaction.
type TXInput struct { type TXInput struct {
TxID [32]byte PreviousOutPoint OutPoint
TxOutputIndex int Address string
Address string ShardID uint32 // The Id of the shard where this UTXO belongs
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. // The proof of accept or reject in the cross shard transaction locking phase.
@ -68,24 +104,24 @@ func (tx *Transaction) SetID() {
} }
// NewCoinbaseTX creates a new coinbase transaction // NewCoinbaseTX creates a new coinbase transaction
func NewCoinbaseTX(to, data string, shardId uint32) *Transaction { func NewCoinbaseTX(to, data string, shardID uint32) *Transaction {
if data == "" { if data == "" {
data = fmt.Sprintf("Reward to '%s'", to) data = fmt.Sprintf("Reward to '%s'", to)
} }
txin := TXInput{[32]byte{}, -1, data, shardId} txin := NewTXInput(NewOutPoint(&TxID{}, math.MaxUint32), to, shardID)
txout := TXOutput{DefaultCoinbaseValue, to, shardId} txout := TXOutput{DefaultCoinbaseValue, to, shardID}
tx := Transaction{[32]byte{}, []TXInput{txin}, []TXOutput{txout}, nil} tx := Transaction{[32]byte{}, []TXInput{*txin}, []TXOutput{txout}, nil}
tx.SetID() tx.SetID()
return &tx return &tx
} }
// Used for debuging. // Used for debuging.
func (txInput *TXInput) String() string { func (txInput *TXInput) String() string {
res := fmt.Sprintf("TxID: %v, ", hex.EncodeToString(txInput.TxID[:])) res := fmt.Sprintf("TxID: %v, ", hex.EncodeToString(txInput.PreviousOutPoint.TxID[:]))
res += fmt.Sprintf("TxOutputIndex: %v, ", txInput.TxOutputIndex) res += fmt.Sprintf("TxOutputIndex: %v, ", txInput.PreviousOutPoint.Index)
res += fmt.Sprintf("Address: %v, ", txInput.Address) 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 return res
} }

@ -8,6 +8,10 @@ import (
"sync" "sync"
) )
type Vout2AmountMap = map[uint32]int
type TXHash2Vout2AmountMap = map[string]Vout2AmountMap
type UtxoMap = map[string]TXHash2Vout2AmountMap
// 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 a map of the index of output // Mapping from address to a map of transaction id to a map of the index of output
@ -25,15 +29,15 @@ type UTXOPool struct {
] ]
] ]
*/ */
UtxoMap map[string]map[string]map[int]int UtxoMap UtxoMap
LockedUtxoMap map[string]map[string]map[int]int LockedUtxoMap UtxoMap
ShardId uint32 ShardID uint32
mutex sync.Mutex mutex sync.Mutex
} }
// VerifyTransactions verifies if a list of transactions valid for this shard. // VerifyTransactions verifies if a list of transactions valid for this shard.
func (utxoPool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool { 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 { if utxoPool != nil {
for _, tx := range transactions { for _, tx := range transactions {
if valid, crossShard := utxoPool.VerifyOneTransaction(tx, &spentTXOs); !crossShard && !valid { if valid, crossShard := utxoPool.VerifyOneTransaction(tx, &spentTXOs); !crossShard && !valid {
@ -45,25 +49,25 @@ func (utxoPool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool {
} }
// VerifyOneTransaction verifies if a list of transactions valid. // 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 { if len(tx.Proofs) != 0 {
return utxoPool.VerifyUnlockTransaction(tx) return utxoPool.VerifyUnlockTransaction(tx)
} }
if spentTXOs == nil { if spentTXOs == nil {
spentTXOs = &map[string]map[string]map[int]bool{} spentTXOs = &map[string]map[string]map[uint32]bool{}
} }
inTotal := 0 inTotal := 0
// Calculate the sum of TxInput // Calculate the sum of TxInput
for _, in := range tx.TxInput { for _, in := range tx.TxInput {
// Only check the input for my own shard. // Only check the input for my own shard.
if in.ShardId != utxoPool.ShardId { if in.ShardID != utxoPool.ShardID {
crossShard = true crossShard = true
continue continue
} }
inTxID := hex.EncodeToString(in.TxID[:]) inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:])
index := in.TxOutputIndex index := in.PreviousOutPoint.Index
// Check if the transaction with the addres is spent or not. // Check if the transaction with the addres is spent or not.
if val, ok := (*spentTXOs)[in.Address][inTxID][index]; ok { if val, ok := (*spentTXOs)[in.Address][inTxID][index]; ok {
if val { if val {
@ -72,10 +76,10 @@ func (utxoPool *UTXOPool) VerifyOneTransaction(tx *Transaction, spentTXOs *map[s
} }
// Mark the transactions with the address and index spent. // Mark the transactions with the address and index spent.
if _, ok := (*spentTXOs)[in.Address]; !ok { 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 { 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 (*spentTXOs)[in.Address][inTxID][index] = true
@ -150,7 +154,7 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) {
isCrossShard := false isCrossShard := false
// check whether it's a cross shard tx. // check whether it's a cross shard tx.
for _, in := range tx.TxInput { for _, in := range tx.TxInput {
if in.ShardId != utxoPool.ShardId { if in.ShardID != utxoPool.ShardID {
isCrossShard = true isCrossShard = true
break break
} }
@ -161,11 +165,11 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) {
// Check whether for this shard this cross transaction is valid or not. // Check whether for this shard this cross transaction is valid or not.
for _, in := range tx.TxInput { for _, in := range tx.TxInput {
// Only check the input for my own shard. // Only check the input for my own shard.
if in.ShardId != utxoPool.ShardId { if in.ShardID != utxoPool.ShardID {
continue continue
} }
inTxID := hex.EncodeToString(in.TxID[:]) inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:])
if _, ok := utxoPool.UtxoMap[in.Address][inTxID][in.TxOutputIndex]; !ok { if _, ok := utxoPool.UtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index]; !ok {
isValidCrossShard = false isValidCrossShard = false
} }
} }
@ -181,25 +185,25 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) {
if isValidCrossShard { if isValidCrossShard {
for _, in := range tx.TxInput { for _, in := range tx.TxInput {
// Only check the input for my own shard. // Only check the input for my own shard.
if in.ShardId != utxoPool.ShardId { if in.ShardID != utxoPool.ShardID {
continue continue
} }
// NOTE: for the locking phase of cross tx, the utxo is simply removed from the pool. // NOTE: for the locking phase of cross tx, the utxo is simply removed from the pool.
inTxID := hex.EncodeToString(in.TxID[:]) inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:])
value := utxoPool.UtxoMap[in.Address][inTxID][in.TxOutputIndex] value := utxoPool.UtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index]
utxoPool.DeleteOneUtxo(in.Address, inTxID, in.TxOutputIndex) utxoPool.DeleteOneUtxo(in.Address, inTxID, in.PreviousOutPoint.Index)
if isCrossShard { if isCrossShard {
// put the delete (locked) utxo into a separate locked utxo pool // put the delete (locked) utxo into a separate locked utxo pool
inTxID := hex.EncodeToString(in.TxID[:]) inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:])
if _, ok := utxoPool.LockedUtxoMap[in.Address]; !ok { if _, ok := utxoPool.LockedUtxoMap[in.Address]; !ok {
utxoPool.LockedUtxoMap[in.Address] = make(map[string]map[int]int) utxoPool.LockedUtxoMap[in.Address] = make(TXHash2Vout2AmountMap)
utxoPool.LockedUtxoMap[in.Address][inTxID] = make(map[int]int) utxoPool.LockedUtxoMap[in.Address][inTxID] = make(Vout2AmountMap)
} }
if _, ok := utxoPool.LockedUtxoMap[in.Address][inTxID]; !ok { if _, ok := utxoPool.LockedUtxoMap[in.Address][inTxID]; !ok {
utxoPool.LockedUtxoMap[in.Address][inTxID] = make(map[int]int) utxoPool.LockedUtxoMap[in.Address][inTxID] = make(Vout2AmountMap)
} }
utxoPool.LockedUtxoMap[in.Address][inTxID][in.TxOutputIndex] = value utxoPool.LockedUtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index] = value
} }
} }
} }
@ -212,40 +216,40 @@ func (utxoPool *UTXOPool) UpdateOneTransaction(tx *Transaction) {
// unlock-to-abort, bring back (unlock) the utxo input // unlock-to-abort, bring back (unlock) the utxo input
for _, in := range tx.TxInput { for _, in := range tx.TxInput {
// Only unlock the input for my own shard. // Only unlock the input for my own shard.
if in.ShardId != utxoPool.ShardId { if in.ShardID != utxoPool.ShardID {
continue continue
} }
// Simply bring back the locked (removed) utxo // Simply bring back the locked (removed) utxo
inTxID := hex.EncodeToString(in.TxID[:]) inTxID := hex.EncodeToString(in.PreviousOutPoint.TxID[:])
if _, ok := utxoPool.UtxoMap[in.Address]; !ok { if _, ok := utxoPool.UtxoMap[in.Address]; !ok {
utxoPool.UtxoMap[in.Address] = make(map[string]map[int]int) utxoPool.UtxoMap[in.Address] = make(TXHash2Vout2AmountMap)
utxoPool.UtxoMap[in.Address][inTxID] = make(map[int]int) utxoPool.UtxoMap[in.Address][inTxID] = make(Vout2AmountMap)
} }
if _, ok := utxoPool.UtxoMap[in.Address][inTxID]; !ok { if _, ok := utxoPool.UtxoMap[in.Address][inTxID]; !ok {
utxoPool.UtxoMap[in.Address][inTxID] = make(map[int]int) utxoPool.UtxoMap[in.Address][inTxID] = make(Vout2AmountMap)
} }
value := utxoPool.LockedUtxoMap[in.Address][inTxID][in.TxOutputIndex] value := utxoPool.LockedUtxoMap[in.Address][inTxID][in.PreviousOutPoint.Index]
utxoPool.UtxoMap[in.Address][inTxID][in.TxOutputIndex] = value 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 { } else {
// normal utxo output update // normal utxo output update
for index, out := range tx.TxOutput { for index, out := range tx.TxOutput {
// Only check the input for my own shard. // Only check the input for my own shard.
if out.ShardId != utxoPool.ShardId { if out.ShardID != utxoPool.ShardID {
continue continue
} }
if _, ok := utxoPool.UtxoMap[out.Address]; !ok { if _, ok := utxoPool.UtxoMap[out.Address]; !ok {
utxoPool.UtxoMap[out.Address] = make(map[string]map[int]int) utxoPool.UtxoMap[out.Address] = make(TXHash2Vout2AmountMap)
utxoPool.UtxoMap[out.Address][txID] = make(map[int]int) utxoPool.UtxoMap[out.Address][txID] = make(Vout2AmountMap)
} }
if _, ok := utxoPool.UtxoMap[out.Address][txID]; !ok { if _, ok := utxoPool.UtxoMap[out.Address][txID]; !ok {
utxoPool.UtxoMap[out.Address][txID] = make(map[int]int) utxoPool.UtxoMap[out.Address][txID] = make(Vout2AmountMap)
} }
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 } // 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,14 +279,14 @@ func (utxoPool *UTXOPool) VerifyAndUpdate(transactions []*Transaction) bool {
func CreateUTXOPoolFromTransaction(tx *Transaction, shardId uint32) *UTXOPool { func CreateUTXOPoolFromTransaction(tx *Transaction, shardId uint32) *UTXOPool {
var utxoPool UTXOPool var utxoPool UTXOPool
txID := hex.EncodeToString(tx.ID[:]) txID := hex.EncodeToString(tx.ID[:])
utxoPool.UtxoMap = make(map[string]map[string]map[int]int) utxoPool.UtxoMap = make(UtxoMap)
utxoPool.LockedUtxoMap = make(map[string]map[string]map[int]int) utxoPool.LockedUtxoMap = make(UtxoMap)
for index, out := range tx.TxOutput { for index, out := range tx.TxOutput {
utxoPool.UtxoMap[out.Address] = make(map[string]map[int]int) utxoPool.UtxoMap[out.Address] = make(TXHash2Vout2AmountMap)
utxoPool.UtxoMap[out.Address][txID] = make(map[int]int) utxoPool.UtxoMap[out.Address][txID] = make(Vout2AmountMap)
utxoPool.UtxoMap[out.Address][txID][index] = out.Value utxoPool.UtxoMap[out.Address][txID][uint32(index)] = out.Value
} }
utxoPool.ShardId = shardId utxoPool.ShardID = shardId
return &utxoPool return &utxoPool
} }
@ -296,7 +300,7 @@ func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool {
// SelectTransactionsForNewBlock returns a list of index of valid transactions for the new block. // SelectTransactionsForNewBlock returns a list of index of valid transactions for the new block.
func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transaction, maxNumTxs int) ([]*Transaction, []*Transaction, []*CrossShardTxAndProof) { func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transaction, maxNumTxs int) ([]*Transaction, []*Transaction, []*CrossShardTxAndProof) {
selected, unselected, crossShardTxs := []*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 { for _, tx := range transactions {
valid, crossShard := utxoPool.VerifyOneTransaction(tx, &spentTXOs) valid, crossShard := utxoPool.VerifyOneTransaction(tx, &spentTXOs)
@ -304,7 +308,7 @@ func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transact
if valid || crossShard { if valid || crossShard {
selected = append(selected, tx) selected = append(selected, tx)
if crossShard { if crossShard {
proof := CrossShardTxProof{Accept: valid, TxID: tx.ID, TxInput: getShardTxInput(tx, utxoPool.ShardId)} proof := CrossShardTxProof{Accept: valid, TxID: tx.ID, TxInput: getShardTxInput(tx, utxoPool.ShardID)}
txAndProof := CrossShardTxAndProof{tx, &proof} txAndProof := CrossShardTxAndProof{tx, &proof}
crossShardTxs = append(crossShardTxs, &txAndProof) crossShardTxs = append(crossShardTxs, &txAndProof)
} }
@ -319,10 +323,10 @@ func (utxoPool *UTXOPool) SelectTransactionsForNewBlock(transactions []*Transact
return selected, unselected, crossShardTxs return selected, unselected, crossShardTxs
} }
func getShardTxInput(transaction *Transaction, shardId uint32) []TXInput { func getShardTxInput(transaction *Transaction, shardID uint32) []TXInput {
result := []TXInput{} result := []TXInput{}
for _, txInput := range transaction.TxInput { for _, txInput := range transaction.TxInput {
if txInput.ShardId == shardId { if txInput.ShardID == shardID {
result = append(result, txInput) result = append(result, txInput)
} }
} }
@ -330,7 +334,7 @@ func getShardTxInput(transaction *Transaction, shardId uint32) []TXInput {
} }
// DeleteOneBalanceItem deletes one balance item of UTXOPool and clean up if possible. // 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) delete(utxoPool.UtxoMap[address][txID], index)
if len(utxoPool.UtxoMap[address][txID]) == 0 { if len(utxoPool.UtxoMap[address][txID]) == 0 {
delete(utxoPool.UtxoMap[address], txID) delete(utxoPool.UtxoMap[address], txID)
@ -341,7 +345,7 @@ func (utxoPool *UTXOPool) DeleteOneUtxo(address, txID string, index int) {
} }
// DeleteOneBalanceItem deletes one balance item of UTXOPool and clean up if possible. // 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) delete(utxoPool.LockedUtxoMap[address][txID], index)
if len(utxoPool.LockedUtxoMap[address][txID]) == 0 { if len(utxoPool.LockedUtxoMap[address][txID]) == 0 {
delete(utxoPool.LockedUtxoMap[address], txID) delete(utxoPool.LockedUtxoMap[address], txID)

@ -54,9 +54,9 @@ func TestDeleteOneBalanceItem(t *testing.T) {
func TestCleanUp(t *testing.T) { func TestCleanUp(t *testing.T) {
var utxoPool UTXOPool var utxoPool UTXOPool
utxoPool.UtxoMap = make(map[string]map[string]map[int]int) utxoPool.UtxoMap = make(UtxoMap)
utxoPool.UtxoMap["minh"] = make(map[string]map[int]int) utxoPool.UtxoMap["minh"] = make(TXHash2Vout2AmountMap)
utxoPool.UtxoMap["rj"] = map[string]map[int]int{ utxoPool.UtxoMap["rj"] = TXHash2Vout2AmountMap{
"abcd": { "abcd": {
0: 1, 0: 1,
}, },

@ -12,6 +12,7 @@ import (
"harmony-benchmark/node" "harmony-benchmark/node"
"harmony-benchmark/p2p" "harmony-benchmark/p2p"
proto_node "harmony-benchmark/proto/node" proto_node "harmony-benchmark/proto/node"
"math"
"sync" "sync"
"time" "time"
@ -77,8 +78,7 @@ LOOP:
tx := blockchain.Transaction{} tx := blockchain.Transaction{}
isCrossShardTx := false isCrossShardTx := false
if btcTx.IsCoinBase() { if btcTx.IsCoinBase() {
// TODO: merge txID with txIndex in TxInput tx.TxInput = []blockchain.TXInput{*blockchain.NewTXInput(blockchain.NewOutPoint(&blockchain.TxID{}, math.MaxUint32), "", nodeShardID)}
tx.TxInput = []blockchain.TXInput{blockchain.TXInput{[32]byte{}, -1, "", nodeShardID}}
} else { } else {
for _, btcTXI := range btcTx.TxIn { for _, btcTXI := range btcTx.TxIn {
btcTXIDStr := btc.NewUint256(btcTXI.Input.Hash[:]).String() btcTXIDStr := btc.NewUint256(btcTXI.Input.Hash[:]).String()
@ -86,7 +86,7 @@ LOOP:
if txRef.shardID != nodeShardID { if txRef.shardID != nodeShardID {
isCrossShardTx = true 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, btcTXI.Input.Vout), "", txRef.shardID))
} }
} }

@ -35,7 +35,7 @@ type TxInfo struct {
dataNodes []*node.Node dataNodes []*node.Node
// Temp Input // Temp Input
id [32]byte id [32]byte
index int index uint32
value int value int
address string address string
// Output // Output
@ -145,7 +145,7 @@ func generateCrossShardTx(txInfo *TxInfo) {
for crossShardIndex, crossShardValue := range crossShardUtxos { for crossShardIndex, crossShardValue := range crossShardUtxos {
crossUtxoValue = crossShardValue crossUtxoValue = crossShardValue
crossTxin = &blockchain.TXInput{crossTxId, crossShardIndex, txInfo.address, uint32(crossShardId)} crossTxin = blockchain.NewTXInput(blockchain.NewOutPoint(&crossTxId, crossShardIndex), txInfo.address, uint32(crossShardId))
break break
} }
if crossTxin != nil { if crossTxin != nil {
@ -154,8 +154,8 @@ func generateCrossShardTx(txInfo *TxInfo) {
} }
// Add the utxo from current shard // Add the utxo from current shard
txin := blockchain.TXInput{txInfo.id, txInfo.index, txInfo.address, nodeShardID} txIn := blockchain.NewTXInput(blockchain.NewOutPoint(&txInfo.id, txInfo.index), txInfo.address, nodeShardID)
txInputs := []blockchain.TXInput{txin} txInputs := []blockchain.TXInput{*txIn}
// Add the utxo from the other shard, if any // 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 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) { func generateSingleShardTx(txInfo *TxInfo) {
nodeShardID := txInfo.dataNodes[txInfo.shardID].Consensus.ShardID nodeShardID := txInfo.dataNodes[txInfo.shardID].Consensus.ShardID
// Add the utxo as new tx input // 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) // Spend the utxo to a random address in [0 - N)
txout := blockchain.TXOutput{txInfo.value, strconv.Itoa(rand.Intn(setting.numOfAddress)), nodeShardID} 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() tx.SetID()
txInfo.txs = append(txInfo.txs, &tx) txInfo.txs = append(txInfo.txs, &tx)

Loading…
Cancel
Save