diff --git a/consensus/XDPoS/engines/engine_v2/engine.go b/consensus/XDPoS/engines/engine_v2/engine.go index c947df1fcc..b1a7712f1b 100644 --- a/consensus/XDPoS/engines/engine_v2/engine.go +++ b/consensus/XDPoS/engines/engine_v2/engine.go @@ -35,7 +35,7 @@ type XDPoS_v2 struct { currentRound utils.Round highestVotedRound utils.Round highestQuorumCert *utils.QuorumCert - // LockQC in XDPoS Consensus 2.0, used in voting rule + // lockQuorumCert in XDPoS Consensus 2.0, used in voting rule lockQuorumCert *utils.QuorumCert highestTimeoutCert *utils.TimeoutCert highestCommitBlock *utils.BlockInfo @@ -79,6 +79,8 @@ func (x *XDPoS_v2) SetNewRoundFaker(newRound utils.Round, resetTimer bool) { // Utils for test to check currentRound value func (x *XDPoS_v2) GetCurrentRound() utils.Round { + x.lock.Lock() + defer x.lock.Unlock() return x.currentRound } @@ -307,22 +309,27 @@ func (x *XDPoS_v2) verifyTC(timeoutCert *utils.TimeoutCert) error { return nil } -// Update local QC variables including highestQC & lockQC, as well as update commit blockInfo before call -/* - 1. Update HighestQC and LockQC - 2. Update commit block info (TODO) - 3. Check QC round >= node's currentRound. If yes, call setNewRound -*/ -func (x *XDPoS_v2) processQC(quorumCert *utils.QuorumCert) error { +// Update local QC variables including highestQC & lockQuorumCert, as well as update commit blockInfo before call +func (x *XDPoS_v2) processQC(blockCahinReader consensus.ChainReader, quorumCert *utils.QuorumCert) error { + // 1. Update HighestQC if x.highestQuorumCert == nil || quorumCert.ProposedBlockInfo.Round > x.highestQuorumCert.ProposedBlockInfo.Round { - x.highestQuorumCert = quorumCert //TODO: do I need a clone? + x.highestQuorumCert = quorumCert } - //TODO: x.blockchain.getBlock(quorumCert.ProposedBlockInfo.Hash) then get the QC inside that block header - //TODO: update lockQC + // 2. Get QC from header and update lockQuorumCert + proposedBlockHeader := blockCahinReader.GetHeaderByHash(quorumCert.ProposedBlockInfo.Hash) + var decodedExtraField utils.ExtraFields_v2 + utils.DecodeBytesExtraFields(proposedBlockHeader.Extra, &decodedExtraField) + x.lockQuorumCert = &decodedExtraField.QuorumCert + + // 3. Update commit block info //TODO: find parent and grandparent and grandgrandparent block, check round number, if so, commit grandgrandparent + if quorumCert.ProposedBlockInfo.Round >= x.currentRound { - x.setNewRound(quorumCert.ProposedBlockInfo.Round + 1) + err := x.setNewRound(quorumCert.ProposedBlockInfo.Round + 1) + if err != nil { + return err + } } return nil } @@ -364,8 +371,8 @@ func (x *XDPoS_v2) verifyVotingRule(header *types.Header) error { Make sure this node has not voted for this round. We can have a variable highestVotedRound, and check currentRound > highestVotedRound. HotStuff Voting rule: header's round == local current round, AND (one of the following two:) - header's block extends LockQC's ProposedBlockInfo (we need a isExtending(block_a, block_b) function), OR - header's QC's ProposedBlockInfo.Round > LockQC's ProposedBlockInfo.Round + header's block extends lockQuorumCert's ProposedBlockInfo (we need a isExtending(block_a, block_b) function), OR + header's QC's ProposedBlockInfo.Round > lockQuorumCert's ProposedBlockInfo.Round */ return nil } diff --git a/eth/bfter/bft.go b/eth/bfter/bft.go index 54b0517cc5..faeaa48cbe 100644 --- a/eth/bfter/bft.go +++ b/eth/bfter/bft.go @@ -4,6 +4,7 @@ import ( "github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS/utils" + "github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/log" lru "github.com/hashicorp/golang-lru" ) @@ -18,10 +19,11 @@ type broadcastTimeoutFn func(*utils.Timeout) type broadcastSyncInfoFn func(*utils.SyncInfo) type Bfter struct { - broadcastCh chan interface{} - quit chan struct{} - consensus ConsensusFns - broadcast BroadcastFns + blockCahinReader *core.BlockChain + broadcastCh chan interface{} + quit chan struct{} + consensus ConsensusFns + broadcast BroadcastFns // Message Cache knownVotes *lru.ARCCache @@ -46,17 +48,18 @@ type BroadcastFns struct { SyncInfo broadcastSyncInfoFn } -func New(broadcasts BroadcastFns) *Bfter { +func New(broadcasts BroadcastFns, blockCahinReader *core.BlockChain) *Bfter { knownVotes, _ := lru.NewARC(messageLimit) knownSyncInfos, _ := lru.NewARC(messageLimit) knownTimeouts, _ := lru.NewARC(messageLimit) return &Bfter{ - quit: make(chan struct{}), - broadcastCh: make(chan interface{}), - broadcast: broadcasts, - knownVotes: knownVotes, - knownSyncInfos: knownSyncInfos, - knownTimeouts: knownTimeouts, + quit: make(chan struct{}), + broadcastCh: make(chan interface{}), + broadcast: broadcasts, + knownVotes: knownVotes, + knownSyncInfos: knownSyncInfos, + knownTimeouts: knownTimeouts, + blockCahinReader: blockCahinReader, } } diff --git a/eth/handler.go b/eth/handler.go index 07576519fd..43e385dda0 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -227,7 +227,7 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne Timeout: manager.BroadcastTimeout, SyncInfo: manager.BroadcastSyncInfo, } - manager.bfter = bfter.New(broadcasts) + manager.bfter = bfter.New(broadcasts, blockchain) if blockchain.Config().XDPoS != nil { manager.bfter.SetConsensusFuns(engine) }