diff --git a/aws-code/transaction_generator.go b/aws-code/transaction_generator.go index 9875023d9..bdec538b5 100644 --- a/aws-code/transaction_generator.go +++ b/aws-code/transaction_generator.go @@ -51,7 +51,7 @@ func getNewFakeTransactions(dataNode *node.Node, numTxs int) []*blockchain.Trans countAll++ if rand.Intn(100) < 50 { // 50% sample rate to select UTXO to use for new transactions // Spend the money of current UTXO to a random address in [1 - 1000] - txin := blockchain.TXInput{txId, index, address} + txin := blockchain.TXInput{txId, index, address, dataNode.Consensus.ShardID} txout := blockchain.TXOutput{value, strconv.Itoa(rand.Intn(10000))} tx := blockchain.Transaction{[32]byte{}, []blockchain.TXInput{txin}, []blockchain.TXOutput{txout}} tx.SetID() diff --git a/blockchain/block.go b/blockchain/block.go index a0d7e8e6e..1eb6e550d 100644 --- a/blockchain/block.go +++ b/blockchain/block.go @@ -18,7 +18,7 @@ type Block struct { NumTransactions int32 TransactionIds [][32]byte Transactions []*Transaction // Transactions - + ShardId uint32 // Signature... } @@ -68,20 +68,20 @@ func (b *Block) HashTransactions() []byte { } // NewBlock creates and returns a neew block. -func NewBlock(transactions []*Transaction, prevBlockHash [32]byte) *Block { +func NewBlock(transactions []*Transaction, prevBlockHash [32]byte, shardId uint32) *Block { numTxs := int32(len(transactions)) var txIds [][32]byte for _, tx := range transactions { txIds = append(txIds, tx.ID) } - block := &Block{time.Now().Unix(), prevBlockHash, [32]byte{}, numTxs, txIds, transactions} + block := &Block{time.Now().Unix(), prevBlockHash, [32]byte{}, numTxs, txIds, transactions, shardId} copy(block.Hash[:], block.HashTransactions()[:]) // TODO(Minh): the blockhash should be a hash of everything in the block return block } // NewGenesisBlock creates and returns genesis Block. -func NewGenesisBlock(coinbase *Transaction) *Block { - return NewBlock([]*Transaction{coinbase}, [32]byte{}) +func NewGenesisBlock(coinbase *Transaction, shardId uint32) *Block { + return NewBlock([]*Transaction{coinbase}, [32]byte{}, shardId) } diff --git a/blockchain/block_test.go b/blockchain/block_test.go index 2566cfcdd..e60d14362 100644 --- a/blockchain/block_test.go +++ b/blockchain/block_test.go @@ -6,11 +6,11 @@ import ( ) func TestBlockSerialize(t *testing.T) { - cbtx := NewCoinbaseTX("minh", genesisCoinbaseData) + cbtx := NewCoinbaseTX("minh", genesisCoinbaseData, 0) if cbtx == nil { t.Errorf("Failed to create a coinbase transaction.") } - block := NewGenesisBlock(cbtx) + block := NewGenesisBlock(cbtx, 0) serializedValue := block.Serialize() deserializedBlock := DeserializeBlock(serializedValue) diff --git a/blockchain/blockchain.go b/blockchain/blockchain.go index 9dcc145e4..e2a986f43 100644 --- a/blockchain/blockchain.go +++ b/blockchain/blockchain.go @@ -103,7 +103,7 @@ Work: } // NewUTXOTransaction creates a new transaction -func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int) *Transaction { +func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int, shardId uint32) *Transaction { var inputs []TXInput var outputs []TXOutput @@ -121,7 +121,7 @@ func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int) *Transacti } for _, out := range outs { - input := TXInput{txID, out, from} + input := TXInput{txID, out, from, shardId} inputs = append(inputs, input) } } @@ -140,10 +140,10 @@ func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int) *Transacti // AddNewUserTransfer creates a new transaction and a block of that transaction. // Mostly used for testing. -func (bc *Blockchain) AddNewUserTransfer(utxoPool *UTXOPool, from, to string, amount int) bool { - tx := bc.NewUTXOTransaction(from, to, amount) +func (bc *Blockchain) AddNewUserTransfer(utxoPool *UTXOPool, from, to string, amount int, shardId uint32) bool { + tx := bc.NewUTXOTransaction(from, to, amount, shardId) if tx != nil { - newBlock := NewBlock([]*Transaction{tx}, bc.Blocks[len(bc.Blocks)-1].Hash) + newBlock := NewBlock([]*Transaction{tx}, bc.Blocks[len(bc.Blocks)-1].Hash, shardId) if bc.VerifyNewBlockAndUpdate(utxoPool, newBlock) { return true } @@ -169,11 +169,11 @@ func (bc *Blockchain) VerifyNewBlockAndUpdate(utxopool *UTXOPool, block *Block) } // CreateBlockchain creates a new blockchain DB -func CreateBlockchain(address string) *Blockchain { +func CreateBlockchain(address string, shardId uint32) *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 := NewCoinbaseTX(address, genesisCoinbaseData) - genesis := NewGenesisBlock(cbtx) + cbtx := NewCoinbaseTX(address, genesisCoinbaseData, shardId) + genesis := NewGenesisBlock(cbtx, shardId) bc := Blockchain{[]*Block{genesis}} diff --git a/blockchain/blockchain_test.go b/blockchain/blockchain_test.go index ed7c73652..f0e6f8c57 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", 0); bc == nil { t.Errorf("failed to create a blockchain") } } func TestFindSpendableOutputs(t *testing.T) { requestAmount := 3 - bc := CreateBlockchain("minh") + bc := CreateBlockchain("minh", 0) 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", 0) utxo := bc.FindUTXO("minh") total := 0 @@ -41,34 +41,34 @@ func TestFindUTXO(t *testing.T) { } func TestAddNewUserTransfer(t *testing.T) { - bc := CreateBlockchain("minh") + bc := CreateBlockchain("minh", 0) utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) - if !bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) { + if !bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3, 0) { t.Error("Failed to add new transfer to alok.") } - if !bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100) { + if !bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100, 0) { t.Error("Failed to add new transfer to rj.") } - if bc.AddNewUserTransfer(utxoPool, "minh", "stephen", DefaultCoinbaseValue-102) { + if bc.AddNewUserTransfer(utxoPool, "minh", "stephen", DefaultCoinbaseValue-102, 0) { t.Error("minh should not have enough fun to make the transfer.") } } func TestVerifyNewBlock(t *testing.T) { - bc := CreateBlockchain("minh") + bc := CreateBlockchain("minh", 0) utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) - bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) - bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100) + bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3, 0) + bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100, 0) - tx := bc.NewUTXOTransaction("minh", "mark", 10) + tx := bc.NewUTXOTransaction("minh", "mark", 10, 0) if tx == nil { t.Error("failed to create a new transaction.") } - newBlock := NewBlock([]*Transaction{tx}, bc.Blocks[len(bc.Blocks)-1].Hash) + newBlock := NewBlock([]*Transaction{tx}, bc.Blocks[len(bc.Blocks)-1].Hash, 0) if !bc.VerifyNewBlockAndUpdate(utxoPool, newBlock) { t.Error("failed to add a new valid block.") diff --git a/blockchain/transaction.go b/blockchain/transaction.go index ee38c78fb..f3843113f 100644 --- a/blockchain/transaction.go +++ b/blockchain/transaction.go @@ -22,11 +22,12 @@ type TXOutput struct { Address string } -// TXInput is the struct of transaction input in a transaction. +// TXInput is the struct of transaction input (a UTXO) in a transaction. type TXInput struct { TxID []byte TxOutputIndex int Address string + ShardId uint32 // The Id of the shard where this UTXO belongs } // DefaultCoinbaseValue is the default value of coinbase transaction. @@ -47,12 +48,12 @@ func (tx *Transaction) SetID() { } // NewCoinbaseTX creates a new coinbase transaction -func NewCoinbaseTX(to, data string) *Transaction { +func NewCoinbaseTX(to, data string, shardId uint32) *Transaction { if data == "" { data = fmt.Sprintf("Reward to '%s'", to) } - txin := TXInput{[]byte{}, -1, data} + txin := TXInput{[]byte{}, -1, data, shardId} txout := TXOutput{DefaultCoinbaseValue, to} tx := Transaction{[32]byte{}, []TXInput{txin}, []TXOutput{txout}} tx.SetID() diff --git a/blockchain/transaction_test.go b/blockchain/transaction_test.go index 037dd807e..bf693cf86 100644 --- a/blockchain/transaction_test.go +++ b/blockchain/transaction_test.go @@ -5,7 +5,7 @@ import ( ) func TestNewCoinbaseTX(t *testing.T) { - if cbtx := NewCoinbaseTX("minh", genesisCoinbaseData); cbtx == nil { + if cbtx := NewCoinbaseTX("minh", genesisCoinbaseData, 0); cbtx == nil { t.Errorf("failed to create a coinbase transaction.") } } diff --git a/blockchain/utxopool_test.go b/blockchain/utxopool_test.go index 84f4e4b42..4973a32e0 100644 --- a/blockchain/utxopool_test.go +++ b/blockchain/utxopool_test.go @@ -5,13 +5,13 @@ import ( ) func TestVerifyOneTransactionAndUpdate(t *testing.T) { - bc := CreateBlockchain("minh") + bc := CreateBlockchain("minh", 0) utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) - bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) - bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100) + bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3, 0) + bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100, 0) - tx := bc.NewUTXOTransaction("minh", "mark", 10) + tx := bc.NewUTXOTransaction("minh", "mark", 10, 0) if tx == nil { t.Error("failed to create a new transaction.") } @@ -23,11 +23,11 @@ func TestVerifyOneTransactionAndUpdate(t *testing.T) { } func TestDeleteOneBalanceItem(t *testing.T) { - bc := CreateBlockchain("minh") + bc := CreateBlockchain("minh", 0) utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) - bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) - bc.AddNewUserTransfer(utxoPool, "alok", "rj", 3) + bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3, 0) + bc.AddNewUserTransfer(utxoPool, "alok", "rj", 3, 0) if _, ok := utxoPool.UtxoMap["alok"]; ok { t.Errorf("alok should not be contained in the balance map") diff --git a/consensus/consensus_leader.go b/consensus/consensus_leader.go index 23c2ee3bd..b1ab24497 100644 --- a/consensus/consensus_leader.go +++ b/consensus/consensus_leader.go @@ -56,8 +56,8 @@ func (consensus *Consensus) ProcessMessageLeader(message []byte) { // Handler for message which triggers consensus process func (consensus *Consensus) processStartConsensusMessage(payload []byte) { - tx := blockchain.NewCoinbaseTX("x", "y") - consensus.startConsensus(blockchain.NewGenesisBlock(tx)) + tx := blockchain.NewCoinbaseTX("x", "y", 0) + consensus.startConsensus(blockchain.NewGenesisBlock(tx, 0)) } func (consensus *Consensus) startConsensus(newBlock *blockchain.Block) { diff --git a/node/node.go b/node/node.go index 85987ee2a..24057475a 100644 --- a/node/node.go +++ b/node/node.go @@ -15,10 +15,10 @@ var pendingTxMutex = &sync.Mutex{} // Node represents a program (machine) participating in the network // TODO(minhdoan, rj): consider using BlockChannel *chan blockchain.Block for efficiency. type Node struct { - consensus *consensus.Consensus // Consensus object containing all consensus related data (e.g. committee members, signatures, commits) + Consensus *consensus.Consensus // Consensus object containing all Consensus related data (e.g. committee members, signatures, commits) BlockChannel chan blockchain.Block // The channel to receive new blocks from Node - pendingTransactions []*blockchain.Transaction // All the transactions received but not yet processed for consensus - transactionInConsensus []*blockchain.Transaction // The transactions selected into the new block and under consensus process + pendingTransactions []*blockchain.Transaction // All the transactions received but not yet processed for Consensus + transactionInConsensus []*blockchain.Transaction // The transactions selected into the new block and under Consensus process blockchain *blockchain.Blockchain // The blockchain for the shard where this node belongs UtxoPool *blockchain.UTXOPool // The corresponding UTXO pool of the current blockchain log log.Logger // Log utility @@ -68,7 +68,7 @@ func (node *Node) listenOnPort(port string) { } func (node *Node) String() string { - return node.consensus.String() + return node.Consensus.String() } // [Testing code] Should be deleted for production @@ -76,7 +76,7 @@ func (node *Node) String() string { func (node *Node) AddMoreFakeTransactions(numTxs int) { txs := make([]*blockchain.Transaction, numTxs) for i := range txs { - txs[i] = blockchain.NewCoinbaseTX(strconv.Itoa(i), "") + txs[i] = blockchain.NewCoinbaseTX(strconv.Itoa(i), "", node.Consensus.ShardID) } node.blockchain.Blocks[0].Transactions = append(node.blockchain.Blocks[0].Transactions, txs...) node.UtxoPool.Update(txs) @@ -97,20 +97,20 @@ func NewNode(consensus *consensus.Consensus) Node { node := Node{} // Consensus and associated channel to communicate blocks - node.consensus = consensus + node.Consensus = consensus node.BlockChannel = make(chan blockchain.Block) // Genesis Block genesisBlock := &blockchain.Blockchain{} genesisBlock.Blocks = make([]*blockchain.Block, 0) - coinbaseTx := blockchain.NewCoinbaseTX("harmony", "1") - genesisBlock.Blocks = append(genesisBlock.Blocks, blockchain.NewGenesisBlock(coinbaseTx)) + coinbaseTx := blockchain.NewCoinbaseTX("harmony", "1", node.Consensus.ShardID) + genesisBlock.Blocks = append(genesisBlock.Blocks, blockchain.NewGenesisBlock(coinbaseTx, node.Consensus.ShardID)) node.blockchain = genesisBlock // UTXO pool from Genesis block node.UtxoPool = blockchain.CreateUTXOPoolFromGenesisBlockChain(node.blockchain) // Logger - node.log = node.consensus.Log + node.log = node.Consensus.Log return node } diff --git a/node/node_handler.go b/node/node_handler.go index 55c0ace20..84bf8a061 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -27,7 +27,7 @@ func (node *Node) NodeHandler(conn net.Conn) { node.log.Error("Read p2p data failed", "err", err, "node", node) return } - consensus := node.consensus + consensus := node.Consensus msgCategory, err := common.GetMessageCategory(content) if err != nil { @@ -115,11 +115,11 @@ func (node *Node) transactionMessageHandler(msgPayload []byte) { // WaitForConsensusReady ... func (node *Node) WaitForConsensusReady(readySignal chan int) { - node.log.Debug("Waiting for consensus ready", "node", node) + node.log.Debug("Waiting for Consensus ready", "node", node) var newBlock *blockchain.Block timeoutCount := 0 - for { // keep waiting for consensus ready + for { // keep waiting for Consensus ready retry := false select { case <-readySignal: @@ -142,17 +142,17 @@ func (node *Node) WaitForConsensusReady(readySignal chan int) { node.log.Debug("Creating new block", "numTxs", len(selectedTxs), "pendingTxs", len(node.pendingTransactions), "currentChainSize", len(node.blockchain.Blocks)) node.transactionInConsensus = selectedTxs - newBlock = blockchain.NewBlock(selectedTxs, node.blockchain.GetLatestBlock().Hash) + newBlock = blockchain.NewBlock(selectedTxs, node.blockchain.GetLatestBlock().Hash, node.Consensus.ShardID) break } } - // If not enough transactions to run consensus, + // If not enough transactions to run Consensus, // periodically check whether we have enough transactions to package into block. time.Sleep(1 * time.Second) } } - // Send the new block to consensus so it can be confirmed. + // Send the new block to Consensus so it can be confirmed. if newBlock != nil { node.BlockChannel <- *newBlock } @@ -168,6 +168,6 @@ func (node *Node) AddNewBlockToBlockchain(newBlock *blockchain.Block) { node.blockchain.Blocks = append(node.blockchain.Blocks, newBlock) // Update UTXO pool node.UtxoPool.Update(newBlock.Transactions) - // Clear transaction-in-consensus list + // Clear transaction-in-Consensus list node.transactionInConsensus = []*blockchain.Transaction{} } diff --git a/node/node_test.go b/node/node_test.go index 6a6cc1f78..d24f7cd19 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -12,7 +12,7 @@ func TestNewNewNode(test *testing.T) { consensus := consensus.NewConsensus("1", "2", "0", []p2p.Peer{leader, validator}, leader) node := NewNode(&consensus) - if node.consensus == nil { + if node.Consensus == nil { test.Error("Consensus is not initialized for the node") }