-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Cache commit votes received for future rounds in the buffer manager #14570
Conversation
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
||
// If the buffer manager receives a commit vote for a block that is not in buffer items, then | ||
// the vote will be cached. We can cache upto 30 blocks, and upto 150 commit votes per block. | ||
pending_commit_votes: LruCache<HashValue, Vec<CommitVote>>, |
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.
this is not ideal, it's not ddos safe. a single malicious validator can flush all useful pending votes. we should maintain something similar to the PendingVote structure that only allows one vote per author.
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.
Done.
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 don't think this works as expected, a single malicious author can still send CommitVote for 30 fake blocks to occupy the whole cache
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.
Good point. Implemented a different eviction mechanism now.
If the number of blocks in pending_commit_votes exceeds 50, then out of all the blocks that were last accessed more than 100ms ago, I remove one block with least voting power.
What do you think?
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.
the invariant we want to maintain is very simple - every author can only have one vote per round and we don't cache rounds that are too far. we just need to maintain a map from round -> pending votes, and each round we only allow author to have one vote. it's basically a subset of the existing PendingVotes structure.
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.
Yes. The current code allows only one vote per author per block.
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 don't see how the current code prevents one author to have multiple fake blocks per round that push every other blocks out
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.
For each block, we store HashMap<AccountAddress, CommitVote>
. So, we can store only one commit vote per author.
In order to protect against malicious authors, we won't evict any block if its last accessed timestamp is within 100ms. When there is a need for eviction, out of all the blocks that were last accessed more than 100ms ago, we evict the blocks with least voting power. So, most likely the malicious authors' blocks will be evicted.
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.
this doesn't prevent a malicious author to submit millions of blocks to OOM the node since there's no limit of how many blocks it can vote for. as I said above, I think the simple way is to maintain a map of round -> pending votes that only allows one vote per author.
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.
Done.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
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.
LGTM except one small comment
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
.epoch_state | ||
.verifier | ||
.get_voting_power(&vote.author()) | ||
.is_some() |
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 don't think we need this given that the signature was verified (it can't verify without being in the validator set)?
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.
The commit vote verification checks that the address is in validator set, but doesn't check it has non zero voting power. But checking for non zero voting power just seems a minor check that can be removed.
With optimistic signature verification, the commit votes won't be verified. So, we will have to put check again to avoid OOM attacks.
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.
what does optimistic verification have to do with this? we only allow one vote per author per round regardless of signature?
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.
But what if a malicious party submits many votes under different author names who either don't exist in ValidatorVerifier or has a zero voting power? That will be an OOM attack vector too?
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.
good point, we should have the check that the sender matches the declared author field, the network link is encrypted with noise handshake and the key is on-chain. so after we move to optimistic verification, we can add the sender check here
aptos-core/consensus/src/network.rs
Line 720 in 6a71f18
ConsensusMsg::CommitVoteMsg(commit_vote) => { |
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.
Removed the check and simplified the if else statement.
} else { | ||
let mut votes = HashMap::new(); | ||
votes.insert(vote.author(), vote); | ||
self.pending_commit_votes.insert(round, votes); |
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.
this whole block can be just self.pending_commit_votes.entry(round).or_insert(..).insert(author, vote)
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.
Done.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
✅ Forge suite
|
✅ Forge suite
|
This comment has been minimized.
This comment has been minimized.
✅ Forge suite
|
Description
When the buffer manager receives a commit vote, but the block is not stored in the buffer items, we cache the commit votes and use those votes when the block is added to the buffer manager.
Type of Change
Which Components or Systems Does This Change Impact?
How Has This Been Tested?
Key Areas to Review
Checklist