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++
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()

@ -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)
}

@ -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)

@ -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}}

@ -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.")

@ -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()

@ -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.")
}
}

@ -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")

@ -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) {

@ -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
}

@ -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{}
}

@ -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")
}

Loading…
Cancel
Save