diff --git a/substrate/abi/src/transaction.rs b/substrate/abi/src/transaction.rs index dfc84f50..be2cd691 100644 --- a/substrate/abi/src/transaction.rs +++ b/substrate/abi/src/transaction.rs @@ -252,35 +252,7 @@ mod substrate { } impl Decode for Transaction { fn decode(input: &mut I) -> Result { - struct ScaleRead<'a, I: scale::Input>(&'a mut I, Option); - impl borsh::io::Read for ScaleRead<'_, I> { - fn read(&mut self, buf: &mut [u8]) -> borsh::io::Result { - let remaining_len = self.0.remaining_len().map_err(|err| { - self.1 = Some(err); - #[allow(clippy::io_other_error)] - borsh::io::Error::new(borsh::io::ErrorKind::Other, "") - })?; - // If we're still calling `read`, we try to read at least one more byte - let to_read = buf.len().min(remaining_len.unwrap_or(1)); - // This may not be _allocated_ making this over-zealous, but it's the best we can do - self.0.on_before_alloc_mem(to_read).map_err(|err| { - self.1 = Some(err); - #[allow(clippy::io_other_error)] - borsh::io::Error::new(borsh::io::ErrorKind::Other, "") - })?; - self.0.read(&mut buf[.. to_read]).map_err(|err| { - self.1 = Some(err); - #[allow(clippy::io_other_error)] - borsh::io::Error::new(borsh::io::ErrorKind::Other, "") - })?; - Ok(to_read) - } - } - let mut input = ScaleRead(input, None); - match Self::deserialize_reader(&mut input) { - Ok(res) => Ok(res), - Err(_) => Err(input.1.unwrap()), - } + serai_primitives::read_scale_as_borsh(input) } } diff --git a/substrate/abi/src/validator_sets.rs b/substrate/abi/src/validator_sets.rs index 5ed222d3..73f467fc 100644 --- a/substrate/abi/src/validator_sets.rs +++ b/substrate/abi/src/validator_sets.rs @@ -1,9 +1,7 @@ use borsh::{BorshSerialize, BorshDeserialize}; -use sp_core::{ConstU32, bounded::BoundedVec}; - use serai_primitives::{ - crypto::{ExternalKey, EmbeddedEllipticCurveKeys, KeyPair, Signature}, + crypto::{SignedEmbeddedEllipticCurveKeys, KeyPair, Signature}, address::SeraiAddress, balance::Amount, network_id::*, @@ -40,14 +38,8 @@ pub enum Call { }, /// Set a validator's keys on embedded elliptic curves for a specific network. set_embedded_elliptic_curve_keys { - /// The network the origin is setting their embedded elliptic curve keys for. - network: ExternalNetworkId, /// The keys on the embedded elliptic curves. - #[borsh( - serialize_with = "serai_primitives::sp_borsh::borsh_serialize_bounded_vec", - deserialize_with = "serai_primitives::sp_borsh::borsh_deserialize_bounded_vec" - )] - keys: EmbeddedEllipticCurveKeys, + keys: SignedEmbeddedEllipticCurveKeys, }, /// Allocate stake to a network. allocate { diff --git a/substrate/primitives/src/crypto.rs b/substrate/primitives/src/crypto.rs index c60b322d..a3df8cbf 100644 --- a/substrate/primitives/src/crypto.rs +++ b/substrate/primitives/src/crypto.rs @@ -1,5 +1,5 @@ use zeroize::Zeroize; -use borsh::{BorshSerialize, BorshDeserialize}; +use borsh::{io, BorshSerialize, BorshDeserialize}; use sp_core::{ConstU32, bounded::BoundedVec}; @@ -137,30 +137,54 @@ impl EmbeddedEllipticCurveKeys { } } -#[cfg(feature = "non_canonical_scale_derivations")] -impl scale::Encode for EmbeddedEllipticCurveKeys { - fn using_encoded R>(&self, f: F) -> R { +impl BorshSerialize for EmbeddedEllipticCurveKeys { + fn serialize(&self, writer: &mut W) -> io::Result<()> { match self { EmbeddedEllipticCurveKeys::Bitcoin(e, s) | EmbeddedEllipticCurveKeys::Ethereum(e, s) => { - let mut res = [0; 66]; + let mut res = [0; 1 + 32 + 33]; res[0] = self.network() as u8; res[1 .. 33].copy_from_slice(e); res[33 ..].copy_from_slice(s); - f(&res) + writer.write_all(&res) } EmbeddedEllipticCurveKeys::Monero(e) => { - let mut res = [0; 33]; + let mut res = [0; 1 + 32]; res[0] = self.network() as u8; res[1 ..].copy_from_slice(e); - f(&res) + writer.write_all(&res) } } } } + +impl BorshDeserialize for EmbeddedEllipticCurveKeys { + fn deserialize_reader(reader: &mut R) -> io::Result { + let network_id = ExternalNetworkId::deserialize_reader(&mut *reader)?; + let embedwards25519 = <[u8; 32]>::deserialize_reader(&mut *reader)?; + Ok(match network_id { + ExternalNetworkId::Bitcoin => { + let secq256k1 = <[u8; 33]>::deserialize_reader(&mut *reader)?; + EmbeddedEllipticCurveKeys::Bitcoin(embedwards25519, secq256k1.into()) + } + ExternalNetworkId::Ethereum => { + let secq256k1 = <[u8; 33]>::deserialize_reader(&mut *reader)?; + EmbeddedEllipticCurveKeys::Ethereum(embedwards25519, secq256k1.into()) + } + ExternalNetworkId::Monero => EmbeddedEllipticCurveKeys::Monero(embedwards25519), + }) + } +} + +#[cfg(feature = "non_canonical_scale_derivations")] +impl scale::Encode for EmbeddedEllipticCurveKeys { + fn using_encoded R>(&self, f: F) -> R { + f(&borsh::to_vec(self).unwrap()) + } +} #[cfg(feature = "non_canonical_scale_derivations")] impl scale::MaxEncodedLen for EmbeddedEllipticCurveKeys { fn max_encoded_len() -> usize { - 66 + 1 + 32 + 33 } } #[cfg(feature = "non_canonical_scale_derivations")] @@ -168,20 +192,7 @@ impl scale::EncodeLike for EmbeddedEllipticCurveKeys #[cfg(feature = "non_canonical_scale_derivations")] impl scale::Decode for EmbeddedEllipticCurveKeys { fn decode(input: &mut I) -> Result { - let network_id = ExternalNetworkId::decode(&mut *input)?; - let embedwards25519 = - <::G as GroupEncoding>::Repr::decode(&mut *input)?; - Ok(match network_id { - ExternalNetworkId::Bitcoin => { - let secq256k1 = <[u8; 33]>::decode(&mut *input)?; - EmbeddedEllipticCurveKeys::Bitcoin(embedwards25519, secq256k1.into()) - } - ExternalNetworkId::Ethereum => { - let secq256k1 = <[u8; 33]>::decode(&mut *input)?; - EmbeddedEllipticCurveKeys::Ethereum(embedwards25519, secq256k1.into()) - } - ExternalNetworkId::Monero => EmbeddedEllipticCurveKeys::Monero(embedwards25519), - }) + crate::read_scale_as_borsh(input) } } #[cfg(feature = "non_canonical_scale_derivations")] @@ -284,40 +295,37 @@ impl SignedEmbeddedEllipticCurveKeys { } } -#[cfg(feature = "non_canonical_scale_derivations")] -impl scale::Encode for SignedEmbeddedEllipticCurveKeys { - fn using_encoded R>(&self, f: F) -> R { +impl BorshSerialize for SignedEmbeddedEllipticCurveKeys { + fn serialize(&self, writer: &mut W) -> io::Result<()> { match self { SignedEmbeddedEllipticCurveKeys::Bitcoin(e, s, e_sig, s_sig) | SignedEmbeddedEllipticCurveKeys::Ethereum(e, s, e_sig, s_sig) => { - let mut res = [0; 195]; + let mut res = [0; 1 + 32 + 33 + 32 + 32 + 33 + 32]; res[0] = self.network() as u8; res[1 .. 33].copy_from_slice(e); res[33 .. 66].copy_from_slice(s); res[66 .. 130].copy_from_slice(e_sig); res[130 ..].copy_from_slice(s_sig); - f(&res) + writer.write_all(&res) } SignedEmbeddedEllipticCurveKeys::Monero(e, e_sig) => { - let mut res = [0; 97]; + let mut res = [0; 1 + 32 + 32 + 32]; res[0] = self.network() as u8; res[1 .. 33].copy_from_slice(e); res[33 ..].copy_from_slice(e_sig); - f(&res) + writer.write_all(&res) } } } } -#[cfg(feature = "non_canonical_scale_derivations")] -impl scale::EncodeLike for SignedEmbeddedEllipticCurveKeys {} -#[cfg(feature = "non_canonical_scale_derivations")] -impl scale::Decode for SignedEmbeddedEllipticCurveKeys { - fn decode(input: &mut I) -> Result { - let embedded_elliptic_curve_keys = EmbeddedEllipticCurveKeys::decode(input)?; - let embedwards25519_signature = <[u8; 64]>::decode(&mut *input)?; + +impl BorshDeserialize for SignedEmbeddedEllipticCurveKeys { + fn deserialize_reader(reader: &mut R) -> io::Result { + let embedded_elliptic_curve_keys = EmbeddedEllipticCurveKeys::deserialize_reader(&mut *reader)?; + let embedwards25519_signature = <[u8; 64]>::deserialize_reader(&mut *reader)?; Ok(match embedded_elliptic_curve_keys { EmbeddedEllipticCurveKeys::Bitcoin(e, s) => { - let secq256k1_signature = <[u8; 65]>::decode(&mut *input)?; + let secq256k1_signature = <[u8; 65]>::deserialize_reader(&mut *reader)?; SignedEmbeddedEllipticCurveKeys::Bitcoin( e, s, @@ -326,7 +334,7 @@ impl scale::Decode for SignedEmbeddedEllipticCurveKeys { ) } EmbeddedEllipticCurveKeys::Ethereum(e, s) => { - let secq256k1_signature = <[u8; 65]>::decode(&mut *input)?; + let secq256k1_signature = <[u8; 65]>::deserialize_reader(&mut *reader)?; SignedEmbeddedEllipticCurveKeys::Ethereum( e, s, @@ -340,6 +348,21 @@ impl scale::Decode for SignedEmbeddedEllipticCurveKeys { }) } } + +#[cfg(feature = "non_canonical_scale_derivations")] +impl scale::Encode for SignedEmbeddedEllipticCurveKeys { + fn using_encoded R>(&self, f: F) -> R { + f(&borsh::to_vec(self).unwrap()) + } +} +#[cfg(feature = "non_canonical_scale_derivations")] +impl scale::EncodeLike for SignedEmbeddedEllipticCurveKeys {} +#[cfg(feature = "non_canonical_scale_derivations")] +impl scale::Decode for SignedEmbeddedEllipticCurveKeys { + fn decode(input: &mut I) -> Result { + crate::read_scale_as_borsh(input) + } +} #[cfg(feature = "non_canonical_scale_derivations")] impl scale::DecodeWithMemTracking for SignedEmbeddedEllipticCurveKeys {} diff --git a/substrate/primitives/src/lib.rs b/substrate/primitives/src/lib.rs index da9f531b..c321b77b 100644 --- a/substrate/primitives/src/lib.rs +++ b/substrate/primitives/src/lib.rs @@ -102,3 +102,39 @@ pub mod prelude { pub use crate::validator_sets::{Session, ValidatorSet, ExternalValidatorSet, Slash, SlashReport}; pub use crate::instructions::*; } + +#[doc(hidden)] +#[cfg(feature = "non_canonical_scale_derivations")] +pub fn read_scale_as_borsh( + input: &mut I, +) -> Result { + struct ScaleRead<'a, I: scale::Input>(&'a mut I, Option); + impl borsh::io::Read for ScaleRead<'_, I> { + fn read(&mut self, buf: &mut [u8]) -> borsh::io::Result { + let remaining_len = self.0.remaining_len().map_err(|err| { + self.1 = Some(err); + #[allow(clippy::io_other_error)] + borsh::io::Error::new(borsh::io::ErrorKind::Other, "") + })?; + // If we're still calling `read`, we try to read at least one more byte + let to_read = buf.len().min(remaining_len.unwrap_or(1)); + // This may not be _allocated_ making this over-zealous, but it's the best we can do + self.0.on_before_alloc_mem(to_read).map_err(|err| { + self.1 = Some(err); + #[allow(clippy::io_other_error)] + borsh::io::Error::new(borsh::io::ErrorKind::Other, "") + })?; + self.0.read(&mut buf[.. to_read]).map_err(|err| { + self.1 = Some(err); + #[allow(clippy::io_other_error)] + borsh::io::Error::new(borsh::io::ErrorKind::Other, "") + })?; + Ok(to_read) + } + } + let mut input = ScaleRead(input, None); + match T::deserialize_reader(&mut input) { + Ok(res) => Ok(res), + Err(_) => Err(input.1.unwrap()), + } +}