diff options
author | Wei-Ning Huang <w@byzantine-lab.io> | 2019-06-12 17:31:08 +0800 |
---|---|---|
committer | Wei-Ning Huang <w@byzantine-lab.io> | 2019-09-17 16:57:29 +0800 |
commit | ac088de6322fc16ebe75c2e5554be73754bf1fe2 (patch) | |
tree | 086b7827d46a4d07b834cd94be73beaabb77b734 /vendor/github.com/dexon-foundation/dexon-consensus/core | |
parent | 67d565f3f0e398e99bef96827f729e3e4b0edf31 (diff) | |
download | go-tangerine-ac088de6322fc16ebe75c2e5554be73754bf1fe2.tar go-tangerine-ac088de6322fc16ebe75c2e5554be73754bf1fe2.tar.gz go-tangerine-ac088de6322fc16ebe75c2e5554be73754bf1fe2.tar.bz2 go-tangerine-ac088de6322fc16ebe75c2e5554be73754bf1fe2.tar.lz go-tangerine-ac088de6322fc16ebe75c2e5554be73754bf1fe2.tar.xz go-tangerine-ac088de6322fc16ebe75c2e5554be73754bf1fe2.tar.zst go-tangerine-ac088de6322fc16ebe75c2e5554be73754bf1fe2.zip |
Rebrand as tangerine-network/go-tangerine
Diffstat (limited to 'vendor/github.com/dexon-foundation/dexon-consensus/core')
42 files changed, 0 insertions, 12166 deletions
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go deleted file mode 100644 index 17def6747..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go +++ /dev/null @@ -1,676 +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 core - -import ( - "context" - "errors" - "math" - "sync" - "time" - - lru "github.com/hashicorp/golang-lru" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/types" - typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// Errors returned from BA modules -var ( - ErrPreviousRoundIsNotFinished = errors.New("previous round is not finished") - ErrRoundOutOfRange = errors.New("round out of range") - ErrInvalidBlock = errors.New("invalid block") - ErrNoValidLeader = errors.New("no valid leader") - ErrIncorrectCRSSignature = errors.New("incorrect CRS signature") - ErrBlockTooOld = errors.New("block too old") -) - -const maxResultCache = 100 -const settingLimit = 3 - -// genValidLeader generate a validLeader function for agreement modules. -func genValidLeader( - mgr *agreementMgr) validLeaderFn { - return func(block *types.Block, crs common.Hash) (bool, error) { - if block.Timestamp.After(time.Now()) { - return false, nil - } - if block.Position.Round >= DKGDelayRound { - if mgr.recv.npks == nil { - return false, nil - } - if block.Position.Round > mgr.recv.npks.Round { - return false, nil - } - if block.Position.Round < mgr.recv.npks.Round { - return false, ErrBlockTooOld - } - } - if !utils.VerifyCRSSignature(block, crs, mgr.recv.npks) { - return false, ErrIncorrectCRSSignature - } - if err := mgr.bcModule.sanityCheck(block); err != nil { - if err == ErrRetrySanityCheckLater { - return false, nil - } - return false, err - } - mgr.logger.Debug("Calling Application.VerifyBlock", "block", block) - switch mgr.app.VerifyBlock(block) { - case types.VerifyInvalidBlock: - return false, ErrInvalidBlock - case types.VerifyRetryLater: - return false, nil - default: - } - return true, nil - } -} - -type agreementMgrConfig struct { - utils.RoundBasedConfig - - notarySetSize uint32 - lambdaBA time.Duration - crs common.Hash -} - -func (c *agreementMgrConfig) from( - round uint64, config *types.Config, crs common.Hash) { - c.notarySetSize = config.NotarySetSize - c.lambdaBA = config.LambdaBA - c.crs = crs - c.SetupRoundBasedFields(round, config) -} - -func newAgreementMgrConfig(prev agreementMgrConfig, config *types.Config, - crs common.Hash) (c agreementMgrConfig) { - c = agreementMgrConfig{} - c.from(prev.RoundID()+1, config, crs) - c.AppendTo(prev.RoundBasedConfig) - return -} - -type baRoundSetting struct { - round uint64 - dkgSet map[types.NodeID]struct{} - threshold int - ticker Ticker - crs common.Hash -} - -type agreementMgr struct { - // TODO(mission): unbound Consensus instance from this module. - con *Consensus - ID types.NodeID - app Application - gov Governance - network Network - logger common.Logger - cache *utils.NodeSetCache - signer *utils.Signer - bcModule *blockChain - ctx context.Context - configs []agreementMgrConfig - baModule *agreement - recv *consensusBAReceiver - processedBAResult map[types.Position]struct{} - voteFilter *utils.VoteFilter - settingCache *lru.Cache - curRoundSetting *baRoundSetting - waitGroup sync.WaitGroup - isRunning bool - lock sync.RWMutex -} - -func newAgreementMgr(con *Consensus) (mgr *agreementMgr, err error) { - settingCache, _ := lru.New(settingLimit) - mgr = &agreementMgr{ - con: con, - ID: con.ID, - app: con.app, - gov: con.gov, - network: con.network, - logger: con.logger, - cache: con.nodeSetCache, - signer: con.signer, - bcModule: con.bcModule, - ctx: con.ctx, - processedBAResult: make(map[types.Position]struct{}, maxResultCache), - voteFilter: utils.NewVoteFilter(), - settingCache: settingCache, - } - mgr.recv = &consensusBAReceiver{ - consensus: con, - restartNotary: make(chan types.Position, 1), - } - return mgr, nil -} - -func (mgr *agreementMgr) prepare() { - round := mgr.bcModule.tipRound() - agr := newAgreement( - mgr.ID, - mgr.recv, - newLeaderSelector(genValidLeader(mgr), mgr.logger), - mgr.signer, - mgr.logger) - setting := mgr.generateSetting(round) - if setting == nil { - mgr.logger.Warn("Unable to prepare init setting", "round", round) - return - } - mgr.curRoundSetting = setting - agr.notarySet = mgr.curRoundSetting.dkgSet - // Hacky way to make agreement module self contained. - mgr.recv.agreementModule = agr - mgr.baModule = agr - if round >= DKGDelayRound { - if _, exist := setting.dkgSet[mgr.ID]; exist { - mgr.logger.Debug("Preparing signer and npks.", "round", round) - npk, signer, err := mgr.con.cfgModule.getDKGInfo(round, false) - if err != nil { - mgr.logger.Error("Failed to prepare signer and npks.", - "round", round, - "error", err) - } - mgr.logger.Debug("Prepared signer and npks.", - "round", round, "signer", signer != nil, "npks", npk != nil) - } - } - return -} - -func (mgr *agreementMgr) run() { - mgr.lock.Lock() - defer mgr.lock.Unlock() - if mgr.isRunning { - return - } - mgr.isRunning = true - mgr.waitGroup.Add(1) - go func() { - defer mgr.waitGroup.Done() - mgr.runBA(mgr.bcModule.tipRound()) - }() -} - -func (mgr *agreementMgr) calcLeader( - dkgSet map[types.NodeID]struct{}, - crs common.Hash, pos types.Position) ( - types.NodeID, error) { - nodeSet := types.NewNodeSetFromMap(dkgSet) - leader := nodeSet.GetSubSet(1, types.NewNodeLeaderTarget( - crs, pos.Height)) - for nID := range leader { - return nID, nil - } - return types.NodeID{}, ErrNoValidLeader -} - -func (mgr *agreementMgr) config(round uint64) *agreementMgrConfig { - mgr.lock.RLock() - defer mgr.lock.RUnlock() - if round < mgr.configs[0].RoundID() { - panic(ErrRoundOutOfRange) - } - roundIndex := round - mgr.configs[0].RoundID() - if roundIndex >= uint64(len(mgr.configs)) { - return nil - } - return &mgr.configs[roundIndex] -} - -func (mgr *agreementMgr) notifyRoundEvents(evts []utils.RoundEventParam) error { - mgr.lock.Lock() - defer mgr.lock.Unlock() - apply := func(e utils.RoundEventParam) error { - if len(mgr.configs) > 0 { - lastCfg := mgr.configs[len(mgr.configs)-1] - if e.BeginHeight != lastCfg.RoundEndHeight() { - return ErrInvalidBlockHeight - } - if lastCfg.RoundID() == e.Round { - mgr.configs[len(mgr.configs)-1].ExtendLength() - } else if lastCfg.RoundID()+1 == e.Round { - mgr.configs = append(mgr.configs, newAgreementMgrConfig( - lastCfg, e.Config, e.CRS)) - } else { - return ErrInvalidRoundID - } - } else { - c := agreementMgrConfig{} - c.from(e.Round, e.Config, e.CRS) - c.SetRoundBeginHeight(e.BeginHeight) - mgr.configs = append(mgr.configs, c) - } - return nil - } - for _, e := range evts { - if err := apply(e); err != nil { - return err - } - } - return nil -} - -func (mgr *agreementMgr) checkProposer( - round uint64, proposerID types.NodeID) error { - if round == mgr.curRoundSetting.round { - if _, exist := mgr.curRoundSetting.dkgSet[proposerID]; !exist { - return ErrNotInNotarySet - } - } else if round == mgr.curRoundSetting.round+1 { - setting := mgr.generateSetting(round) - if setting == nil { - return ErrConfigurationNotReady - } - if _, exist := setting.dkgSet[proposerID]; !exist { - return ErrNotInNotarySet - } - } - return nil -} - -func (mgr *agreementMgr) processVote(v *types.Vote) (err error) { - if !mgr.recv.isNotary { - return nil - } - if mgr.voteFilter.Filter(v) { - return nil - } - if err := mgr.checkProposer(v.Position.Round, v.ProposerID); err != nil { - return err - } - if err = mgr.baModule.processVote(v); err == nil { - mgr.baModule.updateFilter(mgr.voteFilter) - mgr.voteFilter.AddVote(v) - } - if err == ErrSkipButNoError { - err = nil - } - return -} - -func (mgr *agreementMgr) processBlock(b *types.Block) error { - if err := mgr.checkProposer(b.Position.Round, b.ProposerID); err != nil { - return err - } - return mgr.baModule.processBlock(b) -} - -func (mgr *agreementMgr) touchAgreementResult( - result *types.AgreementResult) (first bool) { - // DO NOT LOCK THIS FUNCTION!!!!!!!! YOU WILL REGRET IT!!!!! - if _, exist := mgr.processedBAResult[result.Position]; !exist { - first = true - if len(mgr.processedBAResult) > maxResultCache { - for k := range mgr.processedBAResult { - // Randomly drop one element. - delete(mgr.processedBAResult, k) - break - } - } - mgr.processedBAResult[result.Position] = struct{}{} - } - return -} - -func (mgr *agreementMgr) untouchAgreementResult( - result *types.AgreementResult) { - // DO NOT LOCK THIS FUNCTION!!!!!!!! YOU WILL REGRET IT!!!!! - delete(mgr.processedBAResult, result.Position) -} - -func (mgr *agreementMgr) processAgreementResult( - result *types.AgreementResult) error { - aID := mgr.baModule.agreementID() - if isStop(aID) { - return nil - } - if result.Position == aID && !mgr.baModule.confirmed() { - mgr.logger.Info("Syncing BA", "position", result.Position) - if result.Position.Round >= DKGDelayRound { - return mgr.baModule.processAgreementResult(result) - } - for key := range result.Votes { - if err := mgr.baModule.processVote(&result.Votes[key]); err != nil { - return err - } - } - } else if result.Position.Newer(aID) { - mgr.logger.Info("Fast syncing BA", "position", result.Position) - if result.Position.Round < DKGDelayRound { - mgr.logger.Debug("Calling Network.PullBlocks for fast syncing BA", - "hash", result.BlockHash) - mgr.network.PullBlocks(common.Hashes{result.BlockHash}) - for key := range result.Votes { - if err := mgr.baModule.processVote(&result.Votes[key]); err != nil { - return err - } - } - } - setting := mgr.generateSetting(result.Position.Round) - if setting == nil { - mgr.logger.Warn("unable to get setting", "round", - result.Position.Round) - return ErrConfigurationNotReady - } - mgr.curRoundSetting = setting - leader, err := mgr.calcLeader(setting.dkgSet, setting.crs, result.Position) - if err != nil { - return err - } - mgr.baModule.restart( - setting.dkgSet, setting.threshold, - result.Position, leader, setting.crs) - if result.Position.Round >= DKGDelayRound { - return mgr.baModule.processAgreementResult(result) - } - } - return nil -} - -func (mgr *agreementMgr) processFinalizedBlock(block *types.Block) error { - aID := mgr.baModule.agreementID() - if block.Position.Older(aID) { - return nil - } - mgr.baModule.processFinalizedBlock(block) - return nil -} - -func (mgr *agreementMgr) stop() { - // Stop all running agreement modules. - func() { - mgr.lock.Lock() - defer mgr.lock.Unlock() - mgr.baModule.stop() - }() - // Block until all routines are done. - mgr.waitGroup.Wait() -} - -func (mgr *agreementMgr) generateSetting(round uint64) *baRoundSetting { - if setting, exist := mgr.settingCache.Get(round); exist { - return setting.(*baRoundSetting) - } - curConfig := mgr.config(round) - if curConfig == nil { - return nil - } - var dkgSet map[types.NodeID]struct{} - if round >= DKGDelayRound { - _, qualidifed, err := typesDKG.CalcQualifyNodes( - mgr.gov.DKGMasterPublicKeys(round), - mgr.gov.DKGComplaints(round), - utils.GetDKGThreshold(mgr.gov.Configuration(round)), - ) - if err != nil { - mgr.logger.Error("Failed to get gpk", "round", round, "error", err) - return nil - } - dkgSet = qualidifed - } - if len(dkgSet) == 0 { - var err error - dkgSet, err = mgr.cache.GetNotarySet(round) - if err != nil { - mgr.logger.Error("Failed to get notarySet", "round", round, "error", err) - return nil - } - } - setting := &baRoundSetting{ - crs: curConfig.crs, - dkgSet: dkgSet, - round: round, - threshold: utils.GetBAThreshold(&types.Config{ - NotarySetSize: curConfig.notarySetSize}), - } - mgr.settingCache.Add(round, setting) - return setting -} - -func (mgr *agreementMgr) runBA(initRound uint64) { - // These are round based variables. - var ( - currentRound uint64 - nextRound = initRound - curConfig = mgr.config(initRound) - setting = &baRoundSetting{} - tickDuration time.Duration - ticker Ticker - ) - - // Check if this routine needs to awake in this round and prepare essential - // variables when yes. - checkRound := func() (isDKG bool) { - defer func() { - currentRound = nextRound - nextRound++ - }() - // Wait until the configuartion for next round is ready. - for { - if setting = mgr.generateSetting(nextRound); setting != nil { - break - } else { - mgr.logger.Debug("Round is not ready", "round", nextRound) - time.Sleep(1 * time.Second) - } - } - _, isDKG = setting.dkgSet[mgr.ID] - if isDKG { - mgr.logger.Info("Selected as dkg set", - "ID", mgr.ID, - "round", nextRound) - } else { - mgr.logger.Info("Not selected as dkg set", - "ID", mgr.ID, - "round", nextRound) - } - // Setup ticker - if tickDuration != curConfig.lambdaBA { - if ticker != nil { - ticker.Stop() - } - ticker = newTicker(mgr.gov, nextRound, TickerBA) - tickDuration = curConfig.lambdaBA - } - setting.ticker = ticker - return - } -Loop: - for { - select { - case <-mgr.ctx.Done(): - break Loop - default: - } - mgr.recv.isNotary = checkRound() - mgr.voteFilter = utils.NewVoteFilter() - mgr.voteFilter.Position.Round = currentRound - mgr.recv.emptyBlockHashMap = &sync.Map{} - if currentRound >= DKGDelayRound && mgr.recv.isNotary { - var err error - mgr.recv.npks, mgr.recv.psigSigner, err = - mgr.con.cfgModule.getDKGInfo(currentRound, false) - if err != nil { - mgr.logger.Warn("cannot get dkg info", - "round", currentRound, "error", err) - } - } else { - mgr.recv.npks = nil - mgr.recv.psigSigner = nil - } - // Run BA for this round. - mgr.recv.restartNotary <- types.Position{ - Round: currentRound, - Height: math.MaxUint64, - } - if err := mgr.baRoutineForOneRound(setting); err != nil { - mgr.logger.Error("BA routine failed", - "error", err, - "nodeID", mgr.ID) - break Loop - } - } -} - -func (mgr *agreementMgr) baRoutineForOneRound( - setting *baRoundSetting) (err error) { - agr := mgr.baModule - recv := mgr.recv - oldPos := agr.agreementID() - restart := func(restartPos types.Position) (breakLoop bool, err error) { - if !isStop(restartPos) { - if restartPos.Height+1 >= mgr.config(setting.round).RoundEndHeight() { - for { - select { - case <-mgr.ctx.Done(): - break - default: - } - tipRound := mgr.bcModule.tipRound() - if tipRound > setting.round { - break - } else { - mgr.logger.Debug("Waiting blockChain to change round...", - "curRound", setting.round, - "tipRound", tipRound) - } - time.Sleep(100 * time.Millisecond) - } - // This round is finished. - breakLoop = true - return - } - if restartPos.Older(oldPos) { - // The restartNotary event is triggered by 'BlockConfirmed' - // of some older block. - return - } - } - var nextHeight uint64 - var nextTime time.Time - for { - // Make sure we are stoppable. - select { - case <-mgr.ctx.Done(): - breakLoop = true - return - default: - } - nextHeight, nextTime = mgr.bcModule.nextBlock() - if nextHeight != notReadyHeight { - if isStop(restartPos) { - break - } - if nextHeight > restartPos.Height { - break - } - } - mgr.logger.Debug("BlockChain not ready!!!", - "old", oldPos, "restart", restartPos, "next", nextHeight) - time.Sleep(100 * time.Millisecond) - } - nextPos := types.Position{ - Round: setting.round, - Height: nextHeight, - } - oldPos = nextPos - var leader types.NodeID - leader, err = mgr.calcLeader(setting.dkgSet, setting.crs, nextPos) - if err != nil { - return - } - time.Sleep(nextTime.Sub(time.Now())) - setting.ticker.Restart() - agr.restart(setting.dkgSet, setting.threshold, nextPos, leader, setting.crs) - return - } -Loop: - for { - select { - case <-mgr.ctx.Done(): - break Loop - default: - } - if agr.confirmed() { - // Block until receive restartPos - select { - case restartPos := <-recv.restartNotary: - breakLoop, err := restart(restartPos) - if err != nil { - return err - } - if breakLoop { - break Loop - } - case <-mgr.ctx.Done(): - break Loop - } - } - select { - case restartPos := <-recv.restartNotary: - breakLoop, err := restart(restartPos) - if err != nil { - return err - } - if breakLoop { - break Loop - } - default: - } - if !mgr.recv.isNotary { - select { - case <-setting.ticker.Tick(): - continue Loop - case <-mgr.ctx.Done(): - break Loop - } - } - if err = agr.nextState(); err != nil { - mgr.logger.Error("Failed to proceed to next state", - "nodeID", mgr.ID.String(), - "error", err) - break Loop - } - if agr.pullVotes() { - pos := agr.agreementID() - mgr.logger.Debug("Calling Network.PullVotes for syncing votes", - "position", pos) - mgr.network.PullVotes(pos) - } - for i := 0; i < agr.clocks(); i++ { - // Priority select for agreement.done(). - select { - case <-agr.done(): - continue Loop - default: - } - select { - case <-agr.done(): - continue Loop - case <-setting.ticker.Tick(): - } - } - } - return nil -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-state.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-state.go deleted file mode 100644 index 0d1ae58bc..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-state.go +++ /dev/null @@ -1,213 +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 core - -import ( - "fmt" - - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -// Errors for agreement state module. -var ( - ErrNoEnoughVoteInPrepareState = fmt.Errorf("no enough vote in prepare state") - ErrNoEnoughVoteInAckState = fmt.Errorf("no enough vote in ack state") -) - -// agreementStateType is the state of agreement -type agreementStateType int - -// agreementStateType enum. -const ( - stateFast agreementStateType = iota - stateFastVote - stateInitial - statePreCommit - stateCommit - stateForward - statePullVote - stateSleep -) - -type agreementState interface { - state() agreementStateType - nextState() (agreementState, error) - clocks() int -} - -//----- FastState ----- -type fastState struct { - a *agreementData -} - -func newFastState(a *agreementData) *fastState { - return &fastState{a: a} -} - -func (s *fastState) state() agreementStateType { return stateFast } -func (s *fastState) clocks() int { return 0 } -func (s *fastState) nextState() (agreementState, error) { - if func() bool { - s.a.lock.Lock() - defer s.a.lock.Unlock() - return s.a.isLeader - }() { - hash := s.a.recv.ProposeBlock() - if hash != types.NullBlockHash { - s.a.lock.Lock() - defer s.a.lock.Unlock() - s.a.recv.ProposeVote(types.NewVote(types.VoteFast, hash, s.a.period)) - } - } - return newFastVoteState(s.a), nil -} - -//----- FastVoteState ----- -type fastVoteState struct { - a *agreementData -} - -func newFastVoteState(a *agreementData) *fastVoteState { - return &fastVoteState{a: a} -} - -func (s *fastVoteState) state() agreementStateType { return stateFastVote } -func (s *fastVoteState) clocks() int { return 3 } -func (s *fastVoteState) nextState() (agreementState, error) { - return newInitialState(s.a), nil -} - -//----- InitialState ----- -type initialState struct { - a *agreementData -} - -func newInitialState(a *agreementData) *initialState { - return &initialState{a: a} -} - -func (s *initialState) state() agreementStateType { return stateInitial } -func (s *initialState) clocks() int { return 0 } -func (s *initialState) nextState() (agreementState, error) { - if func() bool { - s.a.lock.Lock() - defer s.a.lock.Unlock() - return !s.a.isLeader - }() { - // Leader already proposed block in fastState. - hash := s.a.recv.ProposeBlock() - s.a.lock.Lock() - defer s.a.lock.Unlock() - s.a.recv.ProposeVote(types.NewVote(types.VoteInit, hash, s.a.period)) - } - return newPreCommitState(s.a), nil -} - -//----- PreCommitState ----- -type preCommitState struct { - a *agreementData -} - -func newPreCommitState(a *agreementData) *preCommitState { - return &preCommitState{a: a} -} - -func (s *preCommitState) state() agreementStateType { return statePreCommit } -func (s *preCommitState) clocks() int { return 2 } -func (s *preCommitState) nextState() (agreementState, error) { - s.a.lock.RLock() - defer s.a.lock.RUnlock() - if s.a.lockValue == types.SkipBlockHash || - s.a.lockValue == types.NullBlockHash { - hash := s.a.leader.leaderBlockHash() - s.a.recv.ProposeVote(types.NewVote(types.VotePreCom, hash, s.a.period)) - } else { - s.a.recv.ProposeVote(types.NewVote( - types.VotePreCom, s.a.lockValue, s.a.period)) - } - return newCommitState(s.a), nil -} - -//----- CommitState ----- -type commitState struct { - a *agreementData -} - -func newCommitState(a *agreementData) *commitState { - return &commitState{a: a} -} - -func (s *commitState) state() agreementStateType { return stateCommit } -func (s *commitState) clocks() int { return 2 } -func (s *commitState) nextState() (agreementState, error) { - s.a.lock.Lock() - defer s.a.lock.Unlock() - s.a.recv.ProposeVote(types.NewVote(types.VoteCom, s.a.lockValue, s.a.period)) - return newForwardState(s.a), nil -} - -// ----- ForwardState ----- -type forwardState struct { - a *agreementData -} - -func newForwardState(a *agreementData) *forwardState { - return &forwardState{a: a} -} - -func (s *forwardState) state() agreementStateType { return stateForward } -func (s *forwardState) clocks() int { return 4 } - -func (s *forwardState) nextState() (agreementState, error) { - return newPullVoteState(s.a), nil -} - -// ----- PullVoteState ----- -// pullVoteState is a special state to ensure the assumption in the consensus -// algorithm that every vote will eventually arrive for all nodes. -type pullVoteState struct { - a *agreementData -} - -func newPullVoteState(a *agreementData) *pullVoteState { - return &pullVoteState{a: a} -} - -func (s *pullVoteState) state() agreementStateType { return statePullVote } -func (s *pullVoteState) clocks() int { return 4 } - -func (s *pullVoteState) nextState() (agreementState, error) { - return s, nil -} - -// ----- SleepState ----- -// sleepState is a special state after BA has output and waits for restart. -type sleepState struct { - a *agreementData -} - -func newSleepState(a *agreementData) *sleepState { - return &sleepState{a: a} -} - -func (s *sleepState) state() agreementStateType { return stateSleep } -func (s *sleepState) clocks() int { return 65536 } - -func (s *sleepState) nextState() (agreementState, error) { - return s, nil -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement.go deleted file mode 100644 index d90afc610..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement.go +++ /dev/null @@ -1,797 +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 core - -import ( - "fmt" - "math" - "sync" - "sync/atomic" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/types" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// closedchan is a reusable closed channel. -var closedchan = make(chan struct{}) - -func init() { - close(closedchan) -} - -// Errors for agreement module. -var ( - ErrInvalidVote = fmt.Errorf("invalid vote") - ErrNotInNotarySet = fmt.Errorf("not in notary set") - ErrIncorrectVoteSignature = fmt.Errorf("incorrect vote signature") - ErrIncorrectVotePartialSignature = fmt.Errorf("incorrect vote psig") - ErrMismatchBlockPosition = fmt.Errorf("mismatch block position") -) - -// ErrFork for fork error in agreement. -type ErrFork struct { - nID types.NodeID - old, new common.Hash -} - -func (e *ErrFork) Error() string { - return fmt.Sprintf("fork is found for %s, old %s, new %s", - e.nID.String(), e.old, e.new) -} - -// ErrForkVote for fork vote error in agreement. -type ErrForkVote struct { - nID types.NodeID - old, new *types.Vote -} - -func (e *ErrForkVote) Error() string { - return fmt.Sprintf("fork vote is found for %s, old %s, new %s", - e.nID.String(), e.old, e.new) -} - -func newVoteListMap() []map[types.NodeID]*types.Vote { - listMap := make([]map[types.NodeID]*types.Vote, types.MaxVoteType) - for idx := range listMap { - listMap[idx] = make(map[types.NodeID]*types.Vote) - } - return listMap -} - -// agreementReceiver is the interface receiving agreement event. -type agreementReceiver interface { - ProposeVote(vote *types.Vote) - ProposeBlock() common.Hash - // ConfirmBlock is called with lock hold. User can safely use all data within - // agreement module. - ConfirmBlock(common.Hash, map[types.NodeID]*types.Vote) - PullBlocks(common.Hashes) - ReportForkVote(v1, v2 *types.Vote) - ReportForkBlock(b1, b2 *types.Block) - VerifyPartialSignature(vote *types.Vote) (bool, bool) -} - -type pendingBlock struct { - block *types.Block - receivedTime time.Time -} - -type pendingVote struct { - vote *types.Vote - receivedTime time.Time -} - -// agreementData is the data for agreementState. -type agreementData struct { - recv agreementReceiver - - ID types.NodeID - isLeader bool - leader *leaderSelector - lockValue common.Hash - lockIter uint64 - period uint64 - requiredVote int - votes map[uint64][]map[types.NodeID]*types.Vote - lock sync.RWMutex - blocks map[types.NodeID]*types.Block - blocksLock sync.Mutex -} - -// agreement is the agreement protocal describe in the Crypto Shuffle Algorithm. -type agreement struct { - state agreementState - data *agreementData - aID *atomic.Value - doneChan chan struct{} - notarySet map[types.NodeID]struct{} - hasVoteFast bool - hasOutput bool - lock sync.RWMutex - pendingBlock []pendingBlock - pendingVote []pendingVote - pendingAgreementResult map[types.Position]*types.AgreementResult - candidateBlock map[common.Hash]*types.Block - fastForward chan uint64 - signer *utils.Signer - logger common.Logger -} - -// newAgreement creates a agreement instance. -func newAgreement( - ID types.NodeID, - recv agreementReceiver, - leader *leaderSelector, - signer *utils.Signer, - logger common.Logger) *agreement { - agreement := &agreement{ - data: &agreementData{ - recv: recv, - ID: ID, - leader: leader, - }, - aID: &atomic.Value{}, - pendingAgreementResult: make(map[types.Position]*types.AgreementResult), - candidateBlock: make(map[common.Hash]*types.Block), - fastForward: make(chan uint64, 1), - signer: signer, - logger: logger, - } - agreement.stop() - return agreement -} - -// restart the agreement -func (a *agreement) restart( - notarySet map[types.NodeID]struct{}, - threshold int, aID types.Position, leader types.NodeID, - crs common.Hash) { - if !func() bool { - a.lock.Lock() - defer a.lock.Unlock() - if !isStop(aID) { - oldAID := a.agreementID() - if !isStop(oldAID) && !aID.Newer(oldAID) { - return false - } - } - a.logger.Debug("Restarting BA", - "notarySet", notarySet, "position", aID, "leader", leader) - a.data.lock.Lock() - defer a.data.lock.Unlock() - a.data.blocksLock.Lock() - defer a.data.blocksLock.Unlock() - a.data.votes = make(map[uint64][]map[types.NodeID]*types.Vote) - a.data.votes[1] = newVoteListMap() - a.data.period = 2 - a.data.blocks = make(map[types.NodeID]*types.Block) - a.data.requiredVote = threshold - a.data.leader.restart(crs) - a.data.lockValue = types.SkipBlockHash - a.data.lockIter = 0 - a.data.isLeader = a.data.ID == leader - if a.doneChan != nil { - close(a.doneChan) - } - a.doneChan = make(chan struct{}) - a.fastForward = make(chan uint64, 1) - a.hasVoteFast = false - a.hasOutput = false - a.state = newFastState(a.data) - a.notarySet = notarySet - a.candidateBlock = make(map[common.Hash]*types.Block) - a.aID.Store(struct { - pos types.Position - leader types.NodeID - }{aID, leader}) - return true - }() { - return - } - - if isStop(aID) { - return - } - - var result *types.AgreementResult - func() { - a.lock.Lock() - defer a.lock.Unlock() - newPendingAgreementResult := make( - map[types.Position]*types.AgreementResult) - for pos, agr := range a.pendingAgreementResult { - if pos.Newer(aID) { - newPendingAgreementResult[pos] = agr - } else if pos == aID { - result = agr - } - } - a.pendingAgreementResult = newPendingAgreementResult - }() - - expireTime := time.Now().Add(-10 * time.Second) - replayBlock := make([]*types.Block, 0) - func() { - a.lock.Lock() - defer a.lock.Unlock() - newPendingBlock := make([]pendingBlock, 0) - for _, pending := range a.pendingBlock { - if aID.Newer(pending.block.Position) { - continue - } else if pending.block.Position == aID { - if result == nil || - result.Position.Round < DKGDelayRound || - result.BlockHash == pending.block.Hash { - replayBlock = append(replayBlock, pending.block) - } - } else if pending.receivedTime.After(expireTime) { - newPendingBlock = append(newPendingBlock, pending) - } - } - a.pendingBlock = newPendingBlock - }() - - replayVote := make([]*types.Vote, 0) - func() { - a.lock.Lock() - defer a.lock.Unlock() - newPendingVote := make([]pendingVote, 0) - for _, pending := range a.pendingVote { - if aID.Newer(pending.vote.Position) { - continue - } else if pending.vote.Position == aID { - if result == nil || result.Position.Round < DKGDelayRound { - replayVote = append(replayVote, pending.vote) - } - } else if pending.receivedTime.After(expireTime) { - newPendingVote = append(newPendingVote, pending) - } - } - a.pendingVote = newPendingVote - }() - - for _, block := range replayBlock { - if err := a.processBlock(block); err != nil { - a.logger.Error("Failed to process block when restarting agreement", - "block", block) - } - } - - if result != nil { - if err := a.processAgreementResult(result); err != nil { - a.logger.Error("Failed to process agreement result when retarting", - "result", result) - } - } - - for _, vote := range replayVote { - if err := a.processVote(vote); err != nil { - a.logger.Error("Failed to process vote when restarting agreement", - "vote", vote) - } - } -} - -func (a *agreement) stop() { - a.restart(make(map[types.NodeID]struct{}), int(math.MaxInt32), - types.Position{ - Height: math.MaxUint64, - }, - types.NodeID{}, common.Hash{}) -} - -func isStop(aID types.Position) bool { - return aID.Height == math.MaxUint64 -} - -// clocks returns how many time this state is required. -func (a *agreement) clocks() int { - a.data.lock.RLock() - defer a.data.lock.RUnlock() - scale := int(a.data.period) - 1 - if a.state.state() == stateForward { - scale = 1 - } - if scale < 1 { - // just in case. - scale = 1 - } - // 10 is a magic number derived from many years of experience. - if scale > 10 { - scale = 10 - } - return a.state.clocks() * scale -} - -// pullVotes returns if current agreement requires more votes to continue. -func (a *agreement) pullVotes() bool { - a.data.lock.RLock() - defer a.data.lock.RUnlock() - return a.state.state() == statePullVote || - a.state.state() == stateInitial || - (a.state.state() == statePreCommit && (a.data.period%3) == 0) -} - -// agreementID returns the current agreementID. -func (a *agreement) agreementID() types.Position { - return a.aID.Load().(struct { - pos types.Position - leader types.NodeID - }).pos -} - -// leader returns the current leader. -func (a *agreement) leader() types.NodeID { - return a.aID.Load().(struct { - pos types.Position - leader types.NodeID - }).leader -} - -// nextState is called at the specific clock time. -func (a *agreement) nextState() (err error) { - a.lock.Lock() - defer a.lock.Unlock() - if a.hasOutput { - a.state = newSleepState(a.data) - return - } - a.state, err = a.state.nextState() - return -} - -func (a *agreement) sanityCheck(vote *types.Vote) error { - if vote.Type >= types.MaxVoteType { - return ErrInvalidVote - } - ok, err := utils.VerifyVoteSignature(vote) - if err != nil { - return err - } - if !ok { - return ErrIncorrectVoteSignature - } - if vote.Position.Round != a.agreementID().Round { - // TODO(jimmy): maybe we can verify partial signature at agreement-mgr. - return nil - } - if ok, report := a.data.recv.VerifyPartialSignature(vote); !ok { - if report { - return ErrIncorrectVotePartialSignature - } - return ErrSkipButNoError - } - return nil -} - -func (a *agreement) checkForkVote(vote *types.Vote) ( - alreadyExist bool, err error) { - a.data.lock.RLock() - defer a.data.lock.RUnlock() - if votes, exist := a.data.votes[vote.Period]; exist { - if oldVote, exist := votes[vote.Type][vote.ProposerID]; exist { - alreadyExist = true - if vote.BlockHash != oldVote.BlockHash { - a.data.recv.ReportForkVote(oldVote, vote) - err = &ErrForkVote{vote.ProposerID, oldVote, vote} - return - } - } - } - return -} - -// prepareVote prepares a vote. -func (a *agreement) prepareVote(vote *types.Vote) (err error) { - vote.Position = a.agreementID() - err = a.signer.SignVote(vote) - return -} - -func (a *agreement) updateFilter(filter *utils.VoteFilter) { - if isStop(a.agreementID()) { - return - } - a.lock.RLock() - defer a.lock.RUnlock() - a.data.lock.RLock() - defer a.data.lock.RUnlock() - filter.Confirm = a.hasOutput - filter.LockIter = a.data.lockIter - filter.Period = a.data.period - filter.Position.Height = a.agreementID().Height -} - -// processVote is the entry point for processing Vote. -func (a *agreement) processVote(vote *types.Vote) error { - a.lock.Lock() - defer a.lock.Unlock() - if err := a.sanityCheck(vote); err != nil { - return err - } - aID := a.agreementID() - - // Agreement module has stopped. - if isStop(aID) { - // Hacky way to not drop first votes when round just begins. - if vote.Position.Round == aID.Round { - a.pendingVote = append(a.pendingVote, pendingVote{ - vote: vote, - receivedTime: time.Now().UTC(), - }) - return nil - } - return ErrSkipButNoError - } - if vote.Position != aID { - if aID.Newer(vote.Position) { - return nil - } - a.pendingVote = append(a.pendingVote, pendingVote{ - vote: vote, - receivedTime: time.Now().UTC(), - }) - return nil - } - exist, err := a.checkForkVote(vote) - if err != nil { - return err - } - if exist { - return nil - } - - a.data.lock.Lock() - defer a.data.lock.Unlock() - if _, exist := a.data.votes[vote.Period]; !exist { - a.data.votes[vote.Period] = newVoteListMap() - } - if _, exist := a.data.votes[vote.Period][vote.Type][vote.ProposerID]; exist { - return nil - } - a.data.votes[vote.Period][vote.Type][vote.ProposerID] = vote - if !a.hasOutput && - (vote.Type == types.VoteCom || - vote.Type == types.VoteFast || - vote.Type == types.VoteFastCom) { - if hash, ok := a.data.countVoteNoLock(vote.Period, vote.Type); ok && - hash != types.SkipBlockHash { - if vote.Type == types.VoteFast { - if !a.hasVoteFast { - if a.state.state() == stateFast || - a.state.state() == stateFastVote { - a.data.recv.ProposeVote( - types.NewVote(types.VoteFastCom, hash, vote.Period)) - a.hasVoteFast = true - - } - if a.data.lockIter == 0 { - a.data.lockValue = hash - a.data.lockIter = 1 - } - } - } else { - a.hasOutput = true - a.data.recv.ConfirmBlock(hash, - a.data.votes[vote.Period][vote.Type]) - if a.doneChan != nil { - close(a.doneChan) - a.doneChan = nil - } - } - return nil - } - } else if a.hasOutput { - return nil - } - - // Check if the agreement requires fast-forwarding. - if len(a.fastForward) > 0 { - return nil - } - if vote.Type == types.VotePreCom { - if vote.Period < a.data.lockIter { - // This PreCom is useless for us. - return nil - } - if hash, ok := a.data.countVoteNoLock(vote.Period, vote.Type); ok && - hash != types.SkipBlockHash { - // Condition 1. - if vote.Period > a.data.lockIter { - a.data.lockValue = hash - a.data.lockIter = vote.Period - } - // Condition 2. - if vote.Period > a.data.period { - a.fastForward <- vote.Period - if a.doneChan != nil { - close(a.doneChan) - a.doneChan = nil - } - return nil - } - } - } - // Condition 3. - if vote.Type == types.VoteCom && vote.Period >= a.data.period && - len(a.data.votes[vote.Period][types.VoteCom]) >= a.data.requiredVote { - hashes := common.Hashes{} - addPullBlocks := func(voteType types.VoteType) { - for _, vote := range a.data.votes[vote.Period][voteType] { - if vote.BlockHash == types.NullBlockHash || - vote.BlockHash == types.SkipBlockHash { - continue - } - if _, found := a.findCandidateBlockNoLock(vote.BlockHash); !found { - hashes = append(hashes, vote.BlockHash) - } - } - } - addPullBlocks(types.VotePreCom) - addPullBlocks(types.VoteCom) - if len(hashes) > 0 { - a.data.recv.PullBlocks(hashes) - } - a.fastForward <- vote.Period + 1 - if a.doneChan != nil { - close(a.doneChan) - a.doneChan = nil - } - return nil - } - return nil -} - -func (a *agreement) processFinalizedBlock(block *types.Block) { - a.lock.Lock() - defer a.lock.Unlock() - if a.hasOutput { - return - } - aID := a.agreementID() - if aID.Older(block.Position) { - return - } - a.addCandidateBlockNoLock(block) - a.hasOutput = true - a.data.lock.Lock() - defer a.data.lock.Unlock() - a.data.recv.ConfirmBlock(block.Hash, nil) - if a.doneChan != nil { - close(a.doneChan) - a.doneChan = nil - } -} - -func (a *agreement) processAgreementResult(result *types.AgreementResult) error { - a.lock.Lock() - defer a.lock.Unlock() - aID := a.agreementID() - if result.Position.Older(aID) { - return nil - } else if result.Position.Newer(aID) { - a.pendingAgreementResult[result.Position] = result - return nil - } - if a.hasOutput { - return nil - } - a.data.lock.Lock() - defer a.data.lock.Unlock() - if _, exist := a.findCandidateBlockNoLock(result.BlockHash); !exist { - a.data.recv.PullBlocks(common.Hashes{result.BlockHash}) - } - a.hasOutput = true - a.data.recv.ConfirmBlock(result.BlockHash, nil) - if a.doneChan != nil { - close(a.doneChan) - a.doneChan = nil - } - return nil -} - -func (a *agreement) done() <-chan struct{} { - a.lock.Lock() - defer a.lock.Unlock() - select { - case period := <-a.fastForward: - a.data.lock.Lock() - defer a.data.lock.Unlock() - if period <= a.data.period { - break - } - a.data.setPeriod(period) - a.state = newPreCommitState(a.data) - a.doneChan = make(chan struct{}) - return closedchan - default: - } - if a.doneChan == nil { - return closedchan - } - return a.doneChan -} - -func (a *agreement) confirmed() bool { - a.lock.RLock() - defer a.lock.RUnlock() - return a.confirmedNoLock() -} - -func (a *agreement) confirmedNoLock() bool { - return a.hasOutput -} - -// processBlock is the entry point for processing Block. -func (a *agreement) processBlock(block *types.Block) error { - checkSkip := func() bool { - aID := a.agreementID() - if block.Position != aID { - // Agreement module has stopped. - if !isStop(aID) { - if aID.Newer(block.Position) { - return true - } - } - } - return false - } - if checkSkip() { - return nil - } - if err := utils.VerifyBlockSignature(block); err != nil { - return err - } - - a.lock.Lock() - defer a.lock.Unlock() - a.data.blocksLock.Lock() - defer a.data.blocksLock.Unlock() - aID := a.agreementID() - // a.agreementID might change during lock, so we need to checkSkip again. - if checkSkip() { - return nil - } else if aID != block.Position { - a.pendingBlock = append(a.pendingBlock, pendingBlock{ - block: block, - receivedTime: time.Now().UTC(), - }) - return nil - } else if a.confirmedNoLock() { - return nil - } - if b, exist := a.data.blocks[block.ProposerID]; exist { - if b.Hash != block.Hash { - a.data.recv.ReportForkBlock(b, block) - return &ErrFork{block.ProposerID, b.Hash, block.Hash} - } - return nil - } - if err := a.data.leader.processBlock(block); err != nil { - return err - } - a.data.blocks[block.ProposerID] = block - a.addCandidateBlockNoLock(block) - if block.ProposerID != a.data.ID && - (a.state.state() == stateFast || a.state.state() == stateFastVote) && - block.ProposerID == a.leader() { - go func() { - for func() bool { - if aID != a.agreementID() { - return false - } - a.lock.RLock() - defer a.lock.RUnlock() - if a.state.state() != stateFast && a.state.state() != stateFastVote { - return false - } - a.data.lock.RLock() - defer a.data.lock.RUnlock() - a.data.blocksLock.Lock() - defer a.data.blocksLock.Unlock() - block, exist := a.data.blocks[a.leader()] - if !exist { - return true - } - ok, err := a.data.leader.validLeader(block, a.data.leader.hashCRS) - if err != nil { - fmt.Println("Error checking validLeader for Fast BA", - "error", err, "block", block) - return false - } - if ok { - a.data.recv.ProposeVote( - types.NewVote(types.VoteFast, block.Hash, a.data.period)) - return false - } - return true - }() { - // TODO(jimmy): retry interval should be related to configurations. - time.Sleep(250 * time.Millisecond) - } - }() - } - return nil -} - -func (a *agreement) addCandidateBlock(block *types.Block) { - a.lock.Lock() - defer a.lock.Unlock() - a.addCandidateBlockNoLock(block) -} - -func (a *agreement) addCandidateBlockNoLock(block *types.Block) { - a.candidateBlock[block.Hash] = block -} - -func (a *agreement) findCandidateBlockNoLock( - hash common.Hash) (*types.Block, bool) { - b, e := a.candidateBlock[hash] - return b, e -} - -// find a block in both candidate blocks and pending blocks in leader-selector. -// A block might be confirmed by others while we can't verify its validity. -func (a *agreement) findBlockNoLock(hash common.Hash) (*types.Block, bool) { - b, e := a.findCandidateBlockNoLock(hash) - if !e { - b, e = a.data.leader.findPendingBlock(hash) - } - return b, e -} - -func (a *agreementData) countVote(period uint64, voteType types.VoteType) ( - blockHash common.Hash, ok bool) { - a.lock.RLock() - defer a.lock.RUnlock() - return a.countVoteNoLock(period, voteType) -} - -func (a *agreementData) countVoteNoLock( - period uint64, voteType types.VoteType) (blockHash common.Hash, ok bool) { - votes, exist := a.votes[period] - if !exist { - return - } - candidate := make(map[common.Hash]int) - for _, vote := range votes[voteType] { - if _, exist := candidate[vote.BlockHash]; !exist { - candidate[vote.BlockHash] = 0 - } - candidate[vote.BlockHash]++ - } - for candidateHash, votes := range candidate { - if votes >= a.requiredVote { - blockHash = candidateHash - ok = true - return - } - } - return -} - -func (a *agreementData) setPeriod(period uint64) { - for i := a.period + 1; i <= period; i++ { - if _, exist := a.votes[i]; !exist { - a.votes[i] = newVoteListMap() - } - } - a.period = period -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go deleted file mode 100644 index 4fae221c7..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go +++ /dev/null @@ -1,681 +0,0 @@ -// Copyright 2019 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 core - -import ( - "bytes" - "errors" - "fmt" - "math" - "sort" - "sync" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/types" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// 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") - ErrInvalidTimestamp = errors.New("invalid timestamp") - 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") -) - -const notReadyHeight uint64 = math.MaxUint64 - -type pendingBlockRecord struct { - position types.Position - block *types.Block -} - -type pendingBlockRecords []pendingBlockRecord - -func (pb *pendingBlockRecords) insert(p pendingBlockRecord) error { - idx := sort.Search(len(*pb), func(i int) bool { - return !(*pb)[i].position.Older(p.position) - }) - switch idx { - case len(*pb): - *pb = append(*pb, p) - default: - if (*pb)[idx].position.Equal(p.position) { - // Allow to overwrite pending block record for empty blocks, we may - // need to pull that block from others when its parent is not found - // locally. - if (*pb)[idx].block == nil && p.block != nil { - (*pb)[idx].block = p.block - return nil - } - return ErrDuplicatedPendingBlock - } - // Insert the value to that index. - *pb = append((*pb), pendingBlockRecord{}) - copy((*pb)[idx+1:], (*pb)[idx:]) - (*pb)[idx] = p - } - return nil -} - -func (pb pendingBlockRecords) searchByHeight(h uint64) ( - pendingBlockRecord, bool) { - idx := sort.Search(len(pb), func(i int) bool { - return pb[i].position.Height >= h - }) - if idx == len(pb) || pb[idx].position.Height != h { - return pendingBlockRecord{}, false - } - return pb[idx], true -} - -func (pb pendingBlockRecords) searchByPosition(p types.Position) ( - pendingBlockRecord, bool) { - idx := sort.Search(len(pb), func(i int) bool { - return !pb[i].block.Position.Older(p) - }) - if idx == len(pb) || !pb[idx].position.Equal(p) { - return pendingBlockRecord{}, false - } - return pb[idx], true -} - -type blockChainConfig struct { - utils.RoundBasedConfig - - minBlockInterval time.Duration -} - -func (c *blockChainConfig) fromConfig(round uint64, config *types.Config) { - c.minBlockInterval = config.MinBlockInterval - c.SetupRoundBasedFields(round, config) -} - -func newBlockChainConfig(prev blockChainConfig, config *types.Config) ( - c blockChainConfig) { - c = blockChainConfig{} - c.fromConfig(prev.RoundID()+1, config) - c.AppendTo(prev.RoundBasedConfig) - return -} - -type tsigVerifierGetter interface { - UpdateAndGet(uint64) (TSigVerifier, bool, error) - Purge(uint64) -} - -type blockChain struct { - lock sync.RWMutex - ID types.NodeID - lastConfirmed *types.Block - lastDelivered *types.Block - signer *utils.Signer - vGetter tsigVerifierGetter - app Application - logger common.Logger - pendingRandomnesses map[types.Position][]byte - configs []blockChainConfig - pendingBlocks pendingBlockRecords - confirmedBlocks types.BlocksByPosition - dMoment time.Time - - // Do not access this variable besides processAgreementResult. - lastPosition types.Position -} - -func newBlockChain(nID types.NodeID, dMoment time.Time, initBlock *types.Block, - app Application, vGetter tsigVerifierGetter, signer *utils.Signer, - logger common.Logger) *blockChain { - return &blockChain{ - ID: nID, - lastConfirmed: initBlock, - lastDelivered: initBlock, - signer: signer, - vGetter: vGetter, - app: app, - logger: logger, - dMoment: dMoment, - pendingRandomnesses: make( - map[types.Position][]byte), - } -} - -func (bc *blockChain) notifyRoundEvents(evts []utils.RoundEventParam) error { - bc.lock.Lock() - defer bc.lock.Unlock() - apply := func(e utils.RoundEventParam) error { - if len(bc.configs) > 0 { - lastCfg := bc.configs[len(bc.configs)-1] - if e.BeginHeight != lastCfg.RoundEndHeight() { - return ErrInvalidBlockHeight - } - if lastCfg.RoundID() == e.Round { - bc.configs[len(bc.configs)-1].ExtendLength() - } else if lastCfg.RoundID()+1 == e.Round { - bc.configs = append(bc.configs, newBlockChainConfig( - lastCfg, e.Config)) - } else { - return ErrInvalidRoundID - } - } else { - c := blockChainConfig{} - c.fromConfig(e.Round, e.Config) - c.SetRoundBeginHeight(e.BeginHeight) - if bc.lastConfirmed == nil { - if c.RoundID() != 0 { - panic(fmt.Errorf( - "genesis config should from round 0, but %d", - c.RoundID())) - } - } else { - if c.RoundID() != bc.lastConfirmed.Position.Round { - panic(fmt.Errorf("incompatible config/block round %s %d", - bc.lastConfirmed, c.RoundID())) - } - if !c.Contains(bc.lastConfirmed.Position.Height) { - panic(fmt.Errorf( - "unmatched round-event with block %s %d %d %d", - bc.lastConfirmed, e.Round, e.Reset, e.BeginHeight)) - } - } - bc.configs = append(bc.configs, c) - } - return nil - } - for _, e := range evts { - if err := apply(e); err != nil { - return err - } - } - return nil -} - -func (bc *blockChain) proposeBlock(position types.Position, - proposeTime time.Time, isEmpty bool) (b *types.Block, err error) { - bc.lock.RLock() - defer bc.lock.RUnlock() - return bc.prepareBlock(position, proposeTime, isEmpty) -} - -func (bc *blockChain) extractBlocks() (ret []*types.Block) { - bc.lock.Lock() - defer bc.lock.Unlock() - for len(bc.confirmedBlocks) > 0 { - c := bc.confirmedBlocks[0] - if c.Position.Round >= DKGDelayRound && - len(c.Randomness) == 0 && - !bc.setRandomnessFromPending(c) { - break - } - c, bc.confirmedBlocks = bc.confirmedBlocks[0], bc.confirmedBlocks[1:] - ret = append(ret, c) - bc.lastDelivered = c - } - return -} - -func (bc *blockChain) sanityCheck(b *types.Block) error { - bc.lock.RLock() - defer bc.lock.RUnlock() - if bc.lastConfirmed == nil { - // It should be a genesis block. - if !b.IsGenesis() { - return ErrNotGenesisBlock - } - if b.Timestamp.Before(bc.dMoment.Add(bc.configs[0].minBlockInterval)) { - return ErrInvalidTimestamp - } - return nil - } - if b.IsGenesis() { - return ErrIsGenesisBlock - } - if b.Position.Height != bc.lastConfirmed.Position.Height+1 { - if b.Position.Height > bc.lastConfirmed.Position.Height { - return ErrRetrySanityCheckLater - } - return ErrInvalidBlockHeight - } - tipConfig := bc.tipConfig() - if tipConfig.IsLastBlock(bc.lastConfirmed) { - if b.Position.Round != bc.lastConfirmed.Position.Round+1 { - return ErrRoundNotSwitch - } - } else { - if b.Position.Round != bc.lastConfirmed.Position.Round { - return ErrInvalidRoundID - } - } - if !b.ParentHash.Equal(bc.lastConfirmed.Hash) { - return ErrIncorrectParentHash - } - if b.Timestamp.Before(bc.lastConfirmed.Timestamp.Add( - tipConfig.minBlockInterval)) { - return ErrInvalidTimestamp - } - if err := utils.VerifyBlockSignature(b); err != nil { - return err - } - return nil -} - -// addEmptyBlock is called when an empty block is confirmed by BA. -func (bc *blockChain) addEmptyBlock(position types.Position) ( - *types.Block, error) { - bc.lock.Lock() - defer bc.lock.Unlock() - add := func() *types.Block { - emptyB, err := bc.prepareBlock(position, time.Time{}, true) - if err != nil || emptyB == nil { - // This helper is expected to be called when an empty block is ready - // to be confirmed. - panic(err) - } - bc.confirmBlock(emptyB) - bc.checkIfBlocksConfirmed() - return emptyB - } - if bc.lastConfirmed != nil { - if !position.Newer(bc.lastConfirmed.Position) { - bc.logger.Warn("Dropping empty block: older than tip", - "position", &position, - "last-confirmed", bc.lastConfirmed) - return nil, ErrBlockFromOlderPosition - } - if bc.lastConfirmed.Position.Height+1 == position.Height { - return add(), nil - } - } else if position.Height == types.GenesisHeight && position.Round == 0 { - return add(), nil - } else { - return nil, ErrInvalidBlockHeight - } - return nil, bc.addPendingBlockRecord(pendingBlockRecord{position, nil}) -} - -// 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.Randomness) == 0 && - !bc.setRandomnessFromPending(b) { - return ErrMissingRandomness - } - bc.lock.Lock() - defer bc.lock.Unlock() - confirmed := false - if bc.lastConfirmed != nil { - if !b.Position.Newer(bc.lastConfirmed.Position) { - bc.logger.Warn("Dropping block: older than tip", - "block", b, "last-confirmed", bc.lastConfirmed) - return nil - } - if bc.lastConfirmed.Position.Height+1 == b.Position.Height { - confirmed = true - } - } else if b.IsGenesis() { - confirmed = true - } - delete(bc.pendingRandomnesses, b.Position) - if !confirmed { - return bc.addPendingBlockRecord(pendingBlockRecord{b.Position, b}) - } - bc.confirmBlock(b) - bc.checkIfBlocksConfirmed() - return nil -} - -func (bc *blockChain) tipRound() uint64 { - bc.lock.RLock() - defer bc.lock.RUnlock() - if bc.lastConfirmed == nil { - return 0 - } - offset, tipConfig := uint64(0), bc.tipConfig() - if tipConfig.IsLastBlock(bc.lastConfirmed) { - offset++ - } - return bc.lastConfirmed.Position.Round + offset -} - -func (bc *blockChain) confirmed(h uint64) bool { - bc.lock.RLock() - defer bc.lock.RUnlock() - if bc.lastConfirmed != nil && bc.lastConfirmed.Position.Height >= h { - return true - } - r, found := bc.pendingBlocks.searchByHeight(h) - if !found { - return false - } - return r.block != nil -} - -func (bc *blockChain) nextBlock() (uint64, time.Time) { - bc.lock.RLock() - defer bc.lock.RUnlock() - // It's ok to access tip config directly without checking the existence of - // lastConfirmed block in the scenario of "nextBlock" method. - tip, config := bc.lastConfirmed, bc.configs[0] - if tip == nil { - return types.GenesisHeight, bc.dMoment - } - if tip != bc.lastDelivered { - // If tip is not delivered, we should not proceed to next block. - return notReadyHeight, time.Time{} - } - return tip.Position.Height + 1, tip.Timestamp.Add(config.minBlockInterval) -} - -func (bc *blockChain) pendingBlocksWithoutRandomness() []*types.Block { - bc.lock.RLock() - defer bc.lock.RUnlock() - blocks := make([]*types.Block, 0) - for _, b := range bc.confirmedBlocks { - if b.Position.Round < DKGDelayRound || - len(b.Randomness) > 0 || - bc.setRandomnessFromPending(b) { - continue - } - blocks = append(blocks, b) - } - for _, r := range bc.pendingBlocks { - if r.position.Round < DKGDelayRound { - continue - } - if r.block != nil && - len(r.block.Randomness) == 0 && - !bc.setRandomnessFromPending(r.block) { - blocks = append(blocks, r.block) - } - } - return blocks -} - -func (bc *blockChain) lastDeliveredBlock() *types.Block { - bc.lock.RLock() - defer bc.lock.RUnlock() - return bc.lastDelivered -} - -func (bc *blockChain) lastPendingBlock() *types.Block { - bc.lock.RLock() - defer bc.lock.RUnlock() - if len(bc.confirmedBlocks) == 0 { - return nil - } - return bc.confirmedBlocks[0] -} - -///////////////////////////////////////////// -// -// internal helpers -// -///////////////////////////////////////////// - -// findPendingBlock is a helper to find a block in either pending or confirmed -// state by position. -func (bc *blockChain) findPendingBlock(p types.Position) *types.Block { - if idx := sort.Search(len(bc.confirmedBlocks), func(i int) bool { - return !bc.confirmedBlocks[i].Position.Older(p) - }); idx != len(bc.confirmedBlocks) && - bc.confirmedBlocks[idx].Position.Equal(p) { - return bc.confirmedBlocks[idx] - } - pendingRec, _ := bc.pendingBlocks.searchByPosition(p) - return pendingRec.block -} - -func (bc *blockChain) addPendingBlockRecord(p pendingBlockRecord) error { - if err := bc.pendingBlocks.insert(p); err != nil { - if err == ErrDuplicatedPendingBlock { - // We need to ignore this error because BA might confirm duplicated - // blocks in position. - err = nil - } - return err - } - return nil -} - -func (bc *blockChain) checkIfBlocksConfirmed() { - var err error - for len(bc.pendingBlocks) > 0 { - if bc.pendingBlocks[0].position.Height < - bc.lastConfirmed.Position.Height+1 { - panic(fmt.Errorf("unexpected case %s %s", bc.lastConfirmed, - bc.pendingBlocks[0].position)) - } - if bc.pendingBlocks[0].position.Height > - bc.lastConfirmed.Position.Height+1 { - break - } - var pending pendingBlockRecord - pending, bc.pendingBlocks = bc.pendingBlocks[0], bc.pendingBlocks[1:] - nextTip := pending.block - if nextTip == nil { - if nextTip, err = bc.prepareBlock( - pending.position, time.Time{}, true); err != nil { - // It should not be error when prepare empty block for correct - // position. - panic(err) - } - } - bc.confirmBlock(nextTip) - } -} - -func (bc *blockChain) purgeConfig() { - for bc.configs[0].RoundID() < bc.lastConfirmed.Position.Round { - bc.configs = bc.configs[1:] - } - if bc.configs[0].RoundID() != bc.lastConfirmed.Position.Round { - panic(fmt.Errorf("mismatched tip config: %d %d", - bc.configs[0].RoundID(), bc.lastConfirmed.Position.Round)) - } -} - -func (bc *blockChain) verifyRandomness( - blockHash common.Hash, round uint64, randomness []byte) (bool, error) { - if round < DKGDelayRound { - return bytes.Compare(randomness, NoRand) == 0, nil - } - v, ok, err := bc.vGetter.UpdateAndGet(round) - if err != nil { - return false, err - } - if !ok { - return false, ErrTSigNotReady - } - return v.VerifySignature(blockHash, crypto.Signature{ - Type: "bls", - Signature: randomness}), nil -} - -func (bc *blockChain) prepareBlock(position types.Position, - proposeTime time.Time, empty bool) (b *types.Block, err error) { - b = &types.Block{Position: position, Timestamp: proposeTime} - tip := bc.lastConfirmed - // Make sure we can propose a block at expected position for callers. - if tip == nil { - if bc.configs[0].RoundID() != uint64(0) { - panic(fmt.Errorf( - "Genesis config should be ready when preparing genesis: %d", - bc.configs[0].RoundID())) - } - // It should be the case for genesis block. - if !position.Equal(types.Position{Height: types.GenesisHeight}) { - b, err = nil, ErrNotGenesisBlock - return - } - minExpectedTime := bc.dMoment.Add(bc.configs[0].minBlockInterval) - if empty { - b.Timestamp = minExpectedTime - } else { - bc.logger.Debug("Calling genesis Application.PreparePayload") - if b.Payload, err = bc.app.PreparePayload(b.Position); err != nil { - b = nil - return - } - bc.logger.Debug("Calling genesis Application.PrepareWitness") - if b.Witness, err = bc.app.PrepareWitness(0); err != nil { - b = nil - return - } - if proposeTime.Before(minExpectedTime) { - b.Timestamp = minExpectedTime - } - } - } else { - tipConfig := bc.tipConfig() - if tip.Position.Height+1 != position.Height { - b, err = nil, ErrNotFollowTipPosition - return - } - if tipConfig.IsLastBlock(tip) { - if tip.Position.Round+1 != position.Round { - b, err = nil, ErrRoundNotSwitch - return - } - } else { - if tip.Position.Round != position.Round { - b, err = nil, ErrInvalidRoundID - return - } - } - minExpectedTime := tip.Timestamp.Add(bc.configs[0].minBlockInterval) - b.ParentHash = tip.Hash - if !empty { - bc.logger.Debug("Calling Application.PreparePayload", - "position", b.Position) - if b.Payload, err = bc.app.PreparePayload(b.Position); err != nil { - b = nil - return - } - bc.logger.Debug("Calling Application.PrepareWitness", - "height", tip.Witness.Height) - if b.Witness, err = bc.app.PrepareWitness( - tip.Witness.Height); err != nil { - b = nil - return - } - if b.Timestamp.Before(minExpectedTime) { - b.Timestamp = minExpectedTime - } - } else { - b.Witness.Height = tip.Witness.Height - b.Witness.Data = make([]byte, len(tip.Witness.Data)) - copy(b.Witness.Data, tip.Witness.Data) - b.Timestamp = minExpectedTime - } - } - if empty { - if b.Hash, err = utils.HashBlock(b); err != nil { - b = nil - return - } - } else { - if err = bc.signer.SignBlock(b); err != nil { - b = nil - return - } - } - return -} - -func (bc *blockChain) tipConfig() blockChainConfig { - if bc.lastConfirmed == nil { - panic(fmt.Errorf("attempting to access config without tip")) - } - if bc.lastConfirmed.Position.Round != bc.configs[0].RoundID() { - panic(fmt.Errorf("inconsist config and tip: %d %d", - bc.lastConfirmed.Position.Round, bc.configs[0].RoundID())) - } - return bc.configs[0] -} - -func (bc *blockChain) confirmBlock(b *types.Block) { - if bc.lastConfirmed != nil && - bc.lastConfirmed.Position.Height+1 != b.Position.Height { - panic(fmt.Errorf("confirmed blocks not continuous in height: %s %s", - bc.lastConfirmed, b)) - } - bc.logger.Debug("Calling Application.BlockConfirmed", "block", b) - bc.app.BlockConfirmed(*b) - bc.lastConfirmed = b - bc.confirmedBlocks = append(bc.confirmedBlocks, b) - bc.purgeConfig() -} - -func (bc *blockChain) setRandomnessFromPending(b *types.Block) bool { - if r, exist := bc.pendingRandomnesses[b.Position]; exist { - b.Randomness = r - delete(bc.pendingRandomnesses, b.Position) - return true - } - return false -} - -func (bc *blockChain) processAgreementResult(result *types.AgreementResult) error { - if result.Position.Round < DKGDelayRound { - return nil - } - if !result.Position.Newer(bc.lastPosition) { - return ErrSkipButNoError - } - ok, err := bc.verifyRandomness( - result.BlockHash, result.Position.Round, result.Randomness) - if err != nil { - return err - } - if !ok { - return ErrIncorrectAgreementResult - } - bc.lock.Lock() - defer bc.lock.Unlock() - if !result.Position.Newer(bc.lastDelivered.Position) { - return nil - } - bc.pendingRandomnesses[result.Position] = result.Randomness - bc.lastPosition = bc.lastDelivered.Position - return nil -} - -func (bc *blockChain) addBlockRandomness(pos types.Position, rand []byte) { - if pos.Round < DKGDelayRound { - return - } - bc.lock.Lock() - defer bc.lock.Unlock() - if !pos.Newer(bc.lastDelivered.Position) { - return - } - bc.pendingRandomnesses[pos] = rand -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go deleted file mode 100644 index 3b4cdbbc8..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/configuration-chain.go +++ /dev/null @@ -1,795 +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 core - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "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" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// Errors for configuration chain.. -var ( - ErrDKGNotRegistered = fmt.Errorf( - "not yet registered in DKG protocol") - ErrTSigAlreadyRunning = fmt.Errorf( - "tsig is already running") - ErrDKGNotReady = fmt.Errorf( - "DKG is not ready") - ErrSkipButNoError = fmt.Errorf( - "skip but no error") - ErrDKGAborted = fmt.Errorf( - "DKG is aborted") -) - -// ErrMismatchDKG represent an attempt to run DKG protocol is failed because -// the register DKG protocol is mismatched, interms of round and resetCount. -type ErrMismatchDKG struct { - expectRound, expectReset uint64 - actualRound, actualReset uint64 -} - -func (e ErrMismatchDKG) Error() string { - return fmt.Sprintf( - "mismatch DKG, abort running: expect(%d %d) actual(%d %d)", - e.expectRound, e.expectReset, e.actualRound, e.actualReset) -} - -type dkgStepFn func(round uint64, reset uint64) error - -type configurationChain struct { - ID types.NodeID - recv dkgReceiver - gov Governance - dkg *dkgProtocol - dkgRunPhases []dkgStepFn - logger common.Logger - dkgLock sync.RWMutex - dkgSigner map[uint64]*dkgShareSecret - npks map[uint64]*typesDKG.NodePublicKeys - complaints []*typesDKG.Complaint - dkgResult sync.RWMutex - tsig map[common.Hash]*tsigProtocol - tsigTouched map[common.Hash]struct{} - tsigReady *sync.Cond - cache *utils.NodeSetCache - db db.Database - notarySet map[types.NodeID]struct{} - mpkReady bool - pendingPrvShare map[types.NodeID]*typesDKG.PrivateShare - // TODO(jimmy-dexon): add timeout to pending psig. - pendingPsig map[common.Hash][]*typesDKG.PartialSignature - prevHash common.Hash - dkgCtx context.Context - dkgCtxCancel context.CancelFunc - dkgRunning bool -} - -func newConfigurationChain( - ID types.NodeID, - recv dkgReceiver, - gov Governance, - cache *utils.NodeSetCache, - dbInst db.Database, - logger common.Logger) *configurationChain { - configurationChain := &configurationChain{ - ID: ID, - recv: recv, - gov: gov, - logger: logger, - dkgSigner: make(map[uint64]*dkgShareSecret), - npks: make(map[uint64]*typesDKG.NodePublicKeys), - tsig: make(map[common.Hash]*tsigProtocol), - tsigTouched: make(map[common.Hash]struct{}), - tsigReady: sync.NewCond(&sync.Mutex{}), - cache: cache, - db: dbInst, - pendingPsig: make(map[common.Hash][]*typesDKG.PartialSignature), - } - configurationChain.initDKGPhasesFunc() - return configurationChain -} - -func (cc *configurationChain) abortDKG( - parentCtx context.Context, - round, reset uint64) bool { - cc.dkgLock.Lock() - defer cc.dkgLock.Unlock() - if cc.dkg != nil { - return cc.abortDKGNoLock(parentCtx, round, reset) - } - return false -} - -func (cc *configurationChain) abortDKGNoLock( - ctx context.Context, - round, reset uint64) bool { - if cc.dkg.round > round || - (cc.dkg.round == round && cc.dkg.reset > reset) { - cc.logger.Error("Newer DKG already is registered", - "round", round, - "reset", reset) - return false - } - cc.logger.Error("Previous DKG is not finished", - "round", round, - "reset", reset, - "previous-round", cc.dkg.round, - "previous-reset", cc.dkg.reset) - // Abort DKG routine in previous round. - cc.logger.Error("Aborting DKG in previous round", - "round", round, - "previous-round", cc.dkg.round) - // Notify current running DKG protocol to abort. - if cc.dkgCtxCancel != nil { - cc.dkgCtxCancel() - } - cc.dkgLock.Unlock() - // Wait for current running DKG protocol aborting. - for { - cc.dkgLock.Lock() - if cc.dkgRunning == false { - cc.dkg = nil - break - } - select { - case <-ctx.Done(): - return false - case <-time.After(100 * time.Millisecond): - } - cc.dkgLock.Unlock() - } - cc.logger.Error("Previous DKG aborted", - "round", round, - "reset", reset) - return cc.dkg == nil -} - -func (cc *configurationChain) registerDKG( - parentCtx context.Context, - round, reset uint64, - threshold int) { - cc.dkgLock.Lock() - defer cc.dkgLock.Unlock() - if cc.dkg != nil { - // Make sure we only proceed when cc.dkg is nil. - if !cc.abortDKGNoLock(parentCtx, round, reset) { - return - } - select { - case <-parentCtx.Done(): - return - default: - } - if cc.dkg != nil { - // This panic would only raise when multiple attampts to register - // a DKG protocol at the same time. - panic(ErrMismatchDKG{ - expectRound: round, - expectReset: reset, - actualRound: cc.dkg.round, - actualReset: cc.dkg.reset, - }) - } - } - notarySet, err := cc.cache.GetNotarySet(round) - if err != nil { - cc.logger.Error("Error getting notary set from cache", "error", err) - return - } - 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) - cc.dkgCtx, cc.dkgCtxCancel = context.WithCancel(parentCtx) - if err != nil { - panic(err) - } - if cc.dkg == nil { - cc.dkg = newDKGProtocol( - cc.ID, - cc.recv, - round, - reset, - threshold) - - err = cc.db.PutOrUpdateDKGProtocol(cc.dkg.toDKGProtocolInfo()) - if err != nil { - cc.logger.Error("Error put or update DKG protocol", "error", - err) - return - } - } - - go func() { - ticker := newTicker(cc.gov, round, TickerDKG) - defer ticker.Stop() - <-ticker.Tick() - cc.dkgLock.Lock() - defer cc.dkgLock.Unlock() - if cc.dkg != nil && cc.dkg.round == round && cc.dkg.reset == reset { - cc.dkg.proposeMPKReady() - } - }() -} - -func (cc *configurationChain) runDKGPhaseOne(round uint64, reset uint64) error { - if cc.dkg.round < round || - (cc.dkg.round == round && cc.dkg.reset < reset) { - return ErrDKGNotRegistered - } - if cc.dkg.round != round || cc.dkg.reset != reset { - cc.logger.Warn("DKG canceled", "round", round, "reset", reset) - return ErrSkipButNoError - } - cc.logger.Debug("Calling Governance.IsDKGFinal", "round", round) - if cc.gov.IsDKGFinal(round) { - cc.logger.Warn("DKG already final", "round", round) - return ErrSkipButNoError - } - cc.logger.Debug("Calling Governance.IsDKGMPKReady", "round", round) - var err error - for err == nil && !cc.gov.IsDKGMPKReady(round) { - cc.dkgLock.Unlock() - cc.logger.Debug("DKG MPKs are not ready yet. Try again later...", - "nodeID", cc.ID, - "round", round) - select { - case <-cc.dkgCtx.Done(): - err = ErrDKGAborted - case <-time.After(500 * time.Millisecond): - } - cc.dkgLock.Lock() - } - return err -} - -func (cc *configurationChain) runDKGPhaseTwoAndThree( - round uint64, reset uint64) error { - // Check if this node successfully join the protocol. - cc.logger.Debug("Calling Governance.DKGMasterPublicKeys", "round", round) - mpks := cc.gov.DKGMasterPublicKeys(round) - inProtocol := false - for _, mpk := range mpks { - if mpk.ProposerID == cc.ID { - inProtocol = true - break - } - } - if !inProtocol { - cc.logger.Warn("Failed to join DKG protocol", - "round", round, - "reset", reset) - return ErrSkipButNoError - } - // Phase 2(T = 0): Exchange DKG secret key share. - if err := cc.dkg.processMasterPublicKeys(mpks); err != nil { - cc.logger.Error("Failed to process master public key", - "round", round, - "reset", reset, - "error", err) - } - cc.mpkReady = true - // The time to process private share might be long, check aborting before - // get into that loop. - select { - case <-cc.dkgCtx.Done(): - return ErrDKGAborted - default: - } - for _, prvShare := range cc.pendingPrvShare { - if err := cc.dkg.processPrivateShare(prvShare); err != nil { - cc.logger.Error("Failed to process private share", - "round", round, - "reset", reset, - "error", err) - } - } - - // Phase 3(T = 0~λ): Propose complaint. - // Propose complaint is done in `processMasterPublicKeys`. - return nil -} - -func (cc *configurationChain) runDKGPhaseFour() { - // Phase 4(T = λ): Propose nack complaints. - cc.dkg.proposeNackComplaints() -} - -func (cc *configurationChain) runDKGPhaseFiveAndSix(round uint64, reset uint64) { - // Phase 5(T = 2λ): Propose Anti nack complaint. - cc.logger.Debug("Calling Governance.DKGComplaints", "round", round) - cc.complaints = cc.gov.DKGComplaints(round) - if err := cc.dkg.processNackComplaints(cc.complaints); err != nil { - cc.logger.Error("Failed to process NackComplaint", - "round", round, - "reset", reset, - "error", err) - } - - // Phase 6(T = 3λ): Rebroadcast anti nack complaint. - // Rebroadcast is done in `processPrivateShare`. -} - -func (cc *configurationChain) runDKGPhaseSeven() { - // Phase 7(T = 4λ): Enforce complaints and nack complaints. - cc.dkg.enforceNackComplaints(cc.complaints) - // Enforce complaint is done in `processPrivateShare`. -} - -func (cc *configurationChain) runDKGPhaseEight() { - // Phase 8(T = 5λ): DKG finalize. - cc.dkg.proposeFinalize() -} - -func (cc *configurationChain) runDKGPhaseNine(round uint64, reset uint64) error { - // Phase 9(T = 6λ): DKG is ready. - // Normally, IsDKGFinal would return true here. Use this for in case of - // unexpected network fluctuation and ensure the robustness of DKG protocol. - cc.logger.Debug("Calling Governance.IsDKGFinal", "round", round) - var err error - for err == nil && !cc.gov.IsDKGFinal(round) { - cc.dkgLock.Unlock() - cc.logger.Debug("DKG is not ready yet. Try again later...", - "nodeID", cc.ID.String()[:6], - "round", round, - "reset", reset) - select { - case <-cc.dkgCtx.Done(): - err = ErrDKGAborted - case <-time.After(500 * time.Millisecond): - } - cc.dkgLock.Lock() - } - if err != nil { - return err - } - cc.logger.Debug("Calling Governance.DKGMasterPublicKeys", "round", round) - cc.logger.Debug("Calling Governance.DKGComplaints", "round", round) - npks, err := typesDKG.NewNodePublicKeys(round, - cc.gov.DKGMasterPublicKeys(round), - cc.gov.DKGComplaints(round), - cc.dkg.threshold) - if err != nil { - return err - } - qualifies := "" - for nID := range npks.QualifyNodeIDs { - qualifies += fmt.Sprintf("%s ", nID.String()[:6]) - } - cc.logger.Info("Qualify Nodes", - "nodeID", cc.ID, - "round", round, - "reset", reset, - "count", len(npks.QualifyIDs), - "qualifies", qualifies) - if _, exist := npks.QualifyNodeIDs[cc.ID]; !exist { - cc.logger.Warn("Self is not in Qualify Nodes", - "round", round, - "reset", reset) - return nil - } - signer, err := cc.dkg.recoverShareSecret(npks.QualifyIDs) - if err != nil { - return err - } - // Save private shares to DB. - if err = - cc.db.PutDKGPrivateKey(round, reset, *signer.privateKey); err != nil { - return err - } - cc.dkg.proposeSuccess() - cc.dkgResult.Lock() - defer cc.dkgResult.Unlock() - cc.dkgSigner[round] = signer - cc.npks[round] = npks - return nil -} - -func (cc *configurationChain) initDKGPhasesFunc() { - cc.dkgRunPhases = []dkgStepFn{ - func(round uint64, reset uint64) error { - return cc.runDKGPhaseOne(round, reset) - }, - func(round uint64, reset uint64) error { - return cc.runDKGPhaseTwoAndThree(round, reset) - }, - func(round uint64, reset uint64) error { - cc.runDKGPhaseFour() - return nil - }, - func(round uint64, reset uint64) error { - cc.runDKGPhaseFiveAndSix(round, reset) - return nil - }, - func(round uint64, reset uint64) error { - cc.runDKGPhaseSeven() - return nil - }, - func(round uint64, reset uint64) error { - cc.runDKGPhaseEight() - return nil - }, - func(round uint64, reset uint64) error { - return cc.runDKGPhaseNine(round, reset) - }, - } -} - -func (cc *configurationChain) runDKG( - round uint64, reset uint64, event *common.Event, - dkgBeginHeight, dkgHeight uint64) (err error) { - // Check if corresponding DKG signer is ready. - if _, _, err = cc.getDKGInfo(round, false); err == nil { - return ErrSkipButNoError - } - cfg := utils.GetConfigWithPanic(cc.gov, round, cc.logger) - phaseHeight := uint64( - cfg.LambdaDKG.Nanoseconds() / cfg.MinBlockInterval.Nanoseconds()) - skipPhase := int(dkgHeight / phaseHeight) - cc.logger.Info("Skipping DKG phase", "phase", skipPhase) - cc.dkgLock.Lock() - defer cc.dkgLock.Unlock() - if cc.dkg == nil { - return ErrDKGNotRegistered - } - // Make sure the existed dkgProtocol is expected one. - if cc.dkg.round != round || cc.dkg.reset != reset { - return ErrMismatchDKG{ - expectRound: round, - expectReset: reset, - actualRound: cc.dkg.round, - actualReset: cc.dkg.reset, - } - } - if cc.dkgRunning { - panic(fmt.Errorf("duplicated call to runDKG: %d %d", round, reset)) - } - cc.dkgRunning = true - defer func() { - // Here we should hold the cc.dkgLock, reset cc.dkg to nil when done. - if cc.dkg != nil { - cc.dkg = nil - } - cc.dkgRunning = false - }() - wg := sync.WaitGroup{} - var dkgError error - // Make a copy of cc.dkgCtx so each phase function can refer to the correct - // context. - ctx := cc.dkgCtx - cc.dkg.step = skipPhase - for i := skipPhase; i < len(cc.dkgRunPhases); i++ { - wg.Add(1) - event.RegisterHeight(dkgBeginHeight+phaseHeight*uint64(i), func(uint64) { - go func() { - defer wg.Done() - cc.dkgLock.Lock() - defer cc.dkgLock.Unlock() - if dkgError != nil { - return - } - select { - case <-ctx.Done(): - dkgError = ErrDKGAborted - return - default: - } - - err := cc.dkgRunPhases[cc.dkg.step](round, reset) - if err == nil || err == ErrSkipButNoError { - err = nil - cc.dkg.step++ - err = cc.db.PutOrUpdateDKGProtocol(cc.dkg.toDKGProtocolInfo()) - if err != nil { - cc.logger.Error("Failed to save DKG Protocol", - "step", cc.dkg.step, - "error", err) - } - } - if err != nil && dkgError == nil { - dkgError = err - } - }() - }) - } - cc.dkgLock.Unlock() - wgChan := make(chan struct{}, 1) - go func() { - wg.Wait() - wgChan <- struct{}{} - }() - select { - case <-cc.dkgCtx.Done(): - case <-wgChan: - } - cc.dkgLock.Lock() - select { - case <-cc.dkgCtx.Done(): - return ErrDKGAborted - default: - } - return dkgError -} - -func (cc *configurationChain) isDKGFinal(round uint64) bool { - if !cc.gov.IsDKGFinal(round) { - return false - } - _, _, err := cc.getDKGInfo(round, false) - return err == nil -} - -func (cc *configurationChain) getDKGInfo( - round uint64, ignoreSigner bool) ( - *typesDKG.NodePublicKeys, *dkgShareSecret, error) { - getFromCache := func() (*typesDKG.NodePublicKeys, *dkgShareSecret) { - cc.dkgResult.RLock() - defer cc.dkgResult.RUnlock() - npks := cc.npks[round] - signer := cc.dkgSigner[round] - return npks, signer - } - npks, signer := getFromCache() - if npks == nil || (!ignoreSigner && signer == nil) { - if err := cc.recoverDKGInfo(round, ignoreSigner); err != nil { - return nil, nil, err - } - npks, signer = getFromCache() - } - if npks == nil || (!ignoreSigner && signer == nil) { - return nil, nil, ErrDKGNotReady - } - return npks, signer, nil -} - -func (cc *configurationChain) recoverDKGInfo( - round uint64, ignoreSigner bool) error { - var npksExists, signerExists bool - func() { - cc.dkgResult.Lock() - defer cc.dkgResult.Unlock() - _, signerExists = cc.dkgSigner[round] - _, npksExists = cc.npks[round] - }() - if signerExists && npksExists { - return nil - } - if !cc.gov.IsDKGFinal(round) { - return ErrDKGNotReady - } - - threshold := utils.GetDKGThreshold( - utils.GetConfigWithPanic(cc.gov, round, cc.logger)) - cc.logger.Debug("Calling Governance.DKGMasterPublicKeys for recoverDKGInfo", - "round", round) - mpk := cc.gov.DKGMasterPublicKeys(round) - cc.logger.Debug("Calling Governance.DKGComplaints for recoverDKGInfo", - "round", round) - comps := cc.gov.DKGComplaints(round) - qualifies, _, err := typesDKG.CalcQualifyNodes(mpk, comps, threshold) - if err != nil { - return err - } - if len(qualifies) < - utils.GetDKGValidThreshold(utils.GetConfigWithPanic( - cc.gov, round, cc.logger)) { - return typesDKG.ErrNotReachThreshold - } - - if !npksExists { - npks, err := typesDKG.NewNodePublicKeys(round, - cc.gov.DKGMasterPublicKeys(round), - cc.gov.DKGComplaints(round), - threshold) - if err != nil { - cc.logger.Warn("Failed to create DKGNodePublicKeys", - "round", round, "error", err) - return err - } - func() { - cc.dkgResult.Lock() - defer cc.dkgResult.Unlock() - cc.npks[round] = npks - }() - } - if !signerExists && !ignoreSigner { - reset := cc.gov.DKGResetCount(round) - // Check if we have private shares in DB. - prvKey, err := cc.db.GetDKGPrivateKey(round, reset) - if err != nil { - cc.logger.Warn("Failed to create DKGPrivateKey", - "round", round, "error", err) - dkgProtocolInfo, err := cc.db.GetDKGProtocol() - if err != nil { - cc.logger.Warn("Unable to recover DKGProtocolInfo", - "round", round, "error", err) - return err - } - if dkgProtocolInfo.Round != round { - cc.logger.Warn("DKGProtocolInfo round mismatch", - "round", round, "infoRound", dkgProtocolInfo.Round) - return err - } - prvKeyRecover, err := - dkgProtocolInfo.PrvShares.RecoverPrivateKey(qualifies) - if err != nil { - cc.logger.Warn("Failed to recover DKGPrivateKey", - "round", round, "error", err) - return err - } - if err = cc.db.PutDKGPrivateKey( - round, reset, *prvKeyRecover); err != nil { - cc.logger.Warn("Failed to save DKGPrivateKey", - "round", round, "error", err) - } - prvKey = *prvKeyRecover - } - func() { - cc.dkgResult.Lock() - defer cc.dkgResult.Unlock() - cc.dkgSigner[round] = &dkgShareSecret{ - privateKey: &prvKey, - } - }() - } - return nil -} - -func (cc *configurationChain) preparePartialSignature( - round uint64, hash common.Hash) (*typesDKG.PartialSignature, error) { - _, signer, _ := cc.getDKGInfo(round, false) - if signer == nil { - return nil, ErrDKGNotReady - } - return &typesDKG.PartialSignature{ - ProposerID: cc.ID, - Round: round, - Hash: hash, - PartialSignature: signer.sign(hash), - }, nil -} - -func (cc *configurationChain) touchTSigHash(hash common.Hash) (first bool) { - cc.tsigReady.L.Lock() - defer cc.tsigReady.L.Unlock() - _, exist := cc.tsigTouched[hash] - cc.tsigTouched[hash] = struct{}{} - return !exist -} - -func (cc *configurationChain) untouchTSigHash(hash common.Hash) { - cc.tsigReady.L.Lock() - defer cc.tsigReady.L.Unlock() - delete(cc.tsigTouched, hash) -} - -func (cc *configurationChain) runTSig( - round uint64, hash common.Hash, wait time.Duration) ( - crypto.Signature, error) { - npks, _, _ := cc.getDKGInfo(round, false) - if npks == nil { - return crypto.Signature{}, ErrDKGNotReady - } - cc.tsigReady.L.Lock() - defer cc.tsigReady.L.Unlock() - if _, exist := cc.tsig[hash]; exist { - return crypto.Signature{}, ErrTSigAlreadyRunning - } - cc.tsig[hash] = newTSigProtocol(npks, hash) - pendingPsig := cc.pendingPsig[hash] - delete(cc.pendingPsig, hash) - go func() { - for _, psig := range pendingPsig { - if err := cc.processPartialSignature(psig); err != nil { - cc.logger.Error("Failed to process partial signature", - "nodeID", cc.ID, - "error", err) - } - } - }() - timeout := make(chan struct{}, 1) - go func() { - time.Sleep(wait) - timeout <- struct{}{} - cc.tsigReady.Broadcast() - }() - var signature crypto.Signature - var err error - for func() bool { - signature, err = cc.tsig[hash].signature() - select { - case <-timeout: - return false - default: - } - return err == ErrNotEnoughtPartialSignatures - }() { - cc.tsigReady.Wait() - } - delete(cc.tsig, hash) - if err != nil { - return crypto.Signature{}, err - } - return signature, nil -} - -func (cc *configurationChain) runCRSTSig( - round uint64, crs common.Hash) ([]byte, error) { - sig, err := cc.runTSig(round, crs, cc.gov.Configuration(round).LambdaDKG*5) - cc.logger.Info("CRS", - "nodeID", cc.ID, - "round", round+1, - "signature", sig) - return sig.Signature[:], err -} - -func (cc *configurationChain) processPrivateShare( - prvShare *typesDKG.PrivateShare) error { - cc.dkgLock.Lock() - defer cc.dkgLock.Unlock() - if cc.dkg == nil { - return nil - } - if _, exist := cc.notarySet[prvShare.ProposerID]; !exist { - return ErrNotDKGParticipant - } - if !cc.mpkReady { - // TODO(jimmy-dexon): remove duplicated signature check in dkg module. - ok, err := utils.VerifyDKGPrivateShareSignature(prvShare) - if err != nil { - return err - } - if !ok { - return ErrIncorrectPrivateShareSignature - } - cc.pendingPrvShare[prvShare.ProposerID] = prvShare - return nil - } - return cc.dkg.processPrivateShare(prvShare) -} - -func (cc *configurationChain) processPartialSignature( - psig *typesDKG.PartialSignature) error { - cc.tsigReady.L.Lock() - defer cc.tsigReady.L.Unlock() - if _, exist := cc.tsig[psig.Hash]; !exist { - ok, err := utils.VerifyDKGPartialSignatureSignature(psig) - if err != nil { - return err - } - if !ok { - return ErrIncorrectPartialSignatureSignature - } - cc.pendingPsig[psig.Hash] = append(cc.pendingPsig[psig.Hash], psig) - return nil - } - if err := cc.tsig[psig.Hash].processPartialSignature(psig); err != nil { - return err - } - cc.tsigReady.Broadcast() - return nil -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go deleted file mode 100644 index fd8456487..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go +++ /dev/null @@ -1,1567 +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 core - -import ( - "context" - "encoding/hex" - "fmt" - "sync" - "time" - - "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" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// Errors for consensus core. -var ( - ErrProposerNotInNodeSet = fmt.Errorf( - "proposer is not in node set") - ErrIncorrectHash = fmt.Errorf( - "hash of block is incorrect") - ErrIncorrectSignature = fmt.Errorf( - "signature of block is incorrect") - ErrUnknownBlockProposed = fmt.Errorf( - "unknown block is proposed") - ErrIncorrectAgreementResultPosition = fmt.Errorf( - "incorrect agreement result position") - ErrNotEnoughVotes = fmt.Errorf( - "not enought votes") - ErrCRSNotReady = fmt.Errorf( - "CRS not ready") - ErrConfigurationNotReady = fmt.Errorf( - "Configuration not ready") - ErrIncorrectBlockRandomness = fmt.Errorf( - "randomness of block is incorrect") - ErrCannotVerifyBlockRandomness = fmt.Errorf( - "cannot verify block randomness") -) - -type selfAgreementResult types.AgreementResult - -// consensusBAReceiver implements agreementReceiver. -type consensusBAReceiver struct { - consensus *Consensus - agreementModule *agreement - emptyBlockHashMap *sync.Map - isNotary bool - restartNotary chan types.Position - npks *typesDKG.NodePublicKeys - psigSigner *dkgShareSecret -} - -func (recv *consensusBAReceiver) emptyBlockHash(pos types.Position) ( - common.Hash, error) { - hashVal, ok := recv.emptyBlockHashMap.Load(pos) - if ok { - return hashVal.(common.Hash), nil - } - emptyBlock, err := recv.consensus.bcModule.prepareBlock( - pos, time.Time{}, true) - if err != nil { - return common.Hash{}, err - } - hash, err := utils.HashBlock(emptyBlock) - if err != nil { - return common.Hash{}, err - } - recv.emptyBlockHashMap.Store(pos, hash) - return hash, nil -} - -func (recv *consensusBAReceiver) VerifyPartialSignature(vote *types.Vote) ( - bool, bool) { - if vote.Position.Round >= DKGDelayRound && vote.BlockHash != types.SkipBlockHash { - if vote.Type == types.VoteCom || vote.Type == types.VoteFastCom { - if recv.npks == nil { - recv.consensus.logger.Debug( - "Unable to verify psig, npks is nil", - "vote", vote) - return false, false - } - if vote.Position.Round != recv.npks.Round { - recv.consensus.logger.Debug( - "Unable to verify psig, round of npks mismatch", - "vote", vote, - "npksRound", recv.npks.Round) - return false, false - } - pubKey, exist := recv.npks.PublicKeys[vote.ProposerID] - if !exist { - recv.consensus.logger.Debug( - "Unable to verify psig, proposer is not qualified", - "vote", vote) - return false, true - } - blockHash := vote.BlockHash - if blockHash == types.NullBlockHash { - var err error - blockHash, err = recv.emptyBlockHash(vote.Position) - if err != nil { - recv.consensus.logger.Error( - "Failed to verify vote for empty block", - "position", vote.Position, - "error", err) - return false, true - } - } - return pubKey.VerifySignature( - blockHash, crypto.Signature(vote.PartialSignature)), true - } - } - return len(vote.PartialSignature.Signature) == 0, true -} - -func (recv *consensusBAReceiver) ProposeVote(vote *types.Vote) { - if !recv.isNotary { - return - } - if recv.psigSigner != nil && - vote.BlockHash != types.SkipBlockHash { - if vote.Type == types.VoteCom || vote.Type == types.VoteFastCom { - if vote.BlockHash == types.NullBlockHash { - hash, err := recv.emptyBlockHash(vote.Position) - if err != nil { - recv.consensus.logger.Error( - "Failed to propose vote for empty block", - "position", vote.Position, - "error", err) - return - } - vote.PartialSignature = recv.psigSigner.sign(hash) - } 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 - } - go func() { - if err := recv.agreementModule.processVote(vote); err != nil { - recv.consensus.logger.Error("Failed to process self vote", - "error", err, - "vote", vote) - return - } - recv.consensus.logger.Debug("Calling Network.BroadcastVote", - "vote", vote) - recv.consensus.network.BroadcastVote(vote) - }() -} - -func (recv *consensusBAReceiver) ProposeBlock() common.Hash { - if !recv.isNotary { - return common.Hash{} - } - block, err := recv.consensus.proposeBlock(recv.agreementModule.agreementID()) - if err != nil || block == nil { - recv.consensus.logger.Error("Unable to propose block", "error", err) - return types.NullBlockHash - } - go func() { - if err := recv.consensus.preProcessBlock(block); err != nil { - recv.consensus.logger.Error("Failed to pre-process block", "error", err) - return - } - recv.consensus.logger.Debug("Calling Network.BroadcastBlock", - "block", block) - recv.consensus.network.BroadcastBlock(block) - }() - return block.Hash -} - -func (recv *consensusBAReceiver) ConfirmBlock( - hash common.Hash, votes map[types.NodeID]*types.Vote) { - var ( - block *types.Block - aID = recv.agreementModule.agreementID() - ) - - isEmptyBlockConfirmed := hash == common.Hash{} - if isEmptyBlockConfirmed { - recv.consensus.logger.Info("Empty block is confirmed", "position", aID) - var err error - block, err = recv.consensus.bcModule.addEmptyBlock(aID) - if err != nil { - recv.consensus.logger.Error("Add position for empty failed", - "error", err) - return - } - if block == nil { - // The empty block's parent is not found locally, thus we can't - // propose it at this moment. - // - // We can only rely on block pulling upon receiving - // types.AgreementResult from the next position. - recv.consensus.logger.Warn( - "An empty block is confirmed without its parent", - "position", aID) - return - } - } else { - var exist bool - block, exist = recv.agreementModule.findBlockNoLock(hash) - if !exist { - recv.consensus.logger.Debug("Unknown block confirmed", - "hash", hash.String()[:6]) - ch := make(chan *types.Block) - func() { - recv.consensus.lock.Lock() - defer recv.consensus.lock.Unlock() - recv.consensus.baConfirmedBlock[hash] = ch - }() - go func() { - hashes := common.Hashes{hash} - PullBlockLoop: - for { - recv.consensus.logger.Debug("Calling Network.PullBlock for BA block", - "hash", hash) - recv.consensus.network.PullBlocks(hashes) - select { - case block = <-ch: - break PullBlockLoop - case <-time.After(1 * time.Second): - } - } - recv.consensus.logger.Debug("Receive unknown block", - "hash", hash.String()[:6], - "position", block.Position) - recv.agreementModule.addCandidateBlock(block) - recv.agreementModule.lock.Lock() - defer recv.agreementModule.lock.Unlock() - recv.ConfirmBlock(block.Hash, votes) - }() - return - } - } - - if len(votes) == 0 && len(block.Randomness) == 0 { - recv.consensus.logger.Error("No votes to recover randomness", - "block", block) - } else if votes != nil { - 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 block.Position.Round >= DKGDelayRound { - ID, exist := recv.npks.IDMap[vote.ProposerID] - if !exist { - continue - } - IDs = append(IDs, ID) - psigs = append(psigs, vote.PartialSignature) - } else { - voteList = append(voteList, *vote) - } - } - if block.Position.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.Randomness = rand.Signature[:] - } - } else { - block.Randomness = NoRand - } - - if recv.isNotary { - result := &types.AgreementResult{ - BlockHash: block.Hash, - Position: block.Position, - Votes: voteList, - IsEmptyBlock: isEmptyBlockConfirmed, - Randomness: block.Randomness, - } - // touchAgreementResult does not support concurrent access. - go func() { - recv.consensus.priorityMsgChan <- (*selfAgreementResult)(result) - }() - recv.consensus.logger.Debug("Broadcast AgreementResult", - "result", result) - recv.consensus.network.BroadcastAgreementResult(result) - if block.IsEmpty() { - recv.consensus.bcModule.addBlockRandomness( - block.Position, block.Randomness) - } - if block.Position.Round >= DKGDelayRound { - recv.consensus.logger.Debug( - "Broadcast finalized block", - "block", block) - recv.consensus.network.BroadcastBlock(block) - } - } - } - - if !block.IsGenesis() && - !recv.consensus.bcModule.confirmed(block.Position.Height-1) { - go func(hash common.Hash) { - parentHash := hash - for { - recv.consensus.logger.Warn("Parent block not confirmed", - "parent-hash", parentHash.String()[:6], - "cur-position", block.Position) - ch := make(chan *types.Block) - if !func() bool { - recv.consensus.lock.Lock() - defer recv.consensus.lock.Unlock() - if _, exist := recv.consensus.baConfirmedBlock[parentHash]; exist { - return false - } - recv.consensus.baConfirmedBlock[parentHash] = ch - return true - }() { - return - } - var block *types.Block - PullBlockLoop: - for { - recv.consensus.logger.Debug("Calling Network.PullBlock for parent", - "hash", parentHash) - recv.consensus.network.PullBlocks(common.Hashes{parentHash}) - select { - case block = <-ch: - break PullBlockLoop - case <-time.After(1 * time.Second): - } - } - recv.consensus.logger.Info("Receive parent block", - "parent-hash", block.ParentHash.String()[:6], - "cur-position", block.Position) - if !block.IsFinalized() { - // TODO(jimmy): use a seperate message to pull finalized - // block. Here, we pull it again as workaround. - continue - } - recv.consensus.processBlockChan <- block - parentHash = block.ParentHash - if block.IsGenesis() || recv.consensus.bcModule.confirmed( - block.Position.Height-1) { - return - } - } - }(block.ParentHash) - } - if !block.IsEmpty() { - recv.consensus.processBlockChan <- block - } - // Clean the restartNotary channel so BA will not stuck by deadlock. -CleanChannelLoop: - for { - select { - case <-recv.restartNotary: - default: - break CleanChannelLoop - } - } - recv.restartNotary <- block.Position -} - -func (recv *consensusBAReceiver) PullBlocks(hashes common.Hashes) { - if !recv.isNotary { - return - } - recv.consensus.logger.Debug("Calling Network.PullBlocks", "hashes", hashes) - recv.consensus.network.PullBlocks(hashes) -} - -func (recv *consensusBAReceiver) ReportForkVote(v1, v2 *types.Vote) { - recv.consensus.gov.ReportForkVote(v1, v2) -} - -func (recv *consensusBAReceiver) ReportForkBlock(b1, b2 *types.Block) { - b1Clone := b1.Clone() - b2Clone := b2.Clone() - b1Clone.Payload = []byte{} - b2Clone.Payload = []byte{} - recv.consensus.gov.ReportForkBlock(b1Clone, b2Clone) -} - -// consensusDKGReceiver implements dkgReceiver. -type consensusDKGReceiver struct { - ID types.NodeID - gov Governance - signer *utils.Signer - nodeSetCache *utils.NodeSetCache - cfgModule *configurationChain - network Network - logger common.Logger -} - -// ProposeDKGComplaint proposes a DKGComplaint. -func (recv *consensusDKGReceiver) ProposeDKGComplaint( - complaint *typesDKG.Complaint) { - if err := recv.signer.SignDKGComplaint(complaint); err != nil { - recv.logger.Error("Failed to sign DKG complaint", "error", err) - return - } - recv.logger.Debug("Calling Governace.AddDKGComplaint", - "complaint", complaint) - recv.gov.AddDKGComplaint(complaint) -} - -// ProposeDKGMasterPublicKey propose a DKGMasterPublicKey. -func (recv *consensusDKGReceiver) ProposeDKGMasterPublicKey( - mpk *typesDKG.MasterPublicKey) { - if err := recv.signer.SignDKGMasterPublicKey(mpk); err != nil { - recv.logger.Error("Failed to sign DKG master public key", "error", err) - return - } - recv.logger.Debug("Calling Governance.AddDKGMasterPublicKey", "key", mpk) - recv.gov.AddDKGMasterPublicKey(mpk) -} - -// ProposeDKGPrivateShare propose a DKGPrivateShare. -func (recv *consensusDKGReceiver) ProposeDKGPrivateShare( - prv *typesDKG.PrivateShare) { - if err := recv.signer.SignDKGPrivateShare(prv); err != nil { - recv.logger.Error("Failed to sign DKG private share", "error", err) - return - } - receiverPubKey, exists := recv.nodeSetCache.GetPublicKey(prv.ReceiverID) - if !exists { - recv.logger.Error("Public key for receiver not found", - "receiver", prv.ReceiverID.String()[:6]) - return - } - if prv.ReceiverID == recv.ID { - go func() { - if err := recv.cfgModule.processPrivateShare(prv); err != nil { - recv.logger.Error("Failed to process self private share", "prvShare", prv) - } - }() - } else { - recv.logger.Debug("Calling Network.SendDKGPrivateShare", - "receiver", hex.EncodeToString(receiverPubKey.Bytes())) - recv.network.SendDKGPrivateShare(receiverPubKey, prv) - } -} - -// ProposeDKGAntiNackComplaint propose a DKGPrivateShare as an anti complaint. -func (recv *consensusDKGReceiver) ProposeDKGAntiNackComplaint( - prv *typesDKG.PrivateShare) { - if prv.ProposerID == recv.ID { - if err := recv.signer.SignDKGPrivateShare(prv); err != nil { - recv.logger.Error("Failed sign DKG private share", "error", err) - return - } - } - recv.logger.Debug("Calling Network.BroadcastDKGPrivateShare", "share", prv) - recv.network.BroadcastDKGPrivateShare(prv) -} - -// ProposeDKGMPKReady propose a DKGMPKReady message. -func (recv *consensusDKGReceiver) ProposeDKGMPKReady(ready *typesDKG.MPKReady) { - if err := recv.signer.SignDKGMPKReady(ready); err != nil { - recv.logger.Error("Failed to sign DKG ready", "error", err) - return - } - recv.logger.Debug("Calling Governance.AddDKGMPKReady", "ready", ready) - recv.gov.AddDKGMPKReady(ready) -} - -// ProposeDKGFinalize propose a DKGFinalize message. -func (recv *consensusDKGReceiver) ProposeDKGFinalize(final *typesDKG.Finalize) { - if err := recv.signer.SignDKGFinalize(final); err != nil { - recv.logger.Error("Failed to sign DKG finalize", "error", err) - return - } - recv.logger.Debug("Calling Governance.AddDKGFinalize", "final", final) - recv.gov.AddDKGFinalize(final) -} - -// ProposeDKGSuccess propose a DKGSuccess message. -func (recv *consensusDKGReceiver) ProposeDKGSuccess(success *typesDKG.Success) { - if err := recv.signer.SignDKGSuccess(success); err != nil { - recv.logger.Error("Failed to sign DKG successize", "error", err) - return - } - recv.logger.Debug("Calling Governance.AddDKGSuccess", "success", success) - recv.gov.AddDKGSuccess(success) -} - -// Consensus implements DEXON Consensus algorithm. -type Consensus struct { - // Node Info. - ID types.NodeID - signer *utils.Signer - - // BA. - baMgr *agreementMgr - baConfirmedBlock map[common.Hash]chan<- *types.Block - - // DKG. - dkgRunning int32 - dkgReady *sync.Cond - cfgModule *configurationChain - - // Interfaces. - db db.Database - app Application - debugApp Debug - gov Governance - network Network - - // Misc. - 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 - resetDeliveryGuardTicker chan struct{} - msgChan chan types.Msg - priorityMsgChan chan interface{} - waitGroup sync.WaitGroup - processBlockChan chan *types.Block - - // Context of Dummy receiver during switching from syncer. - dummyCancel context.CancelFunc - dummyFinished <-chan struct{} - dummyMsgBuffer []types.Msg -} - -// NewConsensus construct an Consensus instance. -func NewConsensus( - dMoment time.Time, - app Application, - gov Governance, - db db.Database, - network Network, - prv crypto.PrivateKey, - logger common.Logger) *Consensus { - return newConsensusForRound( - nil, dMoment, app, gov, db, network, prv, logger, true) -} - -// NewConsensusForSimulation creates an instance of Consensus for simulation, -// the only difference with NewConsensus is nonblocking of app. -func NewConsensusForSimulation( - dMoment time.Time, - app Application, - gov Governance, - db db.Database, - network Network, - prv crypto.PrivateKey, - logger common.Logger) *Consensus { - return newConsensusForRound( - nil, dMoment, app, gov, db, network, prv, logger, false) -} - -// NewConsensusFromSyncer constructs an Consensus instance from information -// provided from syncer. -// -// You need to provide the initial block for this newly created Consensus -// instance to bootstrap with. A proper choice is the last finalized block you -// delivered to syncer. -// -// NOTE: those confirmed blocks should be organized by chainID and sorted by -// their positions, in ascending order. -func NewConsensusFromSyncer( - initBlock *types.Block, - startWithEmpty bool, - dMoment time.Time, - app Application, - gov Governance, - db db.Database, - networkModule Network, - prv crypto.PrivateKey, - confirmedBlocks []*types.Block, - cachedMessages []types.Msg, - logger common.Logger) (*Consensus, error) { - // Setup Consensus instance. - con := newConsensusForRound(initBlock, dMoment, app, gov, db, - networkModule, prv, logger, true) - // Launch a dummy receiver before we start receiving from network module. - con.dummyMsgBuffer = cachedMessages - con.dummyCancel, con.dummyFinished = utils.LaunchDummyReceiver( - con.ctx, networkModule.ReceiveChan(), func(msg types.Msg) { - con.dummyMsgBuffer = append(con.dummyMsgBuffer, msg) - }) - // Dump all BA-confirmed blocks to the consensus instance, make sure these - // added blocks forming a DAG. - refBlock := initBlock - for _, b := range confirmedBlocks { - // Only when its parent block is already added to lattice, we can - // then add this block. If not, our pulling mechanism would stop at - // the block we added, and lost its parent block forever. - if b.Position.Height != refBlock.Position.Height+1 { - break - } - if err := con.processBlock(b); err != nil { - return nil, err - } - refBlock = b - } - if startWithEmpty { - emptyPos := types.Position{ - Round: con.bcModule.tipRound(), - Height: initBlock.Position.Height + 1, - } - _, err := con.bcModule.addEmptyBlock(emptyPos) - if err != nil { - panic(err) - } - } - return con, nil -} - -// newConsensusForRound creates a Consensus instance. -func newConsensusForRound( - initBlock *types.Block, - dMoment time.Time, - app Application, - gov Governance, - db db.Database, - network Network, - prv crypto.PrivateKey, - logger common.Logger, - usingNonBlocking bool) *Consensus { - // TODO(w): load latest blockHeight from DB, and use config at that height. - nodeSetCache := utils.NewNodeSetCache(gov) - // Setup signer module. - signer := utils.NewSigner(prv) - // Check if the application implement Debug interface. - var debugApp Debug - if a, ok := app.(Debug); ok { - debugApp = a - } - // Get configuration for bootstrap round. - initPos := types.Position{ - Round: 0, - Height: types.GenesisHeight, - } - if initBlock != nil { - initPos = initBlock.Position - } - // Init configuration chain. - ID := types.NewNodeID(prv.PublicKey()) - recv := &consensusDKGReceiver{ - ID: ID, - gov: gov, - signer: signer, - nodeSetCache: nodeSetCache, - network: network, - logger: logger, - } - cfgModule := newConfigurationChain(ID, recv, gov, nodeSetCache, db, logger) - recv.cfgModule = cfgModule - signer.SetBLSSigner( - func(round uint64, hash common.Hash) (crypto.Signature, error) { - _, signer, err := cfgModule.getDKGInfo(round, false) - if err != nil { - return crypto.Signature{}, err - } - return crypto.Signature(signer.sign(hash)), nil - }) - appModule := app - if usingNonBlocking { - appModule = newNonBlocking(app, debugApp) - } - tsigVerifierCache := NewTSigVerifierCache(gov, 7) - bcModule := newBlockChain(ID, dMoment, initBlock, appModule, - tsigVerifierCache, signer, logger) - // Construct Consensus instance. - con := &Consensus{ - ID: ID, - app: appModule, - debugApp: debugApp, - gov: gov, - db: db, - network: network, - baConfirmedBlock: make(map[common.Hash]chan<- *types.Block), - dkgReady: sync.NewCond(&sync.Mutex{}), - cfgModule: cfgModule, - bcModule: bcModule, - dMoment: dMoment, - nodeSetCache: nodeSetCache, - tsigVerifierCache: tsigVerifierCache, - signer: signer, - event: common.NewEvent(), - logger: logger, - resetDeliveryGuardTicker: make(chan struct{}), - msgChan: make(chan types.Msg, 1024), - priorityMsgChan: make(chan interface{}, 1024), - processBlockChan: make(chan *types.Block, 1024), - } - con.ctx, con.ctxCancel = context.WithCancel(context.Background()) - var err error - con.roundEvent, err = utils.NewRoundEvent(con.ctx, gov, logger, initPos, - ConfigRoundShift) - if err != nil { - panic(err) - } - if con.baMgr, err = newAgreementMgr(con); err != nil { - panic(err) - } - if err = con.prepare(initBlock); err != nil { - panic(err) - } - return con -} - -// prepare the Consensus instance to be ready for blocks after 'initBlock'. -// 'initBlock' could be either: -// - nil -// - the last finalized block -func (con *Consensus) prepare(initBlock *types.Block) (err error) { - // Trigger the round validation method for the next round of the first - // round. - // The block past from full node should be delivered already or known by - // full node. We don't have to notify it. - initRound := uint64(0) - if initBlock != nil { - initRound = initBlock.Position.Round - } - if initRound == 0 { - if DKGDelayRound == 0 { - panic("not implemented yet") - } - } - // Measure time elapse for each handler of round events. - elapse := func(what string, lastE utils.RoundEventParam) func() { - start := time.Now() - con.logger.Info("Handle round event", - "what", what, - "event", lastE) - return func() { - con.logger.Info("Finish round event", - "what", what, - "event", lastE, - "elapse", time.Since(start)) - } - } - // Register round event handler to purge cached node set. To make sure each - // modules see the up-to-date node set, we need to make sure this action - // should be taken as the first one. - con.roundEvent.Register(func(evts []utils.RoundEventParam) { - defer elapse("purge-cache", evts[len(evts)-1])() - for _, e := range evts { - if e.Reset == 0 { - continue - } - con.nodeSetCache.Purge(e.Round + 1) - con.tsigVerifierCache.Purge(e.Round + 1) - } - }) - // Register round event handler to abort previous running DKG if any. - con.roundEvent.Register(func(evts []utils.RoundEventParam) { - e := evts[len(evts)-1] - go func() { - defer elapse("abort-DKG", e)() - if e.Reset > 0 { - aborted := con.cfgModule.abortDKG(con.ctx, e.Round+1, e.Reset-1) - con.logger.Info("DKG aborting result", - "round", e.Round+1, - "reset", e.Reset-1, - "aborted", aborted) - } - }() - }) - // Register round event handler to update BA and BC modules. - con.roundEvent.Register(func(evts []utils.RoundEventParam) { - defer elapse("append-config", evts[len(evts)-1])() - // Always updates newer configs to the later modules first in the data - // flow. - if err := con.bcModule.notifyRoundEvents(evts); err != nil { - panic(err) - } - if err := con.baMgr.notifyRoundEvents(evts); err != nil { - panic(err) - } - }) - // Register round event handler to reset DKG if the DKG set for next round - // failed to setup. - con.roundEvent.Register(func(evts []utils.RoundEventParam) { - e := evts[len(evts)-1] - defer elapse("reset-DKG", e)() - nextRound := e.Round + 1 - if nextRound < DKGDelayRound { - return - } - curNotarySet, err := con.nodeSetCache.GetNotarySet(e.Round) - if err != nil { - con.logger.Error("Error getting notary set when proposing CRS", - "round", e.Round, - "error", err) - return - } - if _, exist := curNotarySet[con.ID]; !exist { - return - } - con.event.RegisterHeight(e.NextDKGResetHeight(), func(uint64) { - if ok, _ := utils.IsDKGValid( - con.gov, con.logger, nextRound, e.Reset); ok { - return - } - // Aborting all previous running DKG protocol instance if any. - go con.runCRS(e.Round, utils.Rehash(e.CRS, uint(e.Reset+1)), true) - }) - }) - // 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 notary set in previous round. - e := evts[len(evts)-1] - defer elapse("propose-CRS", e)() - if e.Reset != 0 || e.Round < DKGDelayRound { - return - } - 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 := curNotarySet[con.ID]; !exist { - return - } - con.event.RegisterHeight(e.NextCRSProposingHeight(), func(uint64) { - con.logger.Debug( - "Calling Governance.CRS to check if already proposed", - "round", e.Round+1) - if (con.gov.CRS(e.Round+1) != common.Hash{}) { - con.logger.Debug("CRS already proposed", "round", e.Round+1) - return - } - go con.runCRS(e.Round, e.CRS, false) - }) - } - }) - // Touch nodeSetCache for next round. - con.roundEvent.Register(func(evts []utils.RoundEventParam) { - e := evts[len(evts)-1] - defer elapse("touch-NodeSetCache", e)() - con.event.RegisterHeight(e.NextTouchNodeSetCacheHeight(), func(uint64) { - if e.Reset == 0 { - return - } - go func() { - nextRound := e.Round + 1 - if err := con.nodeSetCache.Touch(nextRound); err != nil { - con.logger.Warn("Failed to update nodeSetCache", - "round", nextRound, - "error", err) - } - }() - }) - }) - con.roundEvent.Register(func(evts []utils.RoundEventParam) { - e := evts[len(evts)-1] - if e.Reset != 0 { - return - } - defer elapse("touch-DKGCache", e)() - go func() { - if _, err := - con.tsigVerifierCache.Update(e.Round); err != nil { - con.logger.Warn("Failed to update tsig cache", - "round", e.Round, - "error", err) - } - }() - go func() { - threshold := utils.GetDKGThreshold( - utils.GetConfigWithPanic(con.gov, e.Round, con.logger)) - // Restore group public key. - con.logger.Debug( - "Calling Governance.DKGMasterPublicKeys for recoverDKGInfo", - "round", e.Round) - con.logger.Debug( - "Calling Governance.DKGComplaints for recoverDKGInfo", - "round", e.Round) - _, qualifies, err := typesDKG.CalcQualifyNodes( - con.gov.DKGMasterPublicKeys(e.Round), - con.gov.DKGComplaints(e.Round), - threshold) - if err != nil { - con.logger.Warn("Failed to calculate dkg set", - "round", e.Round, - "error", err) - return - } - if _, exist := qualifies[con.ID]; !exist { - return - } - if _, _, err := - con.cfgModule.getDKGInfo(e.Round, true); err != nil { - con.logger.Warn("Failed to recover DKG info", - "round", e.Round, - "error", err) - } - }() - }) - // checkCRS is a generator of checker to check if CRS for that round is - // ready or not. - checkCRS := func(round uint64) func() bool { - return func() bool { - nextCRS := con.gov.CRS(round) - if (nextCRS != common.Hash{}) { - return true - } - con.logger.Debug("CRS is not ready yet. Try again later...", - "nodeID", con.ID, - "round", round) - return false - } - } - // Trigger round validation method for next period. - con.roundEvent.Register(func(evts []utils.RoundEventParam) { - e := evts[len(evts)-1] - defer elapse("next-round", e)() - // Register a routine to trigger round events. - con.event.RegisterHeight(e.NextRoundValidationHeight(), - utils.RoundEventRetryHandlerGenerator(con.roundEvent, con.event)) - // Register a routine to register next DKG. - con.event.RegisterHeight(e.NextDKGRegisterHeight(), func(uint64) { - nextRound := e.Round + 1 - if nextRound < DKGDelayRound { - con.logger.Info("Skip runDKG for round", - "round", nextRound, - "reset", e.Reset) - return - } - go func() { - // Normally, gov.CRS would return non-nil. Use this for in case - // 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 notary set", - "round", nextRound, - "reset", e.Reset) - return - } - nextNotarySet, err := con.nodeSetCache.GetNotarySet(nextRound) - if err != nil { - con.logger.Error("Error getting notary set for next round", - "round", nextRound, - "reset", e.Reset, - "error", err) - return - } - 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 notary set", - "round", nextRound, - "reset", e.Reset) - nextConfig := utils.GetConfigWithPanic(con.gov, nextRound, - con.logger) - con.cfgModule.registerDKG(con.ctx, nextRound, e.Reset, - utils.GetDKGThreshold(nextConfig)) - con.event.RegisterHeight(e.NextDKGPreparationHeight(), - func(h uint64) { - func() { - con.dkgReady.L.Lock() - defer con.dkgReady.L.Unlock() - con.dkgRunning = 0 - }() - // We want to skip some of the DKG phases when started. - dkgCurrentHeight := h - e.NextDKGPreparationHeight() - con.runDKG( - nextRound, e.Reset, - e.NextDKGPreparationHeight(), dkgCurrentHeight) - }) - }() - }) - }) - con.roundEvent.TriggerInitEvent() - if initBlock != nil { - con.event.NotifyHeight(initBlock.Position.Height) - } - con.baMgr.prepare() - return -} - -// Run starts running DEXON Consensus. -func (con *Consensus) Run() { - // There may have emptys block in blockchain added by force sync. - blocksWithoutRandomness := con.bcModule.pendingBlocksWithoutRandomness() - // Launch BA routines. - con.baMgr.run() - // Launch network handler. - con.logger.Debug("Calling Network.ReceiveChan") - con.waitGroup.Add(1) - go con.deliverNetworkMsg() - con.waitGroup.Add(1) - go con.processMsg() - go con.processBlockLoop() - // Stop dummy receiver if launched. - if con.dummyCancel != nil { - con.logger.Trace("Stop dummy receiver") - con.dummyCancel() - <-con.dummyFinished - // Replay those cached messages. - con.logger.Trace("Dummy receiver stoped, start dumping cached messages", - "count", len(con.dummyMsgBuffer)) - for _, msg := range con.dummyMsgBuffer { - loop: - for { - select { - case con.msgChan <- msg: - break loop - case <-time.After(50 * time.Millisecond): - con.logger.Debug( - "internal message channel is full when syncing") - } - } - } - con.logger.Trace("Finish dumping cached messages") - } - con.generateBlockRandomness(blocksWithoutRandomness) - // 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. - select { - case <-con.ctx.Done(): - } -} - -func (con *Consensus) generateBlockRandomness(blocks []*types.Block) { - con.logger.Debug("Start generating block randomness", "blocks", blocks) - isNotarySet := make(map[uint64]bool) - for _, block := range blocks { - if block.Position.Round < DKGDelayRound { - continue - } - doRun, exist := isNotarySet[block.Position.Round] - if !exist { - curNotarySet, err := con.nodeSetCache.GetNotarySet(block.Position.Round) - if err != nil { - con.logger.Error("Error getting notary set when generate block tsig", - "round", block.Position.Round, - "error", err) - continue - } - _, exist := curNotarySet[con.ID] - isNotarySet[block.Position.Round] = exist - doRun = exist - } - if !doRun { - continue - } - go func(block *types.Block) { - psig, err := con.cfgModule.preparePartialSignature( - block.Position.Round, block.Hash) - if err != nil { - con.logger.Error("Failed to prepare partial signature", - "block", block, - "error", err) - } else if err = con.signer.SignDKGPartialSignature(psig); err != nil { - con.logger.Error("Failed to sign DKG partial signature", - "block", block, - "error", err) - } else if err = con.cfgModule.processPartialSignature(psig); err != nil { - con.logger.Error("Failed to process partial signature", - "block", block, - "error", err) - } else { - con.logger.Debug("Calling Network.BroadcastDKGPartialSignature", - "proposer", psig.ProposerID, - "block", block) - con.network.BroadcastDKGPartialSignature(psig) - sig, err := con.cfgModule.runTSig( - block.Position.Round, - block.Hash, - 60*time.Minute, - ) - if err != nil { - con.logger.Error("Failed to run Block Tsig", - "block", block, - "error", err) - return - } - result := &types.AgreementResult{ - BlockHash: block.Hash, - Position: block.Position, - Randomness: sig.Signature[:], - } - con.bcModule.addBlockRandomness(block.Position, sig.Signature[:]) - con.logger.Debug("Broadcast BlockRandomness", - "block", block, - "result", result) - con.network.BroadcastAgreementResult(result) - if err := con.deliverFinalizedBlocks(); err != nil { - con.logger.Error("Failed to deliver finalized block", - "error", err) - } - } - }(block) - } -} - -// runDKG starts running DKG protocol. -func (con *Consensus) runDKG( - round, reset, dkgBeginHeight, dkgHeight uint64) { - con.dkgReady.L.Lock() - defer con.dkgReady.L.Unlock() - if con.dkgRunning != 0 { - return - } - con.dkgRunning = 1 - go func() { - defer func() { - con.dkgReady.L.Lock() - defer con.dkgReady.L.Unlock() - con.dkgReady.Broadcast() - con.dkgRunning = 2 - }() - if err := - con.cfgModule.runDKG( - round, reset, - con.event, dkgBeginHeight, dkgHeight); err != nil { - con.logger.Error("Failed to runDKG", "error", err) - } - }() -} - -func (con *Consensus) runCRS(round uint64, hash common.Hash, reset bool) { - // Start running next round CRS. - psig, err := con.cfgModule.preparePartialSignature(round, hash) - if err != nil { - con.logger.Error("Failed to prepare partial signature", "error", err) - } else if err = con.signer.SignDKGPartialSignature(psig); err != nil { - con.logger.Error("Failed to sign DKG partial signature", "error", err) - } else if err = con.cfgModule.processPartialSignature(psig); err != nil { - con.logger.Error("Failed to process partial signature", "error", err) - } else { - con.logger.Debug("Calling Network.BroadcastDKGPartialSignature", - "proposer", psig.ProposerID, - "round", psig.Round, - "hash", psig.Hash) - con.network.BroadcastDKGPartialSignature(psig) - con.logger.Debug("Calling Governance.CRS", "round", round) - crs, err := con.cfgModule.runCRSTSig(round, hash) - if err != nil { - con.logger.Error("Failed to run CRS Tsig", "error", err) - } else { - if reset { - con.logger.Debug("Calling Governance.ResetDKG", - "round", round+1, - "crs", hex.EncodeToString(crs)) - con.gov.ResetDKG(crs) - } else { - con.logger.Debug("Calling Governance.ProposeCRS", - "round", round+1, - "crs", hex.EncodeToString(crs)) - con.gov.ProposeCRS(round+1, crs) - } - } - } -} - -// Stop the Consensus core. -func (con *Consensus) Stop() { - con.ctxCancel() - con.baMgr.stop() - con.event.Reset() - con.waitGroup.Wait() - if nbApp, ok := con.app.(*nonBlocking); ok { - nbApp.wait() - } -} - -func (con *Consensus) deliverNetworkMsg() { - defer con.waitGroup.Done() - recv := con.network.ReceiveChan() - for { - select { - case <-con.ctx.Done(): - return - default: - } - select { - case msg := <-recv: - innerLoop: - for { - select { - case con.msgChan <- msg: - break innerLoop - case <-time.After(500 * time.Millisecond): - con.logger.Debug("internal message channel is full", - "pending", msg) - } - } - case <-con.ctx.Done(): - return - } - } -} - -func (con *Consensus) processMsg() { - defer con.waitGroup.Done() -MessageLoop: - for { - select { - case <-con.ctx.Done(): - return - default: - } - var msg, peer interface{} - select { - case msg = <-con.priorityMsgChan: - default: - } - if msg == nil { - select { - case message := <-con.msgChan: - msg, peer = message.Payload, message.PeerID - case msg = <-con.priorityMsgChan: - case <-con.ctx.Done(): - return - } - } - switch val := msg.(type) { - case *selfAgreementResult: - con.baMgr.touchAgreementResult((*types.AgreementResult)(val)) - case *types.Block: - if ch, exist := func() (chan<- *types.Block, bool) { - con.lock.RLock() - defer con.lock.RUnlock() - ch, e := con.baConfirmedBlock[val.Hash] - return ch, e - }(); exist { - if val.IsEmpty() { - hash, err := utils.HashBlock(val) - if err != nil { - con.logger.Error("Error verifying empty block hash", - "block", val, - "error, err") - con.network.ReportBadPeerChan() <- peer - continue MessageLoop - } - if hash != val.Hash { - con.logger.Error("Incorrect confirmed empty block hash", - "block", val, - "hash", hash) - con.network.ReportBadPeerChan() <- peer - 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) - con.network.ReportBadPeerChan() <- peer - continue MessageLoop - } - } else { - if !val.IsFinalized() { - con.logger.Warn("Ignore not finalized block", - "block", val) - continue MessageLoop - } - ok, err := con.bcModule.verifyRandomness( - val.Hash, val.Position.Round, val.Randomness) - if err != nil { - con.logger.Error("Error verifying confirmed block randomness", - "block", val, - "error", err) - con.network.ReportBadPeerChan() <- peer - continue MessageLoop - } - if !ok { - con.logger.Error("Incorrect confirmed block randomness", - "block", val) - con.network.ReportBadPeerChan() <- peer - continue MessageLoop - } - if err := utils.VerifyBlockSignature(val); err != nil { - con.logger.Error("VerifyBlockSignature failed", - "block", val, - "error", err) - con.network.ReportBadPeerChan() <- peer - continue MessageLoop - } - } - func() { - con.lock.Lock() - defer con.lock.Unlock() - // In case of multiple delivered block. - if _, exist := con.baConfirmedBlock[val.Hash]; !exist { - return - } - delete(con.baConfirmedBlock, val.Hash) - ch <- val - }() - } else if val.IsFinalized() { - if err := con.processFinalizedBlock(val); err != nil { - con.logger.Error("Failed to process finalized block", - "block", val, - "error", err) - con.network.ReportBadPeerChan() <- peer - } - } else { - if err := con.preProcessBlock(val); err != nil { - con.logger.Error("Failed to pre process block", - "block", val, - "error", err) - con.network.ReportBadPeerChan() <- peer - } - } - case *types.Vote: - if err := con.ProcessVote(val); err != nil { - con.logger.Error("Failed to process vote", - "vote", val, - "error", err) - con.network.ReportBadPeerChan() <- peer - } - case *types.AgreementResult: - if err := con.ProcessAgreementResult(val); err != nil { - con.logger.Error("Failed to process agreement result", - "result", val, - "error", err) - con.network.ReportBadPeerChan() <- peer - } - case *typesDKG.PrivateShare: - if err := con.cfgModule.processPrivateShare(val); err != nil { - con.logger.Error("Failed to process private share", - "error", err) - con.network.ReportBadPeerChan() <- peer - } - - case *typesDKG.PartialSignature: - if err := con.cfgModule.processPartialSignature(val); err != nil { - con.logger.Error("Failed to process partial signature", - "error", err) - con.network.ReportBadPeerChan() <- peer - } - } - } -} - -// ProcessVote is the entry point to submit ont vote to a Consensus instance. -func (con *Consensus) ProcessVote(vote *types.Vote) (err error) { - err = con.baMgr.processVote(vote) - return -} - -// ProcessAgreementResult processes the randomness request. -func (con *Consensus) ProcessAgreementResult( - rand *types.AgreementResult) error { - if !con.baMgr.touchAgreementResult(rand) { - return nil - } - // Sanity Check. - if err := VerifyAgreementResult(rand, con.nodeSetCache); err != nil { - con.baMgr.untouchAgreementResult(rand) - return err - } - if err := con.bcModule.processAgreementResult(rand); err != nil { - con.baMgr.untouchAgreementResult(rand) - if err == ErrSkipButNoError { - return nil - } - return err - } - // Syncing BA Module. - if err := con.baMgr.processAgreementResult(rand); err != nil { - con.baMgr.untouchAgreementResult(rand) - return err - } - - con.logger.Debug("Rebroadcast AgreementResult", - "result", rand) - con.network.BroadcastAgreementResult(rand) - - return con.deliverFinalizedBlocks() -} - -// preProcessBlock performs Byzantine Agreement on the block. -func (con *Consensus) preProcessBlock(b *types.Block) (err error) { - err = con.baMgr.processBlock(b) - if err == nil && con.debugApp != nil { - con.debugApp.BlockReceived(b.Hash) - } - return -} - -func (con *Consensus) processFinalizedBlock(b *types.Block) (err error) { - if b.Position.Round < DKGDelayRound { - return - } - if err = utils.VerifyBlockSignature(b); err != nil { - return - } - verifier, ok, err := con.tsigVerifierCache.UpdateAndGet(b.Position.Round) - if err != nil { - return - } - if !ok { - err = ErrCannotVerifyBlockRandomness - return - } - if !verifier.VerifySignature(b.Hash, crypto.Signature{ - Type: "bls", - Signature: b.Randomness, - }) { - err = ErrIncorrectBlockRandomness - return - } - err = con.baMgr.processFinalizedBlock(b) - if err == nil && con.debugApp != nil { - con.debugApp.BlockReceived(b.Hash) - } - return -} - -func (con *Consensus) deliveryGuard() { - defer con.waitGroup.Done() - select { - case <-con.ctx.Done(): - case <-time.After(con.dMoment.Sub(time.Now())): - } - // Node takes time to start. - select { - case <-con.ctx.Done(): - case <-time.After(60 * time.Second): - } - for { - select { - case <-con.ctx.Done(): - return - default: - } - select { - case <-con.ctx.Done(): - return - case <-con.resetDeliveryGuardTicker: - case <-time.After(60 * time.Second): - con.logger.Error("No blocks delivered for too long", "ID", con.ID) - panic(fmt.Errorf("No blocks delivered for too long")) - } - } -} - -// deliverBlock deliver a block to application layer. -func (con *Consensus) deliverBlock(b *types.Block) { - select { - case con.resetDeliveryGuardTicker <- struct{}{}: - default: - } - if err := con.db.PutBlock(*b); err != nil { - panic(err) - } - if err := con.db.PutCompactionChainTipInfo(b.Hash, - b.Position.Height); err != nil { - panic(err) - } - con.logger.Debug("Calling Application.BlockDelivered", "block", b) - con.app.BlockDelivered(b.Hash, b.Position, common.CopyBytes(b.Randomness)) - if con.debugApp != nil { - con.debugApp.BlockReady(b.Hash) - } -} - -// deliverFinalizedBlocks extracts and delivers finalized blocks to application -// layer. -func (con *Consensus) deliverFinalizedBlocks() error { - con.lock.Lock() - defer con.lock.Unlock() - return con.deliverFinalizedBlocksWithoutLock() -} - -func (con *Consensus) deliverFinalizedBlocksWithoutLock() (err error) { - deliveredBlocks := con.bcModule.extractBlocks() - con.logger.Debug("Last blocks in compaction chain", - "delivered", con.bcModule.lastDeliveredBlock(), - "pending", con.bcModule.lastPendingBlock()) - for _, b := range deliveredBlocks { - con.deliverBlock(b) - con.event.NotifyHeight(b.Position.Height) - } - return -} - -func (con *Consensus) processBlockLoop() { - for { - select { - case <-con.ctx.Done(): - return - default: - } - select { - case <-con.ctx.Done(): - return - case block := <-con.processBlockChan: - if err := con.processBlock(block); err != nil { - con.logger.Error("Error processing block", - "block", block, - "error", err) - } - } - } -} - -// processBlock is the entry point to submit one block to a Consensus instance. -func (con *Consensus) processBlock(block *types.Block) (err error) { - // Block processed by blockChain can be out-of-order. But the output from - // blockChain (deliveredBlocks) cannot, thus we need to protect the part - // below with writer lock. - con.lock.Lock() - defer con.lock.Unlock() - if err = con.bcModule.addBlock(block); err != nil { - return - } - if err = con.deliverFinalizedBlocksWithoutLock(); err != nil { - return - } - return -} - -// 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(), false) - if err != nil { - return nil, err - } - con.logger.Debug("Calling Governance.CRS", "round", b.Position.Round) - crs := con.gov.CRS(b.Position.Round) - if crs.Equal(common.Hash{}) { - con.logger.Error("CRS for round is not ready, unable to prepare block", - "position", &b.Position) - return nil, ErrCRSNotReady - } - if err = con.signer.SignCRS(b, crs); err != nil { - return nil, err - } - return b, nil -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/constant.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/constant.go deleted file mode 100644 index 29dae8b73..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/constant.go +++ /dev/null @@ -1,41 +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 core - -import "github.com/dexon-foundation/dexon-consensus/core/utils" - -// ConfigRoundShift refers to the difference between block's round and config -// round derived from its state. -// -// For example, when round shift is 2, a block in round 0 should derive config -// for round 2. -const ConfigRoundShift uint64 = 2 - -// DKGDelayRound refers to the round that first DKG is run. -// -// For example, when delay round is 1, new DKG will run at round 1. Round 0 will -// have neither DKG nor CRS. -const DKGDelayRound uint64 = 1 - -// NoRand is the magic placeholder for randomness field in blocks for blocks -// proposed before DKGDelayRound. -var NoRand = []byte("norand") - -func init() { - utils.SetDKGDelayRound(DKGDelayRound) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/constant.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/constant.go deleted file mode 100644 index 37d873d6f..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/constant.go +++ /dev/null @@ -1,26 +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 dkg - -import ( - "github.com/dexon-foundation/bls/ffi/go/bls" -) - -const ( - curve = bls.BLS12_381 -) diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go deleted file mode 100644 index ab43f5130..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/dkg.go +++ /dev/null @@ -1,637 +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 dkg - -import ( - "encoding/json" - "fmt" - "io" - "sync" - "sync/atomic" - - "github.com/dexon-foundation/bls/ffi/go/bls" - "github.com/dexon-foundation/dexon/rlp" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" -) - -var ( - // ErrDuplicatedShare is reported when adding an private key share of same id. - ErrDuplicatedShare = fmt.Errorf("invalid share") - // ErrNoIDToRecover is reported when no id is provided for recovering private - // key. - ErrNoIDToRecover = fmt.Errorf("no id to recover private key") - // ErrShareNotFound is reported when the private key share of id is not found - // when recovering private key. - ErrShareNotFound = fmt.Errorf("share not found") -) - -const cryptoType = "bls" - -var publicKeyLength int - -func init() { - if err := bls.Init(curve); err != nil { - panic(err) - } - - pubKey := &bls.PublicKey{} - publicKeyLength = len(pubKey.Serialize()) -} - -// PrivateKey represents a private key structure implments -// Crypto.PrivateKey interface. -type PrivateKey struct { - privateKey bls.SecretKey - publicKey PublicKey -} - -// EncodeRLP implements rlp.Encoder -func (prv *PrivateKey) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, prv.Bytes()) -} - -// DecodeRLP implements rlp.Decoder -func (prv *PrivateKey) DecodeRLP(s *rlp.Stream) error { - var b []byte - if err := s.Decode(&b); err != nil { - return err - } - return prv.SetBytes(b) -} - -// MarshalJSON implements json.Marshaller. -func (prv *PrivateKey) MarshalJSON() ([]byte, error) { - return json.Marshal(&prv.privateKey) -} - -// UnmarshalJSON implements json.Unmarshaller. -func (prv *PrivateKey) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &prv.privateKey) -} - -// ID is the id for DKG protocol. -type ID = bls.ID - -// IDs is an array of ID. -type IDs []ID - -// PublicKey represents a public key structure implements -// Crypto.PublicKey interface. -type PublicKey struct { - publicKey bls.PublicKey -} - -// PrivateKeyShares represents a private key shares for DKG protocol. -type PrivateKeyShares struct { - shares []PrivateKey - shareIndex map[ID]int - masterPrivateKey []bls.SecretKey -} - -// Equal check equality between two PrivateKeyShares instances. -func (prvs *PrivateKeyShares) Equal(other *PrivateKeyShares) bool { - // Check shares. - if len(prvs.shareIndex) != len(other.shareIndex) { - return false - } - for dID, idx := range prvs.shareIndex { - otherIdx, exists := other.shareIndex[dID] - if !exists { - return false - } - if !prvs.shares[idx].privateKey.IsEqual( - &other.shares[otherIdx].privateKey) { - return false - } - } - // Check master private keys. - if len(prvs.masterPrivateKey) != len(other.masterPrivateKey) { - return false - } - for idx, m := range prvs.masterPrivateKey { - if m.GetHexString() != other.masterPrivateKey[idx].GetHexString() { - return false - } - } - return true -} - -// EncodeRLP implements rlp.Encoder -func (prvs *PrivateKeyShares) EncodeRLP(w io.Writer) error { - data := make([][][]byte, 3) - shares := make([][]byte, len(prvs.shares)) - for i, s := range prvs.shares { - shares[i] = s.Bytes() - } - data[0] = shares - - shareIndex := make([][]byte, 0) - for k, v := range prvs.shareIndex { - shareIndex = append(shareIndex, k.GetLittleEndian()) - - vBytes, err := rlp.EncodeToBytes(uint64(v)) - if err != nil { - return err - } - shareIndex = append(shareIndex, vBytes) - } - data[1] = shareIndex - - mpks := make([][]byte, len(prvs.masterPrivateKey)) - for i, m := range prvs.masterPrivateKey { - mpks[i] = m.GetLittleEndian() - } - data[2] = mpks - return rlp.Encode(w, data) -} - -// DecodeRLP implements rlp.Decoder -func (prvs *PrivateKeyShares) DecodeRLP(s *rlp.Stream) error { - *prvs = PrivateKeyShares{} - var dec [][][]byte - if err := s.Decode(&dec); err != nil { - return err - } - - var shares []PrivateKey - for _, bs := range dec[0] { - var key PrivateKey - err := key.SetBytes(bs) - if err != nil { - return err - } - shares = append(shares, key) - } - (*prvs).shares = shares - - sharesIndex := map[ID]int{} - for i := 0; i < len(dec[1]); i += 2 { - var key ID - err := key.SetLittleEndian(dec[1][i]) - if err != nil { - return err - } - - var value uint64 - err = rlp.DecodeBytes(dec[1][i+1], &value) - if err != nil { - return err - } - - sharesIndex[key] = int(value) - } - (*prvs).shareIndex = sharesIndex - - var mpks []bls.SecretKey - for _, bs := range dec[2] { - var key bls.SecretKey - if err := key.SetLittleEndian(bs); err != nil { - return err - } - mpks = append(mpks, key) - } - (*prvs).masterPrivateKey = mpks - - return nil -} - -type publicKeySharesCache struct { - share []PublicKey - index map[ID]int -} - -// PublicKeyShares represents a public key shares for DKG protocol. -type PublicKeyShares struct { - cache atomic.Value - lock sync.Mutex - masterPublicKey []bls.PublicKey -} - -// Equal checks equality of two PublicKeyShares instance. -func (pubs *PublicKeyShares) Equal(other *PublicKeyShares) bool { - cache := pubs.cache.Load().(*publicKeySharesCache) - cacheOther := other.cache.Load().(*publicKeySharesCache) - // Check shares. - for dID, idx := range cache.index { - otherIdx, exists := cacheOther.index[dID] - if !exists { - continue - } - if !cache.share[idx].publicKey.IsEqual( - &cacheOther.share[otherIdx].publicKey) { - return false - } - } - // Check master public keys. - if len(pubs.masterPublicKey) != len(other.masterPublicKey) { - return false - } - for idx, m := range pubs.masterPublicKey { - if m.GetHexString() != other.masterPublicKey[idx].GetHexString() { - return false - } - } - return true -} - -// EncodeRLP implements rlp.Encoder -func (pubs *PublicKeyShares) EncodeRLP(w io.Writer) error { - mpks := make([][]byte, len(pubs.masterPublicKey)) - for i, m := range pubs.masterPublicKey { - mpks[i] = m.Serialize() - } - return rlp.Encode(w, mpks) -} - -// DecodeRLP implements rlp.Decoder -func (pubs *PublicKeyShares) DecodeRLP(s *rlp.Stream) error { - var dec [][]byte - if err := s.Decode(&dec); err != nil { - return err - } - - ps := NewEmptyPublicKeyShares() - for _, k := range dec { - var key bls.PublicKey - if err := key.Deserialize(k); err != nil { - return err - } - ps.masterPublicKey = append(ps.masterPublicKey, key) - } - - *pubs = *ps.Move() - return nil -} - -// MarshalJSON implements json.Marshaller. -func (pubs *PublicKeyShares) MarshalJSON() ([]byte, error) { - type Alias PublicKeyShares - data := &struct { - MasterPublicKeys []*bls.PublicKey `json:"master_public_keys"` - }{ - make([]*bls.PublicKey, len(pubs.masterPublicKey)), - } - for i := range pubs.masterPublicKey { - data.MasterPublicKeys[i] = &pubs.masterPublicKey[i] - } - return json.Marshal(data) -} - -// UnmarshalJSON implements json.Unmarshaller. -func (pubs *PublicKeyShares) UnmarshalJSON(data []byte) error { - type Alias PublicKeyShares - aux := &struct { - MasterPublicKeys []*bls.PublicKey `json:"master_public_keys"` - }{} - if err := json.Unmarshal(data, &aux); err != nil { - return err - } - mpk := make([]bls.PublicKey, len(aux.MasterPublicKeys)) - for i, pk := range aux.MasterPublicKeys { - mpk[i] = *pk - } - pubs.masterPublicKey = mpk - return nil -} - -// Clone clones every fields of PublicKeyShares. This method is mainly -// for testing purpose thus would panic when error. -func (pubs *PublicKeyShares) Clone() *PublicKeyShares { - b, err := rlp.EncodeToBytes(pubs) - if err != nil { - panic(err) - } - pubsCopy := NewEmptyPublicKeyShares() - if err := rlp.DecodeBytes(b, pubsCopy); err != nil { - panic(err) - } - return pubsCopy -} - -// NewID creates a ew ID structure. -func NewID(id []byte) ID { - var blsID bls.ID - // #nosec G104 - blsID.SetLittleEndian(id) - return blsID -} - -// BytesID creates a new ID structure, -// It returns err if the byte slice is not valid. -func BytesID(id []byte) (ID, error) { - var blsID bls.ID - // #nosec G104 - err := blsID.SetLittleEndian(id) - return blsID, err -} - -// NewPrivateKey creates a new PrivateKey structure. -func NewPrivateKey() *PrivateKey { - var key bls.SecretKey - key.SetByCSPRNG() - return &PrivateKey{ - privateKey: key, - publicKey: *newPublicKey(&key), - } -} - -// NewPrivateKeyShares creates a DKG private key shares of threshold t. -func NewPrivateKeyShares(t int) (*PrivateKeyShares, *PublicKeyShares) { - var prv bls.SecretKey - prv.SetByCSPRNG() - msk := prv.GetMasterSecretKey(t) - mpk := bls.GetMasterPublicKey(msk) - pubShare := NewEmptyPublicKeyShares() - pubShare.masterPublicKey = mpk - return &PrivateKeyShares{ - masterPrivateKey: msk, - shareIndex: make(map[ID]int), - }, pubShare -} - -// NewEmptyPrivateKeyShares creates an empty private key shares. -func NewEmptyPrivateKeyShares() *PrivateKeyShares { - return &PrivateKeyShares{ - shareIndex: make(map[ID]int), - } -} - -// SetParticipants sets the DKG participants. -func (prvs *PrivateKeyShares) SetParticipants(IDs IDs) { - prvs.shares = make([]PrivateKey, len(IDs)) - prvs.shareIndex = make(map[ID]int, len(IDs)) - for idx, ID := range IDs { - // #nosec G104 - prvs.shares[idx].privateKey.Set(prvs.masterPrivateKey, &ID) - prvs.shareIndex[ID] = idx - } -} - -// AddShare adds a share. -func (prvs *PrivateKeyShares) AddShare(ID ID, share *PrivateKey) error { - if idx, exist := prvs.shareIndex[ID]; exist { - if !share.privateKey.IsEqual(&prvs.shares[idx].privateKey) { - return ErrDuplicatedShare - } - return nil - } - prvs.shareIndex[ID] = len(prvs.shares) - prvs.shares = append(prvs.shares, *share) - return nil -} - -// RecoverPrivateKey recovers private key from the shares. -func (prvs *PrivateKeyShares) RecoverPrivateKey(qualifyIDs IDs) ( - *PrivateKey, error) { - var prv PrivateKey - if len(qualifyIDs) == 0 { - return nil, ErrNoIDToRecover - } - for i, ID := range qualifyIDs { - idx, exist := prvs.shareIndex[ID] - if !exist { - return nil, ErrShareNotFound - } - if i == 0 { - prv.privateKey = prvs.shares[idx].privateKey - continue - } - prv.privateKey.Add(&prvs.shares[idx].privateKey) - } - return &prv, nil -} - -// RecoverPublicKey recovers public key from the shares. -func (prvs *PrivateKeyShares) RecoverPublicKey(qualifyIDs IDs) ( - *PublicKey, error) { - var pub PublicKey - if len(qualifyIDs) == 0 { - return nil, ErrNoIDToRecover - } - for i, ID := range qualifyIDs { - idx, exist := prvs.shareIndex[ID] - if !exist { - return nil, ErrShareNotFound - } - if i == 0 { - pub.publicKey = *prvs.shares[idx].privateKey.GetPublicKey() - continue - } - pub.publicKey.Add(prvs.shares[idx].privateKey.GetPublicKey()) - } - return &pub, nil -} - -// Share returns the share for the ID. -func (prvs *PrivateKeyShares) Share(ID ID) (*PrivateKey, bool) { - idx, exist := prvs.shareIndex[ID] - if !exist { - return nil, false - } - return &prvs.shares[idx], true -} - -// NewEmptyPublicKeyShares creates an empty public key shares. -func NewEmptyPublicKeyShares() *PublicKeyShares { - pubShares := &PublicKeyShares{} - pubShares.cache.Store(&publicKeySharesCache{ - index: make(map[ID]int), - }) - return pubShares -} - -// Move will invalidate itself. Do not access to original reference. -func (pubs *PublicKeyShares) Move() *PublicKeyShares { - return pubs -} - -// Share returns the share for the ID. -func (pubs *PublicKeyShares) Share(ID ID) (*PublicKey, error) { - cache := pubs.cache.Load().(*publicKeySharesCache) - idx, exist := cache.index[ID] - if exist { - return &cache.share[idx], nil - } - var pk PublicKey - if err := pk.publicKey.Set(pubs.masterPublicKey, &ID); err != nil { - return nil, err - } - if err := pubs.AddShare(ID, &pk); err != nil { - return nil, err - } - return &pk, nil -} - -// AddShare adds a share. -func (pubs *PublicKeyShares) AddShare(shareID ID, share *PublicKey) error { - cache := pubs.cache.Load().(*publicKeySharesCache) - if idx, exist := cache.index[shareID]; exist { - if !share.publicKey.IsEqual(&cache.share[idx].publicKey) { - return ErrDuplicatedShare - } - return nil - } - pubs.lock.Lock() - defer pubs.lock.Unlock() - cache = pubs.cache.Load().(*publicKeySharesCache) - newCache := &publicKeySharesCache{ - index: make(map[ID]int, len(cache.index)+1), - share: make([]PublicKey, len(cache.share), len(cache.share)+1), - } - for k, v := range cache.index { - newCache.index[k] = v - } - copy(newCache.share, cache.share) - newCache.index[shareID] = len(newCache.share) - newCache.share = append(newCache.share, *share) - pubs.cache.Store(newCache) - return nil -} - -// VerifyPrvShare verifies if the private key shares is valid. -func (pubs *PublicKeyShares) VerifyPrvShare(ID ID, share *PrivateKey) ( - bool, error) { - var pk bls.PublicKey - if err := pk.Set(pubs.masterPublicKey, &ID); err != nil { - return false, err - } - return pk.IsEqual(share.privateKey.GetPublicKey()), nil -} - -// VerifyPubShare verifies if the public key shares is valid. -func (pubs *PublicKeyShares) VerifyPubShare(ID ID, share *PublicKey) ( - bool, error) { - var pk bls.PublicKey - if err := pk.Set(pubs.masterPublicKey, &ID); err != nil { - return false, err - } - return pk.IsEqual(&share.publicKey), nil -} - -// RecoverPublicKey recovers private key from the shares. -func (pubs *PublicKeyShares) RecoverPublicKey(qualifyIDs IDs) ( - *PublicKey, error) { - var pub PublicKey - if len(qualifyIDs) == 0 { - return nil, ErrNoIDToRecover - } - for i, ID := range qualifyIDs { - pk, err := pubs.Share(ID) - if err != nil { - return nil, err - } - if i == 0 { - pub.publicKey = pk.publicKey - continue - } - pub.publicKey.Add(&pk.publicKey) - } - return &pub, nil -} - -// MasterKeyBytes returns []byte representation of master public key. -func (pubs *PublicKeyShares) MasterKeyBytes() []byte { - bytes := make([]byte, 0, len(pubs.masterPublicKey)*publicKeyLength) - for _, pk := range pubs.masterPublicKey { - bytes = append(bytes, pk.Serialize()...) - } - return bytes -} - -// newPublicKey creates a new PublicKey structure. -func newPublicKey(prvKey *bls.SecretKey) *PublicKey { - return &PublicKey{ - publicKey: *prvKey.GetPublicKey(), - } -} - -// newPublicKeyFromBytes create a new PublicKey structure -// from bytes representation of bls.PublicKey -func newPublicKeyFromBytes(b []byte) (*PublicKey, error) { - var pub PublicKey - err := pub.publicKey.Deserialize(b) - return &pub, err -} - -// PublicKey returns the public key associate this private key. -func (prv *PrivateKey) PublicKey() crypto.PublicKey { - return prv.publicKey -} - -// Sign calculates a signature. -func (prv *PrivateKey) Sign(hash common.Hash) (crypto.Signature, error) { - msg := string(hash[:]) - sign := prv.privateKey.Sign(msg) - return crypto.Signature{ - Type: cryptoType, - Signature: sign.Serialize(), - }, nil -} - -// Bytes returns []byte representation of private key. -func (prv *PrivateKey) Bytes() []byte { - return prv.privateKey.GetLittleEndian() -} - -// SetBytes sets the private key data to []byte. -func (prv *PrivateKey) SetBytes(bytes []byte) error { - var key bls.SecretKey - if err := key.SetLittleEndian(bytes); err != nil { - return err - } - prv.privateKey = key - prv.publicKey = *newPublicKey(&prv.privateKey) - return nil -} - -// String returns string representation of privat key. -func (prv *PrivateKey) String() string { - return prv.privateKey.GetHexString() -} - -// VerifySignature checks that the given public key created signature over hash. -func (pub PublicKey) VerifySignature( - hash common.Hash, signature crypto.Signature) bool { - if len(signature.Signature) == 0 { - return false - } - var sig bls.Sign - if err := sig.Deserialize(signature.Signature[:]); err != nil { - fmt.Println(err) - return false - } - msg := string(hash[:]) - return sig.Verify(&pub.publicKey, msg) -} - -// Bytes returns []byte representation of public key. -func (pub PublicKey) Bytes() []byte { - return pub.publicKey.Serialize() -} - -// Serialize return bytes representation of public key. -func (pub *PublicKey) Serialize() []byte { - return pub.publicKey.Serialize() -} - -// Deserialize parses bytes representation of public key. -func (pub *PublicKey) Deserialize(b []byte) error { - return pub.publicKey.Deserialize(b) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/utils.go deleted file mode 100644 index 9e470f0cf..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/dkg/utils.go +++ /dev/null @@ -1,92 +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 dkg - -import ( - "encoding/binary" - "fmt" - "math/rand" - - "github.com/dexon-foundation/bls/ffi/go/bls" - - "github.com/dexon-foundation/dexon-consensus/core/crypto" -) - -// PartialSignature is a partial signature in DKG+TSIG protocol. -type PartialSignature crypto.Signature - -var ( - // ErrEmptySignature is reported if the signature is empty. - ErrEmptySignature = fmt.Errorf("invalid empty signature") -) - -// RecoverSignature recovers TSIG signature. -func RecoverSignature(sigs []PartialSignature, signerIDs IDs) ( - crypto.Signature, error) { - blsSigs := make([]bls.Sign, len(sigs)) - for i, sig := range sigs { - if len(sig.Signature) == 0 { - return crypto.Signature{}, ErrEmptySignature - } - if err := blsSigs[i].Deserialize([]byte(sig.Signature)); err != nil { - return crypto.Signature{}, err - } - } - var recoverSig bls.Sign - if err := recoverSig.Recover(blsSigs, []bls.ID(signerIDs)); err != nil { - return crypto.Signature{}, err - } - return crypto.Signature{ - Type: cryptoType, - Signature: recoverSig.Serialize()}, nil -} - -// RecoverGroupPublicKey recovers group public key. -func RecoverGroupPublicKey(pubShares []*PublicKeyShares) *PublicKey { - var pub *PublicKey - for _, pubShare := range pubShares { - pk0 := pubShare.masterPublicKey[0] - if pub == nil { - pub = &PublicKey{ - publicKey: pk0, - } - } else { - pub.publicKey.Add(&pk0) - } - } - return pub -} - -// NewRandomPrivateKeyShares constructs a private key shares randomly. -func NewRandomPrivateKeyShares() *PrivateKeyShares { - // Generate IDs. - rndIDs := make(IDs, 0, 10) - for i := range rndIDs { - id := make([]byte, 8) - binary.LittleEndian.PutUint64(id, rand.Uint64()) - rndIDs[i] = NewID(id) - } - prvShares := NewEmptyPrivateKeyShares() - prvShares.SetParticipants(rndIDs) - for _, id := range rndIDs { - if err := prvShares.AddShare(id, NewPrivateKey()); err != nil { - panic(err) - } - } - return prvShares -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa/ecdsa.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa/ecdsa.go deleted file mode 100644 index 9da5f4fb5..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/ecdsa/ecdsa.go +++ /dev/null @@ -1,135 +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 ecdsa - -import ( - "crypto/ecdsa" - - dexCrypto "github.com/dexon-foundation/dexon/crypto" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" -) - -const cryptoType = "ecdsa" - -func init() { - if err := crypto.RegisterSigToPub(cryptoType, SigToPub); err != nil { - panic(err) - } -} - -// PrivateKey represents a private key structure used in geth and implments -// Crypto.PrivateKey interface. -type PrivateKey struct { - privateKey *ecdsa.PrivateKey -} - -// PublicKey represents a public key structure used in geth and implements -// Crypto.PublicKey interface. -type PublicKey struct { - publicKey *ecdsa.PublicKey -} - -// NewPrivateKey creates a new PrivateKey structure. -func NewPrivateKey() (*PrivateKey, error) { - key, err := dexCrypto.GenerateKey() - if err != nil { - return nil, err - } - return &PrivateKey{privateKey: key}, nil -} - -// NewPrivateKeyFromECDSA creates a new PrivateKey structure from -// ecdsa.PrivateKey. -func NewPrivateKeyFromECDSA(key *ecdsa.PrivateKey) *PrivateKey { - return &PrivateKey{privateKey: key} -} - -// NewPublicKeyFromECDSA creates a new PublicKey structure from -// ecdsa.PublicKey. -func NewPublicKeyFromECDSA(key *ecdsa.PublicKey) *PublicKey { - return &PublicKey{publicKey: key} -} - -// NewPublicKeyFromByteSlice constructs an eth.publicKey instance from -// a byte slice. -func NewPublicKeyFromByteSlice(b []byte) (crypto.PublicKey, error) { - pub, err := dexCrypto.UnmarshalPubkey(b) - if err != nil { - return &PublicKey{}, err - } - return &PublicKey{publicKey: pub}, nil -} - -// PublicKey returns the public key associate this private key. -func (prv *PrivateKey) PublicKey() crypto.PublicKey { - return NewPublicKeyFromECDSA(&(prv.privateKey.PublicKey)) -} - -// Sign calculates an ECDSA signature. -// -// This function is susceptible to chosen plaintext attacks that can leak -// information about the private key that is used for signing. Callers must -// be aware that the given hash cannot be chosen by an adversery. Common -// solution is to hash any input before calculating the signature. -// -// The produced signature is in the [R || S || V] format where V is 0 or 1. -func (prv *PrivateKey) Sign(hash common.Hash) ( - sig crypto.Signature, err error) { - s, err := dexCrypto.Sign(hash[:], prv.privateKey) - sig = crypto.Signature{ - Type: cryptoType, - Signature: s, - } - return -} - -// VerifySignature checks that the given public key created signature over hash. -// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) -// format. -// The signature should have the 64 byte [R || S] format. -func (pub *PublicKey) VerifySignature( - hash common.Hash, signature crypto.Signature) bool { - sig := signature.Signature - if len(sig) == 65 { - // The last byte is for ecrecover. - sig = sig[:64] - } - return dexCrypto.VerifySignature(pub.Bytes(), hash[:], sig) -} - -// Compress encodes a public key to the 33-byte compressed format. -func (pub *PublicKey) Compress() []byte { - return dexCrypto.CompressPubkey(pub.publicKey) -} - -// Bytes returns the []byte representation of uncompressed public key. (65 bytes) -func (pub *PublicKey) Bytes() []byte { - return dexCrypto.FromECDSAPub(pub.publicKey) -} - -// SigToPub returns the PublicKey that created the given signature. -func SigToPub( - hash common.Hash, signature crypto.Signature) (crypto.PublicKey, error) { - key, err := dexCrypto.SigToPub(hash[:], signature.Signature[:]) - if err != nil { - return &PublicKey{}, err - } - return &PublicKey{publicKey: key}, nil -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/interfaces.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/interfaces.go deleted file mode 100644 index f3e01e42c..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/interfaces.go +++ /dev/null @@ -1,48 +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 crypto - -import ( - "github.com/dexon-foundation/dexon-consensus/common" -) - -// Signature is the basic signature type in DEXON. -type Signature struct { - Type string - Signature []byte -} - -// PrivateKey describes the asymmetric cryptography interface that interacts -// with the private key. -type PrivateKey interface { - // PublicKey returns the public key associate this private key. - PublicKey() PublicKey - - // Sign calculates a signature. - Sign(hash common.Hash) (Signature, error) -} - -// PublicKey describes the asymmetric cryptography interface that interacts -// with the public key. -type PublicKey interface { - // VerifySignature checks that the given public key created signature over hash. - VerifySignature(hash common.Hash, signature Signature) bool - - // Bytes returns the []byte representation of public key. - Bytes() []byte -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/utils.go deleted file mode 100644 index 59e91f5a5..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/crypto/utils.go +++ /dev/null @@ -1,80 +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 crypto - -import ( - "encoding/hex" - "fmt" - - "github.com/dexon-foundation/dexon/crypto" - - "github.com/dexon-foundation/dexon-consensus/common" -) - -var ( - // ErrSigToPubTypeNotFound is reported if the type is already used. - ErrSigToPubTypeNotFound = fmt.Errorf("type of sigToPub is not found") - - // ErrSigToPubTypeAlreadyExist is reported if the type is already used. - ErrSigToPubTypeAlreadyExist = fmt.Errorf("type of sigToPub is already exist") -) - -// SigToPubFn is a function to recover public key from signature. -type SigToPubFn func(hash common.Hash, signature Signature) (PublicKey, error) - -var sigToPubCB map[string]SigToPubFn - -func init() { - sigToPubCB = make(map[string]SigToPubFn) -} - -// Keccak256Hash calculates and returns the Keccak256 hash of the input data, -// converting it to an internal Hash data structure. -func Keccak256Hash(data ...[]byte) (h common.Hash) { - return common.Hash(crypto.Keccak256Hash(data...)) -} - -// Clone returns a deep copy of a signature. -func (sig Signature) Clone() Signature { - return Signature{ - Type: sig.Type, - Signature: sig.Signature[:], - } -} - -func (sig Signature) String() string { - return hex.EncodeToString([]byte(sig.Signature[:])) -} - -// RegisterSigToPub registers a sigToPub function of type. -func RegisterSigToPub(sigType string, sigToPub SigToPubFn) error { - if _, exist := sigToPubCB[sigType]; exist { - return ErrSigToPubTypeAlreadyExist - } - sigToPubCB[sigType] = sigToPub - return nil -} - -// SigToPub recovers public key from signature. -func SigToPub(hash common.Hash, signature Signature) (PublicKey, error) { - sigToPub, exist := sigToPubCB[signature.Type] - if !exist { - return nil, ErrSigToPubTypeNotFound - } - return sigToPub(hash, signature) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/interfaces.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/interfaces.go deleted file mode 100644 index a571a8021..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/interfaces.go +++ /dev/null @@ -1,100 +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 db - -import ( - "errors" - "fmt" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -var ( - // ErrBlockExists is the error when block eixsts. - ErrBlockExists = errors.New("block exists") - // ErrBlockDoesNotExist is the error when block does not eixst. - ErrBlockDoesNotExist = errors.New("block does not exist") - // ErrIterationFinished is the error to check if the iteration is finished. - ErrIterationFinished = errors.New("iteration finished") - // ErrEmptyPath is the error when the required path is empty. - ErrEmptyPath = fmt.Errorf("empty path") - // ErrClosed is the error when using DB after it's closed. - ErrClosed = fmt.Errorf("db closed") - // ErrNotImplemented is the error that some interface is not implemented. - ErrNotImplemented = fmt.Errorf("not implemented") - // ErrInvalidCompactionChainTipHeight means the newly updated height of - // the tip of compaction chain is invalid, usually means it's smaller than - // current cached one. - ErrInvalidCompactionChainTipHeight = fmt.Errorf( - "invalid compaction chain tip height") - // ErrDKGPrivateKeyExists raised when attempting to save DKG private key - // that already saved. - ErrDKGPrivateKeyExists = errors.New("dkg private key exists") - // ErrDKGPrivateKeyDoesNotExist raised when the DKG private key of the - // requested round does not exists. - ErrDKGPrivateKeyDoesNotExist = errors.New("dkg private key does not exists") - // ErrDKGProtocolExists raised when attempting to save DKG protocol - // that already saved. - ErrDKGProtocolExists = errors.New("dkg protocol exists") - // ErrDKGProtocolDoesNotExist raised when the DKG protocol of the - // requested round does not exists. - ErrDKGProtocolDoesNotExist = errors.New("dkg protocol does not exists") -) - -// Database is the interface for a Database. -type Database interface { - Reader - Writer - - // Close allows database implementation able to - // release resource when finishing. - Close() error -} - -// Reader defines the interface for reading blocks into DB. -type Reader interface { - HasBlock(hash common.Hash) bool - GetBlock(hash common.Hash) (types.Block, error) - GetAllBlocks() (BlockIterator, error) - - // GetCompactionChainTipInfo returns the block hash and finalization height - // of the tip block of compaction chain. Empty hash and zero height means - // the compaction chain is empty. - GetCompactionChainTipInfo() (common.Hash, uint64) - - // DKG Private Key related methods. - GetDKGPrivateKey(round, reset uint64) (dkg.PrivateKey, error) - GetDKGProtocol() (dkgProtocol DKGProtocolInfo, err error) -} - -// Writer defines the interface for writing blocks into DB. -type Writer interface { - UpdateBlock(block types.Block) error - PutBlock(block types.Block) error - PutCompactionChainTipInfo(common.Hash, uint64) error - PutDKGPrivateKey(round, reset uint64, pk dkg.PrivateKey) error - PutOrUpdateDKGProtocol(dkgProtocol DKGProtocolInfo) error -} - -// BlockIterator defines an iterator on blocks hold -// in a DB. -type BlockIterator interface { - NextBlock() (types.Block, error) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go deleted file mode 100644 index da8bc0bc1..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go +++ /dev/null @@ -1,573 +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 db - -import ( - "encoding/binary" - "io" - - "github.com/syndtr/goleveldb/leveldb" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" - "github.com/dexon-foundation/dexon-consensus/core/types" - "github.com/dexon-foundation/dexon/rlp" -) - -var ( - blockKeyPrefix = []byte("b-") - compactionChainTipInfoKey = []byte("cc-tip") - dkgPrivateKeyKeyPrefix = []byte("dkg-prvs") - dkgProtocolInfoKeyPrefix = []byte("dkg-protocol-info") -) - -type compactionChainTipInfo struct { - Height uint64 `json:"height"` - Hash common.Hash `json:"hash"` -} - -// DKGProtocolInfo DKG protocol info. -type DKGProtocolInfo struct { - ID types.NodeID - Round uint64 - Threshold uint64 - IDMap NodeIDToDKGID - MpkMap NodeIDToPubShares - MasterPrivateShare dkg.PrivateKeyShares - IsMasterPrivateShareEmpty bool - PrvShares dkg.PrivateKeyShares - IsPrvSharesEmpty bool - PrvSharesReceived NodeID - NodeComplained NodeID - AntiComplaintReceived NodeIDToNodeIDs - Step uint64 - Reset uint64 -} - -type dkgPrivateKey struct { - PK dkg.PrivateKey - Reset uint64 -} - -// Equal compare with target DKGProtocolInfo. -func (info *DKGProtocolInfo) Equal(target *DKGProtocolInfo) bool { - if !info.ID.Equal(target.ID) || - info.Round != target.Round || - info.Threshold != target.Threshold || - info.IsMasterPrivateShareEmpty != target.IsMasterPrivateShareEmpty || - info.IsPrvSharesEmpty != target.IsPrvSharesEmpty || - info.Step != target.Step || - info.Reset != target.Reset || - !info.MasterPrivateShare.Equal(&target.MasterPrivateShare) || - !info.PrvShares.Equal(&target.PrvShares) { - return false - } - - if len(info.IDMap) != len(target.IDMap) { - return false - } - for k, v := range info.IDMap { - tV, exist := target.IDMap[k] - if !exist { - return false - } - - if !v.IsEqual(&tV) { - return false - } - } - - if len(info.MpkMap) != len(target.MpkMap) { - return false - } - for k, v := range info.MpkMap { - tV, exist := target.MpkMap[k] - if !exist { - return false - } - - if !v.Equal(tV) { - return false - } - } - - if len(info.PrvSharesReceived) != len(target.PrvSharesReceived) { - return false - } - for k := range info.PrvSharesReceived { - _, exist := target.PrvSharesReceived[k] - if !exist { - return false - } - } - - if len(info.NodeComplained) != len(target.NodeComplained) { - return false - } - for k := range info.NodeComplained { - _, exist := target.NodeComplained[k] - if !exist { - return false - } - } - - if len(info.AntiComplaintReceived) != len(target.AntiComplaintReceived) { - return false - } - for k, v := range info.AntiComplaintReceived { - tV, exist := target.AntiComplaintReceived[k] - if !exist { - return false - } - - if len(v) != len(tV) { - return false - } - for kk := range v { - _, exist := tV[kk] - if !exist { - return false - } - } - } - - return true -} - -// NodeIDToNodeIDs the map with NodeID to NodeIDs. -type NodeIDToNodeIDs map[types.NodeID]map[types.NodeID]struct{} - -// EncodeRLP implements rlp.Encoder -func (m NodeIDToNodeIDs) EncodeRLP(w io.Writer) error { - var allBytes [][][]byte - for k, v := range m { - kBytes, err := k.MarshalText() - if err != nil { - return err - } - allBytes = append(allBytes, [][]byte{kBytes}) - - var vBytes [][]byte - for subK := range v { - bytes, err := subK.MarshalText() - if err != nil { - return err - } - vBytes = append(vBytes, bytes) - } - allBytes = append(allBytes, vBytes) - } - - return rlp.Encode(w, allBytes) -} - -// DecodeRLP implements rlp.Encoder -func (m *NodeIDToNodeIDs) DecodeRLP(s *rlp.Stream) error { - *m = make(NodeIDToNodeIDs) - var dec [][][]byte - if err := s.Decode(&dec); err != nil { - return err - } - - for i := 0; i < len(dec); i += 2 { - key := types.NodeID{} - err := key.UnmarshalText(dec[i][0]) - if err != nil { - return err - } - - valueMap := map[types.NodeID]struct{}{} - for _, v := range dec[i+1] { - value := types.NodeID{} - err := value.UnmarshalText(v) - if err != nil { - return err - } - - valueMap[value] = struct{}{} - } - - (*m)[key] = valueMap - } - - return nil -} - -// NodeID the map with NodeID. -type NodeID map[types.NodeID]struct{} - -// EncodeRLP implements rlp.Encoder -func (m NodeID) EncodeRLP(w io.Writer) error { - var allBytes [][]byte - for k := range m { - kBytes, err := k.MarshalText() - if err != nil { - return err - } - allBytes = append(allBytes, kBytes) - } - - return rlp.Encode(w, allBytes) -} - -// DecodeRLP implements rlp.Encoder -func (m *NodeID) DecodeRLP(s *rlp.Stream) error { - *m = make(NodeID) - var dec [][]byte - if err := s.Decode(&dec); err != nil { - return err - } - - for i := 0; i < len(dec); i++ { - key := types.NodeID{} - err := key.UnmarshalText(dec[i]) - if err != nil { - return err - } - - (*m)[key] = struct{}{} - } - - return nil -} - -// NodeIDToPubShares the map with NodeID to PublicKeyShares. -type NodeIDToPubShares map[types.NodeID]*dkg.PublicKeyShares - -// EncodeRLP implements rlp.Encoder -func (m NodeIDToPubShares) EncodeRLP(w io.Writer) error { - var allBytes [][]byte - for k, v := range m { - kBytes, err := k.MarshalText() - if err != nil { - return err - } - allBytes = append(allBytes, kBytes) - - bytes, err := rlp.EncodeToBytes(v) - if err != nil { - return err - } - allBytes = append(allBytes, bytes) - } - - return rlp.Encode(w, allBytes) -} - -// DecodeRLP implements rlp.Encoder -func (m *NodeIDToPubShares) DecodeRLP(s *rlp.Stream) error { - *m = make(NodeIDToPubShares) - var dec [][]byte - if err := s.Decode(&dec); err != nil { - return err - } - - for i := 0; i < len(dec); i += 2 { - key := types.NodeID{} - err := key.UnmarshalText(dec[i]) - if err != nil { - return err - } - - value := dkg.PublicKeyShares{} - err = rlp.DecodeBytes(dec[i+1], &value) - if err != nil { - return err - } - - (*m)[key] = &value - } - - return nil -} - -// NodeIDToDKGID the map with NodeID to DKGID. -type NodeIDToDKGID map[types.NodeID]dkg.ID - -// EncodeRLP implements rlp.Encoder -func (m NodeIDToDKGID) EncodeRLP(w io.Writer) error { - var allBytes [][]byte - for k, v := range m { - kBytes, err := k.MarshalText() - if err != nil { - return err - } - allBytes = append(allBytes, kBytes) - allBytes = append(allBytes, v.GetLittleEndian()) - } - - return rlp.Encode(w, allBytes) -} - -// DecodeRLP implements rlp.Encoder -func (m *NodeIDToDKGID) DecodeRLP(s *rlp.Stream) error { - *m = make(NodeIDToDKGID) - var dec [][]byte - if err := s.Decode(&dec); err != nil { - return err - } - - for i := 0; i < len(dec); i += 2 { - key := types.NodeID{} - err := key.UnmarshalText(dec[i]) - if err != nil { - return err - } - - value := dkg.ID{} - err = value.SetLittleEndian(dec[i+1]) - if err != nil { - return err - } - - (*m)[key] = value - } - - return nil -} - -// LevelDBBackedDB is a leveldb backed DB implementation. -type LevelDBBackedDB struct { - db *leveldb.DB -} - -// NewLevelDBBackedDB initialize a leveldb-backed database. -func NewLevelDBBackedDB( - path string) (lvl *LevelDBBackedDB, err error) { - - dbInst, err := leveldb.OpenFile(path, nil) - if err != nil { - return - } - lvl = &LevelDBBackedDB{db: dbInst} - return -} - -// Close implement Closer interface, which would release allocated resource. -func (lvl *LevelDBBackedDB) Close() error { - return lvl.db.Close() -} - -// HasBlock implements the Reader.Has method. -func (lvl *LevelDBBackedDB) HasBlock(hash common.Hash) bool { - exists, err := lvl.internalHasBlock(lvl.getBlockKey(hash)) - if err != nil { - panic(err) - } - return exists -} - -func (lvl *LevelDBBackedDB) internalHasBlock(key []byte) (bool, error) { - return lvl.db.Has(key, nil) -} - -// GetBlock implements the Reader.GetBlock method. -func (lvl *LevelDBBackedDB) GetBlock( - hash common.Hash) (block types.Block, err error) { - queried, err := lvl.db.Get(lvl.getBlockKey(hash), nil) - if err != nil { - if err == leveldb.ErrNotFound { - err = ErrBlockDoesNotExist - } - return - } - err = rlp.DecodeBytes(queried, &block) - return -} - -// UpdateBlock implements the Writer.UpdateBlock method. -func (lvl *LevelDBBackedDB) UpdateBlock(block types.Block) (err error) { - // NOTE: we didn't handle changes of block hash (and it - // should not happen). - marshaled, err := rlp.EncodeToBytes(&block) - if err != nil { - return - } - blockKey := lvl.getBlockKey(block.Hash) - exists, err := lvl.internalHasBlock(blockKey) - if err != nil { - return - } - if !exists { - err = ErrBlockDoesNotExist - return - } - err = lvl.db.Put(blockKey, marshaled, nil) - return -} - -// PutBlock implements the Writer.PutBlock method. -func (lvl *LevelDBBackedDB) PutBlock(block types.Block) (err error) { - marshaled, err := rlp.EncodeToBytes(&block) - if err != nil { - return - } - blockKey := lvl.getBlockKey(block.Hash) - exists, err := lvl.internalHasBlock(blockKey) - if err != nil { - return - } - if exists { - err = ErrBlockExists - return - } - err = lvl.db.Put(blockKey, marshaled, nil) - return -} - -// GetAllBlocks implements Reader.GetAllBlocks method, which allows callers -// to retrieve all blocks in DB. -func (lvl *LevelDBBackedDB) GetAllBlocks() (BlockIterator, error) { - return nil, ErrNotImplemented -} - -// PutCompactionChainTipInfo saves tip of compaction chain into the database. -func (lvl *LevelDBBackedDB) PutCompactionChainTipInfo( - blockHash common.Hash, height uint64) error { - marshaled, err := rlp.EncodeToBytes(&compactionChainTipInfo{ - Hash: blockHash, - Height: height, - }) - if err != nil { - return err - } - // Check current cached tip info to make sure the one to be updated is - // valid. - info, err := lvl.internalGetCompactionChainTipInfo() - if err != nil { - return err - } - if info.Height+1 != height { - return ErrInvalidCompactionChainTipHeight - } - return lvl.db.Put(compactionChainTipInfoKey, marshaled, nil) -} - -func (lvl *LevelDBBackedDB) internalGetCompactionChainTipInfo() ( - info compactionChainTipInfo, err error) { - queried, err := lvl.db.Get(compactionChainTipInfoKey, nil) - if err != nil { - if err == leveldb.ErrNotFound { - err = nil - } - return - } - err = rlp.DecodeBytes(queried, &info) - return -} - -// GetCompactionChainTipInfo get the tip info of compaction chain into the -// database. -func (lvl *LevelDBBackedDB) GetCompactionChainTipInfo() ( - hash common.Hash, height uint64) { - info, err := lvl.internalGetCompactionChainTipInfo() - if err != nil { - panic(err) - } - hash, height = info.Hash, info.Height - return -} - -// GetDKGPrivateKey get DKG private key of one round. -func (lvl *LevelDBBackedDB) GetDKGPrivateKey(round, reset uint64) ( - prv dkg.PrivateKey, err error) { - queried, err := lvl.db.Get(lvl.getDKGPrivateKeyKey(round), nil) - if err != nil { - if err == leveldb.ErrNotFound { - err = ErrDKGPrivateKeyDoesNotExist - } - return - } - pk := dkgPrivateKey{} - err = rlp.DecodeBytes(queried, &pk) - if pk.Reset != reset { - err = ErrDKGPrivateKeyDoesNotExist - return - } - prv = pk.PK - return -} - -// PutDKGPrivateKey save DKG private key of one round. -func (lvl *LevelDBBackedDB) PutDKGPrivateKey( - round, reset uint64, prv dkg.PrivateKey) error { - // Check existence. - _, err := lvl.GetDKGPrivateKey(round, reset) - if err == nil { - return ErrDKGPrivateKeyExists - } - if err != ErrDKGPrivateKeyDoesNotExist { - return err - } - pk := &dkgPrivateKey{ - PK: prv, - Reset: reset, - } - marshaled, err := rlp.EncodeToBytes(&pk) - if err != nil { - return err - } - return lvl.db.Put( - lvl.getDKGPrivateKeyKey(round), marshaled, nil) -} - -// GetDKGProtocol get DKG protocol. -func (lvl *LevelDBBackedDB) GetDKGProtocol() ( - info DKGProtocolInfo, err error) { - queried, err := lvl.db.Get(lvl.getDKGProtocolInfoKey(), nil) - if err != nil { - if err == leveldb.ErrNotFound { - err = ErrDKGProtocolDoesNotExist - } - return - } - - err = rlp.DecodeBytes(queried, &info) - return -} - -// PutOrUpdateDKGProtocol save DKG protocol. -func (lvl *LevelDBBackedDB) PutOrUpdateDKGProtocol(info DKGProtocolInfo) error { - marshaled, err := rlp.EncodeToBytes(&info) - if err != nil { - return err - } - return lvl.db.Put(lvl.getDKGProtocolInfoKey(), marshaled, nil) -} - -func (lvl *LevelDBBackedDB) getBlockKey(hash common.Hash) (ret []byte) { - ret = make([]byte, len(blockKeyPrefix)+len(hash[:])) - copy(ret, blockKeyPrefix) - copy(ret[len(blockKeyPrefix):], hash[:]) - return -} - -func (lvl *LevelDBBackedDB) getDKGPrivateKeyKey( - round uint64) (ret []byte) { - ret = make([]byte, len(dkgPrivateKeyKeyPrefix)+8) - copy(ret, dkgPrivateKeyKeyPrefix) - binary.LittleEndian.PutUint64( - ret[len(dkgPrivateKeyKeyPrefix):], round) - return -} - -func (lvl *LevelDBBackedDB) getDKGProtocolInfoKey() (ret []byte) { - ret = make([]byte, len(dkgProtocolInfoKeyPrefix)+8) - copy(ret, dkgProtocolInfoKeyPrefix) - return -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/memory.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/memory.go deleted file mode 100644 index 6555de855..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/db/memory.go +++ /dev/null @@ -1,262 +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 db - -import ( - "encoding/json" - "io/ioutil" - "os" - "sync" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto/dkg" - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -type blockSeqIterator struct { - idx int - db *MemBackedDB -} - -// NextBlock implemenets BlockIterator.NextBlock method. -func (seq *blockSeqIterator) NextBlock() (types.Block, error) { - curIdx := seq.idx - seq.idx++ - return seq.db.getBlockByIndex(curIdx) -} - -// MemBackedDB is a memory backed DB implementation. -type MemBackedDB struct { - blocksLock sync.RWMutex - blockHashSequence common.Hashes - blocksByHash map[common.Hash]*types.Block - compactionChainTipLock sync.RWMutex - compactionChainTipHash common.Hash - compactionChainTipHeight uint64 - dkgPrivateKeysLock sync.RWMutex - dkgPrivateKeys map[uint64]*dkgPrivateKey - dkgProtocolLock sync.RWMutex - dkgProtocolInfo *DKGProtocolInfo - persistantFilePath string -} - -// NewMemBackedDB initialize a memory-backed database. -func NewMemBackedDB(persistantFilePath ...string) ( - dbInst *MemBackedDB, err error) { - dbInst = &MemBackedDB{ - blockHashSequence: common.Hashes{}, - blocksByHash: make(map[common.Hash]*types.Block), - dkgPrivateKeys: make(map[uint64]*dkgPrivateKey), - } - if len(persistantFilePath) == 0 || len(persistantFilePath[0]) == 0 { - return - } - dbInst.persistantFilePath = persistantFilePath[0] - buf, err := ioutil.ReadFile(dbInst.persistantFilePath) - if err != nil { - if !os.IsNotExist(err) { - // Something unexpected happened. - return - } - // It's expected behavior that file doesn't exists, we should not - // report error on it. - err = nil - return - } - - // Init this instance by file content, it's a temporary way - // to export those private field for JSON encoding. - toLoad := struct { - Sequence common.Hashes - ByHash map[common.Hash]*types.Block - }{} - err = json.Unmarshal(buf, &toLoad) - if err != nil { - return - } - dbInst.blockHashSequence = toLoad.Sequence - dbInst.blocksByHash = toLoad.ByHash - return -} - -// HasBlock returns wheter or not the DB has a block identified with the hash. -func (m *MemBackedDB) HasBlock(hash common.Hash) bool { - m.blocksLock.RLock() - defer m.blocksLock.RUnlock() - - _, ok := m.blocksByHash[hash] - return ok -} - -// GetBlock returns a block given a hash. -func (m *MemBackedDB) GetBlock(hash common.Hash) (types.Block, error) { - m.blocksLock.RLock() - defer m.blocksLock.RUnlock() - - return m.internalGetBlock(hash) -} - -func (m *MemBackedDB) internalGetBlock(hash common.Hash) (types.Block, error) { - b, ok := m.blocksByHash[hash] - if !ok { - return types.Block{}, ErrBlockDoesNotExist - } - return *b, nil -} - -// PutBlock inserts a new block into the database. -func (m *MemBackedDB) PutBlock(block types.Block) error { - if m.HasBlock(block.Hash) { - return ErrBlockExists - } - - m.blocksLock.Lock() - defer m.blocksLock.Unlock() - - m.blockHashSequence = append(m.blockHashSequence, block.Hash) - m.blocksByHash[block.Hash] = &block - return nil -} - -// UpdateBlock updates a block in the database. -func (m *MemBackedDB) UpdateBlock(block types.Block) error { - if !m.HasBlock(block.Hash) { - return ErrBlockDoesNotExist - } - - m.blocksLock.Lock() - defer m.blocksLock.Unlock() - - m.blocksByHash[block.Hash] = &block - return nil -} - -// PutCompactionChainTipInfo saves tip of compaction chain into the database. -func (m *MemBackedDB) PutCompactionChainTipInfo( - blockHash common.Hash, height uint64) error { - m.compactionChainTipLock.Lock() - defer m.compactionChainTipLock.Unlock() - if m.compactionChainTipHeight+1 != height { - return ErrInvalidCompactionChainTipHeight - } - m.compactionChainTipHeight = height - m.compactionChainTipHash = blockHash - return nil -} - -// GetCompactionChainTipInfo get the tip info of compaction chain into the -// database. -func (m *MemBackedDB) GetCompactionChainTipInfo() ( - hash common.Hash, height uint64) { - m.compactionChainTipLock.RLock() - defer m.compactionChainTipLock.RUnlock() - return m.compactionChainTipHash, m.compactionChainTipHeight -} - -// GetDKGPrivateKey get DKG private key of one round. -func (m *MemBackedDB) GetDKGPrivateKey(round, reset uint64) ( - dkg.PrivateKey, error) { - m.dkgPrivateKeysLock.RLock() - defer m.dkgPrivateKeysLock.RUnlock() - if prv, exists := m.dkgPrivateKeys[round]; exists && prv.Reset == reset { - return prv.PK, nil - } - return dkg.PrivateKey{}, ErrDKGPrivateKeyDoesNotExist -} - -// PutDKGPrivateKey save DKG private key of one round. -func (m *MemBackedDB) PutDKGPrivateKey( - round, reset uint64, prv dkg.PrivateKey) error { - m.dkgPrivateKeysLock.Lock() - defer m.dkgPrivateKeysLock.Unlock() - if prv, exists := m.dkgPrivateKeys[round]; exists && prv.Reset == reset { - return ErrDKGPrivateKeyExists - } - m.dkgPrivateKeys[round] = &dkgPrivateKey{ - PK: prv, - Reset: reset, - } - return nil -} - -// GetDKGProtocol get DKG protocol. -func (m *MemBackedDB) GetDKGProtocol() ( - DKGProtocolInfo, error) { - m.dkgProtocolLock.RLock() - defer m.dkgProtocolLock.RUnlock() - if m.dkgProtocolInfo == nil { - return DKGProtocolInfo{}, ErrDKGProtocolDoesNotExist - } - - return *m.dkgProtocolInfo, nil -} - -// PutOrUpdateDKGProtocol save DKG protocol. -func (m *MemBackedDB) PutOrUpdateDKGProtocol(dkgProtocol DKGProtocolInfo) error { - m.dkgProtocolLock.Lock() - defer m.dkgProtocolLock.Unlock() - m.dkgProtocolInfo = &dkgProtocol - return nil -} - -// Close implement Closer interface, which would release allocated resource. -func (m *MemBackedDB) Close() (err error) { - // Save internal state to a pretty-print json file. It's a temporary way - // to dump private file via JSON encoding. - if len(m.persistantFilePath) == 0 { - return - } - - m.blocksLock.RLock() - defer m.blocksLock.RUnlock() - - toDump := struct { - Sequence common.Hashes - ByHash map[common.Hash]*types.Block - }{ - Sequence: m.blockHashSequence, - ByHash: m.blocksByHash, - } - - // Dump to JSON with 2-space indent. - buf, err := json.Marshal(&toDump) - if err != nil { - return - } - - err = ioutil.WriteFile(m.persistantFilePath, buf, 0644) - return -} - -func (m *MemBackedDB) getBlockByIndex(idx int) (types.Block, error) { - m.blocksLock.RLock() - defer m.blocksLock.RUnlock() - - if idx >= len(m.blockHashSequence) { - return types.Block{}, ErrIterationFinished - } - - hash := m.blockHashSequence[idx] - return m.internalGetBlock(hash) -} - -// GetAllBlocks implement Reader.GetAllBlocks method, which allows caller -// to retrieve all blocks in DB. -func (m *MemBackedDB) GetAllBlocks() (BlockIterator, error) { - return &blockSeqIterator{db: m}, nil -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go deleted file mode 100644 index ce5c89c47..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/dkg-tsig-protocol.go +++ /dev/null @@ -1,709 +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 core - -import ( - "fmt" - "sync" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "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" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// Errors for dkg module. -var ( - ErrNotDKGParticipant = fmt.Errorf( - "not a DKG participant") - ErrNotQualifyDKGParticipant = fmt.Errorf( - "not a qualified DKG participant") - ErrIDShareNotFound = fmt.Errorf( - "private share not found for specific ID") - ErrIncorrectPrivateShareSignature = fmt.Errorf( - "incorrect private share signature") - ErrMismatchPartialSignatureHash = fmt.Errorf( - "mismatch partialSignature hash") - ErrIncorrectPartialSignatureSignature = fmt.Errorf( - "incorrect partialSignature signature") - ErrIncorrectPartialSignature = fmt.Errorf( - "incorrect partialSignature") - ErrNotEnoughtPartialSignatures = fmt.Errorf( - "not enough of partial signatures") - ErrRoundAlreadyPurged = fmt.Errorf( - "cache of round already been purged") - ErrTSigNotReady = fmt.Errorf( - "tsig not ready") - ErrSelfMPKNotRegister = fmt.Errorf( - "self mpk not registered") - ErrUnableGetSelfPrvShare = fmt.Errorf( - "unable to get self DKG PrivateShare") - ErrSelfPrvShareMismatch = fmt.Errorf( - "self privateShare does not match mpk registered") -) - -// ErrUnexpectedDKGResetCount represents receiving a DKG message with unexpected -// DKG reset count. -type ErrUnexpectedDKGResetCount struct { - expect, actual uint64 - proposerID types.NodeID -} - -func (e ErrUnexpectedDKGResetCount) Error() string { - return fmt.Sprintf( - "unexpected DKG reset count, from:%s expect:%d actual:%d", - e.proposerID.String()[:6], e.expect, e.actual) -} - -// ErrUnexpectedRound represents receiving a DKG message with unexpected round. -type ErrUnexpectedRound struct { - expect, actual uint64 - proposerID types.NodeID -} - -func (e ErrUnexpectedRound) Error() string { - return fmt.Sprintf("unexpected round, from:%s expect:%d actual:%d", - e.proposerID.String()[:6], e.expect, e.actual) -} - -type dkgReceiver interface { - // ProposeDKGComplaint proposes a DKGComplaint. - ProposeDKGComplaint(complaint *typesDKG.Complaint) - - // ProposeDKGMasterPublicKey propose a DKGMasterPublicKey. - ProposeDKGMasterPublicKey(mpk *typesDKG.MasterPublicKey) - - // ProposeDKGPrivateShare propose a DKGPrivateShare. - ProposeDKGPrivateShare(prv *typesDKG.PrivateShare) - - // ProposeDKGAntiNackComplaint propose a DKGPrivateShare as an anti complaint. - ProposeDKGAntiNackComplaint(prv *typesDKG.PrivateShare) - - // ProposeDKGMPKReady propose a DKGMPKReady message. - ProposeDKGMPKReady(ready *typesDKG.MPKReady) - - // ProposeDKGFinalize propose a DKGFinalize message. - ProposeDKGFinalize(final *typesDKG.Finalize) - - // ProposeDKGSuccess propose a DKGSuccess message. - ProposeDKGSuccess(final *typesDKG.Success) -} - -type dkgProtocol struct { - ID types.NodeID - recv dkgReceiver - round uint64 - reset uint64 - threshold int - idMap map[types.NodeID]dkg.ID - mpkMap map[types.NodeID]*dkg.PublicKeyShares - masterPrivateShare *dkg.PrivateKeyShares - prvShares *dkg.PrivateKeyShares - prvSharesReceived map[types.NodeID]struct{} - nodeComplained map[types.NodeID]struct{} - // Complaint[from][to]'s anti is saved to antiComplaint[from][to]. - antiComplaintReceived map[types.NodeID]map[types.NodeID]struct{} - // The completed step in `runDKG`. - step int -} - -func (d *dkgProtocol) convertFromInfo(info db.DKGProtocolInfo) { - d.ID = info.ID - d.idMap = info.IDMap - d.round = info.Round - d.threshold = int(info.Threshold) - d.idMap = info.IDMap - d.mpkMap = info.MpkMap - d.prvSharesReceived = info.PrvSharesReceived - d.nodeComplained = info.NodeComplained - d.antiComplaintReceived = info.AntiComplaintReceived - d.step = int(info.Step) - d.reset = info.Reset - if info.IsMasterPrivateShareEmpty { - d.masterPrivateShare = nil - } else { - d.masterPrivateShare = &info.MasterPrivateShare - } - - if info.IsPrvSharesEmpty { - d.prvShares = nil - } else { - d.prvShares = &info.PrvShares - } -} - -func (d *dkgProtocol) toDKGProtocolInfo() db.DKGProtocolInfo { - info := db.DKGProtocolInfo{ - ID: d.ID, - Round: d.round, - Threshold: uint64(d.threshold), - IDMap: d.idMap, - MpkMap: d.mpkMap, - PrvSharesReceived: d.prvSharesReceived, - NodeComplained: d.nodeComplained, - AntiComplaintReceived: d.antiComplaintReceived, - Step: uint64(d.step), - Reset: d.reset, - } - - if d.masterPrivateShare != nil { - info.MasterPrivateShare = *d.masterPrivateShare - } else { - info.IsMasterPrivateShareEmpty = true - } - - if d.prvShares != nil { - info.PrvShares = *d.prvShares - } else { - info.IsPrvSharesEmpty = true - } - - return info -} - -type dkgShareSecret struct { - privateKey *dkg.PrivateKey -} - -// TSigVerifier is the interface verifying threshold signature. -type TSigVerifier interface { - VerifySignature(hash common.Hash, sig crypto.Signature) bool -} - -// TSigVerifierCacheInterface specifies interface used by TSigVerifierCache. -type TSigVerifierCacheInterface interface { - // Configuration returns the configuration at a given round. - // Return the genesis configuration if round == 0. - Configuration(round uint64) *types.Config - - // DKGComplaints gets all the DKGComplaints of round. - DKGComplaints(round uint64) []*typesDKG.Complaint - - // DKGMasterPublicKeys gets all the DKGMasterPublicKey of round. - DKGMasterPublicKeys(round uint64) []*typesDKG.MasterPublicKey - - // IsDKGFinal checks if DKG is final. - IsDKGFinal(round uint64) bool -} - -// TSigVerifierCache is the cache for TSigVerifier. -type TSigVerifierCache struct { - intf TSigVerifierCacheInterface - verifier map[uint64]TSigVerifier - minRound uint64 - cacheSize int - lock sync.RWMutex -} - -type tsigProtocol struct { - nodePublicKeys *typesDKG.NodePublicKeys - hash common.Hash - sigs map[dkg.ID]dkg.PartialSignature - threshold int -} - -func newDKGProtocol( - ID types.NodeID, - recv dkgReceiver, - round uint64, - reset uint64, - threshold int) *dkgProtocol { - - prvShare, pubShare := dkg.NewPrivateKeyShares(threshold) - - recv.ProposeDKGMasterPublicKey(&typesDKG.MasterPublicKey{ - Round: round, - Reset: reset, - DKGID: typesDKG.NewID(ID), - PublicKeyShares: *pubShare.Move(), - }) - - return &dkgProtocol{ - ID: ID, - recv: recv, - round: round, - reset: reset, - threshold: threshold, - idMap: make(map[types.NodeID]dkg.ID), - mpkMap: make(map[types.NodeID]*dkg.PublicKeyShares), - masterPrivateShare: prvShare, - prvShares: dkg.NewEmptyPrivateKeyShares(), - prvSharesReceived: make(map[types.NodeID]struct{}), - nodeComplained: make(map[types.NodeID]struct{}), - antiComplaintReceived: make(map[types.NodeID]map[types.NodeID]struct{}), - } -} - -func recoverDKGProtocol( - ID types.NodeID, - recv dkgReceiver, - round uint64, - reset uint64, - coreDB db.Database) (*dkgProtocol, error) { - dkgProtocolInfo, err := coreDB.GetDKGProtocol() - if err != nil { - if err == db.ErrDKGProtocolDoesNotExist { - return nil, nil - } - return nil, err - } - - dkgProtocol := dkgProtocol{ - recv: recv, - } - dkgProtocol.convertFromInfo(dkgProtocolInfo) - - if dkgProtocol.ID != ID || dkgProtocol.round != round || dkgProtocol.reset != reset { - return nil, nil - } - - return &dkgProtocol, nil -} - -func (d *dkgProtocol) processMasterPublicKeys( - mpks []*typesDKG.MasterPublicKey) (err error) { - d.idMap = make(map[types.NodeID]dkg.ID, len(mpks)) - d.mpkMap = make(map[types.NodeID]*dkg.PublicKeyShares, len(mpks)) - d.prvSharesReceived = make(map[types.NodeID]struct{}, len(mpks)) - ids := make(dkg.IDs, len(mpks)) - for i := range mpks { - if mpks[i].Reset != d.reset { - return ErrUnexpectedDKGResetCount{ - expect: d.reset, - actual: mpks[i].Reset, - proposerID: mpks[i].ProposerID, - } - } - nID := mpks[i].ProposerID - d.idMap[nID] = mpks[i].DKGID - d.mpkMap[nID] = &mpks[i].PublicKeyShares - ids[i] = mpks[i].DKGID - } - d.masterPrivateShare.SetParticipants(ids) - if err = d.verifySelfPrvShare(); err != nil { - return - } - for _, mpk := range mpks { - share, ok := d.masterPrivateShare.Share(mpk.DKGID) - if !ok { - err = ErrIDShareNotFound - continue - } - d.recv.ProposeDKGPrivateShare(&typesDKG.PrivateShare{ - ReceiverID: mpk.ProposerID, - Round: d.round, - Reset: d.reset, - PrivateShare: *share, - }) - } - return -} - -func (d *dkgProtocol) verifySelfPrvShare() error { - selfMPK, exist := d.mpkMap[d.ID] - if !exist { - return ErrSelfMPKNotRegister - } - share, ok := d.masterPrivateShare.Share(d.idMap[d.ID]) - if !ok { - return ErrUnableGetSelfPrvShare - } - ok, err := selfMPK.VerifyPrvShare( - d.idMap[d.ID], share) - if err != nil { - return err - } - if !ok { - return ErrSelfPrvShareMismatch - } - return nil -} - -func (d *dkgProtocol) proposeNackComplaints() { - for nID := range d.mpkMap { - if _, exist := d.prvSharesReceived[nID]; exist { - continue - } - d.recv.ProposeDKGComplaint(&typesDKG.Complaint{ - Round: d.round, - Reset: d.reset, - PrivateShare: typesDKG.PrivateShare{ - ProposerID: nID, - Round: d.round, - Reset: d.reset, - }, - }) - } -} - -func (d *dkgProtocol) processNackComplaints(complaints []*typesDKG.Complaint) ( - err error) { - if err = d.verifySelfPrvShare(); err != nil { - return - } - for _, complaint := range complaints { - if !complaint.IsNack() { - continue - } - if complaint.Reset != d.reset { - continue - } - if complaint.PrivateShare.ProposerID != d.ID { - continue - } - id, exist := d.idMap[complaint.ProposerID] - if !exist { - err = ErrNotDKGParticipant - continue - } - share, ok := d.masterPrivateShare.Share(id) - if !ok { - err = ErrIDShareNotFound - continue - } - d.recv.ProposeDKGAntiNackComplaint(&typesDKG.PrivateShare{ - ProposerID: d.ID, - ReceiverID: complaint.ProposerID, - Round: d.round, - Reset: d.reset, - PrivateShare: *share, - }) - } - return -} - -func (d *dkgProtocol) enforceNackComplaints(complaints []*typesDKG.Complaint) { - complained := make(map[types.NodeID]struct{}) - // Do not propose nack complaint to itself. - complained[d.ID] = struct{}{} - for _, complaint := range complaints { - if d.round != complaint.Round || d.reset != complaint.Reset { - continue - } - if !complaint.IsNack() { - continue - } - if complaint.Reset != d.reset { - continue - } - to := complaint.PrivateShare.ProposerID - if _, exist := complained[to]; exist { - continue - } - from := complaint.ProposerID - // Nack complaint is already proposed. - if from == d.ID { - continue - } - if _, exist := - d.antiComplaintReceived[from][to]; !exist { - complained[to] = struct{}{} - d.recv.ProposeDKGComplaint(&typesDKG.Complaint{ - Round: d.round, - Reset: d.reset, - PrivateShare: typesDKG.PrivateShare{ - ProposerID: to, - Round: d.round, - Reset: d.reset, - }, - }) - } - } -} - -func (d *dkgProtocol) sanityCheck(prvShare *typesDKG.PrivateShare) error { - if d.round != prvShare.Round { - return ErrUnexpectedRound{ - expect: d.round, - actual: prvShare.Round, - proposerID: prvShare.ProposerID, - } - } - if d.reset != prvShare.Reset { - return ErrUnexpectedDKGResetCount{ - expect: d.reset, - actual: prvShare.Reset, - proposerID: prvShare.ProposerID, - } - } - if _, exist := d.idMap[prvShare.ProposerID]; !exist { - return ErrNotDKGParticipant - } - ok, err := utils.VerifyDKGPrivateShareSignature(prvShare) - if err != nil { - return err - } - if !ok { - return ErrIncorrectPrivateShareSignature - } - return nil -} - -func (d *dkgProtocol) processPrivateShare( - prvShare *typesDKG.PrivateShare) error { - receiverID, exist := d.idMap[prvShare.ReceiverID] - // This node is not a DKG participant, ignore the private share. - if !exist { - return nil - } - if prvShare.ReceiverID == d.ID { - if _, exist := d.prvSharesReceived[prvShare.ProposerID]; exist { - return nil - } - } else { - if _, exist := d.antiComplaintReceived[prvShare.ReceiverID]; exist { - if _, exist := - d.antiComplaintReceived[prvShare.ReceiverID][prvShare.ProposerID]; exist { - return nil - } - } - } - if err := d.sanityCheck(prvShare); err != nil { - return err - } - mpk := d.mpkMap[prvShare.ProposerID] - ok, err := mpk.VerifyPrvShare(receiverID, &prvShare.PrivateShare) - if err != nil { - return err - } - if prvShare.ReceiverID == d.ID { - d.prvSharesReceived[prvShare.ProposerID] = struct{}{} - } - if !ok { - if _, exist := d.nodeComplained[prvShare.ProposerID]; exist { - return nil - } - complaint := &typesDKG.Complaint{ - Round: d.round, - Reset: d.reset, - PrivateShare: *prvShare, - } - d.nodeComplained[prvShare.ProposerID] = struct{}{} - d.recv.ProposeDKGComplaint(complaint) - } else if prvShare.ReceiverID == d.ID { - sender := d.idMap[prvShare.ProposerID] - if err := d.prvShares.AddShare(sender, &prvShare.PrivateShare); err != nil { - return err - } - } else { - // The prvShare is an anti complaint. - if _, exist := d.antiComplaintReceived[prvShare.ReceiverID]; !exist { - d.antiComplaintReceived[prvShare.ReceiverID] = - make(map[types.NodeID]struct{}) - } - if _, exist := - d.antiComplaintReceived[prvShare.ReceiverID][prvShare.ProposerID]; !exist { - d.recv.ProposeDKGAntiNackComplaint(prvShare) - d.antiComplaintReceived[prvShare.ReceiverID][prvShare.ProposerID] = - struct{}{} - } - } - return nil -} - -func (d *dkgProtocol) proposeMPKReady() { - d.recv.ProposeDKGMPKReady(&typesDKG.MPKReady{ - ProposerID: d.ID, - Round: d.round, - Reset: d.reset, - }) -} - -func (d *dkgProtocol) proposeFinalize() { - d.recv.ProposeDKGFinalize(&typesDKG.Finalize{ - ProposerID: d.ID, - Round: d.round, - Reset: d.reset, - }) -} - -func (d *dkgProtocol) proposeSuccess() { - d.recv.ProposeDKGSuccess(&typesDKG.Success{ - ProposerID: d.ID, - Round: d.round, - Reset: d.reset, - }) -} - -func (d *dkgProtocol) recoverShareSecret(qualifyIDs dkg.IDs) ( - *dkgShareSecret, error) { - if len(qualifyIDs) < d.threshold { - return nil, typesDKG.ErrNotReachThreshold - } - prvKey, err := d.prvShares.RecoverPrivateKey(qualifyIDs) - if err != nil { - return nil, err - } - return &dkgShareSecret{ - privateKey: prvKey, - }, nil -} - -func (ss *dkgShareSecret) sign(hash common.Hash) dkg.PartialSignature { - // DKG sign will always success. - sig, _ := ss.privateKey.Sign(hash) - return dkg.PartialSignature(sig) -} - -// NewTSigVerifierCache creats a TSigVerifierCache instance. -func NewTSigVerifierCache( - intf TSigVerifierCacheInterface, cacheSize int) *TSigVerifierCache { - return &TSigVerifierCache{ - intf: intf, - verifier: make(map[uint64]TSigVerifier), - cacheSize: cacheSize, - } -} - -// UpdateAndGet calls Update and then Get. -func (tc *TSigVerifierCache) UpdateAndGet(round uint64) ( - TSigVerifier, bool, error) { - ok, err := tc.Update(round) - if err != nil { - return nil, false, err - } - if !ok { - return nil, false, nil - } - v, ok := tc.Get(round) - return v, ok, nil -} - -// Purge the cache. -func (tc *TSigVerifierCache) Purge(round uint64) { - tc.lock.Lock() - defer tc.lock.Unlock() - delete(tc.verifier, round) -} - -// Update the cache and returns if success. -func (tc *TSigVerifierCache) Update(round uint64) (bool, error) { - tc.lock.Lock() - defer tc.lock.Unlock() - if round < tc.minRound { - return false, ErrRoundAlreadyPurged - } - if _, exist := tc.verifier[round]; exist { - return true, nil - } - if !tc.intf.IsDKGFinal(round) { - return false, nil - } - gpk, err := typesDKG.NewGroupPublicKey(round, - tc.intf.DKGMasterPublicKeys(round), - tc.intf.DKGComplaints(round), - utils.GetDKGThreshold(utils.GetConfigWithPanic(tc.intf, round, nil))) - if err != nil { - return false, err - } - if len(tc.verifier) == 0 { - tc.minRound = round - } - tc.verifier[round] = gpk - if len(tc.verifier) > tc.cacheSize { - delete(tc.verifier, tc.minRound) - } - for { - if _, exist := tc.verifier[tc.minRound]; !exist { - tc.minRound++ - } else { - break - } - } - return true, nil -} - -// Delete the cache of given round. -func (tc *TSigVerifierCache) Delete(round uint64) { - tc.lock.Lock() - defer tc.lock.Unlock() - delete(tc.verifier, round) -} - -// Get the TSigVerifier of round and returns if it exists. -func (tc *TSigVerifierCache) Get(round uint64) (TSigVerifier, bool) { - tc.lock.RLock() - defer tc.lock.RUnlock() - verifier, exist := tc.verifier[round] - return verifier, exist -} - -func newTSigProtocol( - npks *typesDKG.NodePublicKeys, - hash common.Hash) *tsigProtocol { - return &tsigProtocol{ - nodePublicKeys: npks, - hash: hash, - sigs: make(map[dkg.ID]dkg.PartialSignature, npks.Threshold+1), - } -} - -func (tsig *tsigProtocol) sanityCheck(psig *typesDKG.PartialSignature) error { - _, exist := tsig.nodePublicKeys.PublicKeys[psig.ProposerID] - if !exist { - return ErrNotQualifyDKGParticipant - } - ok, err := utils.VerifyDKGPartialSignatureSignature(psig) - if err != nil { - return err - } - if !ok { - return ErrIncorrectPartialSignatureSignature - } - if psig.Hash != tsig.hash { - return ErrMismatchPartialSignatureHash - } - return nil -} - -func (tsig *tsigProtocol) processPartialSignature( - psig *typesDKG.PartialSignature) error { - if psig.Round != tsig.nodePublicKeys.Round { - return nil - } - id, exist := tsig.nodePublicKeys.IDMap[psig.ProposerID] - if !exist { - return ErrNotQualifyDKGParticipant - } - if err := tsig.sanityCheck(psig); err != nil { - return err - } - pubKey := tsig.nodePublicKeys.PublicKeys[psig.ProposerID] - if !pubKey.VerifySignature( - tsig.hash, crypto.Signature(psig.PartialSignature)) { - return ErrIncorrectPartialSignature - } - tsig.sigs[id] = psig.PartialSignature - return nil -} - -func (tsig *tsigProtocol) signature() (crypto.Signature, error) { - if len(tsig.sigs) < tsig.nodePublicKeys.Threshold { - return crypto.Signature{}, ErrNotEnoughtPartialSignatures - } - ids := make(dkg.IDs, 0, len(tsig.sigs)) - psigs := make([]dkg.PartialSignature, 0, len(tsig.sigs)) - for id, psig := range tsig.sigs { - ids = append(ids, id) - psigs = append(psigs, psig) - } - return dkg.RecoverSignature(psigs, ids) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go deleted file mode 100644 index c88b3dcb4..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go +++ /dev/null @@ -1,182 +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 core - -import ( - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/types" - typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -// Application describes the application interface that interacts with DEXON -// consensus core. -type Application interface { - // PreparePayload is called when consensus core is preparing a block. - PreparePayload(position types.Position) ([]byte, error) - - // PrepareWitness will return the witness data no lower than consensusHeight. - PrepareWitness(consensusHeight uint64) (types.Witness, error) - - // VerifyBlock verifies if the block is valid. - VerifyBlock(block *types.Block) types.BlockVerifyStatus - - // BlockConfirmed is called when a block is confirmed and added to lattice. - BlockConfirmed(block types.Block) - - // BlockDelivered is called when a block is added to the compaction chain. - BlockDelivered(hash common.Hash, position types.Position, rand []byte) -} - -// Debug describes the application interface that requires -// more detailed consensus execution. -type Debug interface { - // BlockReceived is called when the block received in agreement. - BlockReceived(common.Hash) - // BlockReady is called when the block's randomness is ready. - BlockReady(common.Hash) -} - -// Network describs the network interface that interacts with DEXON consensus -// core. -type Network interface { - // PullBlocks tries to pull blocks from the DEXON network. - PullBlocks(hashes common.Hashes) - - // PullVotes tries to pull votes from the DEXON network. - PullVotes(position types.Position) - - // BroadcastVote broadcasts vote to all nodes in DEXON network. - BroadcastVote(vote *types.Vote) - - // BroadcastBlock broadcasts block to all nodes in DEXON network. - BroadcastBlock(block *types.Block) - - // BroadcastAgreementResult broadcasts agreement result to DKG set. - BroadcastAgreementResult(randRequest *types.AgreementResult) - - // SendDKGPrivateShare sends PrivateShare to a DKG participant. - SendDKGPrivateShare(pub crypto.PublicKey, prvShare *typesDKG.PrivateShare) - - // BroadcastDKGPrivateShare broadcasts PrivateShare to all DKG participants. - BroadcastDKGPrivateShare(prvShare *typesDKG.PrivateShare) - - // BroadcastDKGPartialSignature broadcasts partialSignature to all - // DKG participants. - BroadcastDKGPartialSignature(psig *typesDKG.PartialSignature) - - // ReceiveChan returns a channel to receive messages from DEXON network. - ReceiveChan() <-chan types.Msg - - // ReportBadPeerChan returns a channel to report bad peer. - ReportBadPeerChan() chan<- interface{} -} - -// Governance interface specifies interface to control the governance contract. -// Note that there are a lot more methods in the governance contract, that this -// interface only define those that are required to run the consensus algorithm. -type Governance interface { - // Configuration returns the configuration at a given round. - // Return the genesis configuration if round == 0. - Configuration(round uint64) *types.Config - - // CRS returns the CRS for a given round. Return the genesis CRS if - // round == 0. - // - // The CRS returned is the proposed or latest reseted one, it would be - // changed later if corresponding DKG set failed to generate group public - // key. - CRS(round uint64) common.Hash - - // Propose a CRS of round. - ProposeCRS(round uint64, signedCRS []byte) - - // NodeSet returns the node set at a given round. - // Return the genesis node set if round == 0. - NodeSet(round uint64) []crypto.PublicKey - - // Get the begin height of a round. - GetRoundHeight(round uint64) uint64 - - //// DKG-related methods. - - // AddDKGComplaint adds a DKGComplaint. - AddDKGComplaint(complaint *typesDKG.Complaint) - - // DKGComplaints gets all the DKGComplaints of round. - DKGComplaints(round uint64) []*typesDKG.Complaint - - // AddDKGMasterPublicKey adds a DKGMasterPublicKey. - AddDKGMasterPublicKey(masterPublicKey *typesDKG.MasterPublicKey) - - // DKGMasterPublicKeys gets all the DKGMasterPublicKey of round. - DKGMasterPublicKeys(round uint64) []*typesDKG.MasterPublicKey - - // AddDKGMPKReady adds a DKG ready message. - AddDKGMPKReady(ready *typesDKG.MPKReady) - - // IsDKGMPKReady checks if DKG's master public key preparation is ready. - IsDKGMPKReady(round uint64) bool - - // AddDKGFinalize adds a DKG finalize message. - AddDKGFinalize(final *typesDKG.Finalize) - - // IsDKGFinal checks if DKG is final. - IsDKGFinal(round uint64) bool - - // AddDKGSuccess adds a DKG success message. - AddDKGSuccess(success *typesDKG.Success) - - // IsDKGSuccess checks if DKG is success. - IsDKGSuccess(round uint64) bool - - // ReportForkVote reports a node for forking votes. - ReportForkVote(vote1, vote2 *types.Vote) - - // ReportForkBlock reports a node for forking blocks. - ReportForkBlock(block1, block2 *types.Block) - - // ResetDKG resets latest DKG data and propose new CRS. - ResetDKG(newSignedCRS []byte) - - // DKGResetCount returns the reset count for DKG of given round. - DKGResetCount(round uint64) uint64 -} - -// Ticker define the capability to tick by interval. -type Ticker interface { - // Tick would return a channel, which would be triggered until next tick. - Tick() <-chan time.Time - - // Stop the ticker. - Stop() - - // Retart the ticker and clear all internal data. - Restart() -} - -// Recovery interface for interacting with recovery information. -type Recovery interface { - // ProposeSkipBlock proposes a skip block. - ProposeSkipBlock(height uint64) error - - // Votes gets the number of votes of given height. - Votes(height uint64) (uint64, error) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/leader-selector.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/leader-selector.go deleted file mode 100644 index 91b2e9979..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/leader-selector.go +++ /dev/null @@ -1,149 +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 core - -import ( - "math/big" - "sync" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -type validLeaderFn func(block *types.Block, crs common.Hash) (bool, error) - -// Some constant value. -var ( - maxHash *big.Int - one *big.Rat -) - -func init() { - hash := make([]byte, common.HashLength) - for i := range hash { - hash[i] = 0xff - } - maxHash = big.NewInt(0).SetBytes(hash) - one = big.NewRat(1, 1) -} - -type leaderSelector struct { - hashCRS common.Hash - numCRS *big.Int - minCRSBlock *big.Int - minBlockHash common.Hash - pendingBlocks map[common.Hash]*types.Block - validLeader validLeaderFn - lock sync.Mutex - logger common.Logger -} - -func newLeaderSelector( - validLeader validLeaderFn, logger common.Logger) *leaderSelector { - return &leaderSelector{ - minCRSBlock: maxHash, - validLeader: validLeader, - logger: logger, - } -} - -func (l *leaderSelector) distance(sig crypto.Signature) *big.Int { - hash := crypto.Keccak256Hash(sig.Signature[:]) - num := big.NewInt(0) - num.SetBytes(hash[:]) - num.Abs(num.Sub(l.numCRS, num)) - return num -} - -func (l *leaderSelector) probability(sig crypto.Signature) float64 { - dis := l.distance(sig) - prob := big.NewRat(1, 1).SetFrac(dis, maxHash) - p, _ := prob.Sub(one, prob).Float64() - return p -} - -func (l *leaderSelector) restart(crs common.Hash) { - numCRS := big.NewInt(0) - numCRS.SetBytes(crs[:]) - l.lock.Lock() - defer l.lock.Unlock() - l.numCRS = numCRS - l.hashCRS = crs - l.minCRSBlock = maxHash - l.minBlockHash = types.NullBlockHash - l.pendingBlocks = make(map[common.Hash]*types.Block) -} - -func (l *leaderSelector) leaderBlockHash() common.Hash { - l.lock.Lock() - defer l.lock.Unlock() - for _, b := range l.pendingBlocks { - ok, dist := l.potentialLeader(b) - if !ok { - continue - } - ok, err := l.validLeader(b, l.hashCRS) - if err != nil { - l.logger.Error("Error checking validLeader", "error", err, "block", b) - delete(l.pendingBlocks, b.Hash) - continue - } - if ok { - l.updateLeader(b, dist) - delete(l.pendingBlocks, b.Hash) - } - } - return l.minBlockHash -} - -func (l *leaderSelector) processBlock(block *types.Block) error { - l.lock.Lock() - defer l.lock.Unlock() - ok, dist := l.potentialLeader(block) - if !ok { - return nil - } - ok, err := l.validLeader(block, l.hashCRS) - if err != nil { - return err - } - if !ok { - l.pendingBlocks[block.Hash] = block - return nil - } - l.updateLeader(block, dist) - return nil -} - -func (l *leaderSelector) potentialLeader(block *types.Block) (bool, *big.Int) { - dist := l.distance(block.CRSSignature) - cmp := l.minCRSBlock.Cmp(dist) - return (cmp > 0 || (cmp == 0 && block.Hash.Less(l.minBlockHash))), dist -} - -func (l *leaderSelector) updateLeader(block *types.Block, dist *big.Int) { - l.minCRSBlock = dist - l.minBlockHash = block.Hash -} - -func (l *leaderSelector) findPendingBlock( - hash common.Hash) (*types.Block, bool) { - b, e := l.pendingBlocks[hash] - return b, e -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go deleted file mode 100644 index 10b47b822..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go +++ /dev/null @@ -1,137 +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 core - -import ( - "fmt" - "sync" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -type blockConfirmedEvent struct { - block *types.Block -} - -type blockDeliveredEvent struct { - blockHash common.Hash - blockPosition types.Position - rand []byte -} - -// nonBlocking implements these interfaces and is a decorator for -// them that makes the methods to be non-blocking. -// - Application -// - Debug -// - It also provides nonblockig for db update. -type nonBlocking struct { - app Application - debug Debug - eventChan chan interface{} - events []interface{} - eventsChange *sync.Cond - running sync.WaitGroup -} - -func newNonBlocking(app Application, debug Debug) *nonBlocking { - nonBlockingModule := &nonBlocking{ - app: app, - debug: debug, - eventChan: make(chan interface{}, 6), - events: make([]interface{}, 0, 100), - eventsChange: sync.NewCond(&sync.Mutex{}), - } - go nonBlockingModule.run() - return nonBlockingModule -} - -func (nb *nonBlocking) addEvent(event interface{}) { - nb.eventsChange.L.Lock() - defer nb.eventsChange.L.Unlock() - nb.events = append(nb.events, event) - nb.eventsChange.Broadcast() -} - -func (nb *nonBlocking) run() { - // This go routine consume the first event from events and call the - // corresponding methods of Application/Debug/db. - for { - var event interface{} - func() { - nb.eventsChange.L.Lock() - defer nb.eventsChange.L.Unlock() - for len(nb.events) == 0 { - nb.eventsChange.Wait() - } - event = nb.events[0] - nb.events = nb.events[1:] - nb.running.Add(1) - }() - switch e := event.(type) { - case blockConfirmedEvent: - nb.app.BlockConfirmed(*e.block) - case blockDeliveredEvent: - nb.app.BlockDelivered(e.blockHash, e.blockPosition, e.rand) - default: - fmt.Printf("Unknown event %v.", e) - } - nb.running.Done() - nb.eventsChange.Broadcast() - } -} - -// wait will wait for all event in events finishes. -func (nb *nonBlocking) wait() { - nb.eventsChange.L.Lock() - defer nb.eventsChange.L.Unlock() - for len(nb.events) > 0 { - nb.eventsChange.Wait() - } - nb.running.Wait() -} - -// PreparePayload cannot be non-blocking. -func (nb *nonBlocking) PreparePayload(position types.Position) ([]byte, error) { - return nb.app.PreparePayload(position) -} - -// PrepareWitness cannot be non-blocking. -func (nb *nonBlocking) PrepareWitness(height uint64) (types.Witness, error) { - return nb.app.PrepareWitness(height) -} - -// VerifyBlock cannot be non-blocking. -func (nb *nonBlocking) VerifyBlock(block *types.Block) types.BlockVerifyStatus { - return nb.app.VerifyBlock(block) -} - -// BlockConfirmed is called when a block is confirmed and added to lattice. -func (nb *nonBlocking) BlockConfirmed(block types.Block) { - nb.addEvent(blockConfirmedEvent{&block}) -} - -// BlockDelivered is called when a block is add to the compaction chain. -func (nb *nonBlocking) BlockDelivered(blockHash common.Hash, - blockPosition types.Position, rand []byte) { - nb.addEvent(blockDeliveredEvent{ - blockHash: blockHash, - blockPosition: blockPosition, - rand: rand, - }) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/agreement.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/agreement.go deleted file mode 100644 index d39c24627..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/agreement.go +++ /dev/null @@ -1,301 +0,0 @@ -// Copyright 2018 The dexon-consensus Authors -// This file is part of the dexon-consensus-core library. -// -// The dexon-consensus-core library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus-core library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus-core library. If not, see -// <http://www.gnu.org/licenses/>. - -package syncer - -import ( - "bytes" - "context" - "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/types" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// Struct agreement implements struct of BA (Byzantine Agreement) protocol -// needed in syncer, which only receives agreement results. -type agreement struct { - chainTip uint64 - cache *utils.NodeSetCache - tsigVerifierCache *core.TSigVerifierCache - inputChan chan interface{} - outputChan chan<- *types.Block - pullChan chan<- common.Hash - blocks map[types.Position]map[common.Hash]*types.Block - agreementResults map[common.Hash][]byte - latestCRSRound uint64 - pendingAgrs map[uint64]map[common.Hash]*types.AgreementResult - pendingBlocks map[uint64]map[common.Hash]*types.Block - logger common.Logger - confirmedBlocks map[common.Hash]struct{} - ctx context.Context - ctxCancel context.CancelFunc -} - -// newAgreement creates a new agreement instance. -func newAgreement(chainTip uint64, - ch chan<- *types.Block, pullChan chan<- common.Hash, - cache *utils.NodeSetCache, verifier *core.TSigVerifierCache, - logger common.Logger) *agreement { - a := &agreement{ - chainTip: chainTip, - cache: cache, - tsigVerifierCache: verifier, - inputChan: make(chan interface{}, 1000), - outputChan: ch, - pullChan: pullChan, - blocks: make(map[types.Position]map[common.Hash]*types.Block), - agreementResults: make(map[common.Hash][]byte), - logger: logger, - pendingAgrs: make( - map[uint64]map[common.Hash]*types.AgreementResult), - pendingBlocks: make( - map[uint64]map[common.Hash]*types.Block), - confirmedBlocks: make(map[common.Hash]struct{}), - } - a.ctx, a.ctxCancel = context.WithCancel(context.Background()) - return a -} - -// run starts the agreement, this does not start a new routine, go a new -// routine explicitly in the caller. -func (a *agreement) run() { - defer a.ctxCancel() - for { - select { - case val, ok := <-a.inputChan: - if !ok { - // InputChan is closed by network when network ends. - return - } - switch v := val.(type) { - case *types.Block: - if v.Position.Round >= core.DKGDelayRound && v.IsFinalized() { - a.processFinalizedBlock(v) - } else { - a.processBlock(v) - } - case *types.AgreementResult: - a.processAgreementResult(v) - case uint64: - a.processNewCRS(v) - } - } - } -} - -func (a *agreement) processBlock(b *types.Block) { - if _, exist := a.confirmedBlocks[b.Hash]; exist { - return - } - if rand, exist := a.agreementResults[b.Hash]; exist { - if len(b.Randomness) == 0 { - b.Randomness = rand - } - a.confirm(b) - } else { - if _, exist := a.blocks[b.Position]; !exist { - a.blocks[b.Position] = make(map[common.Hash]*types.Block) - } - a.blocks[b.Position][b.Hash] = b - } -} - -func (a *agreement) processFinalizedBlock(block *types.Block) { - // Cache those results that CRS is not ready yet. - if _, exists := a.confirmedBlocks[block.Hash]; exists { - a.logger.Trace("finalized block already confirmed", "block", block) - return - } - if block.Position.Round > a.latestCRSRound { - pendingsForRound, exists := a.pendingBlocks[block.Position.Round] - if !exists { - pendingsForRound = make(map[common.Hash]*types.Block) - a.pendingBlocks[block.Position.Round] = pendingsForRound - } - pendingsForRound[block.Hash] = block - a.logger.Trace("finalized block cached", "block", block) - return - } - if err := utils.VerifyBlockSignature(block); err != nil { - return - } - verifier, ok, err := a.tsigVerifierCache.UpdateAndGet( - block.Position.Round) - if err != nil { - a.logger.Error("error verifying block randomness", - "block", block, - "error", err) - return - } - if !ok { - a.logger.Error("cannot verify block randomness", "block", block) - return - } - if !verifier.VerifySignature(block.Hash, crypto.Signature{ - Type: "bls", - Signature: block.Randomness, - }) { - a.logger.Error("incorrect block randomness", "block", block) - return - } - a.confirm(block) -} - -func (a *agreement) processAgreementResult(r *types.AgreementResult) { - // Cache those results that CRS is not ready yet. - if _, exists := a.confirmedBlocks[r.BlockHash]; exists { - a.logger.Trace("Agreement result already confirmed", "result", r) - return - } - if r.Position.Round > a.latestCRSRound { - pendingsForRound, exists := a.pendingAgrs[r.Position.Round] - if !exists { - pendingsForRound = make(map[common.Hash]*types.AgreementResult) - a.pendingAgrs[r.Position.Round] = pendingsForRound - } - pendingsForRound[r.BlockHash] = r - a.logger.Trace("Agreement result cached", "result", r) - return - } - if err := core.VerifyAgreementResult(r, a.cache); err != nil { - a.logger.Error("Agreement result verification failed", - "result", r, - "error", err) - return - } - if r.Position.Round >= core.DKGDelayRound { - verifier, ok, err := a.tsigVerifierCache.UpdateAndGet(r.Position.Round) - if err != nil { - a.logger.Error("error verifying agreement result randomness", - "result", r, - "error", err) - return - } - if !ok { - a.logger.Error("cannot verify agreement result randomness", "result", r) - return - } - if !verifier.VerifySignature(r.BlockHash, crypto.Signature{ - Type: "bls", - Signature: r.Randomness, - }) { - a.logger.Error("incorrect agreement result randomness", "result", r) - return - } - } else { - // Special case for rounds before DKGDelayRound. - if bytes.Compare(r.Randomness, core.NoRand) != 0 { - a.logger.Error("incorrect agreement result randomness", "result", r) - return - } - } - if r.IsEmptyBlock { - b := &types.Block{ - Position: r.Position, - Randomness: r.Randomness, - } - // Empty blocks should be confirmed directly, they won't be sent over - // the wire. - a.confirm(b) - return - } - if bs, exist := a.blocks[r.Position]; exist { - if b, exist := bs[r.BlockHash]; exist { - b.Randomness = r.Randomness - a.confirm(b) - return - } - } - a.agreementResults[r.BlockHash] = r.Randomness -loop: - for { - select { - case a.pullChan <- r.BlockHash: - break loop - case <-a.ctx.Done(): - a.logger.Error("Pull request is not sent", - "position", &r.Position, - "hash", r.BlockHash.String()[:6]) - return - case <-time.After(500 * time.Millisecond): - a.logger.Debug("Pull request is unable to send", - "position", &r.Position, - "hash", r.BlockHash.String()[:6]) - } - } -} - -func (a *agreement) processNewCRS(round uint64) { - if round <= a.latestCRSRound { - return - } - prevRound := a.latestCRSRound + 1 - a.latestCRSRound = round - // Verify all pending results. - for r := prevRound; r <= a.latestCRSRound; r++ { - pendingsForRound := a.pendingAgrs[r] - if pendingsForRound == nil { - continue - } - delete(a.pendingAgrs, r) - for _, res := range pendingsForRound { - if err := core.VerifyAgreementResult(res, a.cache); err != nil { - a.logger.Error("Invalid agreement result", - "result", res, - "error", err) - continue - } - a.logger.Error("Flush agreement result", "result", res) - a.processAgreementResult(res) - break - } - } -} - -// confirm notifies consensus the confirmation of a block in BA. -func (a *agreement) confirm(b *types.Block) { - if !b.IsFinalized() { - panic(fmt.Errorf("confirm a block %s without randomness", b)) - } - if _, exist := a.confirmedBlocks[b.Hash]; !exist { - delete(a.blocks, b.Position) - delete(a.agreementResults, b.Hash) - loop: - for { - select { - case a.outputChan <- b: - break loop - case <-a.ctx.Done(): - a.logger.Error("Confirmed block is not sent", "block", b) - return - case <-time.After(500 * time.Millisecond): - a.logger.Debug("Agreement output channel is full", "block", b) - } - } - a.confirmedBlocks[b.Hash] = struct{}{} - } - if b.Position.Height > a.chainTip+1 { - if _, exist := a.confirmedBlocks[b.ParentHash]; !exist { - a.pullChan <- b.ParentHash - } - } -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/consensus.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/consensus.go deleted file mode 100644 index 496c0f9a8..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/consensus.go +++ /dev/null @@ -1,543 +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 syncer - -import ( - "context" - "fmt" - "sort" - "sync" - "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/types" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -var ( - // ErrAlreadySynced is reported when syncer is synced. - ErrAlreadySynced = fmt.Errorf("already synced") - // ErrNotSynced is reported when syncer is not synced yet. - ErrNotSynced = fmt.Errorf("not synced yet") - // ErrGenesisBlockReached is reported when genesis block reached. - ErrGenesisBlockReached = fmt.Errorf("genesis block reached") - // ErrInvalidBlockOrder is reported when SyncBlocks receives unordered - // blocks. - ErrInvalidBlockOrder = fmt.Errorf("invalid block order") - // ErrInvalidSyncingHeight raised when the blocks to sync is not following - // the compaction chain tip in database. - ErrInvalidSyncingHeight = fmt.Errorf("invalid syncing height") -) - -// Consensus is for syncing consensus module. -type Consensus struct { - db db.Database - gov core.Governance - dMoment time.Time - logger common.Logger - app core.Application - prv crypto.PrivateKey - network core.Network - nodeSetCache *utils.NodeSetCache - tsigVerifier *core.TSigVerifierCache - - blocks types.BlocksByPosition - agreementModule *agreement - agreementRoundCut uint64 - heightEvt *common.Event - roundEvt *utils.RoundEvent - - // lock for accessing all fields. - lock sync.RWMutex - duringBuffering bool - latestCRSRound uint64 - waitGroup sync.WaitGroup - agreementWaitGroup sync.WaitGroup - pullChan chan common.Hash - receiveChan chan *types.Block - ctx context.Context - ctxCancel context.CancelFunc - syncedLastBlock *types.Block - syncedConsensus *core.Consensus - syncedSkipNext bool - dummyCancel context.CancelFunc - dummyFinished <-chan struct{} - dummyMsgBuffer []types.Msg - initChainTipHeight uint64 -} - -// NewConsensus creates an instance for Consensus (syncer consensus). -func NewConsensus( - initHeight uint64, - dMoment time.Time, - app core.Application, - gov core.Governance, - db db.Database, - network core.Network, - prv crypto.PrivateKey, - 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), - heightEvt: common.NewEvent(), - } - con.ctx, con.ctxCancel = context.WithCancel(context.Background()) - _, con.initChainTipHeight = db.GetCompactionChainTipInfo() - con.agreementModule = newAgreement( - con.initChainTipHeight, - con.receiveChan, - con.pullChan, - con.nodeSetCache, - con.tsigVerifier, - con.logger) - con.agreementWaitGroup.Add(1) - go func() { - defer con.agreementWaitGroup.Done() - con.agreementModule.run() - }() - if err := con.deliverPendingBlocks(initHeight); err != nil { - panic(err) - } - return con -} - -func (con *Consensus) deliverPendingBlocks(height uint64) error { - if height >= con.initChainTipHeight { - return nil - } - blocks := make([]*types.Block, 0, con.initChainTipHeight-height) - hash, _ := con.db.GetCompactionChainTipInfo() - for { - block, err := con.db.GetBlock(hash) - if err != nil { - return err - } - if block.Position.Height == height { - break - } - blocks = append(blocks, &block) - hash = block.ParentHash - } - sort.Sort(types.BlocksByPosition(blocks)) - for _, b := range blocks { - con.logger.Debug("Syncer BlockConfirmed", "block", b) - con.app.BlockConfirmed(*b) - con.logger.Debug("Syncer BlockDelivered", "block", b) - con.app.BlockDelivered(b.Hash, b.Position, b.Randomness) - } - return nil -} - -func (con *Consensus) assureBuffering() { - if func() bool { - con.lock.RLock() - defer con.lock.RUnlock() - return con.duringBuffering - }() { - return - } - con.lock.Lock() - defer con.lock.Unlock() - if con.duringBuffering { - return - } - con.duringBuffering = true - // Get latest block to prepare utils.RoundEvent. - var ( - err error - blockHash, height = con.db.GetCompactionChainTipInfo() - ) - if height == 0 { - con.roundEvt, err = utils.NewRoundEvent(con.ctx, con.gov, con.logger, - types.Position{}, core.ConfigRoundShift) - } else { - var b types.Block - if b, err = con.db.GetBlock(blockHash); err == nil { - con.roundEvt, err = utils.NewRoundEvent(con.ctx, con.gov, - con.logger, b.Position, core.ConfigRoundShift) - } - } - if err != nil { - panic(err) - } - // Make sure con.roundEvt stopped before stopping con.agreementModule. - con.waitGroup.Add(1) - // Register a round event handler to reset node set cache, this handler - // should be the highest priority. - con.roundEvt.Register(func(evts []utils.RoundEventParam) { - for _, e := range evts { - if e.Reset == 0 { - continue - } - con.nodeSetCache.Purge(e.Round + 1) - con.tsigVerifier.Purge(e.Round + 1) - } - }) - // Register a round event handler to notify CRS to agreementModule. - con.roundEvt.Register(func(evts []utils.RoundEventParam) { - con.waitGroup.Add(1) - go func() { - defer con.waitGroup.Done() - for _, e := range evts { - select { - case <-con.ctx.Done(): - return - default: - } - for func() bool { - select { - case <-con.ctx.Done(): - return false - case con.agreementModule.inputChan <- e.Round: - return false - case <-time.After(500 * time.Millisecond): - con.logger.Warn( - "Agreement input channel is full when notifying new round", - "round", e.Round, - ) - return true - } - }() { - } - } - }() - }) - // Register a round event handler to validate next round. - con.roundEvt.Register(func(evts []utils.RoundEventParam) { - con.heightEvt.RegisterHeight( - evts[len(evts)-1].NextRoundValidationHeight(), - utils.RoundEventRetryHandlerGenerator(con.roundEvt, con.heightEvt), - ) - }) - con.roundEvt.TriggerInitEvent() - con.startAgreement() - con.startNetwork() -} - -func (con *Consensus) checkIfSynced(blocks []*types.Block) (synced bool) { - con.lock.RLock() - defer con.lock.RUnlock() - defer func() { - con.logger.Debug("Syncer synced status", - "last-block", blocks[len(blocks)-1], - "synced", synced, - ) - }() - if len(con.blocks) == 0 || len(blocks) == 0 { - return - } - synced = !blocks[len(blocks)-1].Position.Older(con.blocks[0].Position) - return -} - -func (con *Consensus) buildAllEmptyBlocks() { - con.lock.Lock() - defer con.lock.Unlock() - // Clean empty blocks on tips of chains. - for len(con.blocks) > 0 && con.isEmptyBlock(con.blocks[0]) { - con.blocks = con.blocks[1:] - } - // Build empty blocks. - for i, b := range con.blocks { - if con.isEmptyBlock(b) { - if con.blocks[i-1].Position.Height+1 == b.Position.Height { - con.buildEmptyBlock(b, con.blocks[i-1]) - } - } - } -} - -// ForceSync forces syncer to become synced. -func (con *Consensus) ForceSync(lastPos types.Position, skip bool) { - if con.syncedLastBlock != nil { - return - } - hash, height := con.db.GetCompactionChainTipInfo() - if height < lastPos.Height { - panic(fmt.Errorf("compaction chain not synced height %d, tip %d", - lastPos.Height, height)) - } else if height > lastPos.Height { - skip = false - } - block, err := con.db.GetBlock(hash) - if err != nil { - panic(err) - } - con.syncedLastBlock = &block - con.stopBuffering() - // We might call stopBuffering without calling assureBuffering. - if con.dummyCancel == nil { - con.dummyCancel, con.dummyFinished = utils.LaunchDummyReceiver( - context.Background(), con.network.ReceiveChan(), - func(msg types.Msg) { - con.dummyMsgBuffer = append(con.dummyMsgBuffer, msg) - }) - } - con.syncedSkipNext = skip - con.logger.Info("Force Sync", "block", &block, "skip", skip) -} - -// SyncBlocks syncs blocks from compaction chain, latest is true if the caller -// regards the blocks are the latest ones. Notice that latest can be true for -// many times. -// NOTICE: parameter "blocks" should be consecutive in compaction height. -// NOTICE: this method is not expected to be called concurrently. -func (con *Consensus) SyncBlocks( - blocks []*types.Block, latest bool) (synced bool, err error) { - defer func() { - con.logger.Debug("SyncBlocks returned", - "synced", synced, - "error", err, - "last-block", con.syncedLastBlock, - ) - }() - if con.syncedLastBlock != nil { - synced, err = true, ErrAlreadySynced - return - } - if len(blocks) == 0 { - return - } - // Check if blocks are consecutive. - for i := 1; i < len(blocks); i++ { - if blocks[i].Position.Height != blocks[i-1].Position.Height+1 { - err = ErrInvalidBlockOrder - return - } - } - // Make sure the first block is the next block of current compaction chain - // tip in DB. - _, tipHeight := con.db.GetCompactionChainTipInfo() - if blocks[0].Position.Height != tipHeight+1 { - con.logger.Error("Mismatched block height", - "now", blocks[0].Position.Height, - "expected", tipHeight+1, - ) - err = ErrInvalidSyncingHeight - return - } - con.logger.Trace("SyncBlocks", - "position", &blocks[0].Position, - "len", len(blocks), - "latest", latest, - ) - for _, b := range blocks { - if err = con.db.PutBlock(*b); err != nil { - // A block might be put into db when confirmed by BA, but not - // finalized yet. - if err == db.ErrBlockExists { - err = con.db.UpdateBlock(*b) - } - if err != nil { - return - } - } - if err = con.db.PutCompactionChainTipInfo( - b.Hash, b.Position.Height); err != nil { - return - } - con.heightEvt.NotifyHeight(b.Position.Height) - } - if latest { - con.assureBuffering() - con.buildAllEmptyBlocks() - // Check if compaction and agreements' blocks are overlapped. The - // overlapping of compaction chain and BA's oldest blocks means the - // syncing is done. - if con.checkIfSynced(blocks) { - con.stopBuffering() - con.syncedLastBlock = blocks[len(blocks)-1] - synced = true - } - } - return -} - -// GetSyncedConsensus returns the core.Consensus instance after synced. -func (con *Consensus) GetSyncedConsensus() (*core.Consensus, error) { - con.lock.Lock() - defer con.lock.Unlock() - if con.syncedConsensus != nil { - return con.syncedConsensus, nil - } - if con.syncedLastBlock == nil { - return nil, ErrNotSynced - } - // flush all blocks in con.blocks into core.Consensus, and build - // core.Consensus from syncer. - con.dummyCancel() - <-con.dummyFinished - var err error - con.syncedConsensus, err = core.NewConsensusFromSyncer( - con.syncedLastBlock, - con.syncedSkipNext, - con.dMoment, - con.app, - con.gov, - con.db, - con.network, - con.prv, - con.blocks, - con.dummyMsgBuffer, - con.logger) - return con.syncedConsensus, err -} - -// stopBuffering stops the syncer buffering routines. -// -// This method is mainly for caller to stop the syncer before synced, the syncer -// would call this method automatically after being synced. -func (con *Consensus) stopBuffering() { - if func() (notBuffering bool) { - con.lock.RLock() - defer con.lock.RUnlock() - notBuffering = !con.duringBuffering - return - }() { - return - } - if func() (alreadyCanceled bool) { - con.lock.Lock() - defer con.lock.Unlock() - if !con.duringBuffering { - alreadyCanceled = true - return - } - con.duringBuffering = false - con.logger.Trace("Syncer is about to stop") - // Stop network and CRS routines, wait until they are all stoped. - con.ctxCancel() - return - }() { - return - } - con.logger.Trace("Stop syncer modules") - con.roundEvt.Stop() - con.waitGroup.Done() - // Wait for all routines depends on con.agreementModule stopped. - con.waitGroup.Wait() - // Since there is no one waiting for the receive channel of fullnode, we - // need to launch a dummy receiver right away. - con.dummyCancel, con.dummyFinished = utils.LaunchDummyReceiver( - context.Background(), con.network.ReceiveChan(), - func(msg types.Msg) { - con.dummyMsgBuffer = append(con.dummyMsgBuffer, msg) - }) - // Stop agreements. - con.logger.Trace("Stop syncer agreement modules") - con.stopAgreement() - con.logger.Trace("Syncer stopped") - return -} - -// isEmptyBlock checks if a block is an empty block by both its hash and parent -// hash are empty. -func (con *Consensus) isEmptyBlock(b *types.Block) bool { - return b.Hash == common.Hash{} && b.ParentHash == common.Hash{} -} - -// buildEmptyBlock builds an empty block in agreement. -func (con *Consensus) buildEmptyBlock(b *types.Block, parent *types.Block) { - cfg := utils.GetConfigWithPanic(con.gov, b.Position.Round, con.logger) - b.Timestamp = parent.Timestamp.Add(cfg.MinBlockInterval) - b.Witness.Height = parent.Witness.Height - b.Witness.Data = make([]byte, len(parent.Witness.Data)) - copy(b.Witness.Data, parent.Witness.Data) -} - -// startAgreement starts agreements for receiving votes and agreements. -func (con *Consensus) startAgreement() { - // Start a routine for listening receive channel and pull block channel. - go func() { - for { - select { - case b, ok := <-con.receiveChan: - if !ok { - return - } - func() { - con.lock.Lock() - defer con.lock.Unlock() - if len(con.blocks) > 0 && - !b.Position.Newer(con.blocks[0].Position) { - return - } - con.blocks = append(con.blocks, b) - sort.Sort(con.blocks) - }() - case h, ok := <-con.pullChan: - if !ok { - return - } - con.network.PullBlocks(common.Hashes{h}) - } - } - }() -} - -// startNetwork starts network for receiving blocks and agreement results. -func (con *Consensus) startNetwork() { - con.waitGroup.Add(1) - go func() { - defer con.waitGroup.Done() - loop: - for { - select { - case val := <-con.network.ReceiveChan(): - switch v := val.Payload.(type) { - case *types.Block: - case *types.AgreementResult: - // Avoid byzantine nodes attack by broadcasting older - // agreement results. Normal nodes might report 'synced' - // while still fall behind other nodes. - if v.Position.Height <= con.initChainTipHeight { - continue loop - } - default: - continue loop - } - con.agreementModule.inputChan <- val.Payload - case <-con.ctx.Done(): - break loop - } - } - }() -} - -func (con *Consensus) stopAgreement() { - if con.agreementModule.inputChan != nil { - close(con.agreementModule.inputChan) - } - con.agreementWaitGroup.Wait() - con.agreementModule.inputChan = nil - close(con.receiveChan) - close(con.pullChan) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/watch-cat.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/watch-cat.go deleted file mode 100644 index f2e197ebe..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/watch-cat.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2019 The dexon-consensus Authors -// This file is part of the dexon-consensus-core library. -// -// The dexon-consensus-core library is free software: you can redistribute it -// and/or modify it under the terms of the GNU Lesser General Public License as -// published by the Free Software Foundation, either version 3 of the License, -// or (at your option) any later version. -// -// The dexon-consensus-core library is distributed in the hope that it will be -// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser -// General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the dexon-consensus-core library. If not, see -// <http://www.gnu.org/licenses/>. - -package syncer - -import ( - "context" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core" - "github.com/dexon-foundation/dexon-consensus/core/types" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -type configReader interface { - Configuration(round uint64) *types.Config -} - -// WatchCat is reponsible for signaling if syncer object should be terminated. -type WatchCat struct { - recovery core.Recovery - timeout time.Duration - configReader configReader - feed chan types.Position - lastPosition types.Position - polling time.Duration - ctx context.Context - cancel context.CancelFunc - logger common.Logger -} - -// NewWatchCat creats a new WatchCat 🐱 object. -func NewWatchCat( - recovery core.Recovery, - configReader configReader, - polling time.Duration, - timeout time.Duration, - logger common.Logger) *WatchCat { - wc := &WatchCat{ - recovery: recovery, - timeout: timeout, - configReader: configReader, - feed: make(chan types.Position), - polling: polling, - logger: logger, - } - return wc -} - -// Feed the WatchCat so it won't produce the termination signal. -func (wc *WatchCat) Feed(position types.Position) { - wc.feed <- position -} - -// Start the WatchCat. -func (wc *WatchCat) Start() { - wc.Stop() - wc.lastPosition = types.Position{} - wc.ctx, wc.cancel = context.WithCancel(context.Background()) - go func() { - var lastPos types.Position - MonitorLoop: - for { - select { - case <-wc.ctx.Done(): - return - default: - } - select { - case <-wc.ctx.Done(): - return - case pos := <-wc.feed: - if !pos.Newer(lastPos) { - wc.logger.Warn("Feed with older height", - "pos", pos, "lastPos", lastPos) - continue - } - lastPos = pos - case <-time.After(wc.timeout): - break MonitorLoop - } - } - go func() { - for { - select { - case <-wc.ctx.Done(): - return - case <-wc.feed: - } - } - }() - defer wc.cancel() - proposed := false - threshold := uint64( - utils.GetConfigWithPanic(wc.configReader, lastPos.Round, wc.logger). - NotarySetSize / 2) - wc.logger.Info("Threshold for recovery", "votes", threshold) - ResetLoop: - for { - if !proposed { - wc.logger.Info("Calling Recovery.ProposeSkipBlock", - "height", lastPos.Height) - if err := wc.recovery.ProposeSkipBlock(lastPos.Height); err != nil { - wc.logger.Warn("Failed to proposeSkipBlock", "height", lastPos.Height, "error", err) - } else { - proposed = true - } - } - votes, err := wc.recovery.Votes(lastPos.Height) - if err != nil { - wc.logger.Error("Failed to get recovery votes", "height", lastPos.Height, "error", err) - } else if votes > threshold { - wc.logger.Info("Threshold for recovery reached!") - wc.lastPosition = lastPos - break ResetLoop - } - select { - case <-wc.ctx.Done(): - return - case <-time.After(wc.polling): - } - } - }() -} - -// Stop the WatchCat. -func (wc *WatchCat) Stop() { - if wc.cancel != nil { - wc.cancel() - } -} - -// Meow return a closed channel if syncer should be terminated. -func (wc *WatchCat) Meow() <-chan struct{} { - return wc.ctx.Done() -} - -// LastPosition returns the last position for recovery. -func (wc *WatchCat) LastPosition() types.Position { - return wc.lastPosition -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/ticker.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/ticker.go deleted file mode 100644 index 636fb8c49..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/ticker.go +++ /dev/null @@ -1,127 +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 core - -import ( - "context" - "fmt" - "sync" - "time" - - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// TickerType is the type of ticker. -type TickerType int - -// TickerType enum. -const ( - TickerBA TickerType = iota - TickerDKG - TickerCRS -) - -// defaultTicker is a wrapper to implement ticker interface based on -// time.Ticker. -type defaultTicker struct { - ticker *time.Ticker - tickerChan chan time.Time - duration time.Duration - ctx context.Context - ctxCancel context.CancelFunc - waitGroup sync.WaitGroup -} - -// newDefaultTicker constructs an defaultTicker instance by giving an interval. -func newDefaultTicker(lambda time.Duration) *defaultTicker { - ticker := &defaultTicker{duration: lambda} - ticker.init() - return ticker -} - -// Tick implements Tick method of ticker interface. -func (t *defaultTicker) Tick() <-chan time.Time { - return t.tickerChan -} - -// Stop implements Stop method of ticker interface. -func (t *defaultTicker) Stop() { - t.ticker.Stop() - t.ctxCancel() - t.waitGroup.Wait() - t.ctx = nil - t.ctxCancel = nil - close(t.tickerChan) - t.tickerChan = nil -} - -// Restart implements Stop method of ticker interface. -func (t *defaultTicker) Restart() { - t.Stop() - t.init() -} - -func (t *defaultTicker) init() { - t.ticker = time.NewTicker(t.duration) - t.tickerChan = make(chan time.Time) - t.ctx, t.ctxCancel = context.WithCancel(context.Background()) - t.waitGroup.Add(1) - go t.monitor() -} - -func (t *defaultTicker) monitor() { - defer t.waitGroup.Done() -loop: - for { - select { - case <-t.ctx.Done(): - break loop - case v := <-t.ticker.C: - select { - case t.tickerChan <- v: - default: - } - } - } -} - -// newTicker is a helper to setup a ticker by giving an Governance. If -// the governace object implements a ticker generator, a ticker from that -// generator would be returned, else constructs a default one. -func newTicker(gov Governance, round uint64, tickerType TickerType) (t Ticker) { - type tickerGenerator interface { - NewTicker(TickerType) Ticker - } - - if gen, ok := gov.(tickerGenerator); ok { - t = gen.NewTicker(tickerType) - } - if t == nil { - var duration time.Duration - switch tickerType { - case TickerBA: - duration = utils.GetConfigWithPanic(gov, round, nil).LambdaBA - case TickerDKG: - duration = utils.GetConfigWithPanic(gov, round, nil).LambdaDKG - default: - panic(fmt.Errorf("unknown ticker type: %d", tickerType)) - } - t = newDefaultTicker(duration) - } - return -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block-randomness.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block-randomness.go deleted file mode 100644 index 1c7454398..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block-randomness.go +++ /dev/null @@ -1,44 +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 types - -import ( - "encoding/hex" - "fmt" - - "github.com/dexon-foundation/dexon-consensus/common" -) - -// 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"` - Randomness []byte `json:"randomness"` -} - -func (r *AgreementResult) String() string { - 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]) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go deleted file mode 100644 index 1dcd41b9e..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go +++ /dev/null @@ -1,227 +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/>. - -// TODO(jimmy-dexon): remove comments of WitnessAck before open source. - -package types - -import ( - "bytes" - "fmt" - "io" - "time" - - "github.com/dexon-foundation/dexon/rlp" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" -) - -// GenesisHeight refers to the initial height the genesis block should be. -const GenesisHeight uint64 = 1 - -// BlockVerifyStatus is the return code for core.Application.VerifyBlock -type BlockVerifyStatus int - -// Enums for return value of core.Application.VerifyBlock. -const ( - // VerifyOK: Block is verified. - VerifyOK BlockVerifyStatus = iota - // VerifyRetryLater: Block is unable to be verified at this moment. - // Try again later. - VerifyRetryLater - // VerifyInvalidBlock: Block is an invalid one. - VerifyInvalidBlock -) - -type rlpTimestamp struct { - time.Time -} - -func (t *rlpTimestamp) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, uint64(t.UTC().UnixNano())) -} - -func (t *rlpTimestamp) DecodeRLP(s *rlp.Stream) error { - var nano uint64 - err := s.Decode(&nano) - if err == nil { - sec := int64(nano) / 1000000000 - nsec := int64(nano) % 1000000000 - t.Time = time.Unix(sec, nsec).UTC() - } - return err -} - -// Witness represents the consensus information on the compaction chain. -type Witness struct { - Height uint64 `json:"height"` - Data []byte `json:"data"` -} - -// Block represents a single event broadcasted on the network. -type Block struct { - ProposerID NodeID `json:"proposer_id"` - ParentHash common.Hash `json:"parent_hash"` - Hash common.Hash `json:"hash"` - Position Position `json:"position"` - Timestamp time.Time `json:"timestamp"` - Payload []byte `json:"payload"` - PayloadHash common.Hash `json:"payload_hash"` - Witness Witness `json:"witness"` - Randomness []byte `json:"randomness"` - Signature crypto.Signature `json:"signature"` - - CRSSignature crypto.Signature `json:"crs_signature"` -} - -type rlpBlock struct { - ProposerID NodeID - ParentHash common.Hash - Hash common.Hash - Position Position - Timestamp *rlpTimestamp - Payload []byte - PayloadHash common.Hash - Witness *Witness - Randomness []byte - Signature crypto.Signature - - CRSSignature crypto.Signature -} - -// EncodeRLP implements rlp.Encoder -func (b *Block) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, rlpBlock{ - ProposerID: b.ProposerID, - ParentHash: b.ParentHash, - Hash: b.Hash, - Position: b.Position, - Timestamp: &rlpTimestamp{b.Timestamp}, - Payload: b.Payload, - PayloadHash: b.PayloadHash, - Witness: &b.Witness, - Randomness: b.Randomness, - Signature: b.Signature, - CRSSignature: b.CRSSignature, - }) -} - -// DecodeRLP implements rlp.Decoder -func (b *Block) DecodeRLP(s *rlp.Stream) error { - var dec rlpBlock - err := s.Decode(&dec) - if err == nil { - *b = Block{ - ProposerID: dec.ProposerID, - ParentHash: dec.ParentHash, - Hash: dec.Hash, - Position: dec.Position, - Timestamp: dec.Timestamp.Time, - Payload: dec.Payload, - PayloadHash: dec.PayloadHash, - Witness: *dec.Witness, - Randomness: dec.Randomness, - Signature: dec.Signature, - CRSSignature: dec.CRSSignature, - } - } - return err -} - -func (b *Block) String() string { - return fmt.Sprintf("Block{Hash:%v %s}", b.Hash.String()[:6], b.Position) -} - -// Clone returns a deep copy of a block. -func (b *Block) Clone() (bcopy *Block) { - bcopy = &Block{} - bcopy.ProposerID = b.ProposerID - bcopy.ParentHash = b.ParentHash - bcopy.Hash = b.Hash - bcopy.Position.Round = b.Position.Round - bcopy.Position.Height = b.Position.Height - bcopy.Signature = b.Signature.Clone() - bcopy.CRSSignature = b.CRSSignature.Clone() - bcopy.Witness.Height = b.Witness.Height - bcopy.Witness.Data = common.CopyBytes(b.Witness.Data) - bcopy.Timestamp = b.Timestamp - bcopy.Payload = common.CopyBytes(b.Payload) - bcopy.PayloadHash = b.PayloadHash - bcopy.Randomness = common.CopyBytes(b.Randomness) - return -} - -// IsGenesis checks if the block is a genesisBlock -func (b *Block) IsGenesis() bool { - return b.Position.Height == GenesisHeight && b.ParentHash == common.Hash{} -} - -// IsFinalized checks if the block is finalized. -func (b *Block) IsFinalized() bool { - return len(b.Randomness) > 0 -} - -// IsEmpty checks if the block is an 'empty block'. -func (b *Block) IsEmpty() bool { - return b.ProposerID.Hash == common.Hash{} -} - -// ByHash is the helper type for sorting slice of blocks by hash. -type ByHash []*Block - -func (b ByHash) Len() int { - return len(b) -} - -func (b ByHash) Less(i int, j int) bool { - return bytes.Compare([]byte(b[i].Hash[:]), []byte(b[j].Hash[:])) == -1 -} - -func (b ByHash) Swap(i int, j int) { - b[i], b[j] = b[j], b[i] -} - -// BlocksByPosition is the helper type for sorting slice of blocks by position. -type BlocksByPosition []*Block - -// Len implements Len method in sort.Sort interface. -func (bs BlocksByPosition) Len() int { - return len(bs) -} - -// Less implements Less method in sort.Sort interface. -func (bs BlocksByPosition) Less(i int, j int) bool { - return bs[j].Position.Newer(bs[i].Position) -} - -// Swap implements Swap method in sort.Sort interface. -func (bs BlocksByPosition) Swap(i int, j int) { - bs[i], bs[j] = bs[j], bs[i] -} - -// Push implements Push method in heap interface. -func (bs *BlocksByPosition) Push(x interface{}) { - *bs = append(*bs, x.(*Block)) -} - -// Pop implements Pop method in heap interface. -func (bs *BlocksByPosition) Pop() (ret interface{}) { - n := len(*bs) - *bs, ret = (*bs)[0:n-1], (*bs)[n-1] - return -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/config.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/config.go deleted file mode 100644 index dce38369e..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/config.go +++ /dev/null @@ -1,75 +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 types - -import ( - "encoding/binary" - "time" -) - -// Config stands for Current Configuration Parameters. -type Config struct { - // Lambda related. - LambdaBA time.Duration - LambdaDKG time.Duration - - // Set related. - NotarySetSize uint32 - - // Time related. - RoundLength uint64 - MinBlockInterval time.Duration -} - -// Clone return a copied configuration. -func (c *Config) Clone() *Config { - return &Config{ - LambdaBA: c.LambdaBA, - LambdaDKG: c.LambdaDKG, - NotarySetSize: c.NotarySetSize, - RoundLength: c.RoundLength, - MinBlockInterval: c.MinBlockInterval, - } -} - -// Bytes returns []byte representation of Config. -func (c *Config) Bytes() []byte { - binaryLambdaBA := make([]byte, 8) - binary.LittleEndian.PutUint64( - binaryLambdaBA, uint64(c.LambdaBA.Nanoseconds())) - binaryLambdaDKG := make([]byte, 8) - binary.LittleEndian.PutUint64( - binaryLambdaDKG, uint64(c.LambdaDKG.Nanoseconds())) - - binaryNotarySetSize := make([]byte, 4) - binary.LittleEndian.PutUint32(binaryNotarySetSize, c.NotarySetSize) - - binaryRoundLength := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRoundLength, c.RoundLength) - binaryMinBlockInterval := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryMinBlockInterval, - uint64(c.MinBlockInterval.Nanoseconds())) - - enc := make([]byte, 0, 40) - enc = append(enc, binaryLambdaBA...) - enc = append(enc, binaryLambdaDKG...) - enc = append(enc, binaryNotarySetSize...) - enc = append(enc, binaryRoundLength...) - enc = append(enc, binaryMinBlockInterval...) - return enc -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go deleted file mode 100644 index cb921e586..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/dkg/dkg.go +++ /dev/null @@ -1,485 +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 dkg - -import ( - "bytes" - "encoding/json" - "fmt" - "io" - - "github.com/dexon-foundation/dexon/rlp" - - "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/types" -) - -// Errors for typesDKG package. -var ( - ErrNotReachThreshold = fmt.Errorf("threshold not reach") - ErrInvalidThreshold = fmt.Errorf("invalid threshold") -) - -// NewID creates a DKGID from NodeID. -func NewID(ID types.NodeID) cryptoDKG.ID { - return cryptoDKG.NewID(ID.Hash[:]) -} - -// PrivateShare describe a secret share in DKG protocol. -type PrivateShare struct { - ProposerID types.NodeID `json:"proposer_id"` - ReceiverID types.NodeID `json:"receiver_id"` - Round uint64 `json:"round"` - Reset uint64 `json:"reset"` - PrivateShare cryptoDKG.PrivateKey `json:"private_share"` - Signature crypto.Signature `json:"signature"` -} - -// Equal checks equality between two PrivateShare instances. -func (p *PrivateShare) Equal(other *PrivateShare) bool { - return p.ProposerID.Equal(other.ProposerID) && - p.ReceiverID.Equal(other.ReceiverID) && - p.Round == other.Round && - p.Reset == other.Reset && - p.Signature.Type == other.Signature.Type && - bytes.Compare(p.Signature.Signature, other.Signature.Signature) == 0 && - bytes.Compare( - p.PrivateShare.Bytes(), other.PrivateShare.Bytes()) == 0 -} - -// MasterPublicKey decrtibe a master public key in DKG protocol. -type MasterPublicKey struct { - ProposerID types.NodeID `json:"proposer_id"` - Round uint64 `json:"round"` - Reset uint64 `json:"reset"` - DKGID cryptoDKG.ID `json:"dkg_id"` - PublicKeyShares cryptoDKG.PublicKeyShares `json:"public_key_shares"` - Signature crypto.Signature `json:"signature"` -} - -func (d *MasterPublicKey) String() string { - return fmt.Sprintf("MasterPublicKey{KP:%s Round:%d Reset:%d}", - d.ProposerID.String()[:6], - d.Round, - d.Reset) -} - -// Equal check equality of two DKG master public keys. -func (d *MasterPublicKey) Equal(other *MasterPublicKey) bool { - return d.ProposerID.Equal(other.ProposerID) && - d.Round == other.Round && - d.Reset == other.Reset && - d.DKGID.GetHexString() == other.DKGID.GetHexString() && - d.PublicKeyShares.Equal(&other.PublicKeyShares) && - d.Signature.Type == other.Signature.Type && - bytes.Compare(d.Signature.Signature, other.Signature.Signature) == 0 -} - -type rlpMasterPublicKey struct { - ProposerID types.NodeID - Round uint64 - Reset uint64 - DKGID []byte - PublicKeyShares *cryptoDKG.PublicKeyShares - Signature crypto.Signature -} - -// EncodeRLP implements rlp.Encoder -func (d *MasterPublicKey) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, rlpMasterPublicKey{ - ProposerID: d.ProposerID, - Round: d.Round, - Reset: d.Reset, - DKGID: d.DKGID.GetLittleEndian(), - PublicKeyShares: &d.PublicKeyShares, - Signature: d.Signature, - }) -} - -// DecodeRLP implements rlp.Decoder -func (d *MasterPublicKey) DecodeRLP(s *rlp.Stream) error { - var dec rlpMasterPublicKey - if err := s.Decode(&dec); err != nil { - return err - } - - id, err := cryptoDKG.BytesID(dec.DKGID) - if err != nil { - return err - } - - *d = MasterPublicKey{ - ProposerID: dec.ProposerID, - Round: dec.Round, - Reset: dec.Reset, - DKGID: id, - PublicKeyShares: *dec.PublicKeyShares.Move(), - Signature: dec.Signature, - } - return err -} - -// NewMasterPublicKey returns a new MasterPublicKey instance. -func NewMasterPublicKey() *MasterPublicKey { - return &MasterPublicKey{ - PublicKeyShares: *cryptoDKG.NewEmptyPublicKeyShares(), - } -} - -// UnmarshalJSON implements json.Unmarshaller. -func (d *MasterPublicKey) UnmarshalJSON(data []byte) error { - type innertMasterPublicKey MasterPublicKey - d.PublicKeyShares = *cryptoDKG.NewEmptyPublicKeyShares() - return json.Unmarshal(data, (*innertMasterPublicKey)(d)) -} - -// Complaint describe a complaint in DKG protocol. -type Complaint struct { - ProposerID types.NodeID `json:"proposer_id"` - Round uint64 `json:"round"` - Reset uint64 `json:"reset"` - PrivateShare PrivateShare `json:"private_share"` - Signature crypto.Signature `json:"signature"` -} - -func (c *Complaint) String() string { - if c.IsNack() { - return fmt.Sprintf("DKGNackComplaint{CP:%s Round:%d Reset %d PSP:%s}", - c.ProposerID.String()[:6], c.Round, c.Reset, - c.PrivateShare.ProposerID.String()[:6]) - } - return fmt.Sprintf("DKGComplaint{CP:%s Round:%d Reset %d PrivateShare:%v}", - c.ProposerID.String()[:6], c.Round, c.Reset, c.PrivateShare) -} - -// Equal checks equality between two Complaint instances. -func (c *Complaint) Equal(other *Complaint) bool { - return c.ProposerID.Equal(other.ProposerID) && - c.Round == other.Round && - c.Reset == other.Reset && - c.PrivateShare.Equal(&other.PrivateShare) && - c.Signature.Type == other.Signature.Type && - bytes.Compare(c.Signature.Signature, other.Signature.Signature) == 0 -} - -type rlpComplaint struct { - ProposerID types.NodeID - Round uint64 - Reset uint64 - IsNack bool - PrivateShare []byte - Signature crypto.Signature -} - -// EncodeRLP implements rlp.Encoder -func (c *Complaint) EncodeRLP(w io.Writer) error { - if c.IsNack() { - return rlp.Encode(w, rlpComplaint{ - ProposerID: c.ProposerID, - Round: c.Round, - Reset: c.Reset, - IsNack: true, - PrivateShare: c.PrivateShare.ProposerID.Hash[:], - Signature: c.Signature, - }) - } - prvShare, err := rlp.EncodeToBytes(&c.PrivateShare) - if err != nil { - return err - } - return rlp.Encode(w, rlpComplaint{ - ProposerID: c.ProposerID, - Round: c.Round, - Reset: c.Reset, - IsNack: false, - PrivateShare: prvShare, - Signature: c.Signature, - }) -} - -// DecodeRLP implements rlp.Decoder -func (c *Complaint) DecodeRLP(s *rlp.Stream) error { - var dec rlpComplaint - if err := s.Decode(&dec); err != nil { - return err - } - - var prvShare PrivateShare - if dec.IsNack { - copy(prvShare.ProposerID.Hash[:], dec.PrivateShare) - prvShare.Round = dec.Round - prvShare.Reset = dec.Reset - } else { - if err := rlp.DecodeBytes(dec.PrivateShare, &prvShare); err != nil { - return err - } - } - - *c = Complaint{ - ProposerID: dec.ProposerID, - Round: dec.Round, - Reset: dec.Reset, - PrivateShare: prvShare, - Signature: dec.Signature, - } - return nil -} - -// IsNack returns true if it's a nack complaint in DKG protocol. -func (c *Complaint) IsNack() bool { - return len(c.PrivateShare.Signature.Signature) == 0 -} - -// PartialSignature describe a partial signature in DKG protocol. -type PartialSignature struct { - ProposerID types.NodeID `json:"proposer_id"` - Round uint64 `json:"round"` - Hash common.Hash `json:"hash"` - PartialSignature cryptoDKG.PartialSignature `json:"partial_signature"` - Signature crypto.Signature `json:"signature"` -} - -// MPKReady describe a dkg ready message in DKG protocol. -type MPKReady struct { - ProposerID types.NodeID `json:"proposer_id"` - Round uint64 `json:"round"` - Reset uint64 `json:"reset"` - Signature crypto.Signature `json:"signature"` -} - -func (ready *MPKReady) String() string { - return fmt.Sprintf("DKGMPKReady{RP:%s Round:%d Reset:%d}", - ready.ProposerID.String()[:6], - ready.Round, - ready.Reset) -} - -// Equal check equality of two MPKReady instances. -func (ready *MPKReady) Equal(other *MPKReady) bool { - return ready.ProposerID.Equal(other.ProposerID) && - ready.Round == other.Round && - ready.Reset == other.Reset && - ready.Signature.Type == other.Signature.Type && - bytes.Compare(ready.Signature.Signature, other.Signature.Signature) == 0 -} - -// Finalize describe a dkg finalize message in DKG protocol. -type Finalize struct { - ProposerID types.NodeID `json:"proposer_id"` - Round uint64 `json:"round"` - Reset uint64 `json:"reset"` - Signature crypto.Signature `json:"signature"` -} - -func (final *Finalize) String() string { - return fmt.Sprintf("DKGFinal{FP:%s Round:%d Reset:%d}", - final.ProposerID.String()[:6], - final.Round, - final.Reset) -} - -// Equal check equality of two Finalize instances. -func (final *Finalize) Equal(other *Finalize) bool { - return final.ProposerID.Equal(other.ProposerID) && - final.Round == other.Round && - final.Reset == other.Reset && - final.Signature.Type == other.Signature.Type && - bytes.Compare(final.Signature.Signature, other.Signature.Signature) == 0 -} - -// Success describe a dkg success message in DKG protocol. -type Success struct { - ProposerID types.NodeID `json:"proposer_id"` - Round uint64 `json:"round"` - Reset uint64 `json:"reset"` - Signature crypto.Signature `json:"signature"` -} - -func (s *Success) String() string { - return fmt.Sprintf("DKGSuccess{SP:%s Round:%d Reset:%d}", - s.ProposerID.String()[:6], - s.Round, - s.Reset) -} - -// Equal check equality of two Success instances. -func (s *Success) Equal(other *Success) bool { - return s.ProposerID.Equal(other.ProposerID) && - s.Round == other.Round && - s.Reset == other.Reset && - s.Signature.Type == other.Signature.Type && - bytes.Compare(s.Signature.Signature, other.Signature.Signature) == 0 -} - -// GroupPublicKey is the result of DKG protocol. -type GroupPublicKey struct { - Round uint64 - QualifyIDs cryptoDKG.IDs - QualifyNodeIDs map[types.NodeID]struct{} - IDMap map[types.NodeID]cryptoDKG.ID - GroupPublicKey *cryptoDKG.PublicKey - Threshold int -} - -// VerifySignature verifies if the signature is correct. -func (gpk *GroupPublicKey) VerifySignature( - hash common.Hash, sig crypto.Signature) bool { - return gpk.GroupPublicKey.VerifySignature(hash, sig) -} - -// CalcQualifyNodes returns the qualified nodes. -func CalcQualifyNodes( - mpks []*MasterPublicKey, complaints []*Complaint, threshold int) ( - qualifyIDs cryptoDKG.IDs, qualifyNodeIDs map[types.NodeID]struct{}, err error) { - if len(mpks) < threshold { - err = ErrInvalidThreshold - return - } - - // Calculate qualify members. - disqualifyIDs := map[types.NodeID]struct{}{} - complaintsByID := map[types.NodeID]map[types.NodeID]struct{}{} - for _, complaint := range complaints { - if complaint.IsNack() { - if _, exist := complaintsByID[complaint.PrivateShare.ProposerID]; !exist { - complaintsByID[complaint.PrivateShare.ProposerID] = - make(map[types.NodeID]struct{}) - } - complaintsByID[complaint.PrivateShare.ProposerID][complaint.ProposerID] = - struct{}{} - } else { - disqualifyIDs[complaint.PrivateShare.ProposerID] = struct{}{} - } - } - for nID, complaints := range complaintsByID { - if len(complaints) >= threshold { - disqualifyIDs[nID] = struct{}{} - } - } - qualifyIDs = make(cryptoDKG.IDs, 0, len(mpks)-len(disqualifyIDs)) - if cap(qualifyIDs) < threshold { - err = ErrNotReachThreshold - return - } - qualifyNodeIDs = make(map[types.NodeID]struct{}) - for _, mpk := range mpks { - if _, exist := disqualifyIDs[mpk.ProposerID]; exist { - continue - } - qualifyIDs = append(qualifyIDs, mpk.DKGID) - qualifyNodeIDs[mpk.ProposerID] = struct{}{} - } - return -} - -// NewGroupPublicKey creats a GroupPublicKey instance. -func NewGroupPublicKey( - round uint64, - mpks []*MasterPublicKey, complaints []*Complaint, - threshold int) ( - *GroupPublicKey, error) { - qualifyIDs, qualifyNodeIDs, err := - CalcQualifyNodes(mpks, complaints, threshold) - if err != nil { - return nil, err - } - mpkMap := make(map[cryptoDKG.ID]*MasterPublicKey, cap(qualifyIDs)) - idMap := make(map[types.NodeID]cryptoDKG.ID) - for _, mpk := range mpks { - if _, exist := qualifyNodeIDs[mpk.ProposerID]; !exist { - continue - } - mpkMap[mpk.DKGID] = mpk - idMap[mpk.ProposerID] = mpk.DKGID - } - // Recover Group Public Key. - pubShares := make([]*cryptoDKG.PublicKeyShares, 0, len(qualifyIDs)) - for _, id := range qualifyIDs { - pubShares = append(pubShares, &mpkMap[id].PublicKeyShares) - } - groupPK := cryptoDKG.RecoverGroupPublicKey(pubShares) - return &GroupPublicKey{ - Round: round, - QualifyIDs: qualifyIDs, - QualifyNodeIDs: qualifyNodeIDs, - IDMap: idMap, - Threshold: threshold, - GroupPublicKey: groupPK, - }, nil -} - -// NodePublicKeys is the result of DKG protocol. -type NodePublicKeys struct { - Round uint64 - QualifyIDs cryptoDKG.IDs - QualifyNodeIDs map[types.NodeID]struct{} - IDMap map[types.NodeID]cryptoDKG.ID - PublicKeys map[types.NodeID]*cryptoDKG.PublicKey - Threshold int -} - -// NewNodePublicKeys creats a NodePublicKeys instance. -func NewNodePublicKeys( - round uint64, - mpks []*MasterPublicKey, complaints []*Complaint, - threshold int) ( - *NodePublicKeys, error) { - qualifyIDs, qualifyNodeIDs, err := - CalcQualifyNodes(mpks, complaints, threshold) - if err != nil { - return nil, err - } - mpkMap := make(map[cryptoDKG.ID]*MasterPublicKey, cap(qualifyIDs)) - idMap := make(map[types.NodeID]cryptoDKG.ID) - for _, mpk := range mpks { - if _, exist := qualifyNodeIDs[mpk.ProposerID]; !exist { - continue - } - mpkMap[mpk.DKGID] = mpk - idMap[mpk.ProposerID] = mpk.DKGID - } - // Recover qualify members' public key. - pubKeys := make(map[types.NodeID]*cryptoDKG.PublicKey, len(qualifyIDs)) - for _, recvID := range qualifyIDs { - pubShares := cryptoDKG.NewEmptyPublicKeyShares() - for _, id := range qualifyIDs { - pubShare, err := mpkMap[id].PublicKeyShares.Share(recvID) - if err != nil { - return nil, err - } - if err := pubShares.AddShare(id, pubShare); err != nil { - return nil, err - } - } - pubKey, err := pubShares.RecoverPublicKey(qualifyIDs) - if err != nil { - return nil, err - } - pubKeys[mpkMap[recvID].ProposerID] = pubKey - } - return &NodePublicKeys{ - Round: round, - QualifyIDs: qualifyIDs, - QualifyNodeIDs: qualifyNodeIDs, - IDMap: idMap, - PublicKeys: pubKeys, - Threshold: threshold, - }, nil -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/message.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/message.go deleted file mode 100644 index 0335cfaae..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/message.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019 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 types - -// Msg for the network ReceiveChan. -type Msg struct { - PeerID interface{} - Payload interface{} -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/node.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/node.go deleted file mode 100644 index 18b6831e0..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/node.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 types - -import ( - "bytes" - "encoding/hex" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" -) - -// NodeID is the ID type for nodes. -type NodeID struct { - common.Hash -} - -// NewNodeID returns a NodeID with Hash set to the hash value of -// public key. -func NewNodeID(pubKey crypto.PublicKey) NodeID { - return NodeID{Hash: crypto.Keccak256Hash(pubKey.Bytes()[1:])} -} - -// Equal checks if the hash representation is the same NodeID. -func (v NodeID) Equal(v2 NodeID) bool { - return v.Hash == v2.Hash -} - -func (v NodeID) String() string { - return hex.EncodeToString(v.Hash[:])[:6] -} - -// NodeIDs implements sort.Interface for NodeID. -type NodeIDs []NodeID - -func (v NodeIDs) Len() int { - return len(v) -} - -func (v NodeIDs) Less(i int, j int) bool { - return bytes.Compare([]byte(v[i].Hash[:]), []byte(v[j].Hash[:])) == -1 -} - -func (v NodeIDs) Swap(i int, j int) { - v[i], v[j] = v[j], v[i] -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/nodeset.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/nodeset.go deleted file mode 100644 index 806000763..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/nodeset.go +++ /dev/null @@ -1,162 +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 types - -import ( - "container/heap" - "encoding/binary" - "math/big" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" -) - -// NodeSet is the node set structure as defined in DEXON consensus core. -type NodeSet struct { - IDs map[NodeID]struct{} -} - -// SubSetTarget is the sub set target for GetSubSet(). -type SubSetTarget struct { - data [][]byte -} - -type subSetTargetType byte - -const ( - targetNotarySet subSetTargetType = iota - targetNodeLeader -) - -type nodeRank struct { - ID NodeID - rank *big.Int -} - -// rankHeap is a MaxHeap structure. -type rankHeap []*nodeRank - -func (h rankHeap) Len() int { return len(h) } -func (h rankHeap) Less(i, j int) bool { return h[i].rank.Cmp(h[j].rank) > 0 } -func (h rankHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } -func (h *rankHeap) Push(x interface{}) { - *h = append(*h, x.(*nodeRank)) -} -func (h *rankHeap) Pop() interface{} { - old := *h - n := len(old) - x := old[n-1] - *h = old[0 : n-1] - return x -} - -// NewNodeSet creates a new NodeSet instance. -func NewNodeSet() *NodeSet { - return &NodeSet{ - IDs: make(map[NodeID]struct{}), - } -} - -// NewNodeSetFromMap creates a new NodeSet from NodeID map. -func NewNodeSetFromMap(nodes map[NodeID]struct{}) *NodeSet { - nIDs := make(map[NodeID]struct{}, len(nodes)) - for nID := range nodes { - nIDs[nID] = struct{}{} - } - return &NodeSet{ - IDs: nIDs, - } -} - -// NewNotarySetTarget is the target for getting Notary Set. -func NewNotarySetTarget(crs common.Hash) *SubSetTarget { - return newTarget(targetNotarySet, crs[:]) -} - -// NewNodeLeaderTarget is the target for getting leader of fast BA. -func NewNodeLeaderTarget(crs common.Hash, height uint64) *SubSetTarget { - binaryHeight := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryHeight, height) - return newTarget(targetNodeLeader, crs[:], binaryHeight) -} - -// Add a NodeID to the set. -func (ns *NodeSet) Add(ID NodeID) { - ns.IDs[ID] = struct{}{} -} - -// Clone the NodeSet. -func (ns *NodeSet) Clone() *NodeSet { - nsCopy := NewNodeSet() - for ID := range ns.IDs { - nsCopy.Add(ID) - } - return nsCopy -} - -// GetSubSet returns the subset of given target. -func (ns *NodeSet) GetSubSet( - size int, target *SubSetTarget) map[NodeID]struct{} { - if size == 0 { - return make(map[NodeID]struct{}) - } - h := rankHeap{} - idx := 0 - for nID := range ns.IDs { - if idx < size { - h = append(h, newNodeRank(nID, target)) - } else if idx == size { - heap.Init(&h) - } - if idx >= size { - rank := newNodeRank(nID, target) - if rank.rank.Cmp(h[0].rank) < 0 { - h[0] = rank - heap.Fix(&h, 0) - } - } - idx++ - } - - nIDs := make(map[NodeID]struct{}, size) - for _, rank := range h { - nIDs[rank.ID] = struct{}{} - } - - return nIDs -} - -func newTarget(targetType subSetTargetType, data ...[]byte) *SubSetTarget { - data = append(data, []byte{byte(targetType)}) - return &SubSetTarget{ - data: data, - } -} - -func newNodeRank(ID NodeID, target *SubSetTarget) *nodeRank { - data := make([][]byte, 1, len(target.data)+1) - data[0] = make([]byte, len(ID.Hash)) - copy(data[0], ID.Hash[:]) - data = append(data, target.data...) - h := crypto.Keccak256Hash(data...) - num := new(big.Int).SetBytes(h[:]) - return &nodeRank{ - ID: ID, - rank: num, - } -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/position.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/position.go deleted file mode 100644 index 81d23c266..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/position.go +++ /dev/null @@ -1,51 +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 types - -import ( - "fmt" -) - -// Position describes the position in the block lattice of an entity. -type Position struct { - Round uint64 `json:"round"` - Height uint64 `json:"height"` -} - -func (pos Position) String() string { - return fmt.Sprintf("Position{Round:%d Height:%d}", pos.Round, pos.Height) -} - -// Equal checks if two positions are equal. -func (pos Position) Equal(other Position) bool { - return pos.Round == other.Round && pos.Height == other.Height -} - -// Newer checks if one block is newer than another one on the same chain. -// If two blocks on different chain compared by this function, it would panic. -func (pos Position) Newer(other Position) bool { - return pos.Round > other.Round || - (pos.Round == other.Round && pos.Height > other.Height) -} - -// Older checks if one block is older than another one on the same chain. -// If two blocks on different chain compared by this function, it would panic. -func (pos Position) Older(other Position) bool { - return pos.Round < other.Round || - (pos.Round == other.Round && pos.Height < other.Height) -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/vote.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/vote.go deleted file mode 100644 index 8bc0c78c2..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/vote.go +++ /dev/null @@ -1,100 +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 types - -import ( - "fmt" - - "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. -type VoteType byte - -// VoteType enum. -const ( - VoteInit VoteType = iota - VotePreCom - VoteCom - VoteFast - VoteFastCom - // Do not add any type below MaxVoteType. - MaxVoteType -) - -// NullBlockHash is the blockHash for ⊥ value. -var NullBlockHash common.Hash - -// SkipBlockHash is the blockHash for SKIP value. -var SkipBlockHash common.Hash - -func init() { - for idx := range SkipBlockHash { - SkipBlockHash[idx] = 0xff - } -} - -// VoteHeader is the header for vote, which can be used as map keys. -type VoteHeader struct { - ProposerID NodeID `json:"proposer_id"` - Type VoteType `json:"type"` - BlockHash common.Hash `json:"block_hash"` - Period uint64 `json:"period"` - Position Position `json:"position"` -} - -// Vote is the vote structure defined in Crypto Shuffle Algorithm. -type Vote struct { - VoteHeader `json:"header"` - PartialSignature cryptoDKG.PartialSignature `json:"partial_signature"` - Signature crypto.Signature `json:"signature"` -} - -func (v *Vote) String() string { - return fmt.Sprintf("Vote{VP:%s %s Period:%d Type:%d Hash:%s}", - v.ProposerID.String()[:6], - v.Position, v.Period, v.Type, v.BlockHash.String()[:6]) -} - -// NewVote constructs a Vote instance with header fields. -func NewVote(t VoteType, hash common.Hash, period uint64) *Vote { - return &Vote{ - VoteHeader: VoteHeader{ - Type: t, - BlockHash: hash, - Period: period, - }} -} - -// Clone returns a deep copy of a vote. -func (v *Vote) Clone() *Vote { - return &Vote{ - VoteHeader: VoteHeader{ - ProposerID: v.ProposerID, - Type: v.Type, - BlockHash: v.BlockHash, - Period: v.Period, - Position: v.Position, - }, - PartialSignature: cryptoDKG.PartialSignature( - crypto.Signature(v.PartialSignature).Clone()), - Signature: v.Signature.Clone(), - } -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go deleted file mode 100644 index c4d7b0fc3..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils.go +++ /dev/null @@ -1,255 +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 core - -import ( - "context" - "errors" - "fmt" - "os" - "sort" - "time" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/types" - "github.com/dexon-foundation/dexon-consensus/core/utils" -) - -// Errors for utils. -var ( - ErrIncorrectVoteBlockHash = fmt.Errorf( - "incorrect vote block hash") - ErrIncorrectVoteType = fmt.Errorf( - "incorrect vote type") - ErrIncorrectVotePosition = fmt.Errorf( - "incorrect vote position") - ErrIncorrectVoteProposer = fmt.Errorf( - "incorrect vote proposer") - ErrIncorrectVotePeriod = fmt.Errorf( - "incorrect vote period") -) - -// NodeSetCache is type alias to avoid fullnode compile error when moving -// it to core/utils package. -type NodeSetCache = utils.NodeSetCache - -// NewNodeSetCache is function alias to avoid fullnode compile error when moving -// it to core/utils package. -var NewNodeSetCache = utils.NewNodeSetCache - -var ( - debug = false - // ErrEmptyTimestamps would be reported if Block.timestamps is empty. - ErrEmptyTimestamps = errors.New("timestamp vector should not be empty") -) - -func init() { - if os.Getenv("DEBUG") != "" { - debug = true - } -} - -// Debugf is like fmt.Printf, but only output when we are in debug mode. -func Debugf(format string, args ...interface{}) { - if debug { - fmt.Printf(format, args...) - } -} - -// Debugln is like fmt.Println, but only output when we are in debug mode. -func Debugln(args ...interface{}) { - if debug { - fmt.Println(args...) - } -} - -func interpoTime(t1 time.Time, t2 time.Time, sep int) []time.Time { - if sep == 0 { - return []time.Time{} - } - if t1.After(t2) { - return interpoTime(t2, t1, sep) - } - timestamps := make([]time.Time, sep) - duration := t2.Sub(t1) - period := time.Duration( - (duration.Nanoseconds() / int64(sep+1))) * time.Nanosecond - prevTime := t1 - for idx := range timestamps { - prevTime = prevTime.Add(period) - timestamps[idx] = prevTime - } - return timestamps -} - -func getMedianTime(timestamps []time.Time) (t time.Time, err error) { - if len(timestamps) == 0 { - err = ErrEmptyTimestamps - return - } - tscopy := make([]time.Time, 0, len(timestamps)) - for _, ts := range timestamps { - tscopy = append(tscopy, ts) - } - sort.Sort(common.ByTime(tscopy)) - if len(tscopy)%2 == 0 { - t1 := tscopy[len(tscopy)/2-1] - t2 := tscopy[len(tscopy)/2] - t = interpoTime(t1, t2, 1)[0] - } else { - t = tscopy[len(tscopy)/2] - } - return -} - -func removeFromSortedUint32Slice(xs []uint32, x uint32) []uint32 { - indexToRemove := sort.Search(len(xs), func(idx int) bool { - return xs[idx] >= x - }) - if indexToRemove == len(xs) || xs[indexToRemove] != x { - // This value is not found. - return xs - } - return append(xs[:indexToRemove], xs[indexToRemove+1:]...) -} - -// HashConfigurationBlock returns the hash value of configuration block. -func HashConfigurationBlock( - notarySet map[types.NodeID]struct{}, - config *types.Config, - snapshotHash common.Hash, - prevHash common.Hash, -) common.Hash { - notaryIDs := make(types.NodeIDs, 0, len(notarySet)) - for nID := range notarySet { - notaryIDs = append(notaryIDs, nID) - } - sort.Sort(notaryIDs) - notarySetBytes := make([]byte, 0, len(notarySet)*len(common.Hash{})) - for _, nID := range notaryIDs { - notarySetBytes = append(notarySetBytes, nID.Hash[:]...) - } - configBytes := config.Bytes() - - return crypto.Keccak256Hash( - notarySetBytes[:], - configBytes[:], - snapshotHash[:], - prevHash[:], - ) -} - -// VerifyAgreementResult perform sanity check against a types.AgreementResult -// instance. -func VerifyAgreementResult( - res *types.AgreementResult, cache *NodeSetCache) error { - if res.Position.Round >= DKGDelayRound { - if len(res.Randomness) == 0 { - return ErrMissingRandomness - } - return nil - } - notarySet, err := cache.GetNotarySet(res.Position.Round) - if err != nil { - return err - } - if len(res.Votes) < len(notarySet)*2/3+1 { - return ErrNotEnoughVotes - } - voted := make(map[types.NodeID]struct{}, len(notarySet)) - voteType := res.Votes[0].Type - votePeriod := res.Votes[0].Period - if voteType != types.VoteFastCom && voteType != types.VoteCom { - return ErrIncorrectVoteType - } - for _, vote := range res.Votes { - if vote.Period != votePeriod { - return ErrIncorrectVotePeriod - } - if res.IsEmptyBlock { - if (vote.BlockHash != common.Hash{}) { - return ErrIncorrectVoteBlockHash - } - } else { - if vote.BlockHash != res.BlockHash { - return ErrIncorrectVoteBlockHash - } - } - if vote.Type != voteType { - return ErrIncorrectVoteType - } - if vote.Position != res.Position { - return ErrIncorrectVotePosition - } - if _, exist := notarySet[vote.ProposerID]; !exist { - return ErrIncorrectVoteProposer - } - ok, err := utils.VerifyVoteSignature(&vote) - if err != nil { - return err - } - if !ok { - return ErrIncorrectVoteSignature - } - voted[vote.ProposerID] = struct{}{} - } - if len(voted) < len(notarySet)*2/3+1 { - return ErrNotEnoughVotes - } - return nil -} - -// DiffUint64 calculates difference between two uint64. -func DiffUint64(a, b uint64) uint64 { - if a > b { - return a - b - } - return b - a -} - -func isCI() bool { - return os.Getenv("CI") != "" -} - -func isCircleCI() bool { - return isCI() && os.Getenv("CIRCLECI") == "true" -} - -func isTravisCI() bool { - return isCI() && os.Getenv("TRAVIS") == "true" -} - -// checkWithCancel is a helper to perform periodic checking with cancel. -func checkWithCancel(parentCtx context.Context, interval time.Duration, - checker func() bool) (ret bool) { - ctx, cancel := context.WithCancel(parentCtx) - defer cancel() -Loop: - for { - if ret = checker(); ret { - return - } - select { - case <-ctx.Done(): - break Loop - case <-time.After(interval): - } - } - return -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/crypto.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/crypto.go deleted file mode 100644 index 42ee6122e..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/crypto.go +++ /dev/null @@ -1,376 +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 utils - -import ( - "bytes" - "encoding/binary" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/types" - typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -func hashWitness(witness *types.Witness) (common.Hash, error) { - binaryHeight := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryHeight, witness.Height) - return crypto.Keccak256Hash( - binaryHeight, - witness.Data), nil -} - -// HashBlock generates hash of a types.Block. -func HashBlock(block *types.Block) (common.Hash, error) { - hashPosition := HashPosition(block.Position) - binaryTimestamp, err := block.Timestamp.UTC().MarshalBinary() - if err != nil { - return common.Hash{}, err - } - binaryWitness, err := hashWitness(&block.Witness) - if err != nil { - return common.Hash{}, err - } - - hash := crypto.Keccak256Hash( - block.ProposerID.Hash[:], - block.ParentHash[:], - hashPosition[:], - binaryTimestamp[:], - block.PayloadHash[:], - binaryWitness[:]) - return hash, nil -} - -// VerifyBlockSignature verifies the signature of types.Block. -func VerifyBlockSignature(b *types.Block) (err error) { - payloadHash := crypto.Keccak256Hash(b.Payload) - if payloadHash != b.PayloadHash { - err = ErrIncorrectHash - return - } - return VerifyBlockSignatureWithoutPayload(b) -} - -// VerifyBlockSignatureWithoutPayload verifies the signature of types.Block but -// does not check if PayloadHash is correct. -func VerifyBlockSignatureWithoutPayload(b *types.Block) (err error) { - hash, err := HashBlock(b) - if err != nil { - return - } - if hash != b.Hash { - err = ErrIncorrectHash - return - } - pubKey, err := crypto.SigToPub(b.Hash, b.Signature) - if err != nil { - return - } - if !b.ProposerID.Equal(types.NewNodeID(pubKey)) { - err = ErrIncorrectSignature - return - } - return - -} - -// HashVote generates hash of a types.Vote. -func HashVote(vote *types.Vote) common.Hash { - binaryPeriod := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryPeriod, vote.Period) - - hashPosition := HashPosition(vote.Position) - - hash := crypto.Keccak256Hash( - vote.ProposerID.Hash[:], - vote.BlockHash[:], - binaryPeriod, - hashPosition[:], - vote.PartialSignature.Signature[:], - []byte{byte(vote.Type)}, - ) - return hash -} - -// VerifyVoteSignature verifies the signature of types.Vote. -func VerifyVoteSignature(vote *types.Vote) (bool, error) { - hash := HashVote(vote) - pubKey, err := crypto.SigToPub(hash, vote.Signature) - if err != nil { - return false, err - } - if vote.ProposerID != types.NewNodeID(pubKey) { - return false, nil - } - return true, nil -} - -func hashCRS(block *types.Block, crs common.Hash) common.Hash { - hashPos := HashPosition(block.Position) - if block.Position.Round < dkgDelayRound { - return crypto.Keccak256Hash(crs[:], hashPos[:], block.ProposerID.Hash[:]) - } - return crypto.Keccak256Hash(crs[:], hashPos[:]) -} - -// VerifyCRSSignature verifies the CRS signature of types.Block. -func VerifyCRSSignature( - block *types.Block, crs common.Hash, npks *typesDKG.NodePublicKeys) bool { - hash := hashCRS(block, crs) - if block.Position.Round < dkgDelayRound { - return bytes.Compare(block.CRSSignature.Signature[:], hash[:]) == 0 - } - if npks == nil { - return false - } - pubKey, exist := npks.PublicKeys[block.ProposerID] - if !exist { - return false - } - return pubKey.VerifySignature(hash, block.CRSSignature) -} - -// HashPosition generates hash of a types.Position. -func HashPosition(position types.Position) common.Hash { - binaryRound := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRound, position.Round) - - binaryHeight := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryHeight, position.Height) - - return crypto.Keccak256Hash( - binaryRound, - binaryHeight, - ) -} - -func hashDKGPrivateShare(prvShare *typesDKG.PrivateShare) common.Hash { - binaryRound := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRound, prvShare.Round) - binaryReset := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryReset, prvShare.Reset) - - return crypto.Keccak256Hash( - prvShare.ProposerID.Hash[:], - prvShare.ReceiverID.Hash[:], - binaryRound, - binaryReset, - prvShare.PrivateShare.Bytes(), - ) -} - -// VerifyDKGPrivateShareSignature verifies the signature of -// typesDKG.PrivateShare. -func VerifyDKGPrivateShareSignature( - prvShare *typesDKG.PrivateShare) (bool, error) { - hash := hashDKGPrivateShare(prvShare) - pubKey, err := crypto.SigToPub(hash, prvShare.Signature) - if err != nil { - return false, err - } - if prvShare.ProposerID != types.NewNodeID(pubKey) { - return false, nil - } - return true, nil -} - -func hashDKGMasterPublicKey(mpk *typesDKG.MasterPublicKey) common.Hash { - binaryRound := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRound, mpk.Round) - binaryReset := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryReset, mpk.Reset) - - return crypto.Keccak256Hash( - mpk.ProposerID.Hash[:], - mpk.DKGID.GetLittleEndian(), - mpk.PublicKeyShares.MasterKeyBytes(), - binaryRound, - binaryReset, - ) -} - -// VerifyDKGMasterPublicKeySignature verifies DKGMasterPublicKey signature. -func VerifyDKGMasterPublicKeySignature( - mpk *typesDKG.MasterPublicKey) (bool, error) { - hash := hashDKGMasterPublicKey(mpk) - pubKey, err := crypto.SigToPub(hash, mpk.Signature) - if err != nil { - return false, err - } - if mpk.ProposerID != types.NewNodeID(pubKey) { - return false, nil - } - return true, nil -} - -func hashDKGComplaint(complaint *typesDKG.Complaint) common.Hash { - binaryRound := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRound, complaint.Round) - binaryReset := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryReset, complaint.Reset) - - hashPrvShare := hashDKGPrivateShare(&complaint.PrivateShare) - - return crypto.Keccak256Hash( - complaint.ProposerID.Hash[:], - binaryRound, - binaryReset, - hashPrvShare[:], - ) -} - -// VerifyDKGComplaintSignature verifies DKGCompliant signature. -func VerifyDKGComplaintSignature( - complaint *typesDKG.Complaint) (bool, error) { - if complaint.Round != complaint.PrivateShare.Round { - return false, nil - } - if complaint.Reset != complaint.PrivateShare.Reset { - return false, nil - } - hash := hashDKGComplaint(complaint) - pubKey, err := crypto.SigToPub(hash, complaint.Signature) - if err != nil { - return false, err - } - if complaint.ProposerID != types.NewNodeID(pubKey) { - return false, nil - } - if !complaint.IsNack() { - return VerifyDKGPrivateShareSignature(&complaint.PrivateShare) - } - return true, nil -} - -func hashDKGPartialSignature(psig *typesDKG.PartialSignature) common.Hash { - binaryRound := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRound, psig.Round) - - return crypto.Keccak256Hash( - psig.ProposerID.Hash[:], - binaryRound, - psig.Hash[:], - psig.PartialSignature.Signature[:], - ) -} - -// VerifyDKGPartialSignatureSignature verifies the signature of -// typesDKG.PartialSignature. -func VerifyDKGPartialSignatureSignature( - psig *typesDKG.PartialSignature) (bool, error) { - hash := hashDKGPartialSignature(psig) - pubKey, err := crypto.SigToPub(hash, psig.Signature) - if err != nil { - return false, err - } - if psig.ProposerID != types.NewNodeID(pubKey) { - return false, nil - } - return true, nil -} - -func hashDKGMPKReady(ready *typesDKG.MPKReady) common.Hash { - binaryRound := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRound, ready.Round) - binaryReset := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryReset, ready.Reset) - - return crypto.Keccak256Hash( - ready.ProposerID.Hash[:], - binaryRound, - binaryReset, - ) -} - -// VerifyDKGMPKReadySignature verifies DKGMPKReady signature. -func VerifyDKGMPKReadySignature( - ready *typesDKG.MPKReady) (bool, error) { - hash := hashDKGMPKReady(ready) - pubKey, err := crypto.SigToPub(hash, ready.Signature) - if err != nil { - return false, err - } - if ready.ProposerID != types.NewNodeID(pubKey) { - return false, nil - } - return true, nil -} - -func hashDKGFinalize(final *typesDKG.Finalize) common.Hash { - binaryRound := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRound, final.Round) - binaryReset := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryReset, final.Reset) - - return crypto.Keccak256Hash( - final.ProposerID.Hash[:], - binaryRound, - binaryReset, - ) -} - -func hashDKGSuccess(success *typesDKG.Success) common.Hash { - binaryRound := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryRound, success.Round) - binaryReset := make([]byte, 8) - binary.LittleEndian.PutUint64(binaryReset, success.Reset) - - return crypto.Keccak256Hash( - success.ProposerID.Hash[:], - binaryRound, - binaryReset, - ) -} - -// VerifyDKGFinalizeSignature verifies DKGFinalize signature. -func VerifyDKGFinalizeSignature( - final *typesDKG.Finalize) (bool, error) { - hash := hashDKGFinalize(final) - pubKey, err := crypto.SigToPub(hash, final.Signature) - if err != nil { - return false, err - } - if final.ProposerID != types.NewNodeID(pubKey) { - return false, nil - } - return true, nil -} - -// VerifyDKGSuccessSignature verifies DKGSuccess signature. -func VerifyDKGSuccessSignature( - success *typesDKG.Success) (bool, error) { - hash := hashDKGSuccess(success) - pubKey, err := crypto.SigToPub(hash, success.Signature) - if err != nil { - return false, err - } - if success.ProposerID != types.NewNodeID(pubKey) { - return false, nil - } - return true, nil -} - -// Rehash hashes the hash again and again and again... -func Rehash(hash common.Hash, count uint) common.Hash { - result := hash - for i := uint(0); i < count; i++ { - result = crypto.Keccak256Hash(result[:]) - } - return result -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/nodeset-cache.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/nodeset-cache.go deleted file mode 100644 index 89dcfc86b..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/nodeset-cache.go +++ /dev/null @@ -1,245 +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 utils - -import ( - "errors" - "sync" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -var ( - // ErrNodeSetNotReady means we got nil empty node set. - ErrNodeSetNotReady = errors.New("node set is not ready") - // ErrCRSNotReady means we got empty CRS. - ErrCRSNotReady = errors.New("crs is not ready") - // ErrConfigurationNotReady means we go nil configuration. - ErrConfigurationNotReady = errors.New("configuration is not ready") -) - -type sets struct { - crs common.Hash - nodeSet *types.NodeSet - notarySet map[types.NodeID]struct{} -} - -// NodeSetCacheInterface interface specifies interface used by NodeSetCache. -type NodeSetCacheInterface interface { - // Configuration returns the configuration at a given round. - // Return the genesis configuration if round == 0. - Configuration(round uint64) *types.Config - - // CRS returns the CRS for a given round. - // Return the genesis CRS if round == 0. - CRS(round uint64) common.Hash - - // NodeSet returns the node set at a given round. - // Return the genesis node set if round == 0. - NodeSet(round uint64) []crypto.PublicKey -} - -// NodeSetCache caches node set information. -// -// NOTE: this module doesn't handle DKG resetting and can only be used along -// with utils.RoundEvent. -type NodeSetCache struct { - lock sync.RWMutex - nsIntf NodeSetCacheInterface - rounds map[uint64]*sets - keyPool map[types.NodeID]*struct { - pubKey crypto.PublicKey - refCnt int - } -} - -// NewNodeSetCache constructs an NodeSetCache instance. -func NewNodeSetCache(nsIntf NodeSetCacheInterface) *NodeSetCache { - return &NodeSetCache{ - nsIntf: nsIntf, - rounds: make(map[uint64]*sets), - keyPool: make(map[types.NodeID]*struct { - pubKey crypto.PublicKey - refCnt int - }), - } -} - -// Exists checks if a node is in node set of that round. -func (cache *NodeSetCache) Exists( - round uint64, nodeID types.NodeID) (exists bool, err error) { - - nIDs, exists := cache.get(round) - if !exists { - if nIDs, err = cache.update(round); err != nil { - return - } - } - _, exists = nIDs.nodeSet.IDs[nodeID] - return -} - -// GetPublicKey return public key for that node: -func (cache *NodeSetCache) GetPublicKey( - nodeID types.NodeID) (key crypto.PublicKey, exists bool) { - - cache.lock.RLock() - defer cache.lock.RUnlock() - - rec, exists := cache.keyPool[nodeID] - if exists { - key = rec.pubKey - } - return -} - -// GetNodeSet returns IDs of nodes set of this round as map. -func (cache *NodeSetCache) GetNodeSet(round uint64) (*types.NodeSet, error) { - IDs, exists := cache.get(round) - if !exists { - var err error - if IDs, err = cache.update(round); err != nil { - return nil, err - } - } - return IDs.nodeSet.Clone(), nil -} - -// GetNotarySet returns of notary set of this round. -func (cache *NodeSetCache) GetNotarySet( - round uint64) (map[types.NodeID]struct{}, error) { - IDs, err := cache.getOrUpdate(round) - if err != nil { - return nil, err - } - return cache.cloneMap(IDs.notarySet), nil -} - -// Purge a specific round. -func (cache *NodeSetCache) Purge(rID uint64) { - cache.lock.Lock() - defer cache.lock.Unlock() - nIDs, exist := cache.rounds[rID] - if !exist { - return - } - for nID := range nIDs.nodeSet.IDs { - rec := cache.keyPool[nID] - if rec.refCnt--; rec.refCnt == 0 { - delete(cache.keyPool, nID) - } - } - delete(cache.rounds, rID) -} - -// Touch updates the internal cache of round. -func (cache *NodeSetCache) Touch(round uint64) (err error) { - _, err = cache.update(round) - return -} - -func (cache *NodeSetCache) cloneMap( - nIDs map[types.NodeID]struct{}) map[types.NodeID]struct{} { - nIDsCopy := make(map[types.NodeID]struct{}, len(nIDs)) - for k := range nIDs { - nIDsCopy[k] = struct{}{} - } - return nIDsCopy -} - -func (cache *NodeSetCache) getOrUpdate(round uint64) (nIDs *sets, err error) { - s, exists := cache.get(round) - if !exists { - if s, err = cache.update(round); err != nil { - return - } - } - nIDs = s - return -} - -// update node set for that round. -// -// This cache would maintain 10 rounds before the updated round and purge -// rounds not in this range. -func (cache *NodeSetCache) update(round uint64) (nIDs *sets, err error) { - cache.lock.Lock() - defer cache.lock.Unlock() - // Get information for the requested round. - keySet := cache.nsIntf.NodeSet(round) - if keySet == nil { - err = ErrNodeSetNotReady - return - } - crs := cache.nsIntf.CRS(round) - if (crs == common.Hash{}) { - err = ErrCRSNotReady - return - } - // Cache new round. - nodeSet := types.NewNodeSet() - for _, key := range keySet { - nID := types.NewNodeID(key) - nodeSet.Add(nID) - if rec, exists := cache.keyPool[nID]; exists { - rec.refCnt++ - } else { - cache.keyPool[nID] = &struct { - pubKey crypto.PublicKey - refCnt int - }{key, 1} - } - } - cfg := cache.nsIntf.Configuration(round) - if cfg == nil { - err = ErrConfigurationNotReady - return - } - nIDs = &sets{ - crs: crs, - nodeSet: nodeSet, - notarySet: make(map[types.NodeID]struct{}), - } - nIDs.notarySet = nodeSet.GetSubSet( - int(cfg.NotarySetSize), types.NewNotarySetTarget(crs)) - cache.rounds[round] = nIDs - // Purge older rounds. - for rID, nIDs := range cache.rounds { - nodeSet := nIDs.nodeSet - if round-rID <= 5 { - continue - } - for nID := range nodeSet.IDs { - rec := cache.keyPool[nID] - if rec.refCnt--; rec.refCnt == 0 { - delete(cache.keyPool, nID) - } - } - delete(cache.rounds, rID) - } - return -} - -func (cache *NodeSetCache) get(round uint64) (nIDs *sets, exists bool) { - cache.lock.RLock() - defer cache.lock.RUnlock() - nIDs, exists = cache.rounds[round] - return -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/penalty-helper.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/penalty-helper.go deleted file mode 100644 index 0b38474a6..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/penalty-helper.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2019 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 utils - -import ( - "errors" - - "github.com/dexon-foundation/dexon-consensus/core/types" - typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -var ( - // ErrInvalidDKGMasterPublicKey means the DKG MasterPublicKey is invalid. - ErrInvalidDKGMasterPublicKey = errors.New("invalid DKG master public key") - // ErrPayloadNotEmpty means the payload of block is not empty. - ErrPayloadNotEmpty = errors.New("payload not empty") -) - -// NeedPenaltyDKGPrivateShare checks if the proposer of dkg private share -// should be penalized. -func NeedPenaltyDKGPrivateShare( - complaint *typesDKG.Complaint, mpk *typesDKG.MasterPublicKey) (bool, error) { - if complaint.IsNack() { - return false, nil - } - if mpk.ProposerID != complaint.PrivateShare.ProposerID { - return false, nil - } - ok, err := VerifyDKGMasterPublicKeySignature(mpk) - if err != nil { - return false, err - } - if !ok { - return false, ErrInvalidDKGMasterPublicKey - } - ok, err = VerifyDKGComplaintSignature(complaint) - if err != nil { - return false, err - } - if !ok { - return false, nil - } - ok, err = mpk.PublicKeyShares.VerifyPrvShare( - typesDKG.NewID(complaint.PrivateShare.ReceiverID), - &complaint.PrivateShare.PrivateShare) - if err != nil { - return false, err - } - return !ok, nil -} - -// NeedPenaltyForkVote checks if two votes are fork vote. -func NeedPenaltyForkVote(vote1, vote2 *types.Vote) (bool, error) { - if vote1.ProposerID != vote2.ProposerID || - vote1.Type != vote2.Type || - vote1.Period != vote2.Period || - vote1.Position != vote2.Position || - vote1.BlockHash == vote2.BlockHash { - return false, nil - } - ok, err := VerifyVoteSignature(vote1) - if err != nil { - return false, err - } - if !ok { - return false, nil - } - ok, err = VerifyVoteSignature(vote2) - if err != nil { - return false, err - } - if !ok { - return false, nil - } - return true, nil -} - -// NeedPenaltyForkBlock checks if two blocks are fork block. -func NeedPenaltyForkBlock(block1, block2 *types.Block) (bool, error) { - if block1.ProposerID != block2.ProposerID || - block1.Position != block2.Position || - block1.Hash == block2.Hash { - return false, nil - } - if len(block1.Payload) != 0 || len(block2.Payload) != 0 { - return false, ErrPayloadNotEmpty - } - verifyBlock := func(block *types.Block) (bool, error) { - err := VerifyBlockSignatureWithoutPayload(block) - switch err { - case nil: - return true, nil - case ErrIncorrectSignature: - return false, nil - case ErrIncorrectHash: - return false, nil - default: - return false, err - } - } - ok, err := verifyBlock(block1) - if err != nil { - return false, err - } - if !ok { - return false, nil - } - ok, err = verifyBlock(block2) - if err != nil { - return false, err - } - if !ok { - return false, nil - } - return true, nil -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-based-config.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-based-config.go deleted file mode 100644 index 4c83d046b..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-based-config.go +++ /dev/null @@ -1,112 +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 utils - -import ( - "fmt" - - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -// RoundBasedConfig is based config for rounds and provide boundary checking -// for rounds. -type RoundBasedConfig struct { - roundID uint64 - roundBeginHeight uint64 - roundEndHeight uint64 - roundLength uint64 -} - -// SetupRoundBasedFields setup round based fields, including round ID, the -// length of rounds. -func (c *RoundBasedConfig) SetupRoundBasedFields( - roundID uint64, cfg *types.Config) { - if c.roundLength > 0 { - panic(fmt.Errorf("duplicated set round based fields: %d", - c.roundLength)) - } - c.roundID = roundID - c.roundLength = cfg.RoundLength -} - -// SetRoundBeginHeight gives the beginning height for the initial round provided -// when constructed. -func (c *RoundBasedConfig) SetRoundBeginHeight(begin uint64) { - if c.roundBeginHeight != 0 { - panic(fmt.Errorf("duplicated set round begin height: %d", - c.roundBeginHeight)) - } - c.roundBeginHeight = begin - c.roundEndHeight = begin + c.roundLength -} - -// IsLastBlock checks if a block is the last block of this round. -func (c *RoundBasedConfig) IsLastBlock(b *types.Block) bool { - if b.Position.Round != c.roundID { - panic(fmt.Errorf("attempt to compare by different round: %s, %d", - b, c.roundID)) - } - return b.Position.Height+1 == c.roundEndHeight -} - -// ExtendLength extends round ending height by the length of current round. -func (c *RoundBasedConfig) ExtendLength() { - c.roundEndHeight += c.roundLength -} - -// Contains checks if a block height is in this round. -func (c *RoundBasedConfig) Contains(h uint64) bool { - return c.roundBeginHeight <= h && c.roundEndHeight > h -} - -// RoundID returns the round ID of this config. -func (c *RoundBasedConfig) RoundID() uint64 { - if c.roundLength == 0 { - panic(fmt.Errorf("config is not initialized: %d", c.roundID)) - } - return c.roundID -} - -// RoundEndHeight returns next checkpoint to varify if this round is ended. -func (c *RoundBasedConfig) RoundEndHeight() uint64 { - if c.roundLength == 0 { - panic(fmt.Errorf("config is not initialized: %d", c.roundID)) - } - return c.roundEndHeight -} - -// AppendTo a config from previous round. -func (c *RoundBasedConfig) AppendTo(other RoundBasedConfig) { - if c.roundID != other.roundID+1 { - panic(fmt.Errorf("round IDs of configs not continuous: %d %d", - c.roundID, other.roundID)) - } - c.SetRoundBeginHeight(other.roundEndHeight) -} - -// LastPeriodBeginHeight returns the begin height of last period. For example, -// if a round is extended twice, then the return from this method is: -// -// begin + 2 * roundLength - roundLength -// -func (c *RoundBasedConfig) LastPeriodBeginHeight() uint64 { - if c.roundLength == 0 { - panic(fmt.Errorf("config is not initialized: %d", c.roundID)) - } - return c.roundEndHeight - c.roundLength -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go deleted file mode 100644 index bda4383fa..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright 2019 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 utils - -import ( - "context" - "fmt" - "sync" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/types" - typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -// ErrUnmatchedBlockHeightWithConfig is for invalid parameters for NewRoundEvent. -type ErrUnmatchedBlockHeightWithConfig struct { - round uint64 - reset uint64 - blockHeight uint64 -} - -func (e ErrUnmatchedBlockHeightWithConfig) Error() string { - return fmt.Sprintf("unsynced block height and cfg: round:%d reset:%d h:%d", - e.round, e.reset, e.blockHeight) -} - -// RoundEventParam defines the parameters passed to event handlers of -// RoundEvent. -type RoundEventParam struct { - // 'Round' of next checkpoint, might be identical to previous checkpoint. - Round uint64 - // the count of reset DKG for 'Round+1'. - Reset uint64 - // the begin block height of this event, the end block height of this event - // would be BeginHeight + config.RoundLength. - BeginHeight uint64 - // The configuration for 'Round'. - Config *types.Config - // The CRS for 'Round'. - CRS common.Hash -} - -// NextRoundValidationHeight returns the height to check if the next round is -// ready. -func (e RoundEventParam) NextRoundValidationHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength*9/10 -} - -// NextCRSProposingHeight returns the height to propose CRS for next round. -func (e RoundEventParam) NextCRSProposingHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength/2 -} - -// NextDKGPreparationHeight returns the height to prepare DKG set for next -// round. -func (e RoundEventParam) NextDKGPreparationHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength*2/3 -} - -// NextRoundHeight returns the height of the beginning of next round. -func (e RoundEventParam) NextRoundHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength -} - -// NextTouchNodeSetCacheHeight returns the height to touch the node set cache. -func (e RoundEventParam) NextTouchNodeSetCacheHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength/2 -} - -// NextDKGResetHeight returns the height to reset DKG for next period. -func (e RoundEventParam) NextDKGResetHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength*85/100 -} - -// NextDKGRegisterHeight returns the height to register DKG. -func (e RoundEventParam) NextDKGRegisterHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength/2 -} - -// RoundEndHeight returns the round ending height of this round event. -func (e RoundEventParam) RoundEndHeight() uint64 { - return e.BeginHeight + e.Config.RoundLength -} - -func (e RoundEventParam) String() string { - return fmt.Sprintf("roundEvtParam{Round:%d Reset:%d Height:%d}", - e.Round, - e.Reset, - e.BeginHeight) -} - -// roundEventFn defines the fingerprint of handlers of round events. -type roundEventFn func([]RoundEventParam) - -// governanceAccessor is a subset of core.Governance to break the dependency -// between core and utils package. -type governanceAccessor interface { - // Configuration returns the configuration at a given round. - // Return the genesis configuration if round == 0. - Configuration(round uint64) *types.Config - - // CRS returns the CRS for a given round. - // Return the genesis CRS if round == 0. - CRS(round uint64) common.Hash - - // DKGComplaints gets all the DKGComplaints of round. - DKGComplaints(round uint64) []*typesDKG.Complaint - - // DKGMasterPublicKeys gets all the DKGMasterPublicKey of round. - DKGMasterPublicKeys(round uint64) []*typesDKG.MasterPublicKey - - // IsDKGFinal checks if DKG is final. - IsDKGFinal(round uint64) bool - - // IsDKGSuccess checks if DKG is success. - IsDKGSuccess(round uint64) bool - - // DKGResetCount returns the reset count for DKG of given round. - DKGResetCount(round uint64) uint64 - - // Get the begin height of a round. - GetRoundHeight(round uint64) uint64 -} - -// RoundEventRetryHandlerGenerator generates a handler to common.Event, which -// would register itself to retry next round validation if round event is not -// triggered. -func RoundEventRetryHandlerGenerator( - rEvt *RoundEvent, hEvt *common.Event) func(uint64) { - var hEvtHandler func(uint64) - hEvtHandler = func(h uint64) { - if rEvt.ValidateNextRound(h) == 0 { - // Retry until at least one round event is triggered. - hEvt.RegisterHeight(h+1, hEvtHandler) - } - } - return hEvtHandler -} - -// RoundEvent would be triggered when either: -// - the next DKG set setup is ready. -// - the next DKG set setup is failed, and previous DKG set already reset the -// CRS. -type RoundEvent struct { - gov governanceAccessor - logger common.Logger - lock sync.Mutex - handlers []roundEventFn - config RoundBasedConfig - lastTriggeredRound uint64 - lastTriggeredResetCount uint64 - roundShift uint64 - gpkInvalid bool - ctx context.Context - ctxCancel context.CancelFunc -} - -// NewRoundEvent creates an RoundEvent instance. -func NewRoundEvent(parentCtx context.Context, gov governanceAccessor, - logger common.Logger, initPos types.Position, roundShift uint64) ( - *RoundEvent, error) { - // We need to generate valid ending block height of this round (taken - // DKG reset count into consideration). - logger.Info("new RoundEvent", "position", initPos, "shift", roundShift) - initConfig := GetConfigWithPanic(gov, initPos.Round, logger) - e := &RoundEvent{ - gov: gov, - logger: logger, - lastTriggeredRound: initPos.Round, - roundShift: roundShift, - } - e.ctx, e.ctxCancel = context.WithCancel(parentCtx) - e.config = RoundBasedConfig{} - e.config.SetupRoundBasedFields(initPos.Round, initConfig) - e.config.SetRoundBeginHeight(GetRoundHeight(gov, initPos.Round)) - // Make sure the DKG reset count in current governance can cover the initial - // block height. - if initPos.Height >= types.GenesisHeight { - resetCount := gov.DKGResetCount(initPos.Round + 1) - remains := resetCount - for ; remains > 0 && !e.config.Contains(initPos.Height); remains-- { - e.config.ExtendLength() - } - if !e.config.Contains(initPos.Height) { - return nil, ErrUnmatchedBlockHeightWithConfig{ - round: initPos.Round, - reset: resetCount, - blockHeight: initPos.Height, - } - } - e.lastTriggeredResetCount = resetCount - remains - } - return e, nil -} - -// Register a handler to be called when new round is confirmed or new DKG reset -// is detected. -// -// The earlier registered handler has higher priority. -func (e *RoundEvent) Register(h roundEventFn) { - e.lock.Lock() - defer e.lock.Unlock() - e.handlers = append(e.handlers, h) -} - -// TriggerInitEvent triggers event from the initial setting. -func (e *RoundEvent) TriggerInitEvent() { - e.lock.Lock() - defer e.lock.Unlock() - events := []RoundEventParam{RoundEventParam{ - Round: e.lastTriggeredRound, - Reset: e.lastTriggeredResetCount, - BeginHeight: e.config.LastPeriodBeginHeight(), - CRS: GetCRSWithPanic(e.gov, e.lastTriggeredRound, e.logger), - Config: GetConfigWithPanic(e.gov, e.lastTriggeredRound, e.logger), - }} - for _, h := range e.handlers { - h(events) - } -} - -// ValidateNextRound validate if the DKG set for next round is ready to go or -// failed to setup, all registered handlers would be called once some decision -// is made on chain. -// -// The count of triggered events would be returned. -func (e *RoundEvent) ValidateNextRound(blockHeight uint64) (count uint) { - // To make triggers continuous and sequential, the next validation should - // wait for previous one finishing. That's why I use mutex here directly. - var events []RoundEventParam - e.lock.Lock() - defer e.lock.Unlock() - e.logger.Trace("ValidateNextRound", - "height", blockHeight, - "round", e.lastTriggeredRound, - "count", e.lastTriggeredResetCount) - defer func() { - count = uint(len(events)) - if count == 0 { - return - } - for _, h := range e.handlers { - // To make sure all handlers receive triggers sequentially, we can't - // raise go routines here. - h(events) - } - }() - var ( - triggered bool - param RoundEventParam - beginHeight = blockHeight - startRound = e.lastTriggeredRound - ) - for { - param, triggered = e.check(beginHeight, startRound) - if !triggered { - break - } - events = append(events, param) - beginHeight = param.BeginHeight - } - return -} - -func (e *RoundEvent) check(blockHeight, startRound uint64) ( - param RoundEventParam, triggered bool) { - defer func() { - if !triggered { - return - } - // A simple assertion to make sure we didn't pick the wrong round. - if e.config.RoundID() != e.lastTriggeredRound { - panic(fmt.Errorf("Triggered round not matched: %d, %d", - e.config.RoundID(), e.lastTriggeredRound)) - } - param.Round = e.lastTriggeredRound - param.Reset = e.lastTriggeredResetCount - param.BeginHeight = e.config.LastPeriodBeginHeight() - param.CRS = GetCRSWithPanic(e.gov, e.lastTriggeredRound, e.logger) - param.Config = GetConfigWithPanic(e.gov, e.lastTriggeredRound, e.logger) - e.logger.Info("New RoundEvent triggered", - "round", e.lastTriggeredRound, - "reset", e.lastTriggeredResetCount, - "begin-height", e.config.LastPeriodBeginHeight(), - "crs", param.CRS.String()[:6], - ) - }() - nextRound := e.lastTriggeredRound + 1 - if nextRound >= startRound+e.roundShift { - // Avoid access configuration newer than last confirmed one over - // 'roundShift' rounds. Fullnode might crash if we access it before it - // knows. - return - } - nextCfg := GetConfigWithPanic(e.gov, nextRound, e.logger) - resetCount := e.gov.DKGResetCount(nextRound) - if resetCount > e.lastTriggeredResetCount { - e.lastTriggeredResetCount++ - e.config.ExtendLength() - e.gpkInvalid = false - triggered = true - return - } - if e.gpkInvalid { - // We know that DKG already failed, now wait for the DKG set from - // previous round to reset DKG and don't have to reconstruct the - // group public key again. - return - } - if nextRound >= dkgDelayRound { - var ok bool - ok, e.gpkInvalid = IsDKGValid( - e.gov, e.logger, nextRound, e.lastTriggeredResetCount) - if !ok { - return - } - } - // The DKG set for next round is well prepared. - e.lastTriggeredRound = nextRound - e.lastTriggeredResetCount = 0 - e.gpkInvalid = false - rCfg := RoundBasedConfig{} - rCfg.SetupRoundBasedFields(nextRound, nextCfg) - rCfg.AppendTo(e.config) - e.config = rCfg - triggered = true - return -} - -// Stop the event source and block until last trigger returns. -func (e *RoundEvent) Stop() { - e.ctxCancel() -} - -// LastPeriod returns block height related info of the last period, including -// begin height and round length. -func (e *RoundEvent) LastPeriod() (begin uint64, length uint64) { - e.lock.Lock() - defer e.lock.Unlock() - begin = e.config.LastPeriodBeginHeight() - length = e.config.RoundEndHeight() - e.config.LastPeriodBeginHeight() - return -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/signer.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/signer.go deleted file mode 100644 index ff767437f..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/signer.go +++ /dev/null @@ -1,154 +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 utils - -import ( - "errors" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/crypto" - "github.com/dexon-foundation/dexon-consensus/core/types" - typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -// Errors for signer. -var ( - ErrInvalidProposerID = errors.New("invalid proposer id") - ErrIncorrectHash = errors.New("hash of block is incorrect") - ErrIncorrectSignature = errors.New("signature of block is incorrect") - ErrNoBLSSigner = errors.New("bls signer not set") -) - -type blsSigner func(round uint64, hash common.Hash) (crypto.Signature, error) - -// Signer signs a segment of data. -type Signer struct { - prvKey crypto.PrivateKey - pubKey crypto.PublicKey - proposerID types.NodeID - blsSign blsSigner -} - -// NewSigner constructs an Signer instance. -func NewSigner(prvKey crypto.PrivateKey) (s *Signer) { - s = &Signer{ - prvKey: prvKey, - pubKey: prvKey.PublicKey(), - } - s.proposerID = types.NewNodeID(s.pubKey) - return -} - -// SetBLSSigner for signing CRSSignature -func (s *Signer) SetBLSSigner(signer blsSigner) { - s.blsSign = signer -} - -// SignBlock signs a types.Block. -func (s *Signer) SignBlock(b *types.Block) (err error) { - b.ProposerID = s.proposerID - b.PayloadHash = crypto.Keccak256Hash(b.Payload) - if b.Hash, err = HashBlock(b); err != nil { - return - } - if b.Signature, err = s.prvKey.Sign(b.Hash); err != nil { - return - } - return -} - -// SignVote signs a types.Vote. -func (s *Signer) SignVote(v *types.Vote) (err error) { - v.ProposerID = s.proposerID - v.Signature, err = s.prvKey.Sign(HashVote(v)) - return -} - -// SignCRS signs CRS signature of types.Block. -func (s *Signer) SignCRS(b *types.Block, crs common.Hash) (err error) { - if b.ProposerID != s.proposerID { - err = ErrInvalidProposerID - return - } - if b.Position.Round < dkgDelayRound { - hash := hashCRS(b, crs) - b.CRSSignature = crypto.Signature{ - Type: "bls", - Signature: hash[:], - } - return - } - if s.blsSign == nil { - err = ErrNoBLSSigner - return - } - b.CRSSignature, err = s.blsSign(b.Position.Round, hashCRS(b, crs)) - return -} - -// SignDKGComplaint signs a DKG complaint. -func (s *Signer) SignDKGComplaint(complaint *typesDKG.Complaint) (err error) { - complaint.ProposerID = s.proposerID - complaint.Signature, err = s.prvKey.Sign(hashDKGComplaint(complaint)) - return -} - -// SignDKGMasterPublicKey signs a DKG master public key. -func (s *Signer) SignDKGMasterPublicKey( - mpk *typesDKG.MasterPublicKey) (err error) { - mpk.ProposerID = s.proposerID - mpk.Signature, err = s.prvKey.Sign(hashDKGMasterPublicKey(mpk)) - return -} - -// SignDKGPrivateShare signs a DKG private share. -func (s *Signer) SignDKGPrivateShare( - prvShare *typesDKG.PrivateShare) (err error) { - prvShare.ProposerID = s.proposerID - prvShare.Signature, err = s.prvKey.Sign(hashDKGPrivateShare(prvShare)) - return -} - -// SignDKGPartialSignature signs a DKG partial signature. -func (s *Signer) SignDKGPartialSignature( - pSig *typesDKG.PartialSignature) (err error) { - pSig.ProposerID = s.proposerID - pSig.Signature, err = s.prvKey.Sign(hashDKGPartialSignature(pSig)) - return -} - -// SignDKGMPKReady signs a DKG ready message. -func (s *Signer) SignDKGMPKReady(ready *typesDKG.MPKReady) (err error) { - ready.ProposerID = s.proposerID - ready.Signature, err = s.prvKey.Sign(hashDKGMPKReady(ready)) - return -} - -// SignDKGFinalize signs a DKG finalize message. -func (s *Signer) SignDKGFinalize(final *typesDKG.Finalize) (err error) { - final.ProposerID = s.proposerID - final.Signature, err = s.prvKey.Sign(hashDKGFinalize(final)) - return -} - -// SignDKGSuccess signs a DKG success message. -func (s *Signer) SignDKGSuccess(success *typesDKG.Success) (err error) { - success.ProposerID = s.proposerID - success.Signature, err = s.prvKey.Sign(hashDKGSuccess(success)) - return -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/utils.go deleted file mode 100644 index f259f34bb..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/utils.go +++ /dev/null @@ -1,207 +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 utils - -import ( - "context" - "fmt" - - "github.com/dexon-foundation/dexon-consensus/common" - "github.com/dexon-foundation/dexon-consensus/core/types" - typesDKG "github.com/dexon-foundation/dexon-consensus/core/types/dkg" -) - -var dkgDelayRound uint64 - -// SetDKGDelayRound sets the variable. -func SetDKGDelayRound(delay uint64) { - dkgDelayRound = delay -} - -type configAccessor interface { - Configuration(round uint64) *types.Config -} - -// GetConfigWithPanic is a helper to access configs, and panic when config for -// that round is not ready yet. -func GetConfigWithPanic(accessor configAccessor, round uint64, - logger common.Logger) *types.Config { - if logger != nil { - logger.Debug("Calling Governance.Configuration", "round", round) - } - c := accessor.Configuration(round) - if c == nil { - panic(fmt.Errorf("configuration is not ready %v", round)) - } - return c -} - -type crsAccessor interface { - CRS(round uint64) common.Hash -} - -// GetCRSWithPanic is a helper to access CRS, and panic when CRS for that -// round is not ready yet. -func GetCRSWithPanic(accessor crsAccessor, round uint64, - logger common.Logger) common.Hash { - if logger != nil { - logger.Debug("Calling Governance.CRS", "round", round) - } - crs := accessor.CRS(round) - if (crs == common.Hash{}) { - panic(fmt.Errorf("CRS is not ready %v", round)) - } - return crs -} - -// VerifyDKGComplaint verifies if its a valid DKGCompliant. -func VerifyDKGComplaint( - complaint *typesDKG.Complaint, mpk *typesDKG.MasterPublicKey) (bool, error) { - ok, err := VerifyDKGComplaintSignature(complaint) - if err != nil { - return false, err - } - if !ok { - return false, nil - } - if complaint.IsNack() { - return true, nil - } - if complaint.Round != mpk.Round { - return false, nil - } - ok, err = VerifyDKGMasterPublicKeySignature(mpk) - if err != nil { - return false, err - } - if !ok { - return false, nil - } - ok, err = mpk.PublicKeyShares.VerifyPrvShare( - typesDKG.NewID(complaint.PrivateShare.ReceiverID), - &complaint.PrivateShare.PrivateShare) - if err != nil { - return false, err - } - return !ok, nil -} - -// LaunchDummyReceiver launches a go routine to receive from the receive -// channel of a network module. An context is required to stop the go routine -// automatically. An optinal message handler could be provided. -func LaunchDummyReceiver( - ctx context.Context, recv <-chan types.Msg, handler func(types.Msg)) ( - context.CancelFunc, <-chan struct{}) { - var ( - dummyCtx, dummyCancel = context.WithCancel(ctx) - finishedChan = make(chan struct{}, 1) - ) - go func() { - defer func() { - finishedChan <- struct{}{} - }() - loop: - for { - select { - case <-dummyCtx.Done(): - break loop - case v, ok := <-recv: - if !ok { - panic(fmt.Errorf( - "receive channel is closed before dummy receiver")) - } - if handler != nil { - handler(v) - } - } - } - }() - return dummyCancel, finishedChan -} - -// GetDKGThreshold return expected threshold for given DKG set size. -func GetDKGThreshold(config *types.Config) int { - return int(config.NotarySetSize*2/3) + 1 -} - -// GetDKGValidThreshold return threshold for DKG set to considered valid. -func GetDKGValidThreshold(config *types.Config) int { - return int(config.NotarySetSize * 5 / 6) -} - -// GetBAThreshold return threshold for BA votes. -func GetBAThreshold(config *types.Config) int { - return int(config.NotarySetSize*2/3 + 1) -} - -// GetNextRoundValidationHeight returns the block height to check if the next -// round is ready. -func GetNextRoundValidationHeight(begin, length uint64) uint64 { - return begin + length*9/10 -} - -// GetRoundHeight wraps the workaround for the round height logic in fullnode. -func GetRoundHeight(accessor interface{}, round uint64) uint64 { - type roundHeightAccessor interface { - GetRoundHeight(round uint64) uint64 - } - accessorInst := accessor.(roundHeightAccessor) - height := accessorInst.GetRoundHeight(round) - if round == 0 && height < types.GenesisHeight { - return types.GenesisHeight - } - return height -} - -// IsDKGValid check if DKG is correctly prepared. -func IsDKGValid( - gov governanceAccessor, logger common.Logger, round, reset uint64) ( - valid bool, gpkInvalid bool) { - if !gov.IsDKGFinal(round) { - logger.Debug("DKG is not final", "round", round, "reset", reset) - return - } - if !gov.IsDKGSuccess(round) { - logger.Debug("DKG is not successful", "round", round, "reset", reset) - return - } - cfg := GetConfigWithPanic(gov, round, logger) - gpk, err := typesDKG.NewGroupPublicKey( - round, - gov.DKGMasterPublicKeys(round), - gov.DKGComplaints(round), - GetDKGThreshold(cfg)) - if err != nil { - logger.Debug("Group public key setup failed", - "round", round, - "reset", reset, - "error", err) - gpkInvalid = true - return - } - if len(gpk.QualifyNodeIDs) < GetDKGValidThreshold(cfg) { - logger.Debug("Group public key threshold not reach", - "round", round, - "reset", reset, - "qualified", len(gpk.QualifyNodeIDs)) - gpkInvalid = true - return - } - valid = true - return -} diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/vote-filter.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/vote-filter.go deleted file mode 100644 index 446d88a64..000000000 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/vote-filter.go +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2019 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 utils - -import ( - "github.com/dexon-foundation/dexon-consensus/core/types" -) - -// VoteFilter filters votes that are useless for now. -// To maximize performance, this structure is not thread-safe and will never be. -type VoteFilter struct { - Voted map[types.VoteHeader]struct{} - Position types.Position - LockIter uint64 - Period uint64 - Confirm bool -} - -// NewVoteFilter creates a new vote filter instance. -func NewVoteFilter() *VoteFilter { - return &VoteFilter{ - Voted: make(map[types.VoteHeader]struct{}), - } -} - -// Filter checks if the vote should be filtered out. -func (vf *VoteFilter) Filter(vote *types.Vote) bool { - if vote.Type == types.VoteInit { - return true - } - if vote.Position.Older(vf.Position) { - return true - } else if vote.Position.Newer(vf.Position) { - // It's impossible to check the vote of other height. - return false - } - if vf.Confirm { - return true - } - if vote.Type == types.VotePreCom && vote.Period < vf.LockIter { - return true - } - if vote.Type == types.VoteCom && - vote.Period < vf.Period && - vote.BlockHash == types.SkipBlockHash { - return true - } - if _, exist := vf.Voted[vote.VoteHeader]; exist { - return true - } - return false -} - -// AddVote to the filter so the same vote will be filtered. -func (vf *VoteFilter) AddVote(vote *types.Vote) { - vf.Voted[vote.VoteHeader] = struct{}{} -} |