mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +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{
|
||||
ProposedBlockInfo: blockInfo,
|
||||
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
|
||||
|
|
@ -201,7 +201,7 @@ func (x *XDPoS_v2) Initial(chain consensus.ChainReader, header *types.Header) er
|
|||
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) {
|
||||
x.lock.RLock()
|
||||
defer x.lock.RUnlock()
|
||||
|
|
@ -222,7 +222,7 @@ func (x *XDPoS_v2) YourTurn(chain consensus.ChainReader, parent *types.Header, s
|
|||
}
|
||||
|
||||
round := x.currentRound
|
||||
isMyTurn, err := x.checkYourturnWithinFinalisedMasternodes(chain, round, parent, signer)
|
||||
isMyTurn, err := x.yourturn(chain, round, parent, signer)
|
||||
if err != nil {
|
||||
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
|
||||
x.signLock.RUnlock()
|
||||
|
||||
isMyTurn, err := x.checkYourturnWithinFinalisedMasternodes(chain, currentRound, parent, signer)
|
||||
isMyTurn, err := x.yourturn(chain, currentRound, parent, signer)
|
||||
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)
|
||||
return err
|
||||
|
|
@ -404,12 +404,6 @@ func (x *XDPoS_v2) CalcDifficulty(chain consensus.ChainReader, time uint64, pare
|
|||
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 {
|
||||
x.lock.RLock()
|
||||
defer x.lock.RUnlock()
|
||||
|
|
@ -523,7 +517,7 @@ func (x *XDPoS_v2) VerifySyncInfoMessage(chain consensus.ChainReader, syncInfo *
|
|||
return false, nil
|
||||
}
|
||||
|
||||
err := x.verifyQC(chain, syncInfo.HighestQuorumCert)
|
||||
err := x.verifyQC(chain, syncInfo.HighestQuorumCert, nil)
|
||||
if err != nil {
|
||||
log.Warn("SyncInfo message verification failed due to QC", "error", err)
|
||||
return false, err
|
||||
|
|
@ -653,7 +647,7 @@ func (x *XDPoS_v2) ProposedBlockHandler(chain consensus.ChainReader, blockHeader
|
|||
return err
|
||||
}
|
||||
|
||||
err = x.verifyQC(chain, quorumCert)
|
||||
err = x.verifyQC(chain, quorumCert, nil)
|
||||
if err != nil {
|
||||
log.Error("[ProposedBlockHandler] Fail to verify QC", "Extra round", round, "QC proposed BlockInfo Hash", quorumCert.ProposedBlockInfo.Hash)
|
||||
return err
|
||||
|
|
@ -732,7 +726,7 @@ func (x *XDPoS_v2) VerifyBlockInfo(blockChainReader consensus.ChainReader, block
|
|||
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
|
||||
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
|
||||
5. Verify blockInfo
|
||||
*/
|
||||
epochInfo, err := x.getEpochSwitchInfo(blockChainReader, nil, quorumCert.ProposedBlockInfo.Hash)
|
||||
epochInfo, err := x.getEpochSwitchInfo(blockChainReader, parentHeader, 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")
|
||||
|
|
@ -764,12 +758,6 @@ func (x *XDPoS_v2) verifyQC(blockChainReader consensus.ChainReader, quorumCert *
|
|||
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
|
||||
wg.Add(len(signatures))
|
||||
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)
|
||||
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)
|
||||
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
|
||||
}
|
||||
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
|
||||
_, _, masterNodes, err = x.getExtraFields(parent)
|
||||
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
|
||||
}
|
||||
} else {
|
||||
masterNodes, _, err = x.calcMasternodes(chain, big.NewInt(0).Add(parent.Number, big.NewInt(1)), parent.Hash())
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
@ -40,26 +40,26 @@ func (x *XDPoS_v2) checkYourturnWithinFinalisedMasternodes(chain consensus.Chain
|
|||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
curIndex := utils.Position(masterNodes, signer)
|
||||
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
|
||||
}
|
||||
|
||||
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))
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
quorumCert, round, _, err := x.getExtraFields(header)
|
||||
if err != nil {
|
||||
|
|
@ -48,7 +64,7 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
|||
return utils.ErrRoundInvalid
|
||||
}
|
||||
|
||||
err = x.verifyQC(chain, quorumCert)
|
||||
err = x.verifyQC(chain, quorumCert, parent)
|
||||
if err != nil {
|
||||
log.Warn("[verifyHeader] fail to verify QC", "QCNumber", quorumCert.ProposedBlockInfo.Number, "QCsigLength", len(quorumCert.Signatures))
|
||||
return err
|
||||
|
|
@ -105,22 +121,6 @@ func (x *XDPoS_v2) verifyHeader(chain consensus.ChainReader, header *types.Heade
|
|||
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)
|
||||
if err != nil {
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
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