From 06693fc13b451835ac460688903c7abb660710fb Mon Sep 17 00:00:00 2001 From: Mission Liao Date: Thu, 13 Dec 2018 09:55:14 +0800 Subject: db: rename blockdb to db (#367) * Rename blockdb package to db * Rename 'BlockDB' to 'DB' * Make all methods in db specific for ''block'. * Rename db.BlockDatabase to db.Database * Rename revealer to block-revealer * Rename test.Revealer to test.BlockRevealer --- core/test/block-revealer.go | 332 +++++++++++++++++++++++++++++++++++++ core/test/block-revealer_test.go | 222 +++++++++++++++++++++++++ core/test/blocks-generator.go | 22 +-- core/test/blocks-generator_test.go | 68 ++++---- core/test/interface.go | 8 +- core/test/revealer.go | 331 ------------------------------------ core/test/revealer_test.go | 222 ------------------------- core/test/stopper.go | 18 +- core/test/stopper_test.go | 54 +++--- 9 files changed, 640 insertions(+), 637 deletions(-) create mode 100644 core/test/block-revealer.go create mode 100644 core/test/block-revealer_test.go delete mode 100644 core/test/revealer.go delete mode 100644 core/test/revealer_test.go (limited to 'core/test') diff --git a/core/test/block-revealer.go b/core/test/block-revealer.go new file mode 100644 index 0000000..ebd2e35 --- /dev/null +++ b/core/test/block-revealer.go @@ -0,0 +1,332 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// . + +package test + +import ( + "errors" + "math/rand" + "sort" + "time" + + "github.com/dexon-foundation/dexon-consensus/common" + "github.com/dexon-foundation/dexon-consensus/core/db" + "github.com/dexon-foundation/dexon-consensus/core/types" +) + +// Errors returns from block-revealer. +var ( + ErrNotValidCompactionChain = errors.New("not valid compaction chain") +) + +// isAllAckingBlockRevealed is a helper to check if all acking blocks of +// one block are revealed. +func isAllAckingBlockRevealed( + b *types.Block, revealed map[common.Hash]struct{}) bool { + + for _, ack := range b.Acks { + if _, exists := revealed[ack]; !exists { + return false + } + } + return true +} + +// loadAllBlocks is a helper to load all blocks from db.BlockIterator. +func loadAllBlocks(iter db.BlockIterator) ( + blocks map[common.Hash]*types.Block, err error) { + + blocks = make(map[common.Hash]*types.Block) + for { + block, err := iter.NextBlock() + if err != nil { + if err == db.ErrIterationFinished { + // It's safe to ignore iteraion-finished error. + err = nil + } + break + } + blocks[block.Hash] = &block + } + return +} + +// RandomDAGBlockRevealer implements BlockRevealer interface, which would load +// all blocks from db, and randomly pick one block to reveal if it still forms +// a valid DAG in revealed blocks. +type RandomDAGBlockRevealer struct { + // blocksByChain group all blocks by chains and sorting + // them by height. + blocksByChain map[uint32][]*types.Block + // tipIndexes store the height of next block from one chain + // to check if is candidate. + tipIndexes map[uint32]int + // candidate are blocks that forms valid DAG with + // current revealed blocks. + candidates []*types.Block + candidateChains map[uint32]struct{} + // revealed stores block hashes of current revealed blocks. + revealed map[common.Hash]struct{} + randGen *rand.Rand +} + +// NewRandomDAGBlockRevealer constructs RandomDAGBlockRevealer. +func NewRandomDAGBlockRevealer( + iter db.BlockIterator) (r *RandomDAGBlockRevealer, err error) { + + blocks, err := loadAllBlocks(iter) + if err != nil { + return + } + + // Rearrange blocks by nodes and height. + blocksByChain := make(map[uint32][]*types.Block) + for _, block := range blocks { + blocksByChain[block.Position.ChainID] = + append(blocksByChain[block.Position.ChainID], block) + } + // Make sure blocks are sorted by block heights, from lower to higher. + for chainID := range blocksByChain { + sort.Sort(types.ByPosition(blocksByChain[chainID])) + } + r = &RandomDAGBlockRevealer{ + blocksByChain: blocksByChain, + randGen: rand.New(rand.NewSource(time.Now().UnixNano())), + candidateChains: make(map[uint32]struct{}), + } + // Make sure this revealer is ready to use. + r.Reset() + return +} + +// pickCandidates is a helper function to pick candidates from current tips. +func (r *RandomDAGBlockRevealer) pickCandidates() { + for chainID, tip := range r.tipIndexes { + if _, isPicked := r.candidateChains[chainID]; isPicked { + continue + } + blocks, exists := r.blocksByChain[chainID] + if !exists { + continue + } + if tip >= len(blocks) { + continue + } + block := blocks[tip] + if isAllAckingBlockRevealed(block, r.revealed) { + r.tipIndexes[chainID]++ + r.candidates = append(r.candidates, block) + r.candidateChains[chainID] = struct{}{} + } + } +} + +// NextBlock implement Revealer.Next method, which would reveal blocks +// forming valid DAGs. +func (r *RandomDAGBlockRevealer) NextBlock() (types.Block, error) { + if len(r.candidates) == 0 { + r.pickCandidates() + if len(r.candidates) == 0 { + return types.Block{}, db.ErrIterationFinished + } + } + + // Pick next block to be revealed. + picked := r.randGen.Intn(len(r.candidates)) + block := r.candidates[picked] + r.candidates = + append(r.candidates[:picked], r.candidates[picked+1:]...) + delete(r.candidateChains, block.Position.ChainID) + r.revealed[block.Hash] = struct{}{} + r.pickCandidates() + return *block, nil +} + +// Reset implement Revealer.Reset method, which would reset the revealing. +func (r *RandomDAGBlockRevealer) Reset() { + r.tipIndexes = make(map[uint32]int) + for chainID := range r.blocksByChain { + r.tipIndexes[chainID] = 0 + } + r.revealed = make(map[common.Hash]struct{}) + r.candidates = []*types.Block{} +} + +// RandomBlockRevealer implements BlockRevealer interface, which would load +// all blocks from db, and randomly pick one block to reveal. +type RandomBlockRevealer struct { + blocks map[common.Hash]*types.Block + remains common.Hashes + randGen *rand.Rand +} + +// NewRandomBlockRevealer constructs RandomBlockRevealer. +func NewRandomBlockRevealer( + iter db.BlockIterator) (r *RandomBlockRevealer, err error) { + + blocks, err := loadAllBlocks(iter) + if err != nil { + return + } + r = &RandomBlockRevealer{ + blocks: blocks, + randGen: rand.New(rand.NewSource(time.Now().UnixNano())), + } + r.Reset() + return +} + +// NextBlock implements Revealer.NextBlock method, which would reveal blocks +// randomly. +func (r *RandomBlockRevealer) NextBlock() (types.Block, error) { + if len(r.remains) == 0 { + return types.Block{}, db.ErrIterationFinished + } + + picked := r.randGen.Intn(len(r.remains)) + block := r.blocks[r.remains[picked]] + r.remains = + append(r.remains[:picked], r.remains[picked+1:]...) + return *block, nil +} + +// Reset implement Revealer.Reset method, which would reset revealing. +func (r *RandomBlockRevealer) Reset() { + hashes := common.Hashes{} + for hash := range r.blocks { + hashes = append(hashes, hash) + } + r.remains = hashes +} + +// RandomTipBlockRevealer implements BlockRevealer interface, which would load +// all blocks from db, and randomly pick one chain's tip to reveal. +type RandomTipBlockRevealer struct { + chainsBlock []map[uint64]*types.Block + chainTip []uint64 + chainRevealSeq []uint32 + revealed int + randGen *rand.Rand +} + +// NewRandomTipBlockRevealer constructs RandomTipBlockRevealer. +func NewRandomTipBlockRevealer( + iter db.BlockIterator) (r *RandomTipBlockRevealer, err error) { + + blocks, err := loadAllBlocks(iter) + if err != nil { + return + } + r = &RandomTipBlockRevealer{ + randGen: rand.New(rand.NewSource(time.Now().UnixNano())), + } + for _, b := range blocks { + for b.Position.ChainID >= uint32(len(r.chainsBlock)) { + r.chainsBlock = append(r.chainsBlock, make(map[uint64]*types.Block)) + r.chainTip = append(r.chainTip, 0) + } + r.chainsBlock[b.Position.ChainID][b.Position.Height] = b + r.chainRevealSeq = append(r.chainRevealSeq, b.Position.ChainID) + } + r.Reset() + return +} + +// NextBlock implements Revealer.Next method, which would reveal blocks randomly. +func (r *RandomTipBlockRevealer) NextBlock() (types.Block, error) { + if len(r.chainRevealSeq) == r.revealed { + return types.Block{}, db.ErrIterationFinished + } + + picked := r.chainRevealSeq[r.revealed] + r.revealed++ + block := r.chainsBlock[picked][r.chainTip[picked]] + r.chainTip[picked]++ + return *block, nil +} + +// Reset implement Revealer.Reset method, which would reset revealing. +func (r *RandomTipBlockRevealer) Reset() { + r.revealed = 0 + r.randGen.Shuffle(len(r.chainRevealSeq), func(i, j int) { + r.chainRevealSeq[i], r.chainRevealSeq[j] = + r.chainRevealSeq[j], r.chainRevealSeq[i] + }) + for i := range r.chainTip { + r.chainTip[i] = 0 + } +} + +// CompactionChainBlockRevealer implements BlockRevealer interface, which would +// load all blocks from db, reveal them in the order of compaction chain, +// from the genesis block to the latest one. +type CompactionChainBlockRevealer struct { + blocks types.ByFinalizationHeight + nextRevealIndex int +} + +// NewCompactionChainBlockRevealer constructs a block revealer in the order of +// compaction chain. +func NewCompactionChainBlockRevealer(iter db.BlockIterator, + startHeight uint64) (r *CompactionChainBlockRevealer, err error) { + blocksByHash, err := loadAllBlocks(iter) + if err != nil { + return + } + if startHeight == 0 { + startHeight = 1 + } + blocks := types.ByFinalizationHeight{} + for _, b := range blocksByHash { + if b.Finalization.Height < startHeight { + continue + } + blocks = append(blocks, b) + } + sort.Sort(types.ByFinalizationHeight(blocks)) + // Make sure the finalization height of blocks are incremental with step 1. + for idx, b := range blocks { + if idx == 0 { + continue + } + if b.Finalization.Height != blocks[idx-1].Finalization.Height+1 { + err = ErrNotValidCompactionChain + return + } + } + r = &CompactionChainBlockRevealer{ + blocks: blocks, + } + r.Reset() + return +} + +// NextBlock implements Revealer.Next method, which would reveal blocks in the +// order of compaction chain. +func (r *CompactionChainBlockRevealer) NextBlock() (types.Block, error) { + if r.nextRevealIndex == len(r.blocks) { + return types.Block{}, db.ErrIterationFinished + } + b := r.blocks[r.nextRevealIndex] + r.nextRevealIndex++ + return *b, nil +} + +// Reset implement Revealer.Reset method, which would reset revealing. +func (r *CompactionChainBlockRevealer) Reset() { + r.nextRevealIndex = 0 +} diff --git a/core/test/block-revealer_test.go b/core/test/block-revealer_test.go new file mode 100644 index 0000000..ba4cf71 --- /dev/null +++ b/core/test/block-revealer_test.go @@ -0,0 +1,222 @@ +// Copyright 2018 The dexon-consensus Authors +// This file is part of the dexon-consensus library. +// +// The dexon-consensus library is free software: you can redistribute it +// and/or modify it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation, either version 3 of the License, +// or (at your option) any later version. +// +// The dexon-consensus library is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the dexon-consensus library. If not, see +// . + +package test + +import ( + "testing" + "time" + + "github.com/dexon-foundation/dexon-consensus/common" + "github.com/dexon-foundation/dexon-consensus/core/db" + "github.com/dexon-foundation/dexon-consensus/core/types" + "github.com/stretchr/testify/suite" +) + +type BlockRevealerTestSuite struct { + suite.Suite + + db db.Database + totalBlockCount int +} + +func (s *BlockRevealerTestSuite) SetupSuite() { + var ( + err error + genesisTime = time.Now().UTC() + ) + // Setup block database. + s.db, err = db.NewMemBackedDB() + s.Require().NoError(err) + + // Randomly generate blocks. + config := &BlocksGeneratorConfig{ + NumChains: 19, + MinBlockTimeInterval: 250 * time.Millisecond, + } + gen := NewBlocksGenerator(config, nil, stableRandomHash) + s.Require().NoError(gen.Generate( + 0, + genesisTime, + genesisTime.Add(30*time.Second), + s.db)) + // Cache the count of total generated block. + iter, err := s.db.GetAllBlocks() + s.Require().NoError(err) + blocks, err := loadAllBlocks(iter) + s.Require().NoError(err) + s.totalBlockCount = len(blocks) +} + +func (s *BlockRevealerTestSuite) baseTest( + revealer BlockRevealer, + repeat int, + checkFunc func(*types.Block, map[common.Hash]struct{})) { + + revealingSequence := map[string]struct{}{} + for i := 0; i < repeat; i++ { + revealed := map[common.Hash]struct{}{} + sequence := "" + for { + b, err := revealer.NextBlock() + if err != nil { + if err == db.ErrIterationFinished { + err = nil + break + } + s.Require().NotNil(err) + } + checkFunc(&b, revealed) + revealed[b.Hash] = struct{}{} + sequence += b.Hash.String() + "," + } + s.Len(revealed, s.totalBlockCount) + revealingSequence[sequence] = struct{}{} + revealer.Reset() + } + // It should be reasonable to reveal at least two + // different sequence. + s.True(len(revealingSequence) > 1) + +} + +func (s *BlockRevealerTestSuite) TestRandomBlockReveal() { + // This test case would make sure we could at least generate + // two different revealing sequence when revealing more than + // 10 times. + iter, err := s.db.GetAllBlocks() + s.Require().Nil(err) + revealer, err := NewRandomBlockRevealer(iter) + s.Require().Nil(err) + + checkFunc := func(b *types.Block, revealed map[common.Hash]struct{}) { + // Make sure the revealer won't reveal the same block twice. + _, alreadyRevealed := revealed[b.Hash] + s.False(alreadyRevealed) + } + s.baseTest(revealer, 10, checkFunc) +} + +func (s *BlockRevealerTestSuite) TestRandomDAGBlockReveal() { + // This test case would make sure we could at least generate + // two different revealing sequence when revealing more than + // 10 times, and each of them would form valid DAGs during + // revealing. + + iter, err := s.db.GetAllBlocks() + s.Require().Nil(err) + revealer, err := NewRandomDAGBlockRevealer(iter) + s.Require().Nil(err) + + checkFunc := func(b *types.Block, revealed map[common.Hash]struct{}) { + // Make sure this revealer won't reveal + // the same block twice. + _, alreadyRevealed := revealed[b.Hash] + s.False(alreadyRevealed) + // Make sure the newly revealed block would still + // form a valid DAG after added to revealed blocks. + s.True(isAllAckingBlockRevealed(b, revealed)) + } + s.baseTest(revealer, 10, checkFunc) +} + +func (s *BlockRevealerTestSuite) TestRandomTipBlockReveal() { + // This test case would make sure we could at least generate + // two different revealing sequence when revealing more than + // 10 times. + iter, err := s.db.GetAllBlocks() + s.Require().Nil(err) + revealer, err := NewRandomTipBlockRevealer(iter) + s.Require().Nil(err) + + checkFunc := func(b *types.Block, revealed map[common.Hash]struct{}) { + // Make sure the revealer won't reveal the same block twice. + _, alreadyRevealed := revealed[b.Hash] + s.False(alreadyRevealed) + // Make sure the parent is already revealed. + if b.Position.Height == 0 { + return + } + _, alreadyRevealed = revealed[b.ParentHash] + s.True(alreadyRevealed) + } + s.baseTest(revealer, 10, checkFunc) +} + +func (s *BlockRevealerTestSuite) TestCompactionChainBlockReveal() { + dbInst, err := db.NewMemBackedDB() + s.Require().NoError(err) + // Put several blocks with finalization field ready. + b1 := &types.Block{ + Hash: common.NewRandomHash(), + Finalization: types.FinalizationResult{ + Height: 1, + }} + b2 := &types.Block{ + Hash: common.NewRandomHash(), + Finalization: types.FinalizationResult{ + ParentHash: b1.Hash, + Height: 2, + }} + b3 := &types.Block{ + Hash: common.NewRandomHash(), + Finalization: types.FinalizationResult{ + ParentHash: b2.Hash, + Height: 3, + }} + s.Require().NoError(dbInst.PutBlock(*b1)) + s.Require().NoError(dbInst.PutBlock(*b3)) + iter, err := dbInst.GetAllBlocks() + s.Require().NoError(err) + // The compaction chain is not complete, we can't construct a revealer + // instance successfully. + r, err := NewCompactionChainBlockRevealer(iter, 0) + s.Require().Nil(r) + s.Require().IsType(ErrNotValidCompactionChain, err) + // Put a block to make the compaction chain complete. + s.Require().NoError(dbInst.PutBlock(*b2)) + // We can construct that revealer now. + iter, err = dbInst.GetAllBlocks() + s.Require().NoError(err) + r, err = NewCompactionChainBlockRevealer(iter, 0) + s.Require().NotNil(r) + s.Require().NoError(err) + // The revealing order should be ok. + chk := func(h uint64) { + b, err := r.NextBlock() + s.Require().NoError(err) + s.Require().Equal(b.Finalization.Height, h) + } + chk(1) + chk(2) + chk(3) + // Iteration should be finished + _, err = r.NextBlock() + s.Require().IsType(db.ErrIterationFinished, err) + // Test 'startHeight' parameter. + iter, err = dbInst.GetAllBlocks() + s.Require().NoError(err) + r, err = NewCompactionChainBlockRevealer(iter, 2) + s.Require().NotNil(r) + s.Require().NoError(err) + chk(2) + chk(3) +} + +func TestBlockRevealer(t *testing.T) { + suite.Run(t, new(BlockRevealerTestSuite)) +} diff --git a/core/test/blocks-generator.go b/core/test/blocks-generator.go index e97985f..e92ff5d 100644 --- a/core/test/blocks-generator.go +++ b/core/test/blocks-generator.go @@ -24,9 +24,9 @@ import ( "time" "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/blockdb" "github.com/dexon-foundation/dexon-consensus/core/crypto" "github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa" + "github.com/dexon-foundation/dexon-consensus/core/db" "github.com/dexon-foundation/dexon-consensus/core/types" ) @@ -323,11 +323,11 @@ func NewBlocksGenerator( func (gen *BlocksGenerator) Generate( roundID uint64, roundBegin, roundEnd time.Time, - db blockdb.BlockDatabase) (err error) { + dbInst db.Database) (err error) { // Find tips of previous round if available. tips := make(map[uint32]*types.Block) if roundID > 0 { - tips, err = gen.findTips(roundID-1, db) + tips, err = gen.findTips(roundID-1, dbInst) if err != nil { return } @@ -361,29 +361,29 @@ func (gen *BlocksGenerator) Generate( return } // Persist block to db. - if err = db.Put(*newBlock); err != nil { + if err = dbInst.PutBlock(*newBlock); err != nil { return } } return } -// findTips is an utility to find tips of each chain in that round in blockdb. -func (gen *BlocksGenerator) findTips( - round uint64, db blockdb.Reader) (tips map[uint32]*types.Block, err error) { - iter, err := db.GetAll() +// findTips is an utility to find tips of each chain in that round in db. +func (gen *BlocksGenerator) findTips(round uint64, dbInst db.Reader) ( + tips map[uint32]*types.Block, err error) { + iter, err := dbInst.GetAllBlocks() if err != nil { return } - revealer, err := NewRandomRevealer(iter) + revealer, err := NewRandomBlockRevealer(iter) if err != nil { return } tips = make(map[uint32]*types.Block) for { var b types.Block - if b, err = revealer.Next(); err != nil { - if err == blockdb.ErrIterationFinished { + if b, err = revealer.NextBlock(); err != nil { + if err == db.ErrIterationFinished { err = nil break } diff --git a/core/test/blocks-generator_test.go b/core/test/blocks-generator_test.go index 8dcc2b7..bd7a5a2 100644 --- a/core/test/blocks-generator_test.go +++ b/core/test/blocks-generator_test.go @@ -18,12 +18,13 @@ package test import ( + "fmt" "sort" "testing" "time" "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/blockdb" + "github.com/dexon-foundation/dexon-consensus/core/db" "github.com/dexon-foundation/dexon-consensus/core/types" "github.com/stretchr/testify/suite" ) @@ -44,17 +45,17 @@ func (s *BlocksGeneratorTestSuite) TestGenerate() { beginTime = time.Now().UTC() endTime = beginTime.Add(time.Minute) ) - db, err := blockdb.NewMemBackedBlockDB() + dbInst, err := db.NewMemBackedDB() req.NoError(err) - req.NoError(gen.Generate(1, beginTime, endTime, db)) + req.NoError(gen.Generate(1, beginTime, endTime, dbInst)) // Load all blocks in that database for further checking. - iter, err := db.GetAll() + iter, err := dbInst.GetAllBlocks() req.NoError(err) blocksByChain := make(map[uint32][]*types.Block) blocksByHash := make(map[common.Hash]*types.Block) for { - block, err := iter.Next() - if err == blockdb.ErrIterationFinished { + block, err := iter.NextBlock() + if err == db.ErrIterationFinished { break } req.NoError(err) @@ -127,7 +128,7 @@ func (s *BlocksGeneratorTestSuite) TestGenerateWithMaxAckCount() { genesisTime = time.Now().UTC() ) // Generate with 0 acks. - db, err := blockdb.NewMemBackedBlockDB() + dbInst, err := db.NewMemBackedDB() req.NoError(err) gen := NewBlocksGenerator( config, MaxAckingCountGenerator(0), stableRandomHash) @@ -135,13 +136,13 @@ func (s *BlocksGeneratorTestSuite) TestGenerateWithMaxAckCount() { 0, genesisTime, genesisTime.Add(50*time.Second), - db)) + dbInst)) // Load blocks to check their acking count. - iter, err := db.GetAll() + iter, err := dbInst.GetAllBlocks() req.NoError(err) for { - block, err := iter.Next() - if err == blockdb.ErrIterationFinished { + block, err := iter.NextBlock() + if err == db.ErrIterationFinished { break } req.NoError(err) @@ -151,7 +152,7 @@ func (s *BlocksGeneratorTestSuite) TestGenerateWithMaxAckCount() { req.Len(block.Acks, 1) } // Generate with acks as many as possible. - db, err = blockdb.NewMemBackedBlockDB() + dbInst, err = db.NewMemBackedDB() req.NoError(err) gen = NewBlocksGenerator( config, MaxAckingCountGenerator(config.NumChains), stableRandomHash) @@ -159,13 +160,13 @@ func (s *BlocksGeneratorTestSuite) TestGenerateWithMaxAckCount() { 0, genesisTime, genesisTime.Add(50*time.Second), - db)) + dbInst)) // Load blocks to verify the average acking count. - iter, err = db.GetAll() + iter, err = dbInst.GetAllBlocks() req.NoError(err) for { - block, err := iter.Next() - if err == blockdb.ErrIterationFinished { + block, err := iter.NextBlock() + if err == db.ErrIterationFinished { break } req.NoError(err) @@ -191,14 +192,14 @@ func (s *BlocksGeneratorTestSuite) TestFindTips() { endTime = genesisTime.Add(100 * time.Second) ) gen := NewBlocksGenerator(config, nil, stableRandomHash) - db, err := blockdb.NewMemBackedBlockDB() + dbInst, err := db.NewMemBackedDB() req.NoError(err) req.NoError(gen.Generate( 0, genesisTime, endTime, - db)) - tips, err := gen.findTips(0, db) + dbInst)) + tips, err := gen.findTips(0, dbInst) req.NoError(err) req.Len(tips, int(config.NumChains)) for _, b := range tips { @@ -208,13 +209,13 @@ func (s *BlocksGeneratorTestSuite) TestFindTips() { func (s *BlocksGeneratorTestSuite) TestConcateBlocksFromRounds() { // This test case run these steps: - // - generate blocks by round but sharing one blockdb. + // - generate blocks by round but sharing one db. // - if those rounds are continuous, they should be concated. var ( req = s.Require() genesisTime = time.Now().UTC() ) - db, err := blockdb.NewMemBackedBlockDB() + dbInst, err := db.NewMemBackedDB() req.NoError(err) // Generate round 0 blocks. gen := NewBlocksGenerator(&BlocksGeneratorConfig{ @@ -225,8 +226,8 @@ func (s *BlocksGeneratorTestSuite) TestConcateBlocksFromRounds() { 0, genesisTime, genesisTime.Add(10*time.Second), - db)) - tips0, err := gen.findTips(0, db) + dbInst)) + tips0, err := gen.findTips(0, dbInst) req.NoError(err) req.Len(tips0, 4) // Generate round 1 blocks. @@ -238,8 +239,8 @@ func (s *BlocksGeneratorTestSuite) TestConcateBlocksFromRounds() { 1, genesisTime.Add(10*time.Second), genesisTime.Add(20*time.Second), - db)) - tips1, err := gen.findTips(1, db) + dbInst)) + tips1, err := gen.findTips(1, dbInst) req.NoError(err) req.Len(tips1, 10) // Generate round 2 blocks. @@ -251,14 +252,14 @@ func (s *BlocksGeneratorTestSuite) TestConcateBlocksFromRounds() { 2, genesisTime.Add(20*time.Second), genesisTime.Add(30*time.Second), - db)) - tips2, err := gen.findTips(2, db) + dbInst)) + tips2, err := gen.findTips(2, dbInst) req.NoError(err) req.Len(tips2, 7) // Check results, make sure tips0, tips1 are acked by correct blocks. - iter, err := db.GetAll() + iter, err := dbInst.GetAllBlocks() req.NoError(err) - revealer, err := NewRandomRevealer(iter) + revealer, err := NewRandomBlockRevealer(iter) req.NoError(err) removeTip := func(tips map[uint32]*types.Block, b *types.Block) { toRemove := []uint32{} @@ -277,9 +278,9 @@ func (s *BlocksGeneratorTestSuite) TestConcateBlocksFromRounds() { // Make sure all tips are acked by loading blocks from db // and check them one by one. for { - b, err := revealer.Next() + b, err := revealer.NextBlock() if err != nil { - if err == blockdb.ErrIterationFinished { + if err == db.ErrIterationFinished { err = nil break } @@ -302,9 +303,9 @@ func (s *BlocksGeneratorTestSuite) TestConcateBlocksFromRounds() { totalAckCount := 0 revealer.Reset() for { - b, err := revealer.Next() + b, err := revealer.NextBlock() if err != nil { - if err == blockdb.ErrIterationFinished { + if err == db.ErrIterationFinished { err = nil break } @@ -317,6 +318,7 @@ func (s *BlocksGeneratorTestSuite) TestConcateBlocksFromRounds() { totalAckCount += len(b.Acks) } // At least all blocks can ack some non-parent block. + fmt.Println(totalAckCount, totalBlockCount) req.True(totalAckCount/totalBlockCount >= 2) } diff --git a/core/test/interface.go b/core/test/interface.go index dcecee8..1388dc1 100644 --- a/core/test/interface.go +++ b/core/test/interface.go @@ -18,15 +18,15 @@ package test import ( - "github.com/dexon-foundation/dexon-consensus/core/blockdb" "github.com/dexon-foundation/dexon-consensus/core/crypto" + "github.com/dexon-foundation/dexon-consensus/core/db" "github.com/dexon-foundation/dexon-consensus/core/types" ) -// Revealer defines the interface to reveal a group +// BlockRevealer defines the interface to reveal a group // of pre-generated blocks. -type Revealer interface { - blockdb.BlockIterator +type BlockRevealer interface { + db.BlockIterator // Reset the revealing. Reset() diff --git a/core/test/revealer.go b/core/test/revealer.go deleted file mode 100644 index dcd75a5..0000000 --- a/core/test/revealer.go +++ /dev/null @@ -1,331 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package test - -import ( - "errors" - "math/rand" - "sort" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/blockdb" - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -// Errors returns from revealer. -var ( - ErrNotValidCompactionChain = errors.New("not valid compaction chain") -) - -// isAllAckingBlockRevealed is a helper to check if all acking blocks of -// one block are revealed. -func isAllAckingBlockRevealed( - b *types.Block, revealed map[common.Hash]struct{}) bool { - - for _, ack := range b.Acks { - if _, exists := revealed[ack]; !exists { - return false - } - } - return true -} - -// loadAllBlocks is a helper to load all blocks from blockdb.BlockIterator. -func loadAllBlocks(iter blockdb.BlockIterator) ( - blocks map[common.Hash]*types.Block, err error) { - - blocks = make(map[common.Hash]*types.Block) - for { - block, err := iter.Next() - if err != nil { - if err == blockdb.ErrIterationFinished { - // It's safe to ignore iteraion-finished error. - err = nil - } - break - } - blocks[block.Hash] = &block - } - return -} - -// RandomDAGRevealer implements Revealer interface, which would load -// all blocks from blockdb, and randomly pick one block to reveal if -// it still forms a valid DAG in revealed blocks. -type RandomDAGRevealer struct { - // blocksByChain group all blocks by chains and sorting - // them by height. - blocksByChain map[uint32][]*types.Block - // tipIndexes store the height of next block from one chain - // to check if is candidate. - tipIndexes map[uint32]int - // candidate are blocks that forms valid DAG with - // current revealed blocks. - candidates []*types.Block - candidateChains map[uint32]struct{} - // revealed stores block hashes of current revealed blocks. - revealed map[common.Hash]struct{} - randGen *rand.Rand -} - -// NewRandomDAGRevealer constructs RandomDAGRevealer. -func NewRandomDAGRevealer( - iter blockdb.BlockIterator) (r *RandomDAGRevealer, err error) { - - blocks, err := loadAllBlocks(iter) - if err != nil { - return - } - - // Rearrange blocks by nodes and height. - blocksByChain := make(map[uint32][]*types.Block) - for _, block := range blocks { - blocksByChain[block.Position.ChainID] = - append(blocksByChain[block.Position.ChainID], block) - } - // Make sure blocks are sorted by block heights, from lower to higher. - for chainID := range blocksByChain { - sort.Sort(types.ByPosition(blocksByChain[chainID])) - } - r = &RandomDAGRevealer{ - blocksByChain: blocksByChain, - randGen: rand.New(rand.NewSource(time.Now().UnixNano())), - candidateChains: make(map[uint32]struct{}), - } - // Make sure this revealer is ready to use. - r.Reset() - return -} - -// pickCandidates is a helper function to pick candidates from current tips. -func (r *RandomDAGRevealer) pickCandidates() { - for chainID, tip := range r.tipIndexes { - if _, isPicked := r.candidateChains[chainID]; isPicked { - continue - } - blocks, exists := r.blocksByChain[chainID] - if !exists { - continue - } - if tip >= len(blocks) { - continue - } - block := blocks[tip] - if isAllAckingBlockRevealed(block, r.revealed) { - r.tipIndexes[chainID]++ - r.candidates = append(r.candidates, block) - r.candidateChains[chainID] = struct{}{} - } - } -} - -// Next implement Revealer.Next method, which would reveal blocks -// forming valid DAGs. -func (r *RandomDAGRevealer) Next() (types.Block, error) { - if len(r.candidates) == 0 { - r.pickCandidates() - if len(r.candidates) == 0 { - return types.Block{}, blockdb.ErrIterationFinished - } - } - - // Pick next block to be revealed. - picked := r.randGen.Intn(len(r.candidates)) - block := r.candidates[picked] - r.candidates = - append(r.candidates[:picked], r.candidates[picked+1:]...) - delete(r.candidateChains, block.Position.ChainID) - r.revealed[block.Hash] = struct{}{} - r.pickCandidates() - return *block, nil -} - -// Reset implement Revealer.Reset method, which would reset the revealing. -func (r *RandomDAGRevealer) Reset() { - r.tipIndexes = make(map[uint32]int) - for chainID := range r.blocksByChain { - r.tipIndexes[chainID] = 0 - } - r.revealed = make(map[common.Hash]struct{}) - r.candidates = []*types.Block{} -} - -// RandomRevealer implements Revealer interface, which would load -// all blocks from blockdb, and randomly pick one block to reveal. -type RandomRevealer struct { - blocks map[common.Hash]*types.Block - remains common.Hashes - randGen *rand.Rand -} - -// NewRandomRevealer constructs RandomRevealer. -func NewRandomRevealer( - iter blockdb.BlockIterator) (r *RandomRevealer, err error) { - - blocks, err := loadAllBlocks(iter) - if err != nil { - return - } - r = &RandomRevealer{ - blocks: blocks, - randGen: rand.New(rand.NewSource(time.Now().UnixNano())), - } - r.Reset() - return -} - -// Next implements Revealer.Next method, which would reveal blocks randomly. -func (r *RandomRevealer) Next() (types.Block, error) { - if len(r.remains) == 0 { - return types.Block{}, blockdb.ErrIterationFinished - } - - picked := r.randGen.Intn(len(r.remains)) - block := r.blocks[r.remains[picked]] - r.remains = - append(r.remains[:picked], r.remains[picked+1:]...) - return *block, nil -} - -// Reset implement Revealer.Reset method, which would reset revealing. -func (r *RandomRevealer) Reset() { - hashes := common.Hashes{} - for hash := range r.blocks { - hashes = append(hashes, hash) - } - r.remains = hashes -} - -// RandomTipRevealer implements Revealer interface, which would load -// all blocks from blockdb, and randomly pick one chain's tip to reveal. -type RandomTipRevealer struct { - chainsBlock []map[uint64]*types.Block - chainTip []uint64 - chainRevealSeq []uint32 - revealed int - randGen *rand.Rand -} - -// NewRandomTipRevealer constructs RandomTipRevealer. -func NewRandomTipRevealer( - iter blockdb.BlockIterator) (r *RandomTipRevealer, err error) { - - blocks, err := loadAllBlocks(iter) - if err != nil { - return - } - r = &RandomTipRevealer{ - randGen: rand.New(rand.NewSource(time.Now().UnixNano())), - } - for _, b := range blocks { - for b.Position.ChainID >= uint32(len(r.chainsBlock)) { - r.chainsBlock = append(r.chainsBlock, make(map[uint64]*types.Block)) - r.chainTip = append(r.chainTip, 0) - } - r.chainsBlock[b.Position.ChainID][b.Position.Height] = b - r.chainRevealSeq = append(r.chainRevealSeq, b.Position.ChainID) - } - r.Reset() - return -} - -// Next implements Revealer.Next method, which would reveal blocks randomly. -func (r *RandomTipRevealer) Next() (types.Block, error) { - if len(r.chainRevealSeq) == r.revealed { - return types.Block{}, blockdb.ErrIterationFinished - } - - picked := r.chainRevealSeq[r.revealed] - r.revealed++ - block := r.chainsBlock[picked][r.chainTip[picked]] - r.chainTip[picked]++ - return *block, nil -} - -// Reset implement Revealer.Reset method, which would reset revealing. -func (r *RandomTipRevealer) Reset() { - r.revealed = 0 - r.randGen.Shuffle(len(r.chainRevealSeq), func(i, j int) { - r.chainRevealSeq[i], r.chainRevealSeq[j] = - r.chainRevealSeq[j], r.chainRevealSeq[i] - }) - for i := range r.chainTip { - r.chainTip[i] = 0 - } -} - -// CompactionChainRevealer implements Revealer interface, which would load -// all blocks from blockdb, reveal them in the order of compaction chain, from -// the genesis block to the latest one. -type CompactionChainRevealer struct { - blocks types.ByFinalizationHeight - nextRevealIndex int -} - -// NewCompactionChainRevealer constructs a revealer in the order of compaction -// chain. -func NewCompactionChainRevealer(iter blockdb.BlockIterator, - startHeight uint64) (r *CompactionChainRevealer, err error) { - blocksByHash, err := loadAllBlocks(iter) - if err != nil { - return - } - if startHeight == 0 { - startHeight = 1 - } - blocks := types.ByFinalizationHeight{} - for _, b := range blocksByHash { - if b.Finalization.Height < startHeight { - continue - } - blocks = append(blocks, b) - } - sort.Sort(types.ByFinalizationHeight(blocks)) - // Make sure the finalization height of blocks are incremental with step 1. - for idx, b := range blocks { - if idx == 0 { - continue - } - if b.Finalization.Height != blocks[idx-1].Finalization.Height+1 { - err = ErrNotValidCompactionChain - return - } - } - r = &CompactionChainRevealer{ - blocks: blocks, - } - r.Reset() - return -} - -// Next implements Revealer.Next method, which would reveal blocks in the order -// of compaction chain. -func (r *CompactionChainRevealer) Next() (types.Block, error) { - if r.nextRevealIndex == len(r.blocks) { - return types.Block{}, blockdb.ErrIterationFinished - } - b := r.blocks[r.nextRevealIndex] - r.nextRevealIndex++ - return *b, nil -} - -// Reset implement Revealer.Reset method, which would reset revealing. -func (r *CompactionChainRevealer) Reset() { - r.nextRevealIndex = 0 -} diff --git a/core/test/revealer_test.go b/core/test/revealer_test.go deleted file mode 100644 index 5a1bc07..0000000 --- a/core/test/revealer_test.go +++ /dev/null @@ -1,222 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus library. -// -// The dexon-consensus library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus library. If not, see -// . - -package test - -import ( - "testing" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/blockdb" - "github.com/dexon-foundation/dexon-consensus/core/types" - "github.com/stretchr/testify/suite" -) - -type RevealerTestSuite struct { - suite.Suite - - db blockdb.BlockDatabase - totalBlockCount int -} - -func (s *RevealerTestSuite) SetupSuite() { - var ( - err error - genesisTime = time.Now().UTC() - ) - // Setup block database. - s.db, err = blockdb.NewMemBackedBlockDB() - s.Require().NoError(err) - - // Randomly generate blocks. - config := &BlocksGeneratorConfig{ - NumChains: 19, - MinBlockTimeInterval: 250 * time.Millisecond, - } - gen := NewBlocksGenerator(config, nil, stableRandomHash) - s.Require().NoError(gen.Generate( - 0, - genesisTime, - genesisTime.Add(30*time.Second), - s.db)) - // Cache the count of total generated block. - iter, err := s.db.GetAll() - s.Require().NoError(err) - blocks, err := loadAllBlocks(iter) - s.Require().NoError(err) - s.totalBlockCount = len(blocks) -} - -func (s *RevealerTestSuite) baseTest( - revealer Revealer, - repeat int, - checkFunc func(*types.Block, map[common.Hash]struct{})) { - - revealingSequence := map[string]struct{}{} - for i := 0; i < repeat; i++ { - revealed := map[common.Hash]struct{}{} - sequence := "" - for { - b, err := revealer.Next() - if err != nil { - if err == blockdb.ErrIterationFinished { - err = nil - break - } - s.Require().NotNil(err) - } - checkFunc(&b, revealed) - revealed[b.Hash] = struct{}{} - sequence += b.Hash.String() + "," - } - s.Len(revealed, s.totalBlockCount) - revealingSequence[sequence] = struct{}{} - revealer.Reset() - } - // It should be reasonable to reveal at least two - // different sequence. - s.True(len(revealingSequence) > 1) - -} - -func (s *RevealerTestSuite) TestRandomReveal() { - // This test case would make sure we could at least generate - // two different revealing sequence when revealing more than - // 10 times. - iter, err := s.db.GetAll() - s.Require().Nil(err) - revealer, err := NewRandomRevealer(iter) - s.Require().Nil(err) - - checkFunc := func(b *types.Block, revealed map[common.Hash]struct{}) { - // Make sure the revealer won't reveal the same block twice. - _, alreadyRevealed := revealed[b.Hash] - s.False(alreadyRevealed) - } - s.baseTest(revealer, 10, checkFunc) -} - -func (s *RevealerTestSuite) TestRandomDAGReveal() { - // This test case would make sure we could at least generate - // two different revealing sequence when revealing more than - // 10 times, and each of them would form valid DAGs during - // revealing. - - iter, err := s.db.GetAll() - s.Require().Nil(err) - revealer, err := NewRandomDAGRevealer(iter) - s.Require().Nil(err) - - checkFunc := func(b *types.Block, revealed map[common.Hash]struct{}) { - // Make sure this revealer won't reveal - // the same block twice. - _, alreadyRevealed := revealed[b.Hash] - s.False(alreadyRevealed) - // Make sure the newly revealed block would still - // form a valid DAG after added to revealed blocks. - s.True(isAllAckingBlockRevealed(b, revealed)) - } - s.baseTest(revealer, 10, checkFunc) -} - -func (s *RevealerTestSuite) TestRandomTipReveal() { - // This test case would make sure we could at least generate - // two different revealing sequence when revealing more than - // 10 times. - iter, err := s.db.GetAll() - s.Require().Nil(err) - revealer, err := NewRandomTipRevealer(iter) - s.Require().Nil(err) - - checkFunc := func(b *types.Block, revealed map[common.Hash]struct{}) { - // Make sure the revealer won't reveal the same block twice. - _, alreadyRevealed := revealed[b.Hash] - s.False(alreadyRevealed) - // Make sure the parent is already revealed. - if b.Position.Height == 0 { - return - } - _, alreadyRevealed = revealed[b.ParentHash] - s.True(alreadyRevealed) - } - s.baseTest(revealer, 10, checkFunc) -} - -func (s *RevealerTestSuite) TestCompactionChainReveal() { - db, err := blockdb.NewMemBackedBlockDB() - s.Require().NoError(err) - // Put several blocks with finalization field ready. - b1 := &types.Block{ - Hash: common.NewRandomHash(), - Finalization: types.FinalizationResult{ - Height: 1, - }} - b2 := &types.Block{ - Hash: common.NewRandomHash(), - Finalization: types.FinalizationResult{ - ParentHash: b1.Hash, - Height: 2, - }} - b3 := &types.Block{ - Hash: common.NewRandomHash(), - Finalization: types.FinalizationResult{ - ParentHash: b2.Hash, - Height: 3, - }} - s.Require().NoError(db.Put(*b1)) - s.Require().NoError(db.Put(*b3)) - iter, err := db.GetAll() - s.Require().NoError(err) - // The compaction chain is not complete, we can't construct a revealer - // instance successfully. - r, err := NewCompactionChainRevealer(iter, 0) - s.Require().Nil(r) - s.Require().IsType(ErrNotValidCompactionChain, err) - // Put a block to make the compaction chain complete. - s.Require().NoError(db.Put(*b2)) - // We can construct that revealer now. - iter, err = db.GetAll() - s.Require().NoError(err) - r, err = NewCompactionChainRevealer(iter, 0) - s.Require().NotNil(r) - s.Require().NoError(err) - // The revealing order should be ok. - chk := func(h uint64) { - b, err := r.Next() - s.Require().NoError(err) - s.Require().Equal(b.Finalization.Height, h) - } - chk(1) - chk(2) - chk(3) - // Iteration should be finished - _, err = r.Next() - s.Require().IsType(blockdb.ErrIterationFinished, err) - // Test 'startHeight' parameter. - iter, err = db.GetAll() - s.Require().NoError(err) - r, err = NewCompactionChainRevealer(iter, 2) - s.Require().NotNil(r) - s.Require().NoError(err) - chk(2) - chk(3) -} - -func TestRevealer(t *testing.T) { - suite.Run(t, new(RevealerTestSuite)) -} diff --git a/core/test/stopper.go b/core/test/stopper.go index 40868d8..2ba31d3 100644 --- a/core/test/stopper.go +++ b/core/test/stopper.go @@ -20,7 +20,7 @@ package test import ( "sync" - "github.com/dexon-foundation/dexon-consensus/core/blockdb" + "github.com/dexon-foundation/dexon-consensus/core/db" "github.com/dexon-foundation/dexon-consensus/core/types" ) @@ -28,7 +28,7 @@ import ( // at least X blocks proposed by itself. type StopByConfirmedBlocks struct { apps map[types.NodeID]*App - dbs map[types.NodeID]blockdb.BlockDatabase + dbs map[types.NodeID]db.Database lastCheckDelivered map[types.NodeID]int confirmedBlocks map[types.NodeID]int blockCount int @@ -39,7 +39,7 @@ type StopByConfirmedBlocks struct { func NewStopByConfirmedBlocks( blockCount int, apps map[types.NodeID]*App, - dbs map[types.NodeID]blockdb.BlockDatabase) *StopByConfirmedBlocks { + dbs map[types.NodeID]db.Database) *StopByConfirmedBlocks { confirmedBlocks := make(map[types.NodeID]int) for nID := range apps { confirmedBlocks[nID] = 0 @@ -60,10 +60,10 @@ func (s *StopByConfirmedBlocks) ShouldStop(nID types.NodeID) bool { // Accumulate confirmed blocks proposed by this node in this round. lastChecked := s.lastCheckDelivered[nID] currentConfirmedBlocks := s.confirmedBlocks[nID] - db := s.dbs[nID] + dbInst := s.dbs[nID] s.apps[nID].WithLock(func(app *App) { for _, h := range app.DeliverSequence[lastChecked:] { - b, err := db.Get(h) + b, err := dbInst.GetBlock(h) if err != nil { panic(err) } @@ -90,7 +90,7 @@ type StopByRound struct { currentRounds map[types.NodeID]uint64 lastCheckDelivered map[types.NodeID]int apps map[types.NodeID]*App - dbs map[types.NodeID]blockdb.BlockDatabase + dbs map[types.NodeID]db.Database lock sync.Mutex } @@ -98,7 +98,7 @@ type StopByRound struct { func NewStopByRound( round uint64, apps map[types.NodeID]*App, - dbs map[types.NodeID]blockdb.BlockDatabase) *StopByRound { + dbs map[types.NodeID]db.Database) *StopByRound { return &StopByRound{ untilRound: round, currentRounds: make(map[types.NodeID]uint64), @@ -115,10 +115,10 @@ func (s *StopByRound) ShouldStop(nID types.NodeID) bool { // Cache latest round of this node. if curRound := s.currentRounds[nID]; curRound < s.untilRound { lastChecked := s.lastCheckDelivered[nID] - db := s.dbs[nID] + dbInst := s.dbs[nID] s.apps[nID].WithLock(func(app *App) { for _, h := range app.DeliverSequence[lastChecked:] { - b, err := db.Get(h) + b, err := dbInst.GetBlock(h) if err != nil { panic(err) } diff --git a/core/test/stopper_test.go b/core/test/stopper_test.go index b34e7b2..d296727 100644 --- a/core/test/stopper_test.go +++ b/core/test/stopper_test.go @@ -23,7 +23,7 @@ import ( "github.com/dexon-foundation/dexon-consensus/common" "github.com/dexon-foundation/dexon-consensus/core" - "github.com/dexon-foundation/dexon-consensus/core/blockdb" + "github.com/dexon-foundation/dexon-consensus/core/db" "github.com/dexon-foundation/dexon-consensus/core/types" "github.com/stretchr/testify/suite" ) @@ -33,11 +33,11 @@ type StopperTestSuite struct { } func (s *StopperTestSuite) deliver( - blocks []*types.Block, app *App, db blockdb.BlockDatabase) { + blocks []*types.Block, app *App, dbInst db.Database) { hashes := common.Hashes{} for _, b := range blocks { hashes = append(hashes, b.Hash) - s.Require().NoError(db.Put(*b)) + s.Require().NoError(dbInst.PutBlock(*b)) } for _, h := range hashes { app.BlockConfirmed(types.Block{Hash: h}) @@ -53,9 +53,9 @@ func (s *StopperTestSuite) deliver( func (s *StopperTestSuite) deliverToAllNodes( blocks []*types.Block, apps map[types.NodeID]*App, - dbs map[types.NodeID]blockdb.BlockDatabase) { + dbInsts map[types.NodeID]db.Database) { for nID := range apps { - s.deliver(blocks, apps[nID], dbs[nID]) + s.deliver(blocks, apps[nID], dbInsts[nID]) } } @@ -64,23 +64,23 @@ func (s *StopperTestSuite) TestStopByConfirmedBlocks() { // all nodes confirmed at least 'x' count of blocks produced // by themselves. var ( - req = s.Require() - apps = make(map[types.NodeID]*App) - dbs = make(map[types.NodeID]blockdb.BlockDatabase) - nodes = GenerateRandomNodeIDs(2) + req = s.Require() + apps = make(map[types.NodeID]*App) + dbInsts = make(map[types.NodeID]db.Database) + nodes = GenerateRandomNodeIDs(2) ) for _, nID := range nodes { apps[nID] = NewApp(nil) - db, err := blockdb.NewMemBackedBlockDB() + dbInst, err := db.NewMemBackedDB() req.NoError(err) - dbs[nID] = db + dbInsts[nID] = dbInst } - stopper := NewStopByConfirmedBlocks(2, apps, dbs) + stopper := NewStopByConfirmedBlocks(2, apps, dbInsts) b00 := &types.Block{ ProposerID: nodes[0], Hash: common.NewRandomHash(), } - s.deliverToAllNodes([]*types.Block{b00}, apps, dbs) + s.deliverToAllNodes([]*types.Block{b00}, apps, dbInsts) b10 := &types.Block{ ProposerID: nodes[1], Hash: common.NewRandomHash(), @@ -90,21 +90,21 @@ func (s *StopperTestSuite) TestStopByConfirmedBlocks() { ParentHash: b10.Hash, Hash: common.NewRandomHash(), } - s.deliverToAllNodes([]*types.Block{b10, b11}, apps, dbs) + s.deliverToAllNodes([]*types.Block{b10, b11}, apps, dbInsts) req.False(stopper.ShouldStop(nodes[1])) b12 := &types.Block{ ProposerID: nodes[1], ParentHash: b11.Hash, Hash: common.NewRandomHash(), } - s.deliverToAllNodes([]*types.Block{b12}, apps, dbs) + s.deliverToAllNodes([]*types.Block{b12}, apps, dbInsts) req.False(stopper.ShouldStop(nodes[1])) b01 := &types.Block{ ProposerID: nodes[0], ParentHash: b00.Hash, Hash: common.NewRandomHash(), } - s.deliverToAllNodes([]*types.Block{b01}, apps, dbs) + s.deliverToAllNodes([]*types.Block{b01}, apps, dbInsts) req.True(stopper.ShouldStop(nodes[0])) } @@ -112,18 +112,18 @@ func (s *StopperTestSuite) TestStopByRound() { // This test case make sure at least one block from round R // is delivered by each node. var ( - req = s.Require() - apps = make(map[types.NodeID]*App) - dbs = make(map[types.NodeID]blockdb.BlockDatabase) - nodes = GenerateRandomNodeIDs(2) + req = s.Require() + apps = make(map[types.NodeID]*App) + dbInsts = make(map[types.NodeID]db.Database) + nodes = GenerateRandomNodeIDs(2) ) for _, nID := range nodes { apps[nID] = NewApp(nil) - db, err := blockdb.NewMemBackedBlockDB() + dbInst, err := db.NewMemBackedDB() req.NoError(err) - dbs[nID] = db + dbInsts[nID] = dbInst } - stopper := NewStopByRound(10, apps, dbs) + stopper := NewStopByRound(10, apps, dbInsts) b00 := &types.Block{ ProposerID: nodes[0], Position: types.Position{ @@ -133,7 +133,7 @@ func (s *StopperTestSuite) TestStopByRound() { }, Hash: common.NewRandomHash(), } - s.deliverToAllNodes([]*types.Block{b00}, apps, dbs) + s.deliverToAllNodes([]*types.Block{b00}, apps, dbInsts) b10 := &types.Block{ ProposerID: nodes[1], Position: types.Position{ @@ -153,7 +153,7 @@ func (s *StopperTestSuite) TestStopByRound() { }, Hash: common.NewRandomHash(), } - s.deliverToAllNodes([]*types.Block{b10, b11}, apps, dbs) + s.deliverToAllNodes([]*types.Block{b10, b11}, apps, dbInsts) req.False(stopper.ShouldStop(nodes[0])) req.False(stopper.ShouldStop(nodes[1])) // Deliver one block at round 10 to node0 @@ -168,11 +168,11 @@ func (s *StopperTestSuite) TestStopByRound() { Hash: common.NewRandomHash(), } // None should stop when only one node reach that round. - s.deliver([]*types.Block{b12}, apps[nodes[0]], dbs[nodes[0]]) + s.deliver([]*types.Block{b12}, apps[nodes[0]], dbInsts[nodes[0]]) req.False(stopper.ShouldStop(nodes[0])) req.False(stopper.ShouldStop(nodes[1])) // Everyone should stop now. - s.deliver([]*types.Block{b12}, apps[nodes[1]], dbs[nodes[1]]) + s.deliver([]*types.Block{b12}, apps[nodes[1]], dbInsts[nodes[1]]) req.True(stopper.ShouldStop(nodes[1])) req.True(stopper.ShouldStop(nodes[0])) } -- cgit v1.2.3