diff --git a/substrate/abi/Cargo.toml b/substrate/abi/Cargo.toml index e048aba3..f4c802c6 100644 --- a/substrate/abi/Cargo.toml +++ b/substrate/abi/Cargo.toml @@ -47,6 +47,6 @@ std = [ "serai-primitives/std", ] -substrate = ["serde", "scale", "scale-info", "sp-runtime", "frame-support"] +substrate = ["serde", "scale", "scale-info", "sp-runtime", "frame-support", "serai-primitives/non_canonical_scale_derivations"] try-runtime = ["sp-runtime/try-runtime"] default = ["std"] diff --git a/substrate/primitives/Cargo.toml b/substrate/primitives/Cargo.toml index d9c2552d..255cdd6d 100644 --- a/substrate/primitives/Cargo.toml +++ b/substrate/primitives/Cargo.toml @@ -32,5 +32,6 @@ bech32 = { version = "0.11", default-features = false } rand_core = { version = "0.6", default-features = false, features = ["std"] } [features] +non_canonical_scale_derivations = [] std = ["zeroize/std", "borsh/std", "ciphersuite/std", "dkg/std", "sp-core/std", "bech32/std"] default = ["std"] diff --git a/substrate/primitives/src/balance.rs b/substrate/primitives/src/balance.rs index d2d6578e..c37846d7 100644 --- a/substrate/primitives/src/balance.rs +++ b/substrate/primitives/src/balance.rs @@ -10,18 +10,10 @@ use crate::coin::{ExternalCoin, Coin}; pub type AmountRepr = u64; /// A wrapper used to represent amounts. -#[derive( - Clone, - Copy, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Debug, - Zeroize, - BorshSerialize, - BorshDeserialize, +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)] +#[cfg_attr( + feature = "non_canonical_scale_derivations", + derive(scale::Encode, scale::Decode, scale::MaxEncodedLen) )] pub struct Amount(pub AmountRepr); @@ -48,6 +40,10 @@ impl Mul for Amount { /// An ExternalCoin and an Amount, forming a balance for an external coin. #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)] +#[cfg_attr( + feature = "non_canonical_scale_derivations", + derive(scale::Encode, scale::Decode, scale::MaxEncodedLen) +)] pub struct ExternalBalance { /// The coin this is a balance for. pub coin: ExternalCoin, @@ -78,6 +74,10 @@ impl Mul for ExternalBalance { /// A Coin and an Amount, forming a balance for a coin. #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize, BorshSerialize, BorshDeserialize)] +#[cfg_attr( + feature = "non_canonical_scale_derivations", + derive(scale::Encode, scale::Decode, scale::MaxEncodedLen) +)] pub struct Balance { /// The coin this is a balance for. pub coin: Coin, diff --git a/substrate/primitives/src/coin.rs b/substrate/primitives/src/coin.rs index 93ddaa76..80405f50 100644 --- a/substrate/primitives/src/coin.rs +++ b/substrate/primitives/src/coin.rs @@ -9,6 +9,10 @@ use crate::network_id::{ExternalNetworkId, NetworkId}; /// This type serializes to a subset of `Coin`. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize, BorshSerialize, BorshDeserialize)] #[borsh(use_discriminant = true)] +#[cfg_attr( + feature = "non_canonical_scale_derivations", + derive(scale::Encode, scale::Decode, scale::MaxEncodedLen) +)] #[non_exhaustive] pub enum ExternalCoin { /// Bitcoin, from the Bitcoin network. @@ -31,6 +35,10 @@ impl ExternalCoin { /// The type used to identify coins. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Zeroize)] +#[cfg_attr( + feature = "non_canonical_scale_derivations", + derive(scale::Encode, scale::Decode, scale::MaxEncodedLen) +)] pub enum Coin { /// The Serai coin. Serai, diff --git a/substrate/primitives/src/merkle.rs b/substrate/primitives/src/merkle.rs index 65a2a649..5b871495 100644 --- a/substrate/primitives/src/merkle.rs +++ b/substrate/primitives/src/merkle.rs @@ -67,7 +67,8 @@ impl UnbalancedMerkleTree { } /// An unbalanced Merkle tree which is incrementally created. -#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] +#[derive(Clone, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "non_canonical_scale_derivations", derive(scale::Encode, scale::Decode))] pub struct IncrementalUnbalancedMerkleTree { /// (number of children under branch, branch hash) branches: Vec<(u64, [u8; 32])>, diff --git a/substrate/runtime/src/core_pallet.rs b/substrate/runtime/src/core_pallet.rs index 5ef17b85..a1470257 100644 --- a/substrate/runtime/src/core_pallet.rs +++ b/substrate/runtime/src/core_pallet.rs @@ -1,7 +1,6 @@ use core::marker::PhantomData; -use alloc::{vec, vec::Vec}; -use borsh::{BorshSerialize, BorshDeserialize}; +use borsh::BorshSerialize; use frame_support::pallet_prelude::*; @@ -10,13 +9,14 @@ use serai_abi::{ *, }; +/// A wrapper around a `StorageValue` which offers a high-level API as an IUMT. struct IncrementalUnbalancedMerkleTree< - T: frame_support::StorageValue, Query = Option>>, + T: frame_support::StorageValue>, const BRANCH_TAG: u8 = 1, const LEAF_TAG: u8 = 0, >(PhantomData); impl< - T: frame_support::StorageValue, Query = Option>>, + T: frame_support::StorageValue>, const BRANCH_TAG: u8, const LEAF_TAG: u8, > IncrementalUnbalancedMerkleTree @@ -27,7 +27,7 @@ impl< fn new_expecting_none() { T::mutate(|value| { assert!(value.is_none()); - *value = Some(borsh::to_vec(&Iumt::new()).unwrap()); + *value = Some(Iumt::new()); }); } /// Append a leaf to the Merkle tree. @@ -37,26 +37,21 @@ impl< let leaf = sp_core::blake2_256(&borsh::to_vec(&(LEAF_TAG, leaf)).unwrap()); T::mutate(|value| { - let mut tree = Iumt::deserialize_reader(&mut value.as_ref().unwrap().as_slice()).unwrap(); + let tree = value.as_mut().unwrap(); tree.append(BRANCH_TAG, leaf); - *value = Some(borsh::to_vec(&tree).unwrap()); }) } /// Get the unbalanced merkle tree. /// /// Panics if no Merkle tree was present. fn get() -> UnbalancedMerkleTree { - Iumt::deserialize_reader(&mut T::get().unwrap().as_slice()).unwrap().calculate(BRANCH_TAG) + T::get().unwrap().calculate(BRANCH_TAG) } /// Take the Merkle tree. /// /// Panics if no Merkle tree was present. fn take() -> UnbalancedMerkleTree { - T::mutate(|value| { - let tree = Iumt::deserialize_reader(&mut value.as_ref().unwrap().as_slice()).unwrap(); - *value = None; - tree.calculate(BRANCH_TAG) - }) + T::mutate(|value| value.take().unwrap().calculate(BRANCH_TAG)) } } @@ -70,20 +65,20 @@ mod pallet { /// The Merkle tree of all blocks added to the blockchain. #[pallet::storage] #[pallet::unbounded] - pub(super) type BlocksCommitment = StorageValue<_, Vec, OptionQuery>; + pub(super) type BlocksCommitment = StorageValue<_, Iumt, OptionQuery>; pub(super) type BlocksCommitmentMerkle = IncrementalUnbalancedMerkleTree>; /// The Merkle tree of all transactions within the current block. #[pallet::storage] #[pallet::unbounded] - pub(super) type BlockTransactionsCommitment = StorageValue<_, Vec, OptionQuery>; + pub(super) type BlockTransactionsCommitment = StorageValue<_, Iumt, OptionQuery>; pub(super) type BlockTransactionsCommitmentMerkle = IncrementalUnbalancedMerkleTree>; /// The hashes of events caused by the current transaction. #[pallet::storage] #[pallet::unbounded] - pub(super) type TransactionEvents = StorageValue<_, Vec, OptionQuery>; + pub(super) type TransactionEvents = StorageValue<_, Iumt, OptionQuery>; pub(super) type TransactionEventsMerkle = IncrementalUnbalancedMerkleTree< TransactionEvents, TRANSACTION_EVENTS_COMMITMENT_BRANCH_TAG, @@ -92,7 +87,7 @@ mod pallet { /// The roots of the Merkle trees of each transaction's events. #[pallet::storage] #[pallet::unbounded] - pub(super) type BlockEventsCommitment = StorageValue<_, Vec, OptionQuery>; + pub(super) type BlockEventsCommitment = StorageValue<_, Iumt, OptionQuery>; pub(super) type BlockEventsCommitmentMerkle = IncrementalUnbalancedMerkleTree< BlockEventsCommitment, EVENTS_COMMITMENT_BRANCH_TAG, @@ -105,12 +100,7 @@ mod pallet { StorageMap<_, Blake2_128Concat, T::AccountId, T::Nonce, ValueQuery>; #[pallet::config] - pub trait Config: - frame_system::Config< - Block: sp_runtime::traits::Block>>, - > - { - } + pub trait Config: frame_system::Config> {} #[pallet::pallet] pub struct Pallet(_); @@ -141,12 +131,11 @@ pub(super) use pallet::*; pub struct StartOfBlock(PhantomData); impl frame_support::traits::PreInherents for StartOfBlock { fn pre_inherents() { - let parent_hash = frame_system::Pallet::::parent_hash(); - Blocks::::set(parent_hash, Some(())); - // TODO: Better detection of genesis - if parent_hash == Default::default() { + if frame_system::Pallet::::block_number().is_zero() { BlocksCommitmentMerkle::::new_expecting_none(); } else { + let parent_hash = frame_system::Pallet::::parent_hash(); + Blocks::::set(parent_hash, Some(())); let parent_hash: [u8; 32] = parent_hash.into(); BlocksCommitmentMerkle::::append(&parent_hash); }