mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-16 01:40:44 +00:00
Xin 166 (#75)
* typo and checkYourturnWithinFinalisedMasternodes func name to yourturn * remove redundant code from verifyQC * Verify QC to optionally pass parent header. This is used to help verifyHeaders * move difficulty into its own file
This commit is contained in:
parent
b790b077c9
commit
b98005a8dd
5 changed files with 82 additions and 46 deletions
14
consensus/XDPoS/engines/engine_v2/difficulty.go
Normal file
14
consensus/XDPoS/engines/engine_v2/difficulty.go
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
package engine_v2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/common"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: what should be new difficulty
|
||||||
|
func (x *XDPoS_v2) calcDifficulty(chain consensus.ChainReader, parent *types.Header, signer common.Address) *big.Int {
|
||||||
|
return big.NewInt(1)
|
||||||
|
}
|
||||||
|
|
@ -143,7 +143,7 @@ func (x *XDPoS_v2) Initial(chain consensus.ChainReader, header *types.Header) er
|
||||||
quorumCert = &utils.QuorumCert{
|
quorumCert = &utils.QuorumCert{
|
||||||
ProposedBlockInfo: blockInfo,
|
ProposedBlockInfo: blockInfo,
|
||||||
Signatures: nil,
|
Signatures: nil,
|
||||||
GapNumber: header.Number.Uint64()-x.config.Gap,
|
GapNumber: header.Number.Uint64() - x.config.Gap,
|
||||||
}
|
}
|
||||||
|
|
||||||
// can not call processQC because round is equal to default
|
// can not call processQC because round is equal to default
|
||||||
|
|
@ -201,7 +201,7 @@ func (x *XDPoS_v2) Initial(chain consensus.ChainReader, header *types.Header) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's my turm to mine a block. Note: The second return value `preIndex` is useless in V2 engine
|
// Check if it's my turn to mine a block. Note: The second return value `preIndex` is useless in V2 engine
|
||||||
func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, signer common.Address) (bool, error) {
|
func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, signer common.Address) (bool, error) {
|
||||||
x.lock.RLock()
|
x.lock.RLock()
|
||||||
defer x.lock.RUnlock()
|
defer x.lock.RUnlock()
|
||||||
|
|
@ -222,7 +222,7 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s
|
||||||
}
|
}
|
||||||
|
|
||||||
round := x.currentRound
|
round := x.currentRound
|
||||||
isMyTurn, err := x.checkYourturnWithinFinalisedMasternodes(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.Error("[Yourturn] Error while checking if i am qualified to mine", "round", round, "error", err)
|
||||||
}
|
}
|
||||||
|
|
@ -269,7 +269,7 @@ func (x *XDPoS_v2) Prepare(chain consensus.ChainReader, header *types.Header) er
|
||||||
signer := x.signer
|
signer := x.signer
|
||||||
x.signLock.RUnlock()
|
x.signLock.RUnlock()
|
||||||
|
|
||||||
isMyTurn, err := x.checkYourturnWithinFinalisedMasternodes(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", "round", currentRound, "ParentHash", parent.Hash().Hex(), "ParentNumber", parent.Number.Uint64(), "error", err)
|
||||||
return err
|
return err
|
||||||
|
|
@ -404,12 +404,6 @@ func (x *XDPoS_v2) CalcDifficulty(chain consensus.ChainReader, time uint64, pare
|
||||||
return x.calcDifficulty(chain, parent, x.signer)
|
return x.calcDifficulty(chain, parent, x.signer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: what should be new difficulty
|
|
||||||
func (x *XDPoS_v2) calcDifficulty(chain consensus.ChainReader, parent *types.Header, signer common.Address) *big.Int {
|
|
||||||
// TODO: The difference of round number between parent round and current round
|
|
||||||
return big.NewInt(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *XDPoS_v2) IsAuthorisedAddress(chain consensus.ChainReader, header *types.Header, address common.Address) bool {
|
func (x *XDPoS_v2) IsAuthorisedAddress(chain consensus.ChainReader, header *types.Header, address common.Address) bool {
|
||||||
x.lock.RLock()
|
x.lock.RLock()
|
||||||
defer x.lock.RUnlock()
|
defer x.lock.RUnlock()
|
||||||
|
|
@ -523,7 +517,7 @@ func (x *XDPoS_v2) VerifySyncInfoMessage(chain consensus.ChainReader, syncInfo *
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err := x.verifyQC(chain, syncInfo.HighestQuorumCert)
|
err := x.verifyQC(chain, syncInfo.HighestQuorumCert, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("SyncInfo message verification failed due to QC", "error", err)
|
log.Warn("SyncInfo message verification failed due to QC", "error", err)
|
||||||
return false, err
|
return false, err
|
||||||
|
|
@ -653,7 +647,7 @@ func (x *XDPoS_v2) ProposedBlockHandler(chain consensus.ChainReader, blockHeader
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = x.verifyQC(chain, quorumCert)
|
err = x.verifyQC(chain, quorumCert, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[ProposedBlockHandler] Fail to verify QC", "Extra round", round, "QC proposed BlockInfo Hash", quorumCert.ProposedBlockInfo.Hash)
|
log.Error("[ProposedBlockHandler] Fail to verify QC", "Extra round", round, "QC proposed BlockInfo Hash", quorumCert.ProposedBlockInfo.Hash)
|
||||||
return err
|
return err
|
||||||
|
|
@ -732,7 +726,7 @@ func (x *XDPoS_v2) VerifyBlockInfo(blockChainReader consensus.ChainReader, block
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *utils.QuorumCert) error {
|
func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *utils.QuorumCert, parentHeader *types.Header) error {
|
||||||
/*
|
/*
|
||||||
1. Check if num of QC signatures is >= x.config.v2.CertThreshold
|
1. Check if num of QC signatures is >= x.config.v2.CertThreshold
|
||||||
2. Get epoch master node list by hash
|
2. Get epoch master node list by hash
|
||||||
|
|
@ -743,7 +737,7 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
||||||
4. Verify gapNumber = epochSwitchNumber - epochSwitchNumber%Epoch - Gap
|
4. Verify gapNumber = epochSwitchNumber - epochSwitchNumber%Epoch - Gap
|
||||||
5. Verify blockInfo
|
5. Verify blockInfo
|
||||||
*/
|
*/
|
||||||
epochInfo, err := x.getEpochSwitchInfo(blockChainReader, nil, quorumCert.ProposedBlockInfo.Hash)
|
epochInfo, err := x.getEpochSwitchInfo(blockChainReader, parentHeader, quorumCert.ProposedBlockInfo.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[verifyQC] Error when getting epoch switch Info to verify QC", "Error", err)
|
log.Error("[verifyQC] Error when getting epoch switch Info to verify QC", "Error", err)
|
||||||
return fmt.Errorf("Fail to verify QC due to failure in getting epoch switch info")
|
return fmt.Errorf("Fail to verify QC due to failure in getting epoch switch info")
|
||||||
|
|
@ -764,12 +758,6 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
||||||
return utils.ErrInvalidQC
|
return utils.ErrInvalidQC
|
||||||
}
|
}
|
||||||
|
|
||||||
epochInfo, err = x.getEpochSwitchInfo(blockChainReader, nil, quorumCert.ProposedBlockInfo.Hash)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("[verifyQC] Error when getting epoch switch Info to verify QC", "Error", err)
|
|
||||||
return fmt.Errorf("Fail to verify QC due to failure in getting epoch switch info")
|
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(signatures))
|
wg.Add(len(signatures))
|
||||||
var haveError error
|
var haveError error
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,10 @@ 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) checkYourturnWithinFinalisedMasternodes(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) {
|
||||||
isEpochSwitch, _, err := x.isEpochSwitchAtRound(round, parent)
|
isEpochSwitch, _, err := x.isEpochSwitchAtRound(round, parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[checkYourturnWithinFinalisedMasternodes] check epoch switch at round failed", "Error", err)
|
log.Error("[yourturn] check epoch switch at round failed", "Error", err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
var masterNodes []common.Address
|
var masterNodes []common.Address
|
||||||
|
|
@ -24,13 +24,13 @@ func (x *XDPoS_v2) checkYourturnWithinFinalisedMasternodes(chain consensus.Chain
|
||||||
// the initial master nodes of v1->v2 switch contains penalties node
|
// the initial master nodes of v1->v2 switch contains penalties node
|
||||||
_, _, masterNodes, err = x.getExtraFields(parent)
|
_, _, masterNodes, err = x.getExtraFields(parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[checkYourturnWithinFinalisedMasternodes] Cannot find snapshot at gap num of last V1", "err", err, "number", x.config.V2.SwitchBlock.Uint64())
|
log.Error("[yourturn] Cannot find snapshot at gap num of last V1", "err", err, "number", x.config.V2.SwitchBlock.Uint64())
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
masterNodes, _, err = x.calcMasternodes(chain, big.NewInt(0).Add(parent.Number, big.NewInt(1)), parent.Hash())
|
masterNodes, _, err = x.calcMasternodes(chain, big.NewInt(0).Add(parent.Number, big.NewInt(1)), parent.Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[checkYourturnWithinFinalisedMasternodes] Cannot calcMasternodes at gap num ", "err", err, "parent number", parent.Number)
|
log.Error("[yourturn] Cannot calcMasternodes at gap num ", "err", err, "parent number", parent.Number)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -40,26 +40,26 @@ func (x *XDPoS_v2) checkYourturnWithinFinalisedMasternodes(chain consensus.Chain
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(masterNodes) == 0 {
|
if len(masterNodes) == 0 {
|
||||||
log.Error("[checkYourturnWithinFinalisedMasternodes] Fail to find any master nodes from current block round epoch", "Hash", parent.Hash(), "CurrentRound", round, "Number", parent.Number)
|
log.Error("[yourturn] Fail to find any master nodes from current block round epoch", "Hash", parent.Hash(), "CurrentRound", round, "Number", parent.Number)
|
||||||
return false, errors.New("masternodes not found")
|
return false, errors.New("masternodes not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
curIndex := utils.Position(masterNodes, signer)
|
curIndex := utils.Position(masterNodes, signer)
|
||||||
if curIndex == -1 {
|
if curIndex == -1 {
|
||||||
log.Debug("[checkYourturnWithinFinalisedMasternodes] Not authorised signer", "MN", masterNodes, "Hash", parent.Hash(), "signer", signer)
|
log.Debug("[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("[checkYourturnWithinFinalisedMasternodes] Masternode:", "index", i, "address", s.String(), "parentBlockNum", parent.Number)
|
log.Debug("[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("[checkYourturnWithinFinalisedMasternodes] Not my turn", "curIndex", curIndex, "leaderIndex", leaderIndex, "Hash", parent.Hash().Hex(), "masterNodes[leaderIndex]", masterNodes[leaderIndex], "signer", signer)
|
log.Debug("[yourturn] Not my turn", "curIndex", curIndex, "leaderIndex", leaderIndex, "Hash", parent.Hash().Hex(), "masterNodes[leaderIndex]", masterNodes[leaderIndex], "signer", signer)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("[checkYourturnWithinFinalisedMasternodes] Yes, it's my turn based on parent block", "ParentHash", parent.Hash().Hex(), "ParentBlockNumber", parent.Number.Uint64())
|
log.Debug("[yourturn] Yes, it's my turn based on parent block", "ParentHash", parent.Hash().Hex(), "ParentBlockNumber", parent.Number.Uint64())
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,22 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that the block's timestamp isn't too close to it's parent
|
||||||
|
var parent *types.Header
|
||||||
|
number := header.Number.Uint64()
|
||||||
|
|
||||||
|
if len(parents) > 0 {
|
||||||
|
parent = parents[len(parents)-1]
|
||||||
|
} else {
|
||||||
|
parent = chain.GetHeader(header.ParentHash, number-1)
|
||||||
|
}
|
||||||
|
if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
|
||||||
|
return consensus.ErrUnknownAncestor
|
||||||
|
}
|
||||||
|
if parent.Number.Uint64() > x.config.V2.SwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.MinePeriod) > header.Time.Uint64() {
|
||||||
|
return utils.ErrInvalidTimestamp
|
||||||
|
}
|
||||||
|
|
||||||
// Verify this is truely a v2 block first
|
// Verify this is truely a v2 block first
|
||||||
quorumCert, round, _, err := x.getExtraFields(header)
|
quorumCert, round, _, err := x.getExtraFields(header)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -48,7 +64,7 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
||||||
return utils.ErrRoundInvalid
|
return utils.ErrRoundInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
err = x.verifyQC(chain, quorumCert)
|
err = x.verifyQC(chain, quorumCert, parent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("[verifyHeader] fail to verify QC", "QCNumber", quorumCert.ProposedBlockInfo.Number, "QCsigLength", len(quorumCert.Signatures))
|
log.Warn("[verifyHeader] fail to verify QC", "QCNumber", quorumCert.ProposedBlockInfo.Number, "QCsigLength", len(quorumCert.Signatures))
|
||||||
return err
|
return err
|
||||||
|
|
@ -105,22 +121,6 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that the block's timestamp isn't too close to it's parent
|
|
||||||
var parent *types.Header
|
|
||||||
number := header.Number.Uint64()
|
|
||||||
|
|
||||||
if len(parents) > 0 {
|
|
||||||
parent = parents[len(parents)-1]
|
|
||||||
} else {
|
|
||||||
parent = chain.GetHeader(header.ParentHash, number-1)
|
|
||||||
}
|
|
||||||
if parent == nil || parent.Number.Uint64() != number-1 || parent.Hash() != header.ParentHash {
|
|
||||||
return consensus.ErrUnknownAncestor
|
|
||||||
}
|
|
||||||
if parent.Number.Uint64() > x.config.V2.SwitchBlock.Uint64() && parent.Time.Uint64()+uint64(x.config.V2.MinePeriod) > header.Time.Uint64() {
|
|
||||||
return utils.ErrInvalidTimestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
_, penalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash)
|
_, penalties, err := x.calcMasternodes(chain, header.Number, header.ParentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[verifyHeader] Fail to calculate master nodes list with penalty", "Number", header.Number, "Hash", header.Hash())
|
log.Error("[verifyHeader] Fail to calculate master nodes list with penalty", "Number", header.Number, "Hash", header.Hash())
|
||||||
|
|
|
||||||
|
|
@ -218,3 +218,37 @@ func TestShouldFailIfNotEnoughQCSignatures(t *testing.T) {
|
||||||
assert.Equal(t, utils.ErrInvalidQC, err)
|
assert.Equal(t, utils.ErrInvalidQC, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShouldVerifyHeaders(t *testing.T) {
|
||||||
|
b, err := json.Marshal(params.TestXDPoSMockChainConfig)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
configString := string(b)
|
||||||
|
|
||||||
|
var config params.ChainConfig
|
||||||
|
err = json.Unmarshal([]byte(configString), &config)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// Enable verify
|
||||||
|
config.XDPoS.V2.SkipV2Validation = false
|
||||||
|
// Skip the mining time validation by set mine time to 0
|
||||||
|
config.XDPoS.V2.MinePeriod = 0
|
||||||
|
// Block 901 is the first v2 block with round of 1
|
||||||
|
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 910, &config, 0)
|
||||||
|
adaptor := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
||||||
|
// var results <-chan error
|
||||||
|
// var abort <-chan struct{}
|
||||||
|
|
||||||
|
// Happy path
|
||||||
|
var happyPathHeaders []*types.Header
|
||||||
|
happyPathHeaders = append(happyPathHeaders, blockchain.GetBlockByNumber(899).Header(), blockchain.GetBlockByNumber(900).Header(), blockchain.GetBlockByNumber(901).Header(), blockchain.GetBlockByNumber(902).Header())
|
||||||
|
// Randomly set full verify
|
||||||
|
var fullVerifies []bool
|
||||||
|
fullVerifies = append(fullVerifies, false, true, true, false)
|
||||||
|
_, results := adaptor.VerifyHeaders(blockchain, happyPathHeaders, fullVerifies)
|
||||||
|
select {
|
||||||
|
case result := <-results:
|
||||||
|
assert.Nil(t, result)
|
||||||
|
case <-time.After(time.Duration(2) * time.Second): // It should be very fast to verify headers
|
||||||
|
t.Fatalf("Taking too long to verify headers")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue