diff --git a/coordinator/Cargo.toml b/coordinator/Cargo.toml index 6a1c90877..7a771140f 100644 --- a/coordinator/Cargo.toml +++ b/coordinator/Cargo.toml @@ -37,7 +37,7 @@ message-queue = { package = "serai-message-queue", path = "../message-queue" } tributary = { package = "tributary-chain", path = "./tributary" } sp-application-crypto = { git = "https://github.com/serai-dex/substrate", default-features = false, features = ["std"] } -serai-client = { path = "../substrate/client", default-features = false, features = ["serai"] } +serai-client = { path = "../substrate/client", default-features = false, features = ["serai", "borsh"] } hex = { version = "0.4", default-features = false, features = ["std"] } borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] } diff --git a/coordinator/src/db.rs b/coordinator/src/db.rs index 560946bc9..9e0c5d919 100644 --- a/coordinator/src/db.rs +++ b/coordinator/src/db.rs @@ -4,6 +4,7 @@ use blake2::{ }; use scale::Encode; +use borsh::{BorshSerialize, BorshDeserialize}; use serai_client::{ primitives::NetworkId, validator_sets::primitives::{Session, ValidatorSet}, @@ -43,7 +44,7 @@ impl ActiveTributaryDb { let mut tributaries = vec![]; while !bytes_ref.is_empty() { - tributaries.push(TributarySpec::read(&mut bytes_ref).unwrap()); + tributaries.push(TributarySpec::deserialize_reader(&mut bytes_ref).unwrap()); } (bytes, tributaries) @@ -57,7 +58,7 @@ impl ActiveTributaryDb { } } - spec.write(&mut existing_bytes).unwrap(); + spec.serialize(&mut existing_bytes).unwrap(); ActiveTributaryDb::set(txn, &existing_bytes); } @@ -72,7 +73,7 @@ impl ActiveTributaryDb { let mut bytes = vec![]; for active in active { - active.write(&mut bytes).unwrap(); + active.serialize(&mut bytes).unwrap(); } Self::set(txn, &bytes); RetiredTributaryDb::set(txn, set, &()); diff --git a/coordinator/src/tests/tributary/chain.rs b/coordinator/src/tests/tributary/chain.rs index a3ad05d2c..8f8c34c29 100644 --- a/coordinator/src/tests/tributary/chain.rs +++ b/coordinator/src/tests/tributary/chain.rs @@ -13,7 +13,7 @@ use ciphersuite::{ }; use sp_application_crypto::sr25519; - +use borsh::BorshDeserialize; use serai_client::{ primitives::NetworkId, validator_sets::primitives::{Session, ValidatorSet}, @@ -58,7 +58,10 @@ pub fn new_spec( .collect::>(); let res = TributarySpec::new(serai_block, start_time, set, set_participants); - assert_eq!(TributarySpec::read::<&[u8]>(&mut res.serialize().as_ref()).unwrap(), res); + assert_eq!( + TributarySpec::deserialize_reader(&mut borsh::to_vec(&res).unwrap().as_slice()).unwrap(), + res, + ); res } diff --git a/coordinator/src/tributary/mod.rs b/coordinator/src/tributary/mod.rs index e1dd90d5d..c82048efa 100644 --- a/coordinator/src/tributary/mod.rs +++ b/coordinator/src/tributary/mod.rs @@ -2,7 +2,7 @@ use core::{ ops::{Deref, Range}, fmt::Debug, }; -use std::io::{self, Read, Write}; +use std::io; use zeroize::Zeroizing; use rand_core::{RngCore, CryptoRng}; @@ -18,12 +18,10 @@ use schnorr::SchnorrSignature; use frost::Participant; use scale::{Encode, Decode}; +use borsh::{BorshSerialize, BorshDeserialize}; use processor_messages::coordinator::SubstrateSignableId; -use serai_client::{ - primitives::{NetworkId, PublicKey}, - validator_sets::primitives::{Session, ValidatorSet}, -}; +use serai_client::{primitives::PublicKey, validator_sets::primitives::ValidatorSet}; use tributary::{ ReadWrite, @@ -41,11 +39,43 @@ pub use handle::*; pub mod scanner; -#[derive(Clone, PartialEq, Eq, Debug)] +fn borsh_serialize_validators( + validators: &Vec<(::G, u16)>, + writer: &mut W, +) -> Result<(), io::Error> { + let len = u16::try_from(validators.len()).unwrap(); + BorshSerialize::serialize(&len, writer)?; + for validator in validators { + BorshSerialize::serialize(&validator.0.to_bytes(), writer)?; + BorshSerialize::serialize(&validator.1, writer)?; + } + Ok(()) +} + +fn borsh_deserialize_validators( + reader: &mut R, +) -> Result::G, u16)>, io::Error> { + let len: u16 = BorshDeserialize::deserialize_reader(reader)?; + let mut res = vec![]; + for _ in 0 .. len { + let compressed: [u8; 32] = BorshDeserialize::deserialize_reader(reader)?; + let point = Option::from(::G::from_bytes(&compressed)) + .ok_or_else(|| io::Error::other("invalid point for validator"))?; + let weight: u16 = BorshDeserialize::deserialize_reader(reader)?; + res.push((point, weight)); + } + Ok(res) +} + +#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] pub struct TributarySpec { serai_block: [u8; 32], start_time: u64, set: ValidatorSet, + #[borsh( + serialize_with = "borsh_serialize_validators", + deserialize_with = "borsh_deserialize_validators" + )] validators: Vec<(::G, u16)>, } @@ -111,59 +141,6 @@ impl TributarySpec { pub fn validators(&self) -> Vec<(::G, u64)> { self.validators.iter().map(|(validator, weight)| (*validator, u64::from(*weight))).collect() } - - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&self.serai_block)?; - writer.write_all(&self.start_time.to_le_bytes())?; - writer.write_all(&self.set.session.0.to_le_bytes())?; - let network_encoded = self.set.network.encode(); - assert_eq!(network_encoded.len(), 1); - writer.write_all(&network_encoded)?; - writer.write_all(&u32::try_from(self.validators.len()).unwrap().to_le_bytes())?; - for validator in &self.validators { - writer.write_all(&validator.0.to_bytes())?; - writer.write_all(&validator.1.to_le_bytes())?; - } - Ok(()) - } - - pub fn serialize(&self) -> Vec { - let mut res = vec![]; - self.write(&mut res).unwrap(); - res - } - - pub fn read(reader: &mut R) -> io::Result { - let mut serai_block = [0; 32]; - reader.read_exact(&mut serai_block)?; - - let mut start_time = [0; 8]; - reader.read_exact(&mut start_time)?; - let start_time = u64::from_le_bytes(start_time); - - let mut session = [0; 4]; - reader.read_exact(&mut session)?; - let session = Session(u32::from_le_bytes(session)); - - let mut network = [0; 1]; - reader.read_exact(&mut network)?; - let network = - NetworkId::decode(&mut &network[..]).map_err(|_| io::Error::other("invalid network"))?; - - let mut validators_len = [0; 4]; - reader.read_exact(&mut validators_len)?; - let validators_len = usize::try_from(u32::from_le_bytes(validators_len)).unwrap(); - - let mut validators = Vec::with_capacity(validators_len); - for _ in 0 .. validators_len { - let key = Ristretto::read_G(reader)?; - let mut weight = [0; 2]; - reader.read_exact(&mut weight)?; - validators.push((key, u16::from_le_bytes(weight))); - } - - Ok(Self { serai_block, start_time, set: ValidatorSet { session, network }, validators }) - } } #[derive(Clone, Copy, PartialEq, Eq, Debug, Encode)] diff --git a/substrate/abi/Cargo.toml b/substrate/abi/Cargo.toml index 0b2715766..fa235d0cd 100644 --- a/substrate/abi/Cargo.toml +++ b/substrate/abi/Cargo.toml @@ -34,5 +34,19 @@ serai-signals-primitives = { path = "../signals/primitives", version = "0.1" } frame-support = { git = "https://github.com/serai-dex/substrate" } [features] -borsh = ["dep:borsh"] -serde = ["dep:serde"] +borsh = [ + "dep:borsh", + "serai-primitives/borsh", + "serai-coins-primitives/borsh", + "serai-validator-sets-primitives/borsh", + "serai-in-instructions-primitives/borsh", + "serai-signals-primitives/borsh", +] +serde = [ + "dep:serde", + "serai-primitives/serde", + "serai-coins-primitives/serde", + "serai-validator-sets-primitives/serde", + "serai-in-instructions-primitives/serde", + "serai-signals-primitives/serde", +] diff --git a/substrate/client/Cargo.toml b/substrate/client/Cargo.toml index 6901a83ff..bf81622e9 100644 --- a/substrate/client/Cargo.toml +++ b/substrate/client/Cargo.toml @@ -54,6 +54,7 @@ serai-docker-tests = { path = "../../tests/docker" } [features] serai = ["thiserror", "serde", "serde_json", "sp-core", "sp-runtime", "frame-system", "simple-request"] +borsh = ["serai-abi/borsh"] networks = [] bitcoin = ["networks", "dep:bitcoin"]