From 101ce1072667a1a8cfeaa58dc862eb4d0dbec6f7 Mon Sep 17 00:00:00 2001 From: Mission Liao Date: Fri, 3 Aug 2018 13:57:41 +0800 Subject: test: random blocks generator (#26) * Add blocks generator. This helper would randomly generate blocks that forms valid DAGs. * Add revealer Revealer is an extension of blockdb.BlockIterator. The block sequence from 'Next' method would be either randomly (see RandomRevealer) or meeting some specific condition (ex. forming a DAG, see RandomDAGRevealer). * Add test for sequencer based on random blocks. * core: refine Application interface and add Governance interface (#24) Add a new Governance interface for interaction with the governance contract. Also remove the ValidateBlock call in application interface as the application should validate it before putting it into the consensus module. A new BlockConverter interface is also added. The consensus module should accept the BlockConverter interface in future implementation, and use the Block() function to get the underlying block info. --- core/sequencer_test.go | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) (limited to 'core/sequencer_test.go') diff --git a/core/sequencer_test.go b/core/sequencer_test.go index fa8b461..ae9cca7 100644 --- a/core/sequencer_test.go +++ b/core/sequencer_test.go @@ -1,10 +1,30 @@ +// Copyright 2018 The dexon-consensus-core Authors +// This file is part of the dexon-consensus-core library. +// +// The dexon-consensus-core 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-core 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-core library. If not, see +// . + package core import ( "sort" + "strings" "testing" + "github.com/dexon-foundation/dexon-consensus-core/blockdb" "github.com/dexon-foundation/dexon-consensus-core/common" + "github.com/dexon-foundation/dexon-consensus-core/core/test" "github.com/dexon-foundation/dexon-consensus-core/core/types" "github.com/stretchr/testify/suite" ) @@ -869,6 +889,108 @@ func (s *SequencerTestSuite) TestBasicCaseForK0() { s.Contains(seq.candidateAckingStatusVectors, b30.Hash) } +func (s *SequencerTestSuite) baseTestRandomlyGeneratedBlocks( + seqConstructor func() *sequencer, + revealer test.Revealer, + repeat int) { + + // TODO (mission): make this part run concurrently. + revealingSequence := map[string]struct{}{} + orderingSequence := map[string]struct{}{} + for i := 0; i < repeat; i++ { + revealed := "" + ordered := "" + revealer.Reset() + seq := seqConstructor() + for { + // Reveal next block. + b, err := revealer.Next() + if err != nil { + if err == blockdb.ErrIterationFinished { + err = nil + break + } + } + s.Require().Nil(err) + revealed += b.Hash.String() + "," + + // Perform total ordering. + hashes, _, err := seq.processBlock(&b) + s.Require().Nil(err) + for _, h := range hashes { + ordered += h.String() + "," + } + } + revealingSequence[revealed] = struct{}{} + orderingSequence[ordered] = struct{}{} + } + + // Make sure we test at least two different + // revealing sequence. + s.True(len(revealingSequence) > 1) + // Make sure all ordering are equal or prefixed + // to another one. + for orderFrom := range orderingSequence { + for orderTo := range orderingSequence { + if orderFrom == orderTo { + continue + } + ok := strings.HasPrefix(orderFrom, orderTo) || + strings.HasPrefix(orderTo, orderFrom) + s.True(ok) + } + } +} + +func (s *SequencerTestSuite) TestRandomlyGeneratedBlocks() { + var ( + validatorCount = 19 + blockCount = 50 + phi uint64 = 10 + repeat = 10 + ) + + // Prepare a randomly genearated blocks. + db, err := blockdb.NewMemBackedBlockDB("test-sequencer-random.blockdb") + s.Require().Nil(err) + defer func() { + // If the test fails, keep the block database for troubleshooting. + if s.T().Failed() { + s.Nil(db.Close()) + } + }() + + gen := test.NewBlocksGenerator(nil) + s.Require().Nil(gen.Generate(validatorCount, blockCount, nil, db)) + iter, err := db.GetAll() + s.Require().Nil(err) + // Setup a revealer that would reveal blocks forming + // valid DAGs. + revealer, err := test.NewRandomDAGRevealer(iter) + s.Require().Nil(err) + + // Test for K=0. + constructor := func() *sequencer { + return newSequencer(0, phi, uint64(validatorCount)) + } + s.baseTestRandomlyGeneratedBlocks(constructor, revealer, repeat) + // Test for K=1, + constructor = func() *sequencer { + return newSequencer(1, phi, uint64(validatorCount)) + } + s.baseTestRandomlyGeneratedBlocks(constructor, revealer, repeat) + // Test for K=2, + constructor = func() *sequencer { + return newSequencer(2, phi, uint64(validatorCount)) + } + s.baseTestRandomlyGeneratedBlocks(constructor, revealer, repeat) + // Test for K=3, + constructor = func() *sequencer { + return newSequencer(2, phi, uint64(validatorCount)) + } + s.baseTestRandomlyGeneratedBlocks(constructor, revealer, repeat) +} + func TestSequencer(t *testing.T) { suite.Run(t, new(SequencerTestSuite)) } -- cgit v1.2.3