update adaptor for verify headers and fix vote handler to include +1 distance when checking rounds (#48)

This commit is contained in:
Jerome 2022-01-30 14:26:05 +11:00 committed by GitHub
parent 328d555b9b
commit 7cc2bef2d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 60 additions and 15 deletions

View file

@ -149,8 +149,30 @@ func (x *XDPoS) VerifyHeader(chain consensus.ChainReader, header *types.Header,
// method returns a quit channel to abort the operations and a results channel to // method returns a quit channel to abort the operations and a results channel to
// retrieve the async verifications (the order is that of the input slice). // retrieve the async verifications (the order is that of the input slice).
func (x *XDPoS) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) { func (x *XDPoS) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) {
// TODO: (Hashlab) This funciton is a special case abort := make(chan struct{})
return x.EngineV1.VerifyHeaders(chain, headers, fullVerifies) results := make(chan error, len(headers))
// Split the headers list into v1 and v2 buckets
var v1headers []*types.Header
var v2headers []*types.Header
for _, header := range headers {
switch x.config.BlockConsensusVersion(header.Number) {
case params.ConsensusEngineVersion2:
v2headers = append(v2headers, header)
default: // Default "v1"
v1headers = append(v1headers, header)
}
}
if v1headers != nil {
x.EngineV1.VerifyHeaders(chain, headers, fullVerifies, abort, results)
}
if v2headers != nil {
x.EngineV2.VerifyHeaders(chain, headers, fullVerifies, abort, results)
}
return abort, results
} }
// VerifyUncles implements consensus.Engine, always returning an error for any // VerifyUncles implements consensus.Engine, always returning an error for any

View file

@ -116,10 +116,7 @@ func (x *XDPoS_v1) VerifyHeader(chain consensus.ChainReader, header *types.Heade
// VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The // VerifyHeaders is similar to VerifyHeader, but verifies a batch of headers. The
// method returns a quit channel to abort the operations and a results channel to // method returns a quit channel to abort the operations and a results channel to
// retrieve the async verifications (the order is that of the input slice). // retrieve the async verifications (the order is that of the input slice).
func (x *XDPoS_v1) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool) (chan<- struct{}, <-chan error) { func (x *XDPoS_v1) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool, abort <-chan struct{}, results chan<- error) {
abort := make(chan struct{})
results := make(chan error, len(headers))
go func() { go func() {
for i, header := range headers { for i, header := range headers {
err := x.verifyHeaderWithCache(chain, header, headers[:i], fullVerifies[i]) err := x.verifyHeaderWithCache(chain, header, headers[:i], fullVerifies[i])
@ -131,7 +128,6 @@ func (x *XDPoS_v1) VerifyHeaders(chain consensus.ChainReader, headers []*types.H
} }
} }
}() }()
return abort, results
} }
func (x *XDPoS_v1) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error { func (x *XDPoS_v1) verifyHeaderWithCache(chain consensus.ChainReader, header *types.Header, parents []*types.Header, fullVerify bool) error {

View file

@ -478,6 +478,19 @@ func (x *XDPoS_v2) VerifyHeader(chain consensus.ChainReader, header *types.Heade
return nil return nil
} }
// TODO: Yet to be implemented XIN-135
func (x *XDPoS_v2) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, fullVerifies []bool, abort <-chan struct{}, results chan<- error) {
go func() {
for range headers {
select {
case <-abort:
return
case results <- nil:
}
}
}()
}
// Utils for test to get current Pool size // Utils for test to get current Pool size
func (x *XDPoS_v2) GetVotePoolSize(vote *utils.Vote) int { func (x *XDPoS_v2) GetVotePoolSize(vote *utils.Vote) int {
return x.votePool.Size(vote) return x.votePool.Size(vote)
@ -556,8 +569,8 @@ func (x *XDPoS_v2) VoteHandler(chain consensus.ChainReader, voteMsg *utils.Vote)
func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *utils.Vote) error { func (x *XDPoS_v2) voteHandler(chain consensus.ChainReader, voteMsg *utils.Vote) error {
// 1. checkRoundNumber // 1. checkRoundNumber
if voteMsg.ProposedBlockInfo.Round != x.currentRound { if (voteMsg.ProposedBlockInfo.Round != x.currentRound) && (voteMsg.ProposedBlockInfo.Round != x.currentRound+1) {
return &utils.ErrIncomingMessageRoundNotEqualCurrentRound{ return &utils.ErrIncomingMessageRoundTooFarFromCurrentRound{
Type: "vote", Type: "vote",
IncomingRound: voteMsg.ProposedBlockInfo.Round, IncomingRound: voteMsg.ProposedBlockInfo.Round,
CurrentRound: x.currentRound, CurrentRound: x.currentRound,

View file

@ -88,3 +88,13 @@ type ErrIncomingMessageRoundNotEqualCurrentRound struct {
func (e *ErrIncomingMessageRoundNotEqualCurrentRound) Error() string { func (e *ErrIncomingMessageRoundNotEqualCurrentRound) Error() string {
return fmt.Sprintf("%s message round number: %v does not match currentRound: %v", e.Type, e.IncomingRound, e.CurrentRound) return fmt.Sprintf("%s message round number: %v does not match currentRound: %v", e.Type, e.IncomingRound, e.CurrentRound)
} }
type ErrIncomingMessageRoundTooFarFromCurrentRound struct {
Type string
IncomingRound Round
CurrentRound Round
}
func (e *ErrIncomingMessageRoundTooFarFromCurrentRound) Error() string {
return fmt.Sprintf("%s message round number: %v is too far away from currentRound: %v", e.Type, e.IncomingRound, e.CurrentRound)
}

View file

@ -126,7 +126,7 @@ func TestVoteMessageHandlerSuccessfullyGeneratedAndProcessQC(t *testing.T) {
assert.Equal(t, big.NewInt(13), highestCommitBlock.Number) assert.Equal(t, big.NewInt(13), highestCommitBlock.Number)
} }
func TestThrowErrorIfVoteMsgRoundNotEqualToCurrentRound(t *testing.T) { func TestThrowErrorIfVoteMsgRoundIsMoreThanOneRoundAwayFromCurrentRound(t *testing.T) {
blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0) blockchain, _, _, _, _, _ := PrepareXDCTestBlockChainForV2Engine(t, 15, params.TestXDPoSMockChainConfigWithV2Engine, 0)
engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2 engineV2 := blockchain.Engine().(*XDPoS.XDPoS).EngineV2
@ -146,14 +146,18 @@ func TestThrowErrorIfVoteMsgRoundNotEqualToCurrentRound(t *testing.T) {
// voteRound > currentRound // voteRound > currentRound
err := engineV2.VoteHandler(blockchain, voteMsg) err := engineV2.VoteHandler(blockchain, voteMsg)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, "vote message round number: 6 does not match currentRound: 7", err.Error()) assert.Equal(t, "vote message round number: 6 is too far away from currentRound: 7", err.Error())
// Set round to 5 // Set round to 5, it's 1 round away, should not trigger failure
engineV2.SetNewRoundFaker(utils.Round(5), false) engineV2.SetNewRoundFaker(utils.Round(5), false)
err = engineV2.VoteHandler(blockchain, voteMsg) err = engineV2.VoteHandler(blockchain, voteMsg)
assert.Nil(t, err)
engineV2.SetNewRoundFaker(utils.Round(4), false)
err = engineV2.VoteHandler(blockchain, voteMsg)
assert.NotNil(t, err) assert.NotNil(t, err)
// voteRound < currentRound assert.Equal(t, "vote message round number: 6 is too far away from currentRound: 4", err.Error())
assert.Equal(t, "vote message round number: 6 does not match currentRound: 5", err.Error())
} }
func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) { func TestProcessVoteMsgThenTimeoutMsg(t *testing.T) {

View file

@ -94,7 +94,7 @@ func (b *Bfter) Vote(vote *utils.Vote) error {
err = b.consensus.voteHandler(b.blockChainReader, vote) err = b.consensus.voteHandler(b.blockChainReader, vote)
if err != nil { if err != nil {
if _, ok := err.(*utils.ErrIncomingMessageRoundNotEqualCurrentRound); ok { if _, ok := err.(*utils.ErrIncomingMessageRoundTooFarFromCurrentRound); ok {
log.Warn("vote round not equal", "error", err, "vote", vote.Hash()) log.Warn("vote round not equal", "error", err, "vote", vote.Hash())
return err return err
} }