diff --git a/client/finality-grandpa/src/communication/mod.rs b/client/finality-grandpa/src/communication/mod.rs index 7723047d1b423..5077d435e8550 100644 --- a/client/finality-grandpa/src/communication/mod.rs +++ b/client/finality-grandpa/src/communication/mod.rs @@ -600,8 +600,28 @@ impl> Clone for NetworkBridge { } } -pub(crate) fn localized_payload(round: RoundNumber, set_id: SetIdNumber, message: &E) -> Vec { - (message, round, set_id).encode() +/// Encode round message localized to a given round and set id. +pub(crate) fn localized_payload( + round: RoundNumber, + set_id: SetIdNumber, + message: &E, +) -> Vec { + let mut buf = Vec::new(); + localized_payload_with_buffer(round, set_id, message, &mut buf); + buf +} + +/// Encode round message localized to a given round and set id using the given +/// buffer. The given buffer will be cleared and the resulting encoded payload +/// will always be written to the start of the buffer. +pub(crate) fn localized_payload_with_buffer( + round: RoundNumber, + set_id: SetIdNumber, + message: &E, + buf: &mut Vec, +) { + buf.clear(); + (message, round, set_id).encode_to(buf) } /// Type-safe wrapper around a round number. @@ -612,17 +632,41 @@ pub struct Round(pub RoundNumber); #[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Encode, Decode)] pub struct SetId(pub SetIdNumber); -// check a message. +/// Check a message signature by encoding the message as a localized payload and +/// verifying the provided signature using the expected authority id. pub(crate) fn check_message_sig( message: &Message, id: &AuthorityId, signature: &AuthoritySignature, round: RoundNumber, set_id: SetIdNumber, +) -> Result<(), ()> { + check_message_sig_with_buffer::( + message, + id, + signature, + round, + set_id, + &mut Vec::new(), + ) +} + +/// Check a message signature by encoding the message as a localized payload and +/// verifying the provided signature using the expected authority id. +/// The encoding necessary to verify the signature will be done using the given +/// buffer, the original content of the buffer will be cleared. +pub(crate) fn check_message_sig_with_buffer( + message: &Message, + id: &AuthorityId, + signature: &AuthoritySignature, + round: RoundNumber, + set_id: SetIdNumber, + buf: &mut Vec, ) -> Result<(), ()> { let as_public = id.clone(); - let encoded_raw = localized_payload(round, set_id, message); - if AuthorityPair::verify(signature, &encoded_raw, &as_public) { + localized_payload_with_buffer(round, set_id, message, buf); + + if AuthorityPair::verify(signature, buf, &as_public) { Ok(()) } else { debug!(target: "afg", "Bad signature on message from {:?}", id); @@ -752,6 +796,7 @@ fn check_compact_commit( } // check signatures on all contained precommits. + let mut buf = Vec::new(); for (i, (precommit, &(ref sig, ref id))) in msg.precommits.iter() .zip(&msg.auth_data) .enumerate() @@ -759,12 +804,13 @@ fn check_compact_commit( use crate::communication::gossip::Misbehavior; use finality_grandpa::Message as GrandpaMessage; - if let Err(()) = check_message_sig::( + if let Err(()) = check_message_sig_with_buffer::( &GrandpaMessage::Precommit(precommit.clone()), id, sig, round.0, set_id.0, + &mut buf, ) { debug!(target: "afg", "Bad commit message signature {}", id); telemetry!(CONSENSUS_DEBUG; "afg.bad_commit_msg_signature"; "id" => ?id); @@ -836,6 +882,7 @@ fn check_catch_up( round: RoundNumber, set_id: SetIdNumber, mut signatures_checked: usize, + buf: &mut Vec, ) -> Result where B: BlockT, I: Iterator, &'a AuthorityId, &'a AuthoritySignature)>, @@ -845,12 +892,13 @@ fn check_catch_up( for (msg, id, sig) in messages { signatures_checked += 1; - if let Err(()) = check_message_sig::( + if let Err(()) = check_message_sig_with_buffer::( &msg, id, sig, round, set_id, + buf, ) { debug!(target: "afg", "Bad catch up message signature {}", id); telemetry!(CONSENSUS_DEBUG; "afg.bad_catch_up_msg_signature"; "id" => ?id); @@ -866,6 +914,8 @@ fn check_catch_up( Ok(signatures_checked) } + let mut buf = Vec::new(); + // check signatures on all contained prevotes. let signatures_checked = check_signatures::( msg.prevotes.iter().map(|vote| { @@ -874,6 +924,7 @@ fn check_catch_up( msg.round_number, set_id.0, 0, + &mut buf, )?; // check signatures on all contained precommits. @@ -884,6 +935,7 @@ fn check_catch_up( msg.round_number, set_id.0, signatures_checked, + &mut buf, )?; Ok(()) diff --git a/client/finality-grandpa/src/justification.rs b/client/finality-grandpa/src/justification.rs index 308056725f67b..ad96956454fd7 100644 --- a/client/finality-grandpa/src/justification.rs +++ b/client/finality-grandpa/src/justification.rs @@ -132,14 +132,16 @@ impl GrandpaJustification { } } + let mut buf = Vec::new(); let mut visited_hashes = HashSet::new(); for signed in self.commit.precommits.iter() { - if let Err(_) = communication::check_message_sig::( + if let Err(_) = communication::check_message_sig_with_buffer::( &finality_grandpa::Message::Precommit(signed.precommit.clone()), &signed.id, &signed.signature, self.round, set_id, + &mut buf, ) { return Err(ClientError::BadJustification( "invalid signature for precommit in grandpa justification".to_string()).into());