mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 18:30:45 +00:00
add highestSelfMinedRound to make sure we mine once per round (#79)
This commit is contained in:
parent
0241d40699
commit
0ded664f0c
4 changed files with 45 additions and 11 deletions
|
|
@ -44,11 +44,12 @@ type XDPoS_v2 struct {
|
||||||
timeoutWorker *countdown.CountdownTimer // Timer to generate broadcast timeout msg if threashold reached
|
timeoutWorker *countdown.CountdownTimer // Timer to generate broadcast timeout msg if threashold reached
|
||||||
timeoutCount int // number of timeout being sent
|
timeoutCount int // number of timeout being sent
|
||||||
|
|
||||||
timeoutPool *utils.Pool
|
timeoutPool *utils.Pool
|
||||||
votePool *utils.Pool
|
votePool *utils.Pool
|
||||||
currentRound utils.Round
|
currentRound utils.Round
|
||||||
highestVotedRound utils.Round
|
highestSelfMinedRound utils.Round
|
||||||
highestQuorumCert *utils.QuorumCert
|
highestVotedRound utils.Round
|
||||||
|
highestQuorumCert *utils.QuorumCert
|
||||||
// lockQuorumCert in XDPoS Consensus 2.0, used in voting rule
|
// lockQuorumCert in XDPoS Consensus 2.0, used in voting rule
|
||||||
lockQuorumCert *utils.QuorumCert
|
lockQuorumCert *utils.QuorumCert
|
||||||
highestTimeoutCert *utils.TimeoutCert
|
highestTimeoutCert *utils.TimeoutCert
|
||||||
|
|
@ -87,6 +88,8 @@ func New(config *params.XDPoSConfig, db ethdb.Database, waitPeriodCh chan int) *
|
||||||
timeoutPool: timeoutPool,
|
timeoutPool: timeoutPool,
|
||||||
votePool: votePool,
|
votePool: votePool,
|
||||||
|
|
||||||
|
highestSelfMinedRound: utils.Round(0),
|
||||||
|
|
||||||
highestTimeoutCert: &utils.TimeoutCert{
|
highestTimeoutCert: &utils.TimeoutCert{
|
||||||
Round: utils.Round(0),
|
Round: utils.Round(0),
|
||||||
Signatures: []utils.Signature{},
|
Signatures: []utils.Signature{},
|
||||||
|
|
@ -225,10 +228,10 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s
|
||||||
round := x.currentRound
|
round := x.currentRound
|
||||||
isMyTurn, err := x.yourturn(chain, round, parent, signer)
|
isMyTurn, err := x.yourturn(chain, round, parent, signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[Yourturn] Error while checking if i am qualified to mine", "round", round, "error", err)
|
log.Warn("[Yourturn] Error while checking if i am qualified to mine", "round", round, "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return isMyTurn, nil
|
return isMyTurn, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare implements consensus.Engine, preparing all the consensus fields of the
|
// Prepare implements consensus.Engine, preparing all the consensus fields of the
|
||||||
|
|
@ -272,7 +275,7 @@ func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) er
|
||||||
|
|
||||||
isMyTurn, err := x.yourturn(chain, currentRound, parent, signer)
|
isMyTurn, err := x.yourturn(chain, currentRound, parent, signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[Prepare] Error while checking if it's still my turn to mine", "round", currentRound, "ParentHash", parent.Hash().Hex(), "ParentNumber", parent.Number.Uint64(), "error", err)
|
log.Error("[Prepare] Error while checking if it's still my turn to mine", "currentRound", currentRound, "ParentHash", parent.Hash().Hex(), "ParentNumber", parent.Number.Uint64(), "error", err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !isMyTurn {
|
if !isMyTurn {
|
||||||
|
|
@ -395,6 +398,15 @@ func (x *XDPoS_v2) Seal(chain consensus.ChainReader, block *types.Block, stop <-
|
||||||
}
|
}
|
||||||
header.Validator = signature
|
header.Validator = signature
|
||||||
|
|
||||||
|
// Mark the highestSelfMinedRound to make sure we only mine once per round
|
||||||
|
var decodedExtraField utils.ExtraFields_v2
|
||||||
|
err = utils.DecodeBytesExtraFields(header.Extra, &decodedExtraField)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("[Seal] Error when decode extra field to get the round number from v2 block during sealing", "Hash", header.Hash().Hex(), "Number", header.Number.Uint64(), "Error", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x.highestSelfMinedRound = decodedExtraField.Round
|
||||||
|
|
||||||
return block.WithSeal(header), nil
|
return block.WithSeal(header), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,11 @@ import (
|
||||||
|
|
||||||
// Using parent and current round to find the finalised master node list(with penalties applied from last epoch)
|
// Using parent and current round to find the finalised master node list(with penalties applied from last epoch)
|
||||||
func (x *XDPoS_v2) yourturn(chain consensus.ChainReader, round utils.Round, parent *types.Header, signer common.Address) (bool, error) {
|
func (x *XDPoS_v2) yourturn(chain consensus.ChainReader, round utils.Round, parent *types.Header, signer common.Address) (bool, error) {
|
||||||
|
if round <= x.highestSelfMinedRound {
|
||||||
|
log.Warn("[yourturn] Already mined on this round", "Round", round, "highestSelfMinedRound", x.highestSelfMinedRound, "ParentHash", parent.Hash().Hex(), "ParentNumber", parent.Number)
|
||||||
|
return false, utils.ErrAlreadyMined
|
||||||
|
}
|
||||||
|
|
||||||
isEpochSwitch, _, err := x.isEpochSwitchAtRound(round, parent)
|
isEpochSwitch, _, err := x.isEpochSwitchAtRound(round, parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[yourturn] check epoch switch at round failed", "Error", err)
|
log.Error("[yourturn] check epoch switch at round failed", "Error", err)
|
||||||
|
|
@ -46,17 +51,17 @@ func (x *XDPoS_v2) yourturn(chain consensus.ChainReader, round utils.Round, pare
|
||||||
|
|
||||||
curIndex := utils.Position(masterNodes, signer)
|
curIndex := utils.Position(masterNodes, signer)
|
||||||
if curIndex == -1 {
|
if curIndex == -1 {
|
||||||
log.Debug("[yourturn] Not authorised signer", "MN", masterNodes, "Hash", parent.Hash(), "signer", signer)
|
log.Warn("[yourturn] Not authorised signer", "MN", masterNodes, "Hash", parent.Hash(), "signer", signer)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, s := range masterNodes {
|
for i, s := range masterNodes {
|
||||||
log.Debug("[yourturn] Masternode:", "index", i, "address", s.String(), "parentBlockNum", parent.Number)
|
log.Warn("[yourturn] Masternode:", "index", i, "address", s.String(), "parentBlockNum", parent.Number)
|
||||||
}
|
}
|
||||||
|
|
||||||
leaderIndex := uint64(round) % x.config.Epoch % uint64(len(masterNodes))
|
leaderIndex := uint64(round) % x.config.Epoch % uint64(len(masterNodes))
|
||||||
if masterNodes[leaderIndex] != signer {
|
if masterNodes[leaderIndex] != signer {
|
||||||
log.Debug("[yourturn] Not my turn", "curIndex", curIndex, "leaderIndex", leaderIndex, "Hash", parent.Hash().Hex(), "masterNodes[leaderIndex]", masterNodes[leaderIndex], "signer", signer)
|
log.Warn("[yourturn] Not my turn", "curIndex", curIndex, "leaderIndex", leaderIndex, "Hash", parent.Hash().Hex(), "masterNodes[leaderIndex]", masterNodes[leaderIndex], "signer", signer)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,8 @@ var (
|
||||||
|
|
||||||
ErrPenaltyListDoesNotMatch = errors.New("Incoming block penalty list does not match")
|
ErrPenaltyListDoesNotMatch = errors.New("Incoming block penalty list does not match")
|
||||||
ErrRoundInvalid = errors.New("Invalid Round, it shall be bigger than QC round")
|
ErrRoundInvalid = errors.New("Invalid Round, it shall be bigger than QC round")
|
||||||
|
|
||||||
|
ErrAlreadyMined = errors.New("Already mined")
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrIncomingMessageRoundNotEqualCurrentRound struct {
|
type ErrIncomingMessageRoundNotEqualCurrentRound struct {
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,21 @@ func TestYourTurnInitialV2(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldMineOncePerRound(t *testing.T) {
|
||||||
|
config := params.TestXDPoSMockChainConfig
|
||||||
|
blockchain, _, block910, signer, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, config, 0)
|
||||||
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
minePeriod := config.XDPoS.V2.MinePeriod
|
||||||
|
|
||||||
|
// Make sure we seal the parentBlock 910
|
||||||
|
_, err := adaptor.Seal(blockchain, block910, nil)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
time.Sleep(time.Duration(minePeriod) * time.Second)
|
||||||
|
b, err := adaptor.YourTurn(blockchain, block910.Header(), signer)
|
||||||
|
assert.False(t, b)
|
||||||
|
assert.Equal(t, utils.ErrAlreadyMined, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestUpdateMasterNodes(t *testing.T) {
|
func TestUpdateMasterNodes(t *testing.T) {
|
||||||
config := params.TestXDPoSMockChainConfig
|
config := params.TestXDPoSMockChainConfig
|
||||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch+config.XDPoS.Gap)-1, config, 0)
|
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, int(config.XDPoS.Epoch+config.XDPoS.Gap)-1, config, 0)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue