diff options
author | Jimmy Hu <jimmy.hu@dexon.org> | 2018-08-30 15:39:06 +0800 |
---|---|---|
committer | missionliao <38416648+missionliao@users.noreply.github.com> | 2018-08-30 15:39:06 +0800 |
commit | a4e0da981a3dfc8817d39be65cb5b24938b0761a (patch) | |
tree | 9c372875258bd942c30050643604d7d1448d2627 | |
parent | 8cb1d5c4f3f7f93d8b2c54addf5c2caced0a1eb8 (diff) | |
download | dexon-consensus-a4e0da981a3dfc8817d39be65cb5b24938b0761a.tar.gz dexon-consensus-a4e0da981a3dfc8817d39be65cb5b24938b0761a.tar.zst dexon-consensus-a4e0da981a3dfc8817d39be65cb5b24938b0761a.zip |
core: Change the lattice key from validatorID to chainID. (#83)
* Add chainID in simulation.Validator
* Change validatorid to chainID in rbModule
-rw-r--r-- | core/consensus.go | 1 | ||||
-rw-r--r-- | core/consensus_test.go | 26 | ||||
-rw-r--r-- | core/reliable-broadcast.go | 100 | ||||
-rw-r--r-- | core/reliable-broadcast_test.go | 141 | ||||
-rw-r--r-- | core/test/blocks-generator.go | 5 | ||||
-rw-r--r-- | integration_test/validator.go | 22 | ||||
-rw-r--r-- | simulation/validator.go | 13 |
7 files changed, 210 insertions, 98 deletions
diff --git a/core/consensus.go b/core/consensus.go index 6c841bf..d163686 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -79,6 +79,7 @@ func NewConsensus( // Setup acking by information returned from Governace. rb := newReliableBroadcast() + rb.setChainNum(len(validatorSet)) for vID := range validatorSet { rb.addValidator(vID) } diff --git a/core/consensus_test.go b/core/consensus_test.go index cd7ff02..46df8eb 100644 --- a/core/consensus_test.go +++ b/core/consensus_test.go @@ -36,10 +36,12 @@ type ConsensusTestSuite struct { func (s *ConsensusTestSuite) prepareGenesisBlock( proposerID types.ValidatorID, + chainID uint64, con *Consensus) *types.Block { block := &types.Block{ ProposerID: proposerID, + ChainID: chainID, } err := con.PrepareGenesisBlock(block, time.Now().UTC()) s.Require().Nil(err) @@ -102,13 +104,13 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { } } // Genesis blocks - b00 := s.prepareGenesisBlock(validators[0], objs[validators[0]].con) + b00 := s.prepareGenesisBlock(validators[0], 0, objs[validators[0]].con) time.Sleep(minInterval) - b10 := s.prepareGenesisBlock(validators[1], objs[validators[1]].con) + b10 := s.prepareGenesisBlock(validators[1], 1, objs[validators[1]].con) time.Sleep(minInterval) - b20 := s.prepareGenesisBlock(validators[2], objs[validators[2]].con) + b20 := s.prepareGenesisBlock(validators[2], 2, objs[validators[2]].con) time.Sleep(minInterval) - b30 := s.prepareGenesisBlock(validators[3], objs[validators[3]].con) + b30 := s.prepareGenesisBlock(validators[3], 3, objs[validators[3]].con) broadcast(b00) broadcast(b10) broadcast(b20) @@ -117,6 +119,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { time.Sleep(minInterval) b11 := &types.Block{ ProposerID: validators[1], + ChainID: 1, } b11.Hash, err = hashBlock(b11) s.Require().Nil(err) @@ -131,6 +134,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { time.Sleep(minInterval) b01 := &types.Block{ ProposerID: validators[0], + ChainID: 0, Hash: common.NewRandomHash(), } req.Nil(objs[validators[0]].con.PrepareBlock(b01, time.Now().UTC())) @@ -140,6 +144,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { time.Sleep(minInterval) b21 := &types.Block{ ProposerID: validators[2], + ChainID: 2, Hash: common.NewRandomHash(), } req.Nil(objs[validators[2]].con.PrepareBlock(b21, time.Now().UTC())) @@ -149,6 +154,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { time.Sleep(minInterval) b31 := &types.Block{ ProposerID: validators[3], + ChainID: 3, Hash: common.NewRandomHash(), } req.Nil(objs[validators[3]].con.PrepareBlock(b31, time.Now().UTC())) @@ -163,6 +169,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { time.Sleep(minInterval) b02 := &types.Block{ ProposerID: validators[0], + ChainID: 0, Hash: common.NewRandomHash(), } req.Nil(objs[validators[0]].con.PrepareBlock(b02, time.Now().UTC())) @@ -174,6 +181,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { time.Sleep(minInterval) b12 := &types.Block{ ProposerID: validators[1], + ChainID: 1, Hash: common.NewRandomHash(), } req.Nil(objs[validators[1]].con.PrepareBlock(b12, time.Now().UTC())) @@ -186,6 +194,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { time.Sleep(minInterval) b22 := &types.Block{ ProposerID: validators[2], + ChainID: 2, Hash: common.NewRandomHash(), } req.Nil(objs[validators[2]].con.PrepareBlock(b22, time.Now().UTC())) @@ -197,6 +206,7 @@ func (s *ConsensusTestSuite) TestSimpleDeliverBlock() { time.Sleep(minInterval) b32 := &types.Block{ ProposerID: validators[3], + ChainID: 3, Hash: common.NewRandomHash(), } req.Nil(objs[validators[3]].con.PrepareBlock(b32, time.Now().UTC())) @@ -286,10 +296,10 @@ func (s *ConsensusTestSuite) TestPrepareBlock() { con *Consensus }{app, con} } - b00 := s.prepareGenesisBlock(validators[0], objs[validators[0]].con) - b10 := s.prepareGenesisBlock(validators[1], objs[validators[1]].con) - b20 := s.prepareGenesisBlock(validators[2], objs[validators[2]].con) - b30 := s.prepareGenesisBlock(validators[3], objs[validators[3]].con) + b00 := s.prepareGenesisBlock(validators[0], 0, objs[validators[0]].con) + b10 := s.prepareGenesisBlock(validators[1], 1, objs[validators[1]].con) + b20 := s.prepareGenesisBlock(validators[2], 2, objs[validators[2]].con) + b30 := s.prepareGenesisBlock(validators[3], 3, objs[validators[3]].con) for _, obj := range objs { con := obj.con req.Nil(con.ProcessBlock(b00)) diff --git a/core/reliable-broadcast.go b/core/reliable-broadcast.go index d9a469a..918bad9 100644 --- a/core/reliable-broadcast.go +++ b/core/reliable-broadcast.go @@ -39,7 +39,7 @@ const ( // reliableBroadcast is a module for reliable broadcast. type reliableBroadcast struct { // lattice stores validator's blocks and other info. - lattice map[types.ValidatorID]*rbcValidatorStatus + lattice []*rbcValidatorStatus // blockInfos stores block infos. blockInfos map[common.Hash]*rbcBlockInfo @@ -47,6 +47,9 @@ type reliableBroadcast struct { // receivedBlocks stores blocks which is received but its acks are not all // in lattice. receivedBlocks map[common.Hash]*types.Block + + // validators stores validator set. + validators map[types.ValidatorID]struct{} } type rbcValidatorStatus struct { @@ -58,21 +61,22 @@ type rbcValidatorStatus struct { // acked height + 1. Initialized to 0, when genesis blocks are still not // being acked. For example, rb.lattice[vid1].NextAck[vid2] - 1 is the last // acked height by vid1 acking vid2. - nextAck map[types.ValidatorID]uint64 + nextAck []uint64 // nextOutput is the next output height of block, default to 0. nextOutput uint64 } type rbcBlockInfo struct { - block *types.Block - receivedTime time.Time - status blockStatus - ackedValidators map[types.ValidatorID]struct{} + block *types.Block + receivedTime time.Time + status blockStatus + ackedChain map[uint64]struct{} } // Errors for sanity check error. var ( + ErrInvalidChainID = fmt.Errorf("invalid chain id") ErrInvalidProposerID = fmt.Errorf("invalid proposer id") ErrInvalidTimestamp = fmt.Errorf("invalid timestamp") ErrForkBlock = fmt.Errorf("fork block") @@ -85,20 +89,25 @@ var ( // newReliableBroadcast creates a new reliableBroadcast struct. func newReliableBroadcast() *reliableBroadcast { return &reliableBroadcast{ - lattice: make(map[types.ValidatorID]*rbcValidatorStatus), blockInfos: make(map[common.Hash]*rbcBlockInfo), receivedBlocks: make(map[common.Hash]*types.Block), + validators: make(map[types.ValidatorID]struct{}), } } func (rb *reliableBroadcast) sanityCheck(b *types.Block) error { + // Check if the chain id is valid. + if b.ChainID >= uint64(len(rb.lattice)) { + return ErrInvalidChainID + } + // Check if its proposer is in validator set. - if _, exist := rb.lattice[b.ProposerID]; !exist { + if _, exist := rb.validators[b.ProposerID]; !exist { return ErrInvalidProposerID } // Check if it forks. - if bInLattice, exist := rb.lattice[b.ProposerID].blocks[b.Height]; exist { + if bInLattice, exist := rb.lattice[b.ChainID].blocks[b.Height]; exist { if b.Hash != bInLattice.Hash { return ErrForkBlock } @@ -120,20 +129,24 @@ func (rb *reliableBroadcast) sanityCheck(b *types.Block) error { for hash := range b.Acks { if bAckStat, exist := rb.blockInfos[hash]; exist { bAck := bAckStat.block - if bAck.Height < rb.lattice[b.ProposerID].nextAck[bAck.ProposerID] { + if bAck.Height < rb.lattice[b.ChainID].nextAck[bAck.ChainID] { return ErrDoubleAck } } } - // Check if its timestamp is valid. - for h := range rb.lattice { - if _, exist := b.Timestamps[h]; !exist { - return ErrInvalidTimestamp + // TODO(jimmy-dexon): verify the timestamps. + /* + // Check if its timestamp is valid. + for h := range rb.lattice { + if _, exist := b.Timestamps[h]; !exist { + return ErrInvalidTimestamp + } } - } - if bParent, exist := rb.lattice[b.ProposerID].blocks[b.Height-1]; exist { - for hash := range rb.lattice { + */ + + if bParent, exist := rb.lattice[b.ChainID].blocks[b.Height-1]; exist { + for hash := range b.Timestamps { if b.Timestamps[hash].Before(bParent.Timestamps[hash]) { return ErrInvalidTimestamp } @@ -154,7 +167,7 @@ func (rb *reliableBroadcast) areAllAcksInLattice(b *types.Block) bool { } bAck := bAckStat.block - bAckInLattice, exist := rb.lattice[bAck.ProposerID].blocks[bAck.Height] + bAckInLattice, exist := rb.lattice[bAck.ChainID].blocks[bAck.Height] if !exist { return false } @@ -173,9 +186,9 @@ func (rb *reliableBroadcast) processBlock(block *types.Block) (err error) { return } rb.blockInfos[block.Hash] = &rbcBlockInfo{ - block: block, - receivedTime: time.Now().UTC(), - ackedValidators: make(map[types.ValidatorID]struct{}), + block: block, + receivedTime: time.Now().UTC(), + ackedChain: make(map[uint64]struct{}), } rb.receivedBlocks[block.Hash] = block @@ -206,28 +219,28 @@ func (rb *reliableBroadcast) processBlock(block *types.Block) (err error) { continue // TODO(mission): how to return for multiple errors? } - rb.lattice[b.ProposerID].blocks[b.Height] = b + rb.lattice[b.ChainID].blocks[b.Height] = b delete(rb.receivedBlocks, b.Hash) for h := range b.Acks { bAckStat := rb.blockInfos[h] // Update nextAck only when bAckStat.block.Height + 1 is greater. A // block might ack blocks proposed by same validator with different // height. - if rb.lattice[b.ProposerID].nextAck[bAckStat.block.ProposerID] < bAckStat.block.Height+1 { - rb.lattice[b.ProposerID].nextAck[bAckStat.block.ProposerID] = bAckStat.block.Height + 1 + if rb.lattice[b.ChainID].nextAck[bAckStat.block.ChainID] < bAckStat.block.Height+1 { + rb.lattice[b.ChainID].nextAck[bAckStat.block.ChainID] = bAckStat.block.Height + 1 } - // Update ackedValidators for each ack blocks and its parents. + // Update ackedChain for each ack blocks and its parents. for { - if _, exist := bAckStat.ackedValidators[b.ProposerID]; exist { + if _, exist := bAckStat.ackedChain[b.ChainID]; exist { break } if bAckStat.status > blockStatusInit { break } - bAckStat.ackedValidators[b.ProposerID] = struct{}{} + bAckStat.ackedChain[b.ChainID] = struct{}{} // A block is strongly acked if it is acked by more than // 2 * (maximum number of byzatine validators) unique validators. - if len(bAckStat.ackedValidators) > 2*((len(rb.lattice)-1)/3) { + if len(bAckStat.ackedChain) > 2*((len(rb.lattice)-1)/3) { blocksToAcked[bAckStat.block.Hash] = bAckStat.block } if bAckStat.block.Height == 0 { @@ -371,19 +384,19 @@ func (rb *reliableBroadcast) prepareBlock(block *types.Block) { } // Initial timestamps with current validator set. times := make(map[types.ValidatorID]time.Time) - for vID := range rb.lattice { + for vID := range rb.validators { times[vID] = time.Time{} } acks := make(map[common.Hash]struct{}) - for vID := range rb.lattice { + for chainID := range rb.lattice { // find height of the latest block for that validator. var ( curBlock *types.Block - nextHeight = rb.lattice[block.ProposerID].nextAck[vID] + nextHeight = rb.lattice[block.ChainID].nextAck[chainID] ) for { - tmpBlock, exists := rb.lattice[vID].blocks[nextHeight] + tmpBlock, exists := rb.lattice[chainID].blocks[nextHeight] if !exists { break } @@ -395,7 +408,7 @@ func (rb *reliableBroadcast) prepareBlock(block *types.Block) { } acks[curBlock.Hash] = struct{}{} accumulateTimestamps(times, curBlock) - if vID == block.ProposerID { + if uint64(chainID) == block.ChainID { block.ParentHash = curBlock.Hash block.Height = curBlock.Height + 1 } @@ -407,17 +420,22 @@ func (rb *reliableBroadcast) prepareBlock(block *types.Block) { // addValidator adds validator in the validator set. func (rb *reliableBroadcast) addValidator(h types.ValidatorID) { - rb.lattice[h] = &rbcValidatorStatus{ - blocks: make(map[uint64]*types.Block), - nextAck: make(map[types.ValidatorID]uint64), - nextOutput: 0, - } + rb.validators[h] = struct{}{} } // deleteValidator deletes validator in validator set. func (rb *reliableBroadcast) deleteValidator(h types.ValidatorID) { - for h := range rb.lattice { - delete(rb.lattice[h].nextAck, h) + delete(rb.validators, h) +} + +// setChainNum set the number of chains. +func (rb *reliableBroadcast) setChainNum(num int) { + rb.lattice = make([]*rbcValidatorStatus, num) + for i := range rb.lattice { + rb.lattice[i] = &rbcValidatorStatus{ + blocks: make(map[uint64]*types.Block), + nextAck: make([]uint64, num), + nextOutput: 0, + } } - delete(rb.lattice, h) } diff --git a/core/reliable-broadcast_test.go b/core/reliable-broadcast_test.go index 28edda7..0dcbb80 100644 --- a/core/reliable-broadcast_test.go +++ b/core/reliable-broadcast_test.go @@ -56,6 +56,12 @@ func (s *ReliableBroadcastTest) prepareGenesisBlock( Acks: make(map[common.Hash]struct{}), Timestamps: genTimestamps(validatorIDs), } + for i, vID := range validatorIDs { + if proposerID == vID { + b.ChainID = uint64(i) + break + } + } for _, vID := range validatorIDs { b.Timestamps[vID] = time.Time{} } @@ -94,6 +100,7 @@ func genTestCase1(s *ReliableBroadcastTest, rb *reliableBroadcast) []types.Valid rb.addValidator(vid) vids = append(vids, vid) } + rb.setChainNum(len(vids)) // Add genesis blocks. for _, vid := range vids { b = s.prepareGenesisBlock(vid, vids) @@ -101,13 +108,14 @@ func genTestCase1(s *ReliableBroadcastTest, rb *reliableBroadcast) []types.Valid } // Add block 0-1 which acks 0-0. - h = rb.lattice[vids[0]].blocks[0].Hash + h = rb.lattice[0].blocks[0].Hash b = &types.Block{ ProposerID: vids[0], ParentHash: h, Hash: common.NewRandomHash(), Timestamps: genTimestamps(vids), Height: 1, + ChainID: 0, Acks: map[common.Hash]struct{}{ h: struct{}{}, }, @@ -116,33 +124,35 @@ func genTestCase1(s *ReliableBroadcastTest, rb *reliableBroadcast) []types.Valid b.Hash, err = hashBlock(b) s.Require().Nil(err) s.Require().Nil(rb.processBlock(b)) - s.Require().NotNil(rb.lattice[vids[0]].blocks[1]) + s.Require().NotNil(rb.lattice[0].blocks[1]) // Add block 0-2 which acks 0-1 and 1-0. - h = rb.lattice[vids[0]].blocks[1].Hash + h = rb.lattice[0].blocks[1].Hash b = &types.Block{ ProposerID: vids[0], ParentHash: h, Height: 2, + ChainID: 0, Timestamps: genTimestamps(vids), Acks: map[common.Hash]struct{}{ h: struct{}{}, - rb.lattice[vids[1]].blocks[0].Hash: struct{}{}, + rb.lattice[1].blocks[0].Hash: struct{}{}, }, } b.Hash, err = hashBlock(b) s.Require().Nil(err) s.Require().Nil(rb.processBlock(b)) - s.Require().NotNil(rb.lattice[vids[0]].blocks[2]) + s.Require().NotNil(rb.lattice[0].blocks[2]) // Add block 0-3 which acks 0-2. - h = rb.lattice[vids[0]].blocks[2].Hash + h = rb.lattice[0].blocks[2].Hash b = &types.Block{ ProposerID: vids[0], ParentHash: h, Hash: common.NewRandomHash(), Timestamps: genTimestamps(vids), Height: 3, + ChainID: 0, Acks: map[common.Hash]struct{}{ h: struct{}{}, }, @@ -150,16 +160,17 @@ func genTestCase1(s *ReliableBroadcastTest, rb *reliableBroadcast) []types.Valid b.Hash, err = hashBlock(b) s.Require().Nil(err) s.Require().Nil(rb.processBlock(b)) - s.Require().NotNil(rb.lattice[vids[0]].blocks[3]) + s.Require().NotNil(rb.lattice[0].blocks[3]) // Add block 3-1 which acks 3-0. - h = rb.lattice[vids[3]].blocks[0].Hash + h = rb.lattice[3].blocks[0].Hash b = &types.Block{ ProposerID: vids[3], ParentHash: h, Hash: common.NewRandomHash(), Timestamps: genTimestamps(vids), Height: 1, + ChainID: 3, Acks: map[common.Hash]struct{}{ h: struct{}{}, }, @@ -167,7 +178,7 @@ func genTestCase1(s *ReliableBroadcastTest, rb *reliableBroadcast) []types.Valid b.Hash, err = hashBlock(b) s.Require().Nil(err) s.Require().Nil(rb.processBlock(b)) - s.Require().NotNil(rb.lattice[vids[3]].blocks[0]) + s.Require().NotNil(rb.lattice[3].blocks[0]) return vids } @@ -195,6 +206,7 @@ func (s *ReliableBroadcastTest) TestSanityCheck() { ProposerID: vids[0], ParentHash: common.NewRandomHash(), Height: 10, + ChainID: 0, Acks: make(map[common.Hash]struct{}), } b.Hash, err = hashBlock(b) @@ -208,8 +220,9 @@ func (s *ReliableBroadcastTest) TestSanityCheck() { ProposerID: vids[1], ParentHash: common.NewRandomHash(), Height: 1, + ChainID: 1, Acks: map[common.Hash]struct{}{ - rb.lattice[vids[2]].blocks[0].Hash: struct{}{}, + rb.lattice[2].blocks[0].Hash: struct{}{}, }, } b.Hash, err = hashBlock(b) @@ -219,11 +232,12 @@ func (s *ReliableBroadcastTest) TestSanityCheck() { s.Require().Equal(ErrNotAckParent.Error(), err.Error()) // Non-genesis block which acks its parent but the height is invalid. - h = rb.lattice[vids[1]].blocks[0].Hash + h = rb.lattice[1].blocks[0].Hash b = &types.Block{ ProposerID: vids[1], ParentHash: h, Height: 2, + ChainID: 1, Acks: map[common.Hash]struct{}{ h: struct{}{}, }, @@ -235,7 +249,7 @@ func (s *ReliableBroadcastTest) TestSanityCheck() { s.Require().Equal(ErrInvalidBlockHeight.Error(), err.Error()) // Invalid proposer ID. - h = rb.lattice[vids[1]].blocks[0].Hash + h = rb.lattice[1].blocks[0].Hash b = &types.Block{ ProposerID: types.ValidatorID{Hash: common.NewRandomHash()}, ParentHash: h, @@ -250,12 +264,30 @@ func (s *ReliableBroadcastTest) TestSanityCheck() { s.Require().NotNil(err) s.Require().Equal(ErrInvalidProposerID.Error(), err.Error()) + // Invalid chain ID. + h = rb.lattice[1].blocks[0].Hash + b = &types.Block{ + ProposerID: vids[1], + ParentHash: h, + Height: 1, + ChainID: 100, + Acks: map[common.Hash]struct{}{ + h: struct{}{}, + }, + } + b.Hash, err = hashBlock(b) + s.Require().Nil(err) + err = rb.sanityCheck(b) + s.Require().NotNil(err) + s.Require().Equal(ErrInvalidChainID.Error(), err.Error()) + // Fork block. - h = rb.lattice[vids[0]].blocks[0].Hash + h = rb.lattice[0].blocks[0].Hash b = &types.Block{ ProposerID: vids[0], ParentHash: h, Height: 1, + ChainID: 0, Acks: map[common.Hash]struct{}{ h: struct{}{}, }, @@ -270,14 +302,15 @@ func (s *ReliableBroadcastTest) TestSanityCheck() { s.Require().Equal(ErrForkBlock.Error(), err.Error()) // Replicated ack. - h = rb.lattice[vids[0]].blocks[3].Hash + h = rb.lattice[0].blocks[3].Hash b = &types.Block{ ProposerID: vids[0], ParentHash: h, Height: 4, + ChainID: 0, Acks: map[common.Hash]struct{}{ h: struct{}{}, - rb.lattice[vids[1]].blocks[0].Hash: struct{}{}, + rb.lattice[1].blocks[0].Hash: struct{}{}, }, } b.Hash, err = hashBlock(b) @@ -287,11 +320,12 @@ func (s *ReliableBroadcastTest) TestSanityCheck() { s.Require().Equal(ErrDoubleAck.Error(), err.Error()) // Normal block. - h = rb.lattice[vids[1]].blocks[0].Hash + h = rb.lattice[1].blocks[0].Hash b = &types.Block{ ProposerID: vids[1], ParentHash: h, Height: 1, + ChainID: 1, Acks: map[common.Hash]struct{}{ h: struct{}{}, common.NewRandomHash(): struct{}{}, @@ -306,9 +340,8 @@ func (s *ReliableBroadcastTest) TestSanityCheck() { func (s *ReliableBroadcastTest) TestAreAllAcksInLattice() { var b *types.Block - var vids []types.ValidatorID rb := newReliableBroadcast() - vids = genTestCase1(s, rb) + genTestCase1(s, rb) // Empty ack should get true, although won't pass sanity check. b = &types.Block{ @@ -319,8 +352,8 @@ func (s *ReliableBroadcastTest) TestAreAllAcksInLattice() { // Acks blocks in lattice b = &types.Block{ Acks: map[common.Hash]struct{}{ - rb.lattice[vids[0]].blocks[0].Hash: struct{}{}, - rb.lattice[vids[0]].blocks[1].Hash: struct{}{}, + rb.lattice[0].blocks[0].Hash: struct{}{}, + rb.lattice[0].blocks[1].Hash: struct{}{}, }, } s.Require().True(rb.areAllAcksInLattice(b)) @@ -343,29 +376,30 @@ func (s *ReliableBroadcastTest) TestStrongAck() { // Check block 0-0 to 0-3 before adding 1-1 and 2-1. for i := uint64(0); i < 4; i++ { - s.Require().Equal(blockStatusInit, rb.blockInfos[rb.lattice[vids[0]].blocks[i].Hash].status) + s.Require().Equal(blockStatusInit, rb.blockInfos[rb.lattice[0].blocks[i].Hash].status) } // Add block 1-1 which acks 1-0 and 0-2, and block 0-0 to 0-3 are still // in blockStatusInit, because they are not strongly acked. b = &types.Block{ ProposerID: vids[1], - ParentHash: rb.lattice[vids[1]].blocks[0].Hash, + ParentHash: rb.lattice[1].blocks[0].Hash, Hash: common.NewRandomHash(), Height: 1, + ChainID: 1, Timestamps: genTimestamps(vids), Acks: map[common.Hash]struct{}{ - rb.lattice[vids[0]].blocks[2].Hash: struct{}{}, - rb.lattice[vids[1]].blocks[0].Hash: struct{}{}, + rb.lattice[0].blocks[2].Hash: struct{}{}, + rb.lattice[1].blocks[0].Hash: struct{}{}, }, } var err error b.Hash, err = hashBlock(b) s.Require().Nil(err) s.Require().Nil(rb.processBlock(b)) - s.Require().NotNil(rb.lattice[vids[1]].blocks[1]) + s.Require().NotNil(rb.lattice[1].blocks[1]) for i := uint64(0); i < 4; i++ { - h := rb.lattice[vids[0]].blocks[i].Hash + h := rb.lattice[0].blocks[i].Hash s.Require().Equal(blockStatusInit, rb.blockInfos[h].status) } @@ -373,23 +407,24 @@ func (s *ReliableBroadcastTest) TestStrongAck() { // 0-3 is still not. b = &types.Block{ ProposerID: vids[2], - ParentHash: rb.lattice[vids[2]].blocks[0].Hash, + ParentHash: rb.lattice[2].blocks[0].Hash, Hash: common.NewRandomHash(), Height: 1, + ChainID: 2, Timestamps: genTimestamps(vids), Acks: map[common.Hash]struct{}{ - rb.lattice[vids[0]].blocks[2].Hash: struct{}{}, - rb.lattice[vids[2]].blocks[0].Hash: struct{}{}, + rb.lattice[0].blocks[2].Hash: struct{}{}, + rb.lattice[2].blocks[0].Hash: struct{}{}, }, } b.Hash, err = hashBlock(b) s.Require().Nil(err) s.Require().Nil(rb.processBlock(b)) - s.Require().Equal(blockStatusAcked, rb.blockInfos[rb.lattice[vids[0]].blocks[0].Hash].status) - s.Require().Equal(blockStatusAcked, rb.blockInfos[rb.lattice[vids[0]].blocks[1].Hash].status) - s.Require().Equal(blockStatusAcked, rb.blockInfos[rb.lattice[vids[0]].blocks[2].Hash].status) - s.Require().Equal(blockStatusInit, rb.blockInfos[rb.lattice[vids[0]].blocks[3].Hash].status) + s.Require().Equal(blockStatusAcked, rb.blockInfos[rb.lattice[0].blocks[0].Hash].status) + s.Require().Equal(blockStatusAcked, rb.blockInfos[rb.lattice[0].blocks[1].Hash].status) + s.Require().Equal(blockStatusAcked, rb.blockInfos[rb.lattice[0].blocks[2].Hash].status) + s.Require().Equal(blockStatusInit, rb.blockInfos[rb.lattice[0].blocks[3].Hash].status) } func (s *ReliableBroadcastTest) TestExtractBlocks() { @@ -400,14 +435,15 @@ func (s *ReliableBroadcastTest) TestExtractBlocks() { // Add block 1-1 which acks 1-0, 0-2, 3-0. b = &types.Block{ ProposerID: vids[1], - ParentHash: rb.lattice[vids[1]].blocks[0].Hash, + ParentHash: rb.lattice[1].blocks[0].Hash, Hash: common.NewRandomHash(), Height: 1, + ChainID: 1, Timestamps: genTimestamps(vids), Acks: map[common.Hash]struct{}{ - rb.lattice[vids[0]].blocks[2].Hash: struct{}{}, - rb.lattice[vids[1]].blocks[0].Hash: struct{}{}, - rb.lattice[vids[3]].blocks[0].Hash: struct{}{}, + rb.lattice[0].blocks[2].Hash: struct{}{}, + rb.lattice[1].blocks[0].Hash: struct{}{}, + rb.lattice[3].blocks[0].Hash: struct{}{}, }, } var err error @@ -418,14 +454,15 @@ func (s *ReliableBroadcastTest) TestExtractBlocks() { // Add block 2-1 which acks 0-2, 2-0, 3-0. b = &types.Block{ ProposerID: vids[2], - ParentHash: rb.lattice[vids[2]].blocks[0].Hash, + ParentHash: rb.lattice[2].blocks[0].Hash, Hash: common.NewRandomHash(), Height: 1, + ChainID: 2, Timestamps: genTimestamps(vids), Acks: map[common.Hash]struct{}{ - rb.lattice[vids[0]].blocks[2].Hash: struct{}{}, - rb.lattice[vids[2]].blocks[0].Hash: struct{}{}, - rb.lattice[vids[3]].blocks[0].Hash: struct{}{}, + rb.lattice[0].blocks[2].Hash: struct{}{}, + rb.lattice[2].blocks[0].Hash: struct{}{}, + rb.lattice[3].blocks[0].Hash: struct{}{}, }, } b.Hash, err = hashBlock(b) @@ -433,9 +470,9 @@ func (s *ReliableBroadcastTest) TestExtractBlocks() { s.Require().Nil(rb.processBlock(b)) hashes := []common.Hash{ - rb.lattice[vids[0]].blocks[0].Hash, - rb.lattice[vids[0]].blocks[1].Hash, - rb.lattice[vids[3]].blocks[0].Hash, + rb.lattice[0].blocks[0].Hash, + rb.lattice[0].blocks[1].Hash, + rb.lattice[3].blocks[0].Hash, } hashExtracted := map[common.Hash]*types.Block{} for _, b := range rb.extractBlocks() { @@ -458,6 +495,7 @@ func (s *ReliableBroadcastTest) TestRandomIntensiveAcking() { for _, vid := range vids { rb.addValidator(vid) } + rb.setChainNum(len(vids)) // Generate genesis blocks. for _, vid := range vids { b := s.prepareGenesisBlock(vid, vids) @@ -466,13 +504,14 @@ func (s *ReliableBroadcastTest) TestRandomIntensiveAcking() { } for i := 0; i < 5000; i++ { - vid := vids[rand.Int()%len(vids)] + id := rand.Int() % len(vids) + vid := vids[id] height := heights[vid] heights[vid]++ - parentHash := rb.lattice[vid].blocks[height-1].Hash + parentHash := rb.lattice[id].blocks[height-1].Hash acks := map[common.Hash]struct{}{} - for _, vid2 := range vids { - if b, exist := rb.lattice[vid2].blocks[rb.lattice[vid].nextAck[vid2]]; exist { + for id2 := range vids { + if b, exist := rb.lattice[id2].blocks[rb.lattice[id].nextAck[id2]]; exist { acks[b.Hash] = struct{}{} } } @@ -480,6 +519,7 @@ func (s *ReliableBroadcastTest) TestRandomIntensiveAcking() { ProposerID: vid, ParentHash: parentHash, Height: height, + ChainID: uint64(id), Timestamps: genTimestamps(vids), Acks: acks, } @@ -526,6 +566,7 @@ func (s *ReliableBroadcastTest) TestRandomlyGeneratedBlocks() { for i := 0; i < repeat; i++ { validators := map[types.ValidatorID]struct{}{} rb := newReliableBroadcast() + rb.setChainNum(validatorCount) stronglyAckedHashes := common.Hashes{} revealer.Reset() @@ -580,6 +621,7 @@ func (s *ReliableBroadcastTest) TestPrepareBlock() { for _, vID := range validators { rb.addValidator(vID) } + rb.setChainNum(len(validators)) // Setup genesis blocks. b00 := s.prepareGenesisBlock(validators[0], validators) time.Sleep(minInterval) @@ -597,6 +639,7 @@ func (s *ReliableBroadcastTest) TestPrepareBlock() { // prepareBlock. b11 := &types.Block{ ProposerID: validators[1], + ChainID: 1, } rb.prepareBlock(b11) var err error @@ -620,6 +663,7 @@ func (s *ReliableBroadcastTest) TestPrepareBlock() { // Propose/Process a block based on collected info. b12 := &types.Block{ ProposerID: validators[1], + ChainID: 1, } rb.prepareBlock(b12) b12.Hash, err = hashBlock(b12) @@ -633,6 +677,7 @@ func (s *ReliableBroadcastTest) TestPrepareBlock() { // get 4 blocks to ack. b01 := &types.Block{ ProposerID: validators[0], + ChainID: 0, } rb.prepareBlock(b01) b01.Hash, err = hashBlock(b01) diff --git a/core/test/blocks-generator.go b/core/test/blocks-generator.go index b05d08f..3485b77 100644 --- a/core/test/blocks-generator.go +++ b/core/test/blocks-generator.go @@ -163,6 +163,11 @@ func (vs *validatorSetStatus) proposeBlock( Timestamps: ts, // TODO(mission.liao): Generate timestamp. } + for i, vID := range vs.validatorIDs { + if vID == proposerID { + newBlock.ChainID = uint64(i) + } + } var err error newBlock.Hash, err = vs.hashBlock(newBlock) if err != nil { diff --git a/integration_test/validator.go b/integration_test/validator.go index 2cb7e43..60c6b1f 100644 --- a/integration_test/validator.go +++ b/integration_test/validator.go @@ -19,9 +19,11 @@ package integration import ( "fmt" + "sort" "time" "github.com/dexon-foundation/dexon-consensus-core/blockdb" + "github.com/dexon-foundation/dexon-consensus-core/common" "github.com/dexon-foundation/dexon-consensus-core/core" "github.com/dexon-foundation/dexon-consensus-core/core/test" "github.com/dexon-foundation/dexon-consensus-core/core/types" @@ -63,6 +65,7 @@ func NewReceiveBlockEvent( // Validator is designed to work with test.Scheduler. type Validator struct { ID types.ValidatorID + chainID uint64 cons *core.Consensus gov core.Governance networkLatency LatencyModel @@ -79,8 +82,22 @@ func NewValidator( networkLatency LatencyModel, proposingLatency LatencyModel) *Validator { + hashes := make(common.Hashes, 0) + for vID := range gov.GetValidatorSet() { + hashes = append(hashes, vID.Hash) + } + sort.Sort(hashes) + chainID := uint64(0) + for i, hash := range hashes { + if hash == vID.Hash { + chainID = uint64(i) + break + } + } + return &Validator{ ID: vID, + chainID: chainID, gov: gov, networkLatency: networkLatency, proposingLatency: proposingLatency, @@ -106,7 +123,10 @@ func (v *Validator) Handle(e *test.Event) (events []*test.Event) { func (v *Validator) handleProposeBlock(when time.Time, piggyback interface{}) ( events []*test.Event, err error) { - b := &types.Block{ProposerID: v.ID} + b := &types.Block{ + ProposerID: v.ID, + ChainID: v.chainID, + } defer types.RecycleBlock(b) if err = v.cons.PrepareBlock(b, when); err != nil { return diff --git a/simulation/validator.go b/simulation/validator.go index 24de155..302f3af 100644 --- a/simulation/validator.go +++ b/simulation/validator.go @@ -19,6 +19,7 @@ package simulation import ( "fmt" + "sort" "time" "github.com/dexon-foundation/dexon-consensus-core/blockdb" @@ -41,6 +42,7 @@ type Validator struct { isFinished chan struct{} ID types.ValidatorID + chainID uint64 prvKey crypto.PrivateKey sigToPub core.SigToPubFn consensus *core.Consensus @@ -84,14 +86,24 @@ func (v *Validator) GetID() types.ValidatorID { func (v *Validator) Run() { v.msgChannel = v.network.Join(v) + hashes := make(common.Hashes, 0, v.network.NumPeers()) for _, vID := range v.network.Endpoints() { v.gov.addValidator(vID) + hashes = append(hashes, vID.Hash) + } + sort.Sort(hashes) + for i, hash := range hashes { + if hash == v.ID.Hash { + v.chainID = uint64(i) + break + } } v.consensus = core.NewConsensus( v.app, v.gov, v.db, v.prvKey, v.sigToPub) genesisBlock := &types.Block{ ProposerID: v.ID, + ChainID: v.chainID, } err := v.consensus.PrepareGenesisBlock(genesisBlock, time.Now().UTC()) if err != nil { @@ -188,6 +200,7 @@ ProposingBlockLoop: block := &types.Block{ ProposerID: v.ID, + ChainID: v.chainID, Hash: common.NewRandomHash(), } if err := v.consensus.PrepareBlock(block, time.Now().UTC()); err != nil { |