Skip to content

Commit 7535a8f

Browse files
committed
app: additional check in abci
1 parent 49e80a1 commit 7535a8f

File tree

4 files changed

+182
-99
lines changed

4 files changed

+182
-99
lines changed

app/abci.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,7 @@ func (app *HeimdallApp) PreBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlo
694694

695695
if err := milestoneAbci.ValidateMilestoneProposition(ctx, &app.MilestoneKeeper, majorityMilestone); err != nil {
696696
logger.Error("Invalid milestone proposition", "error", err, "height", req.Height, "majorityMilestone", majorityMilestone)
697-
// We don't want to halt consensus because of invalid majority milestone proposition
697+
// We don't want to halt consensus because of an invalid majority milestone proposition
698698
} else if helper.IsRio(majorityMilestone.StartBlockNumber) && ctx.BlockHeight() == int64(lastSpanHeimdallBlock)+1 {
699699
logger.Info("Last span was created in the previous block, skipping milestone addition", "lastSpanHeimdallBlock", lastSpanHeimdallBlock, "currentBlock", ctx.BlockHeight())
700700
} else {
@@ -790,7 +790,7 @@ func (app *HeimdallApp) PreBlocker(ctx sdk.Context, req *abci.RequestFinalizeBlo
790790
}
791791

792792
// tally votes
793-
approvedTxs, _, _, err := tallyVotes(extVoteInfo, logger, validatorSet.GetTotalVotingPower(), req.Height)
793+
approvedTxs, _, _, err := tallyVotes(extVoteInfo, logger, validatorSet, req.Height)
794794
if err != nil {
795795
logger.Error("Error occurred while tallying votes", "error", err)
796796
return nil, err

app/vote_ext_utils.go

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ func ValidateVoteExtensions(ctx sdk.Context, reqHeight int64, extVoteInfo []abci
124124
continue
125125
}
126126

127+
// ensure proposer-supplied power matches canonical power
128+
// This is not used for tallying, but a mismatch indicates potential tampering.
129+
if vote.Validator.Power != validator.VotingPower {
130+
return fmt.Errorf(
131+
"mismatching voting power in ValidateVoteExtension for validator %s: got %d from ExtendedCommitInfo, expected %d",
132+
valAddrStr,
133+
vote.Validator.Power,
134+
validator.VotingPower,
135+
)
136+
}
137+
127138
cmtPubKey, err := getValidatorPublicKey(validator)
128139
if err != nil {
129140
return err
@@ -252,6 +263,17 @@ func FilterVoteExtensions(ctx sdk.Context, reqHeight int64, extVoteInfo []abciTy
252263
continue
253264
}
254265

266+
// ensure proposer-supplied power matches canonical power
267+
if vote.Validator.Power != validator.VotingPower {
268+
logger.Warn(
269+
"mismatching voting power in FilterVoteExtension",
270+
"validator", valAddrStr,
271+
"receivedVotingPower", vote.Validator.Power,
272+
"expectedVotingPower", validator.VotingPower,
273+
)
274+
continue
275+
}
276+
255277
cmtPubKey, err := getValidatorPublicKey(validator)
256278
if err != nil {
257279
return nil, err
@@ -326,10 +348,13 @@ func FilterVoteExtensions(ctx sdk.Context, reqHeight int64, extVoteInfo []abciTy
326348

327349
// tallyVotes tallies the votes received for the side tx
328350
// It returns the lists of txs which got >2/3+ YES, NO and UNSPECIFIED votes respectively
329-
func tallyVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, logger log.Logger, totalVotingPower int64, currentHeight int64) ([][]byte, [][]byte, [][]byte, error) {
351+
func tallyVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, logger log.Logger, validatorSet *stakeTypes.ValidatorSet, currentHeight int64) ([][]byte, [][]byte, [][]byte, error) {
330352
logger.Debug("Tallying votes")
331353

332-
voteByTxHash, err := aggregateVotes(extVoteInfo, currentHeight, logger)
354+
// Always derive total voting power from the canonical validator set
355+
totalVotingPower := validatorSet.GetTotalVotingPower()
356+
357+
voteByTxHash, err := aggregateVotes(extVoteInfo, validatorSet, currentHeight, logger)
333358
if err != nil {
334359
return nil, nil, nil, err
335360
}
@@ -386,11 +411,13 @@ func tallyVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, logger log.Logger, tot
386411
}
387412

388413
// aggregateVotes collates votes received for side txs
389-
func aggregateVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, currentHeight int64, logger log.Logger) (map[string]map[sidetxs.Vote]int64, error) {
414+
func aggregateVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, validatorSet *stakeTypes.ValidatorSet, currentHeight int64, logger log.Logger) (map[string]map[sidetxs.Vote]int64, error) {
390415
voteByTxHash := make(map[string]map[sidetxs.Vote]int64) // track votes for a side tx
391416
validatorToTxMap := make(map[string]map[string]struct{}) // ensure a validator doesn't procure conflicting votes for a side tx
392417
var blockHash []byte // store the block hash to make sure all votes are for the same block
393418

419+
ac := address.HexCodec{}
420+
394421
for _, vote := range extVoteInfo {
395422
// make sure the BlockIdFlag is valid
396423
if !isBlockIdFlagValid(vote.BlockIdFlag) {
@@ -402,8 +429,7 @@ func aggregateVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, currentHeight int6
402429
}
403430

404431
ve := new(sidetxs.VoteExtension)
405-
err := ve.Unmarshal(vote.VoteExtension)
406-
if err != nil {
432+
if err := ve.Unmarshal(vote.VoteExtension); err != nil {
407433
return nil, err
408434
}
409435

@@ -416,7 +442,6 @@ func aggregateVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, currentHeight int6
416442
// store the block hash from the first vote
417443
blockHash = ve.BlockHash
418444
} else {
419-
ac := address.HexCodec{}
420445
valAddr, err := ac.BytesToString(vote.Validator.Address)
421446
if err != nil {
422447
return nil, err
@@ -431,11 +456,20 @@ func aggregateVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, currentHeight int6
431456
}
432457
}
433458

434-
addr, err := address.NewHexCodec().BytesToString(vote.Validator.Address)
459+
addr, err := ac.BytesToString(vote.Validator.Address)
435460
if err != nil {
436461
return nil, err
437462
}
438463

464+
// Look up canonical validator and voting power (don't trust the power carried in ExtendedCommitInfo)
465+
_, validator := validatorSet.GetByAddress(addr)
466+
if validator == nil {
467+
logger.Error(
468+
"validator from vote extension not found in canonical validator set", "validator", addr, "height", currentHeight)
469+
continue
470+
}
471+
canonicalPower := validator.VotingPower
472+
439473
if validatorToTxMap[addr] != nil {
440474
return nil, fmt.Errorf("duplicate vote received from %s", addr)
441475
}
@@ -459,7 +493,8 @@ func aggregateVotes(extVoteInfo []abciTypes.ExtendedVoteInfo, currentHeight int6
459493
voteByTxHash[txHashStr] = make(map[sidetxs.Vote]int64)
460494
}
461495

462-
voteByTxHash[txHashStr][res.Result] += vote.Validator.Power
496+
// use canonical power from the validator set
497+
voteByTxHash[txHashStr][res.Result] += canonicalPower
463498

464499
// validator's vote received; mark it to avoid duplicated votes
465500
validatorToTxMap[addr][txHashStr] = struct{}{}

0 commit comments

Comments
 (0)