From b296be8515ab444ce2193d87f65c894e5c7acf7b Mon Sep 17 00:00:00 2001 From: Luke Parker Date: Sat, 25 Nov 2023 04:01:11 -0500 Subject: [PATCH] Replace bincode with borsh (#452) * Add SignalsConfig to chain_spec * Correct multiexp feature flagging for rand_core std * Remove bincode for borsh Replaces a non-canonical encoding with a canonical encoding which additionally should be faster. Also fixes an issue where we used bincode in transcripts where it cannot be trusted. This ended up fixing a myriad of other bugs observed, unfortunately. Accordingly, it either has to be merged or the bug fixes from it must be ported to a new PR. * Make serde optional, minimize usage * Make borsh an optional dependency of substrate/ crates * Remove unused dependencies * Use [u8; 64] where possible in the processor messages * Correct borsh feature flagging --- Cargo.lock | 105 ++++++++++++++---- common/db/src/create_db.rs | 8 +- coordinator/Cargo.toml | 4 +- coordinator/src/main.rs | 10 +- coordinator/src/processors.rs | 6 +- coordinator/src/tests/tributary/dkg.rs | 3 +- coordinator/src/tributary/handle.rs | 18 ++- crypto/dkg/Cargo.toml | 7 +- crypto/dkg/src/lib.rs | 2 + crypto/multiexp/Cargo.toml | 2 +- message-queue/Cargo.toml | 4 +- message-queue/src/main.rs | 2 +- message-queue/src/messages.rs | 13 ++- message-queue/src/queue.rs | 6 +- processor/Cargo.toml | 2 +- processor/messages/Cargo.toml | 12 +- processor/messages/src/lib.rs | 71 ++++++++---- processor/src/batch_signer.rs | 2 +- processor/src/coordinator.rs | 6 +- processor/src/cosigner.rs | 2 +- processor/src/multisigs/db.rs | 2 +- processor/src/signer.rs | 1 - processor/src/tests/key_gen.rs | 4 +- .../client/tests/common/in_instructions.rs | 4 +- substrate/client/tests/validator_sets.rs | 4 +- substrate/coins/pallet/Cargo.toml | 2 +- substrate/coins/primitives/Cargo.toml | 7 +- substrate/coins/primitives/src/lib.rs | 21 ++-- substrate/in-instructions/pallet/Cargo.toml | 4 - substrate/in-instructions/pallet/src/lib.rs | 12 -- .../in-instructions/primitives/Cargo.toml | 10 +- .../in-instructions/primitives/src/lib.rs | 57 +++++----- .../primitives/src/shorthand.rs | 9 +- substrate/node/src/chain_spec.rs | 3 +- substrate/primitives/Cargo.toml | 9 +- substrate/primitives/src/account.rs | 51 ++++++--- substrate/primitives/src/amount.rs | 18 +-- substrate/primitives/src/balance.rs | 7 +- substrate/primitives/src/block.rs | 36 ++---- substrate/primitives/src/lib.rs | 54 +++++++-- substrate/primitives/src/networks.rs | 57 ++++------ .../validator-sets/primitives/Cargo.toml | 7 +- .../validator-sets/primitives/src/lib.rs | 66 ++++++----- tests/coordinator/Cargo.toml | 2 +- tests/coordinator/src/lib.rs | 8 +- tests/coordinator/src/tests/batch.rs | 8 +- tests/coordinator/src/tests/key_gen.rs | 4 +- tests/coordinator/src/tests/sign.rs | 8 +- tests/processor/Cargo.toml | 1 + tests/processor/src/lib.rs | 4 +- tests/processor/src/tests/batch.rs | 4 +- tests/processor/src/tests/key_gen.rs | 8 +- 52 files changed, 468 insertions(+), 309 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2818e931..a93e1dc9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -675,6 +675,30 @@ dependencies = [ "serde_with", ] +[[package]] +name = "borsh" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf617fabf5cdbdc92f774bfe5062d870f228b80056d41180797abf48bed4056e" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f404657a7ea7b5249e36808dff544bc88a28f26e0ac40009f674b7a009d14be3" +dependencies = [ + "once_cell", + "proc-macro-crate 2.0.0", + "proc-macro2", + "quote", + "syn 2.0.39", + "syn_derive", +] + [[package]] name = "bounded-collections" version = "0.1.9" @@ -1636,6 +1660,7 @@ dependencies = [ name = "dkg" version = "0.5.1" dependencies = [ + "borsh", "chacha20", "ciphersuite", "dleq", @@ -2434,7 +2459,7 @@ version = "4.0.0-dev" source = "git+https://github.com/serai-dex/substrate#49b7d20ef96b6ad42ea0266ea27f128e0ef3214d" dependencies = [ "frame-support-procedural-tools-derive", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.39", @@ -3408,7 +3433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44e8ab85614a08792b9bff6c8feee23be78c98d0182d4c622c05256ab553892a" dependencies = [ "heck", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -4569,7 +4594,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc076939022111618a5026d3be019fd8b366e76314538ff9a1b59ffbcbf98bcd" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", @@ -4594,7 +4619,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d38685e08adb338659871ecfc6ee47ba9b22dcc8abcf6975d379cc49145c3040" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro-error", "proc-macro2", "quote", @@ -4854,7 +4879,7 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c11e44798ad209ccdd91fc192f0526a369a01234f7373e1b141c96d7cee4f0e" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.39", @@ -5150,7 +5175,7 @@ version = "3.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -5505,7 +5530,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", ] [[package]] @@ -6351,7 +6385,7 @@ name = "sc-chain-spec-derive" version = "4.0.0-dev" source = "git+https://github.com/serai-dex/substrate#49b7d20ef96b6ad42ea0266ea27f128e0ef3214d" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.39", @@ -7113,7 +7147,7 @@ name = "sc-tracing-proc-macro" version = "4.0.0-dev" source = "git+https://github.com/serai-dex/substrate#49b7d20ef96b6ad42ea0266ea27f128e0ef3214d" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.39", @@ -7209,7 +7243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4391f0dfbb6690f035f6d2a15d6a12f88cc5395c36bcc056db07ffa2a90870ec" dependencies = [ "darling 0.14.4", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -7237,7 +7271,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "316e0fb10ec0fee266822bd641bab5e332a4ab80ef8c5b5ff35e5401a394f5a6" dependencies = [ "darling 0.14.4", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -7263,7 +7297,7 @@ version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19" dependencies = [ - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 1.0.109", @@ -7518,6 +7552,7 @@ dependencies = [ name = "serai-coins-primitives" version = "0.1.0" dependencies = [ + "borsh", "parity-scale-codec", "scale-info", "serai-primitives", @@ -7531,8 +7566,8 @@ name = "serai-coordinator" version = "0.1.0" dependencies = [ "async-trait", - "bincode", "blake2", + "borsh", "ciphersuite", "env_logger", "flexible-transcript", @@ -7551,8 +7586,6 @@ dependencies = [ "serai-env", "serai-message-queue", "serai-processor-messages", - "serde", - "serde_json", "sp-application-crypto", "sp-runtime", "tokio", @@ -7565,6 +7598,7 @@ name = "serai-coordinator-tests" version = "0.1.0" dependencies = [ "blake2", + "borsh", "ciphersuite", "dkg", "dockertest", @@ -7577,7 +7611,6 @@ dependencies = [ "serai-message-queue", "serai-message-queue-tests", "serai-processor-messages", - "serde_json", "tokio", "zeroize", ] @@ -7658,13 +7691,13 @@ dependencies = [ "sp-io", "sp-runtime", "sp-std", - "thiserror", ] [[package]] name = "serai-in-instructions-primitives" version = "0.1.0" dependencies = [ + "borsh", "parity-scale-codec", "scale-info", "serai-coins-primitives", @@ -7680,7 +7713,7 @@ dependencies = [ name = "serai-message-queue" version = "0.1.0" dependencies = [ - "bincode", + "borsh", "ciphersuite", "env_logger", "flexible-transcript", @@ -7773,6 +7806,7 @@ dependencies = [ name = "serai-primitives" version = "0.1.0" dependencies = [ + "borsh", "parity-scale-codec", "scale-info", "serde", @@ -7787,8 +7821,8 @@ name = "serai-processor" version = "0.1.0" dependencies = [ "async-trait", - "bincode", "bitcoin-serai", + "borsh", "ciphersuite", "dalek-ff-group", "dockertest", @@ -7824,13 +7858,13 @@ dependencies = [ name = "serai-processor-messages" version = "0.1.0" dependencies = [ + "borsh", "dkg", "parity-scale-codec", "serai-coins-primitives", "serai-in-instructions-primitives", "serai-primitives", "serai-validator-sets-primitives", - "serde", "zeroize", ] @@ -7839,6 +7873,7 @@ name = "serai-processor-tests" version = "0.1.0" dependencies = [ "bitcoin-serai", + "borsh", "ciphersuite", "curve25519-dalek", "dkg", @@ -7948,6 +7983,7 @@ dependencies = [ name = "serai-validator-sets-primitives" version = "0.1.0" dependencies = [ + "borsh", "ciphersuite", "dkg", "parity-scale-codec", @@ -8277,7 +8313,7 @@ dependencies = [ "Inflector", "blake2", "expander", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.39", @@ -8664,7 +8700,7 @@ version = "11.0.0" source = "git+https://github.com/serai-dex/substrate#49b7d20ef96b6ad42ea0266ea27f128e0ef3214d" dependencies = [ "Inflector", - "proc-macro-crate", + "proc-macro-crate 1.3.1", "proc-macro2", "quote", "syn 2.0.39", @@ -9173,6 +9209,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.39", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -9465,7 +9513,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.19.15", ] [[package]] @@ -9490,6 +9538,17 @@ dependencies = [ "winnow", ] +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" diff --git a/common/db/src/create_db.rs b/common/db/src/create_db.rs index 0fbe3404..0b0cb010 100644 --- a/common/db/src/create_db.rs +++ b/common/db/src/create_db.rs @@ -16,7 +16,7 @@ pub fn serai_db_key( /// Creates a unit struct and a default implementation for the `key`, `get`, and `set`. The macro /// uses a syntax similar to defining a function. Parameters are concatenated to produce a key, /// they must be `scale` encodable. The return type is used to auto encode and decode the database -/// value bytes using `bincode`. +/// value bytes using `borsh`. /// /// # Arguments /// @@ -52,14 +52,14 @@ macro_rules! create_db { ) } #[allow(dead_code)] - pub fn set(txn: &mut impl DbTxn $(, $arg: $arg_type)*, data: &impl serde::Serialize) { + pub fn set(txn: &mut impl DbTxn $(, $arg: $arg_type)*, data: &$field_type) { let key = $field_name::key($($arg),*); - txn.put(&key, bincode::serialize(data).unwrap()); + txn.put(&key, borsh::to_vec(data).unwrap()); } #[allow(dead_code)] pub fn get(getter: &impl Get, $($arg: $arg_type),*) -> Option<$field_type> { getter.get($field_name::key($($arg),*)).map(|data| { - bincode::deserialize(data.as_ref()).unwrap() + borsh::from_slice(data.as_ref()).unwrap() }) } #[allow(dead_code)] diff --git a/coordinator/Cargo.toml b/coordinator/Cargo.toml index b5bda710..460e5d8b 100644 --- a/coordinator/Cargo.toml +++ b/coordinator/Cargo.toml @@ -41,9 +41,7 @@ sp-application-crypto = { git = "https://github.com/serai-dex/substrate", defaul serai-client = { path = "../substrate/client", default-features = false, features = ["serai"] } hex = { version = "0.4", default-features = false, features = ["std"] } -bincode = { version = "1", default-features = false } -serde = "1" -serde_json = { version = "1", default-features = false, features = ["std"] } +borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] } log = { version = "0.4", default-features = false, features = ["std"] } env_logger = { version = "0.10", default-features = false, features = ["humantime"] } diff --git a/coordinator/src/main.rs b/coordinator/src/main.rs index adaf92a8..06319f70 100644 --- a/coordinator/src/main.rs +++ b/coordinator/src/main.rs @@ -21,7 +21,7 @@ use serai_env as env; use scale::Encode; use serai_client::{ primitives::NetworkId, - validator_sets::primitives::{Session, ValidatorSet}, + validator_sets::primitives::{Session, ValidatorSet, KeyPair}, Public, Serai, SeraiInInstructions, }; @@ -501,7 +501,7 @@ async fn handle_processor_message( &mut txn, key, spec, - &(Public(substrate_key), network_key.try_into().unwrap()), + &KeyPair(Public(substrate_key), network_key.try_into().unwrap()), id.attempt, ); @@ -587,7 +587,7 @@ async fn handle_processor_message( vec![Transaction::SubstratePreprocess(SignData { plan: id.id, attempt: id.attempt, - data: preprocesses, + data: preprocesses.into_iter().map(Into::into).collect(), signed: Transaction::empty_signed(), })] } @@ -612,7 +612,7 @@ async fn handle_processor_message( }; id.encode() }, - preprocesses, + preprocesses.into_iter().map(Into::into).collect(), ); let intended = Transaction::Batch( @@ -681,7 +681,7 @@ async fn handle_processor_message( vec![Transaction::SubstratePreprocess(SignData { plan: id.id, attempt: id.attempt, - data: preprocesses, + data: preprocesses.into_iter().map(Into::into).collect(), signed: Transaction::empty_signed(), })] } diff --git a/coordinator/src/processors.rs b/coordinator/src/processors.rs index c147fad1..7dc34ec9 100644 --- a/coordinator/src/processors.rs +++ b/coordinator/src/processors.rs @@ -25,8 +25,8 @@ impl Processors for Arc { let msg: CoordinatorMessage = msg.into(); let metadata = Metadata { from: self.service, to: Service::Processor(network), intent: msg.intent() }; - let msg = serde_json::to_string(&msg).unwrap(); - self.queue(metadata, msg.into_bytes()).await; + let msg = borsh::to_vec(&msg).unwrap(); + self.queue(metadata, msg).await; } async fn recv(&mut self, network: NetworkId) -> Message { let msg = self.next(Service::Processor(network)).await; @@ -36,7 +36,7 @@ impl Processors for Arc { // Deserialize it into a ProcessorMessage let msg: ProcessorMessage = - serde_json::from_slice(&msg.msg).expect("message wasn't a JSON-encoded ProcessorMessage"); + borsh::from_slice(&msg.msg).expect("message wasn't a borsh-encoded ProcessorMessage"); return Message { id, network, msg }; } diff --git a/coordinator/src/tests/tributary/dkg.rs b/coordinator/src/tests/tributary/dkg.rs index 42be186d..c429a754 100644 --- a/coordinator/src/tests/tributary/dkg.rs +++ b/coordinator/src/tests/tributary/dkg.rs @@ -10,6 +10,7 @@ use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; use frost::Participant; use sp_runtime::traits::Verify; +use serai_client::validator_sets::primitives::KeyPair; use tokio::time::sleep; @@ -279,7 +280,7 @@ async fn dkg_test() { OsRng.fill_bytes(&mut substrate_key); let mut network_key = vec![0; usize::try_from((OsRng.next_u64() % 32) + 32).unwrap()]; OsRng.fill_bytes(&mut network_key); - let key_pair = (serai_client::Public(substrate_key), network_key.try_into().unwrap()); + let key_pair = KeyPair(serai_client::Public(substrate_key), network_key.try_into().unwrap()); let mut txs = vec![]; for (i, key) in keys.iter().enumerate() { diff --git a/coordinator/src/tributary/handle.rs b/coordinator/src/tributary/handle.rs index eb88bdcc..7b94b065 100644 --- a/coordinator/src/tributary/handle.rs +++ b/coordinator/src/tributary/handle.rs @@ -72,7 +72,7 @@ pub fn error_generating_key_pair( // Sign a key pair which can't be valid // (0xff used as 0 would be the Ristretto identity point, 0-length for the network key) - let key_pair = (Public([0xff; 32]), vec![0xffu8; 0].try_into().unwrap()); + let key_pair = KeyPair(Public([0xff; 32]), vec![0xffu8; 0].try_into().unwrap()); match DkgConfirmer::share(spec, key, attempt, preprocesses, &key_pair) { Ok(mut share) => { // Zeroize the share to ensure it's not accessed @@ -312,7 +312,7 @@ pub(crate) async fn handle_application_tx< } let to = Participant::new(to).unwrap(); - DkgShare::set(txn, genesis, from.into(), to.into(), &share); + DkgShare::set(txn, genesis, from.into(), to.into(), share); } } } @@ -556,9 +556,16 @@ pub(crate) async fn handle_application_tx< } Transaction::SubstratePreprocess(data) => { - let Ok(_) = check_sign_data_len::(txn, spec, data.signed.signer, data.data.len()) else { + let signer = data.signed.signer; + let Ok(_) = check_sign_data_len::(txn, spec, signer, data.data.len()) else { return; }; + for data in &data.data { + if data.len() != 64 { + fatal_slash::(txn, genesis, signer.to_bytes(), "non-64-byte Substrate preprocess"); + return; + } + } match handle( txn, &DataSpecification { @@ -578,7 +585,10 @@ pub(crate) async fn handle_application_tx< spec.set().network, coordinator::CoordinatorMessage::SubstratePreprocesses { id: SubstrateSignId { key, id: data.plan, attempt: data.attempt }, - preprocesses, + preprocesses: preprocesses + .into_iter() + .map(|(k, v)| (k, v.try_into().unwrap())) + .collect(), }, ) .await; diff --git a/crypto/dkg/Cargo.toml b/crypto/dkg/Cargo.toml index ac26d3a9..2b8cd25d 100644 --- a/crypto/dkg/Cargo.toml +++ b/crypto/dkg/Cargo.toml @@ -22,7 +22,8 @@ zeroize = { version = "^1.5", default-features = false, features = ["zeroize_der std-shims = { version = "0.1", path = "../../common/std-shims", default-features = false } -serde = { version = "1", features = ["derive"], optional = true } +borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true } +serde = { version = "1", default-features = false, features = ["derive"], optional = true } transcript = { package = "flexible-transcript", path = "../transcript", version = "^0.3.2", default-features = false, features = ["recommended"] } chacha20 = { version = "0.9", default-features = false, features = ["zeroize"] } @@ -45,7 +46,8 @@ std = [ "std-shims/std", - "serde/std", + "borsh?/std", + "serde?/std", "transcript/std", "chacha20/std", @@ -58,6 +60,7 @@ std = [ "dleq/std", "dleq/serialize" ] +borsh = ["dep:borsh"] serde = ["dep:serde"] tests = ["rand_core/getrandom"] default = ["std"] diff --git a/crypto/dkg/src/lib.rs b/crypto/dkg/src/lib.rs index 9648a6a6..fd49856f 100644 --- a/crypto/dkg/src/lib.rs +++ b/crypto/dkg/src/lib.rs @@ -31,6 +31,7 @@ pub mod tests; /// The ID of a participant, defined as a non-zero u16. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Zeroize)] +#[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Participant(pub(crate) u16); impl Participant { @@ -146,6 +147,7 @@ mod lib { /// Parameters for a multisig. // These fields should not be made public as they should be static #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] + #[cfg_attr(feature = "borsh", derive(borsh::BorshSerialize, borsh::BorshDeserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ThresholdParams { /// Participants needed to sign on behalf of the group. diff --git a/crypto/multiexp/Cargo.toml b/crypto/multiexp/Cargo.toml index 128fca4a..2bc9ece5 100644 --- a/crypto/multiexp/Cargo.toml +++ b/crypto/multiexp/Cargo.toml @@ -32,7 +32,7 @@ k256 = { version = "^0.13.1", default-features = false, features = ["arithmetic" dalek-ff-group = { path = "../dalek-ff-group" } [features] -std = ["std-shims/std", "zeroize/std", "ff/std", "rand_core/std"] +std = ["std-shims/std", "zeroize/std", "ff/std", "rand_core?/std"] batch = ["rand_core"] diff --git a/message-queue/Cargo.toml b/message-queue/Cargo.toml index 4b6b8bd1..489c256d 100644 --- a/message-queue/Cargo.toml +++ b/message-queue/Cargo.toml @@ -20,7 +20,7 @@ serde = { version = "1", default-features = false, features = ["std", "derive"] # Encoders hex = { version = "0.4", default-features = false, features = ["std"] } -bincode = { version = "1", default-features = false } +borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] } serde_json = { version = "1", default-features = false, features = ["std"] } # Libs @@ -43,7 +43,7 @@ serai-db = { path = "../common/db", optional = true } serai-env = { path = "../common/env" } -serai-primitives = { path = "../substrate/primitives" } +serai-primitives = { path = "../substrate/primitives", features = ["borsh", "serde"] } jsonrpsee = { version = "0.16", default-features = false, features = ["server"], optional = true } simple-request = { path = "../common/request", default-features = false } diff --git a/message-queue/src/main.rs b/message-queue/src/main.rs index 69c7166b..36c2dcd9 100644 --- a/message-queue/src/main.rs +++ b/message-queue/src/main.rs @@ -76,7 +76,7 @@ mod binaries { [&[u8::try_from(domain.len()).unwrap()], domain, key.as_ref()].concat() } fn intent_key(from: Service, to: Service, intent: &[u8]) -> Vec { - key(b"intent_seen", bincode::serialize(&(from, to, intent)).unwrap()) + key(b"intent_seen", borsh::to_vec(&(from, to, intent)).unwrap()) } let mut db = db.write().unwrap(); let mut txn = db.txn(); diff --git a/message-queue/src/messages.rs b/message-queue/src/messages.rs index 89557ad7..edaea72b 100644 --- a/message-queue/src/messages.rs +++ b/message-queue/src/messages.rs @@ -1,11 +1,14 @@ use transcript::{Transcript, RecommendedTranscript}; use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; +use borsh::{BorshSerialize, BorshDeserialize}; use serde::{Serialize, Deserialize}; use serai_primitives::NetworkId; -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +#[derive( + Clone, Copy, PartialEq, Eq, Hash, Debug, BorshSerialize, BorshDeserialize, Serialize, Deserialize, +)] pub enum Service { Processor(NetworkId), Coordinator, @@ -36,9 +39,9 @@ pub fn message_challenge( ) -> ::F { let mut transcript = RecommendedTranscript::new(b"Serai Message Queue v0.1 Message"); transcript.domain_separate(b"metadata"); - transcript.append_message(b"from", bincode::serialize(&from).unwrap()); + transcript.append_message(b"from", borsh::to_vec(&from).unwrap()); transcript.append_message(b"from_key", from_key.to_bytes()); - transcript.append_message(b"to", bincode::serialize(&to).unwrap()); + transcript.append_message(b"to", borsh::to_vec(&to).unwrap()); transcript.append_message(b"intent", intent); transcript.domain_separate(b"message"); transcript.append_message(b"msg", msg); @@ -56,9 +59,9 @@ pub fn ack_challenge( ) -> ::F { let mut transcript = RecommendedTranscript::new(b"Serai Message Queue v0.1 Ackowledgement"); transcript.domain_separate(b"metadata"); - transcript.append_message(b"to", bincode::serialize(&to).unwrap()); + transcript.append_message(b"to", borsh::to_vec(&to).unwrap()); transcript.append_message(b"to_key", to_key.to_bytes()); - transcript.append_message(b"from", bincode::serialize(&from).unwrap()); + transcript.append_message(b"from", borsh::to_vec(&from).unwrap()); transcript.domain_separate(b"message"); transcript.append_message(b"id", id.to_le_bytes()); transcript.domain_separate(b"signature"); diff --git a/message-queue/src/queue.rs b/message-queue/src/queue.rs index aa9e99cd..257c83c2 100644 --- a/message-queue/src/queue.rs +++ b/message-queue/src/queue.rs @@ -10,7 +10,7 @@ impl Queue { } fn message_count_key(&self) -> Vec { - Self::key(b"message_count", bincode::serialize(&(self.1, self.2)).unwrap()) + Self::key(b"message_count", borsh::to_vec(&(self.1, self.2)).unwrap()) } pub(crate) fn message_count(&self) -> u64 { self @@ -21,7 +21,7 @@ impl Queue { } fn last_acknowledged_key(&self) -> Vec { - Self::key(b"last_acknowledged", bincode::serialize(&(self.1, self.2)).unwrap()) + Self::key(b"last_acknowledged", borsh::to_vec(&(self.1, self.2)).unwrap()) } pub(crate) fn last_acknowledged(&self) -> Option { self @@ -31,7 +31,7 @@ impl Queue { } fn message_key(&self, id: u64) -> Vec { - Self::key(b"message", bincode::serialize(&(self.1, self.2, id)).unwrap()) + Self::key(b"message", borsh::to_vec(&(self.1, self.2, id)).unwrap()) } // TODO: This is fine as-used, yet gets from the DB while having a txn. It should get from the // txn diff --git a/processor/Cargo.toml b/processor/Cargo.toml index 830394d1..43780d7e 100644 --- a/processor/Cargo.toml +++ b/processor/Cargo.toml @@ -28,7 +28,7 @@ rand_chacha = { version = "0.3", default-features = false, features = ["std"] } # Encoders hex = { version = "0.4", default-features = false, features = ["std"] } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] } -bincode = { version = "1", default-features = false } +borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] } serde_json = { version = "1", default-features = false, features = ["std"] } # Cryptography diff --git a/processor/messages/Cargo.toml b/processor/messages/Cargo.toml index 98684ed3..6856dab9 100644 --- a/processor/messages/Cargo.toml +++ b/processor/messages/Cargo.toml @@ -17,11 +17,11 @@ rustdoc-args = ["--cfg", "docsrs"] zeroize = { version = "1", default-features = false, features = ["std", "derive"] } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["std"] } -serde = { version = "1", default-features = false, features = ["std", "derive"] } +borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] } -dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "serde"] } +dkg = { path = "../../crypto/dkg", default-features = false, features = ["std", "borsh", "serde"] } -serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std"] } -in-instructions-primitives = { package = "serai-in-instructions-primitives", path = "../../substrate/in-instructions/primitives", default-features = false, features = ["std"] } -coins-primitives = { package = "serai-coins-primitives", path = "../../substrate/coins/primitives", default-features = false, features = ["std"] } -validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std"] } +serai-primitives = { path = "../../substrate/primitives", default-features = false, features = ["std", "borsh"] } +in-instructions-primitives = { package = "serai-in-instructions-primitives", path = "../../substrate/in-instructions/primitives", default-features = false, features = ["std", "borsh"] } +coins-primitives = { package = "serai-coins-primitives", path = "../../substrate/coins/primitives", default-features = false, features = ["std", "borsh"] } +validator-sets-primitives = { package = "serai-validator-sets-primitives", path = "../../substrate/validator-sets/primitives", default-features = false, features = ["std", "borsh"] } diff --git a/processor/messages/src/lib.rs b/processor/messages/src/lib.rs index 2905c16e..59eb3c4e 100644 --- a/processor/messages/src/lib.rs +++ b/processor/messages/src/lib.rs @@ -3,7 +3,7 @@ use std::collections::HashMap; use zeroize::Zeroize; use scale::{Encode, Decode}; -use serde::{Serialize, Deserialize}; +use borsh::{BorshSerialize, BorshDeserialize}; use dkg::{Participant, ThresholdParams}; @@ -12,7 +12,9 @@ use in_instructions_primitives::{Batch, SignedBatch}; use coins_primitives::OutInstructionWithBalance; use validator_sets_primitives::{ValidatorSet, KeyPair}; -#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, Encode, Decode, Serialize, Deserialize)] +#[derive( + Clone, Copy, PartialEq, Eq, Debug, Zeroize, Encode, Decode, BorshSerialize, BorshDeserialize, +)] pub struct SubstrateContext { pub serai_time: u64, pub network_latest_finalized_block: BlockHash, @@ -22,14 +24,24 @@ pub mod key_gen { use super::*; #[derive( - Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, Encode, Decode, Serialize, Deserialize, + Clone, + Copy, + PartialEq, + Eq, + Hash, + Debug, + Zeroize, + Encode, + Decode, + BorshSerialize, + BorshDeserialize, )] pub struct KeyGenId { pub set: ValidatorSet, pub attempt: u32, } - #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] + #[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] pub enum CoordinatorMessage { // Instructs the Processor to begin the key generation process. // TODO: Should this be moved under Substrate? @@ -64,7 +76,7 @@ pub mod key_gen { } } - #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] + #[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] pub enum ProcessorMessage { // Created commitments for the specified key generation protocol. Commitments { @@ -106,14 +118,16 @@ pub mod key_gen { pub mod sign { use super::*; - #[derive(Clone, PartialEq, Eq, Hash, Debug, Zeroize, Encode, Decode, Serialize, Deserialize)] + #[derive( + Clone, PartialEq, Eq, Hash, Debug, Zeroize, Encode, Decode, BorshSerialize, BorshDeserialize, + )] pub struct SignId { pub key: Vec, pub id: [u8; 32], pub attempt: u32, } - #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] + #[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] pub enum CoordinatorMessage { // Received preprocesses for the specified signing protocol. Preprocesses { id: SignId, preprocesses: HashMap> }, @@ -140,7 +154,7 @@ pub mod sign { } } - #[derive(Clone, PartialEq, Eq, Debug, Zeroize, Serialize, Deserialize)] + #[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)] pub enum ProcessorMessage { // Participant sent an invalid message during the sign protocol. InvalidParticipant { id: SignId, participant: Participant }, @@ -166,25 +180,36 @@ pub mod coordinator { } #[derive( - Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, Encode, Decode, Serialize, Deserialize, + Clone, + Copy, + PartialEq, + Eq, + Hash, + Debug, + Zeroize, + Encode, + Decode, + BorshSerialize, + BorshDeserialize, )] pub enum SubstrateSignableId { CosigningSubstrateBlock([u8; 32]), Batch([u8; 5]), } - #[derive(Clone, PartialEq, Eq, Hash, Debug, Zeroize, Encode, Decode, Serialize, Deserialize)] + #[derive( + Clone, PartialEq, Eq, Hash, Debug, Zeroize, Encode, Decode, BorshSerialize, BorshDeserialize, + )] pub struct SubstrateSignId { pub key: [u8; 32], pub id: SubstrateSignableId, pub attempt: u32, } - #[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] + #[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] pub enum CoordinatorMessage { CosignSubstrateBlock { id: SubstrateSignId, block_number: u64 }, - // Uses Vec instead of [u8; 64] since serde Deserialize isn't implemented for [u8; 64] - SubstratePreprocesses { id: SubstrateSignId, preprocesses: HashMap> }, + SubstratePreprocesses { id: SubstrateSignId, preprocesses: HashMap }, SubstrateShares { id: SubstrateSignId, shares: HashMap }, // Re-attempt a batch signing protocol. BatchReattempt { id: SubstrateSignId }, @@ -214,18 +239,20 @@ pub mod coordinator { } } - #[derive(Clone, PartialEq, Eq, Debug, Zeroize, Encode, Decode, Serialize, Deserialize)] + #[derive( + Clone, PartialEq, Eq, Debug, Zeroize, Encode, Decode, BorshSerialize, BorshDeserialize, + )] pub struct PlanMeta { pub key: Vec, pub id: [u8; 32], } - #[derive(Clone, PartialEq, Eq, Debug, Zeroize, Serialize, Deserialize)] + #[derive(Clone, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)] pub enum ProcessorMessage { SubstrateBlockAck { network: NetworkId, block: u64, plans: Vec }, InvalidParticipant { id: SubstrateSignId, participant: Participant }, - CosignPreprocess { id: SubstrateSignId, preprocesses: Vec> }, - BatchPreprocess { id: SubstrateSignId, block: BlockHash, preprocesses: Vec> }, + CosignPreprocess { id: SubstrateSignId, preprocesses: Vec<[u8; 64]> }, + BatchPreprocess { id: SubstrateSignId, block: BlockHash, preprocesses: Vec<[u8; 64]> }, SubstrateShare { id: SubstrateSignId, shares: Vec<[u8; 32]> }, CosignedBlock { block_number: u64, block: [u8; 32], signature: Vec }, } @@ -234,7 +261,7 @@ pub mod coordinator { pub mod substrate { use super::*; - #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, Serialize, Deserialize)] + #[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, BorshSerialize, BorshDeserialize)] pub enum CoordinatorMessage { ConfirmKeyPair { context: SubstrateContext, @@ -260,7 +287,9 @@ pub mod substrate { } } - #[derive(Clone, PartialEq, Eq, Debug, Zeroize, Encode, Decode, Serialize, Deserialize)] + #[derive( + Clone, PartialEq, Eq, Debug, Zeroize, Encode, Decode, BorshSerialize, BorshDeserialize, + )] pub enum ProcessorMessage { Batch { batch: Batch }, SignedBatch { batch: SignedBatch }, @@ -277,7 +306,7 @@ macro_rules! impl_from { }; } -#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] pub enum CoordinatorMessage { KeyGen(key_gen::CoordinatorMessage), Sign(sign::CoordinatorMessage), @@ -308,7 +337,7 @@ impl CoordinatorMessage { } } -#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] pub enum ProcessorMessage { KeyGen(key_gen::ProcessorMessage), Sign(sign::ProcessorMessage), diff --git a/processor/src/batch_signer.rs b/processor/src/batch_signer.rs index 28b094a3..b7700856 100644 --- a/processor/src/batch_signer.rs +++ b/processor/src/batch_signer.rs @@ -191,7 +191,7 @@ impl BatchSigner { let (machine, preprocess) = machine.preprocess(&mut OsRng); machines.push(machine); - serialized_preprocesses.push(preprocess.serialize()); + serialized_preprocesses.push(preprocess.serialize().try_into().unwrap()); preprocesses.push(preprocess); } self.preprocessing.insert(id, (machines, preprocesses)); diff --git a/processor/src/coordinator.rs b/processor/src/coordinator.rs index 7f4e39fb..26786e30 100644 --- a/processor/src/coordinator.rs +++ b/processor/src/coordinator.rs @@ -20,9 +20,9 @@ impl Coordinator for MessageQueue { async fn send(&mut self, msg: impl Send + Into) { let msg: ProcessorMessage = msg.into(); let metadata = Metadata { from: self.service, to: Service::Coordinator, intent: msg.intent() }; - let msg = serde_json::to_string(&msg).unwrap(); + let msg = borsh::to_vec(&msg).unwrap(); - self.queue(metadata, msg.into_bytes()).await; + self.queue(metadata, msg).await; } async fn recv(&mut self) -> Message { @@ -32,7 +32,7 @@ impl Coordinator for MessageQueue { // Deserialize it into a CoordinatorMessage let msg: CoordinatorMessage = - serde_json::from_slice(&msg.msg).expect("message wasn't a JSON-encoded CoordinatorMessage"); + borsh::from_slice(&msg.msg).expect("message wasn't a borsh-encoded CoordinatorMessage"); return Message { id, msg }; } diff --git a/processor/src/cosigner.rs b/processor/src/cosigner.rs index 414c2d47..c53772cf 100644 --- a/processor/src/cosigner.rs +++ b/processor/src/cosigner.rs @@ -95,7 +95,7 @@ impl Cosigner { let (machine, preprocess) = machine.preprocess(&mut OsRng); machines.push(machine); - serialized_preprocesses.push(preprocess.serialize()); + serialized_preprocesses.push(preprocess.serialize().try_into().unwrap()); preprocesses.push(preprocess); } let preprocessing = Some((machines, preprocesses)); diff --git a/processor/src/multisigs/db.rs b/processor/src/multisigs/db.rs index 57e134bc..0a5fbbf0 100644 --- a/processor/src/multisigs/db.rs +++ b/processor/src/multisigs/db.rs @@ -44,7 +44,7 @@ impl PlanDb { } signing.extend(&id); - SigningDb::set(txn, key, &id); + SigningDb::set(txn, key, &signing); } { diff --git a/processor/src/signer.rs b/processor/src/signer.rs index b84646ee..80bc9857 100644 --- a/processor/src/signer.rs +++ b/processor/src/signer.rs @@ -51,7 +51,6 @@ impl CompletedOnChainDb { .unwrap_or_default() .into_iter() .filter(|active| active != id) - .flatten() .collect::>(), ); } diff --git a/processor/src/tests/key_gen.rs b/processor/src/tests/key_gen.rs index 4a9de16f..90f11fbb 100644 --- a/processor/src/tests/key_gen.rs +++ b/processor/src/tests/key_gen.rs @@ -12,7 +12,7 @@ use serai_db::{DbTxn, Db, MemDb}; use sp_application_crypto::sr25519; use serai_client::{ primitives::NetworkId, - validator_sets::primitives::{Session, ValidatorSet}, + validator_sets::primitives::{Session, ValidatorSet, KeyPair}, }; use messages::key_gen::*; @@ -139,7 +139,7 @@ pub async fn test_key_gen() { let key_gen = key_gens.get_mut(&i).unwrap(); let mut txn = dbs.get_mut(&i).unwrap().txn(); let KeyConfirmed { mut substrate_keys, mut network_keys } = key_gen - .confirm(&mut txn, ID.set, (sr25519::Public(res.0), res.1.clone().try_into().unwrap())) + .confirm(&mut txn, ID.set, KeyPair(sr25519::Public(res.0), res.1.clone().try_into().unwrap())) .await; txn.commit(); diff --git a/substrate/client/tests/common/in_instructions.rs b/substrate/client/tests/common/in_instructions.rs index 7ec94910..e7f27cd8 100644 --- a/substrate/client/tests/common/in_instructions.rs +++ b/substrate/client/tests/common/in_instructions.rs @@ -10,7 +10,7 @@ use sp_core::Pair; use serai_client::{ primitives::{insecure_pair_from_name, BlockHash, NetworkId, Balance, SeraiAddress}, - validator_sets::primitives::{Session, ValidatorSet}, + validator_sets::primitives::{Session, ValidatorSet, KeyPair}, in_instructions::{ primitives::{Batch, SignedBatch, batch_message, InInstruction, InInstructionWithBalance}, InInstructionsEvent, @@ -30,7 +30,7 @@ pub async fn provide_batch(serai: &Serai, batch: Batch) -> [u8; 32] { { keys } else { - let keys = (pair.public(), vec![].try_into().unwrap()); + let keys = KeyPair(pair.public(), vec![].try_into().unwrap()); set_keys(serai, set, keys.clone()).await; keys }; diff --git a/substrate/client/tests/validator_sets.rs b/substrate/client/tests/validator_sets.rs index f7175171..ca165b9a 100644 --- a/substrate/client/tests/validator_sets.rs +++ b/substrate/client/tests/validator_sets.rs @@ -5,7 +5,7 @@ use sp_core::{sr25519::Public, Pair}; use serai_client::{ primitives::{NETWORKS, NetworkId, insecure_pair_from_name}, validator_sets::{ - primitives::{Session, ValidatorSet, musig_key}, + primitives::{Session, ValidatorSet, KeyPair, musig_key}, ValidatorSetsEvent, }, Serai, @@ -28,7 +28,7 @@ serai_test!( OsRng.fill_bytes(&mut ristretto_key); let mut external_key = vec![0; 33]; OsRng.fill_bytes(&mut external_key); - let key_pair = (Public(ristretto_key), external_key.try_into().unwrap()); + let key_pair = KeyPair(Public(ristretto_key), external_key.try_into().unwrap()); // Make sure the genesis is as expected assert_eq!( diff --git a/substrate/coins/pallet/Cargo.toml b/substrate/coins/pallet/Cargo.toml index 88b890af..afbae927 100644 --- a/substrate/coins/pallet/Cargo.toml +++ b/substrate/coins/pallet/Cargo.toml @@ -25,7 +25,7 @@ sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features pallet-transaction-payment = { git = "https://github.com/serai-dex/substrate", default-features = false } -serai-primitives = { path = "../../primitives", default-features = false } +serai-primitives = { path = "../../primitives", default-features = false, features = ["serde"] } coins-primitives = { package = "serai-coins-primitives", path = "../primitives", default-features = false } [features] diff --git a/substrate/coins/primitives/Cargo.toml b/substrate/coins/primitives/Cargo.toml index 913b043d..af483fba 100644 --- a/substrate/coins/primitives/Cargo.toml +++ b/substrate/coins/primitives/Cargo.toml @@ -14,7 +14,8 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] zeroize = { version = "^1.5", features = ["derive"], optional = true } -serde = { version = "1", default-features = false, features = ["derive", "alloc"] } +borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true } +serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"] } @@ -25,5 +26,7 @@ serai-primitives = { path = "../../primitives", default-features = false } sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } [features] -std = ["zeroize", "serde/std", "scale/std", "scale-info/std", "sp-runtime/std", "serai-primitives/std"] +std = ["zeroize", "borsh?/std", "serde/std", "scale/std", "scale-info/std", "sp-runtime/std", "serai-primitives/std"] +borsh = ["dep:borsh", "serai-primitives/borsh"] +serde = ["dep:serde", "serai-primitives/serde"] default = ["std"] diff --git a/substrate/coins/primitives/src/lib.rs b/substrate/coins/primitives/src/lib.rs index d7253196..a7b45cf0 100644 --- a/substrate/coins/primitives/src/lib.rs +++ b/substrate/coins/primitives/src/lib.rs @@ -5,6 +5,9 @@ #[cfg(feature = "std")] use zeroize::Zeroize; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; @@ -14,28 +17,28 @@ use serai_primitives::{Balance, SeraiAddress, ExternalAddress, Data, system_addr pub const FEE_ACCOUNT: SeraiAddress = system_address(b"Coins-fees"); -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct OutInstruction { pub address: ExternalAddress, pub data: Option, } -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct OutInstructionWithBalance { pub instruction: OutInstruction, pub balance: Balance, } -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Destination { Native(SeraiAddress), External(OutInstruction), diff --git a/substrate/in-instructions/pallet/Cargo.toml b/substrate/in-instructions/pallet/Cargo.toml index f3aafb52..fc342c3b 100644 --- a/substrate/in-instructions/pallet/Cargo.toml +++ b/substrate/in-instructions/pallet/Cargo.toml @@ -13,8 +13,6 @@ all-features = true rustdoc-args = ["--cfg", "docsrs"] [dependencies] -thiserror = { version = "1", optional = true } - scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2", default-features = false, features = ["derive"] } @@ -36,8 +34,6 @@ validator-sets-pallet = { package = "serai-validator-sets-pallet", path = "../.. [features] std = [ - "thiserror", - "scale/std", "scale-info/std", diff --git a/substrate/in-instructions/pallet/src/lib.rs b/substrate/in-instructions/pallet/src/lib.rs index 5054466b..0e61f2be 100644 --- a/substrate/in-instructions/pallet/src/lib.rs +++ b/substrate/in-instructions/pallet/src/lib.rs @@ -2,25 +2,13 @@ #![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(not(feature = "std"), no_std)] -use scale::Encode; - use sp_io::hashing::blake2_256; -use sp_runtime::RuntimeDebug; use serai_primitives::{BlockHash, NetworkId}; pub use in_instructions_primitives as primitives; use primitives::*; -#[derive(Clone, Copy, Encode, RuntimeDebug)] -#[cfg_attr(feature = "std", derive(scale::Decode, thiserror::Error))] -pub enum PalletError { - #[cfg_attr(feature = "std", error("batch for unrecognized network"))] - UnrecognizedNetwork, - #[cfg_attr(feature = "std", error("invalid signature for batch"))] - InvalidSignature, -} - #[frame_support::pallet] pub mod pallet { use sp_std::vec; diff --git a/substrate/in-instructions/primitives/Cargo.toml b/substrate/in-instructions/primitives/Cargo.toml index 47055d44..f7cadccb 100644 --- a/substrate/in-instructions/primitives/Cargo.toml +++ b/substrate/in-instructions/primitives/Cargo.toml @@ -14,7 +14,8 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] zeroize = { version = "^1.5", features = ["derive"], optional = true } -serde = { version = "1", default-features = false, features = ["derive", "alloc"] } +borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true } +serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"] } @@ -30,7 +31,8 @@ coins-primitives = { package = "serai-coins-primitives", path = "../../coins/pri std = [ "zeroize", - "serde/std", + "borsh?/std", + "serde?/std", "scale/std", "scale-info/std", @@ -40,6 +42,8 @@ std = [ "sp-runtime/std", "serai-primitives/std", - "coins-primitives/std" + "coins-primitives/std", ] +borsh = ["dep:borsh", "serai-primitives/borsh", "coins-primitives/borsh"] +serde = ["dep:serde", "serai-primitives/serde", "coins-primitives/serde"] default = ["std"] diff --git a/substrate/in-instructions/primitives/src/lib.rs b/substrate/in-instructions/primitives/src/lib.rs index 56a7ec42..afa11cac 100644 --- a/substrate/in-instructions/primitives/src/lib.rs +++ b/substrate/in-instructions/primitives/src/lib.rs @@ -5,6 +5,9 @@ #[cfg(feature = "std")] use zeroize::Zeroize; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; @@ -27,10 +30,10 @@ pub const MAX_BATCH_SIZE: usize = 25_000; // ~25kb // This is the account which will be the origin for any dispatched `InInstruction`s. pub const IN_INSTRUCTION_EXECUTOR: SeraiAddress = system_address(b"InInstructions-executor"); -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum OutAddress { Serai(SeraiAddress), External(ExternalAddress), @@ -56,10 +59,10 @@ impl OutAddress { } } -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum DexCall { // address to send the lp tokens to // TODO: Update this per documentation/Shorthand @@ -68,44 +71,37 @@ pub enum DexCall { Swap(Balance, OutAddress), } -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum InInstruction { Transfer(SeraiAddress), Dex(DexCall), } -#[derive( - Clone, - PartialEq, - Eq, - Serialize, - Deserialize, - Encode, - Decode, - MaxEncodedLen, - TypeInfo, - RuntimeDebug, -)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, MaxEncodedLen, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct RefundableInInstruction { pub origin: Option, pub instruction: InInstruction, } -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct InInstructionWithBalance { pub instruction: InInstruction, pub balance: Balance, } -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Encode, Decode, TypeInfo, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, RuntimeDebug)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Batch { pub network: NetworkId, pub id: u32, @@ -113,9 +109,18 @@ pub struct Batch { pub instructions: Vec, } -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Encode, Decode, TypeInfo, RuntimeDebug)] +#[derive(Clone, PartialEq, Eq, Encode, Decode, TypeInfo, RuntimeDebug)] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct SignedBatch { pub batch: Batch, + #[cfg_attr( + feature = "borsh", + borsh( + serialize_with = "serai_primitives::borsh_serialize_signature", + deserialize_with = "serai_primitives::borsh_deserialize_signature" + ) + )] pub signature: Signature, } diff --git a/substrate/in-instructions/primitives/src/shorthand.rs b/substrate/in-instructions/primitives/src/shorthand.rs index e6a8de51..8b1103c3 100644 --- a/substrate/in-instructions/primitives/src/shorthand.rs +++ b/substrate/in-instructions/primitives/src/shorthand.rs @@ -1,6 +1,9 @@ #[cfg(feature = "std")] use zeroize::Zeroize; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; @@ -14,10 +17,10 @@ use crate::RefundableInInstruction; #[cfg(feature = "std")] use crate::InInstruction; -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Shorthand { Raw(RefundableInInstruction), Swap { diff --git a/substrate/node/src/chain_spec.rs b/substrate/node/src/chain_spec.rs index f206c534..042f5178 100644 --- a/substrate/node/src/chain_spec.rs +++ b/substrate/node/src/chain_spec.rs @@ -6,7 +6,7 @@ use sc_service::ChainType; use serai_runtime::{ primitives::*, WASM_BINARY, BABE_GENESIS_EPOCH_CONFIG, RuntimeGenesisConfig, SystemConfig, - CoinsConfig, DexConfig, ValidatorSetsConfig, BabeConfig, GrandpaConfig, + CoinsConfig, DexConfig, ValidatorSetsConfig, SignalsConfig, BabeConfig, GrandpaConfig, }; pub type ChainSpec = sc_service::GenericChainSpec; @@ -51,6 +51,7 @@ fn testnet_genesis( .collect(), participants: validators.clone(), }, + signals: SignalsConfig::default(), babe: BabeConfig { authorities: validators.iter().map(|validator| ((*validator).into(), 1)).collect(), epoch_config: Some(BABE_GENESIS_EPOCH_CONFIG), diff --git a/substrate/primitives/Cargo.toml b/substrate/primitives/Cargo.toml index 799665f3..556ce975 100644 --- a/substrate/primitives/Cargo.toml +++ b/substrate/primitives/Cargo.toml @@ -15,15 +15,18 @@ rustdoc-args = ["--cfg", "docsrs"] [dependencies] zeroize = { version = "^1.5", features = ["derive"], optional = true } -serde = { version = "1", default-features = false, features = ["derive", "alloc"] } - scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } scale-info = { version = "2", default-features = false, features = ["derive"] } +borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true } +serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true } + sp-application-crypto = { git = "https://github.com/serai-dex/substrate", default-features = false } sp-core = { git = "https://github.com/serai-dex/substrate", default-features = false } sp-runtime = { git = "https://github.com/serai-dex/substrate", default-features = false } [features] -std = ["zeroize", "scale/std", "serde/std", "scale-info/std", "sp-core/std", "sp-runtime/std"] +std = ["zeroize", "scale/std", "borsh?/std", "serde?/std", "scale-info/std", "sp-core/std", "sp-runtime/std"] +borsh = ["dep:borsh"] +serde = ["dep:serde"] default = ["std"] diff --git a/substrate/primitives/src/account.rs b/substrate/primitives/src/account.rs index 094e17f9..b510da65 100644 --- a/substrate/primitives/src/account.rs +++ b/substrate/primitives/src/account.rs @@ -1,6 +1,9 @@ #[cfg(feature = "std")] use zeroize::Zeroize; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; @@ -15,22 +18,44 @@ use sp_runtime::traits::{LookupError, Lookup, StaticLookup}; pub type PublicKey = Public; +#[cfg(feature = "borsh")] +pub fn borsh_serialize_public( + public: &Public, + writer: &mut W, +) -> Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&public.0, writer) +} + +#[cfg(feature = "borsh")] +pub fn borsh_deserialize_public( + reader: &mut R, +) -> Result { + let public: [u8; 32] = borsh::BorshDeserialize::deserialize_reader(reader)?; + Ok(Public(public)) +} + +#[cfg(feature = "borsh")] +pub fn borsh_serialize_signature( + signature: &Signature, + writer: &mut W, +) -> Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(&signature.0, writer) +} + +#[cfg(feature = "borsh")] +pub fn borsh_deserialize_signature( + reader: &mut R, +) -> Result { + let signature: [u8; 64] = borsh::BorshDeserialize::deserialize_reader(reader)?; + Ok(Signature(signature)) +} + #[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Debug, - Serialize, - Deserialize, - Encode, - Decode, - MaxEncodedLen, - TypeInfo, + Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, )] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct SeraiAddress(pub [u8; 32]); impl SeraiAddress { pub fn new(key: [u8; 32]) -> SeraiAddress { diff --git a/substrate/primitives/src/amount.rs b/substrate/primitives/src/amount.rs index dcf8497f..3953b420 100644 --- a/substrate/primitives/src/amount.rs +++ b/substrate/primitives/src/amount.rs @@ -6,6 +6,9 @@ use core::{ #[cfg(feature = "std")] use zeroize::Zeroize; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; @@ -19,20 +22,11 @@ use scale_info::TypeInfo; pub type SubstrateAmount = u64; /// The type used for amounts. #[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Debug, - Serialize, - Deserialize, - Encode, - Decode, - MaxEncodedLen, - TypeInfo, + Clone, Copy, PartialEq, Eq, PartialOrd, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, )] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Amount(pub SubstrateAmount); impl Add for Amount { diff --git a/substrate/primitives/src/balance.rs b/substrate/primitives/src/balance.rs index 9d6ca678..8a0a7c9d 100644 --- a/substrate/primitives/src/balance.rs +++ b/substrate/primitives/src/balance.rs @@ -3,6 +3,9 @@ use core::ops::{Add, Sub, Mul}; #[cfg(feature = "std")] use zeroize::Zeroize; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; @@ -13,9 +16,11 @@ use crate::{Coin, Amount}; /// The type used for balances (a Coin and Balance). #[rustfmt::skip] #[derive( - Clone, Copy, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, + Clone, Copy, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, )] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Balance { pub coin: Coin, pub amount: Amount, diff --git a/substrate/primitives/src/block.rs b/substrate/primitives/src/block.rs index 0545ac63..db80a20c 100644 --- a/substrate/primitives/src/block.rs +++ b/substrate/primitives/src/block.rs @@ -1,6 +1,9 @@ #[cfg(feature = "std")] use zeroize::Zeroize; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; @@ -10,21 +13,11 @@ use sp_core::H256; /// The type used to identify block numbers. #[derive( - Clone, - Copy, - Default, - PartialEq, - Eq, - Hash, - Debug, - Serialize, - Deserialize, - Encode, - Decode, - MaxEncodedLen, - TypeInfo, + Clone, Copy, Default, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, )] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BlockNumber(pub u64); impl From for BlockNumber { fn from(number: u64) -> BlockNumber { @@ -37,21 +30,10 @@ impl From for BlockNumber { // If a block exists with a hash which isn't 32-bytes, it can be hashed into a value with 32-bytes // This would require the processor to maintain a mapping of 32-byte IDs to actual hashes, which // would be fine -#[derive( - Clone, - Copy, - PartialEq, - Eq, - Hash, - Debug, - Serialize, - Deserialize, - Encode, - Decode, - MaxEncodedLen, - TypeInfo, -)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct BlockHash(pub [u8; 32]); impl AsRef<[u8]> for BlockHash { diff --git a/substrate/primitives/src/lib.rs b/substrate/primitives/src/lib.rs index 6e946af2..c77be43f 100644 --- a/substrate/primitives/src/lib.rs +++ b/substrate/primitives/src/lib.rs @@ -5,6 +5,9 @@ #[cfg(feature = "std")] use zeroize::Zeroize; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use scale::{Encode, Decode, MaxEncodedLen}; @@ -29,16 +32,40 @@ pub use balance::*; mod account; pub use account::*; +#[cfg(feature = "borsh")] +pub fn borsh_serialize_bounded_vec( + bounded: &BoundedVec>, + writer: &mut W, +) -> Result<(), borsh::io::Error> { + borsh::BorshSerialize::serialize(bounded.as_slice(), writer) +} + +#[cfg(feature = "borsh")] +pub fn borsh_deserialize_bounded_vec( + reader: &mut R, +) -> Result>, borsh::io::Error> { + let vec: Vec = borsh::BorshDeserialize::deserialize_reader(reader)?; + vec.try_into().map_err(|_| borsh::io::Error::other("bound exceeded")) +} + // Monero, our current longest address candidate, has a longest address of featured // 1 (enum) + 1 (flags) + 64 (two keys) = 66 // When JAMTIS arrives, it'll become 112 or potentially even 142 bytes pub const MAX_ADDRESS_LEN: u32 = 196; -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] -pub struct ExternalAddress(BoundedVec>); - +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct ExternalAddress( + #[cfg_attr( + feature = "borsh", + borsh( + serialize_with = "borsh_serialize_bounded_vec", + deserialize_with = "borsh_deserialize_bounded_vec" + ) + )] + BoundedVec>, +); #[cfg(feature = "std")] impl Zeroize for ExternalAddress { fn zeroize(&mut self) { @@ -70,10 +97,19 @@ impl AsRef<[u8]> for ExternalAddress { // Should be enough for a Uniswap v3 call pub const MAX_DATA_LEN: u32 = 512; -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] -pub struct Data(BoundedVec>); +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct Data( + #[cfg_attr( + feature = "borsh", + borsh( + serialize_with = "borsh_serialize_bounded_vec", + deserialize_with = "borsh_deserialize_bounded_vec" + ) + )] + BoundedVec>, +); #[cfg(feature = "std")] impl Zeroize for Data { diff --git a/substrate/primitives/src/networks.rs b/substrate/primitives/src/networks.rs index 0e8b8c0e..80e5f3cb 100644 --- a/substrate/primitives/src/networks.rs +++ b/substrate/primitives/src/networks.rs @@ -1,29 +1,24 @@ #[cfg(feature = "std")] use zeroize::Zeroize; -use serde::{Serialize, Deserialize}; - use scale::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] +use serde::{Serialize, Deserialize}; + use sp_core::{ConstU32, bounded::BoundedVec}; +#[cfg(feature = "borsh")] +use crate::{borsh_serialize_bounded_vec, borsh_deserialize_bounded_vec}; + /// The type used to identify networks. -#[derive( - Clone, - Copy, - PartialEq, - Eq, - Hash, - Debug, - Serialize, - Deserialize, - Encode, - Decode, - MaxEncodedLen, - TypeInfo, -)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum NetworkId { Serai, Bitcoin, @@ -38,22 +33,11 @@ pub const COINS: [Coin; 5] = [Coin::Serai, Coin::Bitcoin, Coin::Ether, Coin::Dai /// The type used to identify coins. #[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Debug, - Serialize, - Deserialize, - Encode, - Decode, - MaxEncodedLen, - TypeInfo, + Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Encode, Decode, MaxEncodedLen, TypeInfo, )] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Coin { Serai, Bitcoin, @@ -123,10 +107,17 @@ impl Coin { pub const MAX_COINS_PER_NETWORK: u32 = 8; /// Network definition. -#[derive( - Clone, PartialEq, Eq, Debug, Serialize, Deserialize, Encode, Decode, MaxEncodedLen, TypeInfo, -)] +#[derive(Clone, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Network { + #[cfg_attr( + feature = "borsh", + borsh( + serialize_with = "borsh_serialize_bounded_vec", + deserialize_with = "borsh_deserialize_bounded_vec" + ) + )] coins: BoundedVec>, } diff --git a/substrate/validator-sets/primitives/Cargo.toml b/substrate/validator-sets/primitives/Cargo.toml index 7f11f4eb..fc37c27a 100644 --- a/substrate/validator-sets/primitives/Cargo.toml +++ b/substrate/validator-sets/primitives/Cargo.toml @@ -18,7 +18,8 @@ zeroize = { version = "^1.5", features = ["derive"], optional = true } ciphersuite = { path = "../../../crypto/ciphersuite", version = "0.4", default-features = false, features = ["alloc", "ristretto"] } dkg = { path = "../../../crypto/dkg", version = "0.5", default-features = false } -serde = { version = "1", default-features = false, features = ["derive", "alloc"] } +borsh = { version = "1", default-features = false, features = ["derive", "de_strict_order"], optional = true } +serde = { version = "1", default-features = false, features = ["derive", "alloc"], optional = true } scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive", "max-encoded-len"] } scale-info = { version = "2", default-features = false, features = ["derive"] } @@ -29,5 +30,7 @@ sp-std = { git = "https://github.com/serai-dex/substrate", default-features = fa serai-primitives = { path = "../../primitives", default-features = false } [features] -std = ["zeroize", "ciphersuite/std", "dkg/std", "serde/std", "scale/std", "scale-info/std", "sp-core/std", "sp-std/std", "serai-primitives/std"] +std = ["zeroize", "ciphersuite/std", "dkg/std", "borsh?/std", "serde?/std", "scale/std", "scale-info/std", "sp-core/std", "sp-std/std", "serai-primitives/std"] +borsh = ["dep:borsh", "serai-primitives/borsh"] +serde = ["dep:serde", "serai-primitives/serde"] default = ["std"] diff --git a/substrate/validator-sets/primitives/src/lib.rs b/substrate/validator-sets/primitives/src/lib.rs index 7485c511..c48e567e 100644 --- a/substrate/validator-sets/primitives/src/lib.rs +++ b/substrate/validator-sets/primitives/src/lib.rs @@ -7,6 +7,10 @@ use ciphersuite::{group::GroupEncoding, Ciphersuite, Ristretto}; use scale::{Encode, Decode, MaxEncodedLen}; use scale_info::TypeInfo; + +#[cfg(feature = "borsh")] +use borsh::{BorshSerialize, BorshDeserialize}; +#[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; use sp_core::{ConstU32, sr25519::Public, bounded::BoundedVec}; @@ -22,39 +26,18 @@ pub const MAX_KEY_LEN: u32 = 96; /// The type used to identify a specific session of validators. #[derive( - Clone, - Copy, - PartialEq, - Eq, - Hash, - Debug, - Serialize, - Deserialize, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, - Default, + Clone, Copy, PartialEq, Eq, Hash, Default, Debug, Encode, Decode, TypeInfo, MaxEncodedLen, )] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct Session(pub u32); /// The type used to identify a specific validator set during a specific session. -#[derive( - Clone, - Copy, - PartialEq, - Eq, - Hash, - Debug, - Serialize, - Deserialize, - Encode, - Decode, - TypeInfo, - MaxEncodedLen, -)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] #[cfg_attr(feature = "std", derive(Zeroize))] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct ValidatorSet { pub session: Session, pub network: NetworkId, @@ -67,7 +50,34 @@ pub type ExternalKey = BoundedVec; /// The key pair for a validator set. /// /// This is their Ristretto key, used for signing Batches, and their key on the external network. -pub type KeyPair = (Public, ExternalKey); +#[derive(Clone, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen)] +#[cfg_attr(feature = "borsh", derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct KeyPair( + #[cfg_attr( + feature = "borsh", + borsh( + serialize_with = "serai_primitives::borsh_serialize_public", + deserialize_with = "serai_primitives::borsh_deserialize_public" + ) + )] + pub Public, + #[cfg_attr( + feature = "borsh", + borsh( + serialize_with = "serai_primitives::borsh_serialize_bounded_vec", + deserialize_with = "serai_primitives::borsh_deserialize_bounded_vec" + ) + )] + pub ExternalKey, +); +#[cfg(feature = "std")] +impl Zeroize for KeyPair { + fn zeroize(&mut self) { + self.0 .0.zeroize(); + self.1.as_mut().zeroize(); + } +} /// The MuSig context for a validator set. pub fn musig_context(set: ValidatorSet) -> Vec { diff --git a/tests/coordinator/Cargo.toml b/tests/coordinator/Cargo.toml index 331ccdd8..2aa805ce 100644 --- a/tests/coordinator/Cargo.toml +++ b/tests/coordinator/Cargo.toml @@ -31,7 +31,7 @@ scale = { package = "parity-scale-codec", version = "3" } serai-client = { path = "../../substrate/client", features = ["serai"] } serai-message-queue = { path = "../../message-queue" } -serde_json = { version = "1", default-features = false } +borsh = { version = "1", features = ["de_strict_order"] } tokio = { version = "1", features = ["time"] } diff --git a/tests/coordinator/src/lib.rs b/tests/coordinator/src/lib.rs index 83a329d6..d2600092 100644 --- a/tests/coordinator/src/lib.rs +++ b/tests/coordinator/src/lib.rs @@ -268,7 +268,7 @@ impl Processor { assert_eq!(msg.from, Service::Coordinator); assert_eq!(msg.id, *next_recv_id); - let msg_msg = serde_json::from_slice(&msg.msg).unwrap(); + let msg_msg = borsh::from_slice(&msg.msg).unwrap(); if !is_cosign_message(&msg_msg) { continue; } @@ -309,7 +309,7 @@ impl Processor { res .send_message(messages::coordinator::ProcessorMessage::CosignPreprocess { id: id.clone(), - preprocesses: vec![vec![raw_i; 64]], + preprocesses: vec![[raw_i; 64]], }) .await; } @@ -387,7 +387,7 @@ impl Processor { to: Service::Coordinator, intent: msg.intent(), }, - serde_json::to_string(&msg).unwrap().into_bytes(), + borsh::to_vec(&msg).unwrap(), ) .await; *next_send_id += 1; @@ -408,7 +408,7 @@ impl Processor { assert_eq!(msg.id, *next_recv_id); // If this is a cosign message, let the cosign task handle it - let msg_msg = serde_json::from_slice(&msg.msg).unwrap(); + let msg_msg = borsh::from_slice(&msg.msg).unwrap(); if is_cosign_message(&msg_msg) { continue; } diff --git a/tests/coordinator/src/tests/batch.rs b/tests/coordinator/src/tests/batch.rs index 21318d7b..0e56f5ad 100644 --- a/tests/coordinator/src/tests/batch.rs +++ b/tests/coordinator/src/tests/batch.rs @@ -63,7 +63,7 @@ pub async fn batch( .send_message(messages::coordinator::ProcessorMessage::BatchPreprocess { id: id.clone(), block: batch.block, - preprocesses: vec![[processor_is[i]; 64].to_vec()], + preprocesses: vec![[processor_is[i]; 64]], }) .await; } @@ -77,7 +77,7 @@ pub async fn batch( .send_message(messages::coordinator::ProcessorMessage::BatchPreprocess { id: id.clone(), block: batch.block, - preprocesses: vec![[processor_is[excluded_signer]; 64].to_vec()], + preprocesses: vec![[processor_is[excluded_signer]; 64]], }) .await; @@ -98,7 +98,7 @@ pub async fn batch( let mut participants = preprocesses.keys().cloned().collect::>(); for (p, preprocess) in preprocesses { - assert_eq!(preprocess, vec![u8::try_from(u16::from(p)).unwrap(); 64]); + assert_eq!(preprocess, [u8::try_from(u16::from(p)).unwrap(); 64]); } participants.insert(known_signer_i); participants @@ -116,7 +116,7 @@ pub async fn batch( let mut preprocesses = participants .clone() .into_iter() - .map(|i| (i, [u8::try_from(u16::from(i)).unwrap(); 64].to_vec())) + .map(|i| (i, [u8::try_from(u16::from(i)).unwrap(); 64])) .collect::>(); preprocesses.remove(&i); diff --git a/tests/coordinator/src/tests/key_gen.rs b/tests/coordinator/src/tests/key_gen.rs index 8c3d54c6..de294571 100644 --- a/tests/coordinator/src/tests/key_gen.rs +++ b/tests/coordinator/src/tests/key_gen.rs @@ -16,7 +16,7 @@ use dkg::ThresholdParams; use serai_client::{ primitives::NetworkId, Public, - validator_sets::primitives::{Session, ValidatorSet}, + validator_sets::primitives::{Session, ValidatorSet, KeyPair}, }; use messages::{key_gen::KeyGenId, CoordinatorMessage}; @@ -205,7 +205,7 @@ pub async fn key_gen( .await .unwrap() .unwrap(), - (Public(substrate_key), network_key.try_into().unwrap()) + KeyPair(Public(substrate_key), network_key.try_into().unwrap()) ); for processor in processors.iter_mut() { diff --git a/tests/coordinator/src/tests/sign.rs b/tests/coordinator/src/tests/sign.rs index 8d593666..cacf4fa8 100644 --- a/tests/coordinator/src/tests/sign.rs +++ b/tests/coordinator/src/tests/sign.rs @@ -52,7 +52,7 @@ pub async fn sign( processor .send_message(messages::sign::ProcessorMessage::Preprocess { id: id.clone(), - preprocesses: vec![[processor_is[i]; 64].to_vec()], + preprocesses: vec![vec![processor_is[i]; 128]], }) .await; } @@ -65,7 +65,7 @@ pub async fn sign( processors[excluded_signer] .send_message(messages::sign::ProcessorMessage::Preprocess { id: id.clone(), - preprocesses: vec![[processor_is[excluded_signer]; 64].to_vec()], + preprocesses: vec![vec![processor_is[excluded_signer]; 128]], }) .await; @@ -83,7 +83,7 @@ pub async fn sign( let mut participants = preprocesses.keys().cloned().collect::>(); for (p, preprocess) in preprocesses { - assert_eq!(preprocess, vec![u8::try_from(u16::from(p)).unwrap(); 64]); + assert_eq!(preprocess, vec![u8::try_from(u16::from(p)).unwrap(); 128]); } participants.insert(known_signer_i); participants @@ -101,7 +101,7 @@ pub async fn sign( let mut preprocesses = participants .clone() .into_iter() - .map(|i| (i, [u8::try_from(u16::from(i)).unwrap(); 64].to_vec())) + .map(|i| (i, vec![u8::try_from(u16::from(i)).unwrap(); 128])) .collect::>(); preprocesses.remove(&i); diff --git a/tests/processor/Cargo.toml b/tests/processor/Cargo.toml index 03998d70..d7582eab 100644 --- a/tests/processor/Cargo.toml +++ b/tests/processor/Cargo.toml @@ -32,6 +32,7 @@ scale = { package = "parity-scale-codec", version = "3" } serai-client = { path = "../../substrate/client" } serai-message-queue = { path = "../../message-queue" } +borsh = { version = "1", features = ["de_strict_order"] } serde = { version = "1", default-features = false } serde_json = { version = "1", default-features = false } diff --git a/tests/processor/src/lib.rs b/tests/processor/src/lib.rs index c801d334..fa917ddc 100644 --- a/tests/processor/src/lib.rs +++ b/tests/processor/src/lib.rs @@ -224,7 +224,7 @@ impl Coordinator { to: Service::Processor(self.network), intent: msg.intent(), }, - serde_json::to_string(&msg).unwrap().into_bytes(), + borsh::to_vec(&msg).unwrap(), ) .await; self.next_send_id += 1; @@ -242,7 +242,7 @@ impl Coordinator { assert_eq!(msg.id, self.next_recv_id); self.queue.ack(Service::Processor(self.network), msg.id).await; self.next_recv_id += 1; - serde_json::from_slice(&msg.msg).unwrap() + borsh::from_slice(&msg.msg).unwrap() } pub async fn add_block(&self, ops: &DockerOperations) -> ([u8; 32], Vec) { diff --git a/tests/processor/src/tests/batch.rs b/tests/processor/src/tests/batch.rs index 96486567..419738db 100644 --- a/tests/processor/src/tests/batch.rs +++ b/tests/processor/src/tests/batch.rs @@ -26,7 +26,7 @@ pub(crate) async fn recv_batch_preprocesses( substrate_key: &[u8; 32], batch: &Batch, attempt: u32, -) -> (SubstrateSignId, HashMap>) { +) -> (SubstrateSignId, HashMap) { let id = SubstrateSignId { key: *substrate_key, id: SubstrateSignableId::Batch((batch.network, batch.id).encode().try_into().unwrap()), @@ -87,7 +87,7 @@ pub(crate) async fn sign_batch( coordinators: &mut [Coordinator], key: [u8; 32], id: SubstrateSignId, - preprocesses: HashMap>, + preprocesses: HashMap, ) -> SignedBatch { assert_eq!(preprocesses.len(), THRESHOLD); diff --git a/tests/processor/src/tests/key_gen.rs b/tests/processor/src/tests/key_gen.rs index f97eb227..c5640819 100644 --- a/tests/processor/src/tests/key_gen.rs +++ b/tests/processor/src/tests/key_gen.rs @@ -4,7 +4,7 @@ use dkg::{Participant, ThresholdParams, tests::clone_without}; use serai_client::{ primitives::{NetworkId, BlockHash, PublicKey}, - validator_sets::primitives::{Session, KeyPair, ValidatorSet}, + validator_sets::primitives::{Session, ValidatorSet, KeyPair}, }; use messages::{SubstrateContext, key_gen::KeyGenId, CoordinatorMessage, ProcessorMessage}; @@ -122,8 +122,10 @@ pub(crate) async fn key_gen(coordinators: &mut [Coordinator], network: NetworkId network_latest_finalized_block: BlockHash([0; 32]), }; - let key_pair = - (PublicKey::from_raw(substrate_key.unwrap()), network_key.clone().unwrap().try_into().unwrap()); + let key_pair = KeyPair( + PublicKey::from_raw(substrate_key.unwrap()), + network_key.clone().unwrap().try_into().unwrap(), + ); for coordinator in coordinators { coordinator