Skip to content

Commit

Permalink
light-client-verifier: reuse sign_bytes buffer (#1413)
Browse files Browse the repository at this point in the history
  • Loading branch information
mina86 authored Apr 23, 2024
1 parent 979456c commit 38a067c
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 4 deletions.
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

0 comments on commit 38a067c

Please sign in to comment.