Skip to content

Commit

Permalink
consortium/v2: reject the vote with wrong target number
Browse files Browse the repository at this point in the history
Currently, a vote with wrong target number is not assembled into block as there
is a check in assembleFinalityVote. In this commit, we move that check to
VerifyVote to reject the vote earlier in vote pool, avoid the vote pool to be
DOSed.
  • Loading branch information
minh-bq committed Aug 10, 2023
1 parent ee2021c commit 8fe92fa
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 4 deletions.
12 changes: 9 additions & 3 deletions consensus/consortium/v2/consortium.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,15 @@ func (c *Consortium) GetRecents(chain consensus.ChainHeaderReader, number uint64
// VerifyVote check if the finality voter is in the validator set, it assumes the signature is
// already verified
func (c *Consortium) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteEnvelope) error {
header := chain.GetHeaderByHash(vote.Data.TargetHash)
if header == nil {
return errors.New("header not found")
}

if header.Number.Uint64() != vote.Data.TargetNumber {
return errors.New("wrong target number in vote")
}

// Look at the comment assembleFinalityVote in function for the
// detailed explanation on the snapshot we need to get to verify the
// finality vote.
Expand Down Expand Up @@ -1154,9 +1163,6 @@ func (c *Consortium) assembleFinalityVote(header *types.Header, snap *Snapshot)
log.Warn("Malformed public key from vote pool", "err", err)
continue
}
if vote.Data.TargetNumber != header.Number.Uint64()-1 {
continue
}
authorized := false
for valPosition, validator := range snap.ValidatorsWithBlsPub {
if publicKey.Equals(validator.BlsPublicKey) {
Expand Down
66 changes: 65 additions & 1 deletion core/vote/vote_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ func generateVote(
secretKey blsCommon.SecretKey,
) *types.VoteEnvelope {
voteData := types.VoteData{
TargetNumber: 1,
TargetNumber: uint64(blockNumber),
TargetHash: blockHash,
}
digest := voteData.Hash()
Expand Down Expand Up @@ -469,3 +469,67 @@ func TestVotePoolDosProtection(t *testing.T) {
t.Fatalf("Number of future vote per peer, expect %d have %d", 0, votePool.numFutureVotePerPeer["AAAA"])
}
}

type mockPOSAv2 struct {
consensus.FastFinalityPoSA
}

func (p *mockPOSAv2) GetJustifiedNumberAndHash(chain consensus.ChainHeaderReader, header *types.Header) (uint64, common.Hash, error) {
parentHeader := chain.GetHeaderByHash(header.ParentHash)
if parentHeader == nil {
return 0, common.Hash{}, fmt.Errorf("unexpected error")
}
return parentHeader.Number.Uint64(), parentHeader.Hash(), nil
}

func (m *mockPOSAv2) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteEnvelope) error {
header := chain.GetHeaderByHash(vote.Data.TargetHash)
if header == nil {
return errors.New("header not found")
}

if header.Number.Uint64() != vote.Data.TargetNumber {
return errors.New("wrong target number in vote")
}

return nil
}

func (m *mockPOSAv2) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *types.Header) bool {
return true
}

func TestVotePoolWrongTargetNumber(t *testing.T) {
secretKey, err := bls.RandKey()
if err != nil {
t.Fatalf("Failed to create secret key, err %s", err)
}

// Create a database pre-initialize with a genesis block
db := rawdb.NewMemoryDatabase()
genesis := (&core.Genesis{
Config: params.TestChainConfig,
Alloc: core.GenesisAlloc{testAddr: {Balance: big.NewInt(1000000)}},
BaseFee: big.NewInt(params.InitialBaseFee),
}).MustCommit(db)
chain, _ := core.NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFullFaker(), vm.Config{}, nil, nil)

bs, _ := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 1, nil, true)
if _, err := chain.InsertChain(bs[:1]); err != nil {
panic(err)
}
mockEngine := &mockPOSAv2{}

// Create vote pool
votePool := NewVotePool(chain, mockEngine, 22)

// bs[0] is the block 1 so the target block number must be 1.
// Here we provide wrong target number 0
vote := generateVote(0, bs[0].Hash(), secretKey)
votePool.PutVote("AAAA", vote)
time.Sleep(100 * time.Millisecond)

if len(votePool.curVotes) != 0 {
t.Fatalf("Current vote length, expect %d have %d", 0, len(votePool.curVotes))
}
}

0 comments on commit 8fe92fa

Please sign in to comment.