Add ShardId into the revelant data structures: block, UTXO etc.

pull/10/head
Rongjian Lan 7 years ago
parent 7eff03f521
commit 2ddd32882c
  1. 2
      aws-code/transaction_generator.go
  2. 10
      blockchain/block.go
  3. 4
      blockchain/block_test.go
  4. 16
      blockchain/blockchain.go
  5. 24
      blockchain/blockchain_test.go
  6. 7
      blockchain/transaction.go
  7. 2
      blockchain/transaction_test.go
  8. 14
      blockchain/utxopool_test.go
  9. 4
      consensus/consensus_leader.go
  10. 18
      node/node.go
  11. 14
      node/node_handler.go
  12. 2
      node/node_test.go

@ -51,7 +51,7 @@ func getNewFakeTransactions(dataNode *node.Node, numTxs int) []*blockchain.Trans
countAll++ countAll++
if rand.Intn(100) < 50 { // 50% sample rate to select UTXO to use for new transactions 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] // 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))} txout := blockchain.TXOutput{value, strconv.Itoa(rand.Intn(10000))}
tx := blockchain.Transaction{[32]byte{}, []blockchain.TXInput{txin}, []blockchain.TXOutput{txout}} tx := blockchain.Transaction{[32]byte{}, []blockchain.TXInput{txin}, []blockchain.TXOutput{txout}}
tx.SetID() tx.SetID()

@ -18,7 +18,7 @@ type Block struct {
NumTransactions int32 NumTransactions int32
TransactionIds [][32]byte TransactionIds [][32]byte
Transactions []*Transaction // Transactions Transactions []*Transaction // Transactions
ShardId uint32
// Signature... // Signature...
} }
@ -68,20 +68,20 @@ func (b *Block) HashTransactions() []byte {
} }
// NewBlock creates and returns a neew block. // 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)) numTxs := int32(len(transactions))
var txIds [][32]byte var txIds [][32]byte
for _, tx := range transactions { for _, tx := range transactions {
txIds = append(txIds, tx.ID) 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 copy(block.Hash[:], block.HashTransactions()[:]) // TODO(Minh): the blockhash should be a hash of everything in the block
return block return block
} }
// NewGenesisBlock creates and returns genesis Block. // NewGenesisBlock creates and returns genesis Block.
func NewGenesisBlock(coinbase *Transaction) *Block { func NewGenesisBlock(coinbase *Transaction, shardId uint32) *Block {
return NewBlock([]*Transaction{coinbase}, [32]byte{}) return NewBlock([]*Transaction{coinbase}, [32]byte{}, shardId)
} }

@ -6,11 +6,11 @@ import (
) )
func TestBlockSerialize(t *testing.T) { func TestBlockSerialize(t *testing.T) {
cbtx := NewCoinbaseTX("minh", genesisCoinbaseData) cbtx := NewCoinbaseTX("minh", genesisCoinbaseData, 0)
if cbtx == nil { if cbtx == nil {
t.Errorf("Failed to create a coinbase transaction.") t.Errorf("Failed to create a coinbase transaction.")
} }
block := NewGenesisBlock(cbtx) block := NewGenesisBlock(cbtx, 0)
serializedValue := block.Serialize() serializedValue := block.Serialize()
deserializedBlock := DeserializeBlock(serializedValue) deserializedBlock := DeserializeBlock(serializedValue)

@ -103,7 +103,7 @@ Work:
} }
// NewUTXOTransaction creates a new transaction // 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 inputs []TXInput
var outputs []TXOutput var outputs []TXOutput
@ -121,7 +121,7 @@ func (bc *Blockchain) NewUTXOTransaction(from, to string, amount int) *Transacti
} }
for _, out := range outs { for _, out := range outs {
input := TXInput{txID, out, from} input := TXInput{txID, out, from, shardId}
inputs = append(inputs, input) 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. // AddNewUserTransfer creates a new transaction and a block of that transaction.
// Mostly used for testing. // Mostly used for testing.
func (bc *Blockchain) AddNewUserTransfer(utxoPool *UTXOPool, from, to string, amount int) bool { func (bc *Blockchain) AddNewUserTransfer(utxoPool *UTXOPool, from, to string, amount int, shardId uint32) bool {
tx := bc.NewUTXOTransaction(from, to, amount) tx := bc.NewUTXOTransaction(from, to, amount, shardId)
if tx != nil { 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) { if bc.VerifyNewBlockAndUpdate(utxoPool, newBlock) {
return true return true
} }
@ -169,11 +169,11 @@ func (bc *Blockchain) VerifyNewBlockAndUpdate(utxopool *UTXOPool, block *Block)
} }
// CreateBlockchain creates a new blockchain DB // 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. // 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. // In current bitcoin, we can check if we created a blockchain before accessing local db.
cbtx := NewCoinbaseTX(address, genesisCoinbaseData) cbtx := NewCoinbaseTX(address, genesisCoinbaseData, shardId)
genesis := NewGenesisBlock(cbtx) genesis := NewGenesisBlock(cbtx, shardId)
bc := Blockchain{[]*Block{genesis}} bc := Blockchain{[]*Block{genesis}}

@ -5,14 +5,14 @@ import (
) )
func TestCreateBlockchain(t *testing.T) { 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") t.Errorf("failed to create a blockchain")
} }
} }
func TestFindSpendableOutputs(t *testing.T) { func TestFindSpendableOutputs(t *testing.T) {
requestAmount := 3 requestAmount := 3
bc := CreateBlockchain("minh") bc := CreateBlockchain("minh", 0)
accumulated, unspentOutputs := bc.FindSpendableOutputs("minh", requestAmount) accumulated, unspentOutputs := bc.FindSpendableOutputs("minh", requestAmount)
if accumulated < DefaultCoinbaseValue { if accumulated < DefaultCoinbaseValue {
t.Error("Failed to find enough unspent ouptuts") t.Error("Failed to find enough unspent ouptuts")
@ -24,7 +24,7 @@ func TestFindSpendableOutputs(t *testing.T) {
} }
func TestFindUTXO(t *testing.T) { func TestFindUTXO(t *testing.T) {
bc := CreateBlockchain("minh") bc := CreateBlockchain("minh", 0)
utxo := bc.FindUTXO("minh") utxo := bc.FindUTXO("minh")
total := 0 total := 0
@ -41,34 +41,34 @@ func TestFindUTXO(t *testing.T) {
} }
func TestAddNewUserTransfer(t *testing.T) { func TestAddNewUserTransfer(t *testing.T) {
bc := CreateBlockchain("minh") bc := CreateBlockchain("minh", 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) 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.") 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.") 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.") t.Error("minh should not have enough fun to make the transfer.")
} }
} }
func TestVerifyNewBlock(t *testing.T) { func TestVerifyNewBlock(t *testing.T) {
bc := CreateBlockchain("minh") bc := CreateBlockchain("minh", 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3, 0)
bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100) bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100, 0)
tx := bc.NewUTXOTransaction("minh", "mark", 10) tx := bc.NewUTXOTransaction("minh", "mark", 10, 0)
if tx == nil { if tx == nil {
t.Error("failed to create a new transaction.") 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) { if !bc.VerifyNewBlockAndUpdate(utxoPool, newBlock) {
t.Error("failed to add a new valid block.") t.Error("failed to add a new valid block.")

@ -22,11 +22,12 @@ type TXOutput struct {
Address string 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 { type TXInput struct {
TxID []byte TxID []byte
TxOutputIndex int TxOutputIndex int
Address string Address string
ShardId uint32 // The Id of the shard where this UTXO belongs
} }
// DefaultCoinbaseValue is the default value of coinbase transaction. // DefaultCoinbaseValue is the default value of coinbase transaction.
@ -47,12 +48,12 @@ func (tx *Transaction) SetID() {
} }
// NewCoinbaseTX creates a new coinbase transaction // NewCoinbaseTX creates a new coinbase transaction
func NewCoinbaseTX(to, data string) *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{[]byte{}, -1, data} txin := TXInput{[]byte{}, -1, data, shardId}
txout := TXOutput{DefaultCoinbaseValue, to} txout := TXOutput{DefaultCoinbaseValue, to}
tx := Transaction{[32]byte{}, []TXInput{txin}, []TXOutput{txout}} tx := Transaction{[32]byte{}, []TXInput{txin}, []TXOutput{txout}}
tx.SetID() tx.SetID()

@ -5,7 +5,7 @@ import (
) )
func TestNewCoinbaseTX(t *testing.T) { 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.") t.Errorf("failed to create a coinbase transaction.")
} }
} }

@ -5,13 +5,13 @@ import (
) )
func TestVerifyOneTransactionAndUpdate(t *testing.T) { func TestVerifyOneTransactionAndUpdate(t *testing.T) {
bc := CreateBlockchain("minh") bc := CreateBlockchain("minh", 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3, 0)
bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100) bc.AddNewUserTransfer(utxoPool, "minh", "rj", 100, 0)
tx := bc.NewUTXOTransaction("minh", "mark", 10) tx := bc.NewUTXOTransaction("minh", "mark", 10, 0)
if tx == nil { if tx == nil {
t.Error("failed to create a new transaction.") t.Error("failed to create a new transaction.")
} }
@ -23,11 +23,11 @@ func TestVerifyOneTransactionAndUpdate(t *testing.T) {
} }
func TestDeleteOneBalanceItem(t *testing.T) { func TestDeleteOneBalanceItem(t *testing.T) {
bc := CreateBlockchain("minh") bc := CreateBlockchain("minh", 0)
utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc) utxoPool := CreateUTXOPoolFromGenesisBlockChain(bc)
bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3) bc.AddNewUserTransfer(utxoPool, "minh", "alok", 3, 0)
bc.AddNewUserTransfer(utxoPool, "alok", "rj", 3) bc.AddNewUserTransfer(utxoPool, "alok", "rj", 3, 0)
if _, ok := utxoPool.UtxoMap["alok"]; ok { if _, ok := utxoPool.UtxoMap["alok"]; ok {
t.Errorf("alok should not be contained in the balance map") t.Errorf("alok should not be contained in the balance map")

@ -56,8 +56,8 @@ func (consensus *Consensus) ProcessMessageLeader(message []byte) {
// Handler for message which triggers consensus process // Handler for message which triggers consensus process
func (consensus *Consensus) processStartConsensusMessage(payload []byte) { func (consensus *Consensus) processStartConsensusMessage(payload []byte) {
tx := blockchain.NewCoinbaseTX("x", "y") tx := blockchain.NewCoinbaseTX("x", "y", 0)
consensus.startConsensus(blockchain.NewGenesisBlock(tx)) consensus.startConsensus(blockchain.NewGenesisBlock(tx, 0))
} }
func (consensus *Consensus) startConsensus(newBlock *blockchain.Block) { func (consensus *Consensus) startConsensus(newBlock *blockchain.Block) {

@ -15,10 +15,10 @@ var pendingTxMutex = &sync.Mutex{}
// Node represents a program (machine) participating in the network // Node represents a program (machine) participating in the network
// TODO(minhdoan, rj): consider using BlockChannel *chan blockchain.Block for efficiency. // TODO(minhdoan, rj): consider using BlockChannel *chan blockchain.Block for efficiency.
type Node struct { 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 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 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 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 blockchain *blockchain.Blockchain // The blockchain for the shard where this node belongs
UtxoPool *blockchain.UTXOPool // The corresponding UTXO pool of the current blockchain UtxoPool *blockchain.UTXOPool // The corresponding UTXO pool of the current blockchain
log log.Logger // Log utility log log.Logger // Log utility
@ -68,7 +68,7 @@ func (node *Node) listenOnPort(port string) {
} }
func (node *Node) String() string { func (node *Node) String() string {
return node.consensus.String() return node.Consensus.String()
} }
// [Testing code] Should be deleted for production // [Testing code] Should be deleted for production
@ -76,7 +76,7 @@ func (node *Node) String() string {
func (node *Node) AddMoreFakeTransactions(numTxs int) { func (node *Node) AddMoreFakeTransactions(numTxs int) {
txs := make([]*blockchain.Transaction, numTxs) txs := make([]*blockchain.Transaction, numTxs)
for i := range txs { 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.blockchain.Blocks[0].Transactions = append(node.blockchain.Blocks[0].Transactions, txs...)
node.UtxoPool.Update(txs) node.UtxoPool.Update(txs)
@ -97,20 +97,20 @@ func NewNode(consensus *consensus.Consensus) Node {
node := Node{} node := Node{}
// Consensus and associated channel to communicate blocks // Consensus and associated channel to communicate blocks
node.consensus = consensus node.Consensus = consensus
node.BlockChannel = make(chan blockchain.Block) node.BlockChannel = make(chan blockchain.Block)
// Genesis Block // Genesis Block
genesisBlock := &blockchain.Blockchain{} genesisBlock := &blockchain.Blockchain{}
genesisBlock.Blocks = make([]*blockchain.Block, 0) genesisBlock.Blocks = make([]*blockchain.Block, 0)
coinbaseTx := blockchain.NewCoinbaseTX("harmony", "1") coinbaseTx := blockchain.NewCoinbaseTX("harmony", "1", node.Consensus.ShardID)
genesisBlock.Blocks = append(genesisBlock.Blocks, blockchain.NewGenesisBlock(coinbaseTx)) genesisBlock.Blocks = append(genesisBlock.Blocks, blockchain.NewGenesisBlock(coinbaseTx, node.Consensus.ShardID))
node.blockchain = genesisBlock node.blockchain = genesisBlock
// UTXO pool from Genesis block // UTXO pool from Genesis block
node.UtxoPool = blockchain.CreateUTXOPoolFromGenesisBlockChain(node.blockchain) node.UtxoPool = blockchain.CreateUTXOPoolFromGenesisBlockChain(node.blockchain)
// Logger // Logger
node.log = node.consensus.Log node.log = node.Consensus.Log
return node return node
} }

@ -27,7 +27,7 @@ func (node *Node) NodeHandler(conn net.Conn) {
node.log.Error("Read p2p data failed", "err", err, "node", node) node.log.Error("Read p2p data failed", "err", err, "node", node)
return return
} }
consensus := node.consensus consensus := node.Consensus
msgCategory, err := common.GetMessageCategory(content) msgCategory, err := common.GetMessageCategory(content)
if err != nil { if err != nil {
@ -115,11 +115,11 @@ func (node *Node) transactionMessageHandler(msgPayload []byte) {
// WaitForConsensusReady ... // WaitForConsensusReady ...
func (node *Node) WaitForConsensusReady(readySignal chan int) { 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 var newBlock *blockchain.Block
timeoutCount := 0 timeoutCount := 0
for { // keep waiting for consensus ready for { // keep waiting for Consensus ready
retry := false retry := false
select { select {
case <-readySignal: 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.log.Debug("Creating new block", "numTxs", len(selectedTxs), "pendingTxs", len(node.pendingTransactions), "currentChainSize", len(node.blockchain.Blocks))
node.transactionInConsensus = selectedTxs node.transactionInConsensus = selectedTxs
newBlock = blockchain.NewBlock(selectedTxs, node.blockchain.GetLatestBlock().Hash) newBlock = blockchain.NewBlock(selectedTxs, node.blockchain.GetLatestBlock().Hash, node.Consensus.ShardID)
break 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. // periodically check whether we have enough transactions to package into block.
time.Sleep(1 * time.Second) 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 { if newBlock != nil {
node.BlockChannel <- *newBlock node.BlockChannel <- *newBlock
} }
@ -168,6 +168,6 @@ func (node *Node) AddNewBlockToBlockchain(newBlock *blockchain.Block) {
node.blockchain.Blocks = append(node.blockchain.Blocks, newBlock) node.blockchain.Blocks = append(node.blockchain.Blocks, newBlock)
// Update UTXO pool // Update UTXO pool
node.UtxoPool.Update(newBlock.Transactions) node.UtxoPool.Update(newBlock.Transactions)
// Clear transaction-in-consensus list // Clear transaction-in-Consensus list
node.transactionInConsensus = []*blockchain.Transaction{} node.transactionInConsensus = []*blockchain.Transaction{}
} }

@ -12,7 +12,7 @@ func TestNewNewNode(test *testing.T) {
consensus := consensus.NewConsensus("1", "2", "0", []p2p.Peer{leader, validator}, leader) consensus := consensus.NewConsensus("1", "2", "0", []p2p.Peer{leader, validator}, leader)
node := NewNode(&consensus) node := NewNode(&consensus)
if node.consensus == nil { if node.Consensus == nil {
test.Error("Consensus is not initialized for the node") test.Error("Consensus is not initialized for the node")
} }

Loading…
Cancel
Save