diff options
Diffstat (limited to 'vendor/github.com/dexon-foundation/dexon-consensus')
15 files changed, 197 insertions, 285 deletions
diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/common/utils.go b/vendor/github.com/dexon-foundation/dexon-consensus/common/utils.go index e46b3e9c9..0e847900f 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/common/utils.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/common/utils.go @@ -29,3 +29,13 @@ func GenerateRandomBytes() []byte { } return randomness } + +// CopyBytes copies byte slice. +func CopyBytes(src []byte) (dst []byte) { + if len(src) == 0 { + return + } + dst = make([]byte, len(src)) + copy(dst, src) + return +} 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 index 7006242b1..423174c48 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement-mgr.go @@ -116,8 +116,7 @@ type agreementMgr struct { lock sync.RWMutex } -func newAgreementMgr(con *Consensus, - initConfig agreementMgrConfig) (mgr *agreementMgr, err error) { +func newAgreementMgr(con *Consensus) (mgr *agreementMgr, err error) { mgr = &agreementMgr{ con: con, ID: con.ID, @@ -130,7 +129,6 @@ func newAgreementMgr(con *Consensus, bcModule: con.bcModule, ctx: con.ctx, processedBAResult: make(map[types.Position]struct{}, maxResultCache), - configs: []agreementMgrConfig{initConfig}, voteFilter: utils.NewVoteFilter(), } mgr.recv = &consensusBAReceiver{ @@ -199,11 +197,6 @@ func (mgr *agreementMgr) notifyRoundEvents(evts []utils.RoundEventParam) error { if len(mgr.configs) > 0 { lastCfg := mgr.configs[len(mgr.configs)-1] if e.BeginHeight != lastCfg.RoundEndHeight() { - // the init config of BA part is provided when constructing. - if len(mgr.configs) == 1 && - e.BeginHeight == lastCfg.LastPeriodBeginHeight() { - return nil - } return ErrInvalidBlockHeight } if lastCfg.RoundID() == e.Round { diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement.go index 6727ecbee..f2a9e3def 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/agreement.go @@ -419,8 +419,8 @@ func (a *agreement) processVote(vote *types.Vote) error { aID := a.agreementID() // Agreement module has stopped. if isStop(aID) { - // Hacky way to not drop first votes for height 0. - if vote.Position.Height == uint64(0) { + // Hacky way to not drop first votes for genesis height. + if vote.Position.Height == types.GenesisHeight { a.pendingVote = append(a.pendingVote, pendingVote{ vote: vote, receivedTime: time.Now().UTC(), diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go index 51747d83b..2d67d626f 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/blockchain.go @@ -18,6 +18,7 @@ package core import ( + "bytes" "errors" "fmt" "sort" @@ -38,6 +39,7 @@ var ( 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") @@ -182,12 +184,13 @@ func (bc *blockChain) notifyRoundEvents(evts []utils.RoundEventParam) error { c.SetRoundBeginHeight(e.BeginHeight) if bc.lastConfirmed == nil { if c.RoundID() != 0 { - panic(fmt.Errorf("genesis config should from round 0 %d", + 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 %s %d", + panic(fmt.Errorf("incompatible config/block round %s %d", bc.lastConfirmed, c.RoundID())) } if !c.Contains(bc.lastConfirmed.Position.Height) { @@ -224,15 +227,11 @@ func (bc *blockChain) extractBlocks() (ret []*types.Block) { for len(bc.confirmedBlocks) > 0 { c := bc.confirmedBlocks[0] if c.Position.Round >= DKGDelayRound && - len(c.Finalization.Randomness) == 0 && + len(c.Randomness) == 0 && !bc.setRandomnessFromPending(c) { break } c, bc.confirmedBlocks = bc.confirmedBlocks[0], bc.confirmedBlocks[1:] - // TODO(mission): remove these duplicated field if we fully converted - // to single chain. - c.Finalization.ParentHash = c.ParentHash - c.Finalization.Timestamp = c.Timestamp ret = append(ret, c) bc.lastDelivered = c } @@ -240,9 +239,6 @@ func (bc *blockChain) extractBlocks() (ret []*types.Block) { } func (bc *blockChain) sanityCheck(b *types.Block) error { - if b.IsEmpty() { - panic(fmt.Errorf("pass empty block to sanity check: %s", b)) - } bc.lock.RLock() defer bc.lock.RUnlock() if bc.lastConfirmed == nil { @@ -250,7 +246,9 @@ func (bc *blockChain) sanityCheck(b *types.Block) error { if !b.IsGenesis() { return ErrNotGenesisBlock } - // TODO(mission): Do we have to check timestamp of genesis block? + if b.Timestamp.Before(bc.dMoment.Add(bc.configs[0].minBlockInterval)) { + return ErrInvalidTimestamp + } return nil } if b.IsGenesis() { @@ -275,6 +273,10 @@ func (bc *blockChain) sanityCheck(b *types.Block) error { 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 } @@ -293,7 +295,6 @@ func (bc *blockChain) addEmptyBlock(position types.Position) ( // to be confirmed. panic(err) } - emptyB.Finalization.Height = emptyB.Position.Height + 1 bc.confirmBlock(emptyB) bc.checkIfBlocksConfirmed() return emptyB @@ -308,8 +309,10 @@ func (bc *blockChain) addEmptyBlock(position types.Position) ( if bc.lastConfirmed.Position.Height+1 == position.Height { return add(), nil } - } else if position.Height == 0 && position.Round == 0 { + } else if position.Height == types.GenesisHeight && position.Round == 0 { return add(), nil + } else { + return nil, ErrInvalidBlockHeight } return nil, bc.addPendingBlockRecord(pendingBlockRecord{position, nil}) } @@ -318,7 +321,7 @@ func (bc *blockChain) addEmptyBlock(position types.Position) ( // sanity check against this block, it's ok to add block with skipping height. func (bc *blockChain) addBlock(b *types.Block) error { if b.Position.Round >= DKGDelayRound && - len(b.Finalization.Randomness) == 0 && + len(b.Randomness) == 0 && !bc.setRandomnessFromPending(b) { return ErrMissingRandomness } @@ -346,8 +349,6 @@ func (bc *blockChain) addBlock(b *types.Block) error { return nil } -// TODO(mission): remove this method after removing the strong binding between -// BA and blockchain. func (bc *blockChain) tipRound() uint64 { bc.lock.RLock() defer bc.lock.RUnlock() @@ -361,8 +362,6 @@ func (bc *blockChain) tipRound() uint64 { return bc.lastConfirmed.Position.Round + offset } -// TODO(mission): the pulling should be done inside of blockchain, then we don't -// have to expose this method. func (bc *blockChain) confirmed(h uint64) bool { bc.lock.RLock() defer bc.lock.RUnlock() @@ -376,8 +375,6 @@ func (bc *blockChain) confirmed(h uint64) bool { return r.block != nil } -// TODO(mission): this method can be removed after refining the relation between -// BA and block storage. func (bc *blockChain) nextBlock() (uint64, time.Time) { bc.lock.RLock() defer bc.lock.RUnlock() @@ -385,7 +382,7 @@ func (bc *blockChain) nextBlock() (uint64, time.Time) { // lastConfirmed block in the scenario of "nextBlock" method. tip, config := bc.lastConfirmed, bc.configs[0] if tip == nil { - return 0, bc.dMoment + return types.GenesisHeight, bc.dMoment } return tip.Position.Height + 1, tip.Timestamp.Add(config.minBlockInterval) } @@ -396,7 +393,7 @@ func (bc *blockChain) pendingBlocksWithoutRandomness() []*types.Block { blocks := make([]*types.Block, 0) for _, b := range bc.confirmedBlocks { if b.Position.Round < DKGDelayRound || - len(b.Finalization.Randomness) > 0 || + len(b.Randomness) > 0 || bc.setRandomnessFromPending(b) { continue } @@ -407,7 +404,7 @@ func (bc *blockChain) pendingBlocksWithoutRandomness() []*types.Block { continue } if r.block != nil && - len(r.block.Finalization.Randomness) == 0 && + len(r.block.Randomness) == 0 && !bc.setRandomnessFromPending(r.block) { blocks = append(blocks, r.block) } @@ -452,8 +449,8 @@ func (bc *blockChain) findPendingBlock(p types.Position) *types.Block { func (bc *blockChain) addPendingBlockRecord(p pendingBlockRecord) error { if err := bc.pendingBlocks.insert(p); err != nil { if err == ErrDuplicatedPendingBlock { - // TODO(mission): stop ignoreing this error once our BA can confirm - // blocks uniquely and sequentially. + // We need to ignore this error because BA might confirm duplicated + // blocks in position. err = nil } return err @@ -501,7 +498,7 @@ func (bc *blockChain) purgeConfig() { func (bc *blockChain) verifyRandomness( blockHash common.Hash, round uint64, randomness []byte) (bool, error) { if round < DKGDelayRound { - return len(randomness) == 0, nil + return bytes.Compare(randomness, NoRand) == 0, nil } v, ok, err := bc.vGetter.UpdateAndGet(round) if err != nil { @@ -517,17 +514,23 @@ func (bc *blockChain) verifyRandomness( func (bc *blockChain) prepareBlock(position types.Position, proposeTime time.Time, empty bool) (b *types.Block, err error) { - // TODO(mission): refine timestamp. 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 { - // The case for genesis block. - if !position.Equal(types.Position{}) { + 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 - } else if empty { - b.Timestamp = bc.dMoment + } + 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 { @@ -539,6 +542,9 @@ func (bc *blockChain) prepareBlock(position types.Position, b = nil return } + if proposeTime.Before(minExpectedTime) { + b.Timestamp = minExpectedTime + } } } else { tipConfig := bc.tipConfig() @@ -548,11 +554,8 @@ func (bc *blockChain) prepareBlock(position types.Position, } if tipConfig.IsLastBlock(tip) { if tip.Position.Round+1 != position.Round { - if !empty { - b, err = nil, ErrRoundNotSwitch - return - } - b.Position.Round = tip.Position.Round + 1 + b, err = nil, ErrRoundNotSwitch + return } } else { if tip.Position.Round != position.Round { @@ -560,6 +563,7 @@ func (bc *blockChain) prepareBlock(position types.Position, return } } + minExpectedTime := tip.Timestamp.Add(bc.configs[0].minBlockInterval) b.ParentHash = tip.Hash if !empty { bc.logger.Debug("Calling Application.PreparePayload", @@ -575,14 +579,14 @@ func (bc *blockChain) prepareBlock(position types.Position, b = nil return } - if !b.Timestamp.After(tip.Timestamp) { - b.Timestamp = tip.Timestamp.Add(tipConfig.minBlockInterval) + 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 = tip.Timestamp.Add(tipConfig.minBlockInterval) + b.Timestamp = minExpectedTime } } if empty { @@ -628,7 +632,7 @@ func (bc *blockChain) setRandomnessFromPending(b *types.Block) bool { if !r.BlockHash.Equal(b.Hash) { panic(fmt.Errorf("mismathed randomness: %s %s", b, r)) } - b.Finalization.Randomness = r.Randomness + b.Randomness = r.Randomness delete(bc.pendingRandomnesses, b.Position) return true } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go index 6e3072371..57b30383c 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/consensus.go @@ -60,7 +60,6 @@ var ( // consensusBAReceiver implements agreementReceiver. type consensusBAReceiver struct { - // TODO(mission): consensus would be replaced by blockChain and network. consensus *Consensus agreementModule *agreement changeNotaryHeightValue *atomic.Value @@ -262,10 +261,7 @@ func (recv *consensusBAReceiver) ConfirmBlock( } } - // It's a workaround, the height for application is one-based. - block.Finalization.Height = block.Position.Height + 1 - - if len(votes) == 0 && len(block.Finalization.Randomness) == 0 { + if len(votes) == 0 && len(block.Randomness) == 0 { recv.consensus.logger.Error("No votes to recover randomness", "block", block) } else if votes != nil { @@ -293,18 +289,19 @@ func (recv *consensusBAReceiver) ConfirmBlock( "block", block, "error", err) } else { - block.Finalization.Randomness = rand.Signature[:] + block.Randomness = rand.Signature[:] } + } else { + block.Randomness = NoRand } if recv.isNotary { result := &types.AgreementResult{ - BlockHash: block.Hash, - Position: block.Position, - Votes: voteList, - FinalizationHeight: block.Finalization.Height, - IsEmptyBlock: isEmptyBlockConfirmed, - Randomness: block.Finalization.Randomness, + BlockHash: block.Hash, + Position: block.Position, + Votes: voteList, + IsEmptyBlock: isEmptyBlockConfirmed, + Randomness: block.Randomness, } recv.consensus.logger.Debug("Broadcast AgreementResult", "result", result) @@ -327,7 +324,7 @@ func (recv *consensusBAReceiver) ConfirmBlock( } } - if block.Position.Height != 0 && + if !block.IsGenesis() && !recv.consensus.bcModule.confirmed(block.Position.Height-1) { go func(hash common.Hash) { parentHash := hash @@ -362,16 +359,15 @@ func (recv *consensusBAReceiver) ConfirmBlock( recv.consensus.logger.Info("Receive parent block", "parent-hash", block.ParentHash.String()[:6], "cur-position", block.Position) - if block.Finalization.Height == 0 { + 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.Position.Height == 0 || - recv.consensus.bcModule.confirmed( - block.Position.Height-1) { + if block.IsGenesis() || recv.consensus.bcModule.confirmed( + block.Position.Height-1) { return } } @@ -646,9 +642,11 @@ func NewConsensusFromSyncer( refBlock = b } if startWithEmpty { - pos := initBlock.Position - pos.Height++ - _, err := con.bcModule.addEmptyBlock(pos) + emptyPos := types.Position{ + Round: con.bcModule.tipRound(), + Height: initBlock.Position.Height + 1, + } + _, err := con.bcModule.addEmptyBlock(emptyPos) if err != nil { panic(err) } @@ -657,7 +655,6 @@ func NewConsensusFromSyncer( } // newConsensusForRound creates a Consensus instance. -// TODO(mission): remove dMoment, it's no longer one part of consensus. func newConsensusForRound( initBlock *types.Block, dMoment time.Time, @@ -678,14 +675,13 @@ func newConsensusForRound( debugApp = a } // Get configuration for bootstrap round. - initRound := uint64(0) - initBlockHeight := uint64(0) + initPos := types.Position{ + Round: 0, + Height: types.GenesisHeight, + } if initBlock != nil { - initRound = initBlock.Position.Round - initBlockHeight = initBlock.Position.Height + initPos = initBlock.Position } - initConfig := utils.GetConfigWithPanic(gov, initRound, logger) - initCRS := utils.GetCRSWithPanic(gov, initRound, logger) // Init configuration chain. ID := types.NewNodeID(prv.PublicKey()) recv := &consensusDKGReceiver{ @@ -729,21 +725,12 @@ func newConsensusForRound( } con.ctx, con.ctxCancel = context.WithCancel(context.Background()) var err error - con.roundEvent, err = utils.NewRoundEvent(con.ctx, gov, logger, initRound, - initBlockHeight, ConfigRoundShift) + con.roundEvent, err = utils.NewRoundEvent(con.ctx, gov, logger, initPos, + ConfigRoundShift) if err != nil { panic(err) } - baConfig := agreementMgrConfig{} - baConfig.from(initRound, initConfig, initCRS) - // TODO(jimmy): remove -1 after we match the height with fullnode. - roundHeight := gov.GetRoundHeight(initRound) - if initRound > 0 { - roundHeight-- - } - baConfig.SetRoundBeginHeight(roundHeight) - con.baMgr, err = newAgreementMgr(con, baConfig) - if err != nil { + if con.baMgr, err = newAgreementMgr(con); err != nil { panic(err) } if err = con.prepare(initBlock); err != nil { @@ -907,9 +894,6 @@ func (con *Consensus) prepare(initBlock *types.Block) (err error) { con.roundEvent.Register(func(evts []utils.RoundEventParam) { e := evts[len(evts)-1] defer elapse("touch-NodeSetCache", e)() - if e.Reset != 0 { - return - } con.event.RegisterHeight(e.NextTouchNodeSetCacheHeight(), func(uint64) { if err := con.nodeSetCache.Touch(e.Round + 1); err != nil { con.logger.Warn("Failed to update nodeSetCache", @@ -997,7 +981,7 @@ func (con *Consensus) prepare(initBlock *types.Block) (err error) { }) con.roundEvent.TriggerInitEvent() if initBlock != nil { - con.event.NotifyHeight(initBlock.Finalization.Height) + con.event.NotifyHeight(initBlock.Position.Height) } con.baMgr.prepare() return @@ -1265,7 +1249,7 @@ MessageLoop: } } else { ok, err := con.bcModule.verifyRandomness( - val.Hash, val.Position.Round, val.Finalization.Randomness) + val.Hash, val.Position.Round, val.Randomness) if err != nil { con.logger.Error("error verifying confirmed block randomness", "block", val, @@ -1395,7 +1379,7 @@ func (con *Consensus) processFinalizedBlock(b *types.Block) (err error) { } if !verifier.VerifySignature(b.Hash, crypto.Signature{ Type: "bls", - Signature: b.Finalization.Randomness, + Signature: b.Randomness, }) { err = ErrIncorrectBlockRandomness return @@ -1441,16 +1425,15 @@ func (con *Consensus) deliverBlock(b *types.Block) { case con.resetDeliveryGuardTicker <- struct{}{}: default: } - // TODO(mission): do we need to put block when confirmed now? if err := con.db.PutBlock(*b); err != nil { panic(err) } - if err := con.db.PutCompactionChainTipInfo( - b.Hash, b.Finalization.Height); err != nil { + 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, b.Finalization.Clone()) + con.app.BlockDelivered(b.Hash, b.Position, common.CopyBytes(b.Randomness)) if con.debugApp != nil { con.debugApp.BlockReady(b.Hash) } @@ -1471,7 +1454,7 @@ func (con *Consensus) deliverFinalizedBlocksWithoutLock() (err error) { "pending", con.bcModule.lastPendingBlock()) for _, b := range deliveredBlocks { con.deliverBlock(b) - con.event.NotifyHeight(b.Finalization.Height) + con.event.NotifyHeight(b.Position.Height) } return } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/constant.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/constant.go index f80e1b9d8..29dae8b73 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/constant.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/constant.go @@ -32,6 +32,10 @@ const ConfigRoundShift uint64 = 2 // 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/db/level-db.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/db/level-db.go index 88f5801fc..52968331e 100644 --- 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 @@ -362,7 +362,6 @@ func (lvl *LevelDBBackedDB) Close() error { func (lvl *LevelDBBackedDB) HasBlock(hash common.Hash) bool { exists, err := lvl.internalHasBlock(lvl.getBlockKey(hash)) if err != nil { - // TODO(missionliao): Modify the interface to return error. panic(err) } return exists @@ -429,7 +428,6 @@ func (lvl *LevelDBBackedDB) PutBlock(block types.Block) (err error) { // GetAllBlocks implements Reader.GetAllBlocks method, which allows callers // to retrieve all blocks in DB. func (lvl *LevelDBBackedDB) GetAllBlocks() (BlockIterator, error) { - // TODO (mission): Implement this part via goleveldb's iterator. return nil, ErrNotImplemented } diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go index 407eaeace..f76ee1975 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/interfaces.go @@ -42,8 +42,7 @@ type Application interface { BlockConfirmed(block types.Block) // BlockDelivered is called when a block is added to the compaction chain. - BlockDelivered(blockHash common.Hash, - blockPosition types.Position, result types.FinalizationResult) + BlockDelivered(hash common.Hash, position types.Position, rand []byte) } // Debug describes the application interface that requires diff --git a/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go index 095170bf0..10b47b822 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/nonblocking.go @@ -32,7 +32,7 @@ type blockConfirmedEvent struct { type blockDeliveredEvent struct { blockHash common.Hash blockPosition types.Position - result *types.FinalizationResult + rand []byte } // nonBlocking implements these interfaces and is a decorator for @@ -87,7 +87,7 @@ func (nb *nonBlocking) run() { case blockConfirmedEvent: nb.app.BlockConfirmed(*e.block) case blockDeliveredEvent: - nb.app.BlockDelivered(e.blockHash, e.blockPosition, *e.result) + nb.app.BlockDelivered(e.blockHash, e.blockPosition, e.rand) default: fmt.Printf("Unknown event %v.", e) } @@ -128,10 +128,10 @@ func (nb *nonBlocking) BlockConfirmed(block types.Block) { // BlockDelivered is called when a block is add to the compaction chain. func (nb *nonBlocking) BlockDelivered(blockHash common.Hash, - blockPosition types.Position, result types.FinalizationResult) { + blockPosition types.Position, rand []byte) { nb.addEvent(blockDeliveredEvent{ blockHash: blockHash, blockPosition: blockPosition, - result: &result, + 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 index 13da027bd..d39c24627 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/agreement.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/agreement.go @@ -18,6 +18,7 @@ package syncer import ( + "bytes" "context" "fmt" "time" @@ -87,7 +88,7 @@ func (a *agreement) run() { } switch v := val.(type) { case *types.Block: - if v.IsFinalized() { + if v.Position.Round >= core.DKGDelayRound && v.IsFinalized() { a.processFinalizedBlock(v) } else { a.processBlock(v) @@ -106,9 +107,8 @@ func (a *agreement) processBlock(b *types.Block) { return } if rand, exist := a.agreementResults[b.Hash]; exist { - if b.Position.Round >= core.DKGDelayRound && - len(b.Finalization.Randomness) == 0 { - b.Finalization.Randomness = rand + if len(b.Randomness) == 0 { + b.Randomness = rand } a.confirm(b) } else { @@ -120,9 +120,6 @@ func (a *agreement) processBlock(b *types.Block) { } func (a *agreement) processFinalizedBlock(block *types.Block) { - if block.Position.Round < core.DKGDelayRound { - return - } // 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) @@ -141,7 +138,8 @@ func (a *agreement) processFinalizedBlock(block *types.Block) { if err := utils.VerifyBlockSignature(block); err != nil { return } - verifier, ok, err := a.tsigVerifierCache.UpdateAndGet(block.Position.Round) + verifier, ok, err := a.tsigVerifierCache.UpdateAndGet( + block.Position.Round) if err != nil { a.logger.Error("error verifying block randomness", "block", block, @@ -154,7 +152,7 @@ func (a *agreement) processFinalizedBlock(block *types.Block) { } if !verifier.VerifySignature(block.Hash, crypto.Signature{ Type: "bls", - Signature: block.Finalization.Randomness, + Signature: block.Randomness, }) { a.logger.Error("incorrect block randomness", "block", block) return @@ -203,13 +201,17 @@ func (a *agreement) processAgreementResult(r *types.AgreementResult) { 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, - Finalization: types.FinalizationResult{ - Randomness: r.Randomness, - }, + Position: r.Position, + Randomness: r.Randomness, } // Empty blocks should be confirmed directly, they won't be sent over // the wire. @@ -218,7 +220,7 @@ func (a *agreement) processAgreementResult(r *types.AgreementResult) { } if bs, exist := a.blocks[r.Position]; exist { if b, exist := bs[r.BlockHash]; exist { - b.Finalization.Randomness = r.Randomness + b.Randomness = r.Randomness a.confirm(b) return } @@ -271,11 +273,9 @@ func (a *agreement) processNewCRS(round uint64) { // confirm notifies consensus the confirmation of a block in BA. func (a *agreement) confirm(b *types.Block) { - if b.Position.Round >= core.DKGDelayRound && - len(b.Finalization.Randomness) == 0 { + if !b.IsFinalized() { panic(fmt.Errorf("confirm a block %s without randomness", b)) } - b.Finalization.Height = b.Position.Height + 1 if _, exist := a.confirmedBlocks[b.Hash]; !exist { delete(a.blocks, b.Position) delete(a.agreementResults, b.Hash) 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 index b692b56ef..f777e35bb 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/consensus.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/syncer/consensus.go @@ -42,13 +42,9 @@ var ( // ErrInvalidBlockOrder is reported when SyncBlocks receives unordered // blocks. ErrInvalidBlockOrder = fmt.Errorf("invalid block order") - // ErrMismatchBlockHashSequence means the delivering sequence is not - // correct, compared to finalized blocks. - ErrMismatchBlockHashSequence = fmt.Errorf("mismatch block hash sequence") - // ErrInvalidSyncingFinalizationHeight raised when the blocks to sync is - // not following the compaction chain tip in database. - ErrInvalidSyncingFinalizationHeight = fmt.Errorf( - "invalid syncing finalization height") + // 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. @@ -150,13 +146,12 @@ func (con *Consensus) assureBuffering() { ) if height == 0 { con.roundEvt, err = utils.NewRoundEvent(con.ctx, con.gov, con.logger, - 0, 0, core.ConfigRoundShift) + 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.Round, b.Finalization.Height, - core.ConfigRoundShift) + con.logger, b.Position, core.ConfigRoundShift) } } if err != nil { @@ -297,7 +292,7 @@ func (con *Consensus) SyncBlocks( } // Check if blocks are consecutive. for i := 1; i < len(blocks); i++ { - if blocks[i].Finalization.Height != blocks[i-1].Finalization.Height+1 { + if blocks[i].Position.Height != blocks[i-1].Position.Height+1 { err = ErrInvalidBlockOrder return } @@ -305,17 +300,16 @@ func (con *Consensus) SyncBlocks( // Make sure the first block is the next block of current compaction chain // tip in DB. _, tipHeight := con.db.GetCompactionChainTipInfo() - if blocks[0].Finalization.Height != tipHeight+1 { - con.logger.Error("Mismatched finalization height", - "now", blocks[0].Finalization.Height, + if blocks[0].Position.Height != tipHeight+1 { + con.logger.Error("Mismatched block height", + "now", blocks[0].Position.Height, "expected", tipHeight+1, ) - err = ErrInvalidSyncingFinalizationHeight + err = ErrInvalidSyncingHeight return } con.logger.Trace("SyncBlocks", "position", &blocks[0].Position, - "final height", blocks[0].Finalization.Height, "len", len(blocks), "latest", latest, ) @@ -331,10 +325,10 @@ func (con *Consensus) SyncBlocks( } } if err = con.db.PutCompactionChainTipInfo( - b.Hash, b.Finalization.Height); err != nil { + b.Hash, b.Position.Height); err != nil { return } - con.heightEvt.NotifyHeight(b.Finalization.Height) + con.heightEvt.NotifyHeight(b.Position.Height) } if latest { con.assureBuffering() 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 index b87e8a11d..1c7454398 100644 --- 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 @@ -26,12 +26,11 @@ import ( // AgreementResult describes an agremeent result. type AgreementResult struct { - BlockHash common.Hash `json:"block_hash"` - Position Position `json:"position"` - Votes []Vote `json:"votes"` - IsEmptyBlock bool `json:"is_empty_block"` - FinalizationHeight uint64 `json:"finalization_height"` - Randomness []byte `json:"randomness"` + 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 { 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 index 2b23e96e3..cff954652 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/types/block.go @@ -31,6 +31,9 @@ import ( "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 @@ -64,58 +67,6 @@ func (t *rlpTimestamp) DecodeRLP(s *rlp.Stream) error { return err } -// FinalizationResult represents the result of DEXON consensus algorithm. -type FinalizationResult struct { - ParentHash common.Hash `json:"parent_hash"` - Randomness []byte `json:"randomness"` - Timestamp time.Time `json:"timestamp"` - Height uint64 `json:"height"` -} - -// Clone returns a deep copy of FinalizationResult -func (f FinalizationResult) Clone() FinalizationResult { - frcopy := FinalizationResult{ - ParentHash: f.ParentHash, - Timestamp: f.Timestamp, - Height: f.Height, - } - frcopy.Randomness = make([]byte, len(f.Randomness)) - copy(frcopy.Randomness, f.Randomness) - return frcopy -} - -type rlpFinalizationResult struct { - ParentHash common.Hash - Randomness []byte - Timestamp *rlpTimestamp - Height uint64 -} - -// EncodeRLP implements rlp.Encoder -func (f *FinalizationResult) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, &rlpFinalizationResult{ - ParentHash: f.ParentHash, - Randomness: f.Randomness, - Timestamp: &rlpTimestamp{f.Timestamp}, - Height: f.Height, - }) -} - -// DecodeRLP implements rlp.Decoder -func (f *FinalizationResult) DecodeRLP(s *rlp.Stream) error { - var dec rlpFinalizationResult - err := s.Decode(&dec) - if err == nil { - *f = FinalizationResult{ - ParentHash: dec.ParentHash, - Randomness: dec.Randomness, - Timestamp: dec.Timestamp.Time, - Height: dec.Height, - } - } - return err -} - // Witness represents the consensus information on the compaction chain. type Witness struct { Height uint64 `json:"height"` @@ -124,31 +75,31 @@ type Witness struct { // 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"` - Finalization FinalizationResult `json:"finalization"` - Signature crypto.Signature `json:"signature"` + 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:"finalization"` + 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 - Finalization *FinalizationResult - Signature crypto.Signature + 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 } @@ -164,7 +115,7 @@ func (b *Block) EncodeRLP(w io.Writer) error { Payload: b.Payload, PayloadHash: b.PayloadHash, Witness: &b.Witness, - Finalization: &b.Finalization, + Randomness: b.Randomness, Signature: b.Signature, CRSSignature: b.CRSSignature, }) @@ -184,7 +135,7 @@ func (b *Block) DecodeRLP(s *rlp.Stream) error { Payload: dec.Payload, PayloadHash: dec.PayloadHash, Witness: *dec.Witness, - Finalization: *dec.Finalization, + Randomness: dec.Randomness, Signature: dec.Signature, CRSSignature: dec.CRSSignature, } @@ -206,25 +157,23 @@ func (b *Block) Clone() (bcopy *Block) { bcopy.Position.Height = b.Position.Height bcopy.Signature = b.Signature.Clone() bcopy.CRSSignature = b.CRSSignature.Clone() - bcopy.Finalization = b.Finalization.Clone() bcopy.Witness.Height = b.Witness.Height - bcopy.Witness.Data = make([]byte, len(b.Witness.Data)) - copy(bcopy.Witness.Data, b.Witness.Data) + bcopy.Witness.Data = common.CopyBytes(b.Witness.Data) bcopy.Timestamp = b.Timestamp - bcopy.Payload = make([]byte, len(b.Payload)) - copy(bcopy.Payload, b.Payload) + 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 == 0 && b.ParentHash == common.Hash{} + return b.Position.Height == GenesisHeight && b.ParentHash == common.Hash{} } -// IsFinalized checks if the finalization data is ready. +// IsFinalized checks if the block is finalized. func (b *Block) IsFinalized() bool { - return b.Finalization.Height != 0 + return len(b.Randomness) > 0 } // IsEmpty checks if the block is an 'empty block'. @@ -276,34 +225,3 @@ func (bs *BlocksByPosition) Pop() (ret interface{}) { *bs, ret = (*bs)[0:n-1], (*bs)[n-1] return } - -// BlocksByFinalizationHeight is the helper type for sorting slice of blocks by -// finalization height. -type BlocksByFinalizationHeight []*Block - -// Len implements Len method in sort.Sort interface. -func (bs BlocksByFinalizationHeight) Len() int { - return len(bs) -} - -// Less implements Less method in sort.Sort interface. -func (bs BlocksByFinalizationHeight) Less(i int, j int) bool { - return bs[i].Finalization.Height < bs[j].Finalization.Height -} - -// Swap implements Swap method in sort.Sort interface. -func (bs BlocksByFinalizationHeight) Swap(i int, j int) { - bs[i], bs[j] = bs[j], bs[i] -} - -// Push implements Push method in heap interface. -func (bs *BlocksByFinalizationHeight) Push(x interface{}) { - *bs = append(*bs, x.(*Block)) -} - -// Pop implements Pop method in heap interface. -func (bs *BlocksByFinalizationHeight) 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/utils/round-event.go b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/round-event.go index 0e70cf250..472c7247b 100644 --- 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 @@ -169,42 +169,39 @@ type RoundEvent struct { // NewRoundEvent creates an RoundEvent instance. func NewRoundEvent(parentCtx context.Context, gov governanceAccessor, - logger common.Logger, initRound uint64, - initBlockHeight uint64, - roundShift uint64) (*RoundEvent, error) { + 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). - initConfig := GetConfigWithPanic(gov, initRound, logger) + logger.Info("new RoundEvent", "position", initPos, "shift", roundShift) + initConfig := GetConfigWithPanic(gov, initPos.Round, logger) e := &RoundEvent{ gov: gov, logger: logger, - lastTriggeredRound: initRound, + lastTriggeredRound: initPos.Round, roundShift: roundShift, } e.ctx, e.ctxCancel = context.WithCancel(parentCtx) e.config = RoundBasedConfig{} - e.config.SetupRoundBasedFields(initRound, initConfig) - // TODO(jimmy): remove -1 after we match the height with fullnode. - roundHeight := gov.GetRoundHeight(initRound) - if initRound != 0 { - roundHeight-- - } - e.config.SetRoundBeginHeight(roundHeight) + 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. - resetCount := gov.DKGResetCount(initRound + 1) - remains := resetCount - for ; remains > 0 && !e.config.Contains(initBlockHeight); remains-- { - e.config.ExtendLength() - } - if !e.config.Contains(initBlockHeight) { - return nil, ErrUnmatchedBlockHeightWithConfig{ - round: initRound, - reset: resetCount, - blockHeight: initBlockHeight, + 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 } - e.lastTriggeredResetCount = resetCount - remains return e, nil } 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 index 9a4ae923b..e6739ce2b 100644 --- a/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/utils.go +++ b/vendor/github.com/dexon-foundation/dexon-consensus/core/utils/utils.go @@ -149,3 +149,16 @@ func GetDKGValidThreshold(config *types.Config) int { 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 +} |