mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-18 10:50:44 +00:00
consensus: verify timeout from epochInfo instead of snap.NextEpochCandidates, close XFN-62 (#1628)
This commit is contained in:
parent
fac866138b
commit
e617598d1d
6 changed files with 33 additions and 55 deletions
|
|
@ -78,6 +78,10 @@ func (x *XDPoS_v2) getEpochSwitchInfo(chain consensus.ChainReader, header *types
|
||||||
log.Error("[getEpochSwitchInfo] get extra field", "err", err, "number", h.Number.Uint64())
|
log.Error("[getEpochSwitchInfo] get extra field", "err", err, "number", h.Number.Uint64())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if len(masternodes) == 0 {
|
||||||
|
return nil, fmt.Errorf("masternodes list is empty at epoch switch block %v", h.Number.Uint64())
|
||||||
|
}
|
||||||
|
|
||||||
snap, err := x.getSnapshot(chain, h.Number.Uint64(), false)
|
snap, err := x.getSnapshot(chain, h.Number.Uint64(), false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[getEpochSwitchInfo] Adaptor v2 getSnapshot has error", "err", err)
|
log.Error("[getEpochSwitchInfo] Adaptor v2 getSnapshot has error", "err", err)
|
||||||
|
|
@ -110,11 +114,13 @@ func (x *XDPoS_v2) getEpochSwitchInfo(chain consensus.ChainReader, header *types
|
||||||
x.epochSwitches.Add(hash, epochSwitchInfo)
|
x.epochSwitches.Add(hash, epochSwitchInfo)
|
||||||
return epochSwitchInfo, nil
|
return epochSwitchInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
epochSwitchInfo, err = x.getEpochSwitchInfo(chain, nil, h.ParentHash)
|
epochSwitchInfo, err = x.getEpochSwitchInfo(chain, nil, h.ParentHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[getEpochSwitchInfo] recursive error", "err", err, "hash", hash.Hex(), "number", h.Number.Uint64())
|
log.Error("[getEpochSwitchInfo] recursive error", "err", err, "hash", hash.Hex(), "number", h.Number.Uint64())
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("[getEpochSwitchInfo] get epoch switch info recursively", "hash", hash.Hex(), "number", h.Number.Uint64())
|
log.Debug("[getEpochSwitchInfo] get epoch switch info recursively", "hash", hash.Hex(), "number", h.Number.Uint64())
|
||||||
x.epochSwitches.Add(hash, epochSwitchInfo)
|
x.epochSwitches.Add(hash, epochSwitchInfo)
|
||||||
return epochSwitchInfo, nil
|
return epochSwitchInfo, nil
|
||||||
|
|
|
||||||
|
|
@ -31,9 +31,9 @@ func (x *XDPoS_v2) VerifySyncInfoMessage(chain consensus.ChainReader, syncInfo *
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot, err := x.getSnapshot(chain, qc.GapNumber, true)
|
epochInfo, err := x.getEpochSwitchInfo(chain, nil, qc.ProposedBlockInfo.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[VerifySyncInfoMessage] fail to get snapshot for a syncInfo message", "blockNum", qc.ProposedBlockInfo.Number, "blockHash", qc.ProposedBlockInfo.Hash, "error", err)
|
log.Error("[VerifySyncInfoMessage] fail to get epochInfo for qc syncInfo message", "blockNum", qc.ProposedBlockInfo.Number, "blockHash", qc.ProposedBlockInfo.Hash, "error", err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,16 +42,16 @@ func (x *XDPoS_v2) VerifySyncInfoMessage(chain consensus.ChainReader, syncInfo *
|
||||||
GapNumber: qc.GapNumber,
|
GapNumber: qc.GapNumber,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := x.verifySignatures(voteSigHash, qc.Signatures, snapshot.NextEpochCandidates); err != nil {
|
if err := x.verifySignatures(voteSigHash, qc.Signatures, epochInfo.Masternodes); err != nil {
|
||||||
log.Warn("[VerifySyncInfoMessage] SyncInfo message verification failed due to QC", "blockNum", qc.ProposedBlockInfo.Number, "gapNum", qc.GapNumber, "round", qc.ProposedBlockInfo.Round, "error", err)
|
log.Warn("[VerifySyncInfoMessage] SyncInfo message verification failed due to QC", "blockNum", qc.ProposedBlockInfo.Number, "gapNum", qc.GapNumber, "round", qc.ProposedBlockInfo.Round, "error", err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if tc != nil { // tc is optional, when the node is starting up there is no TC at the memory
|
if tc != nil { // tc is optional, when the node is starting up there is no TC at the memory
|
||||||
snapshot, err = x.getSnapshot(chain, tc.GapNumber, true)
|
epochInfo, err := x.getTCEpochInfo(chain, tc.Round)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[VerifySyncInfoMessage] Fail to get snapshot when verifying TC!", "tcGapNumber", tc.GapNumber)
|
log.Error("[VerifySyncInfoMessage] Fail to get epochInfo for tc syncInfo message", "tcRound", tc.Round, "error", err)
|
||||||
return false, fmt.Errorf("[VerifySyncInfoMessage] Unable to get snapshot, %s", err)
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
signedTimeoutObj := types.TimeoutSigHash(&types.TimeoutForSign{
|
signedTimeoutObj := types.TimeoutSigHash(&types.TimeoutForSign{
|
||||||
|
|
@ -59,7 +59,7 @@ func (x *XDPoS_v2) VerifySyncInfoMessage(chain consensus.ChainReader, syncInfo *
|
||||||
GapNumber: tc.GapNumber,
|
GapNumber: tc.GapNumber,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := x.verifySignatures(signedTimeoutObj, tc.Signatures, snapshot.NextEpochCandidates); err != nil {
|
if err := x.verifySignatures(signedTimeoutObj, tc.Signatures, epochInfo.Masternodes); err != nil {
|
||||||
log.Warn("[VerifySyncInfoMessage] SyncInfo message verification failed due to TC", "gapNum", tc.GapNumber, "round", tc.Round, "error", err)
|
log.Warn("[VerifySyncInfoMessage] SyncInfo message verification failed due to TC", "gapNum", tc.GapNumber, "round", tc.Round, "error", err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,20 +22,17 @@ func (x *XDPoS_v2) VerifyTimeoutMessage(chain consensus.ChainReader, timeoutMsg
|
||||||
log.Debug("[VerifyTimeoutMessage] Disqualified timeout message as the proposed round does not match currentRound", "timeoutHash", timeoutMsg.Hash(), "timeoutRound", timeoutMsg.Round, "currentRound", x.currentRound)
|
log.Debug("[VerifyTimeoutMessage] Disqualified timeout message as the proposed round does not match currentRound", "timeoutHash", timeoutMsg.Hash(), "timeoutRound", timeoutMsg.Round, "currentRound", x.currentRound)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
snap, err := x.getSnapshot(chain, timeoutMsg.GapNumber, true)
|
|
||||||
if err != nil || snap == nil {
|
epochInfo, err := x.getTCEpochInfo(chain, timeoutMsg.Round)
|
||||||
log.Error("[VerifyTimeoutMessage] Fail to get snapshot when verifying timeout message!", "messageGapNumber", timeoutMsg.GapNumber, "err", err)
|
if err != nil {
|
||||||
|
log.Error("[VerifyTimeoutMessage] Fail to get epochInfo for timeout message", "tcGapNumber", timeoutMsg.GapNumber, "tcRound", timeoutMsg.Round, "error", err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
if len(snap.NextEpochCandidates) == 0 {
|
|
||||||
log.Error("[VerifyTimeoutMessage] cannot find NextEpochCandidates from snapshot", "messageGapNumber", timeoutMsg.GapNumber)
|
|
||||||
return false, errors.New("empty master node lists from snapshot")
|
|
||||||
}
|
|
||||||
|
|
||||||
verified, signer, err := x.verifyMsgSignature(types.TimeoutSigHash(&types.TimeoutForSign{
|
verified, signer, err := x.verifyMsgSignature(types.TimeoutSigHash(&types.TimeoutForSign{
|
||||||
Round: timeoutMsg.Round,
|
Round: timeoutMsg.Round,
|
||||||
GapNumber: timeoutMsg.GapNumber,
|
GapNumber: timeoutMsg.GapNumber,
|
||||||
}), timeoutMsg.Signature, snap.NextEpochCandidates)
|
}), timeoutMsg.Signature, epochInfo.Masternodes)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("[VerifyTimeoutMessage] cannot verify timeout signature", "err", err)
|
log.Warn("[VerifyTimeoutMessage] cannot verify timeout signature", "err", err)
|
||||||
|
|
@ -116,7 +113,7 @@ func (x *XDPoS_v2) onTimeoutPoolThresholdReached(blockChainReader consensus.Chai
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *XDPoS_v2) getTCEpochInfo(chain consensus.ChainReader, timeoutCert *types.TimeoutCert) (*types.EpochSwitchInfo, error) {
|
func (x *XDPoS_v2) getTCEpochInfo(chain consensus.ChainReader, timeoutRound types.Round) (*types.EpochSwitchInfo, error) {
|
||||||
epochSwitchInfo, err := x.getEpochSwitchInfo(chain, (chain.CurrentHeader()), (chain.CurrentHeader()).Hash())
|
epochSwitchInfo, err := x.getEpochSwitchInfo(chain, (chain.CurrentHeader()), (chain.CurrentHeader()).Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[getTCEpochInfo] Error when getting epoch switch info", "error", err)
|
log.Error("[getTCEpochInfo] Error when getting epoch switch info", "error", err)
|
||||||
|
|
@ -131,18 +128,18 @@ func (x *XDPoS_v2) getTCEpochInfo(chain consensus.ChainReader, timeoutCert *type
|
||||||
Round: epochRound,
|
Round: epochRound,
|
||||||
Number: epochSwitchInfo.EpochSwitchBlockInfo.Number,
|
Number: epochSwitchInfo.EpochSwitchBlockInfo.Number,
|
||||||
}
|
}
|
||||||
log.Info("[getTCEpochInfo] Init epochInfo", "number", epochBlockInfo.Number, "round", epochRound, "tcRound", timeoutCert.Round, "tcEpoch", tempTCEpoch)
|
log.Info("[getTCEpochInfo] Init epochInfo", "number", epochBlockInfo.Number, "round", epochRound, "tcRound", timeoutRound, "tcEpoch", tempTCEpoch)
|
||||||
for epochBlockInfo.Round > timeoutCert.Round {
|
for epochBlockInfo.Round > timeoutRound {
|
||||||
tempTCEpoch--
|
tempTCEpoch--
|
||||||
epochBlockInfo, err = x.GetBlockByEpochNumber(chain, tempTCEpoch)
|
epochBlockInfo, err = x.GetBlockByEpochNumber(chain, tempTCEpoch)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[getTCEpochInfo] Error when getting epoch block info by tc round", "error", err)
|
log.Error("[getTCEpochInfo] Error when getting epoch block info by tc round", "error", err)
|
||||||
return nil, fmt.Errorf("fail on getTCEpochInfo due to failure in getting epoch block info tc round, %s", err)
|
return nil, fmt.Errorf("fail on getTCEpochInfo due to failure in getting epoch block info tc round, %s", err)
|
||||||
}
|
}
|
||||||
log.Debug("[getTCEpochInfo] Loop to get right epochInfo", "number", epochBlockInfo.Number, "round", epochBlockInfo.Round, "tcRound", timeoutCert.Round, "tcEpoch", tempTCEpoch)
|
log.Debug("[getTCEpochInfo] Loop to get right epochInfo", "number", epochBlockInfo.Number, "round", epochBlockInfo.Round, "tcRound", timeoutRound, "tcEpoch", tempTCEpoch)
|
||||||
}
|
}
|
||||||
tcEpoch := tempTCEpoch
|
tcEpoch := tempTCEpoch
|
||||||
log.Info("[getTCEpochInfo] Final TC epochInfo", "number", epochBlockInfo.Number, "round", epochBlockInfo.Round, "tcRound", timeoutCert.Round, "tcEpoch", tcEpoch)
|
log.Info("[getTCEpochInfo] Final TC epochInfo", "number", epochBlockInfo.Number, "round", epochBlockInfo.Round, "tcRound", timeoutRound, "tcEpoch", tcEpoch)
|
||||||
|
|
||||||
epochInfo, err := x.getEpochSwitchInfo(chain, nil, epochBlockInfo.Hash)
|
epochInfo, err := x.getEpochSwitchInfo(chain, nil, epochBlockInfo.Hash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -175,7 +172,7 @@ func (x *XDPoS_v2) verifyTC(chain consensus.ChainReader, timeoutCert *types.Time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
epochInfo, err := x.getTCEpochInfo(chain, timeoutCert)
|
epochInfo, err := x.getTCEpochInfo(chain, timeoutCert.Round)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,18 @@ func (x *XDPoS_v2) VerifyVoteMessage(chain consensus.ChainReader, vote *types.Vo
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot, err := x.getSnapshot(chain, vote.GapNumber, true)
|
epochInfo, err := x.getEpochSwitchInfo(chain, chain.CurrentHeader(), chain.CurrentHeader().Hash())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("[VerifyVoteMessage] fail to get snapshot for a vote message", "blockNum", vote.ProposedBlockInfo.Number, "blockHash", vote.ProposedBlockInfo.Hash, "voteHash", vote.Hash(), "error", err.Error())
|
log.Error("[VerifyVoteMessage] Fail to get epochInfo when verifying vote message!", "blockNum", vote.ProposedBlockInfo.Number, "blockHash", vote.ProposedBlockInfo.Hash, "voteHash", vote.Hash(), "voteGapNumber", vote.GapNumber, "err", err)
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
verified, signer, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{
|
verified, signer, err := x.verifyMsgSignature(types.VoteSigHash(&types.VoteForSign{
|
||||||
ProposedBlockInfo: vote.ProposedBlockInfo,
|
ProposedBlockInfo: vote.ProposedBlockInfo,
|
||||||
GapNumber: vote.GapNumber,
|
GapNumber: vote.GapNumber,
|
||||||
}), vote.Signature, snapshot.NextEpochCandidates)
|
}), vote.Signature, epochInfo.Masternodes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
for i, mn := range snapshot.NextEpochCandidates {
|
for i, mn := range epochInfo.Masternodes {
|
||||||
log.Warn("[VerifyVoteMessage] Master node list item", "index", i, "Master node", mn.Hex())
|
log.Warn("[VerifyVoteMessage] Master node list item", "index", i, "Master node", mn.Hex())
|
||||||
}
|
}
|
||||||
log.Warn("[VerifyVoteMessage] Error while verifying vote message", "votedBlockNum", vote.ProposedBlockInfo.Number.Uint64(), "votedBlockHash", vote.ProposedBlockInfo.Hash.Hex(), "voteHash", vote.Hash(), "error", err.Error())
|
log.Warn("[VerifyVoteMessage] Error while verifying vote message", "votedBlockNum", vote.ProposedBlockInfo.Number.Uint64(), "votedBlockHash", vote.ProposedBlockInfo.Hash.Hex(), "voteHash", vote.Hash(), "error", err.Error())
|
||||||
|
|
|
||||||
|
|
@ -172,11 +172,11 @@ func TestGetBlockByEpochNumber(t *testing.T) {
|
||||||
blockchain, _, currentBlock, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, 1802, params.TestXDPoSMockChainConfig)
|
blockchain, _, currentBlock, signer, signFn := PrepareXDCTestBlockChainWithPenaltyForV2Engine(t, 1802, params.TestXDPoSMockChainConfig)
|
||||||
|
|
||||||
blockCoinBase := "0x111000000000000000000000000000000123"
|
blockCoinBase := "0x111000000000000000000000000000000123"
|
||||||
largeRound := int64(1802)
|
largeRound := int64(1800)
|
||||||
newBlock := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, int(currentBlock.NumberU64())+1, largeRound, blockCoinBase, signer, signFn, nil, nil, currentBlock.Header().Root.Hex())
|
newBlock := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, currentBlock, int(currentBlock.NumberU64())+1, largeRound, blockCoinBase, signer, signFn, nil, nil, currentBlock.Header().Root.Hex())
|
||||||
err := blockchain.InsertBlock(newBlock)
|
err := blockchain.InsertBlock(newBlock)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
largeRound2 := int64(3603)
|
largeRound2 := int64(3600)
|
||||||
newBlock2 := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, newBlock, int(newBlock.NumberU64())+1, largeRound2, blockCoinBase, signer, signFn, nil, nil, newBlock.Header().Root.Hex())
|
newBlock2 := CreateBlock(blockchain, params.TestXDPoSMockChainConfig, newBlock, int(newBlock.NumberU64())+1, largeRound2, blockCoinBase, signer, signFn, nil, nil, newBlock.Header().Root.Hex())
|
||||||
err = blockchain.InsertBlock(newBlock2)
|
err = blockchain.InsertBlock(newBlock2)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
|
|
@ -189,9 +189,9 @@ func TestGetBlockByEpochNumber(t *testing.T) {
|
||||||
// 1800,900,2 (2nd epoch switch block)
|
// 1800,900,2 (2nd epoch switch block)
|
||||||
// 1801,901,2
|
// 1801,901,2
|
||||||
// 1802,902,2
|
// 1802,902,2
|
||||||
// 1803,1802,3 (epoch switch)
|
// 1803,1800,3 (epoch switch)
|
||||||
// epoch 4 has no block
|
// epoch 4 has no block
|
||||||
// 1804,3603,5 (epoch switch)
|
// 1804,3600,5 (epoch switch)
|
||||||
engine := blockchain.Engine().(*XDPoS.XDPoS)
|
engine := blockchain.Engine().(*XDPoS.XDPoS)
|
||||||
|
|
||||||
// init the snapshot, otherwise getEpochSwitchInfo would return error
|
// init the snapshot, otherwise getEpochSwitchInfo would return error
|
||||||
|
|
|
||||||
|
|
@ -537,32 +537,6 @@ func TestVerifyVoteMsg(t *testing.T) {
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVoteMsgMissingSnapshot(t *testing.T) {
|
|
||||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 915, params.TestXDPoSMockChainConfig, nil)
|
|
||||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
|
||||||
|
|
||||||
blockInfo := &types.BlockInfo{
|
|
||||||
Hash: currentBlock.Hash(),
|
|
||||||
Round: types.Round(14),
|
|
||||||
Number: big.NewInt(915),
|
|
||||||
}
|
|
||||||
voteForSign := &types.VoteForSign{
|
|
||||||
ProposedBlockInfo: blockInfo,
|
|
||||||
GapNumber: 450,
|
|
||||||
}
|
|
||||||
|
|
||||||
signHash, _ := signFn(accounts.Account{Address: signer}, types.VoteSigHash(voteForSign).Bytes())
|
|
||||||
voteMsg := &types.Vote{
|
|
||||||
ProposedBlockInfo: blockInfo,
|
|
||||||
Signature: signHash,
|
|
||||||
GapNumber: 1350, // missing 1350 snapshot
|
|
||||||
}
|
|
||||||
engineV2.SetNewRoundFaker(blockchain, types.Round(14), false)
|
|
||||||
verified, err := engineV2.VerifyVoteMessage(blockchain, voteMsg)
|
|
||||||
assert.False(t, verified)
|
|
||||||
assert.NotNil(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVoteMessageHandlerWrongGapNumber(t *testing.T) {
|
func TestVoteMessageHandlerWrongGapNumber(t *testing.T) {
|
||||||
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, nil)
|
blockchain, _, currentBlock, signer, signFn, _ := PrepareXDCTestBlockChainForV2Engine(t, 905, params.TestXDPoSMockChainConfig, nil)
|
||||||
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue