aboutsummaryrefslogtreecommitdiffstats
path: root/integration_test
diff options
context:
space:
mode:
authorMission Liao <mission.liao@dexon.org>2019-02-15 14:18:59 +0800
committerJimmy Hu <jimmy.hu@dexon.org>2019-02-19 10:48:50 +0800
commit4dbdc22e355cf1f6f0c39af1b2f3737b7527bc0c (patch)
tree625b7d34aa700d072ffb8e68dc89ed3936b76d29 /integration_test
parente4825619fb2499f5f534537c1a4d52d3e0bcacfe (diff)
downloadtangerine-consensus-4dbdc22e355cf1f6f0c39af1b2f3737b7527bc0c.tar
tangerine-consensus-4dbdc22e355cf1f6f0c39af1b2f3737b7527bc0c.tar.gz
tangerine-consensus-4dbdc22e355cf1f6f0c39af1b2f3737b7527bc0c.tar.bz2
tangerine-consensus-4dbdc22e355cf1f6f0c39af1b2f3737b7527bc0c.tar.lz
tangerine-consensus-4dbdc22e355cf1f6f0c39af1b2f3737b7527bc0c.tar.xz
tangerine-consensus-4dbdc22e355cf1f6f0c39af1b2f3737b7527bc0c.tar.zst
tangerine-consensus-4dbdc22e355cf1f6f0c39af1b2f3737b7527bc0c.zip
big-bang: single chain (#446)
Diffstat (limited to 'integration_test')
-rw-r--r--integration_test/consensus_test.go38
-rw-r--r--integration_test/node.go355
-rw-r--r--integration_test/stats.go192
-rw-r--r--integration_test/stats_test.go84
-rw-r--r--integration_test/utils.go140
-rw-r--r--integration_test/utils_test.go61
-rw-r--r--integration_test/with_scheduler_test.go150
7 files changed, 26 insertions, 994 deletions
diff --git a/integration_test/consensus_test.go b/integration_test/consensus_test.go
index 8af118b..454ed1e 100644
--- a/integration_test/consensus_test.go
+++ b/integration_test/consensus_test.go
@@ -239,10 +239,10 @@ Loop:
s.verifyNodes(nodes)
}
-func (s *ConsensusTestSuite) TestNumChainsChange() {
+func (s *ConsensusTestSuite) TestSetSizeChange() {
var (
req = s.Require()
- peerCount = 4
+ peerCount = 7
dMoment = time.Now().UTC()
untilRound = uint64(6)
)
@@ -261,24 +261,34 @@ func (s *ConsensusTestSuite) TestNumChainsChange() {
req.NoError(err)
req.NoError(seedGov.State().RequestChange(
test.StateChangeRoundInterval, 45*time.Second))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeNotarySetSize, uint32(4)))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeDKGSetSize, uint32(4)))
seedGov.CatchUpWithRound(0)
// Setup configuration for round 0 and round 1.
req.NoError(seedGov.State().RequestChange(
- test.StateChangeNumChains, uint32(5)))
- req.NoError(seedGov.State().RequestChange(
test.StateChangeRoundInterval, 55*time.Second))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeNotarySetSize, uint32(5)))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeDKGSetSize, uint32(6)))
seedGov.CatchUpWithRound(1)
// Setup configuration for round 2.
req.NoError(seedGov.State().RequestChange(
- test.StateChangeNumChains, uint32(6)))
- req.NoError(seedGov.State().RequestChange(
test.StateChangeRoundInterval, 55*time.Second))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeNotarySetSize, uint32(6)))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeDKGSetSize, uint32(5)))
seedGov.CatchUpWithRound(2)
// Setup configuration for round 3.
req.NoError(seedGov.State().RequestChange(
- test.StateChangeNumChains, uint32(5)))
- req.NoError(seedGov.State().RequestChange(
test.StateChangeRoundInterval, 75*time.Second))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeNotarySetSize, uint32(4)))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeDKGSetSize, uint32(4)))
seedGov.CatchUpWithRound(3)
// Setup nodes.
nodes := s.setupNodes(dMoment, prvKeys, seedGov)
@@ -289,14 +299,18 @@ func (s *ConsensusTestSuite) TestNumChainsChange() {
}
// Register configuration changes for round 4.
req.NoError(pickedNode.gov.RegisterConfigChange(
- 4, test.StateChangeNumChains, uint32(4)))
- req.NoError(pickedNode.gov.RegisterConfigChange(
4, test.StateChangeRoundInterval, 45*time.Second))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeNotarySetSize, uint32(5)))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeDKGSetSize, uint32(5)))
// Register configuration changes for round 5.
req.NoError(pickedNode.gov.RegisterConfigChange(
- 5, test.StateChangeNumChains, uint32(5)))
- req.NoError(pickedNode.gov.RegisterConfigChange(
5, test.StateChangeRoundInterval, 55*time.Second))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeNotarySetSize, uint32(4)))
+ req.NoError(seedGov.State().RequestChange(
+ test.StateChangeDKGSetSize, uint32(4)))
// Run test.
for _, n := range nodes {
go n.con.Run()
diff --git a/integration_test/node.go b/integration_test/node.go
deleted file mode 100644
index 732e54a..0000000
--- a/integration_test/node.go
+++ /dev/null
@@ -1,355 +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
-// <http://www.gnu.org/licenses/>.
-
-package integration
-
-import (
- "fmt"
- "time"
-
- "github.com/dexon-foundation/dexon-consensus/common"
- "github.com/dexon-foundation/dexon-consensus/core"
- "github.com/dexon-foundation/dexon-consensus/core/crypto"
- "github.com/dexon-foundation/dexon-consensus/core/db"
- "github.com/dexon-foundation/dexon-consensus/core/test"
- "github.com/dexon-foundation/dexon-consensus/core/types"
- "github.com/dexon-foundation/dexon-consensus/core/utils"
-)
-
-type consensusEventType int
-
-const (
- evtProposeBlock consensusEventType = iota
- evtReceiveBlock
-)
-
-type consensusEventPayload struct {
- Type consensusEventType
- PiggyBack interface{}
-}
-
-// newProposeBlockEvent constructs an test.Event that would trigger
-// block proposing.
-func newProposeBlockEvent(nID types.NodeID,
- roundID uint64, chainID uint32, when time.Time) *test.Event {
- return test.NewEvent(nID, when, &consensusEventPayload{
- Type: evtProposeBlock,
- PiggyBack: &struct {
- round uint64
- chain uint32
- }{roundID, chainID},
- })
-}
-
-// newReceiveBlockEvent constructs an test.Event that would trigger
-// block received.
-func newReceiveBlockEvent(
- nID types.NodeID, when time.Time, block *types.Block) *test.Event {
-
- return test.NewEvent(nID, when, &consensusEventPayload{
- Type: evtReceiveBlock,
- PiggyBack: block,
- })
-}
-
-// Node is designed to work with test.Scheduler.
-type Node struct {
- ID types.NodeID
- ownChains []uint32
- roundEndTimes []time.Time
- roundToNotify uint64
- lattice *core.Lattice
- appModule *test.App
- stateModule *test.State
- govModule *test.Governance
- dbModule db.Database
- broadcastTargets map[types.NodeID]struct{}
- networkLatency test.LatencyModel
- proposingLatency test.LatencyModel
- prevFinalHeight uint64
- pendings []*types.Block
- prevHash common.Hash
- // This variable caches the maximum NumChains seen by this node when
- // it's notified for round switching.
- latticeMaxNumChains uint32
-}
-
-// newNode constructs an instance of Node.
-func newNode(
- gov *test.Governance,
- privateKey crypto.PrivateKey,
- dMoment time.Time,
- ownChains []uint32,
- networkLatency test.LatencyModel,
- proposingLatency test.LatencyModel) (*Node, error) {
- // Load all configs prepared in core.Governance into core.Lattice.
- copiedGov := gov.Clone()
- configs := loadAllConfigs(copiedGov)
- // Setup db.
- dbInst, err := db.NewMemBackedDB()
- if err != nil {
- return nil, err
- }
- // Setup test.App
- app := test.NewApp(0, copiedGov)
- // Setup lattice instance.
- lattice := core.NewLattice(
- dMoment,
- 0,
- configs[0],
- utils.NewSigner(privateKey),
- app,
- app,
- dbInst,
- &common.NullLogger{})
- n := &Node{
- ID: types.NewNodeID(privateKey.PublicKey()),
- ownChains: ownChains,
- roundEndTimes: genRoundEndTimes(configs, dMoment),
- roundToNotify: 2,
- networkLatency: networkLatency,
- proposingLatency: proposingLatency,
- appModule: app,
- stateModule: copiedGov.State(),
- dbModule: dbInst,
- govModule: copiedGov,
- lattice: lattice,
- latticeMaxNumChains: configs[0].NumChains,
- }
- for idx, config := range configs[1:] {
- if err := lattice.AppendConfig(uint64(idx+1), config); err != nil {
- return nil, err
- }
- if config.NumChains > n.latticeMaxNumChains {
- n.latticeMaxNumChains = config.NumChains
- }
- }
- return n, nil
-}
-
-// Handle implements test.EventHandler interface.
-func (n *Node) Handle(e *test.Event) (events []*test.Event) {
- payload := e.Payload.(*consensusEventPayload)
- switch payload.Type {
- case evtProposeBlock:
- events, e.ExecError = n.handleProposeBlock(e.Time, payload.PiggyBack)
- case evtReceiveBlock:
- events, e.ExecError = n.handleReceiveBlock(payload.PiggyBack)
- default:
- panic(fmt.Errorf("unknown consensus event type: %v", payload.Type))
- }
- return
-}
-
-func (n *Node) handleProposeBlock(when time.Time, payload interface{}) (
- events []*test.Event, err error) {
- pos := payload.(*struct {
- round uint64
- chain uint32
- })
- b, err := n.prepareBlock(pos.round, pos.chain, when)
- if err != nil {
- if err == utils.ErrInvalidChainID {
- // This chain is not included in this round, retry in next round.
- events = append(events, newProposeBlockEvent(
- n.ID, b.Position.Round+1, b.Position.ChainID,
- n.roundEndTimes[b.Position.Round]))
- }
- return
- }
- if events, err = n.processBlock(b); err != nil {
- // It's shouldn't be error when prepared.
- panic(err)
- }
- // Create 'block received' event for each other nodes.
- for nID := range n.broadcastTargets {
- events = append(events, newReceiveBlockEvent(
- nID, when.Add(n.networkLatency.Delay()), b.Clone()))
- }
- // Create next 'block proposing' event for this nodes.
- events = append(events, newProposeBlockEvent(n.ID,
- b.Position.Round,
- b.Position.ChainID,
- when.Add(n.proposingLatency.Delay())))
- return
-}
-
-func (n *Node) handleReceiveBlock(piggyback interface{}) (
- events []*test.Event, err error) {
- events, err = n.processBlock(piggyback.(*types.Block))
- if err != nil {
- panic(err)
- }
- return
-}
-
-func (n *Node) prepareBlock(
- round uint64, chainID uint32, when time.Time) (b *types.Block, err error) {
- b = &types.Block{
- Position: types.Position{
- Round: round,
- ChainID: chainID,
- }}
- if err = n.lattice.PrepareBlock(b, when); err != nil {
- if err == core.ErrRoundNotSwitch {
- b.Position.Round++
- err = n.lattice.PrepareBlock(b, when)
- }
- }
- return
-}
-
-func (n *Node) processBlock(b *types.Block) (events []*test.Event, err error) {
- // TODO(mission): this segment of code is identical to testLatticeMgr in
- // core/lattice_test.go, except the compaction-chain part.
- var (
- delivered []*types.Block
- )
- n.pendings = append([]*types.Block{b}, n.pendings...)
- for {
- var (
- newPendings []*types.Block
- tmpDelivered []*types.Block
- tmpErr error
- )
- updated := false
- for _, p := range n.pendings {
- if tmpErr = n.lattice.SanityCheck(p, false); tmpErr != nil {
- if tmpErr == core.ErrRetrySanityCheckLater {
- newPendings = append(newPendings, p)
- } else {
- // Those blocks are prepared by lattice module, they should
- // not be wrong.
- panic(tmpErr)
- }
- continue
- }
- if tmpDelivered, tmpErr =
- n.lattice.ProcessBlock(p); tmpErr != nil {
- // It's not allowed that sanity checked block failed to
- // be added to lattice.
- panic(tmpErr)
- }
- delivered = append(delivered, tmpDelivered...)
- updated = true
- }
- n.pendings = newPendings
- if !updated {
- break
- }
- }
- // Deliver blocks.
- for _, b = range delivered {
- b.Finalization.Height = n.prevFinalHeight + 1
- b.Finalization.ParentHash = n.prevHash
- n.appModule.BlockDelivered(b.Hash, b.Position, b.Finalization)
- n.prevFinalHeight++
- n.prevHash = b.Hash
- events = append(events, n.checkRoundSwitch(b)...)
- }
- if err = n.lattice.PurgeBlocks(delivered); err != nil {
- panic(err)
- }
- return
-}
-
-func (n *Node) checkRoundSwitch(b *types.Block) (evts []*test.Event) {
- if !b.Timestamp.After(n.roundEndTimes[b.Position.Round]) {
- return
- }
- if b.Position.Round+2 != n.roundToNotify {
- return
- }
- // Handle round switching logic.
- n.govModule.NotifyRound(n.roundToNotify)
- if n.roundToNotify == uint64(len(n.roundEndTimes)) {
- config := n.govModule.Configuration(n.roundToNotify)
- if config == nil {
- panic(fmt.Errorf(
- "config is not ready for round: %v", n.roundToNotify-1))
- }
- // Cache round ended time for each round.
- n.roundEndTimes = append(n.roundEndTimes,
- n.roundEndTimes[len(n.roundEndTimes)-1].Add(
- config.RoundInterval))
- // Add new config to lattice module.
- if err := n.lattice.AppendConfig(n.roundToNotify, config); err != nil {
- panic(err)
- }
- if config.NumChains > n.latticeMaxNumChains {
- // We can be sure that lattice module can support this number of
- // chains.
- for _, chainID := range n.ownChains {
- if chainID < n.latticeMaxNumChains {
- continue
- }
- if chainID >= config.NumChains {
- continue
- }
- // For newly added chains, add block proposing seed event.
- evts = append(evts, newProposeBlockEvent(n.ID, n.roundToNotify,
- chainID, n.roundEndTimes[n.roundToNotify-1]))
- }
- n.latticeMaxNumChains = config.NumChains
- }
- } else if n.roundToNotify > uint64(len(n.roundEndTimes)) {
- panic(fmt.Errorf(
- "config notification not incremental: %v, cached configs: %v",
- n.roundToNotify, len(n.roundEndTimes)))
- }
- n.roundToNotify++
- return
-}
-
-// Bootstrap this node with block proposing event.
-func (n *Node) Bootstrap(sch *test.Scheduler, now time.Time) (err error) {
- sch.RegisterEventHandler(n.ID, n)
- for _, chainID := range n.ownChains {
- if chainID >= n.latticeMaxNumChains {
- continue
- }
- err = sch.Seed(newProposeBlockEvent(n.ID, 0, chainID, now))
- if err != nil {
- return
- }
- }
- return
-}
-
-func (n *Node) setBroadcastTargets(targets map[types.NodeID]struct{}) {
- // Clone targets, except self.
- targetsCopy := make(map[types.NodeID]struct{})
- for nID := range targets {
- if nID == n.ID {
- continue
- }
- targetsCopy[nID] = struct{}{}
- }
- n.broadcastTargets = targetsCopy
-}
-
-func (n *Node) app() *test.App {
- return n.appModule
-}
-
-func (n *Node) db() db.Database {
- return n.dbModule
-}
-
-func (n *Node) gov() *test.Governance {
- return n.govModule
-}
diff --git a/integration_test/stats.go b/integration_test/stats.go
deleted file mode 100644
index 5d66e29..0000000
--- a/integration_test/stats.go
+++ /dev/null
@@ -1,192 +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
-// <http://www.gnu.org/licenses/>.
-
-package integration
-
-import (
- "fmt"
- "time"
-
- "github.com/dexon-foundation/dexon-consensus/core/test"
- "github.com/dexon-foundation/dexon-consensus/core/types"
-)
-
-// Errors when calculating statistics for events.
-var (
- ErrUnknownEvent = fmt.Errorf("unknown event")
- ErrUnknownConsensusEventType = fmt.Errorf("unknown consensus event type")
-)
-
-// StatsSet represents accumulatee result of a group of related events
-// (ex. All events from one node).
-type StatsSet struct {
- ProposedBlockCount int
- ReceivedBlockCount int
- ConfirmedBlockCount int
- TotalOrderedBlockCount int
- DeliveredBlockCount int
- ProposingLatency time.Duration
- ReceivingLatency time.Duration
- PrepareExecLatency time.Duration
- ProcessExecLatency time.Duration
-}
-
-// newBlockProposeEvent accumulates a block proposing event.
-func (s *StatsSet) newBlockProposeEvent(
- e *test.Event, payload *consensusEventPayload, history []*test.Event) {
-
- // Find previous block proposing event.
- if e.ParentHistoryIndex != -1 {
- parentEvent := history[e.ParentHistoryIndex]
- s.ProposingLatency +=
- e.Time.Sub(parentEvent.Time) - parentEvent.ExecInterval
- }
- s.PrepareExecLatency += e.ExecInterval
- s.ProposedBlockCount++
-}
-
-// newBlockReceiveEvent accumulates a block received event.
-func (s *StatsSet) newBlockReceiveEvent(
- e *test.Event,
- payload *consensusEventPayload,
- history []*test.Event,
- app *test.App) {
-
- // Find previous block proposing event.
- parentEvent := history[e.ParentHistoryIndex]
- s.ReceivingLatency +=
- e.Time.Sub(parentEvent.Time) - parentEvent.ExecInterval
- s.ProcessExecLatency += e.ExecInterval
- s.ReceivedBlockCount++
-
- // Find statistics from test.App
- block := payload.PiggyBack.(*types.Block)
- app.WithLock(func(app *test.App) {
- // Is this block confirmed?
- if _, exists := app.Confirmed[block.Hash]; !exists {
- return
- }
- s.ConfirmedBlockCount++
- // Is this block total ordered?
- if _, exists := app.TotalOrderedByHash[block.Hash]; !exists {
- return
- }
- s.TotalOrderedBlockCount++
-
- // Is this block delivered?
- if _, exists := app.Delivered[block.Hash]; !exists {
- return
- }
- s.DeliveredBlockCount++
- })
-}
-
-// done would divide the latencies we cached with related event count. This way
-// to calculate average latency is more accurate.
-func (s *StatsSet) done(nodeCount int) {
- s.ProposingLatency /= time.Duration(s.ProposedBlockCount - nodeCount)
- s.ReceivingLatency /= time.Duration(s.ReceivedBlockCount)
- s.PrepareExecLatency /= time.Duration(s.ProposedBlockCount)
- s.ProcessExecLatency /= time.Duration(s.ReceivedBlockCount)
-}
-
-// Stats is statistics of a slice of test.Event generated by nodes.
-type Stats struct {
- ByNode map[types.NodeID]*StatsSet
- All *StatsSet
- BPS float64
- ExecutionTime time.Duration
-}
-
-// NewStats constructs an Stats instance by providing a slice of
-// test.Event.
-func NewStats(
- history []*test.Event, apps map[types.NodeID]*test.App) (
- stats *Stats, err error) {
-
- stats = &Stats{
- ByNode: make(map[types.NodeID]*StatsSet),
- All: &StatsSet{},
- }
- if err = stats.calculate(history, apps); err != nil {
- stats = nil
- }
- stats.summary(history)
- return
-}
-
-func (stats *Stats) calculate(
- history []*test.Event, apps map[types.NodeID]*test.App) error {
-
- defer func() {
- stats.All.done(len(stats.ByNode))
- for _, set := range stats.ByNode {
- set.done(1)
- }
- }()
-
- for _, e := range history {
- payload, ok := e.Payload.(*consensusEventPayload)
- if !ok {
- return ErrUnknownEvent
- }
- switch payload.Type {
- case evtProposeBlock:
- stats.All.newBlockProposeEvent(
- e, payload, history)
- stats.getStatsSetByNode(e.NodeID).newBlockProposeEvent(
- e, payload, history)
- case evtReceiveBlock:
- stats.All.newBlockReceiveEvent(
- e, payload, history, apps[e.NodeID])
- stats.getStatsSetByNode(e.NodeID).newBlockReceiveEvent(
- e, payload, history, apps[e.NodeID])
- default:
- return ErrUnknownConsensusEventType
- }
- }
- return nil
-}
-
-func (stats *Stats) getStatsSetByNode(
- vID types.NodeID) (s *StatsSet) {
-
- s = stats.ByNode[vID]
- if s == nil {
- s = &StatsSet{}
- stats.ByNode[vID] = s
- }
- return
-}
-
-func (stats *Stats) summary(history []*test.Event) {
- // Find average delivered block count among all blocks.
- totalConfirmedBlocks := 0
- for _, s := range stats.ByNode {
- totalConfirmedBlocks += s.DeliveredBlockCount
- }
- averageConfirmedBlocks := totalConfirmedBlocks / len(stats.ByNode)
-
- // Find execution time.
- // Note: it's a simplified way to calculate the execution time:
- // the latest event might not be at the end of history when
- // the number of worker routine is larger than 1.
- stats.ExecutionTime = history[len(history)-1].Time.Sub(history[0].Time)
- // Calculate BPS.
- latencyAsSecond := stats.ExecutionTime.Nanoseconds() / (1000 * 1000 * 1000)
- stats.BPS = float64(averageConfirmedBlocks) / float64(latencyAsSecond)
-}
diff --git a/integration_test/stats_test.go b/integration_test/stats_test.go
deleted file mode 100644
index 95bd5ac..0000000
--- a/integration_test/stats_test.go
+++ /dev/null
@@ -1,84 +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
-// <http://www.gnu.org/licenses/>.
-
-package integration
-
-import (
- "testing"
- "time"
-
- "github.com/dexon-foundation/dexon-consensus/common"
- "github.com/dexon-foundation/dexon-consensus/core"
- "github.com/dexon-foundation/dexon-consensus/core/test"
- "github.com/stretchr/testify/suite"
-)
-
-type EventStatsTestSuite struct {
- suite.Suite
-}
-
-func (s *EventStatsTestSuite) TestCalculate() {
- // Setup a test with fixed latency in proposing and network,
- // and make sure the calculated statistics is expected.
- var (
- networkLatency = &test.FixedLatencyModel{Latency: 100}
- proposingLatency = &test.FixedLatencyModel{Latency: 300}
- req = s.Require()
- )
- prvKeys, pubKeys, err := test.NewKeys(7)
- req.NoError(err)
- gov, err := test.NewGovernance(
- test.NewState(
- pubKeys, 100*time.Millisecond, &common.NullLogger{}, true),
- core.ConfigRoundShift)
- req.NoError(err)
- nodes, err := PrepareNodes(
- gov, prvKeys, 7, networkLatency, proposingLatency)
- req.NoError(err)
- apps, dbs := CollectAppAndDBFromNodes(nodes)
- sch := test.NewScheduler(test.NewStopByConfirmedBlocks(50, apps, dbs))
- now := time.Now().UTC()
- for _, n := range nodes {
- req.NoError(n.Bootstrap(sch, now))
- }
- sch.Run(10)
- req.Nil(VerifyApps(apps))
- // Check total statistics result.
- stats, err := NewStats(sch.CloneExecutionHistory(), apps)
- req.Nil(err)
- req.True(stats.All.ProposedBlockCount > 350)
- req.True(stats.All.ReceivedBlockCount > 350)
- req.True(stats.All.ConfirmedBlockCount > 350)
- req.True(stats.All.TotalOrderedBlockCount >= 350)
- req.True(stats.All.DeliveredBlockCount >= 350)
- req.Equal(stats.All.ProposingLatency, 300*time.Millisecond)
- req.Equal(stats.All.ReceivingLatency, 100*time.Millisecond)
- // Check statistics for each node.
- for _, vStats := range stats.ByNode {
- req.True(vStats.ProposedBlockCount > 50)
- req.True(vStats.ReceivedBlockCount > 50)
- req.True(vStats.ConfirmedBlockCount > 50)
- req.True(vStats.TotalOrderedBlockCount >= 50)
- req.True(vStats.DeliveredBlockCount >= 50)
- req.Equal(vStats.ProposingLatency, 300*time.Millisecond)
- req.Equal(vStats.ReceivingLatency, 100*time.Millisecond)
- }
-}
-
-func TestEventStats(t *testing.T) {
- suite.Run(t, new(EventStatsTestSuite))
-}
diff --git a/integration_test/utils.go b/integration_test/utils.go
deleted file mode 100644
index 2fbfa1a..0000000
--- a/integration_test/utils.go
+++ /dev/null
@@ -1,140 +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
-// <http://www.gnu.org/licenses/>.
-
-package integration
-
-import (
- "errors"
- "time"
-
- "github.com/dexon-foundation/dexon-consensus/core"
- "github.com/dexon-foundation/dexon-consensus/core/crypto"
- "github.com/dexon-foundation/dexon-consensus/core/db"
- "github.com/dexon-foundation/dexon-consensus/core/test"
- "github.com/dexon-foundation/dexon-consensus/core/types"
-)
-
-func genRoundEndTimes(
- configs []*types.Config, dMoment time.Time) (ends []time.Time) {
- now := dMoment
- for _, config := range configs {
- now = now.Add(config.RoundInterval)
- ends = append(ends, now)
- }
- return
-}
-
-// loadAllConfigs loads all prepared configuration from governance,
-// starts from round 0.
-func loadAllConfigs(gov core.Governance) (configs []*types.Config) {
- var round uint64
- for {
- config := gov.Configuration(round)
- if config == nil {
- break
- }
- configs = append(configs, config)
- round++
- }
- return
-}
-
-// decideOwnChains compute which chainIDs belongs to this node.
-func decideOwnChains(numChains uint32, numNodes, id int) (own []uint32) {
- var cur = uint32(id)
- if numNodes == 0 {
- panic(errors.New("attempt to arrange chains on 0 nodes"))
- }
- for {
- if cur >= numChains {
- break
- }
- own = append(own, cur)
- cur += uint32(numNodes)
- }
- return
-}
-
-// PrepareNodes setups nodes for testing.
-func PrepareNodes(
- gov *test.Governance,
- prvKeys []crypto.PrivateKey,
- maxNumChains uint32,
- networkLatency, proposingLatency test.LatencyModel) (
- nodes map[types.NodeID]*Node, err error) {
- if maxNumChains == 0 {
- err = errors.New("zero NumChains is unexpected")
- return
- }
- // Setup nodes, count of nodes is derived from the count of private keys
- // hold in Governance.
- nodes = make(map[types.NodeID]*Node)
- dMoment := time.Now().UTC()
- broadcastTargets := make(map[types.NodeID]struct{})
- for idx, prvKey := range prvKeys {
- nID := types.NewNodeID(prvKey.PublicKey())
- broadcastTargets[nID] = struct{}{}
- // Decides which chains are owned by this node.
- if nodes[nID], err = newNode(
- gov,
- prvKey,
- dMoment,
- decideOwnChains(maxNumChains, len(prvKeys), idx),
- networkLatency,
- proposingLatency); err != nil {
- return
- }
- }
- // Assign broadcast targets.
- for _, n := range nodes {
- n.setBroadcastTargets(broadcastTargets)
- n.gov().State().SwitchToRemoteMode()
- }
- return
-}
-
-// VerifyApps is a helper to check delivery between test.Apps
-func VerifyApps(apps map[types.NodeID]*test.App) (err error) {
- for vFrom, fromApp := range apps {
- if err = fromApp.Verify(); err != nil {
- return
- }
- for vTo, toApp := range apps {
- if vFrom == vTo {
- continue
- }
- if err = fromApp.Compare(toApp); err != nil {
- return
- }
- }
- }
- return
-}
-
-// CollectAppAndDBFromNodes collects test.App and db.Database
-// from nodes.
-func CollectAppAndDBFromNodes(nodes map[types.NodeID]*Node) (
- apps map[types.NodeID]*test.App,
- dbs map[types.NodeID]db.Database) {
- apps = make(map[types.NodeID]*test.App)
- dbs = make(map[types.NodeID]db.Database)
- for nID, node := range nodes {
- apps[nID] = node.app()
- dbs[nID] = node.db()
- }
- return
-}
diff --git a/integration_test/utils_test.go b/integration_test/utils_test.go
deleted file mode 100644
index 99b62c1..0000000
--- a/integration_test/utils_test.go
+++ /dev/null
@@ -1,61 +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
-// <http://www.gnu.org/licenses/>.
-
-package integration
-
-import (
- "testing"
-
- "github.com/stretchr/testify/suite"
-)
-
-type UtilsTestSuite struct {
- suite.Suite
-}
-
-func (s *UtilsTestSuite) TestDecideOwnChains() {
- // Basic test for each node index.
- s.Empty(decideOwnChains(1, 1, 1))
- s.Equal(decideOwnChains(1, 1, 0), []uint32{0})
- s.Equal(decideOwnChains(30, 7, 4), []uint32{4, 11, 18, 25})
- // Make sure every chain is covered.
- isAllCovered := func(numChains uint32, numNodes int) bool {
- if numNodes == 0 {
- decideOwnChains(numChains, numNodes, 0)
- return false
- }
- covered := make(map[uint32]struct{})
- for i := 0; i < numNodes; i++ {
- for _, chainID := range decideOwnChains(numChains, numNodes, i) {
- s.Require().True(chainID < numChains)
- covered[chainID] = struct{}{}
- }
- }
- return uint32(len(covered)) == numChains
- }
- s.True(isAllCovered(100, 33))
- s.True(isAllCovered(100, 200))
- s.True(isAllCovered(100, 50))
- s.True(isAllCovered(100, 1))
- s.Panics(func() {
- isAllCovered(100, 0)
- })
-}
-
-func TestUtils(t *testing.T) {
- suite.Run(t, new(UtilsTestSuite))
-}
diff --git a/integration_test/with_scheduler_test.go b/integration_test/with_scheduler_test.go
deleted file mode 100644
index 66fc9b8..0000000
--- a/integration_test/with_scheduler_test.go
+++ /dev/null
@@ -1,150 +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
-// <http://www.gnu.org/licenses/>.
-
-package integration
-
-import (
- "testing"
- "time"
-
- "github.com/dexon-foundation/dexon-consensus/common"
- "github.com/dexon-foundation/dexon-consensus/core"
- "github.com/dexon-foundation/dexon-consensus/core/test"
- "github.com/stretchr/testify/suite"
-)
-
-type WithSchedulerTestSuite struct {
- suite.Suite
-}
-
-func (s *WithSchedulerTestSuite) TestNonByzantine() {
- var (
- networkLatency = &test.NormalLatencyModel{
- Sigma: 20,
- Mean: 250,
- }
- proposingLatency = &test.NormalLatencyModel{
- Sigma: 30,
- Mean: 500,
- }
- numNodes = 25
- req = s.Require()
- )
- if testing.Short() {
- numNodes = 7
- }
- // Setup key pairs.
- prvKeys, pubKeys, err := test.NewKeys(numNodes)
- req.NoError(err)
- // Setup governance.
- gov, err := test.NewGovernance(
- test.NewState(
- pubKeys, 250*time.Millisecond, &common.NullLogger{}, true),
- core.ConfigRoundShift)
- req.NoError(err)
- // Setup nodes.
- nodes, err := PrepareNodes(
- gov, prvKeys, 25, networkLatency, proposingLatency)
- req.NoError(err)
- // Setup scheduler.
- apps, dbs := CollectAppAndDBFromNodes(nodes)
- now := time.Now().UTC()
- sch := test.NewScheduler(test.NewStopByConfirmedBlocks(50, apps, dbs))
- for _, n := range nodes {
- req.NoError(n.Bootstrap(sch, now))
- }
- sch.Run(4)
- // Check results by comparing test.App instances.
- req.NoError(VerifyApps(apps))
-}
-
-func (s *WithSchedulerTestSuite) TestConfigurationChange() {
- // This test case verify the correctness of core.Lattice when configuration
- // changes.
- // - Configuration changes are registered at 'pickedNode', and would carried
- // in blocks' payload and broadcast to other nodes.
- var (
- networkLatency = &test.NormalLatencyModel{
- Sigma: 20,
- Mean: 250,
- }
- proposingLatency = &test.NormalLatencyModel{
- Sigma: 30,
- Mean: 500,
- }
- numNodes = 4
- req = s.Require()
- maxNumChains = uint32(9)
- )
- // Setup key pairs.
- prvKeys, pubKeys, err := test.NewKeys(numNodes)
- req.NoError(err)
- // Setup governance.
- gov, err := test.NewGovernance(
- test.NewState(
- pubKeys, 250*time.Millisecond, &common.NullLogger{}, true),
- core.ConfigRoundShift)
- req.NoError(err)
- // Change default round interval, expect 1 round produce 30 blocks.
- gov.State().RequestChange(test.StateChangeRoundInterval, 15*time.Second)
- // Setup nodes.
- nodes, err := PrepareNodes(
- gov, prvKeys, maxNumChains, networkLatency, proposingLatency)
- req.NoError(err)
- // Set scheduler.
- apps, dbs := CollectAppAndDBFromNodes(nodes)
- now := time.Now().UTC()
- sch := test.NewScheduler(test.NewStopByRound(9, apps, dbs))
- for _, n := range nodes {
- req.NoError(n.Bootstrap(sch, now))
- }
- // Register some configuration changes at some node.
- var pickedNode *Node
- for _, pickedNode = range nodes {
- break
- }
- // Config changes for round 5, numChains from 4 to 7.
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 5, test.StateChangeNumChains, uint32(7)))
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 5, test.StateChangeK, 3))
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 5, test.StateChangePhiRatio, float32(0.5)))
- // Config changes for round 6, numChains from 7 to 9.
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 6, test.StateChangeNumChains, maxNumChains))
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 6, test.StateChangeK, 0))
- // Config changes for round 7, numChains from 9 to 7.
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 7, test.StateChangeNumChains, uint32(7)))
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 7, test.StateChangeK, 1))
- // Config changes for round 8, numChains from 7 to 5.
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 8, test.StateChangeNumChains, uint32(5)))
- req.NoError(pickedNode.gov().RegisterConfigChange(
- 8, test.StateChangeK, 1))
- // Perform test.
- sch.Run(4)
- // Check results by comparing test.App instances.
- req.NoError(VerifyApps(apps))
-}
-
-func TestWithScheduler(t *testing.T) {
- suite.Run(t, new(WithSchedulerTestSuite))
-}