From 6efe199cb38eb4cb9a9a64d98ff5f8c4fb997da7 Mon Sep 17 00:00:00 2001 From: Jimmy Hu Date: Wed, 20 Mar 2019 14:57:12 +0800 Subject: core: merge notarySet and DKGSet (#488) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * core: さよなら DKGSet * test logger * temporary fix before finalized * core: Sign psig on commit vote * Add syncer log * fixup --- core/agreement-mgr.go | 4 +- core/agreement-state_test.go | 4 + core/agreement.go | 11 +- core/agreement_test.go | 4 + core/blockchain.go | 84 ++------ core/blockchain_test.go | 154 ++----------- core/configuration-chain.go | 32 +-- core/configuration-chain_test.go | 17 +- core/consensus.go | 383 ++++++++++++++++----------------- core/consensus_test.go | 13 +- core/interfaces.go | 6 - core/syncer/consensus.go | 83 ++----- core/test/governance.go | 6 +- core/test/governance_test.go | 16 +- core/test/marshaller.go | 15 +- core/test/network.go | 272 ++++++----------------- core/test/network_test.go | 20 +- core/test/state-change-request.go | 5 - core/test/state-change-request_test.go | 2 +- core/test/state.go | 11 - core/test/state_test.go | 3 - core/test/tcp-transport.go | 2 - core/test/utils.go | 8 +- core/types/block-randomness.go | 31 ++- core/types/config.go | 5 - core/types/config_test.go | 1 - core/types/nodeset.go | 6 - core/types/vote.go | 8 +- core/utils/crypto.go | 10 +- core/utils/nodeset-cache.go | 15 -- core/utils/nodeset-cache_test.go | 4 - core/utils/utils.go | 2 +- integration_test/consensus_test.go | 41 ++-- simulation/config/utils.go | 4 +- simulation/node.go | 1 - 35 files changed, 413 insertions(+), 870 deletions(-) diff --git a/core/agreement-mgr.go b/core/agreement-mgr.go index d29863d..02b7b7b 100644 --- a/core/agreement-mgr.go +++ b/core/agreement-mgr.go @@ -141,7 +141,7 @@ func newAgreementMgr(con *Consensus, initRound uint64, roundValue: &atomic.Value{}, changeNotaryHeightValue: &atomic.Value{}, } - mgr.recv.roundValue.Store(uint64(0)) + mgr.recv.updateRound(uint64(0)) mgr.recv.changeNotaryHeightValue.Store(uint64(0)) agr := newAgreement( mgr.ID, @@ -377,7 +377,7 @@ Loop: } mgr.recv.isNotary = checkRound() // Run BA for this round. - mgr.recv.roundValue.Store(currentRound) + mgr.recv.updateRound(currentRound) mgr.recv.changeNotaryHeightValue.Store(curConfig.RoundEndHeight()) mgr.recv.restartNotary <- types.Position{ Round: mgr.recv.round(), diff --git a/core/agreement-state_test.go b/core/agreement-state_test.go index 1b7d41b..c4197b5 100644 --- a/core/agreement-state_test.go +++ b/core/agreement-state_test.go @@ -43,6 +43,10 @@ type agreementStateTestReceiver struct { leader *leaderSelector } +func (r *agreementStateTestReceiver) VerifyPartialSignature(*types.Vote) bool { + return true +} + func (r *agreementStateTestReceiver) ProposeVote(vote *types.Vote) { r.s.voteChan <- vote } diff --git a/core/agreement.go b/core/agreement.go index 16f36bc..1ba9034 100644 --- a/core/agreement.go +++ b/core/agreement.go @@ -38,9 +38,10 @@ func init() { // Errors for agreement module. var ( - ErrInvalidVote = fmt.Errorf("invalid vote") - ErrNotInNotarySet = fmt.Errorf("not in notary set") - ErrIncorrectVoteSignature = fmt.Errorf("incorrect vote signature") + ErrInvalidVote = fmt.Errorf("invalid vote") + ErrNotInNotarySet = fmt.Errorf("not in notary set") + ErrIncorrectVoteSignature = fmt.Errorf("incorrect vote signature") + ErrIncorrectVotePartialSignature = fmt.Errorf("incorrect vote psig") ) // ErrFork for fork error in agreement. @@ -83,6 +84,7 @@ type agreementReceiver interface { PullBlocks(common.Hashes) ReportForkVote(v1, v2 *types.Vote) ReportForkBlock(b1, b2 *types.Block) + VerifyPartialSignature(vote *types.Vote) bool } type pendingBlock struct { @@ -332,6 +334,9 @@ func (a *agreement) sanityCheck(vote *types.Vote) error { if !ok { return ErrIncorrectVoteSignature } + if !a.data.recv.VerifyPartialSignature(vote) { + return ErrIncorrectVotePartialSignature + } return nil } diff --git a/core/agreement_test.go b/core/agreement_test.go index 4ddff8d..dfeb783 100644 --- a/core/agreement_test.go +++ b/core/agreement_test.go @@ -34,6 +34,10 @@ type agreementTestReceiver struct { agreementIndex int } +func (r *agreementTestReceiver) VerifyPartialSignature(*types.Vote) bool { + return true +} + func (r *agreementTestReceiver) ProposeVote(vote *types.Vote) { r.s.voteChan <- vote } diff --git a/core/blockchain.go b/core/blockchain.go index 610ab28..0ecd083 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -32,18 +32,19 @@ import ( // Errors for sanity check error. var ( - ErrBlockFromOlderPosition = errors.New("block from older position") - ErrNotGenesisBlock = errors.New("not a genesis block") - ErrIsGenesisBlock = errors.New("is a genesis block") - ErrIncorrectParentHash = errors.New("incorrect parent hash") - ErrInvalidBlockHeight = errors.New("invalid block height") - ErrInvalidRoundID = errors.New("invalid round id") - ErrNotFollowTipPosition = errors.New("not follow tip position") - ErrDuplicatedPendingBlock = errors.New("duplicated pending block") - ErrRetrySanityCheckLater = errors.New("retry sanity check later") - ErrRoundNotSwitch = errors.New("round not switch") - ErrIncorrectBlockRandomnessResult = errors.New( + ErrBlockFromOlderPosition = errors.New("block from older position") + ErrNotGenesisBlock = errors.New("not a genesis block") + ErrIsGenesisBlock = errors.New("is a genesis block") + ErrIncorrectParentHash = errors.New("incorrect parent hash") + ErrInvalidBlockHeight = errors.New("invalid block height") + ErrInvalidRoundID = errors.New("invalid round id") + ErrNotFollowTipPosition = errors.New("not follow tip position") + ErrDuplicatedPendingBlock = errors.New("duplicated pending block") + ErrRetrySanityCheckLater = errors.New("retry sanity check later") + ErrRoundNotSwitch = errors.New("round not switch") + ErrIncorrectAgreementResult = errors.New( "incorrect block randomness result") + ErrMissingRandomness = errors.New("missing block randomness") ) type pendingBlockRecord struct { @@ -134,7 +135,7 @@ type blockChain struct { vGetter tsigVerifierGetter app Application logger common.Logger - pendingRandomnesses map[types.Position]*types.BlockRandomnessResult + pendingRandomnesses map[types.Position]*types.AgreementResult configs []blockChainConfig pendingBlocks pendingBlockRecords confirmedBlocks types.BlocksByPosition @@ -154,7 +155,7 @@ func newBlockChain(nID types.NodeID, dMoment time.Time, initBlock *types.Block, logger: logger, dMoment: dMoment, pendingRandomnesses: make( - map[types.Position]*types.BlockRandomnessResult), + map[types.Position]*types.AgreementResult), } } @@ -211,10 +212,10 @@ func (bc *blockChain) notifyRoundEvents(evts []utils.RoundEventParam) error { } func (bc *blockChain) proposeBlock(position types.Position, - proposeTime time.Time) (b *types.Block, err error) { + proposeTime time.Time, isEmpty bool) (b *types.Block, err error) { bc.lock.RLock() defer bc.lock.RUnlock() - return bc.prepareBlock(position, proposeTime, false) + return bc.prepareBlock(position, proposeTime, isEmpty) } func (bc *blockChain) extractBlocks() (ret []*types.Block) { @@ -222,9 +223,6 @@ func (bc *blockChain) extractBlocks() (ret []*types.Block) { defer bc.lock.Unlock() for len(bc.confirmedBlocks) > 0 { c := bc.confirmedBlocks[0] - if c.Position.Round >= DKGDelayRound && len(c.Finalization.Randomness) == 0 { - break - } c, bc.confirmedBlocks = bc.confirmedBlocks[0], bc.confirmedBlocks[1:] // TODO(mission): remove these duplicated field if we fully converted // to single chain. @@ -315,6 +313,9 @@ func (bc *blockChain) addEmptyBlock(position types.Position) ( // addBlock should be called when the block is confirmed by BA, we won't perform // sanity check against this block, it's ok to add block with skipping height. func (bc *blockChain) addBlock(b *types.Block) error { + if b.Position.Round >= DKGDelayRound && len(b.Finalization.Randomness) == 0 { + return ErrMissingRandomness + } bc.lock.Lock() defer bc.lock.Unlock() confirmed := false @@ -338,45 +339,6 @@ func (bc *blockChain) addBlock(b *types.Block) error { return nil } -func (bc *blockChain) shouldAddRandomness(r *types.BlockRandomnessResult) bool { - bc.lock.RLock() - defer bc.lock.RUnlock() - if bc.lastDelivered != nil && - bc.lastDelivered.Position.Newer(r.Position) { - return false - } - _, exists := bc.pendingRandomnesses[r.Position] - if exists { - return false - } - b := bc.findPendingBlock(r.Position) - return b == nil || len(b.Finalization.Randomness) == 0 -} - -func (bc *blockChain) addRandomness(r *types.BlockRandomnessResult) error { - if !bc.shouldAddRandomness(r) { - return nil - } - ok, err := bc.verifyRandomness(r.BlockHash, r.Position.Round, r.Randomness) - if err != nil { - return err - } - if !ok { - return ErrIncorrectBlockRandomnessResult - } - bc.lock.Lock() - defer bc.lock.Unlock() - if b := bc.findPendingBlock(r.Position); b != nil { - if !r.BlockHash.Equal(b.Hash) { - panic(fmt.Errorf("mismathed randomness: %s %s", b, r)) - } - b.Finalization.Randomness = r.Randomness - } else { - bc.pendingRandomnesses[r.Position] = r - } - return nil -} - // TODO(mission): remove this method after removing the strong binding between // BA and blockchain. func (bc *blockChain) tipRound() uint64 { @@ -456,14 +418,6 @@ func (bc *blockChain) lastPendingBlock() *types.Block { return bc.confirmedBlocks[0] } -func (bc *blockChain) processFinalizedBlock(b *types.Block) error { - return bc.addRandomness(&types.BlockRandomnessResult{ - BlockHash: b.Hash, - Position: b.Position, - Randomness: b.Finalization.Randomness, - }) -} - ///////////////////////////////////////////// // // internal helpers diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 87b8eac..6a615c1 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -18,7 +18,6 @@ package core import ( - "fmt" "testing" "time" @@ -82,6 +81,9 @@ func (s *BlockChainTestSuite) newBlocks(c uint64, initBlock *types.Block) ( Position: types.Position{Round: initRound, Height: baseHeight + i}, Timestamp: t, } + if b.Position.Round >= DKGDelayRound { + b.Finalization.Randomness = common.GenerateRandomBytes() + } s.Require().NoError(s.signer.SignBlock(b)) blocks = append(blocks, b) parentHash = b.Hash @@ -116,19 +118,13 @@ func (s *BlockChainTestSuite) newBlock(parent *types.Block, round uint64, }, Timestamp: parent.Timestamp.Add(blockInterval), } + if b.Position.Round >= DKGDelayRound { + b.Finalization.Randomness = common.GenerateRandomBytes() + } s.Require().NoError(s.signer.SignBlock(b)) return b } -func (s *BlockChainTestSuite) newRandomnessFromBlock( - b *types.Block) *types.BlockRandomnessResult { - return &types.BlockRandomnessResult{ - BlockHash: b.Hash, - Position: b.Position, - Randomness: common.GenerateRandomBytes(), - } -} - func (s *BlockChainTestSuite) newBlockChain(initB *types.Block, roundLength uint64) (bc *blockChain) { initRound := uint64(0) @@ -163,64 +159,6 @@ func (s *BlockChainTestSuite) newRoundOneInitBlock() *types.Block { return initBlock } -func (s *BlockChainTestSuite) baseConcurrentAceessTest(initBlock *types.Block, - blocks []*types.Block, rands []*types.BlockRandomnessResult) { - var ( - bc = s.newBlockChain(initBlock, uint64(len(blocks)+1)) - start = make(chan struct{}) - newNotif = make(chan struct{}, 1) - delivered []*types.Block - ) - add := func(v interface{}) { - <-start - switch val := v.(type) { - case *types.Block: - if err := bc.addBlock(val); err != nil { - // Never assertion in sub routine when testing. - panic(err) - } - case *types.BlockRandomnessResult: - if err := bc.addRandomness(val); err != nil { - // Never assertion in sub routine when testing. - panic(err) - } - default: - panic(fmt.Errorf("unknown type: %v", v)) - } - select { - case newNotif <- struct{}{}: - default: - } - } - for _, b := range blocks { - go add(b) - } - for _, r := range rands { - go add(r) - } - close(start) - for { - select { - case <-newNotif: - delivered = append(delivered, bc.extractBlocks()...) - case <-time.After(100 * time.Millisecond): - delivered = append(delivered, bc.extractBlocks()...) - } - if len(delivered) == len(blocks) { - break - } - } - // Check result. - b := delivered[0] - s.Require().Equal(b.Position.Height, uint64(1)) - s.Require().NotEmpty(b.Finalization.Randomness) - for _, bb := range delivered[1:] { - s.Require().Equal(b.Position.Height+1, bb.Position.Height) - s.Require().NotEmpty(b.Finalization.Randomness) - b = bb - } -} - func (s *BlockChainTestSuite) TestBasicUsage() { initBlock := s.newRoundOneInitBlock() bc := s.newBlockChain(initBlock, 10) @@ -233,20 +171,11 @@ func (s *BlockChainTestSuite) TestBasicUsage() { b5 := &types.Block{ ParentHash: b4.Hash, Position: types.Position{Round: 1, Height: b4.Position.Height + 1}, + Finalization: types.FinalizationResult{ + Randomness: common.GenerateRandomBytes(), + }, } s.Require().NoError(s.signer.SignBlock(b5)) - r0 := s.newRandomnessFromBlock(b0) - r1 := s.newRandomnessFromBlock(b1) - r2 := s.newRandomnessFromBlock(b2) - r3 := s.newRandomnessFromBlock(b3) - r4 := s.newRandomnessFromBlock(b4) - r5 := s.newRandomnessFromBlock(b5) - // add those datum in reversed order of position. - s.Require().NoError(bc.addRandomness(r4)) - s.Require().NoError(bc.addRandomness(r3)) - s.Require().NoError(bc.addRandomness(r2)) - s.Require().NoError(bc.addRandomness(r1)) - s.Require().NoError(bc.addRandomness(r0)) s.Require().NoError(bc.addBlock(b5)) emptyB, err := bc.addEmptyBlock(b4.Position) s.Require().Nil(emptyB) @@ -256,29 +185,10 @@ func (s *BlockChainTestSuite) TestBasicUsage() { s.Require().NoError(bc.addBlock(b1)) s.Require().NoError(bc.addBlock(b0)) extracted := bc.extractBlocks() - s.Require().Len(extracted, 5) + s.Require().Len(extracted, 6) s.Require().Equal(extracted[4].Hash, b4.Hash) - s.Require().NoError(bc.addRandomness(r5)) extracted = bc.extractBlocks() - s.Require().Len(extracted, 1) - s.Require().Equal(extracted[0].Hash, b5.Hash) -} - -func (s *BlockChainTestSuite) TestConcurrentAccess() { - // Raise one go routine for each block and randomness. And let them try to - // add to blockChain at the same time. Make sure we can delivered them all. - var ( - retry = 10 - initBlock = s.newRoundOneInitBlock() - blocks = s.newBlocks(500, initBlock) - rands = []*types.BlockRandomnessResult{} - ) - for _, b := range blocks { - rands = append(rands, s.newRandomnessFromBlock(b)) - } - for i := 0; i < retry; i++ { - s.baseConcurrentAceessTest(initBlock, blocks, rands) - } + s.Require().Len(extracted, 0) } func (s *BlockChainTestSuite) TestSanityCheck() { @@ -411,20 +321,6 @@ func (s *BlockChainTestSuite) TestNextBlockAndTipRound() { s.Require().Equal(bc.tipRound(), uint64(1)) } -func (s *BlockChainTestSuite) TestPendingBlocksWithoutRandomness() { - initBlock := s.newRoundOneInitBlock() - bc := s.newBlockChain(initBlock, 10) - blocks := s.newBlocks(4, initBlock) - s.Require().NoError(bc.addBlock(blocks[0])) - s.Require().NoError(bc.addBlock(blocks[1])) - s.Require().NoError(bc.addBlock(blocks[3])) - s.Require().Equal(bc.pendingBlocksWithoutRandomness(), common.Hashes{ - blocks[0].Hash, blocks[1].Hash, blocks[3].Hash}) - s.Require().NoError(bc.addRandomness(s.newRandomnessFromBlock(blocks[0]))) - s.Require().Equal(bc.pendingBlocksWithoutRandomness(), common.Hashes{ - blocks[1].Hash, blocks[3].Hash}) -} - func (s *BlockChainTestSuite) TestLastXBlock() { initBlock := s.newRoundOneInitBlock() bc := s.newBlockChain(initBlock, 10) @@ -434,7 +330,6 @@ func (s *BlockChainTestSuite) TestLastXBlock() { s.Require().NoError(bc.addBlock(blocks[0])) s.Require().True(bc.lastPendingBlock() == blocks[0]) s.Require().True(bc.lastDeliveredBlock() == initBlock) - s.Require().NoError(bc.addRandomness(s.newRandomnessFromBlock(blocks[0]))) s.Require().Len(bc.extractBlocks(), 1) s.Require().Nil(bc.lastPendingBlock()) s.Require().True(bc.lastDeliveredBlock() == blocks[0]) @@ -498,7 +393,7 @@ func (s *BlockChainTestSuite) TestAddEmptyBlockDirectly() { s.Require().NoError(err) // prepare a normal block. pos = types.Position{Height: 3} - b3, err := bc.proposeBlock(pos, emptyB2.Timestamp.Add(s.blockInterval)) + b3, err := bc.proposeBlock(pos, emptyB2.Timestamp.Add(s.blockInterval), false) s.Require().NotNil(b3) s.Require().NoError(err) // Add an empty block far away from current tip. @@ -525,31 +420,6 @@ func (s *BlockChainTestSuite) TestAddEmptyBlockDirectly() { s.Require().NotNil(rec.block) } -func (s *BlockChainTestSuite) TestShouldAddRandomness() { - initBlock := s.newRoundOneInitBlock() - bc := s.newBlockChain(initBlock, 10) - blocks := s.newBlocks(2, initBlock) - b0, b1 := blocks[0], blocks[1] - r0 := s.newRandomnessFromBlock(b0) - r1 := s.newRandomnessFromBlock(b1) - - // If a block is extracted, the randomness should not be added. - s.Require().NoError(bc.addBlock(b0)) - s.True(bc.shouldAddRandomness(r0)) - s.Require().NoError(bc.addRandomness(r0)) - s.False(bc.shouldAddRandomness(r0)) - s.Require().Len(bc.extractBlocks(), 1) - s.Require().Equal(b0.Hash, bc.lastDelivered.Hash) - - // If a block has already have randomness, it should not be added. - s.True(bc.shouldAddRandomness(r1)) - s.Require().NoError(bc.addRandomness(r1)) - s.Require().Len(bc.pendingRandomnesses, 1) - s.False(bc.shouldAddRandomness(r1)) - s.Require().NoError(bc.addBlock(b1)) - s.False(bc.shouldAddRandomness(r1)) -} - func TestBlockChain(t *testing.T) { suite.Run(t, new(BlockChainTestSuite)) } diff --git a/core/configuration-chain.go b/core/configuration-chain.go index 48b0f2a..92b2830 100644 --- a/core/configuration-chain.go +++ b/core/configuration-chain.go @@ -76,7 +76,7 @@ type configurationChain struct { tsigReady *sync.Cond cache *utils.NodeSetCache db db.Database - dkgSet map[types.NodeID]struct{} + notarySet map[types.NodeID]struct{} mpkReady bool pendingPrvShare map[types.NodeID]*typesDKG.PrivateShare // TODO(jimmy-dexon): add timeout to pending psig. @@ -194,12 +194,12 @@ func (cc *configurationChain) registerDKG( }) } } - dkgSet, err := cc.cache.GetDKGSet(round) + notarySet, err := cc.cache.GetNotarySet(round) if err != nil { - cc.logger.Error("Error getting DKG set from cache", "error", err) + cc.logger.Error("Error getting notary set from cache", "error", err) return } - cc.dkgSet = dkgSet + cc.notarySet = notarySet cc.pendingPrvShare = make(map[types.NodeID]*typesDKG.PrivateShare) cc.mpkReady = false cc.dkg, err = recoverDKGProtocol(cc.ID, cc.recv, round, reset, cc.db) @@ -479,7 +479,7 @@ func (cc *configurationChain) runDKG(round uint64, reset uint64) (err error) { cc.dkgRunning = false }() // Check if corresponding DKG signer is ready. - if _, _, err = cc.getDKGInfo(round); err == nil { + if _, _, err = cc.getDKGInfo(round, true); err == nil { return ErrSkipButNoError } tickStartAt := 1 @@ -518,12 +518,13 @@ func (cc *configurationChain) isDKGFinal(round uint64) bool { if !cc.gov.IsDKGFinal(round) { return false } - _, _, err := cc.getDKGInfo(round) + _, _, err := cc.getDKGInfo(round, false) return err == nil } func (cc *configurationChain) getDKGInfo( - round uint64) (*typesDKG.NodePublicKeys, *dkgShareSecret, error) { + round uint64, ignoreSigner bool) ( + *typesDKG.NodePublicKeys, *dkgShareSecret, error) { getFromCache := func() (*typesDKG.NodePublicKeys, *dkgShareSecret) { cc.dkgResult.RLock() defer cc.dkgResult.RUnlock() @@ -532,19 +533,20 @@ func (cc *configurationChain) getDKGInfo( return npks, signer } npks, signer := getFromCache() - if npks == nil || signer == nil { - if err := cc.recoverDKGInfo(round); err != nil { + if npks == nil || (!ignoreSigner && signer == nil) { + if err := cc.recoverDKGInfo(round, ignoreSigner); err != nil { return nil, nil, err } npks, signer = getFromCache() } - if npks == nil || signer == nil { + if npks == nil || (!ignoreSigner && signer == nil) { return nil, nil, ErrDKGNotReady } return npks, signer, nil } -func (cc *configurationChain) recoverDKGInfo(round uint64) error { +func (cc *configurationChain) recoverDKGInfo( + round uint64, ignoreSigner bool) error { var npksExists, signerExists bool func() { cc.dkgResult.Lock() @@ -582,7 +584,7 @@ func (cc *configurationChain) recoverDKGInfo(round uint64) error { cc.npks[round] = npks }() } - if !signerExists { + if !signerExists && !ignoreSigner { // Check if we have private shares in DB. prvKey, err := cc.db.GetDKGPrivateKey(round) if err != nil { @@ -603,7 +605,7 @@ func (cc *configurationChain) recoverDKGInfo(round uint64) error { func (cc *configurationChain) preparePartialSignature( round uint64, hash common.Hash) (*typesDKG.PartialSignature, error) { - _, signer, _ := cc.getDKGInfo(round) + _, signer, _ := cc.getDKGInfo(round, false) if signer == nil { return nil, ErrDKGNotReady } @@ -632,7 +634,7 @@ func (cc *configurationChain) untouchTSigHash(hash common.Hash) { func (cc *configurationChain) runTSig( round uint64, hash common.Hash) ( crypto.Signature, error) { - npks, _, _ := cc.getDKGInfo(round) + npks, _, _ := cc.getDKGInfo(round, false) if npks == nil { return crypto.Signature{}, ErrDKGNotReady } @@ -697,7 +699,7 @@ func (cc *configurationChain) processPrivateShare( if cc.dkg == nil { return nil } - if _, exist := cc.dkgSet[prvShare.ProposerID]; !exist { + if _, exist := cc.notarySet[prvShare.ProposerID]; !exist { return ErrNotDKGParticipant } if !cc.mpkReady { diff --git a/core/configuration-chain_test.go b/core/configuration-chain_test.go index af7e36d..a4c6e2a 100644 --- a/core/configuration-chain_test.go +++ b/core/configuration-chain_test.go @@ -430,10 +430,17 @@ func (s *ConfigurationChainTestSuite) TestDKGComplaintDelayAdd() { errs <- cc.runDKG(round, reset) }(cc) } + complaints := -1 go func() { // Node 0 proposes NackComplaint to all others at 3λ but they should - // be ignored because NackComplaint shoould be proposed before 2λ. + // be ignored because NackComplaint should be proposed before 2λ. time.Sleep(lambdaDKG * 3) + for _, gov := range recv.govs { + if complaints == -1 { + complaints = len(gov.DKGComplaints(round)) + } + s.Require().Len(gov.DKGComplaints(round), complaints) + } nID := s.nIDs[0] for _, targetNode := range s.nIDs { if targetNode == nID { @@ -449,15 +456,19 @@ func (s *ConfigurationChainTestSuite) TestDKGComplaintDelayAdd() { } }() wg.Wait() + complaints += len(s.nIDs) - 1 + for _, gov := range recv.govs { + s.Require().Len(gov.DKGComplaints(round), complaints) + } for range cfgChains { s.Require().NoError(<-errs) } for nID, cc := range cfgChains { if _, exist := cc.npks[round]; !exist { - s.FailNow("Should be qualifyied") + s.FailNow("Should be qualified") } if _, exist := cc.npks[round].QualifyNodeIDs[nID]; !exist { - s.FailNow("Should be qualifyied") + s.FailNow("Should be qualified") } } } diff --git a/core/consensus.go b/core/consensus.go index d74a4a2..2b0d5a4 100644 --- a/core/consensus.go +++ b/core/consensus.go @@ -27,6 +27,7 @@ import ( "github.com/dexon-foundation/dexon-consensus/common" "github.com/dexon-foundation/dexon-consensus/core/crypto" + cryptoDKG "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" "github.com/dexon-foundation/dexon-consensus/core/db" "github.com/dexon-foundation/dexon-consensus/core/types" typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" @@ -51,6 +52,8 @@ var ( "CRS not ready") ErrConfigurationNotReady = fmt.Errorf( "Configuration not ready") + ErrIncorrectBlockRandomness = fmt.Errorf( + "randomness of block is incorrect") ) // consensusBAReceiver implements agreementReceiver. @@ -62,6 +65,8 @@ type consensusBAReceiver struct { roundValue *atomic.Value isNotary bool restartNotary chan types.Position + npks *typesDKG.NodePublicKeys + psigSigner *dkgShareSecret } func (recv *consensusBAReceiver) round() uint64 { @@ -72,10 +77,51 @@ func (recv *consensusBAReceiver) changeNotaryHeight() uint64 { return recv.changeNotaryHeightValue.Load().(uint64) } +func (recv *consensusBAReceiver) VerifyPartialSignature(vote *types.Vote) bool { + if recv.round() >= DKGDelayRound && vote.BlockHash != types.SkipBlockHash { + if vote.Type == types.VoteCom || vote.Type == types.VoteFastCom { + if recv.npks == nil || recv.npks.Round != vote.Position.Round { + var err error + recv.npks, _, err = + recv.consensus.cfgModule.getDKGInfo(vote.Position.Round, true) + if err != nil || recv.npks == nil { + recv.consensus.logger.Warn("cannot get npks", + "round", vote.Position.Round, "error", err) + return false + } + } + pubKey, exist := recv.npks.PublicKeys[vote.ProposerID] + if !exist { + return false + } + blockHash := vote.BlockHash + if blockHash == types.NullBlockHash { + blockHash = utils.HashPosition(vote.Position) + } + return pubKey.VerifySignature( + vote.BlockHash, crypto.Signature(vote.PartialSignature)) + } + } + return len(vote.PartialSignature.Signature) == 0 +} + func (recv *consensusBAReceiver) ProposeVote(vote *types.Vote) { if !recv.isNotary { return } + if recv.round() >= DKGDelayRound && vote.BlockHash != types.SkipBlockHash { + if vote.Type == types.VoteCom || vote.Type == types.VoteFastCom { + if recv.psigSigner == nil { + return + } + if vote.BlockHash == types.NullBlockHash { + vote.PartialSignature = recv.psigSigner.sign( + utils.HashPosition(vote.Position)) + } else { + vote.PartialSignature = recv.psigSigner.sign(vote.BlockHash) + } + } + } if err := recv.agreementModule.prepareVote(vote); err != nil { recv.consensus.logger.Error("Failed to prepare vote", "error", err) return @@ -120,6 +166,7 @@ func (recv *consensusBAReceiver) ConfirmBlock( block *types.Block aID = recv.agreementModule.agreementID() ) + isEmptyBlockConfirmed := hash == common.Hash{} if isEmptyBlockConfirmed { recv.consensus.logger.Info("Empty block is confirmed", "position", aID) @@ -177,6 +224,47 @@ func (recv *consensusBAReceiver) ConfirmBlock( return } } + + voteList := make([]types.Vote, 0, len(votes)) + IDs := make(cryptoDKG.IDs, 0, len(votes)) + psigs := make([]cryptoDKG.PartialSignature, 0, len(votes)) + for _, vote := range votes { + if vote.BlockHash != hash { + continue + } + if recv.round() >= DKGDelayRound { + ID, exist := recv.npks.IDMap[vote.ProposerID] + if !exist { + continue + } + IDs = append(IDs, ID) + psigs = append(psigs, vote.PartialSignature) + } + voteList = append(voteList, *vote) + } + if recv.round() >= DKGDelayRound { + rand, err := cryptoDKG.RecoverSignature(psigs, IDs) + if err != nil { + recv.consensus.logger.Warn("Unable to recover randomness", + "block", block, + "error", err) + } else { + block.Finalization.Randomness = rand.Signature[:] + } + } + if recv.isNotary { + result := &types.AgreementResult{ + BlockHash: block.Hash, + Position: block.Position, + Votes: voteList, + Randomness: block.Finalization.Randomness, + IsEmptyBlock: isEmptyBlockConfirmed, + } + recv.consensus.logger.Debug("Propose AgreementResult", + "result", result) + recv.consensus.msgChan <- result + } + if block.Position.Height != 0 && !recv.consensus.bcModule.confirmed(block.Position.Height-1) { go func(hash common.Hash) { @@ -222,25 +310,9 @@ func (recv *consensusBAReceiver) ConfirmBlock( } }(block.ParentHash) } - if recv.isNotary { - voteList := make([]types.Vote, 0, len(votes)) - for _, vote := range votes { - if vote.BlockHash != hash { - continue - } - voteList = append(voteList, *vote) - } - result := &types.AgreementResult{ - BlockHash: block.Hash, - Position: block.Position, - Votes: voteList, - IsEmptyBlock: isEmptyBlockConfirmed, - } - recv.consensus.logger.Debug("Propose AgreementResult", - "result", result) - recv.consensus.network.BroadcastAgreementResult(result) + if !block.IsEmpty() { + recv.consensus.processBlockChan <- block } - recv.consensus.processBlockChan <- block // Clean the restartNotary channel so BA will not stuck by deadlock. CleanChannelLoop: for { @@ -253,7 +325,7 @@ CleanChannelLoop: newPos := block.Position if block.Position.Height+1 == recv.changeNotaryHeight() { newPos.Round++ - recv.roundValue.Store(newPos.Round) + recv.updateRound(newPos.Round) } currentRound := recv.round() changeNotaryHeight := recv.changeNotaryHeight() @@ -282,6 +354,18 @@ func (recv *consensusBAReceiver) ReportForkBlock(b1, b2 *types.Block) { recv.consensus.gov.ReportForkBlock(b1, b2) } +func (recv *consensusBAReceiver) updateRound(round uint64) { + recv.roundValue.Store(round) + var err error + _, recv.psigSigner, err = + recv.consensus.cfgModule.getDKGInfo(round, false) + if err != nil { + recv.consensus.logger.Warn("cannot get dkg info", + "round", round, "error", err) + recv.psigSigner = nil + } +} + // consensusDKGReceiver implements dkgReceiver. type consensusDKGReceiver struct { ID types.NodeID @@ -401,13 +485,13 @@ type Consensus struct { bcModule *blockChain dMoment time.Time nodeSetCache *utils.NodeSetCache + tsigVerifierCache *TSigVerifierCache lock sync.RWMutex ctx context.Context ctxCancel context.CancelFunc event *common.Event roundEvent *utils.RoundEvent logger common.Logger - resetRandomnessTicker chan struct{} resetDeliveryGuardTicker chan struct{} msgChan chan interface{} waitGroup sync.WaitGroup @@ -465,7 +549,6 @@ func NewConsensusFromSyncer( networkModule Network, prv crypto.PrivateKey, confirmedBlocks []*types.Block, - randomnessResults []*types.BlockRandomnessResult, cachedMessages []interface{}, logger common.Logger) (*Consensus, error) { // Setup Consensus instance. @@ -492,30 +575,13 @@ func NewConsensusFromSyncer( } refBlock = b } - // Dump all randomness result to the consensus instance. - for _, r := range randomnessResults { - if err := con.ProcessBlockRandomnessResult(r, false); err != nil { - con.logger.Error("failed to process randomness result when syncing", - "result", r) - continue - } - } if startWithEmpty { pos := initBlock.Position pos.Height++ - block, err := con.bcModule.addEmptyBlock(pos) + _, err := con.bcModule.addEmptyBlock(pos) if err != nil { panic(err) } - con.processBlockChan <- block - if pos.Round >= DKGDelayRound { - rand := &types.AgreementResult{ - BlockHash: block.Hash, - Position: block.Position, - IsEmptyBlock: true, - } - go con.prepareRandomnessResult(rand) - } } return con, nil } @@ -566,8 +632,9 @@ func newConsensusForRound( if usingNonBlocking { appModule = newNonBlocking(app, debugApp) } + tsigVerifierCache := NewTSigVerifierCache(gov, 7) bcModule := newBlockChain(ID, dMoment, initBlock, appModule, - NewTSigVerifierCache(gov, 7), signer, logger) + tsigVerifierCache, signer, logger) // Construct Consensus instance. con := &Consensus{ ID: ID, @@ -582,10 +649,10 @@ func newConsensusForRound( bcModule: bcModule, dMoment: dMoment, nodeSetCache: nodeSetCache, + tsigVerifierCache: tsigVerifierCache, signer: signer, event: common.NewEvent(), logger: logger, - resetRandomnessTicker: make(chan struct{}), resetDeliveryGuardTicker: make(chan struct{}), msgChan: make(chan interface{}, 1024), processBlockChan: make(chan *types.Block, 1024), @@ -690,14 +757,14 @@ func (con *Consensus) prepare(initBlock *types.Block) (err error) { if nextRound < DKGDelayRound { return } - curDKGSet, err := con.nodeSetCache.GetDKGSet(e.Round) + curNotarySet, err := con.nodeSetCache.GetNotarySet(e.Round) if err != nil { - con.logger.Error("Error getting DKG set when proposing CRS", + con.logger.Error("Error getting notary set when proposing CRS", "round", e.Round, "error", err) return } - if _, exist := curDKGSet[con.ID]; !exist { + if _, exist := curNotarySet[con.ID]; !exist { return } isDKGValid := func() bool { @@ -733,18 +800,18 @@ func (con *Consensus) prepare(initBlock *types.Block) (err error) { // Register round event handler to propose new CRS. con.roundEvent.Register(func(evts []utils.RoundEventParam) { // We don't have to propose new CRS during DKG reset, the reset of DKG - // would be done by the DKG set in previous round. + // would be done by the notary set in previous round. e := evts[len(evts)-1] defer elapse("propose-CRS", e)() if e.Reset != 0 || e.Round < DKGDelayRound { return } - if curDkgSet, err := con.nodeSetCache.GetDKGSet(e.Round); err != nil { - con.logger.Error("Error getting DKG set when proposing CRS", + if curNotarySet, err := con.nodeSetCache.GetNotarySet(e.Round); err != nil { + con.logger.Error("Error getting notary set when proposing CRS", "round", e.Round, "error", err) } else { - if _, exist := curDkgSet[con.ID]; !exist { + if _, exist := curNotarySet[con.ID]; !exist { return } con.event.RegisterHeight(e.NextCRSProposingHeight(), func(uint64) { @@ -809,26 +876,26 @@ func (con *Consensus) prepare(initBlock *types.Block) (err error) { // of unexpected network fluctuation and ensure the robustness. if !checkWithCancel( con.ctx, 500*time.Millisecond, checkCRS(nextRound)) { - con.logger.Debug("unable to prepare CRS for DKG set", + con.logger.Debug("unable to prepare CRS for notary set", "round", nextRound, "reset", e.Reset) return } - nextDkgSet, err := con.nodeSetCache.GetDKGSet(nextRound) + nextNotarySet, err := con.nodeSetCache.GetNotarySet(nextRound) if err != nil { - con.logger.Error("Error getting DKG set for next round", + con.logger.Error("Error getting notary set for next round", "round", nextRound, "reset", e.Reset, "error", err) return } - if _, exist := nextDkgSet[con.ID]; !exist { - con.logger.Info("Not selected as DKG set", + if _, exist := nextNotarySet[con.ID]; !exist { + con.logger.Info("Not selected as notary set", "round", nextRound, "reset", e.Reset) return } - con.logger.Info("Selected as DKG set", + con.logger.Info("Selected as notary set", "round", nextRound, "reset", e.Reset) nextConfig := utils.GetConfigWithPanic(con.gov, nextRound, @@ -865,12 +932,6 @@ func (con *Consensus) Run() { con.waitGroup.Add(1) go con.processMsg() go con.processBlockLoop() - // Sleep until dMoment come. - time.Sleep(con.dMoment.Sub(time.Now().UTC())) - // Take some time to bootstrap. - time.Sleep(3 * time.Second) - con.waitGroup.Add(1) - go con.pullRandomness() // Stop dummy receiver if launched. if con.dummyCancel != nil { con.logger.Trace("Stop dummy receiver") @@ -893,6 +954,10 @@ func (con *Consensus) Run() { } con.logger.Trace("Finish dumping cached messages") } + // Sleep until dMoment come. + time.Sleep(con.dMoment.Sub(time.Now().UTC())) + // Take some time to bootstrap. + time.Sleep(3 * time.Second) con.waitGroup.Add(1) go con.deliveryGuard() // Block until done. @@ -964,7 +1029,6 @@ func (con *Consensus) Stop() { con.event.Reset() con.waitGroup.Wait() if nbApp, ok := con.app.(*nonBlocking); ok { - fmt.Println("Stopping nonBlocking App") nbApp.wait() } } @@ -1019,11 +1083,47 @@ MessageLoop: ch, e := con.baConfirmedBlock[val.Hash] return ch, e }(); exist { - if err := utils.VerifyBlockSignature(val); err != nil { - con.logger.Error("VerifyBlockSignature failed", - "block", val, - "error", err) - continue MessageLoop + if val.IsEmpty() { + hash, err := utils.HashBlock(val) + if err != nil { + con.logger.Error("error verifying empty block hash", + "block", val, + "error, err") + continue MessageLoop + } + if hash != val.Hash { + con.logger.Error("incorrect confirmed empty block hash", + "block", val, + "hash", hash) + continue MessageLoop + } + if _, err := con.bcModule.proposeBlock( + val.Position, time.Time{}, true); err != nil { + con.logger.Error("error adding empty block", + "block", val, + "error", err) + continue MessageLoop + } + } else { + ok, err := con.bcModule.verifyRandomness( + val.Hash, val.Position.Round, val.Finalization.Randomness) + if err != nil { + con.logger.Error("error verifying confirmed block randomness", + "block", val, + "error", err) + continue MessageLoop + } + if !ok { + con.logger.Error("incorrect confirmed block randomness", + "block", val) + continue MessageLoop + } + if err := utils.VerifyBlockSignature(val); err != nil { + con.logger.Error("VerifyBlockSignature failed", + "block", val, + "error", err) + continue MessageLoop + } } func() { con.lock.Lock() @@ -1035,13 +1135,6 @@ MessageLoop: delete(con.baConfirmedBlock, val.Hash) ch <- val }() - } else if val.IsFinalized() { - // For sync mode. - if err := con.processFinalizedBlock(val); err != nil { - con.logger.Error("Failed to process finalized block", - "block", val, - "error", err) - } } else { if err := con.preProcessBlock(val); err != nil { con.logger.Error("Failed to pre process block", @@ -1061,13 +1154,6 @@ MessageLoop: "result", val, "error", err) } - case *types.BlockRandomnessResult: - if err := con.ProcessBlockRandomnessResult(val, true); err != nil { - con.logger.Error("Failed to process block randomness result", - "hash", val.BlockHash.String()[:6], - "position", val.Position, - "error", err) - } case *typesDKG.PrivateShare: if err := con.cfgModule.processPrivateShare(val); err != nil { con.logger.Error("Failed to process private share", @@ -1096,6 +1182,15 @@ func (con *Consensus) ProcessAgreementResult( if !con.baMgr.touchAgreementResult(rand) { return nil } + // TODO(jimmy): merge tsig check to VerifyAgreementResult + ok, err := con.bcModule.verifyRandomness( + rand.BlockHash, rand.Position.Round, rand.Randomness) + if err != nil { + return err + } + if !ok { + return ErrIncorrectBlockRandomness + } // Sanity Check. if err := VerifyAgreementResult(rand, con.nodeSetCache); err != nil { con.baMgr.untouchAgreementResult(rand) @@ -1105,96 +1200,11 @@ func (con *Consensus) ProcessAgreementResult( if err := con.baMgr.processAgreementResult(rand); err != nil { return err } - // Calculating randomness. - if rand.Position.Round == 0 { - return nil - } - // TODO(mission): find a way to avoid spamming by older agreement results. - // Sanity check done. - if !con.cfgModule.touchTSigHash(rand.BlockHash) { - return nil - } - con.logger.Debug("Rebroadcast AgreementResult", + con.logger.Debug("Broadcast AgreementResult", "result", rand) con.network.BroadcastAgreementResult(rand) - go con.prepareRandomnessResult(rand) - return nil -} -func (con *Consensus) prepareRandomnessResult(rand *types.AgreementResult) { - dkgSet, err := con.nodeSetCache.GetDKGSet(rand.Position.Round) - if err != nil { - con.logger.Error("Failed to get dkg set", - "round", rand.Position.Round, "error", err) - return - } - if _, exist := dkgSet[con.ID]; !exist { - return - } - con.logger.Debug("PrepareRandomness", "round", rand.Position.Round, "hash", rand.BlockHash) - psig, err := con.cfgModule.preparePartialSignature(rand.Position.Round, rand.BlockHash) - if err != nil { - con.logger.Error("Failed to prepare psig", - "round", rand.Position.Round, - "hash", rand.BlockHash.String()[:6], - "error", err) - return - } - if err = con.signer.SignDKGPartialSignature(psig); err != nil { - con.logger.Error("Failed to sign psig", - "hash", rand.BlockHash.String()[:6], - "error", err) - return - } - if err = con.cfgModule.processPartialSignature(psig); err != nil { - con.logger.Error("Failed process psig", - "hash", rand.BlockHash.String()[:6], - "error", err) - return - } - con.logger.Debug("Calling Network.BroadcastDKGPartialSignature", - "proposer", psig.ProposerID, - "round", psig.Round, - "hash", psig.Hash.String()[:6]) - con.network.BroadcastDKGPartialSignature(psig) - tsig, err := con.cfgModule.runTSig(rand.Position.Round, rand.BlockHash) - if err != nil { - if err != ErrTSigAlreadyRunning { - con.logger.Error("Failed to run TSIG", - "position", rand.Position, - "hash", rand.BlockHash.String()[:6], - "error", err) - } - return - } - result := &types.BlockRandomnessResult{ - BlockHash: rand.BlockHash, - Position: rand.Position, - Randomness: tsig.Signature, - } - // ProcessBlockRandomnessResult is not thread-safe so we put the result in - // the message channnel to be processed in the main thread. - con.msgChan <- result -} - -// ProcessBlockRandomnessResult processes the randomness result. -func (con *Consensus) ProcessBlockRandomnessResult( - rand *types.BlockRandomnessResult, needBroadcast bool) error { - if rand.Position.Round == 0 { - return nil - } - if !con.bcModule.shouldAddRandomness(rand) { - return nil - } - if err := con.bcModule.addRandomness(rand); err != nil { - return err - } - if needBroadcast { - con.logger.Debug("Calling Network.BroadcastRandomnessResult", - "randomness", rand) - con.network.BroadcastRandomnessResult(rand) - } return con.deliverFinalizedBlocks() } @@ -1207,33 +1217,12 @@ func (con *Consensus) preProcessBlock(b *types.Block) (err error) { return } -func (con *Consensus) pullRandomness() { - defer con.waitGroup.Done() - for { - select { - case <-con.ctx.Done(): - return - default: - } - select { - case <-con.ctx.Done(): - return - case <-con.resetRandomnessTicker: - case <-time.After(1500 * time.Millisecond): - // TODO(jimmy): pulling period should be related to lambdaBA. - hashes := con.bcModule.pendingBlocksWithoutRandomness() - if len(hashes) > 0 { - con.logger.Debug( - "Calling Network.PullRandomness", "blocks", hashes) - con.network.PullRandomness(hashes) - } - } - } -} - func (con *Consensus) deliveryGuard() { defer con.waitGroup.Done() - time.Sleep(con.dMoment.Sub(time.Now())) + select { + case <-con.ctx.Done(): + case <-time.After(con.dMoment.Sub(time.Now())): + } // Node takes time to start. select { case <-con.ctx.Done(): @@ -1258,10 +1247,6 @@ func (con *Consensus) deliveryGuard() { // deliverBlock deliver a block to application layer. func (con *Consensus) deliverBlock(b *types.Block) { - select { - case con.resetRandomnessTicker <- struct{}{}: - default: - } select { case con.resetDeliveryGuardTicker <- struct{}{}: default: @@ -1274,7 +1259,6 @@ func (con *Consensus) deliverBlock(b *types.Block) { b.Hash, b.Finalization.Height); err != nil { panic(err) } - con.cfgModule.untouchTSigHash(b.Hash) con.logger.Debug("Calling Application.BlockDelivered", "block", b) con.app.BlockDelivered(b.Hash, b.Position, b.Finalization.Clone()) if con.debugApp != nil { @@ -1338,15 +1322,10 @@ func (con *Consensus) processBlock(block *types.Block) (err error) { return } -// processFinalizedBlock is the entry point for handling finalized blocks. -func (con *Consensus) processFinalizedBlock(block *types.Block) error { - return con.bcModule.processFinalizedBlock(block) -} - // PrepareBlock would setup header fields of block based on its ProposerID. func (con *Consensus) proposeBlock(position types.Position) ( *types.Block, error) { - b, err := con.bcModule.proposeBlock(position, time.Now().UTC()) + b, err := con.bcModule.proposeBlock(position, time.Now().UTC(), false) if err != nil { return nil, err } diff --git a/core/consensus_test.go b/core/consensus_test.go index 8744c00..9565e95 100644 --- a/core/consensus_test.go +++ b/core/consensus_test.go @@ -67,12 +67,6 @@ func (n *network) BroadcastAgreementResult( n.conn.broadcast(n.nID, randRequest) } -// BroadcastRandomnessResult broadcasts rand request to Notary set. -func (n *network) BroadcastRandomnessResult( - randResult *types.BlockRandomnessResult) { - n.conn.broadcast(n.nID, randResult) -} - // SendDKGPrivateShare sends PrivateShare to a DKG participant. func (n *network) SendDKGPrivateShare( recv crypto.PublicKey, prvShare *typesDKG.PrivateShare) { @@ -158,8 +152,6 @@ func (nc *networkConnection) setCon(nID types.NodeID, con *Consensus) { err = con.ProcessVote(val) case *types.AgreementResult: err = con.ProcessAgreementResult(val) - case *types.BlockRandomnessResult: - err = con.ProcessBlockRandomnessResult(val, true) case *typesDKG.PrivateShare: err = con.cfgModule.processPrivateShare(val) case *typesDKG.PartialSignature: @@ -236,10 +228,14 @@ func (s *ConsensusTestSuite) TestRegisteredDKGRecover() { s.Require().Nil(con.cfgModule.dkg) con.cfgModule.registerDKG(con.ctx, 0, 0, 10) + con.cfgModule.dkgLock.Lock() + defer con.cfgModule.dkgLock.Unlock() _, newCon := s.prepareConsensusWithDB(dMoment, gov, prvKeys[0], conn, dbInst) newCon.cfgModule.registerDKG(newCon.ctx, 0, 0, 10) + newCon.cfgModule.dkgLock.Lock() + defer newCon.cfgModule.dkgLock.Unlock() s.Require().NotNil(newCon.cfgModule.dkg) s.Require().True(newCon.cfgModule.dkg.prvShares.Equal(con.cfgModule.dkg.prvShares)) @@ -377,7 +373,6 @@ func (s *ConsensusTestSuite) TestInitialHeightEventTriggered() { network, prvKey, []*types.Block(nil), - []*types.BlockRandomnessResult(nil), []interface{}(nil), &common.NullLogger{}, ) diff --git a/core/interfaces.go b/core/interfaces.go index 06838e0..407eaea 100644 --- a/core/interfaces.go +++ b/core/interfaces.go @@ -64,9 +64,6 @@ type Network interface { // PullVotes tries to pull votes from the DEXON network. PullVotes(position types.Position) - // PullRandomness tries to pull randomness from the DEXON network. - PullRandomness(hashes common.Hashes) - // BroadcastVote broadcasts vote to all nodes in DEXON network. BroadcastVote(vote *types.Vote) @@ -76,9 +73,6 @@ type Network interface { // BroadcastAgreementResult broadcasts agreement result to DKG set. BroadcastAgreementResult(randRequest *types.AgreementResult) - // BroadcastRandomnessResult broadcasts rand request to Notary set. - BroadcastRandomnessResult(randResult *types.BlockRandomnessResult) - // SendDKGPrivateShare sends PrivateShare to a DKG participant. SendDKGPrivateShare(pub crypto.PublicKey, prvShare *typesDKG.PrivateShare) diff --git a/core/syncer/consensus.go b/core/syncer/consensus.go index 24c781a..65068a4 100644 --- a/core/syncer/consensus.go +++ b/core/syncer/consensus.go @@ -63,7 +63,6 @@ type Consensus struct { nodeSetCache *utils.NodeSetCache tsigVerifier *core.TSigVerifierCache - randomnessResults map[common.Hash]*types.BlockRandomnessResult blocks types.BlocksByPosition agreementModule *agreement agreementRoundCut uint64 @@ -100,19 +99,18 @@ func NewConsensus( logger common.Logger) *Consensus { con := &Consensus{ - dMoment: dMoment, - app: app, - gov: gov, - db: db, - network: network, - nodeSetCache: utils.NewNodeSetCache(gov), - tsigVerifier: core.NewTSigVerifierCache(gov, 7), - prv: prv, - logger: logger, - receiveChan: make(chan *types.Block, 1000), - pullChan: make(chan common.Hash, 1000), - randomnessResults: make(map[common.Hash]*types.BlockRandomnessResult), - heightEvt: common.NewEvent(), + dMoment: dMoment, + app: app, + gov: gov, + db: db, + network: network, + nodeSetCache: utils.NewNodeSetCache(gov), + tsigVerifier: core.NewTSigVerifierCache(gov, 7), + prv: prv, + logger: logger, + receiveChan: make(chan *types.Block, 1000), + pullChan: make(chan common.Hash, 1000), + heightEvt: common.NewEvent(), } con.ctx, con.ctxCancel = context.WithCancel(context.Background()) _, con.initChainTipHeight = db.GetCompactionChainTipInfo() @@ -360,10 +358,6 @@ func (con *Consensus) GetSyncedConsensus() (*core.Consensus, error) { } // flush all blocks in con.blocks into core.Consensus, and build // core.Consensus from syncer. - randomnessResults := []*types.BlockRandomnessResult{} - for _, r := range con.randomnessResults { - randomnessResults = append(randomnessResults, r) - } con.dummyCancel() <-con.dummyFinished var err error @@ -377,7 +371,6 @@ func (con *Consensus) GetSyncedConsensus() (*core.Consensus, error) { con.network, con.prv, con.blocks, - randomnessResults, con.dummyMsgBuffer, con.logger) return con.syncedConsensus, err @@ -475,55 +468,6 @@ func (con *Consensus) startAgreement() { }() } -func (con *Consensus) cacheRandomnessResult(r *types.BlockRandomnessResult) { - // There is no block randomness at round-0. - if r.Position.Round == 0 { - return - } - // We only have to cache randomness result after cutting round. - if func() bool { - con.lock.RLock() - defer con.lock.RUnlock() - if len(con.blocks) > 0 && r.Position.Older(con.blocks[0].Position) { - return true - } - if r.Position.Round > con.latestCRSRound { - // We can't process randomness from rounds that its CRS is still - // unknown. - return true - } - _, exists := con.randomnessResults[r.BlockHash] - return exists - }() { - return - } - v, ok, err := con.tsigVerifier.UpdateAndGet(r.Position.Round) - if err != nil { - con.logger.Error("Unable to get tsig verifier", - "hash", r.BlockHash.String()[:6], - "position", r.Position, - "error", err, - ) - return - } - if !ok { - con.logger.Error("Tsig is not ready", "position", &r.Position) - return - } - if !v.VerifySignature(r.BlockHash, crypto.Signature{ - Type: "bls", - Signature: r.Randomness}) { - con.logger.Info("Block randomness is not valid", - "position", r.Position, - "hash", r.BlockHash.String()[:6], - ) - return - } - con.lock.Lock() - defer con.lock.Unlock() - con.randomnessResults[r.BlockHash] = r -} - // startNetwork starts network for receiving blocks and agreement results. func (con *Consensus) startNetwork() { con.waitGroup.Add(1) @@ -542,9 +486,6 @@ func (con *Consensus) startNetwork() { if v.Position.Height <= con.initChainTipHeight { continue loop } - case *types.BlockRandomnessResult: - con.cacheRandomnessResult(v) - continue loop default: continue loop } diff --git a/core/test/governance.go b/core/test/governance.go index e256504..538d064 100644 --- a/core/test/governance.go +++ b/core/test/governance.go @@ -231,7 +231,7 @@ func (g *Governance) IsDKGMPKReady(round uint64) bool { if round >= uint64(len(g.configs)) { return false } - return g.stateModule.IsDKGMPKReady(round, int(g.configs[round].DKGSetSize)/3*2) + return g.stateModule.IsDKGMPKReady(round, int(g.configs[round].NotarySetSize)/3*2) } // AddDKGFinalize adds a DKG finalize message. @@ -259,7 +259,7 @@ func (g *Governance) IsDKGFinal(round uint64) bool { if round >= uint64(len(g.configs)) { return false } - return g.stateModule.IsDKGFinal(round, int(g.configs[round].DKGSetSize)/3*2) + return g.stateModule.IsDKGFinal(round, int(g.configs[round].NotarySetSize)/3*2) } // ReportForkVote reports a node for forking votes. @@ -449,7 +449,7 @@ func (g *Governance) Equal(other *Governance, checkState bool) bool { // NOTE: this function should be called before running. func (g *Governance) RegisterConfigChange( round uint64, t StateChangeType, v interface{}) (err error) { - if t < StateAddCRS || t > StateChangeDKGSetSize { + if t < StateAddCRS || t > StateChangeNotarySetSize { return fmt.Errorf("state changes to register is not supported: %v", t) } if round < 2 { diff --git a/core/test/governance_test.go b/core/test/governance_test.go index b64f785..474ec80 100644 --- a/core/test/governance_test.go +++ b/core/test/governance_test.go @@ -92,16 +92,16 @@ func (s *GovernanceTestSuite) TestRegisterChange() { req.NoError(g.State().RequestChange(StateChangeRoundLength, uint64(roundLength))) // Unable to register change for genesis round. - req.Error(g.RegisterConfigChange(0, StateChangeDKGSetSize, uint32(32))) + req.Error(g.RegisterConfigChange(0, StateChangeNotarySetSize, uint32(32))) // Make some round prepared. g.CatchUpWithRound(4) - req.Equal(g.Configuration(4).DKGSetSize, uint32(20)) + req.Equal(g.Configuration(4).NotarySetSize, uint32(20)) // Unable to register change for prepared round. - req.Error(g.RegisterConfigChange(4, StateChangeDKGSetSize, uint32(32))) + req.Error(g.RegisterConfigChange(4, StateChangeNotarySetSize, uint32(32))) // It's ok to make some change when condition is met. - req.NoError(g.RegisterConfigChange(5, StateChangeDKGSetSize, uint32(32))) - req.NoError(g.RegisterConfigChange(6, StateChangeDKGSetSize, uint32(32))) - req.NoError(g.RegisterConfigChange(7, StateChangeDKGSetSize, uint32(40))) + req.NoError(g.RegisterConfigChange(5, StateChangeNotarySetSize, uint32(32))) + req.NoError(g.RegisterConfigChange(6, StateChangeNotarySetSize, uint32(32))) + req.NoError(g.RegisterConfigChange(7, StateChangeNotarySetSize, uint32(40))) // In local mode, state for round 6 would be ready after notified with // round 2. g.NotifyRound(2, roundLength*2) @@ -111,8 +111,8 @@ func (s *GovernanceTestSuite) TestRegisterChange() { g.NotifyRound(4, roundLength*4) // Notify governance to take a snapshot for round 7's configuration. g.NotifyRound(5, roundLength*5) - req.Equal(g.Configuration(6).DKGSetSize, uint32(32)) - req.Equal(g.Configuration(7).DKGSetSize, uint32(40)) + req.Equal(g.Configuration(6).NotarySetSize, uint32(32)) + req.Equal(g.Configuration(7).NotarySetSize, uint32(40)) } func (s *GovernanceTestSuite) TestProhibit() { diff --git a/core/test/marshaller.go b/core/test/marshaller.go index 5f15e11..91a3057 100644 --- a/core/test/marshaller.go +++ b/core/test/marshaller.go @@ -53,14 +53,8 @@ func (m *DefaultMarshaller) Unmarshal( break } msg = vote - case "block-randomness-request": - request := &types.AgreementResult{} - if err = json.Unmarshal(payload, request); err != nil { - break - } - msg = request - case "block-randomness-result": - result := &types.BlockRandomnessResult{} + case "agreement-result": + result := &types.AgreementResult{} if err = json.Unmarshal(payload, result); err != nil { break } @@ -128,10 +122,7 @@ func (m *DefaultMarshaller) Marshal( msgType = "vote" payload, err = json.Marshal(msg) case *types.AgreementResult: - msgType = "block-randomness-request" - payload, err = json.Marshal(msg) - case *types.BlockRandomnessResult: - msgType = "block-randomness-result" + msgType = "agreement-result" payload, err = json.Marshal(msg) case *typesDKG.PrivateShare: msgType = "dkg-private-share" diff --git a/core/test/network.go b/core/test/network.go index 443a26c..6034fa6 100644 --- a/core/test/network.go +++ b/core/test/network.go @@ -39,6 +39,9 @@ const ( maxPullingPeerCount = 3 maxBlockCache = 1000 maxVoteCache = 128 + + // Gossiping parameter. + gossipAgreementResultPercent = 33 ) // NetworkType is the simulation network type. @@ -77,8 +80,6 @@ func (req *PullRequest) MarshalJSON() (b []byte, err error) { idAsBytes, err = json.Marshal(req.Identity.(common.Hashes)) case "vote": idAsBytes, err = json.Marshal(req.Identity.(types.Position)) - case "randomness": - idAsBytes, err = json.Marshal(req.Identity.(common.Hashes)) default: err = fmt.Errorf("unknown ID type for pull request: %v", req.Type) } @@ -117,12 +118,6 @@ func (req *PullRequest) UnmarshalJSON(data []byte) (err error) { break } ID = pos - case "randomness": - hashes := common.Hashes{} - if err = json.Unmarshal(rawReq.Identity, &hashes); err != nil { - break - } - ID = hashes default: err = fmt.Errorf("unknown pull request type: %v", rawReq.Type) } @@ -137,38 +132,30 @@ func (req *PullRequest) UnmarshalJSON(data []byte) (err error) { // Network implements core.Network interface based on TransportClient. type Network struct { - ID types.NodeID - config NetworkConfig - ctx context.Context - ctxCancel context.CancelFunc - trans TransportClient - dMoment time.Time - fromTransport <-chan *TransportEnvelope - toConsensus chan interface{} - toNode chan interface{} - sentRandomnessLock sync.Mutex - sentRandomness map[common.Hash]struct{} - sentAgreementLock sync.Mutex - sentAgreement map[common.Hash]struct{} - blockCacheLock sync.RWMutex - blockCache map[common.Hash]*types.Block - voteCacheLock sync.RWMutex - voteCache map[types.Position]map[types.VoteHeader]*types.Vote - voteCacheSize int - votePositions []types.Position - randomnessCacheLock sync.RWMutex - randomnessCache map[common.Hash]*types.BlockRandomnessResult - stateModule *State - peers map[types.NodeID]struct{} - unreceivedBlocksLock sync.RWMutex - unreceivedBlocks map[common.Hash]chan<- common.Hash - unreceivedRandomnessLock sync.RWMutex - unreceivedRandomness map[common.Hash]chan<- common.Hash - cache *utils.NodeSetCache - notarySetCachesLock sync.Mutex - notarySetCaches map[uint64]map[types.NodeID]struct{} - dkgSetCachesLock sync.Mutex - dkgSetCaches map[uint64]map[types.NodeID]struct{} + ID types.NodeID + config NetworkConfig + ctx context.Context + ctxCancel context.CancelFunc + trans TransportClient + dMoment time.Time + fromTransport <-chan *TransportEnvelope + toConsensus chan interface{} + toNode chan interface{} + sentAgreementLock sync.Mutex + sentAgreement map[common.Hash]struct{} + blockCacheLock sync.RWMutex + blockCache map[common.Hash]*types.Block + voteCacheLock sync.RWMutex + voteCache map[types.Position]map[types.VoteHeader]*types.Vote + voteCacheSize int + votePositions []types.Position + stateModule *State + peers map[types.NodeID]struct{} + unreceivedBlocksLock sync.RWMutex + unreceivedBlocks map[common.Hash]chan<- common.Hash + cache *utils.NodeSetCache + notarySetCachesLock sync.Mutex + notarySetCaches map[uint64]map[types.NodeID]struct{} } // NewNetwork setup network stuffs for nodes, which provides an @@ -177,19 +164,15 @@ func NewNetwork(pubKey crypto.PublicKey, config NetworkConfig) ( n *Network) { // Construct basic network instance. n = &Network{ - ID: types.NewNodeID(pubKey), - config: config, - toConsensus: make(chan interface{}, 1000), - toNode: make(chan interface{}, 1000), - sentRandomness: make(map[common.Hash]struct{}), - sentAgreement: make(map[common.Hash]struct{}), - blockCache: make(map[common.Hash]*types.Block, maxBlockCache), - randomnessCache: make(map[common.Hash]*types.BlockRandomnessResult), - unreceivedBlocks: make(map[common.Hash]chan<- common.Hash), - unreceivedRandomness: make(map[common.Hash]chan<- common.Hash), - peers: make(map[types.NodeID]struct{}), - notarySetCaches: make(map[uint64]map[types.NodeID]struct{}), - dkgSetCaches: make(map[uint64]map[types.NodeID]struct{}), + ID: types.NewNodeID(pubKey), + config: config, + toConsensus: make(chan interface{}, 1000), + toNode: make(chan interface{}, 1000), + sentAgreement: make(map[common.Hash]struct{}), + blockCache: make(map[common.Hash]*types.Block, maxBlockCache), + unreceivedBlocks: make(map[common.Hash]chan<- common.Hash), + peers: make(map[types.NodeID]struct{}), + notarySetCaches: make(map[uint64]map[types.NodeID]struct{}), voteCache: make( map[types.Position]map[types.VoteHeader]*types.Vote), } @@ -218,11 +201,6 @@ func (n *Network) PullVotes(pos types.Position) { go n.pullVotesAsync(pos) } -// PullRandomness implememnts core.Network interface. -func (n *Network) PullRandomness(hashes common.Hashes) { - go n.pullRandomnessAsync(hashes) -} - // BroadcastVote implements core.Network interface. func (n *Network) BroadcastVote(vote *types.Vote) { if err := n.trans.Broadcast(n.getNotarySet(vote.Position.Round), @@ -254,37 +232,22 @@ func (n *Network) BroadcastAgreementResult( if !n.markAgreementResultAsSent(result.BlockHash) { return } - // Send to DKG set first. - dkgSet := n.getDKGSet(result.Position.Round) - if err := n.trans.Broadcast( - dkgSet, n.config.DirectLatency, result); err != nil { - panic(err) - } - // Gossip to other nodes. - if err := n.trans.Broadcast(getComplementSet(n.peers, dkgSet), - n.config.GossipLatency, result); err != nil { - panic(err) - } -} - -// BroadcastRandomnessResult implements core.Network interface. -func (n *Network) BroadcastRandomnessResult( - randResult *types.BlockRandomnessResult) { - if !n.markRandomnessResultAsSent(randResult.BlockHash) { - return - } - // Send to notary set first. - notarySet := n.getNotarySet(randResult.Position.Round) - if err := n.trans.Broadcast( - notarySet, n.config.DirectLatency, randResult); err != nil { - panic(err) + n.addBlockRandomnessToCache(result.BlockHash, result.Randomness) + notarySet := n.getNotarySet(result.Position.Round) + count := len(notarySet) * gossipAgreementResultPercent / 100 + for nID := range notarySet { + if count--; count < 0 { + break + } + if err := n.trans.Send(nID, result); err != nil { + panic(err) + } } // Gossip to other nodes. if err := n.trans.Broadcast(getComplementSet(n.peers, notarySet), - n.config.GossipLatency, randResult); err != nil { + n.config.GossipLatency, result); err != nil { panic(err) } - n.addRandomnessToCache(randResult) } // SendDKGPrivateShare implements core.Network interface. @@ -296,7 +259,7 @@ func (n *Network) SendDKGPrivateShare( // BroadcastDKGPrivateShare implements core.Network interface. func (n *Network) BroadcastDKGPrivateShare( prvShare *typesDKG.PrivateShare) { - if err := n.trans.Broadcast(n.getDKGSet(prvShare.Round), + if err := n.trans.Broadcast(n.getNotarySet(prvShare.Round), n.config.DirectLatency, prvShare); err != nil { panic(err) } @@ -306,7 +269,7 @@ func (n *Network) BroadcastDKGPrivateShare( func (n *Network) BroadcastDKGPartialSignature( psig *typesDKG.PartialSignature) { if err := n.trans.Broadcast( - n.getDKGSet(psig.Round), n.config.DirectLatency, psig); err != nil { + n.getNotarySet(psig.Round), n.config.DirectLatency, psig); err != nil { panic(err) } } @@ -358,7 +321,7 @@ func (n *Network) dispatchMsg(e *TransportEnvelope) { // Add this vote to cache. n.addVoteToCache(v) n.toConsensus <- v - case *types.AgreementResult, *types.BlockRandomnessResult, + case *types.AgreementResult, *typesDKG.PrivateShare, *typesDKG.PartialSignature: n.toConsensus <- v case packedStateChanges: @@ -408,25 +371,6 @@ func (n *Network) handlePullRequest(req *PullRequest) { } } }() - case "randomness": - hashes := req.Identity.(common.Hashes) - func() { - n.randomnessCacheLock.Lock() - defer n.randomnessCacheLock.Unlock() - All: - for _, h := range hashes { - r, exists := n.randomnessCache[h] - if !exists { - continue - } - select { - case <-n.ctx.Done(): - break All - default: - } - n.send(req.Requester, r) - } - }() default: panic(fmt.Errorf("unknown type of pull request: %v", req.Type)) } @@ -582,57 +526,6 @@ func (n *Network) pullVotesAsync(pos types.Position) { } } -func (n *Network) pullRandomnessAsync(hashes common.Hashes) { - // Setup notification channels for each block hash. - notYetReceived := make(map[common.Hash]struct{}) - ch := make(chan common.Hash, len(hashes)) - func() { - n.unreceivedRandomnessLock.Lock() - defer n.unreceivedRandomnessLock.Unlock() - for _, h := range hashes { - if _, exists := n.unreceivedRandomness[h]; exists { - continue - } - n.unreceivedRandomness[h] = ch - notYetReceived[h] = struct{}{} - } - }() - req := &PullRequest{ - Requester: n.ID, - Type: "randomness", - Identity: hashes, - } - // Randomly pick peers to send pull requests. -Loop: - for nID := range n.peers { - if nID == n.ID { - continue - } - n.send(nID, req) - select { - case <-n.ctx.Done(): - break Loop - case <-time.After(2 * n.config.DirectLatency.Delay()): - // Consume everything in the notification channel. - for { - select { - case h, ok := <-ch: - if !ok { - // This network module is closed. - break Loop - } - delete(notYetReceived, h) - if len(notYetReceived) == 0 { - break Loop - } - default: - continue Loop - } - } - } - } -} - func (n *Network) addBlockToCache(b *types.Block) { n.blockCacheLock.Lock() defer n.blockCacheLock.Unlock() @@ -646,6 +539,16 @@ func (n *Network) addBlockToCache(b *types.Block) { n.blockCache[b.Hash] = b.Clone() } +func (n *Network) addBlockRandomnessToCache(hash common.Hash, rand []byte) { + n.blockCacheLock.Lock() + defer n.blockCacheLock.Unlock() + block, exist := n.blockCache[hash] + if !exist { + return + } + block.Finalization.Randomness = rand +} + func (n *Network) addVoteToCache(v *types.Vote) { n.voteCacheLock.Lock() defer n.voteCacheLock.Unlock() @@ -667,19 +570,6 @@ func (n *Network) addVoteToCache(v *types.Vote) { n.voteCacheSize++ } -func (n *Network) addRandomnessToCache(rand *types.BlockRandomnessResult) { - n.randomnessCacheLock.Lock() - defer n.randomnessCacheLock.Unlock() - if len(n.randomnessCache) > 1000 { - // Randomly purge one randomness from cache. - for k := range n.randomnessCache { - delete(n.randomnessCache, k) - break - } - } - n.randomnessCache[rand.BlockHash] = rand -} - func (n *Network) markAgreementResultAsSent(blockHash common.Hash) bool { n.sentAgreementLock.Lock() defer n.sentAgreementLock.Unlock() @@ -697,23 +587,6 @@ func (n *Network) markAgreementResultAsSent(blockHash common.Hash) bool { return true } -func (n *Network) markRandomnessResultAsSent(blockHash common.Hash) bool { - n.sentRandomnessLock.Lock() - defer n.sentRandomnessLock.Unlock() - if _, exist := n.sentRandomness[blockHash]; exist { - return false - } - if len(n.sentRandomness) > 1000 { - // Randomly drop one entry. - for k := range n.sentRandomness { - delete(n.sentRandomness, k) - break - } - } - n.sentRandomness[blockHash] = struct{}{} - return true -} - func (n *Network) cloneForFake(v interface{}) interface{} { if n.config.Type != NetworkTypeFake { return v @@ -721,9 +594,9 @@ func (n *Network) cloneForFake(v interface{}) interface{} { switch val := v.(type) { case *types.Block: return val.Clone() - case *types.BlockRandomnessResult: + case *types.AgreementResult: // Perform deep copy for randomness result. - return cloneBlockRandomnessResult(val) + return cloneAgreementResult(val) } return v } @@ -749,27 +622,6 @@ func (n *Network) getNotarySet(round uint64) map[types.NodeID]struct{} { return set } -// getDKGSet gets DKG set for that round from cache. -func (n *Network) getDKGSet(round uint64) map[types.NodeID]struct{} { - if n.cache == nil { - // Default behavior is to broadcast to all peers, which makes it easier - // to be used in simple test cases. - return n.peers - } - n.dkgSetCachesLock.Lock() - defer n.dkgSetCachesLock.Unlock() - set, exists := n.dkgSetCaches[round] - if !exists { - var err error - set, err = n.cache.GetDKGSet(round) - if err != nil { - panic(err) - } - n.dkgSetCaches[round] = set - } - return set -} - func (n *Network) send(endpoint types.NodeID, msg interface{}) { go func() { time.Sleep(n.config.DirectLatency.Delay()) diff --git a/core/test/network_test.go b/core/test/network_test.go index 63407d6..993ae70 100644 --- a/core/test/network_test.go +++ b/core/test/network_test.go @@ -251,43 +251,31 @@ func (s *NetworkTestSuite) TestBroadcastToSet() { gov, err := NewGovernance(NewState( 1, pubKeys, time.Second, &common.NullLogger{}, true), 2) req.NoError(err) - req.NoError(gov.State().RequestChange(StateChangeDKGSetSize, uint32(1))) req.NoError(gov.State().RequestChange(StateChangeNotarySetSize, uint32(1))) gov.NotifyRound(round, gov.Configuration(0).RoundLength) networks := s.setupNetworks(pubKeys) cache := utils.NewNodeSetCache(gov) // Cache required set of nodeIDs. - dkgSet, err := cache.GetDKGSet(round) - req.NoError(err) - req.Len(dkgSet, 1) notarySet, err := cache.GetNotarySet(round) req.NoError(err) req.Len(notarySet, 1) var ( // Some node don't belong to any set. - nerd *Network - dkgNode, notaryNode *Network + nerd *Network + notaryNode *Network ) for nID, n := range networks { - if _, exists := dkgSet[nID]; exists { - continue - } if _, exists := notarySet[nID]; exists { continue } nerd = n break } - for nID := range dkgSet { - dkgNode = networks[nID] - break - } for nID := range notarySet { notaryNode = networks[nID] break } req.NotNil(nerd) - req.NotNil(dkgNode) req.NotNil(notaryNode) nerd.AttachNodeSetCache(cache) // Try broadcasting with datum from round 0, and make sure only node belongs @@ -296,9 +284,9 @@ func (s *NetworkTestSuite) TestBroadcastToSet() { Position: types.Position{Round: round}}}) req.IsType(&types.Vote{}, <-notaryNode.ReceiveChan()) nerd.BroadcastDKGPrivateShare(&typesDKG.PrivateShare{Round: round}) - req.IsType(&typesDKG.PrivateShare{}, <-dkgNode.ReceiveChan()) + req.IsType(&typesDKG.PrivateShare{}, <-notaryNode.ReceiveChan()) nerd.BroadcastDKGPartialSignature(&typesDKG.PartialSignature{Round: round}) - req.IsType(&typesDKG.PartialSignature{}, <-dkgNode.ReceiveChan()) + req.IsType(&typesDKG.PartialSignature{}, <-notaryNode.ReceiveChan()) nerd.BroadcastBlock(&types.Block{Position: types.Position{Round: round}}) req.IsType(&types.Block{}, <-notaryNode.ReceiveChan()) } diff --git a/core/test/state-change-request.go b/core/test/state-change-request.go index b7c7bac..fe55d6e 100644 --- a/core/test/state-change-request.go +++ b/core/test/state-change-request.go @@ -47,7 +47,6 @@ const ( StateChangeRoundLength StateChangeMinBlockInterval StateChangeNotarySetSize - StateChangeDKGSetSize // Node set related. StateAddNode ) @@ -76,8 +75,6 @@ func (t StateChangeType) String() string { return "ChangeMinBlockInterval" case StateChangeNotarySetSize: return "ChangeNotarySetSize" - case StateChangeDKGSetSize: - return "ChangeDKGSetSize" case StateAddNode: return "AddNode" } @@ -195,8 +192,6 @@ func (req *StateChangeRequest) String() (ret string) { ret += fmt.Sprintf("%v", time.Duration(req.Payload.(uint64))) case StateChangeNotarySetSize: ret += fmt.Sprintf("%v", req.Payload.(uint32)) - case StateChangeDKGSetSize: - ret += fmt.Sprintf("%v", req.Payload.(uint32)) case StateAddNode: ret += fmt.Sprintf( "%s", types.NewNodeID(req.Payload.(crypto.PublicKey)).String()[:6]) diff --git a/core/test/state-change-request_test.go b/core/test/state-change-request_test.go index eeba4c4..517a929 100644 --- a/core/test/state-change-request_test.go +++ b/core/test/state-change-request_test.go @@ -42,7 +42,7 @@ func (s *StateChangeRequestTestSuite) TestEqual() { func (s *StateChangeRequestTestSuite) TestClone() { // The cloned one should be no error when compared with 'Equal' method. - st00 := NewStateChangeRequest(StateChangeDKGSetSize, uint32(7)) + st00 := NewStateChangeRequest(StateChangeNotarySetSize, uint32(7)) s.NoError(st00.Equal(st00.Clone())) st10 := NewStateChangeRequest( StateAddDKGMasterPublicKey, typesDKG.NewMasterPublicKey()) diff --git a/core/test/state.go b/core/test/state.go index ce906ae..41c6b38 100644 --- a/core/test/state.go +++ b/core/test/state.go @@ -94,7 +94,6 @@ type State struct { lambdaBA time.Duration lambdaDKG time.Duration notarySetSize uint32 - dkgSetSize uint32 roundInterval uint64 minBlockInterval time.Duration // Nodes @@ -145,7 +144,6 @@ func NewState( crs: crs, nodes: nodes, notarySetSize: uint32(len(nodes)), - dkgSetSize: uint32(len(nodes)), ownRequests: make(map[common.Hash]*StateChangeRequest), globalRequests: make(map[common.Hash]*StateChangeRequest), dkgReadys: make( @@ -183,7 +181,6 @@ func (s *State) Snapshot() (*types.Config, []crypto.PublicKey) { LambdaBA: s.lambdaBA, LambdaDKG: s.lambdaDKG, NotarySetSize: s.notarySetSize, - DKGSetSize: s.dkgSetSize, RoundLength: s.roundInterval, MinBlockInterval: s.minBlockInterval, } @@ -238,10 +235,6 @@ func (s *State) unpackPayload( var tmp uint32 err = rlp.DecodeBytes(raw.Payload, &tmp) v = tmp - case StateChangeDKGSetSize: - var tmp uint32 - err = rlp.DecodeBytes(raw.Payload, &tmp) - v = tmp case StateAddNode: var tmp []byte err = rlp.DecodeBytes(raw.Payload, &tmp) @@ -283,7 +276,6 @@ func (s *State) Equal(other *State) error { configEqual := s.lambdaBA == other.lambdaBA && s.lambdaDKG == other.lambdaDKG && s.notarySetSize == other.notarySetSize && - s.dkgSetSize == other.dkgSetSize && s.roundInterval == other.roundInterval && s.minBlockInterval == other.minBlockInterval if !configEqual { @@ -452,7 +444,6 @@ func (s *State) Clone() (copied *State) { lambdaBA: s.lambdaBA, lambdaDKG: s.lambdaDKG, notarySetSize: s.notarySetSize, - dkgSetSize: s.dkgSetSize, roundInterval: s.roundInterval, minBlockInterval: s.minBlockInterval, local: s.local, @@ -774,8 +765,6 @@ func (s *State) applyRequest(req *StateChangeRequest) error { s.minBlockInterval = time.Duration(req.Payload.(uint64)) case StateChangeNotarySetSize: s.notarySetSize = req.Payload.(uint32) - case StateChangeDKGSetSize: - s.dkgSetSize = req.Payload.(uint32) default: return errors.New("you are definitely kidding me") } diff --git a/core/test/state_test.go b/core/test/state_test.go index 0ec90a4..5ad5a3e 100644 --- a/core/test/state_test.go +++ b/core/test/state_test.go @@ -147,7 +147,6 @@ func (s *StateTestSuite) makeConfigChanges(st *State) { st.RequestChange(StateChangeRoundLength, uint64(1001)) st.RequestChange(StateChangeMinBlockInterval, time.Second) st.RequestChange(StateChangeNotarySetSize, uint32(5)) - st.RequestChange(StateChangeDKGSetSize, uint32(6)) } func (s *StateTestSuite) checkConfigChanges(config *types.Config) { @@ -157,7 +156,6 @@ func (s *StateTestSuite) checkConfigChanges(config *types.Config) { req.Equal(config.RoundLength, uint64(1001)) req.Equal(config.MinBlockInterval, time.Second) req.Equal(config.NotarySetSize, uint32(5)) - req.Equal(config.DKGSetSize, uint32(6)) } func (s *StateTestSuite) TestEqual() { @@ -265,7 +263,6 @@ func (s *StateTestSuite) TestLocalMode() { req.Equal(config1.LambdaDKG, lambda*10) req.Equal(config1.RoundLength, uint64(1000)) req.Equal(config1.NotarySetSize, uint32(len(genesisNodes))) - req.Equal(config1.DKGSetSize, uint32(len(genesisNodes))) // Request some changes, every fields for config should be affected. s.makeConfigChanges(st) // Add new node. diff --git a/core/test/tcp-transport.go b/core/test/tcp-transport.go index 19d9bfa..bbc4d56 100644 --- a/core/test/tcp-transport.go +++ b/core/test/tcp-transport.go @@ -896,8 +896,6 @@ func (t *TCPTransport) handleThroughputData(msg interface{}, payload []byte) { recordType = "agreement_result" case *dkg.PartialSignature: recordType = "partial_sig" - case *types.BlockRandomnessResult: - recordType = "block_random" } if len(recordType) > 0 { t.throughputRecords = append(t.throughputRecords, ThroughputRecord{ diff --git a/core/test/utils.go b/core/test/utils.go index a2819ae..74cde45 100644 --- a/core/test/utils.go +++ b/core/test/utils.go @@ -184,13 +184,13 @@ func CloneDKGPrivateShare(prvShare *typesDKG.PrivateShare) ( return } -func cloneBlockRandomnessResult(rand *types.BlockRandomnessResult) ( - copied *types.BlockRandomnessResult) { - b, err := rlp.EncodeToBytes(rand) +func cloneAgreementResult(result *types.AgreementResult) ( + copied *types.AgreementResult) { + b, err := rlp.EncodeToBytes(result) if err != nil { panic(err) } - copied = &types.BlockRandomnessResult{} + copied = &types.AgreementResult{} if err = rlp.DecodeBytes(b, copied); err != nil { panic(err) } diff --git a/core/types/block-randomness.go b/core/types/block-randomness.go index 74360c7..9a0a65e 100644 --- a/core/types/block-randomness.go +++ b/core/types/block-randomness.go @@ -26,27 +26,20 @@ import ( // AgreementResult describes an agremeent result. type AgreementResult struct { - BlockHash common.Hash `json:"block_hash"` - Position Position `json:"position"` - Votes []Vote `json:"votes"` - IsEmptyBlock bool `json:"is_empty_block"` + BlockHash common.Hash `json:"block_hash"` + Position Position `json:"position"` + // TODO(jimmy): remove Votes + Votes []Vote `json:"votes"` + IsEmptyBlock bool `json:"is_empty_block"` + Randomness []byte `json:"randomness"` } func (r *AgreementResult) String() string { - return fmt.Sprintf("agreementResult{Hash:%s %s}", - r.BlockHash.String()[:6], r.Position) -} - -// BlockRandomnessResult describes a block randomness result -type BlockRandomnessResult struct { - BlockHash common.Hash `json:"block_hash"` - Position Position `json:"position"` - Randomness []byte `json:"randomness"` -} - -func (r *BlockRandomnessResult) String() string { - return fmt.Sprintf("blockRandomness{Block:%s Pos:%s Rand:%s}", + if len(r.Randomness) == 0 { + return fmt.Sprintf("agreementResult{Block:%s Pos:%s}", + r.BlockHash.String()[:6], r.Position) + } + return fmt.Sprintf("agreementResult{Block:%s Pos:%s Rand:%s}", r.BlockHash.String()[:6], r.Position, - hex.EncodeToString(r.Randomness)[:6], - ) + hex.EncodeToString(r.Randomness)[:6]) } diff --git a/core/types/config.go b/core/types/config.go index eda09f0..dce3836 100644 --- a/core/types/config.go +++ b/core/types/config.go @@ -30,7 +30,6 @@ type Config struct { // Set related. NotarySetSize uint32 - DKGSetSize uint32 // Time related. RoundLength uint64 @@ -43,7 +42,6 @@ func (c *Config) Clone() *Config { LambdaBA: c.LambdaBA, LambdaDKG: c.LambdaDKG, NotarySetSize: c.NotarySetSize, - DKGSetSize: c.DKGSetSize, RoundLength: c.RoundLength, MinBlockInterval: c.MinBlockInterval, } @@ -60,8 +58,6 @@ func (c *Config) Bytes() []byte { binaryNotarySetSize := make([]byte, 4) binary.LittleEndian.PutUint32(binaryNotarySetSize, c.NotarySetSize) - binaryDKGSetSize := make([]byte, 4) - binary.LittleEndian.PutUint32(binaryDKGSetSize, c.DKGSetSize) binaryRoundLength := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRoundLength, c.RoundLength) @@ -73,7 +69,6 @@ func (c *Config) Bytes() []byte { enc = append(enc, binaryLambdaBA...) enc = append(enc, binaryLambdaDKG...) enc = append(enc, binaryNotarySetSize...) - enc = append(enc, binaryDKGSetSize...) enc = append(enc, binaryRoundLength...) enc = append(enc, binaryMinBlockInterval...) return enc diff --git a/core/types/config_test.go b/core/types/config_test.go index ac9ef5e..b55004e 100644 --- a/core/types/config_test.go +++ b/core/types/config_test.go @@ -33,7 +33,6 @@ func (s *ConfigTestSuite) TestClone() { LambdaBA: 1 * time.Millisecond, LambdaDKG: 2 * time.Hour, NotarySetSize: 5, - DKGSetSize: 6, RoundLength: 1000, MinBlockInterval: 7 * time.Nanosecond, } diff --git a/core/types/nodeset.go b/core/types/nodeset.go index fccfbb6..8060007 100644 --- a/core/types/nodeset.go +++ b/core/types/nodeset.go @@ -40,7 +40,6 @@ type subSetTargetType byte const ( targetNotarySet subSetTargetType = iota - targetDKGSet targetNodeLeader ) @@ -89,11 +88,6 @@ func NewNotarySetTarget(crs common.Hash) *SubSetTarget { return newTarget(targetNotarySet, crs[:]) } -// NewDKGSetTarget is the target for getting DKG Set. -func NewDKGSetTarget(crs common.Hash) *SubSetTarget { - return newTarget(targetDKGSet, crs[:]) -} - // NewNodeLeaderTarget is the target for getting leader of fast BA. func NewNodeLeaderTarget(crs common.Hash, height uint64) *SubSetTarget { binaryHeight := make([]byte, 8) diff --git a/core/types/vote.go b/core/types/vote.go index c4a625e..8bc0c78 100644 --- a/core/types/vote.go +++ b/core/types/vote.go @@ -22,6 +22,7 @@ import ( "github.com/dexon-foundation/dexon-consensus/common" "github.com/dexon-foundation/dexon-consensus/core/crypto" + cryptoDKG "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" ) // VoteType is the type of vote. @@ -61,8 +62,9 @@ type VoteHeader struct { // Vote is the vote structure defined in Crypto Shuffle Algorithm. type Vote struct { - VoteHeader `json:"header"` - Signature crypto.Signature `json:"signature"` + VoteHeader `json:"header"` + PartialSignature cryptoDKG.PartialSignature `json:"partial_signature"` + Signature crypto.Signature `json:"signature"` } func (v *Vote) String() string { @@ -91,6 +93,8 @@ func (v *Vote) Clone() *Vote { Period: v.Period, Position: v.Position, }, + PartialSignature: cryptoDKG.PartialSignature( + crypto.Signature(v.PartialSignature).Clone()), Signature: v.Signature.Clone(), } } diff --git a/core/utils/crypto.go b/core/utils/crypto.go index 8be503f..34bf08f 100644 --- a/core/utils/crypto.go +++ b/core/utils/crypto.go @@ -36,7 +36,7 @@ func hashWitness(witness *types.Witness) (common.Hash, error) { // HashBlock generates hash of a types.Block. func HashBlock(block *types.Block) (common.Hash, error) { - hashPosition := hashPosition(block.Position) + hashPosition := HashPosition(block.Position) binaryTimestamp, err := block.Timestamp.UTC().MarshalBinary() if err != nil { return common.Hash{}, err @@ -88,13 +88,14 @@ func HashVote(vote *types.Vote) common.Hash { binaryPeriod := make([]byte, 8) binary.LittleEndian.PutUint64(binaryPeriod, vote.Period) - hashPosition := hashPosition(vote.Position) + hashPosition := HashPosition(vote.Position) hash := crypto.Keccak256Hash( vote.ProposerID.Hash[:], vote.BlockHash[:], binaryPeriod, hashPosition[:], + vote.PartialSignature.Signature[:], []byte{byte(vote.Type)}, ) return hash @@ -114,7 +115,7 @@ func VerifyVoteSignature(vote *types.Vote) (bool, error) { } func hashCRS(block *types.Block, crs common.Hash) common.Hash { - hashPos := hashPosition(block.Position) + hashPos := HashPosition(block.Position) return crypto.Keccak256Hash(crs[:], hashPos[:]) } @@ -132,7 +133,8 @@ func VerifyCRSSignature(block *types.Block, crs common.Hash) ( return true, nil } -func hashPosition(position types.Position) common.Hash { +// HashPosition generates hash of a types.Position. +func HashPosition(position types.Position) common.Hash { binaryRound := make([]byte, 8) binary.LittleEndian.PutUint64(binaryRound, position.Round) diff --git a/core/utils/nodeset-cache.go b/core/utils/nodeset-cache.go index 0090123..89ebd24 100644 --- a/core/utils/nodeset-cache.go +++ b/core/utils/nodeset-cache.go @@ -39,7 +39,6 @@ type sets struct { crs common.Hash nodeSet *types.NodeSet notarySet map[types.NodeID]struct{} - dkgSet map[types.NodeID]struct{} leaderNode map[uint64]types.NodeID } @@ -134,16 +133,6 @@ func (cache *NodeSetCache) GetNotarySet( return cache.cloneMap(IDs.notarySet), nil } -// GetDKGSet returns of DKG set of this round. -func (cache *NodeSetCache) GetDKGSet( - round uint64) (map[types.NodeID]struct{}, error) { - IDs, err := cache.getOrUpdate(round) - if err != nil { - return nil, err - } - return cache.cloneMap(IDs.dkgSet), nil -} - // GetLeaderNode returns the BA leader of the position. func (cache *NodeSetCache) GetLeaderNode(pos types.Position) ( types.NodeID, error) { @@ -254,10 +243,6 @@ func (cache *NodeSetCache) update(round uint64) (nIDs *sets, err error) { notarySet: make(map[types.NodeID]struct{}), leaderNode: make(map[uint64]types.NodeID, cfg.RoundLength), } - if round >= dkgDelayRound { - nIDs.dkgSet = nodeSet.GetSubSet( - int(cfg.DKGSetSize), types.NewDKGSetTarget(crs)) - } nIDs.notarySet = nodeSet.GetSubSet( int(cfg.NotarySetSize), types.NewNotarySetTarget(crs)) cache.rounds[round] = nIDs diff --git a/core/utils/nodeset-cache_test.go b/core/utils/nodeset-cache_test.go index 45d30a7..0ee3883 100644 --- a/core/utils/nodeset-cache_test.go +++ b/core/utils/nodeset-cache_test.go @@ -37,7 +37,6 @@ type nsIntf struct { func (g *nsIntf) Configuration(round uint64) (cfg *types.Config) { return &types.Config{ NotarySetSize: 7, - DKGSetSize: 7, RoundLength: 60, LambdaBA: 250 * time.Millisecond, MinBlockInterval: 1 * time.Second, @@ -91,9 +90,6 @@ func (s *NodeSetCacheTestSuite) TestBasicUsage() { notarySet, err := cache.GetNotarySet(0) req.NoError(err) chk(cache, 0, notarySet) - dkgSet, err := cache.GetDKGSet(0) - req.NoError(err) - chk(cache, 0, dkgSet) leaderNode, err := cache.GetLeaderNode(types.Position{ Round: uint64(0), Height: uint64(10), diff --git a/core/utils/utils.go b/core/utils/utils.go index 14687d6..fcdf422 100644 --- a/core/utils/utils.go +++ b/core/utils/utils.go @@ -136,7 +136,7 @@ func LaunchDummyReceiver( // GetDKGThreshold return expected threshold for given DKG set size. func GetDKGThreshold(config *types.Config) int { - return int(config.DKGSetSize/3) + 1 + return int(config.NotarySetSize*2/3) + 1 } // GetNextRoundValidationHeight returns the block height to check if the next diff --git a/integration_test/consensus_test.go b/integration_test/consensus_test.go index 6bdc3dc..2c7f762 100644 --- a/integration_test/consensus_test.go +++ b/integration_test/consensus_test.go @@ -20,6 +20,8 @@ package integration import ( "context" "fmt" + "log" + "os" "sync" "testing" "time" @@ -110,7 +112,7 @@ func (s *ConsensusTestSuite) setupNodes( // setup nodes. nodes := make(map[types.NodeID]*node) wg.Add(len(prvKeys)) - for _, k := range prvKeys { + for i, k := range prvKeys { dbInst, err := db.NewMemBackedDB() s.Require().NoError(err) // Prepare essential modules: app, gov, db. @@ -124,7 +126,11 @@ func (s *ConsensusTestSuite) setupNodes( gov.SwitchToRemoteMode(networkModule) gov.NotifyRound(initRound, 0) networkModule.AttachNodeSetCache(utils.NewNodeSetCache(gov)) - logger := &common.NullLogger{} + f, err := os.Create(fmt.Sprintf("log.%d.log", i)) + if err != nil { + panic(err) + } + logger := common.NewCustomLogger(log.New(f, "", log.LstdFlags|log.Lmicroseconds)) rEvt, err := utils.NewRoundEvent(context.Background(), gov, logger, 0, 0, core.ConfigRoundShift) s.Require().NoError(err) @@ -318,32 +324,24 @@ func (s *ConsensusTestSuite) TestSetSizeChange() { test.StateChangeRoundLength, uint64(100))) 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.StateChangeRoundLength, uint64(100))) 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.StateChangeRoundLength, uint64(100))) 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.StateChangeRoundLength, uint64(100))) 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) @@ -357,8 +355,11 @@ func (s *ConsensusTestSuite) TestSetSizeChange() { 4, test.StateChangeRoundLength, uint64(100))) req.NoError(pickedNode.gov.RegisterConfigChange( 4, test.StateChangeNotarySetSize, uint32(5))) + // Register configuration changes for round 5. req.NoError(pickedNode.gov.RegisterConfigChange( - 4, test.StateChangeDKGSetSize, uint32(5))) + 5, test.StateChangeRoundLength, uint64(60))) + req.NoError(pickedNode.gov.RegisterConfigChange( + 5, test.StateChangeNotarySetSize, uint32(4))) // Run test. for _, n := range nodes { go n.con.Run() @@ -463,6 +464,11 @@ ReachAlive: // Initiate Syncer. runnerCtx, runnerCtxCancel := context.WithCancel(context.Background()) defer runnerCtxCancel() + f, err := os.Create("log.sync.log") + if err != nil { + panic(err) + } + logger := common.NewCustomLogger(log.New(f, "", log.LstdFlags|log.Lmicroseconds)) syncerObj := syncer.NewConsensus( dMoment, syncNode.app, @@ -470,7 +476,7 @@ ReachAlive: syncNode.db, syncNode.network, prvKeys[0], - &common.NullLogger{}, + logger, ) // Initialize communication channel, it's not recommended to assertion in // another go routine. @@ -620,7 +626,12 @@ ReachStop: node.app.ClearUndeliveredBlocks() } syncerCon := make(map[types.NodeID]*syncer.Consensus, len(nodes)) - for _, prvKey := range prvKeys { + for i, prvKey := range prvKeys { + f, err := os.Create(fmt.Sprintf("log.sync.%d.log", i)) + if err != nil { + panic(err) + } + logger := common.NewCustomLogger(log.New(f, "", log.LstdFlags|log.Lmicroseconds)) nID := types.NewNodeID(prvKey.PublicKey()) node := nodes[nID] syncerCon[nID] = syncer.NewConsensus( @@ -630,7 +641,7 @@ ReachStop: node.db, node.network, prvKey, - &common.NullLogger{}, + logger, ) } targetNode := nodes[latestNodeID] @@ -711,8 +722,6 @@ func (s *ConsensusTestSuite) TestResetDKG() { test.StateChangeRoundLength, uint64(100))) req.NoError(seedGov.State().RequestChange( test.StateChangeNotarySetSize, uint32(4))) - req.NoError(seedGov.State().RequestChange( - test.StateChangeDKGSetSize, uint32(4))) nodes := s.setupNodes(dMoment, prvKeys, seedGov) for _, n := range nodes { n.rEvt.Register(purgeHandlerGen(n.network)) diff --git a/simulation/config/utils.go b/simulation/config/utils.go index 6e9024a..ade7471 100644 --- a/simulation/config/utils.go +++ b/simulation/config/utils.go @@ -37,8 +37,6 @@ func StateChangeTypeFromString(s string) test.StateChangeType { return test.StateChangeMinBlockInterval case "notary_set_size": return test.StateChangeNotarySetSize - case "dkg_set_size": - return test.StateChangeDKGSetSize } panic(fmt.Errorf("unsupported state change type %s", s)) } @@ -48,7 +46,7 @@ func StateChangeTypeFromString(s string) test.StateChangeType { func StateChangeValueFromString( t test.StateChangeType, v string) interface{} { switch t { - case test.StateChangeNotarySetSize, test.StateChangeDKGSetSize: + case test.StateChangeNotarySetSize: ret, err := strconv.ParseUint(v, 10, 32) if err != nil { panic(err) diff --git a/simulation/node.go b/simulation/node.go index 5bd8ec1..ee2dd89 100644 --- a/simulation/node.go +++ b/simulation/node.go @@ -206,7 +206,6 @@ func (n *node) prepareConfigs() { cConfig := n.cfg.Node.Consensus n.gov.State().RequestChange( test.StateChangeNotarySetSize, cConfig.NotarySetSize) // #nosec G104 - n.gov.State().RequestChange(test.StateChangeDKGSetSize, cConfig.DKGSetSize) // #nosec G104 n.gov.State().RequestChange(test.StateChangeLambdaBA, time.Duration( cConfig.LambdaBA)*time.Millisecond) // #nosec G104 n.gov.State().RequestChange(test.StateChangeLambdaDKG, time.Duration( -- cgit v1.2.3