From c45ed9439fe9b27eee044a15e489c01ada336318 Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Sun, 17 Jun 2018 05:44:32 -0700 Subject: [PATCH 1/6] update utxopool --- blockchain/utxopool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blockchain/utxopool.go b/blockchain/utxopool.go index 399071488..66d1b1c0d 100644 --- a/blockchain/utxopool.go +++ b/blockchain/utxopool.go @@ -8,7 +8,7 @@ import ( type UTXOPool struct { // 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. - utxo map[string]map[string]int + utxo map[string]map[string]map[int]int } // VerifyTransactions verifies if a list of transactions valid. From b94be925a04681f87db3873b7e90fb21c2391988 Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Sun, 17 Jun 2018 05:45:48 -0700 Subject: [PATCH 2/6] fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1f3aac11b..4184cbb1d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ mkdir -p $HOME//src cd $HOME//src -clone +git clone git@github.com:simple-rules/harmony-benchmark.git ``` ## Usage ``` From 5f5abd3e46f9fecb8a41c69fe1673919d3e8098e Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Sun, 17 Jun 2018 05:54:39 -0700 Subject: [PATCH 3/6] add slack notification --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 635126ff2..42e529457 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,12 @@ language: go - go: - - master +- master install: | export GOPATH=$HOME/gopath mkdir -p $HOME/gopath/src/harmony-benchmark rsync -az ${TRAVIS_BUILD_DIR}/ $HOME/gopath/src/harmony-benchmark/ export TRAVIS_BUILD_DIR=$HOME/gopath/src/harmony-benchmark - cd $HOME/gopath/src/harmony-benchmark \ No newline at end of file + cd $HOME/gopath/src/harmony-benchmark +notifications: + slack: + secure: F6PRLJ7fIVpvZAEAIikE9u53CwklytznkNSJPuzB7cxLttAejls8ou3jsFFUkdTyyyy+QKFP9Bj+IFcAI9dq3CDYp7MnTQx/ajn8TC0xBwKW3gEKYoptIQJkXzvdwp9OanpU78QynRe1oRLefkN8qrL0zWLvoqcaHSYwjh1kzDCbO9G13aiI5CiFdW7jKwBKEPlleze4so0UdAaaGxyXUiSsmvHrOwF72ElnahKLy9DzmIgT8PdQkf1BmV3yaH3VQoU4fyu8t5P/jy8NYIXomcpo+pavgUBfXwd3mPf1KkAoB2RXdGCkORzHNZ6h+63ZVDzi1t8FWAbuNmvJ/Hq07IScGcsjZCEdy+79NSSBHThUejnHnqD4QdcXdhr30PoWBX85+phwPEVehAtddzgLyzivGByKHQMfWcetvPRww7Im+MpJW3OssgHlPxbRCE0uFtSDYgD9UoKevuZzFnME3U1rT9xqTweqOzxdsGRpvU/fLbh0PQCJnDQJjOB054l6ZTu9mtt+ogbYpOhB2PO6qLJZ64cn7M5/wLMiswRWooT9DeN+5a7n5MRo1i/TWFDFWBFYQVWTYdiTaU+oZdSZsu25TMboVraHPw3HE5tKIGgqOBLLd187HbE5ZeR62bzUnlN1wK1tphfgVa4ztmL+NY9nTgHMKki7LiNIL1p7M68= From 6a48a4d810bab1255672a5612584ea8db4a23037 Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Sun, 17 Jun 2018 16:03:26 -0700 Subject: [PATCH 4/6] decouple CreateBlockchain and UTXOPool into different methods --- blockchain/block_test.go | 4 ++-- blockchain/blockchain.go | 6 +++--- blockchain/blockchain_test.go | 13 ++++++++----- blockchain/transaction.go | 11 ++--------- blockchain/transaction_test.go | 2 +- blockchain/utxopool.go | 31 ++++++++++++++++++++++++++++--- blockchain/utxopool_test.go | 2 +- 7 files changed, 45 insertions(+), 24 deletions(-) diff --git a/blockchain/block_test.go b/blockchain/block_test.go index 61df9d6e5..623890e8f 100644 --- a/blockchain/block_test.go +++ b/blockchain/block_test.go @@ -6,8 +6,8 @@ import ( ) func TestBlockSerialize(t *testing.T) { - cbtx, utxoPool := NewCoinbaseTX("minh", genesisCoinbaseData) - if cbtx == nil || utxoPool == nil { + cbtx := NewCoinbaseTX("minh", genesisCoinbaseData) + if cbtx == nil { t.Errorf("Failed to create a coinbase transaction.") } block := NewGenesisBlock(cbtx) diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 69abb82a3..44ab3d8bc 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -161,13 +161,13 @@ func (bc *Blockchain) VerifyNewBlockAndUpdate(utxopool *UTXOPool, block *Block) } // CreateBlockchain creates a new blockchain DB -func CreateBlockchain(address string) (*Blockchain, *UTXOPool) { +func CreateBlockchain(address string) *Blockchain { // TODO: We assume we have not created any blockchain before. // In current bitcoin, we can check if we created a blockchain before accessing local db. - cbtx, utxoPool := NewCoinbaseTX(address, genesisCoinbaseData) + cbtx := NewCoinbaseTX(address, genesisCoinbaseData) genesis := NewGenesisBlock(cbtx) bc := Blockchain{[]*Block{genesis}} - return &bc, utxoPool + return &bc } diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go index ab0c57610..b4318367c 100644 --- a/blockchain/blockchain_test.go +++ b/blockchain/blockchain_test.go @@ -5,14 +5,14 @@ import ( ) func TestCreateBlockchain(t *testing.T) { - if bc, _ := CreateBlockchain("minh"); bc == nil { + if bc := CreateBlockchain("minh"); bc == nil { t.Errorf("failed to create a blockchain") } } func TestFindSpendableOutputs(t *testing.T) { requestAmount := 3 - bc, _ := CreateBlockchain("minh") + bc := CreateBlockchain("minh") accumulated, unspentOutputs := bc.FindSpendableOutputs("minh", requestAmount) if accumulated < DefaultCoinbaseValue { t.Error("Failed to find enough unspent ouptuts") @@ -24,7 +24,7 @@ func TestFindSpendableOutputs(t *testing.T) { } func TestFindUTXO(t *testing.T) { - bc, _ := CreateBlockchain("minh") + bc := CreateBlockchain("minh") utxo := bc.FindUTXO("minh") total := 0 @@ -41,7 +41,8 @@ func TestFindUTXO(t *testing.T) { } func TestAddNewUserTransfer(t *testing.T) { - bc, utxoPool := CreateBlockchain("minh") + bc := CreateBlockchain("minh") + utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) if !bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) { t.Error("Failed to add new transfer to alok.") @@ -57,7 +58,9 @@ func TestAddNewUserTransfer(t *testing.T) { } func TestVerifyNewBlock(t *testing.T) { - bc, utxoPool := CreateBlockchain("minh") + bc := CreateBlockchain("minh") + utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) + bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100) diff --git a/blockchain/transaction.go b/blockchain/transaction.go index 119c99361..dab10cb2a 100644 --- a/blockchain/transaction.go +++ b/blockchain/transaction.go @@ -47,7 +47,7 @@ func (tx *Transaction) SetID() { } // NewCoinbaseTX creates a new coinbase transaction -func NewCoinbaseTX(to, data string) (*Transaction, *UTXOPool) { +func NewCoinbaseTX(to, data string) *Transaction { if data == "" { data = fmt.Sprintf("Reward to '%s'", to) } @@ -56,14 +56,7 @@ func NewCoinbaseTX(to, data string) (*Transaction, *UTXOPool) { txout := TXOutput{DefaultCoinbaseValue, to} tx := Transaction{nil, []TXInput{txin}, []TXOutput{txout}} tx.SetID() - txID := hex.EncodeToString(tx.ID) - - var utxoPool UTXOPool - utxoPool.utxo = make(map[string]map[string]int) - utxoPool.utxo[to] = make(map[string]int) - utxoPool.utxo[to][txID] = DefaultCoinbaseValue - - return &tx, &utxoPool + return &tx } // Used for debuging. diff --git a/blockchain/transaction_test.go b/blockchain/transaction_test.go index a2a479e7c..037dd807e 100644 --- a/blockchain/transaction_test.go +++ b/blockchain/transaction_test.go @@ -5,7 +5,7 @@ import ( ) func TestNewCoinbaseTX(t *testing.T) { - if cbtx, utxoPool := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil || utxoPool == nil { + if cbtx := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil { t.Errorf("failed to create a coinbase transaction.") } } diff --git a/blockchain/utxopool.go b/blockchain/utxopool.go index 66d1b1c0d..69c39f429 100644 --- a/blockchain/utxopool.go +++ b/blockchain/utxopool.go @@ -6,9 +6,9 @@ import ( // UTXOPool stores transactions and balance associated with each address. type UTXOPool struct { - // 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. - utxo map[string]map[string]map[int]int + // Mapping from address to a map of transaction id to a map of the index of output + // array in that transaction to that balance. + utxo map[string]map[string]int } // VerifyTransactions verifies if a list of transactions valid. @@ -88,3 +88,28 @@ func (utxopool *UTXOPool) Update(transactions []*Transaction) { } } } + +// CreateUTXOPoolFromTransaction a utxo pool from a genesis transaction. +func CreateUTXOPoolFromTransaction(tx *Transaction) *UTXOPool { + var utxoPool UTXOPool + txID := hex.EncodeToString(tx.ID) + utxoPool.utxo = make(map[string]map[string]int) + for _, out := range tx.TxOutput { + utxoPool.utxo[out.Address] = make(map[string]int) + utxoPool.utxo[out.Address][txID] = DefaultCoinbaseValue + } + return &utxoPool +} + +// CreateUTXOPoolFromGenesisBlockChain a utxo pool from a genesis blockchain. +func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool { + tx := bc.blocks[0].Transactions[0] + var utxoPool UTXOPool + txID := hex.EncodeToString(tx.ID) + utxoPool.utxo = make(map[string]map[string]int) + for _, out := range tx.TxOutput { + utxoPool.utxo[out.Address] = make(map[string]int) + utxoPool.utxo[out.Address][txID] = DefaultCoinbaseValue + } + return &utxoPool +} diff --git a/blockchain/utxopool_test.go b/blockchain/utxopool_test.go index 71146dc26..4e76f322e 100644 --- a/blockchain/utxopool_test.go +++ b/blockchain/utxopool_test.go @@ -5,7 +5,7 @@ import ( ) func TestVerifyTransactions(t *testing.T) { - if cbtx, utxoPool := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil || utxoPool == nil { + if cbtx := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil { t.Errorf("failed to create a coinbase transaction.") } } From 3a7f9eb46de0bddb57dac69b407297e16c2cb990 Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Sun, 17 Jun 2018 16:42:15 -0700 Subject: [PATCH 5/6] add more generic utxo --- blockchain/utxopool.go | 56 +++++++++++++++++------------------ consensus/consensus_leader.go | 2 +- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/blockchain/utxopool.go b/blockchain/utxopool.go index 69c39f429..cb198c054 100644 --- a/blockchain/utxopool.go +++ b/blockchain/utxopool.go @@ -8,34 +8,36 @@ import ( type UTXOPool struct { // Mapping from address to a map of transaction id to a map of the index of output // array in that transaction to that balance. - utxo map[string]map[string]int + utxo map[string]map[string]map[int]int } // VerifyTransactions verifies if a list of transactions valid. func (utxopool *UTXOPool) VerifyTransactions(transactions []*Transaction) bool { - spentTXOs := make(map[string]map[string]bool) + spentTXOs := make(map[string]map[string]map[int]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) + index := in.TxOutputIndex // Check if the transaction with the addres is spent or not. - if val, ok := spentTXOs[in.Address][inTxID]; ok { + if val, ok := spentTXOs[in.Address][inTxID][index]; 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 + // 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 // Sum the balance up to the inTotal. - if val, ok := utxopool.utxo[in.Address][inTxID]; ok { + if val, ok := utxopool.utxo[in.Address][inTxID][index]; ok { inTotal += val } else { return false @@ -73,17 +75,19 @@ func (utxopool *UTXOPool) Update(transactions []*Transaction) { // Remove for _, in := range tx.TxInput { inTxID := hex.EncodeToString(in.TxID) - delete(utxopool.utxo[in.Address], inTxID) + delete(utxopool.utxo[in.Address][inTxID], in.TxOutputIndex) } // 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 + 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][curTxID] = make(map[int]int) + } + if _, ok := utxopool.utxo[out.Address][curTxID]; !ok { + utxopool.utxo[out.Address][curTxID] = make(map[int]int) } + utxopool.utxo[out.Address][curTxID][index] = out.Value } } } @@ -93,10 +97,11 @@ func (utxopool *UTXOPool) Update(transactions []*Transaction) { func CreateUTXOPoolFromTransaction(tx *Transaction) *UTXOPool { var utxoPool UTXOPool txID := hex.EncodeToString(tx.ID) - utxoPool.utxo = make(map[string]map[string]int) - for _, out := range tx.TxOutput { - utxoPool.utxo[out.Address] = make(map[string]int) - utxoPool.utxo[out.Address][txID] = DefaultCoinbaseValue + utxoPool.utxo = make(map[string]map[string]map[int]int) + for index, out := range tx.TxOutput { + utxoPool.utxo[out.Address] = make(map[string]map[int]int) + utxoPool.utxo[out.Address][txID] = make(map[int]int) + utxoPool.utxo[out.Address][txID][index] = out.Value } return &utxoPool } @@ -104,12 +109,5 @@ func CreateUTXOPoolFromTransaction(tx *Transaction) *UTXOPool { // CreateUTXOPoolFromGenesisBlockChain a utxo pool from a genesis blockchain. func CreateUTXOPoolFromGenesisBlockChain(bc *Blockchain) *UTXOPool { tx := bc.blocks[0].Transactions[0] - var utxoPool UTXOPool - txID := hex.EncodeToString(tx.ID) - utxoPool.utxo = make(map[string]map[string]int) - for _, out := range tx.TxOutput { - utxoPool.utxo[out.Address] = make(map[string]int) - utxoPool.utxo[out.Address][txID] = DefaultCoinbaseValue - } - return &utxoPool + return CreateUTXOPoolFromTransaction(tx) } diff --git a/consensus/consensus_leader.go b/consensus/consensus_leader.go index 75d7cc795..10472166d 100644 --- a/consensus/consensus_leader.go +++ b/consensus/consensus_leader.go @@ -55,7 +55,7 @@ func (consensus *Consensus) ProcessMessageLeader(message []byte) { // Handler for message which triggers consensus process func (consensus *Consensus) processStartConsensusMessage(payload []byte) { - tx, _ := blockchain.NewCoinbaseTX("x", "y") // TODO: @minh, this fix is temporary to unblock the build. Please fix later. + tx := blockchain.NewCoinbaseTX("x", "y") consensus.startConsensus(blockchain.NewGenesisBlock(tx)) } From 271106289e64aa3132ba13f4c645f67c5e50d3c7 Mon Sep 17 00:00:00 2001 From: Minh Doan Date: Sun, 17 Jun 2018 17:01:10 -0700 Subject: [PATCH 6/6] fix comments --- consensus/consensus_leader.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/consensus/consensus_leader.go b/consensus/consensus_leader.go index 10472166d..85f2127f7 100644 --- a/consensus/consensus_leader.go +++ b/consensus/consensus_leader.go @@ -14,6 +14,7 @@ import ( var mutex = &sync.Mutex{} +// WaitForNewBlock waits for a new block. func (consensus *Consensus) WaitForNewBlock(blockChannel chan blockchain.Block) { for { // keep waiting for new blocks newBlock := <-blockChannel @@ -24,7 +25,7 @@ func (consensus *Consensus) WaitForNewBlock(blockChannel chan blockchain.Block) } } -// Leader's consensus message dispatcher +// ProcessMessageLeader is the leader's consensus message dispatcher func (consensus *Consensus) ProcessMessageLeader(message []byte) { msgType, err := GetConsensusMessageType(message) if err != nil {