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
This commit is contained in:
Luke Parker
2023-11-25 04:01:11 -05:00
committed by GitHub
parent 6b2876351e
commit b296be8515
52 changed files with 468 additions and 309 deletions

View File

@@ -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
};

View File

@@ -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!(

View File

@@ -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]

View File

@@ -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"]

View File

@@ -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<Data>,
}
#[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),

View File

@@ -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",

View File

@@ -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;

View File

@@ -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"]

View File

@@ -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<ExternalAddress>,
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<InInstructionWithBalance>,
}
#[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,
}

View File

@@ -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 {

View File

@@ -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<RuntimeGenesisConfig>;
@@ -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),

View File

@@ -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"]

View File

@@ -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<W: borsh::io::Write>(
public: &Public,
writer: &mut W,
) -> Result<(), borsh::io::Error> {
borsh::BorshSerialize::serialize(&public.0, writer)
}
#[cfg(feature = "borsh")]
pub fn borsh_deserialize_public<R: borsh::io::Read>(
reader: &mut R,
) -> Result<Public, borsh::io::Error> {
let public: [u8; 32] = borsh::BorshDeserialize::deserialize_reader(reader)?;
Ok(Public(public))
}
#[cfg(feature = "borsh")]
pub fn borsh_serialize_signature<W: borsh::io::Write>(
signature: &Signature,
writer: &mut W,
) -> Result<(), borsh::io::Error> {
borsh::BorshSerialize::serialize(&signature.0, writer)
}
#[cfg(feature = "borsh")]
pub fn borsh_deserialize_signature<R: borsh::io::Read>(
reader: &mut R,
) -> Result<Signature, borsh::io::Error> {
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 {

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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<u64> for BlockNumber {
fn from(number: u64) -> BlockNumber {
@@ -37,21 +30,10 @@ impl From<u64> 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 {

View File

@@ -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<W: borsh::io::Write, T: BorshSerialize, const B: u32>(
bounded: &BoundedVec<T, ConstU32<B>>,
writer: &mut W,
) -> Result<(), borsh::io::Error> {
borsh::BorshSerialize::serialize(bounded.as_slice(), writer)
}
#[cfg(feature = "borsh")]
pub fn borsh_deserialize_bounded_vec<R: borsh::io::Read, T: BorshDeserialize, const B: u32>(
reader: &mut R,
) -> Result<BoundedVec<T, ConstU32<B>>, borsh::io::Error> {
let vec: Vec<T> = 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<u8, ConstU32<{ MAX_ADDRESS_LEN }>>);
#[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<u8, ConstU32<{ MAX_ADDRESS_LEN }>>,
);
#[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<u8, ConstU32<{ MAX_DATA_LEN }>>);
#[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<u8, ConstU32<{ MAX_DATA_LEN }>>,
);
#[cfg(feature = "std")]
impl Zeroize for Data {

View File

@@ -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<Coin, ConstU32<{ MAX_COINS_PER_NETWORK }>>,
}

View File

@@ -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"]

View File

@@ -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<u8, MaxKeyLen>;
/// 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<u8> {