Skip to content
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

light-client-verifier: reuse sign_bytes buffer #1413

Merged
merged 3 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/unreleased/improvements/1413-reuse-sign-bytes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- `[tendermint-light-client-verifier]` Reuse buffer used to store
sign_bytes to reduce number of allocations and deallocations.
([\#1413](https://github.com/informalsystems/tendermint-rs/pull/1413))
32 changes: 28 additions & 4 deletions light-client-verifier/src/operations/voting_power.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,9 +264,26 @@ impl NonAbsentCommitVote {
struct NonAbsentCommitVotes {
/// Votes sorted by validator address.
votes: Vec<NonAbsentCommitVote>,
/// Internal buffer for storing sign_bytes.
///
/// The buffer is reused for each canonical vote so that we allocate it
/// once.
sign_bytes: Vec<u8>,
}

impl NonAbsentCommitVotes {
/// Initial capacity of the `sign_bytes` buffer.
///
/// The buffer will be resized if it happens to be too small so this value
/// isn’t critical for correctness. It’s a matter of performance to avoid
/// reallocations.
///
/// Note: As of protocol 0.38, maximum length of the sign bytes is `115 + (N
/// > 13) + N` where `N` is the length of the chain id. Chain id can be at
/// most 50 bytes (see [`tendermint::chain::id::MAX_LEN`]) thus the largest
/// buffer we’ll ever need is 166 bytes long.
const SIGN_BYTES_INITIAL_CAPACITY: usize = 166;

pub fn new(signed_header: &SignedHeader) -> Result<Self, VerificationError> {
let mut votes = signed_header
.commit
Expand Down Expand Up @@ -297,7 +314,10 @@ impl NonAbsentCommitVotes {
pair[0].validator_id(),
))
} else {
Ok(Self { votes })
Ok(Self {
votes,
sign_bytes: Vec::with_capacity(Self::SIGN_BYTES_INITIAL_CAPACITY),
})
}
}

Expand All @@ -319,14 +339,18 @@ impl NonAbsentCommitVotes {
};

if !vote.verified {
let sign_bytes = vote.signed_vote.sign_bytes();
self.sign_bytes.truncate(0);
vote.signed_vote
.sign_bytes_into(&mut self.sign_bytes)
.expect("buffer is resized if needed and encoding never fails");
let sign_bytes = self.sign_bytes.as_slice();
validator
.verify_signature::<V>(&sign_bytes, vote.signed_vote.signature())
.verify_signature::<V>(sign_bytes, vote.signed_vote.signature())
.map_err(|_| {
VerificationError::invalid_signature(
vote.signed_vote.signature().as_bytes().to_vec(),
Box::new(validator.clone()),
sign_bytes,
sign_bytes.to_vec(),
)
})?;
}
Expand Down
4 changes: 4 additions & 0 deletions tendermint/src/vote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ impl SignedVote {
Protobuf::<RawCanonicalVote>::encode_length_delimited_vec(self.vote.clone())
}

pub fn sign_bytes_into(&self, buf: &mut impl BufMut) -> Result<(), ProtobufError> {
Protobuf::<RawCanonicalVote>::encode_length_delimited(self.vote.clone(), buf)
}

/// Return the actual signature on the canonicalized vote.
pub fn signature(&self) -> &Signature {
&self.signature
Expand Down
Loading