-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(baseapp): Utilizing voting power from VEs in ValidateVoteExtensions #17518
Changes from 5 commits
fdd0c10
0326838
f5d0bf2
cd4b843
e1adb6a
cb1648c
dc416ce
f1ef63d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,6 @@ type ( | |
// extension signatures. Typically, this will be implemented by the x/staking | ||
// module, which has knowledge of the CometBFT public key. | ||
ValidatorStore interface { | ||
TotalBondedTokens(ctx context.Context) (math.Int, error) | ||
BondedTokensAndPubKeyByConsAddr(context.Context, sdk.ConsAddress) (math.Int, cmtprotocrypto.PublicKey, error) | ||
} | ||
|
||
|
@@ -62,8 +61,16 @@ func ValidateVoteExtensions( | |
return buf.Bytes(), nil | ||
} | ||
|
||
sumVP := math.NewInt(0) | ||
var ( | ||
// Total voting power of all vote extensions. | ||
totalVP int64 | ||
// Total voting power of all validators that submitted valid vote extensions. | ||
sumVP int64 | ||
) | ||
|
||
for _, vote := range extCommit.Votes { | ||
totalVP += vote.Validator.Power | ||
|
||
// Only check + include power if the vote is a commit vote. There must be super-majority, otherwise the | ||
// previous block (the block vote is for) could not have been committed. | ||
if vote.BlockIdFlag != cmtproto.BlockIDFlagCommit { | ||
|
@@ -86,7 +93,7 @@ func ValidateVoteExtensions( | |
} | ||
|
||
valConsAddr := sdk.ConsAddress(vote.Validator.Address) | ||
bondedTokens, cmtPubKeyProto, err := valStore.BondedTokensAndPubKeyByConsAddr(ctx, valConsAddr) | ||
_, cmtPubKeyProto, err := valStore.BondedTokensAndPubKeyByConsAddr(ctx, valConsAddr) | ||
if err != nil { | ||
return fmt.Errorf("failed to get validator %X info (bonded tokens and public key): %w", valConsAddr, err) | ||
} | ||
|
@@ -112,19 +119,14 @@ func ValidateVoteExtensions( | |
return fmt.Errorf("failed to verify validator %X vote extension signature", valConsAddr) | ||
} | ||
|
||
sumVP = sumVP.Add(bondedTokens) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is such a footgun. bondedTokens is actually useless in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea wasn't sure if updating the staking keeper's There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
sumVP += vote.Validator.Power | ||
} | ||
|
||
// Ensure we have at least 2/3 voting power that submitted valid vote | ||
// extensions. | ||
totalVP, err := valStore.TotalBondedTokens(ctx) | ||
if err != nil { | ||
return fmt.Errorf("failed to get total bonded tokens: %w", err) | ||
} | ||
|
||
percentSubmitted := math.LegacyNewDecFromInt(sumVP).Quo(math.LegacyNewDecFromInt(totalVP)) | ||
if percentSubmitted.LT(VoteExtensionThreshold) { | ||
return fmt.Errorf("insufficient cumulative voting power received to verify vote extensions; got: %s, expected: >=%s", percentSubmitted, VoteExtensionThreshold) | ||
if totalVP > 0 { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not sure if this should ever be possible, but adding this as a sanity check. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. its totalVP a signed integer? lmfao 🤣 I'd flip the logic around, personally. <= 0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. lol better safe than sorry... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. kek |
||
percentSubmitted := math.LegacyNewDecFromInt(math.NewInt(sumVP)).Quo(math.LegacyNewDecFromInt(math.NewInt(totalVP))) | ||
if percentSubmitted.LT(VoteExtensionThreshold) { | ||
return fmt.Errorf("insufficient cumulative voting power received to verify vote extensions; got: %s, expected: >=%s", percentSubmitted, VoteExtensionThreshold) | ||
} | ||
} | ||
|
||
return nil | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we actually need to ignore the value, we should delete this method from x/staking and update the ValidatorStore interface.
It was added recently and has never been released (see #17164).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea agreed, though I think we should think in more detail around the footgun of CometBFT power vs whats int he staking module being different and either document the weirdness or define access patterns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto. Let's address this @davidterpay and we can merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll add some docs on why we are utilizing the voting power on
CometBFT
instead of most recent bonded tokens on base app. But at a high level, liveness of the network is dependent on the consensus power each validator has as derived by base app. But this voting power has a delay in terms of relaying toCometBFT
. What this means is that for vote extensions to be in sync with the underlying consensus engine, they should default to voting power from the VEs themselves - not from baseapp at the current block. Otherwise you have liveness issues.Copying this over from the open issue related to this.
Say there are two validators in the network, val1 and val2:
Block H - 1:
Only val1 signs off on block H - 1 which constitutes a valid block (> 2/3+). In block H-1, there is a redelegation transaction that moves 30 voting power from val1 to val2.
Block H:
Within
ValidateVoteExtensions
,When validate vote extensions is called in prepare/process proposal, it will see that Val1 only has a voting power of 50 and will reject the set of vote extensions (even though it should still be 80 since this is what comet is utilizing).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think this should be added to the ADR or within the code itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say both 😬 or link the ADR in the code for explanation.