From d20340fc7384d9b656853cb6d5bc7b14c182007f Mon Sep 17 00:00:00 2001 From: R2D2 Date: Mon, 26 Sep 2022 16:23:35 +0200 Subject: [PATCH 01/28] [tmp]: Refactoring the merkle tree to properly support multistores more easily --- Cargo.lock | 268 ++++++++++++++++++ apps/src/lib/node/ledger/protocol/mod.rs | 3 - shared/Cargo.toml | 2 + .../ledger/eth_bridge/storage/bridge_pool.rs | 158 +++++++++++ shared/src/ledger/storage/merkle_tree.rs | 250 +++++----------- shared/src/ledger/storage/mod.rs | 1 + shared/src/ledger/storage/traits.rs | 214 ++++++++++++++ shared/src/types/eth_bridge_pool.rs | 28 +- shared/src/types/ethereum_events.rs | 15 +- shared/src/types/hash.rs | 23 +- shared/src/types/keccak.rs | 194 +++++++++++++ shared/src/types/mod.rs | 1 + shared/src/types/storage.rs | 57 +++- .../vote_extensions/validator_set_update.rs | 8 +- .../validator_set_update/encoding.rs | 99 ------- 15 files changed, 1005 insertions(+), 316 deletions(-) create mode 100644 shared/src/ledger/storage/traits.rs create mode 100644 shared/src/types/keccak.rs delete mode 100644 shared/src/types/vote_extensions/validator_set_update/encoding.rs diff --git a/Cargo.lock b/Cargo.lock index ad55b9f77b..69d5ab3f90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,6 +1137,28 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "chrono-tz" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + [[package]] name = "chunked_transfer" version = "1.4.0" @@ -1780,6 +1802,12 @@ dependencies = [ "syn", ] +[[package]] +name = "deunicode" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" + [[package]] name = "diff" version = "0.1.12" @@ -2619,6 +2647,17 @@ dependencies = [ "regex", ] +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags", + "ignore", + "walkdir", +] + [[package]] name = "gloo-timers" version = "0.2.4" @@ -2895,6 +2934,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humansize" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" + [[package]] name = "hyper" version = "0.10.16" @@ -3121,6 +3166,24 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ignore" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +dependencies = [ + "crossbeam-utils 0.8.8", + "globset", + "lazy_static 1.4.0", + "log 0.4.17", + "memchr", + "regex", + "same-file", + "thread_local 1.1.4", + "walkdir", + "winapi-util", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -4060,6 +4123,12 @@ dependencies = [ "serde_yaml", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "match_cfg" version = "0.1.0" @@ -4424,6 +4493,8 @@ dependencies = [ "tonic-build", "tracing 0.1.35", "tracing-subscriber 0.3.11", + "variant_access_derive", + "variant_access_traits", "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", @@ -5173,6 +5244,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + [[package]] name = "paste" version = "1.0.7" @@ -5239,6 +5319,40 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1 0.8.2", +] + [[package]] name = "petgraph" version = "0.5.1" @@ -5259,6 +5373,45 @@ dependencies = [ "indexmap", ] +[[package]] +name = "phf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +dependencies = [ + "siphasher", + "uncased", +] + [[package]] name = "pin-project" version = "0.4.29" @@ -6736,12 +6889,27 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "slab" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +[[package]] +name = "slug" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" +dependencies = [ + "deunicode", +] + [[package]] name = "smallvec" version = "0.6.14" @@ -7130,6 +7298,28 @@ dependencies = [ "time 0.3.9", ] +[[package]] +name = "tera" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d" +dependencies = [ + "chrono", + "chrono-tz", + "globwalk", + "humansize", + "lazy_static 1.4.0", + "percent-encoding 2.1.0", + "pest", + "pest_derive", + "rand 0.8.5", + "regex", + "serde 1.0.137", + "serde_json", + "slug", + "unic-segment", +] + [[package]] name = "term_size" version = "0.3.2" @@ -7936,6 +8126,65 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uncased" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" +dependencies = [ + "version_check 0.9.4", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" +dependencies = [ + "unic-ucd-segment", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "1.4.2" @@ -8096,6 +8345,25 @@ dependencies = [ "version_check 0.9.4", ] +[[package]] +name = "variant_access_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd235ffafb854ed81b49217ce411e850a39628a5d26740ecfb60421c873d834" +dependencies = [ + "lazy_static 1.4.0", + "quote", + "syn", + "tera", + "variant_access_traits", +] + +[[package]] +name = "variant_access_traits" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d75c5a83bb8912dd9c628adf954c9f9bff74a4e170d2c90242f4e56a0d643e" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/apps/src/lib/node/ledger/protocol/mod.rs b/apps/src/lib/node/ledger/protocol/mod.rs index 9b1b13c859..90bb6994b1 100644 --- a/apps/src/lib/node/ledger/protocol/mod.rs +++ b/apps/src/lib/node/ledger/protocol/mod.rs @@ -204,9 +204,6 @@ where /// containing changed keys and the like should be returned in the normal way. pub(crate) fn apply_protocol_tx<'a, D, H>( tx: ProtocolTxType, - // TODO: eventually this `storage` parameter could be tightened further to - // an impl trait of only the subset of [`Storage`] functionality that we - // need _storage: &'a mut Storage, ) -> Result where diff --git a/shared/Cargo.toml b/shared/Cargo.toml index aa20e50739..d344d346ad 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -96,6 +96,8 @@ tendermint-proto = {git = "https://github.com/heliaxdev/tendermint-rs", rev = "9 thiserror = "1.0.30" tiny-keccak = "2.0.2" tracing = "0.1.30" +variant_access_derive = "0.4.1" +variant_access_traits = "0.4.1" wasmer = {version = "=2.2.0", optional = true} wasmer-cache = {version = "=2.2.0", optional = true} wasmer-compiler-singlepass = {version = "=2.2.0", optional = true} diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index b86266f124..8588ae0550 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -1,8 +1,18 @@ //! Tools for accessing the storage subspaces of the Ethereum //! bridge pool +use std::collections::BTreeMap; +use std::convert::TryInto; +use std::ops::Deref; + +use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use eyre::eyre; use crate::types::address::{Address, InternalAddress}; +use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; +use crate::types::ethereum_events::KeccakHash; +use crate::types::hash::{Hash, keccak_hash}; use crate::types::storage::{DbKeySeg, Key}; +use crate::ledger::storage::{Sha256Hasher, StorageHasher}; /// The main address of the Ethereum bridge pool pub const BRIDGE_POOL_ADDRESS: Address = @@ -12,6 +22,11 @@ const PENDING_TRANSFERS_SEG: &str = "pending_transfers"; /// Sub-segment for getting the latest signed const SIGNED_ROOT_SEG: &str = "signed_root"; +#[derive(thiserror::Error, Debug)] +#[error(transparent)] +/// Generic error that may be returned by the validity predicate +pub struct Error(#[from] eyre::Error); + /// Get the storage key for the transfers in the pool pub fn get_pending_key() -> Key { Key { @@ -44,3 +59,146 @@ pub fn is_bridge_pool_key(key: &Key) -> bool { pub fn is_protected_storage(key: &Key) -> bool { is_bridge_pool_key(key) && *key != get_pending_key() } + +/// A simple Merkle tree for the Ethereum bridge pool +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, BorshSchema)] +pub struct BridgePoolTree { + /// Root of the tree + root: KeccakHash, + /// The underlying storage + store: BTreeMap +} + +/// TODO: Hash ABI instead of Borsh +impl BridgePoolTree { + /// Create a new merkle tree for the Ethereum bridge pool + pub fn new(root: KeccakHash, store: BTreeMap) -> Self { + Self{ root, store } + } + + /// Parse the key to ensure it is of the correct type. + /// + /// If it is, it can be converted to a hash. + /// Checks if the hash is in the tree. + pub fn has_key(&self, key: &Key) -> Result { + Ok(self.store.contains_key(&Self::parse_key(key)?)) + } + + /// Update the tree with a new value. + /// + /// Returns the new root if successful. Will + /// return an error if the key is malformed. + pub fn update(&mut self, key: &Key, value: PendingTransfer) -> Result { + let hash = Self::parse_key(key)?; + if hash != keccak_hash(&value.try_to_vec().unwrap()) { + return eyre!("Key does not match hash of the value")?; + } + _ = self.store.insert(hash, value); + self.root = self.compute_root(); + Ok(self.root()) + } + + /// Delete a key from storage and update the root + pub fn delete(&mut self, key: &Key) -> Result<(), Error>{ + let hash = Self::parse_key(key)?; + _ = self.store.remove(&hash); + self.root = self.compute_root(); + Ok(()) + } + + /// Compute the root of the merkle tree + pub fn compute_root(&self) -> KeccakHash { + let mut leaves = self.store.iter(); + let mut root = if let Some((hash, _)) = leaves.next() { + hash.clone() + } else { + return Default::default(); + }; + + for (leaf, _) in leaves { + root = keccak_hash([root.0, leaf.0].concat()); + } + root + } + + /// Return the root as a [`Hash`] type. + pub fn root(&self) -> Hash { + self.root.clone().into() + } + + /// Get a reference to the backing store + pub fn store(&self) -> &BTreeMap { + &self.store + } + + pub fn membership_proof(&self, keys: &[Key]) -> BridgePoolProof { + for (key, value) in self.store { + + } + } + + /// Parse a db key to see if it is valid for the + /// bridge pool. + /// + /// It should have one string segment which should + /// parse into a [Hash] + fn parse_key(key: &Key) -> Result { + if key.segments.len() == 1 { + match &key.segments[0] { + DbKeySeg::StringSeg(str) => str.as_str().try_into().ok_or( + eyre!("Could not parse key segment as a hash")? + ), + _ => eyre!("Bridge pool keys should be strings, not addresses")? + } + } else { + eyre!("Key for the bridge pool should not have more than one segment")? + } + } +} + +/// A multi-leaf membership proof +pub struct BridgePoolProof { + /// The hashes other than the provided leaves + pub proof: Vec, + /// The leaves; must be sorted + pub leaves: Vec, + /// flags to indicate how to combine hashes + pub flags: Vec, +} + +impl BridgePoolProof { + + /// Verify a membership proof matches the provided root + pub fn verify(&self, root: KeccakHash) -> bool { + if self.proof.len() + self.leaves.len() != self.flags.len() { + return false; + } + if self.flags.len() == 0 { + return true; + } + let mut leaf_pos = 0usize; + let mut proof_pos = 0usize; + let mut computed; + if self.flags[0] { + leaf = self.leaves[leaf_pos].clone(); + computed = keccak_hash(leaf.try_to_vec().unwrap()); + leaf_pos += 1; + } else { + computed = self.proof[proof_pos].clone(); + proof_pos += 1; + } + for flag in 1..self.flages.len() { + let mut next_hash; + if self.flags[flag] { + leaf = self.leaves[leaf_pos].clone(); + next_hash = keccak_hash(leaf.try_to_vec().unwrap()); + leaf_pos += 1; + } else { + next_hash = self.proof[proof_pos].clone(); + proof_pos += 1; + } + computed = keccak_hash([computed, next_hash].concat()); + } + computed == root + } +} diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index c7fec10126..cc26b95b5d 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -16,20 +16,22 @@ use ics23::{ CommitmentProof, ExistenceProof, HashOp, LeafOp, LengthOp, NonExistenceProof, ProofSpec, }; -use itertools::Either; +use itertools::{Either, Itertools}; use prost::Message; use sha2::{Digest, Sha256}; use tendermint::merkle::proof::{Proof, ProofOp}; use thiserror::Error; use super::IBC_KEY_LIMIT; +use super::traits::{self, StorageHasher, Sha256Hasher}; use crate::bytes::ByteBuf; +use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; use crate::ledger::storage::types; use crate::types::address::{Address, InternalAddress}; +use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; +use crate::types::ethereum_events::KeccakHash; use crate::types::hash::Hash; -use crate::types::storage::{ - DbKeySeg, Error as StorageError, Key, MerkleKey, StringKey, TreeBytes, -}; +use crate::types::storage::{DbKeySeg, Error as StorageError, Key, StringKey, TreeBytes, MerkleValue}; #[allow(missing_docs)] #[derive(Error, Debug)] @@ -41,11 +43,13 @@ pub enum Error { #[error("Empty Key: {0}")] EmptyKey(String), #[error("Merkle Tree error: {0}")] - MerkleTree(MtError), + MerkleTree(String), #[error("Invalid store type: {0}")] StoreType(String), #[error("Non-existence proofs not supported for store type: {0}")] NonExistenceProof(String), + #[error("Invalid value given to sub-tree storage")] + InvalidValue, } /// Result for functions that may fail @@ -54,6 +58,7 @@ type Result = std::result::Result; /// Type aliases for the different merkle trees and backing stores pub type SmtStore = DefaultStore; pub type AmtStore = DefaultStore; +pub type BridgePoolStore = std::collections::BTreeMap; pub type Smt = ArseMerkleTree; pub type Amt = ArseMerkleTree; @@ -79,6 +84,8 @@ pub enum StoreType { Ibc, /// For PoS-related data PoS, + /// For the Ethereum bridge Pool transfers + BridgePool, } /// Backing storage for merkle trees @@ -91,6 +98,8 @@ pub enum Store { Ibc(AmtStore), /// For PoS-related data PoS(SmtStore), + /// For the Ethereum bridge Pool transfers + BridgePool(BTreeSetStore) } impl Store { @@ -100,6 +109,7 @@ impl Store { Self::Account(store) => StoreRef::Account(store), Self::Ibc(store) => StoreRef::Ibc(store), Self::PoS(store) => StoreRef::PoS(store), + Self::BridgePool(store) => StoreRef::BridgePool(store), } } } @@ -114,6 +124,8 @@ pub enum StoreRef<'a> { Ibc(&'a AmtStore), /// For PoS-related data PoS(&'a SmtStore), + /// For the Ethereum bridge Pool transfers + BridgePool(&'a BTreeSetStore) } impl<'a> StoreRef<'a> { @@ -123,6 +135,7 @@ impl<'a> StoreRef<'a> { Self::Account(store) => Store::Account(store.to_owned()), Self::Ibc(store) => Store::Ibc(store.to_owned()), Self::PoS(store) => Store::PoS(store.to_owned()), + Self::BridgePool(store) => Store::BridgePool(store.to_owned()), } } @@ -132,6 +145,7 @@ impl<'a> StoreRef<'a> { Self::Account(store) => store.try_to_vec(), Self::Ibc(store) => store.try_to_vec(), Self::PoS(store) => store.try_to_vec(), + Self::BridgePool(store) => store.try_to_vec(), } .expect("Serialization failed") } @@ -140,11 +154,12 @@ impl<'a> StoreRef<'a> { impl StoreType { /// Get an iterator for the base tree and subtrees pub fn iter() -> std::slice::Iter<'static, Self> { - static SUB_TREE_TYPES: [StoreType; 4] = [ + static SUB_TREE_TYPES: [StoreType; 5] = [ StoreType::Base, StoreType::Account, StoreType::PoS, StoreType::Ibc, + StoreType::BridgePool, ]; SUB_TREE_TYPES.iter() } @@ -162,6 +177,9 @@ impl StoreType { InternalAddress::Ibc => { Ok((StoreType::Ibc, key.sub_key()?)) } + InternalAddress::EthBridgePool => { + Ok((StoreType::BridgePool, key.sub_key()?)) + } // use the same key for Parameters _ => Ok((StoreType::Account, key.clone())), } @@ -190,6 +208,9 @@ impl StoreType { Self::PoS => Ok(Store::PoS( types::decode(bytes).map_err(Error::CodingError)?, )), + Self::BridgePool => Ok(Store::BridgePool( + types::decode(bytes).map_err(Error::CodingError)?, + )), } } } @@ -203,6 +224,7 @@ impl FromStr for StoreType { "account" => Ok(StoreType::Account), "ibc" => Ok(StoreType::Ibc), "pos" => Ok(StoreType::PoS), + "eth_bridge_pool" => Ok(StoreType::BridgePool), _ => Err(Error::StoreType(s.to_string())), } } @@ -215,6 +237,7 @@ impl fmt::Display for StoreType { StoreType::Account => write!(f, "account"), StoreType::Ibc => write!(f, "ibc"), StoreType::PoS => write!(f, "pos"), + StoreType::BridgePool => write!(f, "eth_bridge_pool"), } } } @@ -226,6 +249,7 @@ pub struct MerkleTree { account: Smt, ibc: Amt, pos: Smt, + bridge_pool: BridgePoolTree, } impl core::fmt::Debug for MerkleTree { @@ -244,47 +268,43 @@ impl MerkleTree { let account = Smt::new(stores.account.0.into(), stores.account.1); let ibc = Amt::new(stores.ibc.0.into(), stores.ibc.1); let pos = Smt::new(stores.pos.0.into(), stores.pos.1); - + let bridge_pool = BridgePoolTree::new(stores.bridge_pool.0, stores.bridge_pool.1); Self { base, account, ibc, pos, + bridge_pool, + } + } + + fn tree(&self, store_type: &StoreType) -> &impl traits::MerkleTree { + match store_type { + StoreType::Base => &self.base, + StoreType::Account => &self.account, + StoreType::Ibc => &self.ibc, + StoreType::PoS => &self.pos, + StoreType::BridgePool => &self.bridge_pool, } } - fn tree(&self, store_type: &StoreType) -> Either<&Smt, &Amt> { + fn tree_mut(&mut self, store_type: &StoreType) -> &mut impl traits::MerkleTree { match store_type { - StoreType::Base => Either::Left(&self.base), - StoreType::Account => Either::Left(&self.account), - StoreType::Ibc => Either::Right(&self.ibc), - StoreType::PoS => Either::Left(&self.pos), + StoreType::Base => &mut self.base, + StoreType::Account => &mut self.account, + StoreType::Ibc => &mut self.ibc, + StoreType::PoS => &mut self.pos, + StoreType::BridgePool => &mut self.bridge_pool, } } - fn update_tree( + fn update_tree>( &mut self, store_type: &StoreType, - key: MerkleKey, - value: Either, + key: &Key, + value: MerkleValue, ) -> Result<()> { - let sub_root = match store_type { - StoreType::Account => self - .account - .update(key.try_into()?, value.unwrap_left()) - .map_err(Error::MerkleTree)?, - StoreType::Ibc => self - .ibc - .update(key.try_into()?, value.unwrap_right()) - .map_err(Error::MerkleTree)?, - StoreType::PoS => self - .pos - .update(key.try_into()?, value.unwrap_left()) - .map_err(Error::MerkleTree)?, - // base tree should not be directly updated - StoreType::Base => unreachable!(), - }; - + let sub_root = self.tree_mut(store_type).update(key, value)?; // update the base tree with the updated sub root without hashing if *store_type != StoreType::Base { let base_key = H::hash(&store_type.to_string()); @@ -296,41 +316,19 @@ impl MerkleTree { /// Check if the key exists in the tree pub fn has_key(&self, key: &Key) -> Result { let (store_type, sub_key) = StoreType::sub_key(key)?; - let value = match self.tree(&store_type) { - Either::Left(smt) => { - smt.get(&H::hash(sub_key.to_string()).into())?.is_zero() - } - Either::Right(amt) => { - let key = - StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; - amt.get(&key)?.is_zero() - } - }; - Ok(!value) + self.tree(&store_type).has_key(&sub_key) } /// Update the tree with the given key and value - pub fn update(&mut self, key: &Key, value: impl AsRef<[u8]>) -> Result<()> { - let sub_key = StoreType::sub_key(key)?; - let store_type = sub_key.0; - let value = match store_type { - StoreType::Ibc => { - Either::Right(TreeBytes::from(value.as_ref().to_vec())) - } - _ => Either::Left(H::hash(value).into()), - }; - self.update_tree(&store_type, sub_key.into(), value) + pub fn update>(&mut self, key: &Key, value: impl Into>) -> Result<()> { + let (store_type, sub_key) = StoreType::sub_key(key)?; + self.update_tree(&store_type, sub_key.into(), value.into()) } /// Delete the value corresponding to the given key pub fn delete(&mut self, key: &Key) -> Result<()> { - let sub_key = StoreType::sub_key(key)?; - let store_type = sub_key.0; - let value = match store_type { - StoreType::Ibc => Either::Right(TreeBytes::zero()), - _ => Either::Left(H256::zero().into()), - }; - self.update_tree(&store_type, sub_key.into(), value) + let (store_type, sub_key) = StoreType::sub_key(key)?; + self.tree_mut(&store_type).delete(&sub_key) } /// Get the root @@ -345,6 +343,7 @@ impl MerkleTree { account: (self.account.root().into(), self.account.store()), ibc: (self.ibc.root().into(), self.ibc.store()), pos: (self.pos.root().into(), self.pos.store()), + bridge_pool: (self.bridge_pool.root(). self.) } } @@ -568,45 +567,6 @@ impl fmt::Display for MerkleRoot { } } -impl From<(StoreType, Key)> for MerkleKey { - fn from((store, key): (StoreType, Key)) -> Self { - match store { - StoreType::Base | StoreType::Account | StoreType::PoS => { - MerkleKey::Sha256(key, PhantomData) - } - StoreType::Ibc => MerkleKey::Raw(key), - } - } -} - -impl TryFrom> for SmtHash { - type Error = Error; - - fn try_from(value: MerkleKey) -> Result { - match value { - MerkleKey::Sha256(key, _) => Ok(H::hash(key.to_string()).into()), - _ => Err(Error::InvalidMerkleKey( - "This key is for a sparse merkle tree".into(), - )), - } - } -} - -impl TryFrom> for StringKey { - type Error = Error; - - fn try_from(value: MerkleKey) -> Result { - match value { - MerkleKey::Raw(key) => { - Self::try_from_bytes(key.to_string().as_bytes()) - } - _ => Err(Error::InvalidMerkleKey( - "This is not an key for the IBC subtree".into(), - )), - } - } -} - /// The root and store pairs to restore the trees #[derive(Default)] pub struct MerkleTreeStoresRead { @@ -614,6 +574,7 @@ pub struct MerkleTreeStoresRead { account: (Hash, SmtStore), ibc: (Hash, AmtStore), pos: (Hash, SmtStore), + bridge_pool: (KeccakHash, BTreeSetStore), } impl MerkleTreeStoresRead { @@ -624,6 +585,7 @@ impl MerkleTreeStoresRead { StoreType::Account => self.account.0 = root, StoreType::Ibc => self.ibc.0 = root, StoreType::PoS => self.pos.0 = root, + StoreType::BridgePool => self.bridge_pool.0 = root.into(), } } @@ -634,6 +596,7 @@ impl MerkleTreeStoresRead { Store::Account(store) => self.account.1 = store, Store::Ibc(store) => self.ibc.1 = store, Store::PoS(store) => self.pos.1 = store, + Store::BridgePool(store) => self.bridge_pool.1 = store, } } } @@ -644,6 +607,7 @@ pub struct MerkleTreeStoresWrite<'a> { account: (Hash, &'a SmtStore), ibc: (Hash, &'a AmtStore), pos: (Hash, &'a SmtStore), + bridge_pool: (Hash, &'a BTreeSetStore) } impl<'a> MerkleTreeStoresWrite<'a> { @@ -654,6 +618,7 @@ impl<'a> MerkleTreeStoresWrite<'a> { StoreType::Account => &self.account.0, StoreType::Ibc => &self.ibc.0, StoreType::PoS => &self.pos.0, + StoreType::BridgePool => &self.bridge_pool.0 } } @@ -664,96 +629,11 @@ impl<'a> MerkleTreeStoresWrite<'a> { StoreType::Account => StoreRef::Account(self.account.1), StoreType::Ibc => StoreRef::Ibc(self.ibc.1), StoreType::PoS => StoreRef::PoS(self.pos.1), + StoreType::BridgePool => StoreRef::BridgePool(self.bridge_pool.1) } } } -impl TreeKey for StringKey { - type Error = Error; - - fn as_slice(&self) -> &[u8] { - &self.original.as_slice()[..self.length] - } - - fn try_from_bytes(bytes: &[u8]) -> Result { - let mut tree_key = [0u8; IBC_KEY_LIMIT]; - let mut original = [0u8; IBC_KEY_LIMIT]; - let mut length = 0; - for (i, byte) in bytes.iter().enumerate() { - if i >= IBC_KEY_LIMIT { - return Err(Error::InvalidMerkleKey( - "Input IBC key is too large".into(), - )); - } - original[i] = *byte; - tree_key[i] = byte.wrapping_add(1); - length += 1; - } - Ok(Self { - original, - tree_key: tree_key.into(), - length, - }) - } -} - -impl Value for TreeBytes { - fn as_slice(&self) -> &[u8] { - self.0.as_slice() - } - - fn zero() -> Self { - TreeBytes::zero() - } -} - -/// The storage hasher used for the merkle tree. -pub trait StorageHasher: Hasher + Default { - /// Hash the value to store - fn hash(value: impl AsRef<[u8]>) -> H256; -} - -/// The storage hasher used for the merkle tree. -#[derive(Default)] -pub struct Sha256Hasher(Sha256); - -impl Hasher for Sha256Hasher { - fn write_bytes(&mut self, h: &[u8]) { - self.0.update(h) - } - - fn finish(self) -> arse_merkle_tree::H256 { - let hash = self.0.finalize(); - let bytes: [u8; 32] = hash - .as_slice() - .try_into() - .expect("Sha256 output conversion to fixed array shouldn't fail"); - bytes.into() - } - - fn hash_op() -> ics23::HashOp { - ics23::HashOp::Sha256 - } -} - -impl StorageHasher for Sha256Hasher { - fn hash(value: impl AsRef<[u8]>) -> H256 { - let mut hasher = Sha256::new(); - hasher.update(value.as_ref()); - let hash = hasher.finalize(); - let bytes: [u8; 32] = hash - .as_slice() - .try_into() - .expect("Sha256 output conversion to fixed array shouldn't fail"); - bytes.into() - } -} - -impl fmt::Debug for Sha256Hasher { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Sha256Hasher") - } -} impl From for Error { fn from(error: StorageError) -> Self { diff --git a/shared/src/ledger/storage/mod.rs b/shared/src/ledger/storage/mod.rs index 8b19a8a16a..5827a7c1a4 100644 --- a/shared/src/ledger/storage/mod.rs +++ b/shared/src/ledger/storage/mod.rs @@ -5,6 +5,7 @@ mod merkle_tree; pub mod mockdb; pub mod types; pub mod write_log; +pub mod traits; use core::fmt::Debug; diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs new file mode 100644 index 0000000000..d5411cc966 --- /dev/null +++ b/shared/src/ledger/storage/traits.rs @@ -0,0 +1,214 @@ +//! Traits needed to provide a uniform interface over +//! all the different Merkle trees used for storage +use std::convert::{TryFrom, TryInto}; +use std::fmt; + +use arse_merkle_tree::{H256, Hash as SmtHash, Key as TreeKey}; +use arse_merkle_tree::traits::{Value, Hasher}; +use ibc_proto::ics23::CommitmentProof; +use sha2::{Digest, Sha256}; + +use super::IBC_KEY_LIMIT; +use super::merkle_tree::{Smt, Amt, Error}; +use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; +use crate::types::eth_bridge_pool::PendingTransfer; +use crate::types::hash::Hash; +use crate::types::storage::{ + MerkleKey, StringKey, TreeBytes, MerkleValue, Key +}; + +pub trait MerkleTree { + type Error; + + fn has_key(&self, key: &Key) -> Result; + fn update>(&mut self, key: &Key, value: MerkleValue) -> Result; + fn delete(&mut self, key: &Key) -> Result<(), Self::Error>; + fn membership_proof(&self, keys: &[Key], proof: Option) -> Option; +} + +impl MerkleTree for Smt { + type Error = Error; + + fn has_key(&self, key: &Key) -> Result { + self.get(&H::hash(key.to_string()).into()) + .and(Ok(true)) + .map_error(|err| Error::MerkleTree(err.to_string())) + } + + fn update>(&mut self, key: &Key, value: MerkleValue) -> Result { + let value = match value { + MerkleValue::Bytes(bytes) => Hash::try_from(bytes.as_ref()) + .map_err(|| Error::InvalidValue)?, + _ => return Err(Error::InvalidValue) + }; + self.update( + H::hash(key.to_string()).into(), + value, + ) + .map(Hash::into) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { + let value = Hash::zero(); + self.update( + H::hash(key.to_string()).into(), + value + ) + .and(Ok(())) + .map_err(|err|Error::MerkleTree(err.to_string())) + } +} + +impl MerkleTree for Amt { + type Error = Error; + + fn has_key(&self, key: &Key) -> Result { + let key = + StringKey::try_from_bytes(key.to_string().as_bytes())?; + self.get(&key) + .and(Ok(bool)) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn update>(&mut self, key: MerkleKey, value: MerkleValue) -> Result { + let key = + StringKey::try_from_bytes(key.to_string().as_bytes())?; + let value = match value { + MerkleValue::Bytes(bytes) => TreeBytes::from(bytes.as_ref().to_vec()), + _ => return Err(Error::InvalidValue) + }; + self.update( + key, + value, + ) + .map(Into::into) + .map_err(|err|Error::MerkleTree(err.to_string())) + } + + fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { + let key = + StringKey::try_from_bytes(key.to_string().as_bytes())?; + let value = TreeBytes::zero(); + self.update( + key, + value + ) + .and(Ok(())) + .map_err(|err| Error::MerkleTree(format!("{:?}", err))) + } +} + +impl MerkleTree for BridgePoolTree { + type Error = Error; + + fn has_key(&self, key: &Key) -> Result { + self.has_key(key) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn update>(&mut self, key: &Key, value: MerkleValue) -> Result { + if let MerkleValue::Transfer(transfer) = value { + self.update(key, transfer) + .map_err( | err| Error::MerkleTree(err.to_string())) + } else { + Err(Error::InvalidValue) + } + } + + fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { + self.delete(key) + .map_err(|err| Error::MerkleTree(err.to_string())) + } +} + +impl TreeKey for StringKey { + type Error = Error; + + fn as_slice(&self) -> &[u8] { + &self.original.as_slice()[..self.length] + } + + fn try_from_bytes(bytes: &[u8]) -> Result { + let mut tree_key = [0u8; IBC_KEY_LIMIT]; + let mut original = [0u8; IBC_KEY_LIMIT]; + let mut length = 0; + for (i, byte) in bytes.iter().enumerate() { + if i >= IBC_KEY_LIMIT { + return Err(Error::InvalidMerkleKey( + "Input IBC key is too large".into(), + )); + } + original[i] = *byte; + tree_key[i] = byte.wrapping_add(1); + length += 1; + } + Ok(Self { + original, + tree_key: tree_key.into(), + length, + }) + } +} + +impl Value for TreeBytes { + fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } + + fn zero() -> Self { + TreeBytes::zero() + } +} + +pub trait MembershipProof { }; + +impl MembershipProof for CommitmentProof; + +/// The storage hasher used for the merkle tree. +pub trait StorageHasher: Hasher + Default { + /// Hash the value to store + fn hash(value: impl AsRef<[u8]>) -> H256; +} + +/// The storage hasher used for the merkle tree. +#[derive(Default)] +pub struct Sha256Hasher(Sha256); + +impl Hasher for Sha256Hasher { + fn write_bytes(&mut self, h: &[u8]) { + self.0.update(h) + } + + fn finish(self) -> arse_merkle_tree::H256 { + let hash = self.0.finalize(); + let bytes: [u8; 32] = hash + .as_slice() + .try_into() + .expect("Sha256 output conversion to fixed array shouldn't fail"); + bytes.into() + } + + fn hash_op() -> ics23::HashOp { + ics23::HashOp::Sha256 + } +} + +impl StorageHasher for Sha256Hasher { + fn hash(value: impl AsRef<[u8]>) -> H256 { + let mut hasher = Sha256::new(); + hasher.update(value.as_ref()); + let hash = hasher.finalize(); + let bytes: [u8; 32] = hash + .as_slice() + .try_into() + .expect("Sha256 output conversion to fixed array shouldn't fail"); + bytes.into() + } +} + +impl fmt::Debug for Sha256Hasher { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Sha256Hasher") + } +} \ No newline at end of file diff --git a/shared/src/types/eth_bridge_pool.rs b/shared/src/types/eth_bridge_pool.rs index 18c6e7f1a9..17ba1f57e7 100644 --- a/shared/src/types/eth_bridge_pool.rs +++ b/shared/src/types/eth_bridge_pool.rs @@ -1,9 +1,11 @@ //! The necessary type definitions for the contents of the //! Ethereum bridge pool -use borsh::{BorshDeserialize, BorshSerialize}; +use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use ethabi::token::Token; use crate::types::address::Address; -use crate::types::ethereum_events::{EthAddress, Uint}; +use crate::types::ethereum_events::{EthAddress, Uint, KeccakHash}; +use crate::types::keccak; use crate::types::token::Amount; /// A transfer message to be submitted to Ethereum @@ -17,6 +19,7 @@ use crate::types::token::Amount; Eq, BorshSerialize, BorshDeserialize, + BorshSchema, )] pub struct TransferToEthereum { /// The type of token @@ -40,6 +43,7 @@ pub struct TransferToEthereum { Eq, BorshSerialize, BorshDeserialize, + BorshSchema, )] pub struct PendingTransfer { /// The message to send to Ethereum to @@ -49,6 +53,25 @@ pub struct PendingTransfer { pub gas_fee: GasFee, } +impl keccak::encode::Encode for PendingTransfer { + + fn tokenize(&self) -> Vec { + let from = Token::String(self.gas_fee.payer.to_string()); + let fee = Token::Uint(u64::from(self.gas_fee.amount).into()); + let to = Token::Address(self.transfer.recipient.0.into()); + let amount = Token::Uint(u64::from(self.transfer.amount).into()); + let nonce = Token::Uint(self.transfer.nonce.into()); + vec![ + from, + fee, + to, + amount, + nonce, + ] + } +} + + /// The amount of NAM to be payed to the relayer of /// a transfer across the Ethereum Bridge to compensate /// for Ethereum gas fees. @@ -61,6 +84,7 @@ pub struct PendingTransfer { Eq, BorshSerialize, BorshDeserialize, + BorshSchema, )] pub struct GasFee { /// The amount of fees (in NAM) diff --git a/shared/src/types/ethereum_events.rs b/shared/src/types/ethereum_events.rs index 869b4a4f14..f5870b057b 100644 --- a/shared/src/types/ethereum_events.rs +++ b/shared/src/types/ethereum_events.rs @@ -8,6 +8,7 @@ use eyre::{eyre, Context}; use crate::types::address::Address; use crate::types::hash::Hash; +use crate::types::keccak::KeccakHash; use crate::types::token::Amount; /// Anoma native type to replace the ethabi::Uint type @@ -80,20 +81,6 @@ impl FromStr for EthAddress { } } -/// A Keccak hash -#[derive( - Clone, - Debug, - PartialEq, - Eq, - PartialOrd, - Ord, - BorshSerialize, - BorshDeserialize, - BorshSchema, -)] -pub struct KeccakHash(pub [u8; 32]); - /// An Ethereum event to be processed by the Anoma ledger #[derive( PartialEq, diff --git a/shared/src/types/hash.rs b/shared/src/types/hash.rs index 0e960ec01f..3ea2c559cc 100644 --- a/shared/src/types/hash.rs +++ b/shared/src/types/hash.rs @@ -6,6 +6,7 @@ use std::ops::Deref; use arse_merkle_tree::traits::Value; use arse_merkle_tree::{Hash as TreeHash, H256}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use hex::FromHex; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use tendermint::abci::transaction; @@ -22,6 +23,8 @@ pub enum Error { Temporary { error: String }, #[error("Failed trying to convert slice to a hash: {0}")] ConversionFailed(std::array::TryFromSliceError), + #[error("Failed to convert string into a hash: {0}")] + FromStringError(hex::FromHexError) } /// Result for functions that may fail @@ -85,6 +88,24 @@ impl TryFrom<&[u8]> for Hash { } } +impl TryFrom for Hash { + type Error = self::Error; + + fn try_from(string: String) -> HashResult { + let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + Self::try_from(&bytes) + } +} + +impl TryFrom<&str> for Hash { + type Error = self::Error; + + fn try_from(string: &str) -> HashResult { + let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + Self::try_from(&bytes) + } +} + impl From for transaction::Hash { fn from(hash: Hash) -> Self { Self::new(hash.0) @@ -143,4 +164,4 @@ impl Value for Hash { fn zero() -> Self { Hash([0u8; 32]) } -} +} \ No newline at end of file diff --git a/shared/src/types/keccak.rs b/shared/src/types/keccak.rs new file mode 100644 index 0000000000..a489cd23ba --- /dev/null +++ b/shared/src/types/keccak.rs @@ -0,0 +1,194 @@ +//! This module is for hashing Anoma types using the keccak +//! hash function in a way that is compatible with smart contracts +//! on Ethereum +use std::convert::TryFrom; + +use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use hex::FromHex; +use tiny_keccak::{Hasher, Keccak}; + +use crate::types::hash::{HASH_LENGTH, Hash, HashResult}; + +#[allow(missing_docs)] +#[derive(Error, Debug)] +pub enum Error { + #[error("TEMPORARY error: {error}")] + Temporary { error: String }, + #[error("Failed trying to convert slice to a hash: {0}")] + ConversionFailed(std::array::TryFromSliceError), + #[error("Failed to convert string into a hash: {0}")] + FromStringError(hex::FromHexError) +} + +/// A Keccak hash +#[derive( + Clone, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + BorshSerialize, + BorshDeserialize, + BorshSchema, +)] +pub struct KeccakHash(pub [u8; 32]); + +impl From for Hash { + fn from(hash: KeccakHash) -> Self { + Hash(hash.0) + } +} + +impl From for KeccakHash { + fn from(hash: Hash) -> Self { + KeccakHash(hash.0) + } +} + +impl TryFrom<&[u8]> for KeccakHash { + type Error = Error; + + fn try_from(value: &[u8]) -> Result { + if value.len() != HASH_LENGTH { + return Err(Error::Temporary { + error: format!( + "Unexpected tx hash length {}, expected {}", + value.len(), + HASH_LENGTH + ), + }); + } + let hash: [u8; 32] = + TryFrom::try_from(value).map_err(Error::ConversionFailed)?; + Ok(KeccakHash(hash)) + } +} + +impl TryFrom for KeccakHash { + type Error = self::Error; + + fn try_from(string: String) -> HashResult { + let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + Self::try_from(&bytes) + } +} + +impl TryFrom<&str> for KeccakHash { + type Error = self::Error; + + fn try_from(string: &str) -> HashResult { + let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + Self::try_from(&bytes).into() + } +} + + +/// This module defines encoding methods compatible with Ethereum +/// smart contracts. +pub mod encode { + #[doc(inline)] + pub use ethabi::token::Token; + use tiny_keccak::{Hasher, Keccak}; + + use crate::types::ethereum_events::KeccakHash; + + /// Contains a method to encode data to a format compatible with Ethereum. + pub trait Encode { + + /// Encodes a struct into a sequence of ABI + /// [`Token`] instances. + fn tokenize(&self) -> Vec; + + /// Returns the encoded [`Token`] instances. + fn encode(&self) -> Vec { + let tokens = self.tokenize(); + ethabi::encode(&tokens) + } + + + /// Encodes a slice of [`Token`] instances, and returns the + /// keccak hash of the encoded string. + fn keccak256(&self) -> KeccakHash { + let mut output = [0; 32]; + + let mut state = Keccak::v256(); + state.update(self.encode().as_slice()); + state.finalize(&mut output); + + KeccakHash(output) + } + + /// Encodes a slice of [`Token`] instances, and returns the + /// keccak hash of the encoded string appended to an Ethereum + /// signature header. + fn signed_keccak256(&self) -> KeccakHash { + let mut output = [0; 32]; + + let eth_message = { + let message = self.encode(); + + let mut eth_message = + format!("\x19Ethereum Signed Message:\n{}", message.len()) + .into_bytes(); + eth_message.extend_from_slice(&message); + eth_message + }; + + let mut state = Keccak::v256(); + state.update(ð_message); + state.finalize(&mut output); + + KeccakHash(output) + } + } + + /// Represents an Ethereum encoding method equivalent + /// to `abi.encode`. + pub type AbiEncode = [Token; N]; + + impl Encode for AbiEncode { + #[inline] + fn tokenize(&self) -> Vec { + return self.to_vec() + } + } + + // TODO: test signatures here once we merge secp keys + #[cfg(test)] + mod tests { + use ethabi::ethereum_types::U256; + + use super::*; + + /// Checks if we get the same result as `abi.encode`, for some given + /// input data. + #[test] + fn test_abi_encode() { + let expected = "0x000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000"; + let expected = hex::decode(&expected[2..]).expect("Test failed"); + let got = AbiEncode::encode(&[ + Token::Uint(U256::from(42u64)), + Token::String("test".into()), + ]); + assert_eq!(expected, got); + } + + /// Sanity check our keccak hash implementation. + #[test] + fn test_keccak_hash_impl() { + let expected = + "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"; + assert_eq!( + expected, + &hex::encode({ + let mut st = Keccak::v256(); + let mut output = [0; 32]; + st.update(b"hello"); + st.finalize(&mut output); + output + }) + ); + } + } +} \ No newline at end of file diff --git a/shared/src/types/mod.rs b/shared/src/types/mod.rs index 4f491d0a99..72db38b769 100644 --- a/shared/src/types/mod.rs +++ b/shared/src/types/mod.rs @@ -10,6 +10,7 @@ pub mod hash; pub mod ibc; pub mod intent; pub mod internal; +pub mod keccak; pub mod key; pub mod matchmaker; pub mod nft; diff --git a/shared/src/types/storage.rs b/shared/src/types/storage.rs index b7e2005bb7..7b7ffad7a2 100644 --- a/shared/src/types/storage.rs +++ b/shared/src/types/storage.rs @@ -11,12 +11,15 @@ use arse_merkle_tree::InternalKey; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use serde::{Deserialize, Serialize}; use thiserror::Error; +use variant_access_derive::*; +use variant_access_traits::*; #[cfg(feature = "ferveo-tpke")] use super::transaction::WrapperTx; use crate::bytes::ByteBuf; use crate::ledger::storage::{StorageHasher, IBC_KEY_LIMIT}; use crate::types::address::{self, Address}; +use crate::types::eth_bridge_pool::{TransferToEthereum, PendingTransfer}; use crate::types::hash::Hash; use crate::types::time::DateTimeUtc; @@ -31,6 +34,8 @@ pub enum Error { ParseAddressFromKey, #[error("Reserved prefix or string is specified: {0}")] InvalidKeySeg(String), + #[error("Could not parse string: '{0}' into requested type: {1}")] + ParseError((String, String)) } /// Result for functions that may fail @@ -233,14 +238,35 @@ impl FromStr for Key { } } -/// A type for converting an Anoma storage key -/// to that of the right type for the different -/// merkle trees used. -pub enum MerkleKey { - /// A key that needs to be hashed - Sha256(Key, PhantomData), - /// A key that can be given as raw bytes - Raw(Key), +/// An enum representing the different types of values +/// that can be passed into Anoma's storage. +/// +/// This is a multi-store organized as +/// several Merkle trees, each of which is +/// responsible for understanding how to parse +/// this value. +pub enum MerkleValue> { + /// raw bytes + Bytes(T), + /// a transfer to be put in the Ethereum bridge pool + /// We actually only need the key (which is the hash + /// of the transfer). So this variant contains no data. + Transfer(PendingTransfer), +} + +impl From for MerkleValue +where + T: AsRef<[u8]> +{ + fn from(bytes: T) -> Self { + Self::Bytes(bytes) + } +} + +impl> From for MerkleValue { + fn from(transfer: PendingTransfer) -> Self { + Self::Transfer(transfer) + } } /// Storage keys that are utf8 encoded strings @@ -581,6 +607,20 @@ impl KeySeg for Address { } } +impl KeySeg for Hash { + fn parse(seg: String) -> Result { + seg.try_into().map_error(Error::ParseError((seg, "Hash".into()))) + } + + fn raw(&self) -> String { + self.to_string() + } + + fn to_db_key(&self) -> DbKeySeg { + DbKeySeg::StringSeg(self.raw()) + } +} + /// Epoch identifier. Epochs are identified by consecutive numbers. #[derive( Clone, @@ -630,6 +670,7 @@ impl Add for Epoch { } } + impl Sub for Epoch { type Output = Epoch; diff --git a/shared/src/types/vote_extensions/validator_set_update.rs b/shared/src/types/vote_extensions/validator_set_update.rs index b51fc83df1..4af065f990 100644 --- a/shared/src/types/vote_extensions/validator_set_update.rs +++ b/shared/src/types/vote_extensions/validator_set_update.rs @@ -1,8 +1,5 @@ //! Contains types necessary for processing validator set updates //! in vote extensions. - -pub mod encoding; - use std::collections::HashMap; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; @@ -224,12 +221,14 @@ fn compute_hash( // this is only here so we don't pollute the // outer namespace with serde traits mod tag { + use ethabi::Token; use serde::{Deserialize, Serialize}; use super::encoding::{AbiEncode, Encode, Token}; use super::{bheight_to_token, Vext, VotingPowersMapExt}; use crate::proto::SignedSerialize; - use crate::types::ethereum_events::KeccakHash; + use crate::types::keccak::KeccakHash; + use crate::types::keccak::encode::{Encode, AbiEncode}; /// Tag type that indicates we should use [`AbiEncode`] /// to sign data in a [`crate::proto::Signed`] wrapper. @@ -263,6 +262,7 @@ mod tag { #[doc(inline)] pub use tag::SerializeWithAbiEncode; +use crate::types::keccak::encode::{AbiEncode, Token}; #[cfg(test)] mod tests { diff --git a/shared/src/types/vote_extensions/validator_set_update/encoding.rs b/shared/src/types/vote_extensions/validator_set_update/encoding.rs deleted file mode 100644 index 0ba253ee23..0000000000 --- a/shared/src/types/vote_extensions/validator_set_update/encoding.rs +++ /dev/null @@ -1,99 +0,0 @@ -//! This module defines encoding methods compatible with Ethereum -//! smart contracts. -// TODO: probably move this module elsewhere - -#[doc(inline)] -pub use ethabi::token::Token; -use tiny_keccak::{Hasher, Keccak}; - -use crate::types::ethereum_events::KeccakHash; - -/// Contains a method to encode data to a format compatible with Ethereum. -pub trait Encode { - /// Returns the encoded [`Token`] instances. - fn encode(tokens: &[Token]) -> Vec; - - /// Encodes a slice of [`Token`] instances, and returns the - /// keccak hash of the encoded string. - fn keccak256(tokens: &[Token]) -> KeccakHash { - let mut output = [0; 32]; - - let mut state = Keccak::v256(); - state.update(&Self::encode(tokens)); - state.finalize(&mut output); - - KeccakHash(output) - } - - /// Encodes a slice of [`Token`] instances, and returns the - /// keccak hash of the encoded string appended to an Ethereum - /// signature header. - fn signed_keccak256(tokens: &[Token]) -> KeccakHash { - let mut output = [0; 32]; - - let eth_message = { - let message = Self::encode(tokens); - - let mut eth_message = - format!("\x19Ethereum Signed Message:\n{}", message.len()) - .into_bytes(); - eth_message.extend_from_slice(&message); - eth_message - }; - - let mut state = Keccak::v256(); - state.update(ð_message); - state.finalize(&mut output); - - KeccakHash(output) - } -} - -/// Represents an Ethereum encoding method equivalent -/// to `abi.encode`. -pub struct AbiEncode; - -impl Encode for AbiEncode { - #[inline] - fn encode(tokens: &[Token]) -> Vec { - ethabi::encode(tokens) - } -} - -// TODO: test signatures here once we merge secp keys -#[cfg(test)] -mod tests { - use ethabi::ethereum_types::U256; - - use super::*; - - /// Checks if we get the same result as `abi.encode`, for some given - /// input data. - #[test] - fn test_abi_encode() { - let expected = "0x000000000000000000000000000000000000000000000000000000000000002a000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000047465737400000000000000000000000000000000000000000000000000000000"; - let expected = hex::decode(&expected[2..]).expect("Test failed"); - let got = AbiEncode::encode(&[ - Token::Uint(U256::from(42u64)), - Token::String("test".into()), - ]); - assert_eq!(expected, got); - } - - /// Sanity check our keccak hash implementation. - #[test] - fn test_keccak_hash_impl() { - let expected = - "1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8"; - assert_eq!( - expected, - &hex::encode({ - let mut st = Keccak::v256(); - let mut output = [0; 32]; - st.update(b"hello"); - st.finalize(&mut output); - output - }) - ); - } -} From 3e01baf863389dca29a111a7279909c2d806f476 Mon Sep 17 00:00:00 2001 From: R2D2 Date: Mon, 26 Sep 2022 17:51:53 +0200 Subject: [PATCH 02/28] [feat]: Added membership proofs for eth bridge pool --- Cargo.lock | 701 ++++++------------ .../ledger/eth_bridge/storage/bridge_pool.rs | 37 +- shared/src/types/keccak.rs | 19 +- 3 files changed, 268 insertions(+), 489 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 69d5ab3f90..17d28aa12b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -656,12 +656,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base64" version = "0.9.3" @@ -1137,28 +1131,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "chrono-tz" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" -dependencies = [ - "parse-zoneinfo", - "phf", - "phf_codegen", -] - [[package]] name = "chunked_transfer" version = "1.4.0" @@ -1321,12 +1293,6 @@ dependencies = [ "windows", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1504,18 +1470,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array 0.14.5", - "rand_core 0.6.3", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.3" @@ -1546,16 +1500,6 @@ dependencies = [ "subtle 2.4.1", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array 0.14.5", - "subtle 2.4.1", -] - [[package]] name = "ct-codecs" version = "1.1.1" @@ -1607,36 +1551,6 @@ dependencies = [ "rand 0.7.3", ] -[[package]] -name = "curl" -version = "0.4.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d855aeef205b43f65a5001e0997d81f8efca7badad4fad7d897aa7f0d0651f" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2 0.4.4", - "winapi 0.3.9", -] - -[[package]] -name = "curl-sys" -version = "0.4.55+curl-7.83.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23734ec77368ec583c2e61dd3f0b0e5c98b93abe6d2a004ca06b91dd7e3e2762" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi 0.3.9", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -1738,15 +1652,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ee2393c4a91429dffb4bedf19f4d6abf27d8a732c8ce4980305d782e5426d57" -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", -] - [[package]] name = "derivative" version = "2.2.0" @@ -1802,12 +1707,6 @@ dependencies = [ "syn", ] -[[package]] -name = "deunicode" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" - [[package]] name = "diff" version = "0.1.12" @@ -1917,18 +1816,6 @@ dependencies = [ "memmap2", ] -[[package]] -name = "ecdsa" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - [[package]] name = "ed25519" version = "1.5.2" @@ -1976,24 +1863,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "elliptic-curve" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "ff", - "generic-array 0.14.5", - "group", - "rand_core 0.6.3", - "sec1", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "embed-resource" version = "1.7.2" @@ -2243,16 +2112,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core 0.6.3", - "subtle 2.4.1", -] - [[package]] name = "file-lock" version = "2.1.4" @@ -2647,17 +2506,6 @@ dependencies = [ "regex", ] -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags", - "ignore", - "walkdir", -] - [[package]] name = "gloo-timers" version = "0.2.4" @@ -2670,17 +2518,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "ff", - "rand_core 0.6.3", - "subtle 2.4.1", -] - [[package]] name = "group-threshold-cryptography" version = "0.1.0" @@ -2857,16 +2694,6 @@ dependencies = [ "digest 0.9.0", ] -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac 0.11.1", - "digest 0.9.0", -] - [[package]] name = "hmac-drbg" version = "0.2.0" @@ -2934,12 +2761,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humansize" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" - [[package]] name = "hyper" version = "0.10.16" @@ -3047,14 +2868,41 @@ dependencies = [ [[package]] name = "ibc" -version = "0.14.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +version = "0.12.0" +source = "git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus#99a761657a51f6e5f074f3217426903e53632934" +dependencies = [ + "bytes 1.1.0", + "derive_more", + "flex-error", + "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", + "ics23 0.6.7", + "num-traits 0.2.15", + "prost 0.9.0", + "prost-types 0.9.0", + "safe-regex", + "serde 1.0.137", + "serde_derive", + "serde_json", + "sha2 0.10.2", + "subtle-encoding", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-light-client-verifier 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-testgen 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "time 0.3.9", + "tracing 0.1.35", +] + +[[package]] +name = "ibc" +version = "0.12.0" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc#30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc" dependencies = [ "bytes 1.1.0", "derive_more", "flex-error", - "ibc-proto", - "ics23", + "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", + "ics23 0.6.7", "num-traits 0.2.15", "prost 0.9.0", "prost-types 0.9.0", @@ -3064,25 +2912,54 @@ dependencies = [ "serde_json", "sha2 0.10.2", "subtle-encoding", - "tendermint", - "tendermint-light-client-verifier", - "tendermint-proto", - "tendermint-testgen", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-light-client-verifier 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-testgen 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", "time 0.3.9", "tracing 0.1.35", ] [[package]] name = "ibc-proto" -version = "0.17.1" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +version = "0.16.0" +source = "git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus#99a761657a51f6e5f074f3217426903e53632934" dependencies = [ - "base64 0.13.0", "bytes 1.1.0", "prost 0.9.0", "prost-types 0.9.0", "serde 1.0.137", - "tendermint-proto", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tonic", +] + +[[package]] +name = "ibc-proto" +version = "0.16.0" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc#30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc" +dependencies = [ + "bytes 1.1.0", + "prost 0.9.0", + "prost-types 0.9.0", + "serde 1.0.137", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tonic", +] + +[[package]] +name = "ics23" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce15e4758c46a0453bdf4b3b1dfcce70c43f79d1943c2ee0635b77eb2e7aa233" +dependencies = [ + "anyhow", + "bytes 1.1.0", + "hex", + "prost 0.9.0", + "ripemd160", + "sha2 0.9.9", + "sha3 0.9.1", + "sp-std", ] [[package]] @@ -3166,24 +3043,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "ignore" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" -dependencies = [ - "crossbeam-utils 0.8.8", - "globset", - "lazy_static 1.4.0", - "log 0.4.17", - "memchr", - "regex", - "same-file", - "thread_local 1.1.4", - "walkdir", - "winapi-util", -] - [[package]] name = "impl-codec" version = "0.6.0" @@ -3366,19 +3225,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "k256" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", - "sec1", - "sha2 0.9.9", -] - [[package]] name = "keccak" version = "0.1.2" @@ -4123,12 +3969,6 @@ dependencies = [ "serde_yaml", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "match_cfg" version = "0.1.0" @@ -4463,9 +4303,11 @@ dependencies = [ "ferveo-common", "group-threshold-cryptography", "hex", - "ibc", - "ibc-proto", - "ics23", + "ibc 0.12.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", + "ibc 0.12.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", + "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", + "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", + "ics23 0.6.7", "itertools 0.10.3", "libsecp256k1 0.7.0", "loupe", @@ -4485,16 +4327,16 @@ dependencies = [ "sha2 0.9.9", "sparse-merkle-tree", "tempfile", - "tendermint", - "tendermint-proto", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", "test-log", "thiserror", "tiny-keccak", "tonic-build", "tracing 0.1.35", "tracing-subscriber 0.3.11", - "variant_access_derive", - "variant_access_traits", "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", @@ -4527,7 +4369,6 @@ dependencies = [ "clarity", "color-eyre", "config", - "curl", "derivative", "directories", "ed25519-consensus", @@ -4575,10 +4416,14 @@ dependencies = [ "sysinfo", "tar", "tempfile", - "tendermint", - "tendermint-config", - "tendermint-proto", - "tendermint-rpc", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-config 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-config 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-rpc 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-rpc 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", "test-log", "thiserror", "tokio", @@ -4587,7 +4432,8 @@ dependencies = [ "tonic", "tonic-build", "tower", - "tower-abci", + "tower-abci 0.1.0 (git+https://github.com/heliaxdev/tower-abci?branch=bat/abciplus)", + "tower-abci 0.1.0 (git+https://github.com/heliaxdev/tower-abci?rev=f6463388fc319b6e210503b43b3aecf6faf6b200)", "tracing 0.1.35", "tracing-log", "tracing-subscriber 0.3.11", @@ -5244,15 +5090,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "parse-zoneinfo" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" -dependencies = [ - "regex", -] - [[package]] name = "paste" version = "1.0.7" @@ -5319,40 +5156,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "pest_derive" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" -dependencies = [ - "maplit", - "pest", - "sha-1 0.8.2", -] - [[package]] name = "petgraph" version = "0.5.1" @@ -5373,45 +5176,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" -dependencies = [ - "phf_shared", - "rand 0.8.5", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", - "uncased", -] - [[package]] name = "pin-project" version = "0.4.29" @@ -6190,17 +5954,6 @@ dependencies = [ "quick-error 1.2.3", ] -[[package]] -name = "rfc6979" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" -dependencies = [ - "crypto-bigint", - "hmac 0.11.0", - "zeroize", -] - [[package]] name = "ring" version = "0.16.20" @@ -6522,18 +6275,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" -dependencies = [ - "der", - "generic-array 0.14.5", - "subtle 2.4.1", - "zeroize", -] - [[package]] name = "secp256k1" version = "0.21.3" @@ -6878,10 +6619,6 @@ name = "signature" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.3", -] [[package]] name = "simple-error" @@ -6889,27 +6626,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - [[package]] name = "slab" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" -[[package]] -name = "slug" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" -dependencies = [ - "deunicode", -] - [[package]] name = "smallvec" version = "0.6.14" @@ -6994,7 +6716,7 @@ dependencies = [ "blake2b-rs", "borsh", "cfg-if 1.0.0", - "ics23", + "ics23 0.7.0", "sha2 0.9.9", ] @@ -7177,6 +6899,34 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "tendermint" +version = "0.23.5" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" +dependencies = [ + "async-trait", + "bytes 1.1.0", + "ed25519", + "ed25519-dalek", + "flex-error", + "futures 0.3.21", + "num-traits 0.2.15", + "once_cell", + "prost 0.9.0", + "prost-types 0.9.0", + "serde 1.0.137", + "serde_bytes", + "serde_json", + "serde_repr", + "sha2 0.9.9", + "signature", + "subtle 2.4.1", + "subtle-encoding", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "time 0.3.9", + "zeroize", +] + [[package]] name = "tendermint" version = "0.23.5" @@ -7188,12 +6938,10 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures 0.3.21", - "k256", "num-traits 0.2.15", "once_cell", "prost 0.9.0", "prost-types 0.9.0", - "ripemd160", "serde 1.0.137", "serde_bytes", "serde_json", @@ -7202,11 +6950,24 @@ dependencies = [ "signature", "subtle 2.4.1", "subtle-encoding", - "tendermint-proto", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", "time 0.3.9", "zeroize", ] +[[package]] +name = "tendermint-config" +version = "0.23.5" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" +dependencies = [ + "flex-error", + "serde 1.0.137", + "serde_json", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "toml", + "url 2.2.2", +] + [[package]] name = "tendermint-config" version = "0.23.5" @@ -7215,11 +6976,24 @@ dependencies = [ "flex-error", "serde 1.0.137", "serde_json", - "tendermint", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", "toml", "url 2.2.2", ] +[[package]] +name = "tendermint-light-client-verifier" +version = "0.23.5" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" +dependencies = [ + "derive_more", + "flex-error", + "serde 1.0.137", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-rpc 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "time 0.3.9", +] + [[package]] name = "tendermint-light-client-verifier" version = "0.23.5" @@ -7228,8 +7002,25 @@ dependencies = [ "derive_more", "flex-error", "serde 1.0.137", - "tendermint", - "tendermint-rpc", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-rpc 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "time 0.3.9", +] + +[[package]] +name = "tendermint-proto" +version = "0.23.5" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" +dependencies = [ + "bytes 1.1.0", + "flex-error", + "num-derive", + "num-traits 0.2.15", + "prost 0.9.0", + "prost-types 0.9.0", + "serde 1.0.137", + "serde_bytes", + "subtle-encoding", "time 0.3.9", ] @@ -7250,6 +7041,39 @@ dependencies = [ "time 0.3.9", ] +[[package]] +name = "tendermint-rpc" +version = "0.23.5" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" +dependencies = [ + "async-trait", + "async-tungstenite", + "bytes 1.1.0", + "flex-error", + "futures 0.3.21", + "getrandom 0.2.6", + "http", + "hyper 0.14.19", + "hyper-proxy", + "hyper-rustls", + "peg", + "pin-project 1.0.10", + "serde 1.0.137", + "serde_bytes", + "serde_json", + "subtle-encoding", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-config 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "thiserror", + "time 0.3.9", + "tokio", + "tracing 0.1.35", + "url 2.2.2", + "uuid", + "walkdir", +] + [[package]] name = "tendermint-rpc" version = "0.23.5" @@ -7271,9 +7095,9 @@ dependencies = [ "serde_bytes", "serde_json", "subtle-encoding", - "tendermint", - "tendermint-config", - "tendermint-proto", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-config 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", "thiserror", "time 0.3.9", "tokio", @@ -7286,7 +7110,7 @@ dependencies = [ [[package]] name = "tendermint-testgen" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "ed25519-dalek", "gumdrop", @@ -7294,30 +7118,23 @@ dependencies = [ "serde_json", "simple-error", "tempfile", - "tendermint", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", "time 0.3.9", ] [[package]] -name = "tera" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d" +name = "tendermint-testgen" +version = "0.23.5" +source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" dependencies = [ - "chrono", - "chrono-tz", - "globwalk", - "humansize", - "lazy_static 1.4.0", - "percent-encoding 2.1.0", - "pest", - "pest_derive", - "rand 0.8.5", - "regex", + "ed25519-dalek", + "gumdrop", "serde 1.0.137", "serde_json", - "slug", - "unic-segment", + "simple-error", + "tempfile", + "tendermint 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "time 0.3.9", ] [[package]] @@ -7790,6 +7607,24 @@ dependencies = [ "tracing 0.1.35", ] +[[package]] +name = "tower-abci" +version = "0.1.0" +source = "git+https://github.com/heliaxdev/tower-abci?branch=bat/abciplus#21623a99bdca5b006d53752a1967849bef3b89ea" +dependencies = [ + "bytes 1.1.0", + "futures 0.3.21", + "pin-project 1.0.10", + "prost 0.9.0", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tokio", + "tokio-stream", + "tokio-util 0.6.10", + "tower", + "tracing 0.1.30", + "tracing-tower", +] + [[package]] name = "tower-abci" version = "0.1.0" @@ -7799,7 +7634,7 @@ dependencies = [ "futures 0.3.21", "pin-project 1.0.10", "prost 0.9.0", - "tendermint-proto", + "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", "tokio", "tokio-stream", "tokio-util 0.6.10", @@ -8126,65 +7961,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "uncased" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" -dependencies = [ - "version_check 0.9.4", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - [[package]] name = "unicase" version = "1.4.2" @@ -8345,25 +8121,6 @@ dependencies = [ "version_check 0.9.4", ] -[[package]] -name = "variant_access_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd235ffafb854ed81b49217ce411e850a39628a5d26740ecfb60421c873d834" -dependencies = [ - "lazy_static 1.4.0", - "quote", - "syn", - "tera", - "variant_access_traits", -] - -[[package]] -name = "variant_access_traits" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d75c5a83bb8912dd9c628adf954c9f9bff74a4e170d2c90242f4e56a0d643e" - [[package]] name = "vcpkg" version = "0.2.15" diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index 8588ae0550..e15de60cb2 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -9,7 +9,8 @@ use eyre::eyre; use crate::types::address::{Address, InternalAddress}; use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; -use crate::types::ethereum_events::KeccakHash; +use crate::types::keccak::{keccak_hash, KeccakHash}; +use crate::types::keccak::encode::Encode; use crate::types::hash::{Hash, keccak_hash}; use crate::types::storage::{DbKeySeg, Key}; use crate::ledger::storage::{Sha256Hasher, StorageHasher}; @@ -66,10 +67,9 @@ pub struct BridgePoolTree { /// Root of the tree root: KeccakHash, /// The underlying storage - store: BTreeMap + store: BTreeMap, } -/// TODO: Hash ABI instead of Borsh impl BridgePoolTree { /// Create a new merkle tree for the Ethereum bridge pool pub fn new(root: KeccakHash, store: BTreeMap) -> Self { @@ -90,7 +90,7 @@ impl BridgePoolTree { /// return an error if the key is malformed. pub fn update(&mut self, key: &Key, value: PendingTransfer) -> Result { let hash = Self::parse_key(key)?; - if hash != keccak_hash(&value.try_to_vec().unwrap()) { + if hash != value.keccak256() { return eyre!("Key does not match hash of the value")?; } _ = self.store.insert(hash, value); @@ -131,9 +131,28 @@ impl BridgePoolTree { &self.store } + /// Create a batched membership proof for the provided keys pub fn membership_proof(&self, keys: &[Key]) -> BridgePoolProof { - for (key, value) in self.store { - + let mut leaves : std::collections::BTreeSet = Default::default(); + for key in keys { + leaves.insert(Self::parse_key(key)?); + } + let mut proof_leaves = vec![]; + let mut proof_hashes = vec![]; + let mut flags = vec![]; + for (hash, value) in self.store { + if leaves.contains(&hash) { + flags.push(true); + proof_leaves.push(value); + } else { + flags.push(false); + proof_hashes.push(hash); + } + } + BridgePoolProof { + proof: proof_hashes, + leaves: proof_leaves, + flags } } @@ -180,8 +199,7 @@ impl BridgePoolProof { let mut proof_pos = 0usize; let mut computed; if self.flags[0] { - leaf = self.leaves[leaf_pos].clone(); - computed = keccak_hash(leaf.try_to_vec().unwrap()); + computed = self.leaves[leaf_pos].keccak256(); leaf_pos += 1; } else { computed = self.proof[proof_pos].clone(); @@ -190,8 +208,7 @@ impl BridgePoolProof { for flag in 1..self.flages.len() { let mut next_hash; if self.flags[flag] { - leaf = self.leaves[leaf_pos].clone(); - next_hash = keccak_hash(leaf.try_to_vec().unwrap()); + next_hash = self.leaves[leaf_pos].keccak256(); leaf_pos += 1; } else { next_hash = self.proof[proof_pos].clone(); diff --git a/shared/src/types/keccak.rs b/shared/src/types/keccak.rs index 185b89956e..70c3fcea3d 100644 --- a/shared/src/types/keccak.rs +++ b/shared/src/types/keccak.rs @@ -96,6 +96,17 @@ impl TryFrom<&str> for KeccakHash { } } +/// Hash bytes using Keccak +pub fn keccak_hash(bytes: &[u8]) -> KeccakHash { + let mut output = [0; 32]; + + let mut hasher = Keccak::v256(); + hasher.update(bytes); + hasher.finalize(&mut output); + + KeccakHash(output) +} + /// This module defines encoding methods compatible with Ethereum /// smart contracts. pub mod encode { @@ -120,13 +131,7 @@ pub mod encode { /// Encodes a slice of [`Token`] instances, and returns the /// keccak hash of the encoded string. fn keccak256(&self) -> KeccakHash { - let mut output = [0; 32]; - - let mut state = Keccak::v256(); - state.update(self.encode().as_slice()); - state.finalize(&mut output); - - KeccakHash(output) + keccak_hash(self.encode().as_slice()) } /// Encodes a slice of [`Token`] instances, and returns the From 2c63406386f27d8e093e6064cb7d7d533e6a6b2c Mon Sep 17 00:00:00 2001 From: R2D2 Date: Thu, 29 Sep 2022 10:20:30 +0200 Subject: [PATCH 03/28] feat: finished base implementation, need to debug --- .../src/ledger/eth_bridge/bridge_pool_vp.rs | 3 +- .../ledger/eth_bridge/storage/bridge_pool.rs | 78 +++--- shared/src/ledger/eth_bridge/vp/mod.rs | 2 +- shared/src/ledger/storage/merkle_tree.rs | 226 ++++++------------ shared/src/ledger/storage/mod.rs | 3 +- shared/src/ledger/storage/traits.rs | 180 ++++++++++---- shared/src/types/eth_bridge_pool.rs | 14 +- shared/src/types/hash.rs | 10 +- shared/src/types/storage.rs | 38 ++- 9 files changed, 289 insertions(+), 265 deletions(-) diff --git a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs index b05b4db7be..12fa7982eb 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs @@ -18,7 +18,8 @@ use crate::ledger::eth_bridge::storage::bridge_pool::{ get_pending_key, is_protected_storage, BRIDGE_POOL_ADDRESS, }; use crate::ledger::native_vp::{Ctx, NativeVp, StorageReader}; -use crate::ledger::storage::{DBIter, StorageHasher, DB}; +use crate::ledger::storage::{DBIter, DB}; +use crate::ledger::storage::traits::StorageHasher; use crate::proto::SignedTxData; use crate::types::address::{xan, Address, InternalAddress}; use crate::types::eth_bridge_pool::PendingTransfer; diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index e15de60cb2..48266bde17 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -1,19 +1,19 @@ //! Tools for accessing the storage subspaces of the Ethereum //! bridge pool -use std::collections::BTreeMap; +use std::collections::BTreeSet; use std::convert::TryInto; use std::ops::Deref; -use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use eyre::eyre; +use crate::ledger::storage::traits::{Sha256Hasher, StorageHasher}; use crate::types::address::{Address, InternalAddress}; use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; -use crate::types::keccak::{keccak_hash, KeccakHash}; +use crate::types::hash::Hash; use crate::types::keccak::encode::Encode; -use crate::types::hash::{Hash, keccak_hash}; +use crate::types::keccak::{keccak_hash, KeccakHash}; use crate::types::storage::{DbKeySeg, Key}; -use crate::ledger::storage::{Sha256Hasher, StorageHasher}; /// The main address of the Ethereum bridge pool pub const BRIDGE_POOL_ADDRESS: Address = @@ -67,13 +67,13 @@ pub struct BridgePoolTree { /// Root of the tree root: KeccakHash, /// The underlying storage - store: BTreeMap, + store: BTreeSet, } impl BridgePoolTree { /// Create a new merkle tree for the Ethereum bridge pool - pub fn new(root: KeccakHash, store: BTreeMap) -> Self { - Self{ root, store } + pub fn new(root: KeccakHash, store: BTreeSet) -> Self { + Self { root, store } } /// Parse the key to ensure it is of the correct type. @@ -81,25 +81,22 @@ impl BridgePoolTree { /// If it is, it can be converted to a hash. /// Checks if the hash is in the tree. pub fn has_key(&self, key: &Key) -> Result { - Ok(self.store.contains_key(&Self::parse_key(key)?)) + Ok(self.store.contains(&Self::parse_key(key)?)) } /// Update the tree with a new value. /// /// Returns the new root if successful. Will /// return an error if the key is malformed. - pub fn update(&mut self, key: &Key, value: PendingTransfer) -> Result { + pub fn update(&mut self, key: &Key) -> Result { let hash = Self::parse_key(key)?; - if hash != value.keccak256() { - return eyre!("Key does not match hash of the value")?; - } - _ = self.store.insert(hash, value); + _ = self.store.insert(hash); self.root = self.compute_root(); Ok(self.root()) } /// Delete a key from storage and update the root - pub fn delete(&mut self, key: &Key) -> Result<(), Error>{ + pub fn delete(&mut self, key: &Key) -> Result<(), Error> { let hash = Self::parse_key(key)?; _ = self.store.remove(&hash); self.root = self.compute_root(); @@ -109,13 +106,12 @@ impl BridgePoolTree { /// Compute the root of the merkle tree pub fn compute_root(&self) -> KeccakHash { let mut leaves = self.store.iter(); - let mut root = if let Some((hash, _)) = leaves.next() { + let mut root = if let Some(hash) = leaves.next() { hash.clone() } else { return Default::default(); }; - - for (leaf, _) in leaves { + for leaf in leaves { root = keccak_hash([root.0, leaf.0].concat()); } root @@ -127,33 +123,43 @@ impl BridgePoolTree { } /// Get a reference to the backing store - pub fn store(&self) -> &BTreeMap { + pub fn store(&self) -> &BTreeSet { &self.store } /// Create a batched membership proof for the provided keys - pub fn membership_proof(&self, keys: &[Key]) -> BridgePoolProof { - let mut leaves : std::collections::BTreeSet = Default::default(); + pub fn membership_proof( + &self, + keys: &[Key], + mut values: Vec, + ) -> Result { + if values.len() != keys.len() { + return eyre!( + "The number of leaves and leaf hashes must be equal." + )?; + } + values.sort(); + let mut leaves: std::collections::BTreeSet = + Default::default(); for key in keys { leaves.insert(Self::parse_key(key)?); } - let mut proof_leaves = vec![]; + let mut proof_hashes = vec![]; let mut flags = vec![]; - for (hash, value) in self.store { + for hash in self.store { if leaves.contains(&hash) { flags.push(true); - proof_leaves.push(value); } else { flags.push(false); proof_hashes.push(hash); } } - BridgePoolProof { + Ok(BridgePoolProof { proof: proof_hashes, - leaves: proof_leaves, - flags - } + leaves: values, + flags, + }) } /// Parse a db key to see if it is valid for the @@ -164,13 +170,18 @@ impl BridgePoolTree { fn parse_key(key: &Key) -> Result { if key.segments.len() == 1 { match &key.segments[0] { - DbKeySeg::StringSeg(str) => str.as_str().try_into().ok_or( - eyre!("Could not parse key segment as a hash")? - ), - _ => eyre!("Bridge pool keys should be strings, not addresses")? + DbKeySeg::StringSeg(str) => str + .as_str() + .try_into() + .ok_or(eyre!("Could not parse key segment as a hash")?), + _ => { + eyre!("Bridge pool keys should be strings, not addresses")? + } } } else { - eyre!("Key for the bridge pool should not have more than one segment")? + eyre!( + "Key for the bridge pool should not have more than one segment" + )? } } } @@ -186,7 +197,6 @@ pub struct BridgePoolProof { } impl BridgePoolProof { - /// Verify a membership proof matches the provided root pub fn verify(&self, root: KeccakHash) -> bool { if self.proof.len() + self.leaves.len() != self.flags.len() { diff --git a/shared/src/ledger/eth_bridge/vp/mod.rs b/shared/src/ledger/eth_bridge/vp/mod.rs index cdcd1815ea..0e62f7270f 100644 --- a/shared/src/ledger/eth_bridge/vp/mod.rs +++ b/shared/src/ledger/eth_bridge/vp/mod.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use crate::ledger::eth_bridge::storage::{self, wrapped_erc20s}; use crate::ledger::native_vp::{Ctx, NativeVp, StorageReader}; use crate::ledger::storage as ledger_storage; -use crate::ledger::storage::StorageHasher; +use crate::ledger::storage::traits::StorageHasher; use crate::types::address::{Address, InternalAddress}; use crate::types::storage::Key; use crate::types::token::Amount; diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index cc26b95b5d..58b05faa2f 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -2,6 +2,7 @@ use std::convert::{TryFrom, TryInto}; use std::fmt; use std::marker::PhantomData; +use std::slice::from_ref; use std::str::FromStr; use arse_merkle_tree::default_store::DefaultStore; @@ -22,16 +23,19 @@ use sha2::{Digest, Sha256}; use tendermint::merkle::proof::{Proof, ProofOp}; use thiserror::Error; +use super::traits::{self, Sha256Hasher, StorageHasher}; use super::IBC_KEY_LIMIT; -use super::traits::{self, StorageHasher, Sha256Hasher}; use crate::bytes::ByteBuf; use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; -use crate::ledger::storage::types; +use crate::ledger::storage::{ics23_specs, types}; use crate::types::address::{Address, InternalAddress}; use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; use crate::types::ethereum_events::KeccakHash; use crate::types::hash::Hash; -use crate::types::storage::{DbKeySeg, Error as StorageError, Key, StringKey, TreeBytes, MerkleValue}; +use crate::types::storage::{ + DbKeySeg, Error as StorageError, Key, MembershipProof, MerkleValue, + StringKey, TreeBytes, +}; #[allow(missing_docs)] #[derive(Error, Debug)] @@ -50,6 +54,10 @@ pub enum Error { NonExistenceProof(String), #[error("Invalid value given to sub-tree storage")] InvalidValue, + #[error("ICS23 commitment proofs do not support multiple leaves")] + Ics23MultiLeaf, + #[error("A Tendermint proof can only be constructed from an ICS23 proof.")] + TendermintProof, } /// Result for functions that may fail @@ -58,7 +66,7 @@ type Result = std::result::Result; /// Type aliases for the different merkle trees and backing stores pub type SmtStore = DefaultStore; pub type AmtStore = DefaultStore; -pub type BridgePoolStore = std::collections::BTreeMap; +pub type BridgePoolStore = std::collections::BTreeSet; pub type Smt = ArseMerkleTree; pub type Amt = ArseMerkleTree; @@ -99,7 +107,7 @@ pub enum Store { /// For PoS-related data PoS(SmtStore), /// For the Ethereum bridge Pool transfers - BridgePool(BTreeSetStore) + BridgePool(BTreeSetStore), } impl Store { @@ -125,7 +133,7 @@ pub enum StoreRef<'a> { /// For PoS-related data PoS(&'a SmtStore), /// For the Ethereum bridge Pool transfers - BridgePool(&'a BTreeSetStore) + BridgePool(&'a BTreeSetStore), } impl<'a> StoreRef<'a> { @@ -268,7 +276,8 @@ impl MerkleTree { let account = Smt::new(stores.account.0.into(), stores.account.1); let ibc = Amt::new(stores.ibc.0.into(), stores.ibc.1); let pos = Smt::new(stores.pos.0.into(), stores.pos.1); - let bridge_pool = BridgePoolTree::new(stores.bridge_pool.0, stores.bridge_pool.1); + let bridge_pool = + BridgePoolTree::new(stores.bridge_pool.0, stores.bridge_pool.1); Self { base, account, @@ -288,7 +297,10 @@ impl MerkleTree { } } - fn tree_mut(&mut self, store_type: &StoreType) -> &mut impl traits::MerkleTree { + fn tree_mut( + &mut self, + store_type: &StoreType, + ) -> &mut impl traits::MerkleTree { match store_type { StoreType::Base => &mut self.base, StoreType::Account => &mut self.account, @@ -320,7 +332,11 @@ impl MerkleTree { } /// Update the tree with the given key and value - pub fn update>(&mut self, key: &Key, value: impl Into>) -> Result<()> { + pub fn update>( + &mut self, + key: &Key, + value: impl Into>, + ) -> Result<()> { let (store_type, sub_key) = StoreType::sub_key(key)?; self.update_tree(&store_type, sub_key.into(), value.into()) } @@ -343,94 +359,70 @@ impl MerkleTree { account: (self.account.root().into(), self.account.store()), ibc: (self.ibc.root().into(), self.ibc.store()), pos: (self.pos.root().into(), self.pos.store()), - bridge_pool: (self.bridge_pool.root(). self.) + bridge_pool: (self.bridge_pool.root(), self.bridge_pool.store()), } } - /// Get the existence proof - pub fn get_existence_proof( + /// Get the existence proof from a sub-tree + pub fn get_sub_tree_existence_proof>( &self, - key: &Key, - value: Vec, - ) -> Result { - let (store_type, sub_key) = StoreType::sub_key(key)?; - let sub_proof = match self.tree(&store_type) { - Either::Left(smt) => { - let cp = smt - .membership_proof(&H::hash(&sub_key.to_string()).into())?; - // Replace the values and the leaf op for the verification - match cp.proof.expect("The proof should exist") { - Ics23Proof::Exist(ep) => CommitmentProof { - proof: Some(Ics23Proof::Exist(ExistenceProof { - key: sub_key.to_string().as_bytes().to_vec(), - value, - leaf: Some(self.leaf_spec()), - ..ep - })), - }, - // the proof should have an ExistenceProof - _ => unreachable!(), - } + keys: &[Key], + values: Vec>, + ) -> Result { + let first_key = keys.iter().next().ok_or(Error::InvalidMerkleKey( + "No keys provided for existence proof.".into(), + ))?; + let (store_type, _) = StoreType::sub_key(first_key)?; + if !keys.iter().all(|k| { + if let Ok((s, _)) = StoreType::sub_key(k) { + s == store_type + } else { + false } - Either::Right(amt) => { - let key = - StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; - let cp = amt.membership_proof(&key)?; - - // Replace the values and the leaf op for the verification - match cp.proof.expect("The proof should exist") { - Ics23Proof::Exist(ep) => CommitmentProof { - proof: Some(Ics23Proof::Exist(ExistenceProof { - leaf: Some(self.ibc_leaf_spec()), - ..ep - })), - }, - _ => unreachable!(), - } - } - }; - self.get_proof(key, sub_proof) + }) { + return Err(Error::InvalidMerkleKey( + "Cannot construct inclusion proof for keys in separate \ + sub-trees." + .into(), + )); + } + self.tree(&store_type).membership_proof(keys, values) } /// Get the non-existence proof pub fn get_non_existence_proof(&self, key: &Key) -> Result { let (store_type, sub_key) = StoreType::sub_key(key)?; - let sub_proof = match self.tree(&store_type) { - Either::Left(_) => { - return Err(Error::NonExistenceProof(store_type.to_string())); - } - Either::Right(amt) => { - let key = - StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; - let mut nep = amt.non_membership_proof(&key)?; - // Replace the values and the leaf op for the verification - if let Some(ref mut nep) = nep.proof { - match nep { - Ics23Proof::Nonexist(ref mut ep) => { - let NonExistenceProof { - ref mut left, - ref mut right, - .. - } = ep; - let ep = left.as_mut().or(right.as_mut()).expect( - "A left or right existence proof should exist.", - ); - ep.leaf = Some(self.ibc_leaf_spec()); - } - _ => unreachable!(), - } + if store_type != StoreType::Ibc { + return Err(Error::NonExistenceProof(store_type.to_string())); + } + + let key = StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; + let mut nep = self.ibc.non_membership_proof(&key)?; + // Replace the values and the leaf op for the verification + if let Some(ref mut nep) = nep.proof { + match nep { + Ics23Proof::Nonexist(ref mut ep) => { + let NonExistenceProof { + ref mut left, + ref mut right, + .. + } = ep; + let ep = left.as_mut().or(right.as_mut()).expect( + "A left or right existence proof should exist.", + ); + ep.leaf = Some(self.ibc_leaf_spec()); } - nep + _ => unreachable!(), } - }; + } + // Get a proof of the sub tree self.get_proof(key, sub_proof) } /// Get the Tendermint proof with the base proof - fn get_proof( + pub fn get_tendermint_proof>( &self, - key: &Key, sub_proof: CommitmentProof, ) -> Result { let mut data = vec![]; @@ -453,7 +445,7 @@ impl MerkleTree { Ics23Proof::Exist(ep) => CommitmentProof { proof: Some(Ics23Proof::Exist(ExistenceProof { key: base_key.as_bytes().to_vec(), - leaf: Some(self.base_leaf_spec()), + leaf: Some(ics23_specs::base_leaf_spec::()), ..ep })), }, @@ -476,73 +468,6 @@ impl MerkleTree { ops: vec![sub_proof_op, base_proof_op], }) } - - /// Get the proof specs - pub fn proof_specs(&self) -> Vec { - let spec = arse_merkle_tree::proof_ics23::get_spec(H::hash_op()); - let sub_tree_spec = ProofSpec { - leaf_spec: Some(self.leaf_spec()), - ..spec.clone() - }; - let base_tree_spec = ProofSpec { - leaf_spec: Some(self.base_leaf_spec()), - ..spec - }; - vec![sub_tree_spec, base_tree_spec] - } - - /// Get the proof specs for ibc - pub fn ibc_proof_specs(&self) -> Vec { - let spec = arse_merkle_tree::proof_ics23::get_spec(H::hash_op()); - let sub_tree_spec = ProofSpec { - leaf_spec: Some(self.ibc_leaf_spec()), - ..spec.clone() - }; - let base_tree_spec = ProofSpec { - leaf_spec: Some(self.base_leaf_spec()), - ..spec - }; - vec![sub_tree_spec, base_tree_spec] - } - - /// Get the leaf spec for the base tree. The key is stored after hashing, - /// but the stored value is the subtree's root without hashing. - fn base_leaf_spec(&self) -> LeafOp { - LeafOp { - hash: H::hash_op().into(), - prehash_key: H::hash_op().into(), - prehash_value: HashOp::NoHash.into(), - length: LengthOp::NoPrefix.into(), - prefix: H256::zero().as_slice().to_vec(), - } - } - - /// Get the leaf spec for the subtree. Non-hashed values are used for the - /// verification with this spec because a subtree stores the key-value pairs - /// after hashing. - fn leaf_spec(&self) -> LeafOp { - LeafOp { - hash: H::hash_op().into(), - prehash_key: H::hash_op().into(), - prehash_value: H::hash_op().into(), - length: LengthOp::NoPrefix.into(), - prefix: H256::zero().as_slice().to_vec(), - } - } - - /// Get the leaf spec for the ibc subtree. Non-hashed values are used for - /// the verification with this spec because a subtree stores the - /// key-value pairs after hashing. However, keys are also not hashed in - /// the backing store. - fn ibc_leaf_spec(&self) -> LeafOp { - LeafOp { - hash: H::hash_op().into(), - prehash_key: HashOp::NoHash.into(), - prehash_value: HashOp::NoHash.into(), - length: LengthOp::NoPrefix.into(), - prefix: H256::zero().as_slice().to_vec(), - } - } } /// The root hash of the merkle tree as bytes @@ -607,7 +532,7 @@ pub struct MerkleTreeStoresWrite<'a> { account: (Hash, &'a SmtStore), ibc: (Hash, &'a AmtStore), pos: (Hash, &'a SmtStore), - bridge_pool: (Hash, &'a BTreeSetStore) + bridge_pool: (Hash, &'a BTreeSetStore), } impl<'a> MerkleTreeStoresWrite<'a> { @@ -618,7 +543,7 @@ impl<'a> MerkleTreeStoresWrite<'a> { StoreType::Account => &self.account.0, StoreType::Ibc => &self.ibc.0, StoreType::PoS => &self.pos.0, - StoreType::BridgePool => &self.bridge_pool.0 + StoreType::BridgePool => &self.bridge_pool.0, } } @@ -629,12 +554,11 @@ impl<'a> MerkleTreeStoresWrite<'a> { StoreType::Account => StoreRef::Account(self.account.1), StoreType::Ibc => StoreRef::Ibc(self.ibc.1), StoreType::PoS => StoreRef::PoS(self.pos.1), - StoreType::BridgePool => StoreRef::BridgePool(self.bridge_pool.1) + StoreType::BridgePool => StoreRef::BridgePool(self.bridge_pool.1), } } } - impl From for Error { fn from(error: StorageError) -> Self { Error::InvalidKey(error) diff --git a/shared/src/ledger/storage/mod.rs b/shared/src/ledger/storage/mod.rs index 4def551e0f..74826fba3c 100644 --- a/shared/src/ledger/storage/mod.rs +++ b/shared/src/ledger/storage/mod.rs @@ -1,11 +1,12 @@ //! Ledger's state storage with key-value backed store and a merkle tree +mod ics23_specs; mod merkle_tree; #[cfg(any(test, feature = "testing"))] pub mod mockdb; +pub mod traits; pub mod types; pub mod write_log; -pub mod traits; use core::fmt::Debug; diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs index d5411cc966..c558c7cbe9 100644 --- a/shared/src/ledger/storage/traits.rs +++ b/shared/src/ledger/storage/traits.rs @@ -3,27 +3,36 @@ use std::convert::{TryFrom, TryInto}; use std::fmt; -use arse_merkle_tree::{H256, Hash as SmtHash, Key as TreeKey}; -use arse_merkle_tree::traits::{Value, Hasher}; -use ibc_proto::ics23::CommitmentProof; +use arse_merkle_tree::traits::{Hasher, Value}; +use arse_merkle_tree::{Hash as SmtHash, Key as TreeKey, H256}; +use ics23::commitment_proof::Proof as Ics23Proof; +use ics23::{CommitmentProof, ExistenceProof}; use sha2::{Digest, Sha256}; -use super::IBC_KEY_LIMIT; -use super::merkle_tree::{Smt, Amt, Error}; +use super::merkle_tree::{Amt, Error, Smt}; +use super::{ics23_specs, IBC_KEY_LIMIT}; use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; use crate::types::eth_bridge_pool::PendingTransfer; use crate::types::hash::Hash; use crate::types::storage::{ - MerkleKey, StringKey, TreeBytes, MerkleValue, Key + Key, MembershipProof, MerkleValue, StringKey, TreeBytes, }; pub trait MerkleTree { type Error; fn has_key(&self, key: &Key) -> Result; - fn update>(&mut self, key: &Key, value: MerkleValue) -> Result; + fn update>( + &mut self, + key: &Key, + value: MerkleValue, + ) -> Result; fn delete(&mut self, key: &Key) -> Result<(), Self::Error>; - fn membership_proof(&self, keys: &[Key], proof: Option) -> Option; + fn membership_proof>( + &self, + keys: &[Key], + values: Vec>, + ) -> Result; } impl MerkleTree for Smt { @@ -35,28 +44,56 @@ impl MerkleTree for Smt { .map_error(|err| Error::MerkleTree(err.to_string())) } - fn update>(&mut self, key: &Key, value: MerkleValue) -> Result { + fn update>( + &mut self, + key: &Key, + value: MerkleValue, + ) -> Result { let value = match value { MerkleValue::Bytes(bytes) => Hash::try_from(bytes.as_ref()) .map_err(|| Error::InvalidValue)?, - _ => return Err(Error::InvalidValue) + _ => return Err(Error::InvalidValue), }; - self.update( - H::hash(key.to_string()).into(), - value, - ) - .map(Hash::into) - .map_err(|err| Error::MerkleTree(err.to_string())) + self.update(H::hash(key.to_string()).into(), value) + .map(Hash::into) + .map_err(|err| Error::MerkleTree(err.to_string())) } fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { let value = Hash::zero(); - self.update( - H::hash(key.to_string()).into(), - value - ) - .and(Ok(())) - .map_err(|err|Error::MerkleTree(err.to_string())) + self.update(H::hash(key.to_string()).into(), value) + .and(Ok(())) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn membership_proof>( + &self, + keys: &[Key], + mut values: Vec>, + ) -> Result { + if keys.len() != 1 || values.len() != 1 { + return Err(Error::Ics23MultiLeaf); + } + let key: &Key = &keys[0]; + let value = match values.remove(0) { + MerkleValue::Bytes(b) => b.as_ref().to_vec(), + _ => return Err(Error::InvalidValue), + }; + let cp = self.membership_proof(&H::hash(key.to_string()).into())?; + // Replace the values and the leaf op for the verification + match cp.proof.expect("The proof should exist") { + Ics23Proof::Exist(ep) => Ok(CommitmentProof { + proof: Some(Ics23Proof::Exist(ExistenceProof { + key: key.to_string().as_bytes().to_vec(), + value, + leaf: Some(ics23_specs::leaf_spec::()), + ..ep + })), + } + .into()), + // the proof should have an ExistenceProof + _ => unreachable!(), + } } } @@ -64,38 +101,60 @@ impl MerkleTree for Amt { type Error = Error; fn has_key(&self, key: &Key) -> Result { - let key = - StringKey::try_from_bytes(key.to_string().as_bytes())?; + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; self.get(&key) .and(Ok(bool)) .map_err(|err| Error::MerkleTree(err.to_string())) } - fn update>(&mut self, key: MerkleKey, value: MerkleValue) -> Result { - let key = - StringKey::try_from_bytes(key.to_string().as_bytes())?; + fn update>( + &mut self, + key: MerkleKey, + value: MerkleValue, + ) -> Result { + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; let value = match value { - MerkleValue::Bytes(bytes) => TreeBytes::from(bytes.as_ref().to_vec()), - _ => return Err(Error::InvalidValue) + MerkleValue::Bytes(bytes) => { + TreeBytes::from(bytes.as_ref().to_vec()) + } + _ => return Err(Error::InvalidValue), }; - self.update( - key, - value, - ) - .map(Into::into) - .map_err(|err|Error::MerkleTree(err.to_string())) + self.update(key, value) + .map(Into::into) + .map_err(|err| Error::MerkleTree(err.to_string())) } fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { - let key = - StringKey::try_from_bytes(key.to_string().as_bytes())?; + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; let value = TreeBytes::zero(); - self.update( - key, - value - ) - .and(Ok(())) - .map_err(|err| Error::MerkleTree(format!("{:?}", err))) + self.update(key, value) + .and(Ok(())) + .map_err(|err| Error::MerkleTree(format!("{:?}", err))) + } + + fn membership_proof>( + &self, + keys: &[Key], + _: Vec>, + ) -> Result { + if keys.len() != 1 || values.len() != 1 { + return Err(Error::Ics23MultiLeaf); + } + + let key = StringKey::try_from_bytes(&keys[0].to_string().as_bytes())?; + let cp = self.membership_proof(&key)?; + // Replace the values and the leaf op for the verification + match cp.proof.expect("The proof should exist") { + Ics23Proof::Exist(ep) => Ok(CommitmentProof { + proof: Some(Ics23Proof::Exist(ExistenceProof { + leaf: Some(ics23_specs::ibc_leaf_spec::()), + ..ep + })), + } + .into()), + // the proof should have an ExistenceProof + _ => unreachable!(), + } } } @@ -107,10 +166,14 @@ impl MerkleTree for BridgePoolTree { .map_err(|err| Error::MerkleTree(err.to_string())) } - fn update>(&mut self, key: &Key, value: MerkleValue) -> Result { - if let MerkleValue::Transfer(transfer) = value { - self.update(key, transfer) - .map_err( | err| Error::MerkleTree(err.to_string())) + fn update>( + &mut self, + key: &Key, + value: MerkleValue, + ) -> Result { + if let MerkleValue::Transfer(_) = value { + self.update(key) + .map_err(|err| Error::MerkleTree(err.to_string())) } else { Err(Error::InvalidValue) } @@ -120,6 +183,23 @@ impl MerkleTree for BridgePoolTree { self.delete(key) .map_err(|err| Error::MerkleTree(err.to_string())) } + + fn membership_proof>( + &self, + keys: &[Key], + values: Vec>, + ) -> Result { + let values = values + .into_iter() + .filter_map(|val| match val { + MerkleValue::Transfer(transfer) => Some(transfer), + _ => None, + }) + .collect(); + self.membership_proof(keys, values) + .map(Into::into) + .map_err(|err| Error::MerkleTree(err.to_string())) + } } impl TreeKey for StringKey { @@ -161,10 +241,6 @@ impl Value for TreeBytes { } } -pub trait MembershipProof { }; - -impl MembershipProof for CommitmentProof; - /// The storage hasher used for the merkle tree. pub trait StorageHasher: Hasher + Default { /// Hash the value to store @@ -211,4 +287,4 @@ impl fmt::Debug for Sha256Hasher { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Sha256Hasher") } -} \ No newline at end of file +} diff --git a/shared/src/types/eth_bridge_pool.rs b/shared/src/types/eth_bridge_pool.rs index 17ba1f57e7..19c0f805cd 100644 --- a/shared/src/types/eth_bridge_pool.rs +++ b/shared/src/types/eth_bridge_pool.rs @@ -1,10 +1,10 @@ //! The necessary type definitions for the contents of the //! Ethereum bridge pool -use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use ethabi::token::Token; use crate::types::address::Address; -use crate::types::ethereum_events::{EthAddress, Uint, KeccakHash}; +use crate::types::ethereum_events::{EthAddress, KeccakHash, Uint}; use crate::types::keccak; use crate::types::token::Amount; @@ -54,24 +54,16 @@ pub struct PendingTransfer { } impl keccak::encode::Encode for PendingTransfer { - fn tokenize(&self) -> Vec { let from = Token::String(self.gas_fee.payer.to_string()); let fee = Token::Uint(u64::from(self.gas_fee.amount).into()); let to = Token::Address(self.transfer.recipient.0.into()); let amount = Token::Uint(u64::from(self.transfer.amount).into()); let nonce = Token::Uint(self.transfer.nonce.into()); - vec![ - from, - fee, - to, - amount, - nonce, - ] + vec![from, fee, to, amount, nonce] } } - /// The amount of NAM to be payed to the relayer of /// a transfer across the Ethereum Bridge to compensate /// for Ethereum gas fees. diff --git a/shared/src/types/hash.rs b/shared/src/types/hash.rs index e4ac6e8c2c..f2a84f19eb 100644 --- a/shared/src/types/hash.rs +++ b/shared/src/types/hash.rs @@ -25,7 +25,7 @@ pub enum Error { #[error("Failed trying to convert slice to a hash: {0}")] ConversionFailed(std::array::TryFromSliceError), #[error("Failed to convert string into a hash: {0}")] - FromStringError(hex::FromHexError) + FromStringError(hex::FromHexError), } /// Result for functions that may fail @@ -93,7 +93,8 @@ impl TryFrom for Hash { type Error = self::Error; fn try_from(string: String) -> HashResult { - let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + let bytes: Vec = + Vec::from_hex(string).map_err(Error::FromStringError)?; Self::try_from(&bytes) } } @@ -102,7 +103,8 @@ impl TryFrom<&str> for Hash { type Error = self::Error; fn try_from(string: &str) -> HashResult { - let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + let bytes: Vec = + Vec::from_hex(string).map_err(Error::FromStringError)?; Self::try_from(&bytes) } } @@ -165,4 +167,4 @@ impl Value for Hash { fn zero() -> Self { Hash([0u8; 32]) } -} \ No newline at end of file +} diff --git a/shared/src/types/storage.rs b/shared/src/types/storage.rs index 7b7ffad7a2..e13aa14dc5 100644 --- a/shared/src/types/storage.rs +++ b/shared/src/types/storage.rs @@ -9,17 +9,17 @@ use std::str::FromStr; use arse_merkle_tree::InternalKey; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use ics23::CommitmentProof; use serde::{Deserialize, Serialize}; use thiserror::Error; -use variant_access_derive::*; -use variant_access_traits::*; #[cfg(feature = "ferveo-tpke")] use super::transaction::WrapperTx; use crate::bytes::ByteBuf; +use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolProof; use crate::ledger::storage::{StorageHasher, IBC_KEY_LIMIT}; use crate::types::address::{self, Address}; -use crate::types::eth_bridge_pool::{TransferToEthereum, PendingTransfer}; +use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; use crate::types::hash::Hash; use crate::types::time::DateTimeUtc; @@ -35,7 +35,7 @@ pub enum Error { #[error("Reserved prefix or string is specified: {0}")] InvalidKeySeg(String), #[error("Could not parse string: '{0}' into requested type: {1}")] - ParseError((String, String)) + ParseError(String, String), } /// Result for functions that may fail @@ -248,15 +248,13 @@ impl FromStr for Key { pub enum MerkleValue> { /// raw bytes Bytes(T), - /// a transfer to be put in the Ethereum bridge pool - /// We actually only need the key (which is the hash - /// of the transfer). So this variant contains no data. + /// A transfer to be put in the Ethereum bridge pool. Transfer(PendingTransfer), } impl From for MerkleValue where - T: AsRef<[u8]> + T: AsRef<[u8]>, { fn from(bytes: T) -> Self { Self::Bytes(bytes) @@ -348,6 +346,26 @@ impl From for Vec { } } +/// Type of membership proof from a merkle tree +pub enum MembershipProof { + /// ICS23 compliant membership proof + ICS23(CommitmentProof), + /// Bespoke membership proof for the Ethereum bridge pool + BridgePool(BridgePoolProof), +} + +impl From for MembershipProof { + fn from(proof: CommitmenProof) -> Self { + Self::ICS23(proof) + } +} + +impl From for MembershipProof { + fn from(proof: BridgePoolProof) -> Self { + Self::BridgePool(proof) + } +} + impl Key { /// Parses string and returns a key pub fn parse(string: impl AsRef) -> Result { @@ -609,7 +627,8 @@ impl KeySeg for Address { impl KeySeg for Hash { fn parse(seg: String) -> Result { - seg.try_into().map_error(Error::ParseError((seg, "Hash".into()))) + seg.try_into() + .map_error(Error::ParseError((seg, "Hash".into()))) } fn raw(&self) -> String { @@ -670,7 +689,6 @@ impl Add for Epoch { } } - impl Sub for Epoch { type Output = Epoch; From 463089d9b30c2753835842b4b636c38596351224 Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 29 Sep 2022 10:26:41 +0200 Subject: [PATCH 04/28] [chore]: Rebase on eth-bridge-intregration --- Cargo.lock | 270 +++++++++++++++++- apps/src/lib/node/ledger/protocol/mod.rs | 3 - shared/Cargo.toml | 2 + .../ledger/eth_bridge/storage/bridge_pool.rs | 158 ++++++++++ shared/src/ledger/storage/merkle_tree.rs | 250 +++++----------- shared/src/ledger/storage/mod.rs | 1 + shared/src/ledger/storage/traits.rs | 214 ++++++++++++++ shared/src/types/eth_bridge_pool.rs | 28 +- shared/src/types/hash.rs | 23 +- shared/src/types/storage.rs | 57 +++- 10 files changed, 806 insertions(+), 200 deletions(-) create mode 100644 shared/src/ledger/storage/traits.rs diff --git a/Cargo.lock b/Cargo.lock index 34a1cf2c90..adbc38f162 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1131,6 +1131,28 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "chrono-tz" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + [[package]] name = "chunked_transfer" version = "1.4.0" @@ -1707,6 +1729,12 @@ dependencies = [ "syn", ] +[[package]] +name = "deunicode" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" + [[package]] name = "diff" version = "0.1.12" @@ -2506,6 +2534,17 @@ dependencies = [ "regex", ] +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags", + "ignore", + "walkdir", +] + [[package]] name = "gloo-timers" version = "0.2.4" @@ -2761,6 +2800,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humansize" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" + [[package]] name = "hyper" version = "0.10.16" @@ -3027,6 +3072,24 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ignore" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +dependencies = [ + "crossbeam-utils 0.8.8", + "globset", + "lazy_static 1.4.0", + "log 0.4.17", + "memchr", + "regex", + "same-file", + "thread_local 1.1.4", + "walkdir", + "winapi-util", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -3953,6 +4016,12 @@ dependencies = [ "serde_yaml", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "match_cfg" version = "0.1.0" @@ -4321,6 +4390,8 @@ dependencies = [ "tonic-build", "tracing 0.1.35", "tracing-subscriber 0.3.11", + "variant_access_derive", + "variant_access_traits", "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", @@ -4391,7 +4462,7 @@ dependencies = [ "rocksdb", "rpassword", "semver 1.0.14", - "serde 1.0.144", + "serde 1.0.137", "serde_bytes", "serde_json", "serde_regex", @@ -5075,6 +5146,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + [[package]] name = "paste" version = "1.0.7" @@ -5141,6 +5221,40 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1 0.8.2", +] + [[package]] name = "petgraph" version = "0.5.1" @@ -5161,6 +5275,45 @@ dependencies = [ "indexmap", ] +[[package]] +name = "phf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +dependencies = [ + "siphasher", + "uncased", +] + [[package]] name = "pin-project" version = "0.4.29" @@ -6611,12 +6764,27 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "slab" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +[[package]] +name = "slug" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" +dependencies = [ + "deunicode", +] + [[package]] name = "smallvec" version = "0.6.14" @@ -7122,6 +7290,28 @@ dependencies = [ "time 0.3.9", ] +[[package]] +name = "tera" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d" +dependencies = [ + "chrono", + "chrono-tz", + "globwalk", + "humansize", + "lazy_static 1.4.0", + "percent-encoding 2.1.0", + "pest", + "pest_derive", + "rand 0.8.5", + "regex", + "serde 1.0.137", + "serde_json", + "slug", + "unic-segment", +] + [[package]] name = "term_size" version = "0.3.2" @@ -7946,6 +8136,65 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uncased" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" +dependencies = [ + "version_check 0.9.4", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" +dependencies = [ + "unic-ucd-segment", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "1.4.2" @@ -8106,6 +8355,25 @@ dependencies = [ "version_check 0.9.4", ] +[[package]] +name = "variant_access_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd235ffafb854ed81b49217ce411e850a39628a5d26740ecfb60421c873d834" +dependencies = [ + "lazy_static 1.4.0", + "quote", + "syn", + "tera", + "variant_access_traits", +] + +[[package]] +name = "variant_access_traits" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d75c5a83bb8912dd9c628adf954c9f9bff74a4e170d2c90242f4e56a0d643e" + [[package]] name = "vcpkg" version = "0.2.15" diff --git a/apps/src/lib/node/ledger/protocol/mod.rs b/apps/src/lib/node/ledger/protocol/mod.rs index 9b1b13c859..90bb6994b1 100644 --- a/apps/src/lib/node/ledger/protocol/mod.rs +++ b/apps/src/lib/node/ledger/protocol/mod.rs @@ -204,9 +204,6 @@ where /// containing changed keys and the like should be returned in the normal way. pub(crate) fn apply_protocol_tx<'a, D, H>( tx: ProtocolTxType, - // TODO: eventually this `storage` parameter could be tightened further to - // an impl trait of only the subset of [`Storage`] functionality that we - // need _storage: &'a mut Storage, ) -> Result where diff --git a/shared/Cargo.toml b/shared/Cargo.toml index 08df6d1949..e66f2b5ed7 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -117,6 +117,8 @@ tendermint-proto = {git = "https://github.com/heliaxdev/tendermint-rs", branch = thiserror = "1.0.30" tiny-keccak = "2.0.2" tracing = "0.1.30" +variant_access_derive = "0.4.1" +variant_access_traits = "0.4.1" wasmer = {version = "=2.2.0", optional = true} wasmer-cache = {version = "=2.2.0", optional = true} wasmer-compiler-singlepass = {version = "=2.2.0", optional = true} diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index b86266f124..8588ae0550 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -1,8 +1,18 @@ //! Tools for accessing the storage subspaces of the Ethereum //! bridge pool +use std::collections::BTreeMap; +use std::convert::TryInto; +use std::ops::Deref; + +use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use eyre::eyre; use crate::types::address::{Address, InternalAddress}; +use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; +use crate::types::ethereum_events::KeccakHash; +use crate::types::hash::{Hash, keccak_hash}; use crate::types::storage::{DbKeySeg, Key}; +use crate::ledger::storage::{Sha256Hasher, StorageHasher}; /// The main address of the Ethereum bridge pool pub const BRIDGE_POOL_ADDRESS: Address = @@ -12,6 +22,11 @@ const PENDING_TRANSFERS_SEG: &str = "pending_transfers"; /// Sub-segment for getting the latest signed const SIGNED_ROOT_SEG: &str = "signed_root"; +#[derive(thiserror::Error, Debug)] +#[error(transparent)] +/// Generic error that may be returned by the validity predicate +pub struct Error(#[from] eyre::Error); + /// Get the storage key for the transfers in the pool pub fn get_pending_key() -> Key { Key { @@ -44,3 +59,146 @@ pub fn is_bridge_pool_key(key: &Key) -> bool { pub fn is_protected_storage(key: &Key) -> bool { is_bridge_pool_key(key) && *key != get_pending_key() } + +/// A simple Merkle tree for the Ethereum bridge pool +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, BorshSchema)] +pub struct BridgePoolTree { + /// Root of the tree + root: KeccakHash, + /// The underlying storage + store: BTreeMap +} + +/// TODO: Hash ABI instead of Borsh +impl BridgePoolTree { + /// Create a new merkle tree for the Ethereum bridge pool + pub fn new(root: KeccakHash, store: BTreeMap) -> Self { + Self{ root, store } + } + + /// Parse the key to ensure it is of the correct type. + /// + /// If it is, it can be converted to a hash. + /// Checks if the hash is in the tree. + pub fn has_key(&self, key: &Key) -> Result { + Ok(self.store.contains_key(&Self::parse_key(key)?)) + } + + /// Update the tree with a new value. + /// + /// Returns the new root if successful. Will + /// return an error if the key is malformed. + pub fn update(&mut self, key: &Key, value: PendingTransfer) -> Result { + let hash = Self::parse_key(key)?; + if hash != keccak_hash(&value.try_to_vec().unwrap()) { + return eyre!("Key does not match hash of the value")?; + } + _ = self.store.insert(hash, value); + self.root = self.compute_root(); + Ok(self.root()) + } + + /// Delete a key from storage and update the root + pub fn delete(&mut self, key: &Key) -> Result<(), Error>{ + let hash = Self::parse_key(key)?; + _ = self.store.remove(&hash); + self.root = self.compute_root(); + Ok(()) + } + + /// Compute the root of the merkle tree + pub fn compute_root(&self) -> KeccakHash { + let mut leaves = self.store.iter(); + let mut root = if let Some((hash, _)) = leaves.next() { + hash.clone() + } else { + return Default::default(); + }; + + for (leaf, _) in leaves { + root = keccak_hash([root.0, leaf.0].concat()); + } + root + } + + /// Return the root as a [`Hash`] type. + pub fn root(&self) -> Hash { + self.root.clone().into() + } + + /// Get a reference to the backing store + pub fn store(&self) -> &BTreeMap { + &self.store + } + + pub fn membership_proof(&self, keys: &[Key]) -> BridgePoolProof { + for (key, value) in self.store { + + } + } + + /// Parse a db key to see if it is valid for the + /// bridge pool. + /// + /// It should have one string segment which should + /// parse into a [Hash] + fn parse_key(key: &Key) -> Result { + if key.segments.len() == 1 { + match &key.segments[0] { + DbKeySeg::StringSeg(str) => str.as_str().try_into().ok_or( + eyre!("Could not parse key segment as a hash")? + ), + _ => eyre!("Bridge pool keys should be strings, not addresses")? + } + } else { + eyre!("Key for the bridge pool should not have more than one segment")? + } + } +} + +/// A multi-leaf membership proof +pub struct BridgePoolProof { + /// The hashes other than the provided leaves + pub proof: Vec, + /// The leaves; must be sorted + pub leaves: Vec, + /// flags to indicate how to combine hashes + pub flags: Vec, +} + +impl BridgePoolProof { + + /// Verify a membership proof matches the provided root + pub fn verify(&self, root: KeccakHash) -> bool { + if self.proof.len() + self.leaves.len() != self.flags.len() { + return false; + } + if self.flags.len() == 0 { + return true; + } + let mut leaf_pos = 0usize; + let mut proof_pos = 0usize; + let mut computed; + if self.flags[0] { + leaf = self.leaves[leaf_pos].clone(); + computed = keccak_hash(leaf.try_to_vec().unwrap()); + leaf_pos += 1; + } else { + computed = self.proof[proof_pos].clone(); + proof_pos += 1; + } + for flag in 1..self.flages.len() { + let mut next_hash; + if self.flags[flag] { + leaf = self.leaves[leaf_pos].clone(); + next_hash = keccak_hash(leaf.try_to_vec().unwrap()); + leaf_pos += 1; + } else { + next_hash = self.proof[proof_pos].clone(); + proof_pos += 1; + } + computed = keccak_hash([computed, next_hash].concat()); + } + computed == root + } +} diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index d5a6d11ab5..b2598aa210 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -16,20 +16,22 @@ use ics23::{ CommitmentProof, ExistenceProof, HashOp, LeafOp, LengthOp, NonExistenceProof, ProofSpec, }; -use itertools::Either; +use itertools::{Either, Itertools}; use prost::Message; use sha2::{Digest, Sha256}; use thiserror::Error; use super::IBC_KEY_LIMIT; +use super::traits::{self, StorageHasher, Sha256Hasher}; use crate::bytes::ByteBuf; +use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; use crate::ledger::storage::types; use crate::tendermint::merkle::proof::{Proof, ProofOp}; use crate::types::address::{Address, InternalAddress}; +use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; +use crate::types::ethereum_events::KeccakHash; use crate::types::hash::Hash; -use crate::types::storage::{ - DbKeySeg, Error as StorageError, Key, MerkleKey, StringKey, TreeBytes, -}; +use crate::types::storage::{DbKeySeg, Error as StorageError, Key, StringKey, TreeBytes, MerkleValue}; #[allow(missing_docs)] #[derive(Error, Debug)] @@ -41,11 +43,13 @@ pub enum Error { #[error("Empty Key: {0}")] EmptyKey(String), #[error("Merkle Tree error: {0}")] - MerkleTree(MtError), + MerkleTree(String), #[error("Invalid store type: {0}")] StoreType(String), #[error("Non-existence proofs not supported for store type: {0}")] NonExistenceProof(String), + #[error("Invalid value given to sub-tree storage")] + InvalidValue, } /// Result for functions that may fail @@ -54,6 +58,7 @@ type Result = std::result::Result; /// Type aliases for the different merkle trees and backing stores pub type SmtStore = DefaultStore; pub type AmtStore = DefaultStore; +pub type BridgePoolStore = std::collections::BTreeMap; pub type Smt = ArseMerkleTree; pub type Amt = ArseMerkleTree; @@ -79,6 +84,8 @@ pub enum StoreType { Ibc, /// For PoS-related data PoS, + /// For the Ethereum bridge Pool transfers + BridgePool, } /// Backing storage for merkle trees @@ -91,6 +98,8 @@ pub enum Store { Ibc(AmtStore), /// For PoS-related data PoS(SmtStore), + /// For the Ethereum bridge Pool transfers + BridgePool(BTreeSetStore) } impl Store { @@ -100,6 +109,7 @@ impl Store { Self::Account(store) => StoreRef::Account(store), Self::Ibc(store) => StoreRef::Ibc(store), Self::PoS(store) => StoreRef::PoS(store), + Self::BridgePool(store) => StoreRef::BridgePool(store), } } } @@ -114,6 +124,8 @@ pub enum StoreRef<'a> { Ibc(&'a AmtStore), /// For PoS-related data PoS(&'a SmtStore), + /// For the Ethereum bridge Pool transfers + BridgePool(&'a BTreeSetStore) } impl<'a> StoreRef<'a> { @@ -123,6 +135,7 @@ impl<'a> StoreRef<'a> { Self::Account(store) => Store::Account(store.to_owned()), Self::Ibc(store) => Store::Ibc(store.to_owned()), Self::PoS(store) => Store::PoS(store.to_owned()), + Self::BridgePool(store) => Store::BridgePool(store.to_owned()), } } @@ -132,6 +145,7 @@ impl<'a> StoreRef<'a> { Self::Account(store) => store.try_to_vec(), Self::Ibc(store) => store.try_to_vec(), Self::PoS(store) => store.try_to_vec(), + Self::BridgePool(store) => store.try_to_vec(), } .expect("Serialization failed") } @@ -140,11 +154,12 @@ impl<'a> StoreRef<'a> { impl StoreType { /// Get an iterator for the base tree and subtrees pub fn iter() -> std::slice::Iter<'static, Self> { - static SUB_TREE_TYPES: [StoreType; 4] = [ + static SUB_TREE_TYPES: [StoreType; 5] = [ StoreType::Base, StoreType::Account, StoreType::PoS, StoreType::Ibc, + StoreType::BridgePool, ]; SUB_TREE_TYPES.iter() } @@ -162,6 +177,9 @@ impl StoreType { InternalAddress::Ibc => { Ok((StoreType::Ibc, key.sub_key()?)) } + InternalAddress::EthBridgePool => { + Ok((StoreType::BridgePool, key.sub_key()?)) + } // use the same key for Parameters _ => Ok((StoreType::Account, key.clone())), } @@ -190,6 +208,9 @@ impl StoreType { Self::PoS => Ok(Store::PoS( types::decode(bytes).map_err(Error::CodingError)?, )), + Self::BridgePool => Ok(Store::BridgePool( + types::decode(bytes).map_err(Error::CodingError)?, + )), } } } @@ -203,6 +224,7 @@ impl FromStr for StoreType { "account" => Ok(StoreType::Account), "ibc" => Ok(StoreType::Ibc), "pos" => Ok(StoreType::PoS), + "eth_bridge_pool" => Ok(StoreType::BridgePool), _ => Err(Error::StoreType(s.to_string())), } } @@ -215,6 +237,7 @@ impl fmt::Display for StoreType { StoreType::Account => write!(f, "account"), StoreType::Ibc => write!(f, "ibc"), StoreType::PoS => write!(f, "pos"), + StoreType::BridgePool => write!(f, "eth_bridge_pool"), } } } @@ -226,6 +249,7 @@ pub struct MerkleTree { account: Smt, ibc: Amt, pos: Smt, + bridge_pool: BridgePoolTree, } impl core::fmt::Debug for MerkleTree { @@ -244,47 +268,43 @@ impl MerkleTree { let account = Smt::new(stores.account.0.into(), stores.account.1); let ibc = Amt::new(stores.ibc.0.into(), stores.ibc.1); let pos = Smt::new(stores.pos.0.into(), stores.pos.1); - + let bridge_pool = BridgePoolTree::new(stores.bridge_pool.0, stores.bridge_pool.1); Self { base, account, ibc, pos, + bridge_pool, + } + } + + fn tree(&self, store_type: &StoreType) -> &impl traits::MerkleTree { + match store_type { + StoreType::Base => &self.base, + StoreType::Account => &self.account, + StoreType::Ibc => &self.ibc, + StoreType::PoS => &self.pos, + StoreType::BridgePool => &self.bridge_pool, } } - fn tree(&self, store_type: &StoreType) -> Either<&Smt, &Amt> { + fn tree_mut(&mut self, store_type: &StoreType) -> &mut impl traits::MerkleTree { match store_type { - StoreType::Base => Either::Left(&self.base), - StoreType::Account => Either::Left(&self.account), - StoreType::Ibc => Either::Right(&self.ibc), - StoreType::PoS => Either::Left(&self.pos), + StoreType::Base => &mut self.base, + StoreType::Account => &mut self.account, + StoreType::Ibc => &mut self.ibc, + StoreType::PoS => &mut self.pos, + StoreType::BridgePool => &mut self.bridge_pool, } } - fn update_tree( + fn update_tree>( &mut self, store_type: &StoreType, - key: MerkleKey, - value: Either, + key: &Key, + value: MerkleValue, ) -> Result<()> { - let sub_root = match store_type { - StoreType::Account => self - .account - .update(key.try_into()?, value.unwrap_left()) - .map_err(Error::MerkleTree)?, - StoreType::Ibc => self - .ibc - .update(key.try_into()?, value.unwrap_right()) - .map_err(Error::MerkleTree)?, - StoreType::PoS => self - .pos - .update(key.try_into()?, value.unwrap_left()) - .map_err(Error::MerkleTree)?, - // base tree should not be directly updated - StoreType::Base => unreachable!(), - }; - + let sub_root = self.tree_mut(store_type).update(key, value)?; // update the base tree with the updated sub root without hashing if *store_type != StoreType::Base { let base_key = H::hash(&store_type.to_string()); @@ -296,41 +316,19 @@ impl MerkleTree { /// Check if the key exists in the tree pub fn has_key(&self, key: &Key) -> Result { let (store_type, sub_key) = StoreType::sub_key(key)?; - let value = match self.tree(&store_type) { - Either::Left(smt) => { - smt.get(&H::hash(sub_key.to_string()).into())?.is_zero() - } - Either::Right(amt) => { - let key = - StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; - amt.get(&key)?.is_zero() - } - }; - Ok(!value) + self.tree(&store_type).has_key(&sub_key) } /// Update the tree with the given key and value - pub fn update(&mut self, key: &Key, value: impl AsRef<[u8]>) -> Result<()> { - let sub_key = StoreType::sub_key(key)?; - let store_type = sub_key.0; - let value = match store_type { - StoreType::Ibc => { - Either::Right(TreeBytes::from(value.as_ref().to_vec())) - } - _ => Either::Left(H::hash(value).into()), - }; - self.update_tree(&store_type, sub_key.into(), value) + pub fn update>(&mut self, key: &Key, value: impl Into>) -> Result<()> { + let (store_type, sub_key) = StoreType::sub_key(key)?; + self.update_tree(&store_type, sub_key.into(), value.into()) } /// Delete the value corresponding to the given key pub fn delete(&mut self, key: &Key) -> Result<()> { - let sub_key = StoreType::sub_key(key)?; - let store_type = sub_key.0; - let value = match store_type { - StoreType::Ibc => Either::Right(TreeBytes::zero()), - _ => Either::Left(H256::zero().into()), - }; - self.update_tree(&store_type, sub_key.into(), value) + let (store_type, sub_key) = StoreType::sub_key(key)?; + self.tree_mut(&store_type).delete(&sub_key) } /// Get the root @@ -345,6 +343,7 @@ impl MerkleTree { account: (self.account.root().into(), self.account.store()), ibc: (self.ibc.root().into(), self.ibc.store()), pos: (self.pos.root().into(), self.pos.store()), + bridge_pool: (self.bridge_pool.root(). self.) } } @@ -568,45 +567,6 @@ impl fmt::Display for MerkleRoot { } } -impl From<(StoreType, Key)> for MerkleKey { - fn from((store, key): (StoreType, Key)) -> Self { - match store { - StoreType::Base | StoreType::Account | StoreType::PoS => { - MerkleKey::Sha256(key, PhantomData) - } - StoreType::Ibc => MerkleKey::Raw(key), - } - } -} - -impl TryFrom> for SmtHash { - type Error = Error; - - fn try_from(value: MerkleKey) -> Result { - match value { - MerkleKey::Sha256(key, _) => Ok(H::hash(key.to_string()).into()), - _ => Err(Error::InvalidMerkleKey( - "This key is for a sparse merkle tree".into(), - )), - } - } -} - -impl TryFrom> for StringKey { - type Error = Error; - - fn try_from(value: MerkleKey) -> Result { - match value { - MerkleKey::Raw(key) => { - Self::try_from_bytes(key.to_string().as_bytes()) - } - _ => Err(Error::InvalidMerkleKey( - "This is not an key for the IBC subtree".into(), - )), - } - } -} - /// The root and store pairs to restore the trees #[derive(Default)] pub struct MerkleTreeStoresRead { @@ -614,6 +574,7 @@ pub struct MerkleTreeStoresRead { account: (Hash, SmtStore), ibc: (Hash, AmtStore), pos: (Hash, SmtStore), + bridge_pool: (KeccakHash, BTreeSetStore), } impl MerkleTreeStoresRead { @@ -624,6 +585,7 @@ impl MerkleTreeStoresRead { StoreType::Account => self.account.0 = root, StoreType::Ibc => self.ibc.0 = root, StoreType::PoS => self.pos.0 = root, + StoreType::BridgePool => self.bridge_pool.0 = root.into(), } } @@ -634,6 +596,7 @@ impl MerkleTreeStoresRead { Store::Account(store) => self.account.1 = store, Store::Ibc(store) => self.ibc.1 = store, Store::PoS(store) => self.pos.1 = store, + Store::BridgePool(store) => self.bridge_pool.1 = store, } } } @@ -644,6 +607,7 @@ pub struct MerkleTreeStoresWrite<'a> { account: (Hash, &'a SmtStore), ibc: (Hash, &'a AmtStore), pos: (Hash, &'a SmtStore), + bridge_pool: (Hash, &'a BTreeSetStore) } impl<'a> MerkleTreeStoresWrite<'a> { @@ -654,6 +618,7 @@ impl<'a> MerkleTreeStoresWrite<'a> { StoreType::Account => &self.account.0, StoreType::Ibc => &self.ibc.0, StoreType::PoS => &self.pos.0, + StoreType::BridgePool => &self.bridge_pool.0 } } @@ -664,96 +629,11 @@ impl<'a> MerkleTreeStoresWrite<'a> { StoreType::Account => StoreRef::Account(self.account.1), StoreType::Ibc => StoreRef::Ibc(self.ibc.1), StoreType::PoS => StoreRef::PoS(self.pos.1), + StoreType::BridgePool => StoreRef::BridgePool(self.bridge_pool.1) } } } -impl TreeKey for StringKey { - type Error = Error; - - fn as_slice(&self) -> &[u8] { - &self.original.as_slice()[..self.length] - } - - fn try_from_bytes(bytes: &[u8]) -> Result { - let mut tree_key = [0u8; IBC_KEY_LIMIT]; - let mut original = [0u8; IBC_KEY_LIMIT]; - let mut length = 0; - for (i, byte) in bytes.iter().enumerate() { - if i >= IBC_KEY_LIMIT { - return Err(Error::InvalidMerkleKey( - "Input IBC key is too large".into(), - )); - } - original[i] = *byte; - tree_key[i] = byte.wrapping_add(1); - length += 1; - } - Ok(Self { - original, - tree_key: tree_key.into(), - length, - }) - } -} - -impl Value for TreeBytes { - fn as_slice(&self) -> &[u8] { - self.0.as_slice() - } - - fn zero() -> Self { - TreeBytes::zero() - } -} - -/// The storage hasher used for the merkle tree. -pub trait StorageHasher: Hasher + Default { - /// Hash the value to store - fn hash(value: impl AsRef<[u8]>) -> H256; -} - -/// The storage hasher used for the merkle tree. -#[derive(Default)] -pub struct Sha256Hasher(Sha256); - -impl Hasher for Sha256Hasher { - fn write_bytes(&mut self, h: &[u8]) { - self.0.update(h) - } - - fn finish(self) -> arse_merkle_tree::H256 { - let hash = self.0.finalize(); - let bytes: [u8; 32] = hash - .as_slice() - .try_into() - .expect("Sha256 output conversion to fixed array shouldn't fail"); - bytes.into() - } - - fn hash_op() -> ics23::HashOp { - ics23::HashOp::Sha256 - } -} - -impl StorageHasher for Sha256Hasher { - fn hash(value: impl AsRef<[u8]>) -> H256 { - let mut hasher = Sha256::new(); - hasher.update(value.as_ref()); - let hash = hasher.finalize(); - let bytes: [u8; 32] = hash - .as_slice() - .try_into() - .expect("Sha256 output conversion to fixed array shouldn't fail"); - bytes.into() - } -} - -impl fmt::Debug for Sha256Hasher { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Sha256Hasher") - } -} impl From for Error { fn from(error: StorageError) -> Self { diff --git a/shared/src/ledger/storage/mod.rs b/shared/src/ledger/storage/mod.rs index 1df873edd6..4def551e0f 100644 --- a/shared/src/ledger/storage/mod.rs +++ b/shared/src/ledger/storage/mod.rs @@ -5,6 +5,7 @@ mod merkle_tree; pub mod mockdb; pub mod types; pub mod write_log; +pub mod traits; use core::fmt::Debug; diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs new file mode 100644 index 0000000000..d5411cc966 --- /dev/null +++ b/shared/src/ledger/storage/traits.rs @@ -0,0 +1,214 @@ +//! Traits needed to provide a uniform interface over +//! all the different Merkle trees used for storage +use std::convert::{TryFrom, TryInto}; +use std::fmt; + +use arse_merkle_tree::{H256, Hash as SmtHash, Key as TreeKey}; +use arse_merkle_tree::traits::{Value, Hasher}; +use ibc_proto::ics23::CommitmentProof; +use sha2::{Digest, Sha256}; + +use super::IBC_KEY_LIMIT; +use super::merkle_tree::{Smt, Amt, Error}; +use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; +use crate::types::eth_bridge_pool::PendingTransfer; +use crate::types::hash::Hash; +use crate::types::storage::{ + MerkleKey, StringKey, TreeBytes, MerkleValue, Key +}; + +pub trait MerkleTree { + type Error; + + fn has_key(&self, key: &Key) -> Result; + fn update>(&mut self, key: &Key, value: MerkleValue) -> Result; + fn delete(&mut self, key: &Key) -> Result<(), Self::Error>; + fn membership_proof(&self, keys: &[Key], proof: Option) -> Option; +} + +impl MerkleTree for Smt { + type Error = Error; + + fn has_key(&self, key: &Key) -> Result { + self.get(&H::hash(key.to_string()).into()) + .and(Ok(true)) + .map_error(|err| Error::MerkleTree(err.to_string())) + } + + fn update>(&mut self, key: &Key, value: MerkleValue) -> Result { + let value = match value { + MerkleValue::Bytes(bytes) => Hash::try_from(bytes.as_ref()) + .map_err(|| Error::InvalidValue)?, + _ => return Err(Error::InvalidValue) + }; + self.update( + H::hash(key.to_string()).into(), + value, + ) + .map(Hash::into) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { + let value = Hash::zero(); + self.update( + H::hash(key.to_string()).into(), + value + ) + .and(Ok(())) + .map_err(|err|Error::MerkleTree(err.to_string())) + } +} + +impl MerkleTree for Amt { + type Error = Error; + + fn has_key(&self, key: &Key) -> Result { + let key = + StringKey::try_from_bytes(key.to_string().as_bytes())?; + self.get(&key) + .and(Ok(bool)) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn update>(&mut self, key: MerkleKey, value: MerkleValue) -> Result { + let key = + StringKey::try_from_bytes(key.to_string().as_bytes())?; + let value = match value { + MerkleValue::Bytes(bytes) => TreeBytes::from(bytes.as_ref().to_vec()), + _ => return Err(Error::InvalidValue) + }; + self.update( + key, + value, + ) + .map(Into::into) + .map_err(|err|Error::MerkleTree(err.to_string())) + } + + fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { + let key = + StringKey::try_from_bytes(key.to_string().as_bytes())?; + let value = TreeBytes::zero(); + self.update( + key, + value + ) + .and(Ok(())) + .map_err(|err| Error::MerkleTree(format!("{:?}", err))) + } +} + +impl MerkleTree for BridgePoolTree { + type Error = Error; + + fn has_key(&self, key: &Key) -> Result { + self.has_key(key) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn update>(&mut self, key: &Key, value: MerkleValue) -> Result { + if let MerkleValue::Transfer(transfer) = value { + self.update(key, transfer) + .map_err( | err| Error::MerkleTree(err.to_string())) + } else { + Err(Error::InvalidValue) + } + } + + fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { + self.delete(key) + .map_err(|err| Error::MerkleTree(err.to_string())) + } +} + +impl TreeKey for StringKey { + type Error = Error; + + fn as_slice(&self) -> &[u8] { + &self.original.as_slice()[..self.length] + } + + fn try_from_bytes(bytes: &[u8]) -> Result { + let mut tree_key = [0u8; IBC_KEY_LIMIT]; + let mut original = [0u8; IBC_KEY_LIMIT]; + let mut length = 0; + for (i, byte) in bytes.iter().enumerate() { + if i >= IBC_KEY_LIMIT { + return Err(Error::InvalidMerkleKey( + "Input IBC key is too large".into(), + )); + } + original[i] = *byte; + tree_key[i] = byte.wrapping_add(1); + length += 1; + } + Ok(Self { + original, + tree_key: tree_key.into(), + length, + }) + } +} + +impl Value for TreeBytes { + fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } + + fn zero() -> Self { + TreeBytes::zero() + } +} + +pub trait MembershipProof { }; + +impl MembershipProof for CommitmentProof; + +/// The storage hasher used for the merkle tree. +pub trait StorageHasher: Hasher + Default { + /// Hash the value to store + fn hash(value: impl AsRef<[u8]>) -> H256; +} + +/// The storage hasher used for the merkle tree. +#[derive(Default)] +pub struct Sha256Hasher(Sha256); + +impl Hasher for Sha256Hasher { + fn write_bytes(&mut self, h: &[u8]) { + self.0.update(h) + } + + fn finish(self) -> arse_merkle_tree::H256 { + let hash = self.0.finalize(); + let bytes: [u8; 32] = hash + .as_slice() + .try_into() + .expect("Sha256 output conversion to fixed array shouldn't fail"); + bytes.into() + } + + fn hash_op() -> ics23::HashOp { + ics23::HashOp::Sha256 + } +} + +impl StorageHasher for Sha256Hasher { + fn hash(value: impl AsRef<[u8]>) -> H256 { + let mut hasher = Sha256::new(); + hasher.update(value.as_ref()); + let hash = hasher.finalize(); + let bytes: [u8; 32] = hash + .as_slice() + .try_into() + .expect("Sha256 output conversion to fixed array shouldn't fail"); + bytes.into() + } +} + +impl fmt::Debug for Sha256Hasher { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Sha256Hasher") + } +} \ No newline at end of file diff --git a/shared/src/types/eth_bridge_pool.rs b/shared/src/types/eth_bridge_pool.rs index 18c6e7f1a9..17ba1f57e7 100644 --- a/shared/src/types/eth_bridge_pool.rs +++ b/shared/src/types/eth_bridge_pool.rs @@ -1,9 +1,11 @@ //! The necessary type definitions for the contents of the //! Ethereum bridge pool -use borsh::{BorshDeserialize, BorshSerialize}; +use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use ethabi::token::Token; use crate::types::address::Address; -use crate::types::ethereum_events::{EthAddress, Uint}; +use crate::types::ethereum_events::{EthAddress, Uint, KeccakHash}; +use crate::types::keccak; use crate::types::token::Amount; /// A transfer message to be submitted to Ethereum @@ -17,6 +19,7 @@ use crate::types::token::Amount; Eq, BorshSerialize, BorshDeserialize, + BorshSchema, )] pub struct TransferToEthereum { /// The type of token @@ -40,6 +43,7 @@ pub struct TransferToEthereum { Eq, BorshSerialize, BorshDeserialize, + BorshSchema, )] pub struct PendingTransfer { /// The message to send to Ethereum to @@ -49,6 +53,25 @@ pub struct PendingTransfer { pub gas_fee: GasFee, } +impl keccak::encode::Encode for PendingTransfer { + + fn tokenize(&self) -> Vec { + let from = Token::String(self.gas_fee.payer.to_string()); + let fee = Token::Uint(u64::from(self.gas_fee.amount).into()); + let to = Token::Address(self.transfer.recipient.0.into()); + let amount = Token::Uint(u64::from(self.transfer.amount).into()); + let nonce = Token::Uint(self.transfer.nonce.into()); + vec![ + from, + fee, + to, + amount, + nonce, + ] + } +} + + /// The amount of NAM to be payed to the relayer of /// a transfer across the Ethereum Bridge to compensate /// for Ethereum gas fees. @@ -61,6 +84,7 @@ pub struct PendingTransfer { Eq, BorshSerialize, BorshDeserialize, + BorshSchema, )] pub struct GasFee { /// The amount of fees (in NAM) diff --git a/shared/src/types/hash.rs b/shared/src/types/hash.rs index e8ef5577cb..e4ac6e8c2c 100644 --- a/shared/src/types/hash.rs +++ b/shared/src/types/hash.rs @@ -6,6 +6,7 @@ use std::ops::Deref; use arse_merkle_tree::traits::Value; use arse_merkle_tree::{Hash as TreeHash, H256}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use hex::FromHex; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use thiserror::Error; @@ -23,6 +24,8 @@ pub enum Error { Temporary { error: String }, #[error("Failed trying to convert slice to a hash: {0}")] ConversionFailed(std::array::TryFromSliceError), + #[error("Failed to convert string into a hash: {0}")] + FromStringError(hex::FromHexError) } /// Result for functions that may fail @@ -86,6 +89,24 @@ impl TryFrom<&[u8]> for Hash { } } +impl TryFrom for Hash { + type Error = self::Error; + + fn try_from(string: String) -> HashResult { + let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + Self::try_from(&bytes) + } +} + +impl TryFrom<&str> for Hash { + type Error = self::Error; + + fn try_from(string: &str) -> HashResult { + let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + Self::try_from(&bytes) + } +} + impl From for transaction::Hash { fn from(hash: Hash) -> Self { Self::new(hash.0) @@ -144,4 +165,4 @@ impl Value for Hash { fn zero() -> Self { Hash([0u8; 32]) } -} +} \ No newline at end of file diff --git a/shared/src/types/storage.rs b/shared/src/types/storage.rs index b7e2005bb7..7b7ffad7a2 100644 --- a/shared/src/types/storage.rs +++ b/shared/src/types/storage.rs @@ -11,12 +11,15 @@ use arse_merkle_tree::InternalKey; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use serde::{Deserialize, Serialize}; use thiserror::Error; +use variant_access_derive::*; +use variant_access_traits::*; #[cfg(feature = "ferveo-tpke")] use super::transaction::WrapperTx; use crate::bytes::ByteBuf; use crate::ledger::storage::{StorageHasher, IBC_KEY_LIMIT}; use crate::types::address::{self, Address}; +use crate::types::eth_bridge_pool::{TransferToEthereum, PendingTransfer}; use crate::types::hash::Hash; use crate::types::time::DateTimeUtc; @@ -31,6 +34,8 @@ pub enum Error { ParseAddressFromKey, #[error("Reserved prefix or string is specified: {0}")] InvalidKeySeg(String), + #[error("Could not parse string: '{0}' into requested type: {1}")] + ParseError((String, String)) } /// Result for functions that may fail @@ -233,14 +238,35 @@ impl FromStr for Key { } } -/// A type for converting an Anoma storage key -/// to that of the right type for the different -/// merkle trees used. -pub enum MerkleKey { - /// A key that needs to be hashed - Sha256(Key, PhantomData), - /// A key that can be given as raw bytes - Raw(Key), +/// An enum representing the different types of values +/// that can be passed into Anoma's storage. +/// +/// This is a multi-store organized as +/// several Merkle trees, each of which is +/// responsible for understanding how to parse +/// this value. +pub enum MerkleValue> { + /// raw bytes + Bytes(T), + /// a transfer to be put in the Ethereum bridge pool + /// We actually only need the key (which is the hash + /// of the transfer). So this variant contains no data. + Transfer(PendingTransfer), +} + +impl From for MerkleValue +where + T: AsRef<[u8]> +{ + fn from(bytes: T) -> Self { + Self::Bytes(bytes) + } +} + +impl> From for MerkleValue { + fn from(transfer: PendingTransfer) -> Self { + Self::Transfer(transfer) + } } /// Storage keys that are utf8 encoded strings @@ -581,6 +607,20 @@ impl KeySeg for Address { } } +impl KeySeg for Hash { + fn parse(seg: String) -> Result { + seg.try_into().map_error(Error::ParseError((seg, "Hash".into()))) + } + + fn raw(&self) -> String { + self.to_string() + } + + fn to_db_key(&self) -> DbKeySeg { + DbKeySeg::StringSeg(self.raw()) + } +} + /// Epoch identifier. Epochs are identified by consecutive numbers. #[derive( Clone, @@ -630,6 +670,7 @@ impl Add for Epoch { } } + impl Sub for Epoch { type Output = Epoch; From 2970208625346f42a6e0e92cb96be9cdaa47c3e4 Mon Sep 17 00:00:00 2001 From: R2D2 Date: Mon, 26 Sep 2022 17:51:53 +0200 Subject: [PATCH 05/28] [feat]: Added membership proofs for eth bridge pool --- Cargo.lock | 331 +++--------------- .../ledger/eth_bridge/storage/bridge_pool.rs | 37 +- shared/src/types/keccak.rs | 19 +- 3 files changed, 78 insertions(+), 309 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index adbc38f162..17d28aa12b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1131,28 +1131,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "chrono-tz" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" -dependencies = [ - "chrono", - "chrono-tz-build", - "phf", -] - -[[package]] -name = "chrono-tz-build" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" -dependencies = [ - "parse-zoneinfo", - "phf", - "phf_codegen", -] - [[package]] name = "chunked_transfer" version = "1.4.0" @@ -1729,12 +1707,6 @@ dependencies = [ "syn", ] -[[package]] -name = "deunicode" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" - [[package]] name = "diff" version = "0.1.12" @@ -2534,17 +2506,6 @@ dependencies = [ "regex", ] -[[package]] -name = "globwalk" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" -dependencies = [ - "bitflags", - "ignore", - "walkdir", -] - [[package]] name = "gloo-timers" version = "0.2.4" @@ -2800,12 +2761,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" -[[package]] -name = "humansize" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" - [[package]] name = "hyper" version = "0.10.16" @@ -2913,14 +2868,14 @@ dependencies = [ [[package]] name = "ibc" -version = "0.14.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" +version = "0.12.0" +source = "git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus#99a761657a51f6e5f074f3217426903e53632934" dependencies = [ "bytes 1.1.0", "derive_more", "flex-error", - "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", - "ics23", + "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", + "ics23 0.6.7", "num-traits 0.2.15", "prost 0.9.0", "prost-types 0.9.0", @@ -2940,14 +2895,14 @@ dependencies = [ [[package]] name = "ibc" -version = "0.14.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +version = "0.12.0" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc#30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc" dependencies = [ "bytes 1.1.0", "derive_more", "flex-error", - "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", - "ics23", + "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", + "ics23 0.6.7", "num-traits 0.2.15", "prost 0.9.0", "prost-types 0.9.0", @@ -2967,28 +2922,44 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.17.1" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" +version = "0.16.0" +source = "git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus#99a761657a51f6e5f074f3217426903e53632934" dependencies = [ - "base64 0.13.0", "bytes 1.1.0", "prost 0.9.0", "prost-types 0.9.0", "serde 1.0.137", "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", + "tonic", ] [[package]] name = "ibc-proto" -version = "0.17.1" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +version = "0.16.0" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc#30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc" dependencies = [ - "base64 0.13.0", "bytes 1.1.0", "prost 0.9.0", "prost-types 0.9.0", "serde 1.0.137", "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", + "tonic", +] + +[[package]] +name = "ics23" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce15e4758c46a0453bdf4b3b1dfcce70c43f79d1943c2ee0635b77eb2e7aa233" +dependencies = [ + "anyhow", + "bytes 1.1.0", + "hex", + "prost 0.9.0", + "ripemd160", + "sha2 0.9.9", + "sha3 0.9.1", + "sp-std", ] [[package]] @@ -3072,24 +3043,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "ignore" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" -dependencies = [ - "crossbeam-utils 0.8.8", - "globset", - "lazy_static 1.4.0", - "log 0.4.17", - "memchr", - "regex", - "same-file", - "thread_local 1.1.4", - "walkdir", - "winapi-util", -] - [[package]] name = "impl-codec" version = "0.6.0" @@ -4016,12 +3969,6 @@ dependencies = [ "serde_yaml", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "match_cfg" version = "0.1.0" @@ -4356,11 +4303,11 @@ dependencies = [ "ferveo-common", "group-threshold-cryptography", "hex", - "ibc 0.14.0 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", - "ibc 0.14.0 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", - "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", - "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", - "ics23", + "ibc 0.12.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", + "ibc 0.12.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", + "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", + "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", + "ics23 0.6.7", "itertools 0.10.3", "libsecp256k1 0.7.0", "loupe", @@ -4390,8 +4337,6 @@ dependencies = [ "tonic-build", "tracing 0.1.35", "tracing-subscriber 0.3.11", - "variant_access_derive", - "variant_access_traits", "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", @@ -4461,7 +4406,6 @@ dependencies = [ "rlimit", "rocksdb", "rpassword", - "semver 1.0.14", "serde 1.0.137", "serde_bytes", "serde_json", @@ -5146,15 +5090,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "parse-zoneinfo" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" -dependencies = [ - "regex", -] - [[package]] name = "paste" version = "1.0.7" @@ -5221,40 +5156,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "pest_derive" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" -dependencies = [ - "maplit", - "pest", - "sha-1 0.8.2", -] - [[package]] name = "petgraph" version = "0.5.1" @@ -5275,45 +5176,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "phf" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" -dependencies = [ - "phf_shared", - "rand 0.8.5", -] - -[[package]] -name = "phf_shared" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" -dependencies = [ - "siphasher", - "uncased", -] - [[package]] name = "pin-project" version = "0.4.29" @@ -6241,7 +6103,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.14", + "semver 1.0.10", ] [[package]] @@ -6474,9 +6336,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.14" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" [[package]] name = "semver-parser" @@ -6764,27 +6626,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" -[[package]] -name = "siphasher" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" - [[package]] name = "slab" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" -[[package]] -name = "slug" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" -dependencies = [ - "deunicode", -] - [[package]] name = "smallvec" version = "0.6.14" @@ -6869,7 +6716,7 @@ dependencies = [ "blake2b-rs", "borsh", "cfg-if 1.0.0", - "ics23", + "ics23 0.7.0", "sha2 0.9.9", ] @@ -7290,28 +7137,6 @@ dependencies = [ "time 0.3.9", ] -[[package]] -name = "tera" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d" -dependencies = [ - "chrono", - "chrono-tz", - "globwalk", - "humansize", - "lazy_static 1.4.0", - "percent-encoding 2.1.0", - "pest", - "pest_derive", - "rand 0.8.5", - "regex", - "serde 1.0.137", - "serde_json", - "slug", - "unic-segment", -] - [[package]] name = "term_size" version = "0.3.2" @@ -8136,65 +7961,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "uncased" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" -dependencies = [ - "version_check 0.9.4", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" -dependencies = [ - "unic-ucd-segment", -] - -[[package]] -name = "unic-ucd-segment" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - [[package]] name = "unicase" version = "1.4.2" @@ -8355,25 +8121,6 @@ dependencies = [ "version_check 0.9.4", ] -[[package]] -name = "variant_access_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd235ffafb854ed81b49217ce411e850a39628a5d26740ecfb60421c873d834" -dependencies = [ - "lazy_static 1.4.0", - "quote", - "syn", - "tera", - "variant_access_traits", -] - -[[package]] -name = "variant_access_traits" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d75c5a83bb8912dd9c628adf954c9f9bff74a4e170d2c90242f4e56a0d643e" - [[package]] name = "vcpkg" version = "0.2.15" diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index 8588ae0550..e15de60cb2 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -9,7 +9,8 @@ use eyre::eyre; use crate::types::address::{Address, InternalAddress}; use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; -use crate::types::ethereum_events::KeccakHash; +use crate::types::keccak::{keccak_hash, KeccakHash}; +use crate::types::keccak::encode::Encode; use crate::types::hash::{Hash, keccak_hash}; use crate::types::storage::{DbKeySeg, Key}; use crate::ledger::storage::{Sha256Hasher, StorageHasher}; @@ -66,10 +67,9 @@ pub struct BridgePoolTree { /// Root of the tree root: KeccakHash, /// The underlying storage - store: BTreeMap + store: BTreeMap, } -/// TODO: Hash ABI instead of Borsh impl BridgePoolTree { /// Create a new merkle tree for the Ethereum bridge pool pub fn new(root: KeccakHash, store: BTreeMap) -> Self { @@ -90,7 +90,7 @@ impl BridgePoolTree { /// return an error if the key is malformed. pub fn update(&mut self, key: &Key, value: PendingTransfer) -> Result { let hash = Self::parse_key(key)?; - if hash != keccak_hash(&value.try_to_vec().unwrap()) { + if hash != value.keccak256() { return eyre!("Key does not match hash of the value")?; } _ = self.store.insert(hash, value); @@ -131,9 +131,28 @@ impl BridgePoolTree { &self.store } + /// Create a batched membership proof for the provided keys pub fn membership_proof(&self, keys: &[Key]) -> BridgePoolProof { - for (key, value) in self.store { - + let mut leaves : std::collections::BTreeSet = Default::default(); + for key in keys { + leaves.insert(Self::parse_key(key)?); + } + let mut proof_leaves = vec![]; + let mut proof_hashes = vec![]; + let mut flags = vec![]; + for (hash, value) in self.store { + if leaves.contains(&hash) { + flags.push(true); + proof_leaves.push(value); + } else { + flags.push(false); + proof_hashes.push(hash); + } + } + BridgePoolProof { + proof: proof_hashes, + leaves: proof_leaves, + flags } } @@ -180,8 +199,7 @@ impl BridgePoolProof { let mut proof_pos = 0usize; let mut computed; if self.flags[0] { - leaf = self.leaves[leaf_pos].clone(); - computed = keccak_hash(leaf.try_to_vec().unwrap()); + computed = self.leaves[leaf_pos].keccak256(); leaf_pos += 1; } else { computed = self.proof[proof_pos].clone(); @@ -190,8 +208,7 @@ impl BridgePoolProof { for flag in 1..self.flages.len() { let mut next_hash; if self.flags[flag] { - leaf = self.leaves[leaf_pos].clone(); - next_hash = keccak_hash(leaf.try_to_vec().unwrap()); + next_hash = self.leaves[leaf_pos].keccak256(); leaf_pos += 1; } else { next_hash = self.proof[proof_pos].clone(); diff --git a/shared/src/types/keccak.rs b/shared/src/types/keccak.rs index 8d43ecf9c6..06beb3adf1 100644 --- a/shared/src/types/keccak.rs +++ b/shared/src/types/keccak.rs @@ -87,6 +87,17 @@ impl TryFrom<&str> for KeccakHash { } } +/// Hash bytes using Keccak +pub fn keccak_hash(bytes: &[u8]) -> KeccakHash { + let mut output = [0; 32]; + + let mut hasher = Keccak::v256(); + hasher.update(bytes); + hasher.finalize(&mut output); + + KeccakHash(output) +} + /// This module defines encoding methods compatible with Ethereum /// smart contracts. pub mod encode { @@ -111,13 +122,7 @@ pub mod encode { /// Encodes a slice of [`Token`] instances, and returns the /// keccak hash of the encoded string. fn keccak256(&self) -> KeccakHash { - let mut output = [0; 32]; - - let mut state = Keccak::v256(); - state.update(self.encode().as_slice()); - state.finalize(&mut output); - - KeccakHash(output) + keccak_hash(self.encode().as_slice()) } /// Encodes a slice of [`Token`] instances, and returns the From 9700e1a1873a29a3c81e8cece7c96aa7a0b06ef4 Mon Sep 17 00:00:00 2001 From: R2D2 Date: Thu, 29 Sep 2022 10:20:30 +0200 Subject: [PATCH 06/28] feat: finished base implementation, need to debug --- .../src/ledger/eth_bridge/bridge_pool_vp.rs | 3 +- .../ledger/eth_bridge/storage/bridge_pool.rs | 78 +++--- shared/src/ledger/eth_bridge/vp/mod.rs | 2 +- shared/src/ledger/storage/merkle_tree.rs | 228 ++++++------------ shared/src/ledger/storage/mod.rs | 3 +- shared/src/ledger/storage/traits.rs | 180 ++++++++++---- shared/src/types/eth_bridge_pool.rs | 14 +- shared/src/types/hash.rs | 10 +- shared/src/types/storage.rs | 38 ++- 9 files changed, 290 insertions(+), 266 deletions(-) diff --git a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs index b05b4db7be..12fa7982eb 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs @@ -18,7 +18,8 @@ use crate::ledger::eth_bridge::storage::bridge_pool::{ get_pending_key, is_protected_storage, BRIDGE_POOL_ADDRESS, }; use crate::ledger::native_vp::{Ctx, NativeVp, StorageReader}; -use crate::ledger::storage::{DBIter, StorageHasher, DB}; +use crate::ledger::storage::{DBIter, DB}; +use crate::ledger::storage::traits::StorageHasher; use crate::proto::SignedTxData; use crate::types::address::{xan, Address, InternalAddress}; use crate::types::eth_bridge_pool::PendingTransfer; diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index e15de60cb2..48266bde17 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -1,19 +1,19 @@ //! Tools for accessing the storage subspaces of the Ethereum //! bridge pool -use std::collections::BTreeMap; +use std::collections::BTreeSet; use std::convert::TryInto; use std::ops::Deref; -use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use eyre::eyre; +use crate::ledger::storage::traits::{Sha256Hasher, StorageHasher}; use crate::types::address::{Address, InternalAddress}; use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; -use crate::types::keccak::{keccak_hash, KeccakHash}; +use crate::types::hash::Hash; use crate::types::keccak::encode::Encode; -use crate::types::hash::{Hash, keccak_hash}; +use crate::types::keccak::{keccak_hash, KeccakHash}; use crate::types::storage::{DbKeySeg, Key}; -use crate::ledger::storage::{Sha256Hasher, StorageHasher}; /// The main address of the Ethereum bridge pool pub const BRIDGE_POOL_ADDRESS: Address = @@ -67,13 +67,13 @@ pub struct BridgePoolTree { /// Root of the tree root: KeccakHash, /// The underlying storage - store: BTreeMap, + store: BTreeSet, } impl BridgePoolTree { /// Create a new merkle tree for the Ethereum bridge pool - pub fn new(root: KeccakHash, store: BTreeMap) -> Self { - Self{ root, store } + pub fn new(root: KeccakHash, store: BTreeSet) -> Self { + Self { root, store } } /// Parse the key to ensure it is of the correct type. @@ -81,25 +81,22 @@ impl BridgePoolTree { /// If it is, it can be converted to a hash. /// Checks if the hash is in the tree. pub fn has_key(&self, key: &Key) -> Result { - Ok(self.store.contains_key(&Self::parse_key(key)?)) + Ok(self.store.contains(&Self::parse_key(key)?)) } /// Update the tree with a new value. /// /// Returns the new root if successful. Will /// return an error if the key is malformed. - pub fn update(&mut self, key: &Key, value: PendingTransfer) -> Result { + pub fn update(&mut self, key: &Key) -> Result { let hash = Self::parse_key(key)?; - if hash != value.keccak256() { - return eyre!("Key does not match hash of the value")?; - } - _ = self.store.insert(hash, value); + _ = self.store.insert(hash); self.root = self.compute_root(); Ok(self.root()) } /// Delete a key from storage and update the root - pub fn delete(&mut self, key: &Key) -> Result<(), Error>{ + pub fn delete(&mut self, key: &Key) -> Result<(), Error> { let hash = Self::parse_key(key)?; _ = self.store.remove(&hash); self.root = self.compute_root(); @@ -109,13 +106,12 @@ impl BridgePoolTree { /// Compute the root of the merkle tree pub fn compute_root(&self) -> KeccakHash { let mut leaves = self.store.iter(); - let mut root = if let Some((hash, _)) = leaves.next() { + let mut root = if let Some(hash) = leaves.next() { hash.clone() } else { return Default::default(); }; - - for (leaf, _) in leaves { + for leaf in leaves { root = keccak_hash([root.0, leaf.0].concat()); } root @@ -127,33 +123,43 @@ impl BridgePoolTree { } /// Get a reference to the backing store - pub fn store(&self) -> &BTreeMap { + pub fn store(&self) -> &BTreeSet { &self.store } /// Create a batched membership proof for the provided keys - pub fn membership_proof(&self, keys: &[Key]) -> BridgePoolProof { - let mut leaves : std::collections::BTreeSet = Default::default(); + pub fn membership_proof( + &self, + keys: &[Key], + mut values: Vec, + ) -> Result { + if values.len() != keys.len() { + return eyre!( + "The number of leaves and leaf hashes must be equal." + )?; + } + values.sort(); + let mut leaves: std::collections::BTreeSet = + Default::default(); for key in keys { leaves.insert(Self::parse_key(key)?); } - let mut proof_leaves = vec![]; + let mut proof_hashes = vec![]; let mut flags = vec![]; - for (hash, value) in self.store { + for hash in self.store { if leaves.contains(&hash) { flags.push(true); - proof_leaves.push(value); } else { flags.push(false); proof_hashes.push(hash); } } - BridgePoolProof { + Ok(BridgePoolProof { proof: proof_hashes, - leaves: proof_leaves, - flags - } + leaves: values, + flags, + }) } /// Parse a db key to see if it is valid for the @@ -164,13 +170,18 @@ impl BridgePoolTree { fn parse_key(key: &Key) -> Result { if key.segments.len() == 1 { match &key.segments[0] { - DbKeySeg::StringSeg(str) => str.as_str().try_into().ok_or( - eyre!("Could not parse key segment as a hash")? - ), - _ => eyre!("Bridge pool keys should be strings, not addresses")? + DbKeySeg::StringSeg(str) => str + .as_str() + .try_into() + .ok_or(eyre!("Could not parse key segment as a hash")?), + _ => { + eyre!("Bridge pool keys should be strings, not addresses")? + } } } else { - eyre!("Key for the bridge pool should not have more than one segment")? + eyre!( + "Key for the bridge pool should not have more than one segment" + )? } } } @@ -186,7 +197,6 @@ pub struct BridgePoolProof { } impl BridgePoolProof { - /// Verify a membership proof matches the provided root pub fn verify(&self, root: KeccakHash) -> bool { if self.proof.len() + self.leaves.len() != self.flags.len() { diff --git a/shared/src/ledger/eth_bridge/vp/mod.rs b/shared/src/ledger/eth_bridge/vp/mod.rs index cdcd1815ea..0e62f7270f 100644 --- a/shared/src/ledger/eth_bridge/vp/mod.rs +++ b/shared/src/ledger/eth_bridge/vp/mod.rs @@ -10,7 +10,7 @@ use itertools::Itertools; use crate::ledger::eth_bridge::storage::{self, wrapped_erc20s}; use crate::ledger::native_vp::{Ctx, NativeVp, StorageReader}; use crate::ledger::storage as ledger_storage; -use crate::ledger::storage::StorageHasher; +use crate::ledger::storage::traits::StorageHasher; use crate::types::address::{Address, InternalAddress}; use crate::types::storage::Key; use crate::types::token::Amount; diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index b2598aa210..58b05faa2f 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -2,6 +2,7 @@ use std::convert::{TryFrom, TryInto}; use std::fmt; use std::marker::PhantomData; +use std::slice::from_ref; use std::str::FromStr; use arse_merkle_tree::default_store::DefaultStore; @@ -19,19 +20,22 @@ use ics23::{ use itertools::{Either, Itertools}; use prost::Message; use sha2::{Digest, Sha256}; +use tendermint::merkle::proof::{Proof, ProofOp}; use thiserror::Error; +use super::traits::{self, Sha256Hasher, StorageHasher}; use super::IBC_KEY_LIMIT; -use super::traits::{self, StorageHasher, Sha256Hasher}; use crate::bytes::ByteBuf; use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; -use crate::ledger::storage::types; -use crate::tendermint::merkle::proof::{Proof, ProofOp}; +use crate::ledger::storage::{ics23_specs, types}; use crate::types::address::{Address, InternalAddress}; use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; use crate::types::ethereum_events::KeccakHash; use crate::types::hash::Hash; -use crate::types::storage::{DbKeySeg, Error as StorageError, Key, StringKey, TreeBytes, MerkleValue}; +use crate::types::storage::{ + DbKeySeg, Error as StorageError, Key, MembershipProof, MerkleValue, + StringKey, TreeBytes, +}; #[allow(missing_docs)] #[derive(Error, Debug)] @@ -50,6 +54,10 @@ pub enum Error { NonExistenceProof(String), #[error("Invalid value given to sub-tree storage")] InvalidValue, + #[error("ICS23 commitment proofs do not support multiple leaves")] + Ics23MultiLeaf, + #[error("A Tendermint proof can only be constructed from an ICS23 proof.")] + TendermintProof, } /// Result for functions that may fail @@ -58,7 +66,7 @@ type Result = std::result::Result; /// Type aliases for the different merkle trees and backing stores pub type SmtStore = DefaultStore; pub type AmtStore = DefaultStore; -pub type BridgePoolStore = std::collections::BTreeMap; +pub type BridgePoolStore = std::collections::BTreeSet; pub type Smt = ArseMerkleTree; pub type Amt = ArseMerkleTree; @@ -99,7 +107,7 @@ pub enum Store { /// For PoS-related data PoS(SmtStore), /// For the Ethereum bridge Pool transfers - BridgePool(BTreeSetStore) + BridgePool(BTreeSetStore), } impl Store { @@ -125,7 +133,7 @@ pub enum StoreRef<'a> { /// For PoS-related data PoS(&'a SmtStore), /// For the Ethereum bridge Pool transfers - BridgePool(&'a BTreeSetStore) + BridgePool(&'a BTreeSetStore), } impl<'a> StoreRef<'a> { @@ -268,7 +276,8 @@ impl MerkleTree { let account = Smt::new(stores.account.0.into(), stores.account.1); let ibc = Amt::new(stores.ibc.0.into(), stores.ibc.1); let pos = Smt::new(stores.pos.0.into(), stores.pos.1); - let bridge_pool = BridgePoolTree::new(stores.bridge_pool.0, stores.bridge_pool.1); + let bridge_pool = + BridgePoolTree::new(stores.bridge_pool.0, stores.bridge_pool.1); Self { base, account, @@ -288,7 +297,10 @@ impl MerkleTree { } } - fn tree_mut(&mut self, store_type: &StoreType) -> &mut impl traits::MerkleTree { + fn tree_mut( + &mut self, + store_type: &StoreType, + ) -> &mut impl traits::MerkleTree { match store_type { StoreType::Base => &mut self.base, StoreType::Account => &mut self.account, @@ -320,7 +332,11 @@ impl MerkleTree { } /// Update the tree with the given key and value - pub fn update>(&mut self, key: &Key, value: impl Into>) -> Result<()> { + pub fn update>( + &mut self, + key: &Key, + value: impl Into>, + ) -> Result<()> { let (store_type, sub_key) = StoreType::sub_key(key)?; self.update_tree(&store_type, sub_key.into(), value.into()) } @@ -343,94 +359,70 @@ impl MerkleTree { account: (self.account.root().into(), self.account.store()), ibc: (self.ibc.root().into(), self.ibc.store()), pos: (self.pos.root().into(), self.pos.store()), - bridge_pool: (self.bridge_pool.root(). self.) + bridge_pool: (self.bridge_pool.root(), self.bridge_pool.store()), } } - /// Get the existence proof - pub fn get_existence_proof( + /// Get the existence proof from a sub-tree + pub fn get_sub_tree_existence_proof>( &self, - key: &Key, - value: Vec, - ) -> Result { - let (store_type, sub_key) = StoreType::sub_key(key)?; - let sub_proof = match self.tree(&store_type) { - Either::Left(smt) => { - let cp = smt - .membership_proof(&H::hash(&sub_key.to_string()).into())?; - // Replace the values and the leaf op for the verification - match cp.proof.expect("The proof should exist") { - Ics23Proof::Exist(ep) => CommitmentProof { - proof: Some(Ics23Proof::Exist(ExistenceProof { - key: sub_key.to_string().as_bytes().to_vec(), - value, - leaf: Some(self.leaf_spec()), - ..ep - })), - }, - // the proof should have an ExistenceProof - _ => unreachable!(), - } + keys: &[Key], + values: Vec>, + ) -> Result { + let first_key = keys.iter().next().ok_or(Error::InvalidMerkleKey( + "No keys provided for existence proof.".into(), + ))?; + let (store_type, _) = StoreType::sub_key(first_key)?; + if !keys.iter().all(|k| { + if let Ok((s, _)) = StoreType::sub_key(k) { + s == store_type + } else { + false } - Either::Right(amt) => { - let key = - StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; - let cp = amt.membership_proof(&key)?; - - // Replace the values and the leaf op for the verification - match cp.proof.expect("The proof should exist") { - Ics23Proof::Exist(ep) => CommitmentProof { - proof: Some(Ics23Proof::Exist(ExistenceProof { - leaf: Some(self.ibc_leaf_spec()), - ..ep - })), - }, - _ => unreachable!(), - } - } - }; - self.get_proof(key, sub_proof) + }) { + return Err(Error::InvalidMerkleKey( + "Cannot construct inclusion proof for keys in separate \ + sub-trees." + .into(), + )); + } + self.tree(&store_type).membership_proof(keys, values) } /// Get the non-existence proof pub fn get_non_existence_proof(&self, key: &Key) -> Result { let (store_type, sub_key) = StoreType::sub_key(key)?; - let sub_proof = match self.tree(&store_type) { - Either::Left(_) => { - return Err(Error::NonExistenceProof(store_type.to_string())); - } - Either::Right(amt) => { - let key = - StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; - let mut nep = amt.non_membership_proof(&key)?; - // Replace the values and the leaf op for the verification - if let Some(ref mut nep) = nep.proof { - match nep { - Ics23Proof::Nonexist(ref mut ep) => { - let NonExistenceProof { - ref mut left, - ref mut right, - .. - } = ep; - let ep = left.as_mut().or(right.as_mut()).expect( - "A left or right existence proof should exist.", - ); - ep.leaf = Some(self.ibc_leaf_spec()); - } - _ => unreachable!(), - } + if store_type != StoreType::Ibc { + return Err(Error::NonExistenceProof(store_type.to_string())); + } + + let key = StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; + let mut nep = self.ibc.non_membership_proof(&key)?; + // Replace the values and the leaf op for the verification + if let Some(ref mut nep) = nep.proof { + match nep { + Ics23Proof::Nonexist(ref mut ep) => { + let NonExistenceProof { + ref mut left, + ref mut right, + .. + } = ep; + let ep = left.as_mut().or(right.as_mut()).expect( + "A left or right existence proof should exist.", + ); + ep.leaf = Some(self.ibc_leaf_spec()); } - nep + _ => unreachable!(), } - }; + } + // Get a proof of the sub tree self.get_proof(key, sub_proof) } /// Get the Tendermint proof with the base proof - fn get_proof( + pub fn get_tendermint_proof>( &self, - key: &Key, sub_proof: CommitmentProof, ) -> Result { let mut data = vec![]; @@ -453,7 +445,7 @@ impl MerkleTree { Ics23Proof::Exist(ep) => CommitmentProof { proof: Some(Ics23Proof::Exist(ExistenceProof { key: base_key.as_bytes().to_vec(), - leaf: Some(self.base_leaf_spec()), + leaf: Some(ics23_specs::base_leaf_spec::()), ..ep })), }, @@ -476,73 +468,6 @@ impl MerkleTree { ops: vec![sub_proof_op, base_proof_op], }) } - - /// Get the proof specs - pub fn proof_specs(&self) -> Vec { - let spec = arse_merkle_tree::proof_ics23::get_spec(H::hash_op()); - let sub_tree_spec = ProofSpec { - leaf_spec: Some(self.leaf_spec()), - ..spec.clone() - }; - let base_tree_spec = ProofSpec { - leaf_spec: Some(self.base_leaf_spec()), - ..spec - }; - vec![sub_tree_spec, base_tree_spec] - } - - /// Get the proof specs for ibc - pub fn ibc_proof_specs(&self) -> Vec { - let spec = arse_merkle_tree::proof_ics23::get_spec(H::hash_op()); - let sub_tree_spec = ProofSpec { - leaf_spec: Some(self.ibc_leaf_spec()), - ..spec.clone() - }; - let base_tree_spec = ProofSpec { - leaf_spec: Some(self.base_leaf_spec()), - ..spec - }; - vec![sub_tree_spec, base_tree_spec] - } - - /// Get the leaf spec for the base tree. The key is stored after hashing, - /// but the stored value is the subtree's root without hashing. - fn base_leaf_spec(&self) -> LeafOp { - LeafOp { - hash: H::hash_op().into(), - prehash_key: H::hash_op().into(), - prehash_value: HashOp::NoHash.into(), - length: LengthOp::NoPrefix.into(), - prefix: H256::zero().as_slice().to_vec(), - } - } - - /// Get the leaf spec for the subtree. Non-hashed values are used for the - /// verification with this spec because a subtree stores the key-value pairs - /// after hashing. - fn leaf_spec(&self) -> LeafOp { - LeafOp { - hash: H::hash_op().into(), - prehash_key: H::hash_op().into(), - prehash_value: H::hash_op().into(), - length: LengthOp::NoPrefix.into(), - prefix: H256::zero().as_slice().to_vec(), - } - } - - /// Get the leaf spec for the ibc subtree. Non-hashed values are used for - /// the verification with this spec because a subtree stores the - /// key-value pairs after hashing. However, keys are also not hashed in - /// the backing store. - fn ibc_leaf_spec(&self) -> LeafOp { - LeafOp { - hash: H::hash_op().into(), - prehash_key: HashOp::NoHash.into(), - prehash_value: HashOp::NoHash.into(), - length: LengthOp::NoPrefix.into(), - prefix: H256::zero().as_slice().to_vec(), - } - } } /// The root hash of the merkle tree as bytes @@ -607,7 +532,7 @@ pub struct MerkleTreeStoresWrite<'a> { account: (Hash, &'a SmtStore), ibc: (Hash, &'a AmtStore), pos: (Hash, &'a SmtStore), - bridge_pool: (Hash, &'a BTreeSetStore) + bridge_pool: (Hash, &'a BTreeSetStore), } impl<'a> MerkleTreeStoresWrite<'a> { @@ -618,7 +543,7 @@ impl<'a> MerkleTreeStoresWrite<'a> { StoreType::Account => &self.account.0, StoreType::Ibc => &self.ibc.0, StoreType::PoS => &self.pos.0, - StoreType::BridgePool => &self.bridge_pool.0 + StoreType::BridgePool => &self.bridge_pool.0, } } @@ -629,12 +554,11 @@ impl<'a> MerkleTreeStoresWrite<'a> { StoreType::Account => StoreRef::Account(self.account.1), StoreType::Ibc => StoreRef::Ibc(self.ibc.1), StoreType::PoS => StoreRef::PoS(self.pos.1), - StoreType::BridgePool => StoreRef::BridgePool(self.bridge_pool.1) + StoreType::BridgePool => StoreRef::BridgePool(self.bridge_pool.1), } } } - impl From for Error { fn from(error: StorageError) -> Self { Error::InvalidKey(error) diff --git a/shared/src/ledger/storage/mod.rs b/shared/src/ledger/storage/mod.rs index 4def551e0f..74826fba3c 100644 --- a/shared/src/ledger/storage/mod.rs +++ b/shared/src/ledger/storage/mod.rs @@ -1,11 +1,12 @@ //! Ledger's state storage with key-value backed store and a merkle tree +mod ics23_specs; mod merkle_tree; #[cfg(any(test, feature = "testing"))] pub mod mockdb; +pub mod traits; pub mod types; pub mod write_log; -pub mod traits; use core::fmt::Debug; diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs index d5411cc966..c558c7cbe9 100644 --- a/shared/src/ledger/storage/traits.rs +++ b/shared/src/ledger/storage/traits.rs @@ -3,27 +3,36 @@ use std::convert::{TryFrom, TryInto}; use std::fmt; -use arse_merkle_tree::{H256, Hash as SmtHash, Key as TreeKey}; -use arse_merkle_tree::traits::{Value, Hasher}; -use ibc_proto::ics23::CommitmentProof; +use arse_merkle_tree::traits::{Hasher, Value}; +use arse_merkle_tree::{Hash as SmtHash, Key as TreeKey, H256}; +use ics23::commitment_proof::Proof as Ics23Proof; +use ics23::{CommitmentProof, ExistenceProof}; use sha2::{Digest, Sha256}; -use super::IBC_KEY_LIMIT; -use super::merkle_tree::{Smt, Amt, Error}; +use super::merkle_tree::{Amt, Error, Smt}; +use super::{ics23_specs, IBC_KEY_LIMIT}; use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; use crate::types::eth_bridge_pool::PendingTransfer; use crate::types::hash::Hash; use crate::types::storage::{ - MerkleKey, StringKey, TreeBytes, MerkleValue, Key + Key, MembershipProof, MerkleValue, StringKey, TreeBytes, }; pub trait MerkleTree { type Error; fn has_key(&self, key: &Key) -> Result; - fn update>(&mut self, key: &Key, value: MerkleValue) -> Result; + fn update>( + &mut self, + key: &Key, + value: MerkleValue, + ) -> Result; fn delete(&mut self, key: &Key) -> Result<(), Self::Error>; - fn membership_proof(&self, keys: &[Key], proof: Option) -> Option; + fn membership_proof>( + &self, + keys: &[Key], + values: Vec>, + ) -> Result; } impl MerkleTree for Smt { @@ -35,28 +44,56 @@ impl MerkleTree for Smt { .map_error(|err| Error::MerkleTree(err.to_string())) } - fn update>(&mut self, key: &Key, value: MerkleValue) -> Result { + fn update>( + &mut self, + key: &Key, + value: MerkleValue, + ) -> Result { let value = match value { MerkleValue::Bytes(bytes) => Hash::try_from(bytes.as_ref()) .map_err(|| Error::InvalidValue)?, - _ => return Err(Error::InvalidValue) + _ => return Err(Error::InvalidValue), }; - self.update( - H::hash(key.to_string()).into(), - value, - ) - .map(Hash::into) - .map_err(|err| Error::MerkleTree(err.to_string())) + self.update(H::hash(key.to_string()).into(), value) + .map(Hash::into) + .map_err(|err| Error::MerkleTree(err.to_string())) } fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { let value = Hash::zero(); - self.update( - H::hash(key.to_string()).into(), - value - ) - .and(Ok(())) - .map_err(|err|Error::MerkleTree(err.to_string())) + self.update(H::hash(key.to_string()).into(), value) + .and(Ok(())) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn membership_proof>( + &self, + keys: &[Key], + mut values: Vec>, + ) -> Result { + if keys.len() != 1 || values.len() != 1 { + return Err(Error::Ics23MultiLeaf); + } + let key: &Key = &keys[0]; + let value = match values.remove(0) { + MerkleValue::Bytes(b) => b.as_ref().to_vec(), + _ => return Err(Error::InvalidValue), + }; + let cp = self.membership_proof(&H::hash(key.to_string()).into())?; + // Replace the values and the leaf op for the verification + match cp.proof.expect("The proof should exist") { + Ics23Proof::Exist(ep) => Ok(CommitmentProof { + proof: Some(Ics23Proof::Exist(ExistenceProof { + key: key.to_string().as_bytes().to_vec(), + value, + leaf: Some(ics23_specs::leaf_spec::()), + ..ep + })), + } + .into()), + // the proof should have an ExistenceProof + _ => unreachable!(), + } } } @@ -64,38 +101,60 @@ impl MerkleTree for Amt { type Error = Error; fn has_key(&self, key: &Key) -> Result { - let key = - StringKey::try_from_bytes(key.to_string().as_bytes())?; + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; self.get(&key) .and(Ok(bool)) .map_err(|err| Error::MerkleTree(err.to_string())) } - fn update>(&mut self, key: MerkleKey, value: MerkleValue) -> Result { - let key = - StringKey::try_from_bytes(key.to_string().as_bytes())?; + fn update>( + &mut self, + key: MerkleKey, + value: MerkleValue, + ) -> Result { + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; let value = match value { - MerkleValue::Bytes(bytes) => TreeBytes::from(bytes.as_ref().to_vec()), - _ => return Err(Error::InvalidValue) + MerkleValue::Bytes(bytes) => { + TreeBytes::from(bytes.as_ref().to_vec()) + } + _ => return Err(Error::InvalidValue), }; - self.update( - key, - value, - ) - .map(Into::into) - .map_err(|err|Error::MerkleTree(err.to_string())) + self.update(key, value) + .map(Into::into) + .map_err(|err| Error::MerkleTree(err.to_string())) } fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { - let key = - StringKey::try_from_bytes(key.to_string().as_bytes())?; + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; let value = TreeBytes::zero(); - self.update( - key, - value - ) - .and(Ok(())) - .map_err(|err| Error::MerkleTree(format!("{:?}", err))) + self.update(key, value) + .and(Ok(())) + .map_err(|err| Error::MerkleTree(format!("{:?}", err))) + } + + fn membership_proof>( + &self, + keys: &[Key], + _: Vec>, + ) -> Result { + if keys.len() != 1 || values.len() != 1 { + return Err(Error::Ics23MultiLeaf); + } + + let key = StringKey::try_from_bytes(&keys[0].to_string().as_bytes())?; + let cp = self.membership_proof(&key)?; + // Replace the values and the leaf op for the verification + match cp.proof.expect("The proof should exist") { + Ics23Proof::Exist(ep) => Ok(CommitmentProof { + proof: Some(Ics23Proof::Exist(ExistenceProof { + leaf: Some(ics23_specs::ibc_leaf_spec::()), + ..ep + })), + } + .into()), + // the proof should have an ExistenceProof + _ => unreachable!(), + } } } @@ -107,10 +166,14 @@ impl MerkleTree for BridgePoolTree { .map_err(|err| Error::MerkleTree(err.to_string())) } - fn update>(&mut self, key: &Key, value: MerkleValue) -> Result { - if let MerkleValue::Transfer(transfer) = value { - self.update(key, transfer) - .map_err( | err| Error::MerkleTree(err.to_string())) + fn update>( + &mut self, + key: &Key, + value: MerkleValue, + ) -> Result { + if let MerkleValue::Transfer(_) = value { + self.update(key) + .map_err(|err| Error::MerkleTree(err.to_string())) } else { Err(Error::InvalidValue) } @@ -120,6 +183,23 @@ impl MerkleTree for BridgePoolTree { self.delete(key) .map_err(|err| Error::MerkleTree(err.to_string())) } + + fn membership_proof>( + &self, + keys: &[Key], + values: Vec>, + ) -> Result { + let values = values + .into_iter() + .filter_map(|val| match val { + MerkleValue::Transfer(transfer) => Some(transfer), + _ => None, + }) + .collect(); + self.membership_proof(keys, values) + .map(Into::into) + .map_err(|err| Error::MerkleTree(err.to_string())) + } } impl TreeKey for StringKey { @@ -161,10 +241,6 @@ impl Value for TreeBytes { } } -pub trait MembershipProof { }; - -impl MembershipProof for CommitmentProof; - /// The storage hasher used for the merkle tree. pub trait StorageHasher: Hasher + Default { /// Hash the value to store @@ -211,4 +287,4 @@ impl fmt::Debug for Sha256Hasher { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "Sha256Hasher") } -} \ No newline at end of file +} diff --git a/shared/src/types/eth_bridge_pool.rs b/shared/src/types/eth_bridge_pool.rs index 17ba1f57e7..19c0f805cd 100644 --- a/shared/src/types/eth_bridge_pool.rs +++ b/shared/src/types/eth_bridge_pool.rs @@ -1,10 +1,10 @@ //! The necessary type definitions for the contents of the //! Ethereum bridge pool -use borsh::{BorshDeserialize, BorshSerialize, BorshSchema}; +use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use ethabi::token::Token; use crate::types::address::Address; -use crate::types::ethereum_events::{EthAddress, Uint, KeccakHash}; +use crate::types::ethereum_events::{EthAddress, KeccakHash, Uint}; use crate::types::keccak; use crate::types::token::Amount; @@ -54,24 +54,16 @@ pub struct PendingTransfer { } impl keccak::encode::Encode for PendingTransfer { - fn tokenize(&self) -> Vec { let from = Token::String(self.gas_fee.payer.to_string()); let fee = Token::Uint(u64::from(self.gas_fee.amount).into()); let to = Token::Address(self.transfer.recipient.0.into()); let amount = Token::Uint(u64::from(self.transfer.amount).into()); let nonce = Token::Uint(self.transfer.nonce.into()); - vec![ - from, - fee, - to, - amount, - nonce, - ] + vec![from, fee, to, amount, nonce] } } - /// The amount of NAM to be payed to the relayer of /// a transfer across the Ethereum Bridge to compensate /// for Ethereum gas fees. diff --git a/shared/src/types/hash.rs b/shared/src/types/hash.rs index e4ac6e8c2c..f2a84f19eb 100644 --- a/shared/src/types/hash.rs +++ b/shared/src/types/hash.rs @@ -25,7 +25,7 @@ pub enum Error { #[error("Failed trying to convert slice to a hash: {0}")] ConversionFailed(std::array::TryFromSliceError), #[error("Failed to convert string into a hash: {0}")] - FromStringError(hex::FromHexError) + FromStringError(hex::FromHexError), } /// Result for functions that may fail @@ -93,7 +93,8 @@ impl TryFrom for Hash { type Error = self::Error; fn try_from(string: String) -> HashResult { - let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + let bytes: Vec = + Vec::from_hex(string).map_err(Error::FromStringError)?; Self::try_from(&bytes) } } @@ -102,7 +103,8 @@ impl TryFrom<&str> for Hash { type Error = self::Error; fn try_from(string: &str) -> HashResult { - let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; + let bytes: Vec = + Vec::from_hex(string).map_err(Error::FromStringError)?; Self::try_from(&bytes) } } @@ -165,4 +167,4 @@ impl Value for Hash { fn zero() -> Self { Hash([0u8; 32]) } -} \ No newline at end of file +} diff --git a/shared/src/types/storage.rs b/shared/src/types/storage.rs index 7b7ffad7a2..e13aa14dc5 100644 --- a/shared/src/types/storage.rs +++ b/shared/src/types/storage.rs @@ -9,17 +9,17 @@ use std::str::FromStr; use arse_merkle_tree::InternalKey; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use ics23::CommitmentProof; use serde::{Deserialize, Serialize}; use thiserror::Error; -use variant_access_derive::*; -use variant_access_traits::*; #[cfg(feature = "ferveo-tpke")] use super::transaction::WrapperTx; use crate::bytes::ByteBuf; +use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolProof; use crate::ledger::storage::{StorageHasher, IBC_KEY_LIMIT}; use crate::types::address::{self, Address}; -use crate::types::eth_bridge_pool::{TransferToEthereum, PendingTransfer}; +use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; use crate::types::hash::Hash; use crate::types::time::DateTimeUtc; @@ -35,7 +35,7 @@ pub enum Error { #[error("Reserved prefix or string is specified: {0}")] InvalidKeySeg(String), #[error("Could not parse string: '{0}' into requested type: {1}")] - ParseError((String, String)) + ParseError(String, String), } /// Result for functions that may fail @@ -248,15 +248,13 @@ impl FromStr for Key { pub enum MerkleValue> { /// raw bytes Bytes(T), - /// a transfer to be put in the Ethereum bridge pool - /// We actually only need the key (which is the hash - /// of the transfer). So this variant contains no data. + /// A transfer to be put in the Ethereum bridge pool. Transfer(PendingTransfer), } impl From for MerkleValue where - T: AsRef<[u8]> + T: AsRef<[u8]>, { fn from(bytes: T) -> Self { Self::Bytes(bytes) @@ -348,6 +346,26 @@ impl From for Vec { } } +/// Type of membership proof from a merkle tree +pub enum MembershipProof { + /// ICS23 compliant membership proof + ICS23(CommitmentProof), + /// Bespoke membership proof for the Ethereum bridge pool + BridgePool(BridgePoolProof), +} + +impl From for MembershipProof { + fn from(proof: CommitmenProof) -> Self { + Self::ICS23(proof) + } +} + +impl From for MembershipProof { + fn from(proof: BridgePoolProof) -> Self { + Self::BridgePool(proof) + } +} + impl Key { /// Parses string and returns a key pub fn parse(string: impl AsRef) -> Result { @@ -609,7 +627,8 @@ impl KeySeg for Address { impl KeySeg for Hash { fn parse(seg: String) -> Result { - seg.try_into().map_error(Error::ParseError((seg, "Hash".into()))) + seg.try_into() + .map_error(Error::ParseError((seg, "Hash".into()))) } fn raw(&self) -> String { @@ -670,7 +689,6 @@ impl Add for Epoch { } } - impl Sub for Epoch { type Output = Epoch; From 5b6e744600610be5bdc0681793373b26e33e3e6a Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 29 Sep 2022 10:27:36 +0200 Subject: [PATCH 07/28] [chore]: Rebase on eth-bridge-intregration --- Cargo.lock | 331 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 292 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17d28aa12b..adbc38f162 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1131,6 +1131,28 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "chrono-tz" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c39203181991a7dd4343b8005bd804e7a9a37afb8ac070e43771e8c820bbde" +dependencies = [ + "chrono", + "chrono-tz-build", + "phf", +] + +[[package]] +name = "chrono-tz-build" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f509c3a87b33437b05e2458750a0700e5bdd6956176773e6c7d6dd15a283a0c" +dependencies = [ + "parse-zoneinfo", + "phf", + "phf_codegen", +] + [[package]] name = "chunked_transfer" version = "1.4.0" @@ -1707,6 +1729,12 @@ dependencies = [ "syn", ] +[[package]] +name = "deunicode" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850878694b7933ca4c9569d30a34b55031b9b139ee1fc7b94a527c4ef960d690" + [[package]] name = "diff" version = "0.1.12" @@ -2506,6 +2534,17 @@ dependencies = [ "regex", ] +[[package]] +name = "globwalk" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" +dependencies = [ + "bitflags", + "ignore", + "walkdir", +] + [[package]] name = "gloo-timers" version = "0.2.4" @@ -2761,6 +2800,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humansize" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" + [[package]] name = "hyper" version = "0.10.16" @@ -2868,14 +2913,14 @@ dependencies = [ [[package]] name = "ibc" -version = "0.12.0" -source = "git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus#99a761657a51f6e5f074f3217426903e53632934" +version = "0.14.0" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "bytes 1.1.0", "derive_more", "flex-error", - "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", - "ics23 0.6.7", + "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", + "ics23", "num-traits 0.2.15", "prost 0.9.0", "prost-types 0.9.0", @@ -2895,14 +2940,14 @@ dependencies = [ [[package]] name = "ibc" -version = "0.12.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc#30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc" +version = "0.14.0" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" dependencies = [ "bytes 1.1.0", "derive_more", "flex-error", - "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", - "ics23 0.6.7", + "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", + "ics23", "num-traits 0.2.15", "prost 0.9.0", "prost-types 0.9.0", @@ -2922,44 +2967,28 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.16.0" -source = "git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus#99a761657a51f6e5f074f3217426903e53632934" +version = "0.17.1" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ + "base64 0.13.0", "bytes 1.1.0", "prost 0.9.0", "prost-types 0.9.0", "serde 1.0.137", "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", - "tonic", ] [[package]] name = "ibc-proto" -version = "0.16.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc#30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc" +version = "0.17.1" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" dependencies = [ + "base64 0.13.0", "bytes 1.1.0", "prost 0.9.0", "prost-types 0.9.0", "serde 1.0.137", "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", - "tonic", -] - -[[package]] -name = "ics23" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce15e4758c46a0453bdf4b3b1dfcce70c43f79d1943c2ee0635b77eb2e7aa233" -dependencies = [ - "anyhow", - "bytes 1.1.0", - "hex", - "prost 0.9.0", - "ripemd160", - "sha2 0.9.9", - "sha3 0.9.1", - "sp-std", ] [[package]] @@ -3043,6 +3072,24 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ignore" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +dependencies = [ + "crossbeam-utils 0.8.8", + "globset", + "lazy_static 1.4.0", + "log 0.4.17", + "memchr", + "regex", + "same-file", + "thread_local 1.1.4", + "walkdir", + "winapi-util", +] + [[package]] name = "impl-codec" version = "0.6.0" @@ -3969,6 +4016,12 @@ dependencies = [ "serde_yaml", ] +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + [[package]] name = "match_cfg" version = "0.1.0" @@ -4303,11 +4356,11 @@ dependencies = [ "ferveo-common", "group-threshold-cryptography", "hex", - "ibc 0.12.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", - "ibc 0.12.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", - "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", - "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", - "ics23 0.6.7", + "ibc 0.14.0 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", + "ibc 0.14.0 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", + "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", + "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", + "ics23", "itertools 0.10.3", "libsecp256k1 0.7.0", "loupe", @@ -4337,6 +4390,8 @@ dependencies = [ "tonic-build", "tracing 0.1.35", "tracing-subscriber 0.3.11", + "variant_access_derive", + "variant_access_traits", "wasmer", "wasmer-cache", "wasmer-compiler-singlepass", @@ -4406,6 +4461,7 @@ dependencies = [ "rlimit", "rocksdb", "rpassword", + "semver 1.0.14", "serde 1.0.137", "serde_bytes", "serde_json", @@ -5090,6 +5146,15 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "parse-zoneinfo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c705f256449c60da65e11ff6626e0c16a0a0b96aaa348de61376b249bc340f41" +dependencies = [ + "regex", +] + [[package]] name = "paste" version = "1.0.7" @@ -5156,6 +5221,40 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +dependencies = [ + "maplit", + "pest", + "sha-1 0.8.2", +] + [[package]] name = "petgraph" version = "0.5.1" @@ -5176,6 +5275,45 @@ dependencies = [ "indexmap", ] +[[package]] +name = "phf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_codegen" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56ac890c5e3ca598bbdeaa99964edb5b0258a583a9eb6ef4e89fc85d9224770" +dependencies = [ + "phf_generator", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +dependencies = [ + "phf_shared", + "rand 0.8.5", +] + +[[package]] +name = "phf_shared" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +dependencies = [ + "siphasher", + "uncased", +] + [[package]] name = "pin-project" version = "0.4.29" @@ -6103,7 +6241,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.10", + "semver 1.0.14", ] [[package]] @@ -6336,9 +6474,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "semver-parser" @@ -6626,12 +6764,27 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc47a29ce97772ca5c927f75bac34866b16d64e07f330c3248e2d7226623901b" +[[package]] +name = "siphasher" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" + [[package]] name = "slab" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" +[[package]] +name = "slug" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3bc762e6a4b6c6fcaade73e77f9ebc6991b676f88bb2358bddb56560f073373" +dependencies = [ + "deunicode", +] + [[package]] name = "smallvec" version = "0.6.14" @@ -6716,7 +6869,7 @@ dependencies = [ "blake2b-rs", "borsh", "cfg-if 1.0.0", - "ics23 0.7.0", + "ics23", "sha2 0.9.9", ] @@ -7137,6 +7290,28 @@ dependencies = [ "time 0.3.9", ] +[[package]] +name = "tera" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c9783d6ff395ae80cf17ed9a25360e7ba37742a79fa8fddabb073c5c7c8856d" +dependencies = [ + "chrono", + "chrono-tz", + "globwalk", + "humansize", + "lazy_static 1.4.0", + "percent-encoding 2.1.0", + "pest", + "pest_derive", + "rand 0.8.5", + "regex", + "serde 1.0.137", + "serde_json", + "slug", + "unic-segment", +] + [[package]] name = "term_size" version = "0.3.2" @@ -7961,6 +8136,65 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "uncased" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b01702b0fd0b3fadcf98e098780badda8742d4f4a7676615cad90e8ac73622" +dependencies = [ + "version_check 0.9.4", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" +dependencies = [ + "unic-ucd-segment", +] + +[[package]] +name = "unic-ucd-segment" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + [[package]] name = "unicase" version = "1.4.2" @@ -8121,6 +8355,25 @@ dependencies = [ "version_check 0.9.4", ] +[[package]] +name = "variant_access_derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd235ffafb854ed81b49217ce411e850a39628a5d26740ecfb60421c873d834" +dependencies = [ + "lazy_static 1.4.0", + "quote", + "syn", + "tera", + "variant_access_traits", +] + +[[package]] +name = "variant_access_traits" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d75c5a83bb8912dd9c628adf954c9f9bff74a4e170d2c90242f4e56a0d643e" + [[package]] name = "vcpkg" version = "0.2.15" From 5be39000c4587635f8bee8262d71d0112878a5b7 Mon Sep 17 00:00:00 2001 From: satan Date: Fri, 30 Sep 2022 16:06:29 +0200 Subject: [PATCH 08/28] [feat]: Debugged code to compiling. Written for tests for the merkle tree --- Cargo.lock | 63 +- .../src/ledger/eth_bridge/bridge_pool_vp.rs | 5 +- .../ledger/eth_bridge/storage/bridge_pool.rs | 622 ++++++++++++++++-- shared/src/ledger/governance/mod.rs | 3 +- shared/src/ledger/governance/parameters.rs | 2 +- shared/src/ledger/governance/utils.rs | 3 +- shared/src/ledger/governance/vp.rs | 3 +- shared/src/ledger/ibc/mod.rs | 3 +- shared/src/ledger/ibc/vp/channel.rs | 3 +- shared/src/ledger/ibc/vp/client.rs | 3 +- shared/src/ledger/ibc/vp/connection.rs | 3 +- shared/src/ledger/ibc/vp/mod.rs | 3 +- shared/src/ledger/ibc/vp/packet.rs | 3 +- shared/src/ledger/ibc/vp/port.rs | 3 +- shared/src/ledger/ibc/vp/sequence.rs | 3 +- shared/src/ledger/ibc/vp/token.rs | 3 +- shared/src/ledger/native_vp.rs | 3 +- shared/src/ledger/parameters/mod.rs | 19 +- shared/src/ledger/pos/mod.rs | 3 +- shared/src/ledger/pos/storage.rs | 3 +- shared/src/ledger/pos/vp.rs | 3 +- shared/src/ledger/storage/ics23_specs.rs | 10 +- shared/src/ledger/storage/merkle_tree.rs | 538 ++++++++------- shared/src/ledger/storage/mod.rs | 25 +- shared/src/ledger/storage/traits.rs | 198 +++--- shared/src/ledger/storage/write_log.rs | 3 +- shared/src/ledger/treasury/mod.rs | 3 +- shared/src/ledger/treasury/parameters.rs | 2 +- shared/src/ledger/vp_env.rs | 3 +- shared/src/types/eth_bridge_pool.rs | 12 +- shared/src/types/hash.rs | 4 +- shared/src/types/keccak.rs | 2 + shared/src/types/storage.rs | 24 +- shared/src/vm/host_env.rs | 6 +- shared/src/vm/wasm/host_env.rs | 3 +- shared/src/vm/wasm/run.rs | 3 +- 36 files changed, 1064 insertions(+), 531 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17d28aa12b..b4448bd3ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2868,14 +2868,14 @@ dependencies = [ [[package]] name = "ibc" -version = "0.12.0" -source = "git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus#99a761657a51f6e5f074f3217426903e53632934" +version = "0.14.0" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "bytes 1.1.0", "derive_more", "flex-error", - "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", - "ics23 0.6.7", + "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", + "ics23", "num-traits 0.2.15", "prost 0.9.0", "prost-types 0.9.0", @@ -2895,14 +2895,14 @@ dependencies = [ [[package]] name = "ibc" -version = "0.12.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc#30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc" +version = "0.14.0" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" dependencies = [ "bytes 1.1.0", "derive_more", "flex-error", - "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", - "ics23 0.6.7", + "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", + "ics23", "num-traits 0.2.15", "prost 0.9.0", "prost-types 0.9.0", @@ -2922,44 +2922,28 @@ dependencies = [ [[package]] name = "ibc-proto" -version = "0.16.0" -source = "git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus#99a761657a51f6e5f074f3217426903e53632934" +version = "0.17.1" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ + "base64 0.13.0", "bytes 1.1.0", "prost 0.9.0", "prost-types 0.9.0", "serde 1.0.137", "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus)", - "tonic", ] [[package]] name = "ibc-proto" -version = "0.16.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc#30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc" +version = "0.17.1" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" dependencies = [ + "base64 0.13.0", "bytes 1.1.0", "prost 0.9.0", "prost-types 0.9.0", "serde 1.0.137", "tendermint-proto 0.23.5 (git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9)", - "tonic", -] - -[[package]] -name = "ics23" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce15e4758c46a0453bdf4b3b1dfcce70c43f79d1943c2ee0635b77eb2e7aa233" -dependencies = [ - "anyhow", - "bytes 1.1.0", - "hex", - "prost 0.9.0", - "ripemd160", - "sha2 0.9.9", - "sha3 0.9.1", - "sp-std", ] [[package]] @@ -4303,11 +4287,11 @@ dependencies = [ "ferveo-common", "group-threshold-cryptography", "hex", - "ibc 0.12.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", - "ibc 0.12.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", - "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?branch=bat/abciplus)", - "ibc-proto 0.16.0 (git+https://github.com/heliaxdev/ibc-rs?rev=30b3495ac56c6c37c99bc69ef9f2e84c3309c6cc)", - "ics23 0.6.7", + "ibc 0.14.0 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", + "ibc 0.14.0 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", + "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63)", + "ibc-proto 0.17.1 (git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d)", + "ics23", "itertools 0.10.3", "libsecp256k1 0.7.0", "loupe", @@ -4406,6 +4390,7 @@ dependencies = [ "rlimit", "rocksdb", "rpassword", + "semver 1.0.14", "serde 1.0.137", "serde_bytes", "serde_json", @@ -6103,7 +6088,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.10", + "semver 1.0.14", ] [[package]] @@ -6336,9 +6321,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a41d061efea015927ac527063765e73601444cdc344ba855bc7bd44578b25e1c" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "semver-parser" @@ -6716,7 +6701,7 @@ dependencies = [ "blake2b-rs", "borsh", "cfg-if 1.0.0", - "ics23 0.7.0", + "ics23", "sha2 0.9.9", ] diff --git a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs index 12fa7982eb..b7b8cf1cf2 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs @@ -18,8 +18,8 @@ use crate::ledger::eth_bridge::storage::bridge_pool::{ get_pending_key, is_protected_storage, BRIDGE_POOL_ADDRESS, }; use crate::ledger::native_vp::{Ctx, NativeVp, StorageReader}; -use crate::ledger::storage::{DBIter, DB}; use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{DBIter, DB}; use crate::proto::SignedTxData; use crate::types::address::{xan, Address, InternalAddress}; use crate::types::eth_bridge_pool::PendingTransfer; @@ -192,8 +192,9 @@ mod test_bridge_pool_vp { use crate::ledger::eth_bridge::storage::bridge_pool::get_signed_root_key; use crate::ledger::gas::VpGasMeter; use crate::ledger::storage::mockdb::MockDB; + use crate::ledger::storage::traits::Sha256Hasher; use crate::ledger::storage::write_log::WriteLog; - use crate::ledger::storage::{Sha256Hasher, Storage}; + use crate::ledger::storage::Storage; use crate::proto::Tx; use crate::types::chain::ChainId; use crate::types::eth_bridge_pool::{GasFee, TransferToEthereum}; diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index 48266bde17..8bf13ab7aa 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -2,14 +2,12 @@ //! bridge pool use std::collections::BTreeSet; use std::convert::TryInto; -use std::ops::Deref; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use eyre::eyre; -use crate::ledger::storage::traits::{Sha256Hasher, StorageHasher}; use crate::types::address::{Address, InternalAddress}; -use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; +use crate::types::eth_bridge_pool::PendingTransfer; use crate::types::hash::Hash; use crate::types::keccak::encode::Encode; use crate::types::keccak::{keccak_hash, KeccakHash}; @@ -62,7 +60,9 @@ pub fn is_protected_storage(key: &Key) -> bool { } /// A simple Merkle tree for the Ethereum bridge pool -#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, BorshSchema)] +#[derive( + Debug, Default, Clone, BorshSerialize, BorshDeserialize, BorshSchema, +)] pub struct BridgePoolTree { /// Root of the tree root: KeccakHash, @@ -72,7 +72,7 @@ pub struct BridgePoolTree { impl BridgePoolTree { /// Create a new merkle tree for the Ethereum bridge pool - pub fn new(root: KeccakHash, store: BTreeSet) -> Self { + pub fn new(root: KeccakHash, store: BTreeSet) -> Self { Self { root, store } } @@ -80,7 +80,7 @@ impl BridgePoolTree { /// /// If it is, it can be converted to a hash. /// Checks if the hash is in the tree. - pub fn has_key(&self, key: &Key) -> Result { + pub fn contains_key(&self, key: &Key) -> Result { Ok(self.store.contains(&Self::parse_key(key)?)) } @@ -88,7 +88,7 @@ impl BridgePoolTree { /// /// Returns the new root if successful. Will /// return an error if the key is malformed. - pub fn update(&mut self, key: &Key) -> Result { + pub fn update_key(&mut self, key: &Key) -> Result { let hash = Self::parse_key(key)?; _ = self.store.insert(hash); self.root = self.compute_root(); @@ -96,7 +96,7 @@ impl BridgePoolTree { } /// Delete a key from storage and update the root - pub fn delete(&mut self, key: &Key) -> Result<(), Error> { + pub fn delete_key(&mut self, key: &Key) -> Result<(), Error> { let hash = Self::parse_key(key)?; _ = self.store.remove(&hash); self.root = self.compute_root(); @@ -105,16 +105,26 @@ impl BridgePoolTree { /// Compute the root of the merkle tree pub fn compute_root(&self) -> KeccakHash { - let mut leaves = self.store.iter(); - let mut root = if let Some(hash) = leaves.next() { - hash.clone() + let mut hashes: Vec = self.store.iter().cloned().collect(); + while hashes.len() > 1 { + let mut next_hashes = vec![]; + let left_leaves = hashes.iter().step_by(2); + let mut right_leaves = hashes.iter(); + _ = right_leaves.next(); + let mut right_leaves = right_leaves.step_by(2); + + for left in left_leaves { + let right = right_leaves.next().cloned().unwrap_or_default(); + next_hashes.push(hash_pair(left.clone(), right)); + } + hashes = next_hashes; + } + + if hashes.is_empty() { + Default::default() } else { - return Default::default(); - }; - for leaf in leaves { - root = keccak_hash([root.0, leaf.0].concat()); + hashes.remove(0) } - root } /// Return the root as a [`Hash`] type. @@ -128,33 +138,87 @@ impl BridgePoolTree { } /// Create a batched membership proof for the provided keys - pub fn membership_proof( + pub fn get_membership_proof( &self, keys: &[Key], mut values: Vec, ) -> Result { if values.len() != keys.len() { - return eyre!( + return Err(eyre!( "The number of leaves and leaf hashes must be equal." - )?; + ) + .into()); } - values.sort(); - let mut leaves: std::collections::BTreeSet = - Default::default(); - for key in keys { - leaves.insert(Self::parse_key(key)?); + // sort the values according to their hash values + values.sort_by_key(|transfer| transfer.keccak256()); + + // get the leaf hashes + let mut leaves: BTreeSet = Default::default(); + for (key, value) in keys.iter().zip(values.iter()) { + let hash = Self::parse_key(key)?; + if hash != value.keccak256() { + return Err(eyre!("Hashes of keys did not match hashes of values.").into()); + } + leaves.insert(hash); } let mut proof_hashes = vec![]; let mut flags = vec![]; - for hash in self.store { - if leaves.contains(&hash) { - flags.push(true); - } else { - flags.push(false); - proof_hashes.push(hash); + let mut hashes: Vec<_> = self + .store + .iter() + .cloned() + .map(|hash| { + if leaves.contains(&hash) { + Node::OnPath(hash) + } else { + Node::Sibling(hash) + } + }) + .collect(); + + while hashes.len() > 1 { + let mut next_hashes = vec![]; + let left_leaves = hashes.iter().step_by(2); + let mut right_leaves = hashes.iter(); + _ = right_leaves.next(); + let mut right_leaves = right_leaves.step_by(2); + + for left in left_leaves { + let right = right_leaves.next().cloned().unwrap_or_default(); + match (left, right) { + (Node::OnPath(left), Node::OnPath(right)) => { + flags.push(true); + next_hashes + .push(Node::OnPath(hash_pair(left.clone(), right))); + } + (Node::OnPath(hash), Node::Sibling(sib)) => { + flags.push(false); + proof_hashes.push(sib.clone()); + next_hashes + .push(Node::OnPath(hash_pair(hash.clone(), sib))); + } + (Node::Sibling(sib), Node::OnPath(hash)) => { + flags.push(false); + proof_hashes.push(sib.clone()); + next_hashes + .push(Node::OnPath(hash_pair(hash, sib.clone()))); + } + (Node::Sibling(left), Node::Sibling(right)) => { + next_hashes.push(Node::Sibling(hash_pair( + left.clone(), + right, + ))); + } + } } + hashes = next_hashes; + } + // add the root to the proof + if proof_hashes.is_empty() { + proof_hashes.push(self.root.clone()); } + Ok(BridgePoolProof { proof: proof_hashes, leaves: values, @@ -170,22 +234,52 @@ impl BridgePoolTree { fn parse_key(key: &Key) -> Result { if key.segments.len() == 1 { match &key.segments[0] { - DbKeySeg::StringSeg(str) => str - .as_str() - .try_into() - .ok_or(eyre!("Could not parse key segment as a hash")?), - _ => { - eyre!("Bridge pool keys should be strings, not addresses")? + DbKeySeg::StringSeg(str) => { + str.as_str().try_into().map_err(|_| { + eyre!("Could not parse key segment as a hash").into() + }) } + _ => Err(eyre!( + "Bridge pool keys should be strings, not addresses" + ) + .into()), } } else { - eyre!( + Err(eyre!( "Key for the bridge pool should not have more than one segment" - )? + ) + .into()) } } } +/// Concatenate two keccak hashes and hash the result +#[inline] +fn hash_pair(left: KeccakHash, right: KeccakHash) -> KeccakHash { + if left.0 < right.0 { + keccak_hash([left.0, right.0].concat().as_slice()) + } else { + keccak_hash([right.0, left.0].concat().as_slice()) + } +} + +/// Keeps track if a node is on a path from the +/// root of the merkle tree to one of the leaves +/// being included in a multi-proof. +#[derive(Debug, Clone)] +enum Node { + /// Node is on a path from root to leaf in proof + OnPath(KeccakHash), + /// Node is not on a path from root to leaf in proof + Sibling(KeccakHash), +} + +impl Default for Node { + fn default() -> Self { + Self::Sibling(Default::default()) + } +} + /// A multi-leaf membership proof pub struct BridgePoolProof { /// The hashes other than the provided leaves @@ -199,33 +293,447 @@ pub struct BridgePoolProof { impl BridgePoolProof { /// Verify a membership proof matches the provided root pub fn verify(&self, root: KeccakHash) -> bool { - if self.proof.len() + self.leaves.len() != self.flags.len() { + if self.proof.len() + self.leaves.len() != self.flags.len() + 1 { return false; } - if self.flags.len() == 0 { - return true; + if self.flags.is_empty() { + return match self.proof.last() { + Some(proof_root) => &root == proof_root, + None => false, + }; } + let total_hashes = self.flags.len(); + let leaf_len = self.leaves.len(); + + let mut hashes = vec![KeccakHash::default(); self.flags.len()]; + let mut hash_pos = 0usize; let mut leaf_pos = 0usize; let mut proof_pos = 0usize; - let mut computed; - if self.flags[0] { - computed = self.leaves[leaf_pos].keccak256(); - leaf_pos += 1; - } else { - computed = self.proof[proof_pos].clone(); - proof_pos += 1; - } - for flag in 1..self.flages.len() { - let mut next_hash; - if self.flags[flag] { - next_hash = self.leaves[leaf_pos].keccak256(); + + for i in 0..total_hashes { + let left = if leaf_pos < leaf_len { + let next = self.leaves[leaf_pos].keccak256(); leaf_pos += 1; + next + } else { + let next = hashes[hash_pos].clone(); + hash_pos += 1; + next + }; + let right = if self.flags[i] { + if leaf_pos < leaf_len { + let next = self.leaves[leaf_pos].keccak256(); + leaf_pos += 1; + next + } else { + let next = hashes[hash_pos].clone(); + hash_pos += 1; + next + } } else { - next_hash = self.proof[proof_pos].clone(); + let next = self.proof[proof_pos].clone(); proof_pos += 1; - } - computed = keccak_hash([computed, next_hash].concat()); + next + }; + hashes[i] = hash_pair(left, right); + } + + if let Some(computed) = hashes.last() { + *computed == root + } else { + false } - computed == root } } + +#[cfg(test)] +mod test_bridge_pool_tree { + use std::array; + use super::*; + use crate::types::ethereum_events::EthAddress; + use crate::types::eth_bridge_pool::{GasFee, TransferToEthereum}; + + /// An established user address for testing & development + fn bertha_address() -> Address { + Address::decode("atest1v4ehgw36xvcyyvejgvenxs34g3zygv3jxqunjd6rxyeyys3sxy6rwvfkx4qnj33hg9qnvse4lsfctw") + .expect("The token address decoding shouldn't fail") + } + + /// Test that if tree has a single leaf, its root is the hash + /// of that leaf + #[test] + fn test_update_single_key() { + let mut tree = BridgePoolTree::default(); + assert_eq!(tree.root().0, [0; 32]); + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([1;20]), + recipient: EthAddress([2; 20]), + amount: 1.into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let key = Key::from(&transfer); + let root = KeccakHash::from(tree.update_key(&key).expect("Test failed")); + assert_eq!(root, transfer.keccak256()); + } + + #[test] + fn test_two_keys() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..2 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + let expected: Hash = hash_pair(transfers[0].keccak256(), transfers[1].keccak256()).into(); + assert_eq!(tree.root(), expected); + } + + /// This is the first number of keys to use dummy leaves + #[test] + fn test_three_leaves() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..3 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + transfers.sort_by_key(|t| t.keccak256()); + let hashes: BTreeSet = transfers.iter().map(|t| t.keccak256()).collect(); + assert_eq!(hashes, tree.store); + + let left_hash = hash_pair(transfers[0].keccak256(), transfers[1].keccak256()); + let right_hash = hash_pair(transfers[2].keccak256(), Default::default()); + let expected: Hash = hash_pair(left_hash, right_hash).into(); + assert_eq!(tree.root(), expected); + } + + /// Test removing all keys + #[test] + fn test_delete_all_keys() { + let mut tree = BridgePoolTree::default(); + + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([1;20]), + recipient: EthAddress([2; 20]), + amount: 1.into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let key = Key::from(&transfer); + let root = KeccakHash::from(tree.update_key(&key).expect("Test failed")); + assert_eq!(root, transfer.keccak256()); + tree.delete_key(&key).expect("Test failed"); + assert_eq!(tree.root().0, [0; 32]); + } + + /// Test deleting a key + #[test] + fn test_delete_key() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..3 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + transfers.sort_by_key(|t| t.keccak256()); + tree.delete_key(&Key::from(&transfers[1])) + .expect("Test failed"); + + let expected: Hash = hash_pair(transfers[0].keccak256(), transfers[2].keccak256()).into(); + assert_eq!(tree.root(), expected); + } + + /// Test that parse key works correctly + #[test] + fn test_parse_key() { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([1; 20]), + recipient: EthAddress([2; 20]), + amount: (1 as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let expected = transfer.keccak256(); + let key = Key::from(&transfer); + assert_eq!(BridgePoolTree::parse_key(&key).expect("Test failed"), expected); + } + + /// Test that parsing a key with multiple segments fails + #[test] + fn test_key_multiple_segments() { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([1; 20]), + recipient: EthAddress([2; 20]), + amount: (1 as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let hash = transfer.keccak256().to_string(); + let key = Key{segments: vec![DbKeySeg::AddressSeg(bertha_address()), DbKeySeg::StringSeg(hash)]}; + assert!(BridgePoolTree::parse_key(&key).is_err()); + } + + /// Test that parsing a key that is not a hash fails + #[test] + fn test_key_not_hash() { + let key = Key{segments: vec![DbKeySeg::StringSeg("bloop".into())]}; + assert!(BridgePoolTree::parse_key(&key).is_err()); + } + + /// Test that [`contains_key`] works correctly + #[test] + fn test_contains_key() { + let mut tree = BridgePoolTree::default(); + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([1; 20]), + recipient: EthAddress([2; 20]), + amount: (1 as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + tree.update_key(&Key::from(&transfer)).expect("Test failed"); + assert!(tree.contains_key(&Key::from(&transfer)).expect("Test failed")); + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([1; 20]), + recipient: EthAddress([0; 20]), + amount: (1 as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + assert!(!tree.contains_key(&Key::from(&transfer)).expect("Test failed")); + } + + /// Test that the empty proof works + #[test] + fn test_empty_proof() { + let tree = BridgePoolTree::default(); + let keys = vec![]; + let values = vec![]; + let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + assert!(proof.verify(Default::default())); + } + + #[test] + fn test_one_leaf_of_two_proof() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..2 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + let key = Key::from(&transfers[0]); + let proof = tree.get_membership_proof( + array::from_ref(&key), + vec![transfers.remove(0)] + ) + .expect("Test failed"); + assert!(proof.verify(tree.root().into())); + } + + /// Test that a multiproof works for leaves who are siblings + #[test] + fn test_proof_two_out_of_three_leaves() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..3 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + transfers.sort_by_key(|t| t.keccak256()); + let keys = vec![Key::from(&transfers[0]), Key::from(&transfers[1])]; + let values = vec![transfers[0].clone(), transfers[1].clone()]; + let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + assert!(proof.verify(tree.root().into())); + } + + #[test] + fn test_proof_no_leaves() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..3 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + let keys = vec![]; + let values = vec![]; + let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + assert!(proof.verify(tree.root().into())) + } + + /// Test a proof for all the leaves + #[test] + fn test_proof_all_leaves() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..3 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + transfers.sort_by_key(|t| t.keccak256()); + let keys: Vec<_> = transfers.iter().map(Key::from).collect(); + let proof = tree.get_membership_proof(&keys, transfers).expect("Test failed"); + assert!(proof.verify(tree.root().into())); + } + + /// Test proofs of large trees + #[test] + fn test_large_proof() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..5 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + transfers.sort_by_key(|t| t.keccak256()); + let keys: Vec<_> = transfers + .iter() + .step_by(2) + .map(Key::from) + .collect(); + let values: Vec<_> = transfers + .iter() + .step_by(2) + .cloned() + .collect(); + let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + assert!(proof.verify(tree.root().into())); + } +} \ No newline at end of file diff --git a/shared/src/ledger/governance/mod.rs b/shared/src/ledger/governance/mod.rs index 72aa7fb3ce..b565970c76 100644 --- a/shared/src/ledger/governance/mod.rs +++ b/shared/src/ledger/governance/mod.rs @@ -16,7 +16,8 @@ pub use vp::Result; use self::storage as gov_storage; use crate::ledger::native_vp::{Ctx, NativeVp}; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::types::address::{xan as m1t, Address, InternalAddress}; use crate::types::storage::Key; use crate::types::token as token_storage; diff --git a/shared/src/ledger/governance/parameters.rs b/shared/src/ledger/governance/parameters.rs index 79c3b4d5b6..f860242a74 100644 --- a/shared/src/ledger/governance/parameters.rs +++ b/shared/src/ledger/governance/parameters.rs @@ -47,7 +47,7 @@ impl GovParams { pub fn init_storage(&self, storage: &mut Storage) where DB: storage::DB + for<'iter> storage::DBIter<'iter>, - H: storage::StorageHasher, + H: storage::traits::StorageHasher, { let Self { min_proposal_fund, diff --git a/shared/src/ledger/governance/utils.rs b/shared/src/ledger/governance/utils.rs index aaca277f91..e6377e4fa6 100644 --- a/shared/src/ledger/governance/utils.rs +++ b/shared/src/ledger/governance/utils.rs @@ -9,7 +9,8 @@ use thiserror::Error; use crate::ledger::governance::storage as gov_storage; use crate::ledger::pos; use crate::ledger::pos::{BondId, Bonds, ValidatorSets, ValidatorTotalDeltas}; -use crate::ledger::storage::{DBIter, Storage, StorageHasher, DB}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{DBIter, Storage, DB}; use crate::types::address::Address; use crate::types::governance::{ProposalVote, TallyResult}; use crate::types::storage::{Epoch, Key}; diff --git a/shared/src/ledger/governance/vp.rs b/shared/src/ledger/governance/vp.rs index 6ccfc7a33e..fbd129b43c 100644 --- a/shared/src/ledger/governance/vp.rs +++ b/shared/src/ledger/governance/vp.rs @@ -6,7 +6,8 @@ use thiserror::Error; use super::storage as gov_storage; use crate::ledger::native_vp::{self, Ctx}; use crate::ledger::pos::{self as pos_storage, BondId, Bonds}; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::types::address::{xan as m1t, Address, InternalAddress}; use crate::types::storage::{Epoch, Key}; use crate::types::token; diff --git a/shared/src/ledger/ibc/mod.rs b/shared/src/ledger/ibc/mod.rs index 5fb599d979..f2a422236a 100644 --- a/shared/src/ledger/ibc/mod.rs +++ b/shared/src/ledger/ibc/mod.rs @@ -9,7 +9,8 @@ use storage::{ connection_counter_key, }; -use crate::ledger::storage::{self as ledger_storage, Storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage, Storage}; /// Initialize storage in the genesis block. pub fn init_genesis_storage(storage: &mut Storage) diff --git a/shared/src/ledger/ibc/vp/channel.rs b/shared/src/ledger/ibc/vp/channel.rs index 3a43834da5..a0dafebc00 100644 --- a/shared/src/ledger/ibc/vp/channel.rs +++ b/shared/src/ledger/ibc/vp/channel.rs @@ -53,7 +53,8 @@ use crate::ibc::proofs::Proofs; use crate::ibc::timestamp::Timestamp; use crate::ledger::native_vp::Error as NativeVpError; use crate::ledger::parameters; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::tendermint::Time; use crate::tendermint_proto::Protobuf; use crate::types::ibc::data::{ diff --git a/shared/src/ledger/ibc/vp/client.rs b/shared/src/ledger/ibc/vp/client.rs index 4b89e1ce30..8b1fa8b73d 100644 --- a/shared/src/ledger/ibc/vp/client.rs +++ b/shared/src/ledger/ibc/vp/client.rs @@ -31,7 +31,8 @@ use crate::ibc::core::ics04_channel::context::ChannelReader; use crate::ibc::core::ics23_commitment::commitment::CommitmentRoot; use crate::ibc::core::ics24_host::identifier::ClientId; use crate::ibc::core::ics26_routing::msgs::Ics26Envelope; -use crate::ledger::storage::{self, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self}; use crate::tendermint_proto::Protobuf; use crate::types::ibc::data::{Error as IbcDataError, IbcMessage}; use crate::types::storage::{BlockHeight, Key}; diff --git a/shared/src/ledger/ibc/vp/connection.rs b/shared/src/ledger/ibc/vp/connection.rs index 2e721bed08..4037d1b02a 100644 --- a/shared/src/ledger/ibc/vp/connection.rs +++ b/shared/src/ledger/ibc/vp/connection.rs @@ -27,7 +27,8 @@ use crate::ibc::core::ics03_connection::msgs::conn_open_confirm::MsgConnectionOp use crate::ibc::core::ics03_connection::msgs::conn_open_try::MsgConnectionOpenTry; use crate::ibc::core::ics23_commitment::commitment::CommitmentPrefix; use crate::ibc::core::ics24_host::identifier::{ClientId, ConnectionId}; -use crate::ledger::storage::{self, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self}; use crate::tendermint_proto::Protobuf; use crate::types::ibc::data::{Error as IbcDataError, IbcMessage}; use crate::types::storage::{BlockHeight, Epoch, Key}; diff --git a/shared/src/ledger/ibc/vp/mod.rs b/shared/src/ledger/ibc/vp/mod.rs index 7e2baf4666..6797a61054 100644 --- a/shared/src/ledger/ibc/vp/mod.rs +++ b/shared/src/ledger/ibc/vp/mod.rs @@ -18,7 +18,8 @@ use super::storage::{client_id, ibc_prefix, is_client_counter_key, IbcPrefix}; use crate::ibc::core::ics02_client::context::ClientReader; use crate::ibc::events::IbcEvent; use crate::ledger::native_vp::{self, Ctx, NativeVp}; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::proto::SignedTxData; use crate::types::address::{Address, InternalAddress}; use crate::types::ibc::IbcEvent as WrappedIbcEvent; diff --git a/shared/src/ledger/ibc/vp/packet.rs b/shared/src/ledger/ibc/vp/packet.rs index 207727e91c..1182d4b821 100644 --- a/shared/src/ledger/ibc/vp/packet.rs +++ b/shared/src/ledger/ibc/vp/packet.rs @@ -32,7 +32,8 @@ use crate::ibc::core::ics24_host::identifier::{ }; use crate::ibc::core::ics26_routing::msgs::Ics26Envelope; use crate::ibc::proofs::Proofs; -use crate::ledger::storage::{self, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self}; use crate::types::ibc::data::{Error as IbcDataError, IbcMessage}; use crate::types::storage::Key; use crate::vm::WasmCacheAccess; diff --git a/shared/src/ledger/ibc/vp/port.rs b/shared/src/ledger/ibc/vp/port.rs index da5ef4e25f..5efade84bd 100644 --- a/shared/src/ledger/ibc/vp/port.rs +++ b/shared/src/ledger/ibc/vp/port.rs @@ -16,7 +16,8 @@ use crate::ibc::core::ics05_port::context::{CapabilityReader, PortReader}; use crate::ibc::core::ics05_port::error::Error as Ics05Error; use crate::ibc::core::ics24_host::identifier::PortId; use crate::ibc::core::ics26_routing::context::ModuleId; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::types::storage::Key; use crate::vm::WasmCacheAccess; diff --git a/shared/src/ledger/ibc/vp/sequence.rs b/shared/src/ledger/ibc/vp/sequence.rs index 0e751ea0de..a47bb4c4ca 100644 --- a/shared/src/ledger/ibc/vp/sequence.rs +++ b/shared/src/ledger/ibc/vp/sequence.rs @@ -8,7 +8,8 @@ use crate::ibc::core::ics04_channel::channel::Order; use crate::ibc::core::ics04_channel::context::ChannelReader; use crate::ibc::core::ics24_host::identifier::PortChannelId; use crate::ledger::ibc::handler::packet_from_message; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::types::ibc::data::{Error as IbcDataError, IbcMessage}; use crate::types::storage::Key; use crate::vm::WasmCacheAccess; diff --git a/shared/src/ledger/ibc/vp/token.rs b/shared/src/ledger/ibc/vp/token.rs index f56382b360..806e26711f 100644 --- a/shared/src/ledger/ibc/vp/token.rs +++ b/shared/src/ledger/ibc/vp/token.rs @@ -11,7 +11,8 @@ use crate::ibc::core::ics04_channel::msgs::PacketMsg; use crate::ibc::core::ics04_channel::packet::Packet; use crate::ibc::core::ics26_routing::msgs::Ics26Envelope; use crate::ledger::native_vp::{self, Ctx, NativeVp}; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::proto::SignedTxData; use crate::types::address::{Address, Error as AddressError, InternalAddress}; use crate::types::ibc::data::{ diff --git a/shared/src/ledger/native_vp.rs b/shared/src/ledger/native_vp.rs index 1819cde903..594db7f8d1 100644 --- a/shared/src/ledger/native_vp.rs +++ b/shared/src/ledger/native_vp.rs @@ -8,8 +8,9 @@ use eyre::Context; use thiserror::Error; use crate::ledger::gas::VpGasMeter; +use crate::ledger::storage::traits::StorageHasher; use crate::ledger::storage::write_log::WriteLog; -use crate::ledger::storage::{Storage, StorageHasher}; +use crate::ledger::storage::Storage; use crate::ledger::{storage, vp_env}; use crate::proto::Tx; use crate::types::address::{Address, InternalAddress}; diff --git a/shared/src/ledger/parameters/mod.rs b/shared/src/ledger/parameters/mod.rs index fdc2a110d0..4891818dc0 100644 --- a/shared/src/ledger/parameters/mod.rs +++ b/shared/src/ledger/parameters/mod.rs @@ -11,7 +11,8 @@ use super::governance::vp::is_proposal_accepted; use super::storage::types::{decode, encode}; use super::storage::{types, Storage}; use crate::ledger::native_vp::{self, Ctx, NativeVp}; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::types::address::{Address, InternalAddress}; use crate::types::storage::Key; use crate::types::time::DurationSecs; @@ -150,7 +151,7 @@ impl Parameters { pub fn init_storage(&self, storage: &mut Storage) where DB: ledger_storage::DB + for<'iter> ledger_storage::DBIter<'iter>, - H: ledger_storage::StorageHasher, + H: StorageHasher, { // write epoch parameters let epoch_key = storage::get_epoch_storage_key(); @@ -198,7 +199,7 @@ pub fn update_max_expected_time_per_block_parameter( ) -> std::result::Result where DB: ledger_storage::DB + for<'iter> ledger_storage::DBIter<'iter>, - H: ledger_storage::StorageHasher, + H: StorageHasher, { let key = storage::get_max_expected_time_per_block_key(); update(storage, value, key) @@ -212,7 +213,7 @@ pub fn update_vp_whitelist_parameter( ) -> std::result::Result where DB: ledger_storage::DB + for<'iter> ledger_storage::DBIter<'iter>, - H: ledger_storage::StorageHasher, + H: StorageHasher, { let key = storage::get_vp_whitelist_storage_key(); update(storage, &value, key) @@ -226,7 +227,7 @@ pub fn update_tx_whitelist_parameter( ) -> std::result::Result where DB: ledger_storage::DB + for<'iter> ledger_storage::DBIter<'iter>, - H: ledger_storage::StorageHasher, + H: StorageHasher, { let key = storage::get_tx_whitelist_storage_key(); update(storage, &value, key) @@ -240,7 +241,7 @@ pub fn update_epoch_parameter( ) -> std::result::Result where DB: ledger_storage::DB + for<'iter> ledger_storage::DBIter<'iter>, - H: ledger_storage::StorageHasher, + H: StorageHasher, { let key = storage::get_epoch_storage_key(); update(storage, value, key) @@ -255,7 +256,7 @@ pub fn update( ) -> std::result::Result where DB: ledger_storage::DB + for<'iter> ledger_storage::DBIter<'iter>, - H: ledger_storage::StorageHasher, + H: StorageHasher, T: BorshSerialize, { let serialized_value = value @@ -273,7 +274,7 @@ pub fn read_epoch_parameter( ) -> std::result::Result<(EpochDuration, u64), ReadError> where DB: ledger_storage::DB + for<'iter> ledger_storage::DBIter<'iter>, - H: ledger_storage::StorageHasher, + H: StorageHasher, { // read epoch let epoch_key = storage::get_epoch_storage_key(); @@ -293,7 +294,7 @@ pub fn read( ) -> std::result::Result<(Parameters, u64), ReadError> where DB: ledger_storage::DB + for<'iter> ledger_storage::DBIter<'iter>, - H: ledger_storage::StorageHasher, + H: StorageHasher, { // read epoch let (epoch_duration, gas_epoch) = read_epoch_parameter(storage) diff --git a/shared/src/ledger/pos/mod.rs b/shared/src/ledger/pos/mod.rs index c980da81da..95a4de4ffa 100644 --- a/shared/src/ledger/pos/mod.rs +++ b/shared/src/ledger/pos/mod.rs @@ -13,7 +13,8 @@ use namada_proof_of_stake::PosBase; pub use storage::*; pub use vp::PosVP; -use crate::ledger::storage::{self as ledger_storage, Storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage, Storage}; use crate::types::address::{self, Address, InternalAddress}; use crate::types::storage::Epoch; use crate::types::{key, token}; diff --git a/shared/src/ledger/pos/storage.rs b/shared/src/ledger/pos/storage.rs index cfe1126b88..9ed2fcbecc 100644 --- a/shared/src/ledger/pos/storage.rs +++ b/shared/src/ledger/pos/storage.rs @@ -10,8 +10,9 @@ use super::{ BondId, Bonds, ValidatorConsensusKeys, ValidatorSets, ValidatorTotalDeltas, ADDRESS, }; +use crate::ledger::storage::traits::StorageHasher; use crate::ledger::storage::types::{decode, encode}; -use crate::ledger::storage::{self, Storage, StorageHasher}; +use crate::ledger::storage::{self, Storage}; use crate::types::address::Address; use crate::types::storage::{DbKeySeg, Key, KeySeg}; use crate::types::{key, token}; diff --git a/shared/src/ledger/pos/vp.rs b/shared/src/ledger/pos/vp.rs index 26be440536..e5cbf9198a 100644 --- a/shared/src/ledger/pos/vp.rs +++ b/shared/src/ledger/pos/vp.rs @@ -32,8 +32,9 @@ use crate::ledger::pos::{ is_validator_address_raw_hash_key, is_validator_consensus_key_key, is_validator_state_key, }; +use crate::ledger::storage::traits::StorageHasher; use crate::ledger::storage::types::decode; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::{self as ledger_storage}; use crate::types::address::{Address, InternalAddress}; use crate::types::storage::{Key, KeySeg}; use crate::types::{key, token}; diff --git a/shared/src/ledger/storage/ics23_specs.rs b/shared/src/ledger/storage/ics23_specs.rs index e1cede8ec2..3bb1680bad 100644 --- a/shared/src/ledger/storage/ics23_specs.rs +++ b/shared/src/ledger/storage/ics23_specs.rs @@ -1,9 +1,7 @@ //! A module that contains use arse_merkle_tree::H256; -use ics23::{ - CommitmentProof, ExistenceProof, HashOp, LeafOp, LengthOp, ProofSpec, -}; +use ics23::{HashOp, LeafOp, LengthOp, ProofSpec}; use super::traits::StorageHasher; @@ -54,7 +52,7 @@ pub fn ibc_proof_specs() -> Vec { ..spec.clone() }; let base_tree_spec = ProofSpec { - leaf_spec: Some(base_leaf_spec()), + leaf_spec: Some(base_leaf_spec::()), ..spec }; vec![sub_tree_spec, base_tree_spec] @@ -64,11 +62,11 @@ pub fn ibc_proof_specs() -> Vec { pub fn proof_specs() -> Vec { let spec = arse_merkle_tree::proof_ics23::get_spec(H::hash_op()); let sub_tree_spec = ProofSpec { - leaf_spec: Some(leaf_spec::()), + leaf_spec: Some(leaf_spec::()), ..spec.clone() }; let base_tree_spec = ProofSpec { - leaf_spec: Some(base_leaf_spec::()), + leaf_spec: Some(base_leaf_spec::()), ..spec }; vec![sub_tree_spec, base_tree_spec] diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index 58b05faa2f..92637476b8 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -1,37 +1,28 @@ //! The merkle tree in the storage -use std::convert::{TryFrom, TryInto}; use std::fmt; -use std::marker::PhantomData; -use std::slice::from_ref; use std::str::FromStr; use arse_merkle_tree::default_store::DefaultStore; use arse_merkle_tree::error::Error as MtError; -use arse_merkle_tree::traits::{Hasher, Value}; use arse_merkle_tree::{ Hash as SmtHash, Key as TreeKey, SparseMerkleTree as ArseMerkleTree, H256, }; use borsh::{BorshDeserialize, BorshSerialize}; use ics23::commitment_proof::Proof as Ics23Proof; -use ics23::{ - CommitmentProof, ExistenceProof, HashOp, LeafOp, LengthOp, - NonExistenceProof, ProofSpec, -}; -use itertools::{Either, Itertools}; +use ics23::{CommitmentProof, ExistenceProof, NonExistenceProof}; use prost::Message; -use sha2::{Digest, Sha256}; use tendermint::merkle::proof::{Proof, ProofOp}; use thiserror::Error; -use super::traits::{self, Sha256Hasher, StorageHasher}; +use super::traits::{StorageHasher, SubTreeRead, SubTreeWrite}; use super::IBC_KEY_LIMIT; use crate::bytes::ByteBuf; use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; +use crate::ledger::storage::ics23_specs::ibc_leaf_spec; use crate::ledger::storage::{ics23_specs, types}; use crate::types::address::{Address, InternalAddress}; -use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; -use crate::types::ethereum_events::KeccakHash; use crate::types::hash::Hash; +use crate::types::keccak::KeccakHash; use crate::types::storage::{ DbKeySeg, Error as StorageError, Key, MembershipProof, MerkleValue, StringKey, TreeBytes, @@ -107,7 +98,7 @@ pub enum Store { /// For PoS-related data PoS(SmtStore), /// For the Ethereum bridge Pool transfers - BridgePool(BTreeSetStore), + BridgePool(BridgePoolStore), } impl Store { @@ -133,7 +124,7 @@ pub enum StoreRef<'a> { /// For PoS-related data PoS(&'a SmtStore), /// For the Ethereum bridge Pool transfers - BridgePool(&'a BTreeSetStore), + BridgePool(&'a BridgePoolStore), } impl<'a> StoreRef<'a> { @@ -287,40 +278,40 @@ impl MerkleTree { } } - fn tree(&self, store_type: &StoreType) -> &impl traits::MerkleTree { + fn tree(&self, store_type: &StoreType) -> Box { match store_type { - StoreType::Base => &self.base, - StoreType::Account => &self.account, - StoreType::Ibc => &self.ibc, - StoreType::PoS => &self.pos, - StoreType::BridgePool => &self.bridge_pool, + StoreType::Base => Box::new(&self.base), + StoreType::Account => Box::new(&self.account), + StoreType::Ibc => Box::new(&self.ibc), + StoreType::PoS => Box::new(&self.pos), + StoreType::BridgePool => Box::new(&self.bridge_pool), } } fn tree_mut( &mut self, store_type: &StoreType, - ) -> &mut impl traits::MerkleTree { + ) -> Box { match store_type { - StoreType::Base => &mut self.base, - StoreType::Account => &mut self.account, - StoreType::Ibc => &mut self.ibc, - StoreType::PoS => &mut self.pos, - StoreType::BridgePool => &mut self.bridge_pool, + StoreType::Base => Box::new(&mut self.base), + StoreType::Account => Box::new(&mut self.account), + StoreType::Ibc => Box::new(&mut self.ibc), + StoreType::PoS => Box::new(&mut self.pos), + StoreType::BridgePool => Box::new(&mut self.bridge_pool), } } - fn update_tree>( + fn update_tree( &mut self, store_type: &StoreType, key: &Key, - value: MerkleValue, + value: MerkleValue, ) -> Result<()> { - let sub_root = self.tree_mut(store_type).update(key, value)?; + let sub_root = self.tree_mut(store_type).subtree_update(key, value)?; // update the base tree with the updated sub root without hashing if *store_type != StoreType::Base { let base_key = H::hash(&store_type.to_string()); - self.base.update(base_key.into(), Hash::from(sub_root))?; + self.base.update(base_key.into(), sub_root)?; } Ok(()) } @@ -328,23 +319,23 @@ impl MerkleTree { /// Check if the key exists in the tree pub fn has_key(&self, key: &Key) -> Result { let (store_type, sub_key) = StoreType::sub_key(key)?; - self.tree(&store_type).has_key(&sub_key) + self.tree(&store_type).subtree_has_key(&sub_key) } /// Update the tree with the given key and value - pub fn update>( + pub fn update( &mut self, key: &Key, - value: impl Into>, + value: impl Into, ) -> Result<()> { let (store_type, sub_key) = StoreType::sub_key(key)?; - self.update_tree(&store_type, sub_key.into(), value.into()) + self.update_tree(&store_type, &sub_key, value.into()) } /// Delete the value corresponding to the given key pub fn delete(&mut self, key: &Key) -> Result<()> { let (store_type, sub_key) = StoreType::sub_key(key)?; - self.tree_mut(&store_type).delete(&sub_key) + self.tree_mut(&store_type).subtree_delete(&sub_key) } /// Get the root @@ -364,14 +355,16 @@ impl MerkleTree { } /// Get the existence proof from a sub-tree - pub fn get_sub_tree_existence_proof>( + pub fn get_sub_tree_existence_proof( &self, keys: &[Key], - values: Vec>, + values: Vec, ) -> Result { - let first_key = keys.iter().next().ok_or(Error::InvalidMerkleKey( - "No keys provided for existence proof.".into(), - ))?; + let first_key = keys.iter().next().ok_or_else(|| { + Error::InvalidMerkleKey( + "No keys provided for existence proof.".into(), + ) + })?; let (store_type, _) = StoreType::sub_key(first_key)?; if !keys.iter().all(|k| { if let Ok((s, _)) = StoreType::sub_key(k) { @@ -386,7 +379,8 @@ impl MerkleTree { .into(), )); } - self.tree(&store_type).membership_proof(keys, values) + self.tree(&store_type) + .subtree_membership_proof(keys, values) } /// Get the non-existence proof @@ -396,8 +390,9 @@ impl MerkleTree { return Err(Error::NonExistenceProof(store_type.to_string())); } - let key = StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; - let mut nep = self.ibc.non_membership_proof(&key)?; + let string_key = + StringKey::try_from_bytes(sub_key.to_string().as_bytes())?; + let mut nep = self.ibc.non_membership_proof(&string_key)?; // Replace the values and the leaf op for the verification if let Some(ref mut nep) = nep.proof { match nep { @@ -410,19 +405,20 @@ impl MerkleTree { let ep = left.as_mut().or(right.as_mut()).expect( "A left or right existence proof should exist.", ); - ep.leaf = Some(self.ibc_leaf_spec()); + ep.leaf = Some(ibc_leaf_spec::()); } _ => unreachable!(), } } // Get a proof of the sub tree - self.get_proof(key, sub_proof) + self.get_tendermint_proof(key, nep) } /// Get the Tendermint proof with the base proof - pub fn get_tendermint_proof>( + pub fn get_tendermint_proof( &self, + key: &Key, sub_proof: CommitmentProof, ) -> Result { let mut data = vec![]; @@ -499,7 +495,7 @@ pub struct MerkleTreeStoresRead { account: (Hash, SmtStore), ibc: (Hash, AmtStore), pos: (Hash, SmtStore), - bridge_pool: (KeccakHash, BTreeSetStore), + bridge_pool: (KeccakHash, BridgePoolStore), } impl MerkleTreeStoresRead { @@ -532,7 +528,7 @@ pub struct MerkleTreeStoresWrite<'a> { account: (Hash, &'a SmtStore), ibc: (Hash, &'a AmtStore), pos: (Hash, &'a SmtStore), - bridge_pool: (Hash, &'a BTreeSetStore), + bridge_pool: (Hash, &'a BridgePoolStore), } impl<'a> MerkleTreeStoresWrite<'a> { @@ -567,228 +563,228 @@ impl From for Error { impl From for Error { fn from(error: MtError) -> Self { - Error::MerkleTree(error) + Error::MerkleTree(error.to_string()) } } -#[cfg(test)] -mod test { - use super::*; - use crate::types::storage::KeySeg; - - #[test] - fn test_crud_value() { - let mut tree = MerkleTree::::default(); - let key_prefix: Key = - Address::Internal(InternalAddress::Ibc).to_db_key().into(); - let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); - let key_prefix: Key = - Address::Internal(InternalAddress::PoS).to_db_key().into(); - let pos_key = key_prefix.push(&"test".to_string()).unwrap(); - - assert!(!tree.has_key(&ibc_key).unwrap()); - assert!(!tree.has_key(&pos_key).unwrap()); - - // update IBC tree - tree.update(&ibc_key, [1u8; 8]).unwrap(); - assert!(tree.has_key(&ibc_key).unwrap()); - assert!(!tree.has_key(&pos_key).unwrap()); - // update another tree - tree.update(&pos_key, [2u8; 8]).unwrap(); - assert!(tree.has_key(&pos_key).unwrap()); - - // delete a value on IBC tree - tree.delete(&ibc_key).unwrap(); - assert!(!tree.has_key(&ibc_key).unwrap()); - assert!(tree.has_key(&pos_key).unwrap()); - } - - #[test] - fn test_restore_tree() { - let mut tree = MerkleTree::::default(); - - let key_prefix: Key = - Address::Internal(InternalAddress::Ibc).to_db_key().into(); - let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); - let key_prefix: Key = - Address::Internal(InternalAddress::PoS).to_db_key().into(); - let pos_key = key_prefix.push(&"test".to_string()).unwrap(); - - tree.update(&ibc_key, [1u8; 8]).unwrap(); - tree.update(&pos_key, [2u8; 8]).unwrap(); - - let stores_write = tree.stores(); - let mut stores_read = MerkleTreeStoresRead::default(); - for st in StoreType::iter() { - stores_read.set_root(st, stores_write.root(st).clone()); - stores_read.set_store(stores_write.store(st).to_owned()); - } - let restored_tree = MerkleTree::::new(stores_read); - assert!(restored_tree.has_key(&ibc_key).unwrap()); - assert!(restored_tree.has_key(&pos_key).unwrap()); - } - - #[test] - fn test_ibc_existence_proof() { - let mut tree = MerkleTree::::default(); - - let key_prefix: Key = - Address::Internal(InternalAddress::Ibc).to_db_key().into(); - let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); - let key_prefix: Key = - Address::Internal(InternalAddress::PoS).to_db_key().into(); - let pos_key = key_prefix.push(&"test".to_string()).unwrap(); - - let ibc_val = [1u8; 8].to_vec(); - tree.update(&ibc_key, ibc_val.clone()).unwrap(); - let pos_val = [2u8; 8].to_vec(); - tree.update(&pos_key, pos_val).unwrap(); - - let specs = tree.ibc_proof_specs(); - let proof = - tree.get_existence_proof(&ibc_key, ibc_val.clone()).unwrap(); - let (store_type, sub_key) = StoreType::sub_key(&ibc_key).unwrap(); - let paths = vec![sub_key.to_string(), store_type.to_string()]; - let mut sub_root = ibc_val.clone(); - let mut value = ibc_val; - // First, the sub proof is verified. Next the base proof is verified - // with the sub root - for ((p, spec), key) in - proof.ops.iter().zip(specs.iter()).zip(paths.iter()) - { - let commitment_proof = CommitmentProof::decode(&*p.data).unwrap(); - let existence_proof = match commitment_proof.clone().proof.unwrap() - { - Ics23Proof::Exist(ep) => ep, - _ => unreachable!(), - }; - sub_root = - ics23::calculate_existence_root(&existence_proof).unwrap(); - assert!(ics23::verify_membership( - &commitment_proof, - spec, - &sub_root, - key.as_bytes(), - &value, - )); - // for the verification of the base tree - value = sub_root.clone(); - } - // Check the base root - assert_eq!(sub_root, tree.root().0); - } - - #[test] - fn test_non_ibc_existence_proof() { - let mut tree = MerkleTree::::default(); - - let key_prefix: Key = - Address::Internal(InternalAddress::Ibc).to_db_key().into(); - let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); - let key_prefix: Key = - Address::Internal(InternalAddress::PoS).to_db_key().into(); - let pos_key = key_prefix.push(&"test".to_string()).unwrap(); - - let ibc_val = [1u8; 8].to_vec(); - tree.update(&ibc_key, ibc_val).unwrap(); - let pos_val = [2u8; 8].to_vec(); - tree.update(&pos_key, pos_val.clone()).unwrap(); - - let specs = tree.proof_specs(); - let proof = - tree.get_existence_proof(&pos_key, pos_val.clone()).unwrap(); - let (store_type, sub_key) = StoreType::sub_key(&pos_key).unwrap(); - let paths = vec![sub_key.to_string(), store_type.to_string()]; - let mut sub_root = pos_val.clone(); - let mut value = pos_val; - // First, the sub proof is verified. Next the base proof is verified - // with the sub root - for ((p, spec), key) in - proof.ops.iter().zip(specs.iter()).zip(paths.iter()) - { - let commitment_proof = CommitmentProof::decode(&*p.data).unwrap(); - let existence_proof = match commitment_proof.clone().proof.unwrap() - { - Ics23Proof::Exist(ep) => ep, - _ => unreachable!(), - }; - sub_root = - ics23::calculate_existence_root(&existence_proof).unwrap(); - assert!(ics23::verify_membership( - &commitment_proof, - spec, - &sub_root, - key.as_bytes(), - &value, - )); - // for the verification of the base tree - value = sub_root.clone(); - } - // Check the base root - assert_eq!(sub_root, tree.root().0); - } - - #[test] - fn test_ibc_non_existence_proof() { - let mut tree = MerkleTree::::default(); - - let key_prefix: Key = - Address::Internal(InternalAddress::Ibc).to_db_key().into(); - let ibc_non_key = - key_prefix.push(&"test".to_string()).expect("Test failed"); - let key_prefix: Key = - Address::Internal(InternalAddress::Ibc).to_db_key().into(); - let ibc_key = - key_prefix.push(&"test2".to_string()).expect("Test failed"); - let ibc_val = [2u8; 8].to_vec(); - tree.update(&ibc_key, ibc_val).expect("Test failed"); - - let nep = tree - .get_non_existence_proof(&ibc_non_key) - .expect("Test failed"); - let subtree_nep = nep.ops.get(0).expect("Test failed"); - let nep_commitment_proof = - CommitmentProof::decode(&*subtree_nep.data).expect("Test failed"); - let non_existence_proof = - match nep_commitment_proof.clone().proof.expect("Test failed") { - Ics23Proof::Nonexist(nep) => nep, - _ => unreachable!(), - }; - let subtree_root = if let Some(left) = &non_existence_proof.left { - ics23::calculate_existence_root(left).unwrap() - } else if let Some(right) = &non_existence_proof.right { - ics23::calculate_existence_root(right).unwrap() - } else { - unreachable!() - }; - let (store_type, sub_key) = - StoreType::sub_key(&ibc_non_key).expect("Test failed"); - let specs = tree.ibc_proof_specs(); - - let nep_verification_res = ics23::verify_non_membership( - &nep_commitment_proof, - &specs[0], - &subtree_root, - sub_key.to_string().as_bytes(), - ); - assert!(nep_verification_res); - let basetree_ep = nep.ops.get(1).unwrap(); - let basetree_ep_commitment_proof = - CommitmentProof::decode(&*basetree_ep.data).unwrap(); - let basetree_ics23_ep = - match basetree_ep_commitment_proof.clone().proof.unwrap() { - Ics23Proof::Exist(ep) => ep, - _ => unreachable!(), - }; - let basetree_root = - ics23::calculate_existence_root(&basetree_ics23_ep).unwrap(); - let basetree_verification_res = ics23::verify_membership( - &basetree_ep_commitment_proof, - &specs[1], - &basetree_root, - store_type.to_string().as_bytes(), - &subtree_root, - ); - assert!(basetree_verification_res); - } -} +// #[cfg(test)] +// mod test { +// use super::*; +// use crate::types::storage::KeySeg; +// +// #[test] +// fn test_crud_value() { +// let mut tree = MerkleTree::::default(); +// let key_prefix: Key = +// Address::Internal(InternalAddress::Ibc).to_db_key().into(); +// let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); +// let key_prefix: Key = +// Address::Internal(InternalAddress::PoS).to_db_key().into(); +// let pos_key = key_prefix.push(&"test".to_string()).unwrap(); +// +// assert!(!tree.has_key(&ibc_key).unwrap()); +// assert!(!tree.has_key(&pos_key).unwrap()); +// +// update IBC tree +// tree.update(&ibc_key, [1u8; 8]).unwrap(); +// assert!(tree.has_key(&ibc_key).unwrap()); +// assert!(!tree.has_key(&pos_key).unwrap()); +// update another tree +// tree.update(&pos_key, [2u8; 8]).unwrap(); +// assert!(tree.has_key(&pos_key).unwrap()); +// +// delete a value on IBC tree +// tree.delete(&ibc_key).unwrap(); +// assert!(!tree.has_key(&ibc_key).unwrap()); +// assert!(tree.has_key(&pos_key).unwrap()); +// } +// +// #[test] +// fn test_restore_tree() { +// let mut tree = MerkleTree::::default(); +// +// let key_prefix: Key = +// Address::Internal(InternalAddress::Ibc).to_db_key().into(); +// let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); +// let key_prefix: Key = +// Address::Internal(InternalAddress::PoS).to_db_key().into(); +// let pos_key = key_prefix.push(&"test".to_string()).unwrap(); +// +// tree.update(&ibc_key, [1u8; 8]).unwrap(); +// tree.update(&pos_key, [2u8; 8]).unwrap(); +// +// let stores_write = tree.stores(); +// let mut stores_read = MerkleTreeStoresRead::default(); +// for st in StoreType::iter() { +// stores_read.set_root(st, stores_write.root(st).clone()); +// stores_read.set_store(stores_write.store(st).to_owned()); +// } +// let restored_tree = MerkleTree::::new(stores_read); +// assert!(restored_tree.has_key(&ibc_key).unwrap()); +// assert!(restored_tree.has_key(&pos_key).unwrap()); +// } +// +// #[test] +// fn test_ibc_existence_proof() { +// let mut tree = MerkleTree::::default(); +// +// let key_prefix: Key = +// Address::Internal(InternalAddress::Ibc).to_db_key().into(); +// let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); +// let key_prefix: Key = +// Address::Internal(InternalAddress::PoS).to_db_key().into(); +// let pos_key = key_prefix.push(&"test".to_string()).unwrap(); +// +// let ibc_val = [1u8; 8].to_vec(); +// tree.update(&ibc_key, ibc_val.clone()).unwrap(); +// let pos_val = [2u8; 8].to_vec(); +// tree.update(&pos_key, pos_val).unwrap(); +// +// let specs = tree.ibc_proof_specs(); +// let proof = +// tree.get_existence_proof(&ibc_key, ibc_val.clone()).unwrap(); +// let (store_type, sub_key) = StoreType::sub_key(&ibc_key).unwrap(); +// let paths = vec![sub_key.to_string(), store_type.to_string()]; +// let mut sub_root = ibc_val.clone(); +// let mut value = ibc_val; +// First, the sub proof is verified. Next the base proof is verified +// with the sub root +// for ((p, spec), key) in +// proof.ops.iter().zip(specs.iter()).zip(paths.iter()) +// { +// let commitment_proof = CommitmentProof::decode(&*p.data).unwrap(); +// let existence_proof = match commitment_proof.clone().proof.unwrap() +// { +// Ics23Proof::Exist(ep) => ep, +// _ => unreachable!(), +// }; +// sub_root = +// ics23::calculate_existence_root(&existence_proof).unwrap(); +// assert!(ics23::verify_membership( +// &commitment_proof, +// spec, +// &sub_root, +// key.as_bytes(), +// &value, +// )); +// for the verification of the base tree +// value = sub_root.clone(); +// } +// Check the base root +// assert_eq!(sub_root, tree.root().0); +// } +// +// #[test] +// fn test_non_ibc_existence_proof() { +// let mut tree = MerkleTree::::default(); +// +// let key_prefix: Key = +// Address::Internal(InternalAddress::Ibc).to_db_key().into(); +// let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); +// let key_prefix: Key = +// Address::Internal(InternalAddress::PoS).to_db_key().into(); +// let pos_key = key_prefix.push(&"test".to_string()).unwrap(); +// +// let ibc_val = [1u8; 8].to_vec(); +// tree.update(&ibc_key, ibc_val).unwrap(); +// let pos_val = [2u8; 8].to_vec(); +// tree.update(&pos_key, pos_val.clone()).unwrap(); +// +// let specs = tree.proof_specs(); +// let proof = +// tree.get_existence_proof(&pos_key, pos_val.clone()).unwrap(); +// let (store_type, sub_key) = StoreType::sub_key(&pos_key).unwrap(); +// let paths = vec![sub_key.to_string(), store_type.to_string()]; +// let mut sub_root = pos_val.clone(); +// let mut value = pos_val; +// First, the sub proof is verified. Next the base proof is verified +// with the sub root +// for ((p, spec), key) in +// proof.ops.iter().zip(specs.iter()).zip(paths.iter()) +// { +// let commitment_proof = CommitmentProof::decode(&*p.data).unwrap(); +// let existence_proof = match commitment_proof.clone().proof.unwrap() +// { +// Ics23Proof::Exist(ep) => ep, +// _ => unreachable!(), +// }; +// sub_root = +// ics23::calculate_existence_root(&existence_proof).unwrap(); +// assert!(ics23::verify_membership( +// &commitment_proof, +// spec, +// &sub_root, +// key.as_bytes(), +// &value, +// )); +// for the verification of the base tree +// value = sub_root.clone(); +// } +// Check the base root +// assert_eq!(sub_root, tree.root().0); +// } +// +// #[test] +// fn test_ibc_non_existence_proof() { +// let mut tree = MerkleTree::::default(); +// +// let key_prefix: Key = +// Address::Internal(InternalAddress::Ibc).to_db_key().into(); +// let ibc_non_key = +// key_prefix.push(&"test".to_string()).expect("Test failed"); +// let key_prefix: Key = +// Address::Internal(InternalAddress::Ibc).to_db_key().into(); +// let ibc_key = +// key_prefix.push(&"test2".to_string()).expect("Test failed"); +// let ibc_val = [2u8; 8].to_vec(); +// tree.update(&ibc_key, ibc_val).expect("Test failed"); +// +// let nep = tree +// .get_non_existence_proof(&ibc_non_key) +// .expect("Test failed"); +// let subtree_nep = nep.ops.get(0).expect("Test failed"); +// let nep_commitment_proof = +// CommitmentProof::decode(&*subtree_nep.data).expect("Test failed"); +// let non_existence_proof = +// match nep_commitment_proof.clone().proof.expect("Test failed") { +// Ics23Proof::Nonexist(nep) => nep, +// _ => unreachable!(), +// }; +// let subtree_root = if let Some(left) = &non_existence_proof.left { +// ics23::calculate_existence_root(left).unwrap() +// } else if let Some(right) = &non_existence_proof.right { +// ics23::calculate_existence_root(right).unwrap() +// } else { +// unreachable!() +// }; +// let (store_type, sub_key) = +// StoreType::sub_key(&ibc_non_key).expect("Test failed"); +// let specs = tree.ibc_proof_specs(); +// +// let nep_verification_res = ics23::verify_non_membership( +// &nep_commitment_proof, +// &specs[0], +// &subtree_root, +// sub_key.to_string().as_bytes(), +// ); +// assert!(nep_verification_res); +// let basetree_ep = nep.ops.get(1).unwrap(); +// let basetree_ep_commitment_proof = +// CommitmentProof::decode(&*basetree_ep.data).unwrap(); +// let basetree_ics23_ep = +// match basetree_ep_commitment_proof.clone().proof.unwrap() { +// Ics23Proof::Exist(ep) => ep, +// _ => unreachable!(), +// }; +// let basetree_root = +// ics23::calculate_existence_root(&basetree_ics23_ep).unwrap(); +// let basetree_verification_res = ics23::verify_membership( +// &basetree_ep_commitment_proof, +// &specs[1], +// &basetree_root, +// store_type.to_string().as_bytes(), +// &subtree_root, +// ); +// assert!(basetree_verification_res); +// } +// } diff --git a/shared/src/ledger/storage/mod.rs b/shared/src/ledger/storage/mod.rs index 74826fba3c..74bde36b0f 100644 --- a/shared/src/ledger/storage/mod.rs +++ b/shared/src/ledger/storage/mod.rs @@ -9,6 +9,7 @@ pub mod types; pub mod write_log; use core::fmt::Debug; +use std::array; use thiserror::Error; @@ -20,9 +21,9 @@ use crate::ledger::storage::merkle_tree::{ Error as MerkleTreeError, MerkleRoot, }; pub use crate::ledger::storage::merkle_tree::{ - MerkleTree, MerkleTreeStoresRead, MerkleTreeStoresWrite, Sha256Hasher, - StorageHasher, StoreType, + MerkleTree, MerkleTreeStoresRead, MerkleTreeStoresWrite, StoreType, }; +use crate::ledger::storage::traits::StorageHasher; use crate::tendermint::merkle::proof::Proof; use crate::types::address::{Address, EstablishedAddressGen, InternalAddress}; use crate::types::chain::{ChainId, CHAIN_ID_LENGTH}; @@ -30,7 +31,7 @@ use crate::types::chain::{ChainId, CHAIN_ID_LENGTH}; use crate::types::storage::TxQueue; use crate::types::storage::{ BlockHash, BlockHeight, Epoch, Epochs, Header, Key, KeySeg, - BLOCK_HASH_LENGTH, + MembershipProof, MerkleValue, BLOCK_HASH_LENGTH, }; use crate::types::time::DateTimeUtc; @@ -509,15 +510,21 @@ where pub fn get_existence_proof( &self, key: &Key, - value: Vec, + value: MerkleValue, height: BlockHeight, - ) -> Result { + ) -> Result { if height >= self.get_block_height().0 { - Ok(self.block.tree.get_existence_proof(key, value)?) + Ok(self.block.tree.get_sub_tree_existence_proof( + array::from_ref(key), + vec![value], + )?) } else { match self.db.read_merkle_tree_stores(height)? { Some(stores) => Ok(MerkleTree::::new(stores) - .get_existence_proof(key, value)?), + .get_sub_tree_existence_proof( + array::from_ref(key), + vec![value], + )?), None => Err(Error::NoMerkleTree { height }), } } @@ -696,11 +703,9 @@ impl From for Error { /// Helpers for testing components that depend on storage #[cfg(any(test, feature = "testing"))] pub mod testing { - use merkle_tree::Sha256Hasher; - use super::mockdb::MockDB; use super::*; - + use crate::ledger::storage::traits::Sha256Hasher; /// Storage with a mock DB for testing pub type TestStorage = Storage; diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs index c558c7cbe9..907aab2ed9 100644 --- a/shared/src/ledger/storage/traits.rs +++ b/shared/src/ledger/storage/traits.rs @@ -4,7 +4,7 @@ use std::convert::{TryFrom, TryInto}; use std::fmt; use arse_merkle_tree::traits::{Hasher, Value}; -use arse_merkle_tree::{Hash as SmtHash, Key as TreeKey, H256}; +use arse_merkle_tree::{Key as TreeKey, H256}; use ics23::commitment_proof::Proof as Ics23Proof; use ics23::{CommitmentProof, ExistenceProof}; use sha2::{Digest, Sha256}; @@ -12,71 +12,55 @@ use sha2::{Digest, Sha256}; use super::merkle_tree::{Amt, Error, Smt}; use super::{ics23_specs, IBC_KEY_LIMIT}; use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; -use crate::types::eth_bridge_pool::PendingTransfer; use crate::types::hash::Hash; use crate::types::storage::{ Key, MembershipProof, MerkleValue, StringKey, TreeBytes, }; -pub trait MerkleTree { - type Error; - - fn has_key(&self, key: &Key) -> Result; - fn update>( - &mut self, - key: &Key, - value: MerkleValue, - ) -> Result; - fn delete(&mut self, key: &Key) -> Result<(), Self::Error>; - fn membership_proof>( +/// Trait for reading from a merkle tree that is a sub-tree +/// of the global merkle tree. +pub trait SubTreeRead { + /// Check if a key is present in the sub-tree + fn subtree_has_key(&self, key: &Key) -> Result; + /// Get a membership proof for various key-value pairs + fn subtree_membership_proof( &self, keys: &[Key], - values: Vec>, - ) -> Result; + values: Vec, + ) -> Result; } -impl MerkleTree for Smt { - type Error = Error; - - fn has_key(&self, key: &Key) -> Result { - self.get(&H::hash(key.to_string()).into()) - .and(Ok(true)) - .map_error(|err| Error::MerkleTree(err.to_string())) - } - - fn update>( +/// Trait for updating a merkle tree that is a sub-tree +/// of the global merkle tree +pub trait SubTreeWrite { + /// Add a key-value pair to the sub-tree + fn subtree_update( &mut self, key: &Key, - value: MerkleValue, - ) -> Result { - let value = match value { - MerkleValue::Bytes(bytes) => Hash::try_from(bytes.as_ref()) - .map_err(|| Error::InvalidValue)?, - _ => return Err(Error::InvalidValue), - }; - self.update(H::hash(key.to_string()).into(), value) - .map(Hash::into) - .map_err(|err| Error::MerkleTree(err.to_string())) - } + value: MerkleValue, + ) -> Result; + /// Delete a key from the sub-tree + fn subtree_delete(&mut self, key: &Key) -> Result<(), Error>; +} - fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { - let value = Hash::zero(); - self.update(H::hash(key.to_string()).into(), value) - .and(Ok(())) +impl<'a, H: StorageHasher + Default> SubTreeRead for &'a Smt { + fn subtree_has_key(&self, key: &Key) -> Result { + self.get(&H::hash(key.to_string()).into()) + .and(Ok(true)) .map_err(|err| Error::MerkleTree(err.to_string())) } - fn membership_proof>( + fn subtree_membership_proof( &self, keys: &[Key], - mut values: Vec>, - ) -> Result { + mut values: Vec, + ) -> Result { if keys.len() != 1 || values.len() != 1 { return Err(Error::Ics23MultiLeaf); } let key: &Key = &keys[0]; let value = match values.remove(0) { - MerkleValue::Bytes(b) => b.as_ref().to_vec(), + MerkleValue::Bytes(b) => b, _ => return Err(Error::InvalidValue), }; let cp = self.membership_proof(&H::hash(key.to_string()).into())?; @@ -97,51 +81,48 @@ impl MerkleTree for Smt { } } -impl MerkleTree for Amt { - type Error = Error; - - fn has_key(&self, key: &Key) -> Result { - let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; - self.get(&key) - .and(Ok(bool)) - .map_err(|err| Error::MerkleTree(err.to_string())) - } - - fn update>( +impl<'a, H: StorageHasher + Default> SubTreeWrite for &'a mut Smt { + fn subtree_update( &mut self, - key: MerkleKey, - value: MerkleValue, - ) -> Result { - let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; + key: &Key, + value: MerkleValue, + ) -> Result { let value = match value { - MerkleValue::Bytes(bytes) => { - TreeBytes::from(bytes.as_ref().to_vec()) - } + MerkleValue::Bytes(bytes) => Hash::try_from(bytes.as_slice()) + .map_err(|_| Error::InvalidValue)?, _ => return Err(Error::InvalidValue), }; - self.update(key, value) - .map(Into::into) + self.update(H::hash(key.to_string()).into(), value) + .map(Hash::from) .map_err(|err| Error::MerkleTree(err.to_string())) } - fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { - let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; - let value = TreeBytes::zero(); - self.update(key, value) + fn subtree_delete(&mut self, key: &Key) -> Result<(), Error> { + let value = Hash::zero(); + self.update(H::hash(key.to_string()).into(), value) .and(Ok(())) - .map_err(|err| Error::MerkleTree(format!("{:?}", err))) + .map_err(|err| Error::MerkleTree(err.to_string())) } +} - fn membership_proof>( +impl<'a, H: StorageHasher + Default> SubTreeRead for &'a Amt { + fn subtree_has_key(&self, key: &Key) -> Result { + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; + self.get(&key) + .and(Ok(true)) + .map_err(|err| Error::MerkleTree(err.to_string())) + } + + fn subtree_membership_proof( &self, keys: &[Key], - _: Vec>, - ) -> Result { - if keys.len() != 1 || values.len() != 1 { + _: Vec, + ) -> Result { + if keys.len() != 1 { return Err(Error::Ics23MultiLeaf); } - let key = StringKey::try_from_bytes(&keys[0].to_string().as_bytes())?; + let key = StringKey::try_from_bytes(keys[0].to_string().as_bytes())?; let cp = self.membership_proof(&key)?; // Replace the values and the leaf op for the verification match cp.proof.expect("The proof should exist") { @@ -158,37 +139,42 @@ impl MerkleTree for Amt { } } -impl MerkleTree for BridgePoolTree { - type Error = Error; - - fn has_key(&self, key: &Key) -> Result { - self.has_key(key) +impl<'a, H: StorageHasher + Default> SubTreeWrite for &'a mut Amt { + fn subtree_update( + &mut self, + key: &Key, + value: MerkleValue, + ) -> Result { + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; + let value = match value { + MerkleValue::Bytes(bytes) => TreeBytes::from(bytes), + _ => return Err(Error::InvalidValue), + }; + self.update(key, value) + .map(Into::into) .map_err(|err| Error::MerkleTree(err.to_string())) } - fn update>( - &mut self, - key: &Key, - value: MerkleValue, - ) -> Result { - if let MerkleValue::Transfer(_) = value { - self.update(key) - .map_err(|err| Error::MerkleTree(err.to_string())) - } else { - Err(Error::InvalidValue) - } + fn subtree_delete(&mut self, key: &Key) -> Result<(), Error> { + let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; + let value = TreeBytes::zero(); + self.update(key, value) + .and(Ok(())) + .map_err(|err| Error::MerkleTree(format!("{:?}", err))) } +} - fn delete(&mut self, key: &Key) -> Result<(), Self::Error> { - self.delete(key) +impl<'a> SubTreeRead for &'a BridgePoolTree { + fn subtree_has_key(&self, key: &Key) -> Result { + self.contains_key(key) .map_err(|err| Error::MerkleTree(err.to_string())) } - fn membership_proof>( + fn subtree_membership_proof( &self, keys: &[Key], - values: Vec>, - ) -> Result { + values: Vec, + ) -> Result { let values = values .into_iter() .filter_map(|val| match val { @@ -196,12 +182,32 @@ impl MerkleTree for BridgePoolTree { _ => None, }) .collect(); - self.membership_proof(keys, values) + self.get_membership_proof(keys, values) .map(Into::into) .map_err(|err| Error::MerkleTree(err.to_string())) } } +impl<'a> SubTreeWrite for &'a mut BridgePoolTree { + fn subtree_update( + &mut self, + key: &Key, + value: MerkleValue, + ) -> Result { + if let MerkleValue::Transfer(_) = value { + self.update_key(key) + .map_err(|err| Error::MerkleTree(err.to_string())) + } else { + Err(Error::InvalidValue) + } + } + + fn subtree_delete(&mut self, key: &Key) -> Result<(), Error> { + self.delete_key(key) + .map_err(|err| Error::MerkleTree(err.to_string())) + } +} + impl TreeKey for StringKey { type Error = Error; diff --git a/shared/src/ledger/storage/write_log.rs b/shared/src/ledger/storage/write_log.rs index 098204b707..45940493a9 100644 --- a/shared/src/ledger/storage/write_log.rs +++ b/shared/src/ledger/storage/write_log.rs @@ -6,7 +6,8 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use thiserror::Error; use crate::ledger; -use crate::ledger::storage::{Storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::Storage; use crate::types::address::{Address, EstablishedAddressGen}; use crate::types::ibc::IbcEvent; use crate::types::storage; diff --git a/shared/src/ledger/treasury/mod.rs b/shared/src/ledger/treasury/mod.rs index 071019059b..35b4ce5022 100644 --- a/shared/src/ledger/treasury/mod.rs +++ b/shared/src/ledger/treasury/mod.rs @@ -12,7 +12,8 @@ use thiserror::Error; use self::storage as treasury_storage; use super::governance::vp::is_proposal_accepted; use crate::ledger::native_vp::{self, Ctx, NativeVp}; -use crate::ledger::storage::{self as ledger_storage, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self as ledger_storage}; use crate::types::address::{xan as nam, Address, InternalAddress}; use crate::types::storage::Key; use crate::types::token; diff --git a/shared/src/ledger/treasury/parameters.rs b/shared/src/ledger/treasury/parameters.rs index 2ccb142d09..11d3b6db5a 100644 --- a/shared/src/ledger/treasury/parameters.rs +++ b/shared/src/ledger/treasury/parameters.rs @@ -35,7 +35,7 @@ impl TreasuryParams { pub fn init_storage(&self, storage: &mut Storage) where DB: storage::DB + for<'iter> storage::DBIter<'iter>, - H: storage::StorageHasher, + H: storage::traits::StorageHasher, { let max_proposal_fund_transfer_key = treasury_storage::get_max_transferable_fund_key(); diff --git a/shared/src/ledger/vp_env.rs b/shared/src/ledger/vp_env.rs index 1f59613e54..aafd4b135a 100644 --- a/shared/src/ledger/vp_env.rs +++ b/shared/src/ledger/vp_env.rs @@ -8,8 +8,9 @@ use thiserror::Error; use super::gas::MIN_STORAGE_GAS; use crate::ledger::gas; use crate::ledger::gas::VpGasMeter; +use crate::ledger::storage::traits::StorageHasher; use crate::ledger::storage::write_log::WriteLog; -use crate::ledger::storage::{self, write_log, Storage, StorageHasher}; +use crate::ledger::storage::{self, write_log, Storage}; use crate::proto::Tx; use crate::types::hash::Hash; use crate::types::storage::{BlockHash, BlockHeight, Epoch, Key}; diff --git a/shared/src/types/eth_bridge_pool.rs b/shared/src/types/eth_bridge_pool.rs index 19c0f805cd..e7c55df8d8 100644 --- a/shared/src/types/eth_bridge_pool.rs +++ b/shared/src/types/eth_bridge_pool.rs @@ -4,8 +4,10 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use ethabi::token::Token; use crate::types::address::Address; -use crate::types::ethereum_events::{EthAddress, KeccakHash, Uint}; +use crate::types::ethereum_events::{EthAddress, Uint}; use crate::types::keccak; +use crate::types::keccak::encode::Encode; +use crate::types::storage::{DbKeySeg, Key}; use crate::types::token::Amount; /// A transfer message to be submitted to Ethereum @@ -59,11 +61,17 @@ impl keccak::encode::Encode for PendingTransfer { let fee = Token::Uint(u64::from(self.gas_fee.amount).into()); let to = Token::Address(self.transfer.recipient.0.into()); let amount = Token::Uint(u64::from(self.transfer.amount).into()); - let nonce = Token::Uint(self.transfer.nonce.into()); + let nonce = Token::Uint(self.transfer.nonce.clone().into()); vec![from, fee, to, amount, nonce] } } +impl From<&PendingTransfer> for Key { + fn from(transfer: &PendingTransfer) -> Self { + Key{segments: vec![DbKeySeg::StringSeg(transfer.keccak256().to_string())]} + } +} + /// The amount of NAM to be payed to the relayer of /// a transfer across the Ethereum Bridge to compensate /// for Ethereum gas fees. diff --git a/shared/src/types/hash.rs b/shared/src/types/hash.rs index f2a84f19eb..5a6abd146c 100644 --- a/shared/src/types/hash.rs +++ b/shared/src/types/hash.rs @@ -95,7 +95,7 @@ impl TryFrom for Hash { fn try_from(string: String) -> HashResult { let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; - Self::try_from(&bytes) + Self::try_from(bytes.as_slice()) } } @@ -105,7 +105,7 @@ impl TryFrom<&str> for Hash { fn try_from(string: &str) -> HashResult { let bytes: Vec = Vec::from_hex(string).map_err(Error::FromStringError)?; - Self::try_from(&bytes) + Self::try_from(bytes.as_slice()) } } diff --git a/shared/src/types/keccak.rs b/shared/src/types/keccak.rs index 06beb3adf1..a390bff3ce 100644 --- a/shared/src/types/keccak.rs +++ b/shared/src/types/keccak.rs @@ -7,6 +7,7 @@ use std::fmt::Display; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use hex::FromHex; use thiserror::Error; +use tiny_keccak::{Hasher, Keccak}; use crate::types::hash::{Hash, HASH_LENGTH}; @@ -26,6 +27,7 @@ pub enum TryFromError { #[derive( Clone, Debug, + Default, PartialEq, Eq, PartialOrd, diff --git a/shared/src/types/storage.rs b/shared/src/types/storage.rs index e13aa14dc5..db7cada8ec 100644 --- a/shared/src/types/storage.rs +++ b/shared/src/types/storage.rs @@ -2,7 +2,6 @@ use std::convert::{TryFrom, TryInto}; use std::fmt::Display; use std::io::Write; -use std::marker::PhantomData; use std::num::ParseIntError; use std::ops::{Add, Deref, Div, Mul, Rem, Sub}; use std::str::FromStr; @@ -17,9 +16,9 @@ use thiserror::Error; use super::transaction::WrapperTx; use crate::bytes::ByteBuf; use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolProof; -use crate::ledger::storage::{StorageHasher, IBC_KEY_LIMIT}; +use crate::ledger::storage::IBC_KEY_LIMIT; use crate::types::address::{self, Address}; -use crate::types::eth_bridge_pool::{PendingTransfer, TransferToEthereum}; +use crate::types::eth_bridge_pool::PendingTransfer; use crate::types::hash::Hash; use crate::types::time::DateTimeUtc; @@ -245,23 +244,23 @@ impl FromStr for Key { /// several Merkle trees, each of which is /// responsible for understanding how to parse /// this value. -pub enum MerkleValue> { +pub enum MerkleValue { /// raw bytes - Bytes(T), + Bytes(Vec), /// A transfer to be put in the Ethereum bridge pool. Transfer(PendingTransfer), } -impl From for MerkleValue +impl From for MerkleValue where T: AsRef<[u8]>, { fn from(bytes: T) -> Self { - Self::Bytes(bytes) + Self::Bytes(bytes.as_ref().to_owned()) } } -impl> From for MerkleValue { +impl From for MerkleValue { fn from(transfer: PendingTransfer) -> Self { Self::Transfer(transfer) } @@ -354,8 +353,8 @@ pub enum MembershipProof { BridgePool(BridgePoolProof), } -impl From for MembershipProof { - fn from(proof: CommitmenProof) -> Self { +impl From for MembershipProof { + fn from(proof: CommitmentProof) -> Self { Self::ICS23(proof) } } @@ -627,8 +626,9 @@ impl KeySeg for Address { impl KeySeg for Hash { fn parse(seg: String) -> Result { - seg.try_into() - .map_error(Error::ParseError((seg, "Hash".into()))) + seg.clone() + .try_into() + .map_err(|_| Error::ParseError(seg, "Hash".into())) } fn raw(&self) -> String { diff --git a/shared/src/vm/host_env.rs b/shared/src/vm/host_env.rs index ac9f89c31e..88bd81b918 100644 --- a/shared/src/vm/host_env.rs +++ b/shared/src/vm/host_env.rs @@ -13,8 +13,9 @@ use super::wasm::TxCache; use super::wasm::VpCache; use super::WasmCacheAccess; use crate::ledger::gas::{self, BlockGasMeter, VpGasMeter}; +use crate::ledger::storage::traits::StorageHasher; use crate::ledger::storage::write_log::{self, WriteLog}; -use crate::ledger::storage::{self, Storage, StorageHasher}; +use crate::ledger::storage::{self, Storage}; use crate::ledger::vp_env; use crate::proto::Tx; use crate::types::address::{self, Address}; @@ -1759,7 +1760,8 @@ pub mod testing { use std::collections::BTreeSet; use super::*; - use crate::ledger::storage::{self, StorageHasher}; + use crate::ledger::storage::traits::StorageHasher; + use crate::ledger::storage::{self}; use crate::vm::memory::testing::NativeMemory; /// Setup a transaction environment diff --git a/shared/src/vm/wasm/host_env.rs b/shared/src/vm/wasm/host_env.rs index 3b6715f383..3736c8a295 100644 --- a/shared/src/vm/wasm/host_env.rs +++ b/shared/src/vm/wasm/host_env.rs @@ -8,7 +8,8 @@ use wasmer::{ WasmerEnv, }; -use crate::ledger::storage::{self, StorageHasher}; +use crate::ledger::storage::traits::StorageHasher; +use crate::ledger::storage::{self}; use crate::vm::host_env::{TxEnv, VpEnv, VpEvaluator}; use crate::vm::wasm::memory::WasmMemory; use crate::vm::{host_env, WasmCacheAccess}; diff --git a/shared/src/vm/wasm/run.rs b/shared/src/vm/wasm/run.rs index 75fbfb4add..dbfdb4c961 100644 --- a/shared/src/vm/wasm/run.rs +++ b/shared/src/vm/wasm/run.rs @@ -11,8 +11,9 @@ use wasmer::BaseTunables; use super::memory::{Limit, WasmMemory}; use super::TxCache; use crate::ledger::gas::{BlockGasMeter, VpGasMeter}; +use crate::ledger::storage::traits::StorageHasher; use crate::ledger::storage::write_log::WriteLog; -use crate::ledger::storage::{self, Storage, StorageHasher}; +use crate::ledger::storage::{self, Storage}; use crate::proto::Tx; use crate::types::address::Address; use crate::types::internal::HostEnvResult; From 3543b63bbb0d099bf0d5a37f6715853ef0960ec5 Mon Sep 17 00:00:00 2001 From: satan Date: Mon, 3 Oct 2022 11:51:39 +0200 Subject: [PATCH 09/28] [feat]: Added proptests to the bridge tree proofs and corrected the bugs it found --- .../ledger/eth_bridge/storage/bridge_pool.rs | 140 +++++++++++++++++- 1 file changed, 135 insertions(+), 5 deletions(-) diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index 8bf13ab7aa..c09bdcb4e8 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -215,7 +215,7 @@ impl BridgePoolTree { hashes = next_hashes; } // add the root to the proof - if proof_hashes.is_empty() { + if flags.is_empty() && proof_hashes.is_empty() && leaves.is_empty() { proof_hashes.push(self.root.clone()); } @@ -297,9 +297,13 @@ impl BridgePoolProof { return false; } if self.flags.is_empty() { - return match self.proof.last() { - Some(proof_root) => &root == proof_root, - None => false, + return if let Some(leaf) = self.leaves.last() { + root == leaf.keccak256() + } else { + match self.proof.last() { + Some(proof_root) => &root == proof_root, + None => false, + } }; } let total_hashes = self.flags.len(); @@ -349,6 +353,10 @@ impl BridgePoolProof { #[cfg(test)] mod test_bridge_pool_tree { use std::array; + + use itertools::Itertools; + use proptest::prelude::*; + use super::*; use crate::types::ethereum_events::EthAddress; use crate::types::eth_bridge_pool::{GasFee, TransferToEthereum}; @@ -574,7 +582,7 @@ mod test_bridge_pool_tree { assert!(!tree.contains_key(&Key::from(&transfer)).expect("Test failed")); } - /// Test that the empty proof works + /// Test that the empty proof works. #[test] fn test_empty_proof() { let tree = BridgePoolTree::default(); @@ -584,6 +592,30 @@ mod test_bridge_pool_tree { assert!(proof.verify(Default::default())); } + /// Test that the proof works for proving the only leaf in the tree + #[test] + fn test_single_leaf() { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([0; 20]), + recipient: EthAddress([0; 20]), + amount: 0.into(), + nonce: 0.into() + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address() + } + }; + let mut tree = BridgePoolTree::default(); + let key = Key::from(&transfer); + let _ = tree.update_key(&key).expect("Test failed"); + let proof = tree.get_membership_proof(array::from_ref(&key), vec![transfer]).expect("Test failed"); + assert!(proof.verify(tree.root().into())); + } + + /// Check proofs for membership of single transfer + /// in a tree with two leaves. #[test] fn test_one_leaf_of_two_proof() { let mut tree = BridgePoolTree::default(); @@ -645,6 +677,7 @@ mod test_bridge_pool_tree { assert!(proof.verify(tree.root().into())); } + /// Test that proving an empty subset of leaves always works #[test] fn test_proof_no_leaves() { let mut tree = BridgePoolTree::default(); @@ -675,6 +708,34 @@ mod test_bridge_pool_tree { /// Test a proof for all the leaves #[test] fn test_proof_all_leaves() { + let mut tree = BridgePoolTree::default(); + let mut transfers = vec![]; + for i in 0..2 { + let transfer = PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress([i;20]), + recipient: EthAddress([i+1; 20]), + amount: (i as u64).into(), + nonce: 42u64.into(), + }, + gas_fee: GasFee { + amount: 0.into(), + payer: bertha_address(), + } + }; + let key = Key::from(&transfer); + transfers.push(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + transfers.sort_by_key(|t| t.keccak256()); + let keys: Vec<_> = transfers.iter().map(Key::from).collect(); + let proof = tree.get_membership_proof(&keys, transfers).expect("Test failed"); + assert!(proof.verify(tree.root().into())); + } + + /// Test a proof for all the leaves when the number of leaves is odd + #[test] + fn test_proof_all_leaves_odd() { let mut tree = BridgePoolTree::default(); let mut transfers = vec![]; for i in 0..3 { @@ -736,4 +797,73 @@ mod test_bridge_pool_tree { let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); assert!(proof.verify(tree.root().into())); } + + /// Create a random set of transfers. + fn random_transfers(number: usize) -> impl Strategy> { + prop::collection::vec( + ( + prop::array::uniform20(0u8..), + prop::num::u64::ANY, + ), + 0..=number, + ) + .prop_flat_map( | addrs | + Just( + addrs.into_iter().map(| (addr, nonce)| + PendingTransfer { + transfer: TransferToEthereum { + asset: EthAddress(addr.clone()), + recipient: EthAddress(addr), + amount: Default::default(), + nonce: nonce.into() + }, + gas_fee: GasFee { + amount: Default::default(), + payer: bertha_address() + } + }, + ) + .dedup() + .collect::>() + ) + ) + } + + prop_compose! { + /// Creates a random set of transfers and + /// then returns them along with a chosen subset. + fn arb_transfers_and_subset() + (transfers in random_transfers(50)) + ( + transfers in Just(transfers.clone()), + to_prove in proptest::sample::subsequence(transfers.clone(), 0..=transfers.len()), + ) + -> (Vec, Vec) { + (transfers, to_prove) + } + } + + proptest!{ + /// Given a random tree and a subset of leaves, + /// verify that the constructed multi-proof correctly + /// verifies. + #[test] + fn test_verify_proof((transfers, mut to_prove) in arb_transfers_and_subset()) { + let mut tree = BridgePoolTree::default(); + for transfer in &transfers { + let key = Key::from(transfer); + let _ = tree.update_key(&key).expect("Test failed"); + } + + to_prove.sort_by_key(|t| t.keccak256()); + let mut keys = vec![]; + let mut values = vec![]; + for transfer in to_prove.into_iter() { + keys.push(Key::from(&transfer)); + values.push(transfer); + } + let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + assert!(proof.verify(tree.root().into())); + } + } } \ No newline at end of file From 0d15fb38625fa21e44a517e1df9587e6452c78db Mon Sep 17 00:00:00 2001 From: satan Date: Fri, 7 Oct 2022 11:13:33 +0200 Subject: [PATCH 10/28] [feat]: Added multi-store logic and brige pool merkle tree --- apps/src/lib/node/ledger/protocol/mod.rs | 2 +- apps/src/lib/node/ledger/shell/mod.rs | 4 +- .../lib/node/ledger/shell/prepare_proposal.rs | 2 +- apps/src/lib/node/ledger/shell/queries.rs | 4 +- .../shell/vote_extensions/eth_events.rs | 2 +- .../shell/vote_extensions/val_set_update.rs | 2 +- apps/src/lib/node/ledger/storage/mod.rs | 2 +- apps/src/lib/node/ledger/storage/rocksdb.rs | 2 +- .../ledger/eth_bridge/storage/bridge_pool.rs | 10 +- shared/src/ledger/storage/ics23_specs.rs | 2 + shared/src/ledger/storage/merkle_tree.rs | 465 +++++++++--------- shared/src/ledger/storage/mod.rs | 44 +- shared/src/ledger/storage/traits.rs | 52 +- shared/src/types/hash.rs | 36 -- tests/src/native_vp/mod.rs | 2 +- tests/src/native_vp/pos.rs | 2 +- tests/src/vm_host_env/ibc.rs | 2 +- tests/src/vm_host_env/vp.rs | 2 +- wasm/checksums.json | 33 +- wasm/tx_template/Cargo.lock | 162 +----- wasm/vp_template/Cargo.lock | 162 +----- wasm/wasm_source/Cargo.lock | 162 +----- wasm_for_tests/wasm_source/Cargo.lock | 162 +----- 23 files changed, 386 insertions(+), 932 deletions(-) diff --git a/apps/src/lib/node/ledger/protocol/mod.rs b/apps/src/lib/node/ledger/protocol/mod.rs index 90bb6994b1..4d21e63ca4 100644 --- a/apps/src/lib/node/ledger/protocol/mod.rs +++ b/apps/src/lib/node/ledger/protocol/mod.rs @@ -11,7 +11,7 @@ use namada::ledger::native_vp::{self, NativeVp}; use namada::ledger::parameters::{self, ParametersVp}; use namada::ledger::pos::{self, PosVP}; use namada::ledger::storage::write_log::WriteLog; -use namada::ledger::storage::{DBIter, Storage, StorageHasher, DB}; +use namada::ledger::storage::{DB, DBIter, Storage, traits::StorageHasher}; use namada::ledger::treasury::TreasuryVp; use namada::proto::{self, Tx}; use namada::types::address::{Address, InternalAddress}; diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index 2be5913d96..aff407ba6b 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -28,7 +28,7 @@ use namada::ledger::pos::namada_proof_of_stake::types::{ use namada::ledger::pos::namada_proof_of_stake::PosBase; use namada::ledger::storage::write_log::WriteLog; use namada::ledger::storage::{ - DBIter, Sha256Hasher, Storage, StorageHasher, DB, + DBIter, traits::Sha256Hasher, Storage, traits::StorageHasher, DB, }; use namada::ledger::{ibc, parameters, pos}; use namada::proto::{self, Tx}; @@ -760,7 +760,7 @@ mod test_utils { #[cfg(not(feature = "abcipp"))] use namada::ledger::pos::namada_proof_of_stake::types::VotingPower; use namada::ledger::storage::mockdb::MockDB; - use namada::ledger::storage::{BlockStateWrite, MerkleTree, Sha256Hasher}; + use namada::ledger::storage::{BlockStateWrite, MerkleTree, traits::Sha256Hasher}; use namada::types::address::{xan, EstablishedAddressGen}; use namada::types::chain::ChainId; use namada::types::hash::Hash; diff --git a/apps/src/lib/node/ledger/shell/prepare_proposal.rs b/apps/src/lib/node/ledger/shell/prepare_proposal.rs index de33ebc38b..6880bd0598 100644 --- a/apps/src/lib/node/ledger/shell/prepare_proposal.rs +++ b/apps/src/lib/node/ledger/shell/prepare_proposal.rs @@ -1,6 +1,6 @@ //! Implementation of the [`RequestPrepareProposal`] ABCI++ method for the Shell -use namada::ledger::storage::{DBIter, StorageHasher, DB}; +use namada::ledger::storage::{DB, DBIter, traits::StorageHasher}; use namada::proto::Tx; use namada::types::storage::BlockHeight; use namada::types::transaction::tx_types::TxType; diff --git a/apps/src/lib/node/ledger/shell/queries.rs b/apps/src/lib/node/ledger/shell/queries.rs index d4ade3b380..5d04cef45c 100644 --- a/apps/src/lib/node/ledger/shell/queries.rs +++ b/apps/src/lib/node/ledger/shell/queries.rs @@ -152,7 +152,7 @@ where for PrefixValue { key, value } in &values { match self.storage.get_existence_proof( key, - value.clone(), + value.clone().into(), height, ) { Ok(p) => { @@ -221,7 +221,7 @@ where let proof_ops = if is_proven { match self.storage.get_existence_proof( key, - value.clone(), + value.clone().into(), height, ) { Ok(proof) => Some({ diff --git a/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs b/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs index fe1bcd20f9..ba8a96c9e5 100644 --- a/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs +++ b/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use namada::ledger::pos::namada_proof_of_stake::types::VotingPower; -use namada::ledger::storage::{DBIter, StorageHasher, DB}; +use namada::ledger::storage::{DB, DBIter, traits::StorageHasher}; use namada::proto::Signed; use namada::types::ethereum_events::EthereumEvent; use namada::types::storage::BlockHeight; diff --git a/apps/src/lib/node/ledger/shell/vote_extensions/val_set_update.rs b/apps/src/lib/node/ledger/shell/vote_extensions/val_set_update.rs index fc07a19f76..358bafa838 100644 --- a/apps/src/lib/node/ledger/shell/vote_extensions/val_set_update.rs +++ b/apps/src/lib/node/ledger/shell/vote_extensions/val_set_update.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use namada::ledger::pos::types::VotingPower; -use namada::ledger::storage::{DBIter, StorageHasher, DB}; +use namada::ledger::storage::{DB, DBIter, traits::StorageHasher}; use namada::types::storage::BlockHeight; use namada::types::vote_extensions::validator_set_update; use namada::types::voting_power::FractionalVotingPower; diff --git a/apps/src/lib/node/ledger/storage/mod.rs b/apps/src/lib/node/ledger/storage/mod.rs index 2876236bca..8017c6b7e4 100644 --- a/apps/src/lib/node/ledger/storage/mod.rs +++ b/apps/src/lib/node/ledger/storage/mod.rs @@ -9,7 +9,7 @@ use arse_merkle_tree::blake2b::Blake2bHasher; use arse_merkle_tree::traits::Hasher; use arse_merkle_tree::H256; use blake2b_rs::{Blake2b, Blake2bBuilder}; -use namada::ledger::storage::{Storage, StorageHasher}; +use namada::ledger::storage::{Storage, traits::StorageHasher}; #[derive(Default)] pub struct PersistentStorageHasher(Blake2bHasher); diff --git a/apps/src/lib/node/ledger/storage/rocksdb.rs b/apps/src/lib/node/ledger/storage/rocksdb.rs index 6af0011dcc..128900240c 100644 --- a/apps/src/lib/node/ledger/storage/rocksdb.rs +++ b/apps/src/lib/node/ledger/storage/rocksdb.rs @@ -930,7 +930,7 @@ mod imp { #[cfg(test)] mod test { - use namada::ledger::storage::{MerkleTree, Sha256Hasher}; + use namada::ledger::storage::{MerkleTree, traits::Sha256Hasher}; use namada::types::address::EstablishedAddressGen; use namada::types::storage::{BlockHash, Epoch, Epochs}; use tempfile::tempdir; diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index c09bdcb4e8..f900efb595 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -509,7 +509,7 @@ mod test_bridge_pool_tree { transfer: TransferToEthereum { asset: EthAddress([1; 20]), recipient: EthAddress([2; 20]), - amount: (1 as u64).into(), + amount: 1u64.into(), nonce: 42u64.into(), }, gas_fee: GasFee { @@ -529,7 +529,7 @@ mod test_bridge_pool_tree { transfer: TransferToEthereum { asset: EthAddress([1; 20]), recipient: EthAddress([2; 20]), - amount: (1 as u64).into(), + amount: 1u64.into(), nonce: 42u64.into(), }, gas_fee: GasFee { @@ -557,7 +557,7 @@ mod test_bridge_pool_tree { transfer: TransferToEthereum { asset: EthAddress([1; 20]), recipient: EthAddress([2; 20]), - amount: (1 as u64).into(), + amount: 1.into(), nonce: 42u64.into(), }, gas_fee: GasFee { @@ -571,7 +571,7 @@ mod test_bridge_pool_tree { transfer: TransferToEthereum { asset: EthAddress([1; 20]), recipient: EthAddress([0; 20]), - amount: (1 as u64).into(), + amount: 1u64.into(), nonce: 42u64.into(), }, gas_fee: GasFee { @@ -812,7 +812,7 @@ mod test_bridge_pool_tree { addrs.into_iter().map(| (addr, nonce)| PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress(addr.clone()), + asset: EthAddress(addr), recipient: EthAddress(addr), amount: Default::default(), nonce: nonce.into() diff --git a/shared/src/ledger/storage/ics23_specs.rs b/shared/src/ledger/storage/ics23_specs.rs index 3bb1680bad..00691bd30e 100644 --- a/shared/src/ledger/storage/ics23_specs.rs +++ b/shared/src/ledger/storage/ics23_specs.rs @@ -45,6 +45,7 @@ pub fn ibc_leaf_spec() -> LeafOp { } /// Get the proof specs for ibc +#[allow(dead_code)] pub fn ibc_proof_specs() -> Vec { let spec = arse_merkle_tree::proof_ics23::get_spec(H::hash_op()); let sub_tree_spec = ProofSpec { @@ -59,6 +60,7 @@ pub fn ibc_proof_specs() -> Vec { } /// Get the proof specs +#[allow(dead_code)] pub fn proof_specs() -> Vec { let spec = arse_merkle_tree::proof_ics23::get_spec(H::hash_op()); let sub_tree_spec = ProofSpec { diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index 92637476b8..ba20544d7d 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -365,7 +365,7 @@ impl MerkleTree { "No keys provided for existence proof.".into(), ) })?; - let (store_type, _) = StoreType::sub_key(first_key)?; + let (store_type, sub_key) = StoreType::sub_key(first_key)?; if !keys.iter().all(|k| { if let Ok((s, _)) = StoreType::sub_key(k) { s == store_type @@ -380,7 +380,7 @@ impl MerkleTree { )); } self.tree(&store_type) - .subtree_membership_proof(keys, values) + .subtree_membership_proof(std::array::from_ref(&sub_key), values) } /// Get the non-existence proof @@ -567,224 +567,243 @@ impl From for Error { } } -// #[cfg(test)] -// mod test { -// use super::*; -// use crate::types::storage::KeySeg; -// -// #[test] -// fn test_crud_value() { -// let mut tree = MerkleTree::::default(); -// let key_prefix: Key = -// Address::Internal(InternalAddress::Ibc).to_db_key().into(); -// let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); -// let key_prefix: Key = -// Address::Internal(InternalAddress::PoS).to_db_key().into(); -// let pos_key = key_prefix.push(&"test".to_string()).unwrap(); -// -// assert!(!tree.has_key(&ibc_key).unwrap()); -// assert!(!tree.has_key(&pos_key).unwrap()); -// -// update IBC tree -// tree.update(&ibc_key, [1u8; 8]).unwrap(); -// assert!(tree.has_key(&ibc_key).unwrap()); -// assert!(!tree.has_key(&pos_key).unwrap()); -// update another tree -// tree.update(&pos_key, [2u8; 8]).unwrap(); -// assert!(tree.has_key(&pos_key).unwrap()); -// -// delete a value on IBC tree -// tree.delete(&ibc_key).unwrap(); -// assert!(!tree.has_key(&ibc_key).unwrap()); -// assert!(tree.has_key(&pos_key).unwrap()); -// } -// -// #[test] -// fn test_restore_tree() { -// let mut tree = MerkleTree::::default(); -// -// let key_prefix: Key = -// Address::Internal(InternalAddress::Ibc).to_db_key().into(); -// let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); -// let key_prefix: Key = -// Address::Internal(InternalAddress::PoS).to_db_key().into(); -// let pos_key = key_prefix.push(&"test".to_string()).unwrap(); -// -// tree.update(&ibc_key, [1u8; 8]).unwrap(); -// tree.update(&pos_key, [2u8; 8]).unwrap(); -// -// let stores_write = tree.stores(); -// let mut stores_read = MerkleTreeStoresRead::default(); -// for st in StoreType::iter() { -// stores_read.set_root(st, stores_write.root(st).clone()); -// stores_read.set_store(stores_write.store(st).to_owned()); -// } -// let restored_tree = MerkleTree::::new(stores_read); -// assert!(restored_tree.has_key(&ibc_key).unwrap()); -// assert!(restored_tree.has_key(&pos_key).unwrap()); -// } -// -// #[test] -// fn test_ibc_existence_proof() { -// let mut tree = MerkleTree::::default(); -// -// let key_prefix: Key = -// Address::Internal(InternalAddress::Ibc).to_db_key().into(); -// let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); -// let key_prefix: Key = -// Address::Internal(InternalAddress::PoS).to_db_key().into(); -// let pos_key = key_prefix.push(&"test".to_string()).unwrap(); -// -// let ibc_val = [1u8; 8].to_vec(); -// tree.update(&ibc_key, ibc_val.clone()).unwrap(); -// let pos_val = [2u8; 8].to_vec(); -// tree.update(&pos_key, pos_val).unwrap(); -// -// let specs = tree.ibc_proof_specs(); -// let proof = -// tree.get_existence_proof(&ibc_key, ibc_val.clone()).unwrap(); -// let (store_type, sub_key) = StoreType::sub_key(&ibc_key).unwrap(); -// let paths = vec![sub_key.to_string(), store_type.to_string()]; -// let mut sub_root = ibc_val.clone(); -// let mut value = ibc_val; -// First, the sub proof is verified. Next the base proof is verified -// with the sub root -// for ((p, spec), key) in -// proof.ops.iter().zip(specs.iter()).zip(paths.iter()) -// { -// let commitment_proof = CommitmentProof::decode(&*p.data).unwrap(); -// let existence_proof = match commitment_proof.clone().proof.unwrap() -// { -// Ics23Proof::Exist(ep) => ep, -// _ => unreachable!(), -// }; -// sub_root = -// ics23::calculate_existence_root(&existence_proof).unwrap(); -// assert!(ics23::verify_membership( -// &commitment_proof, -// spec, -// &sub_root, -// key.as_bytes(), -// &value, -// )); -// for the verification of the base tree -// value = sub_root.clone(); -// } -// Check the base root -// assert_eq!(sub_root, tree.root().0); -// } -// -// #[test] -// fn test_non_ibc_existence_proof() { -// let mut tree = MerkleTree::::default(); -// -// let key_prefix: Key = -// Address::Internal(InternalAddress::Ibc).to_db_key().into(); -// let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); -// let key_prefix: Key = -// Address::Internal(InternalAddress::PoS).to_db_key().into(); -// let pos_key = key_prefix.push(&"test".to_string()).unwrap(); -// -// let ibc_val = [1u8; 8].to_vec(); -// tree.update(&ibc_key, ibc_val).unwrap(); -// let pos_val = [2u8; 8].to_vec(); -// tree.update(&pos_key, pos_val.clone()).unwrap(); -// -// let specs = tree.proof_specs(); -// let proof = -// tree.get_existence_proof(&pos_key, pos_val.clone()).unwrap(); -// let (store_type, sub_key) = StoreType::sub_key(&pos_key).unwrap(); -// let paths = vec![sub_key.to_string(), store_type.to_string()]; -// let mut sub_root = pos_val.clone(); -// let mut value = pos_val; -// First, the sub proof is verified. Next the base proof is verified -// with the sub root -// for ((p, spec), key) in -// proof.ops.iter().zip(specs.iter()).zip(paths.iter()) -// { -// let commitment_proof = CommitmentProof::decode(&*p.data).unwrap(); -// let existence_proof = match commitment_proof.clone().proof.unwrap() -// { -// Ics23Proof::Exist(ep) => ep, -// _ => unreachable!(), -// }; -// sub_root = -// ics23::calculate_existence_root(&existence_proof).unwrap(); -// assert!(ics23::verify_membership( -// &commitment_proof, -// spec, -// &sub_root, -// key.as_bytes(), -// &value, -// )); -// for the verification of the base tree -// value = sub_root.clone(); -// } -// Check the base root -// assert_eq!(sub_root, tree.root().0); -// } -// -// #[test] -// fn test_ibc_non_existence_proof() { -// let mut tree = MerkleTree::::default(); -// -// let key_prefix: Key = -// Address::Internal(InternalAddress::Ibc).to_db_key().into(); -// let ibc_non_key = -// key_prefix.push(&"test".to_string()).expect("Test failed"); -// let key_prefix: Key = -// Address::Internal(InternalAddress::Ibc).to_db_key().into(); -// let ibc_key = -// key_prefix.push(&"test2".to_string()).expect("Test failed"); -// let ibc_val = [2u8; 8].to_vec(); -// tree.update(&ibc_key, ibc_val).expect("Test failed"); -// -// let nep = tree -// .get_non_existence_proof(&ibc_non_key) -// .expect("Test failed"); -// let subtree_nep = nep.ops.get(0).expect("Test failed"); -// let nep_commitment_proof = -// CommitmentProof::decode(&*subtree_nep.data).expect("Test failed"); -// let non_existence_proof = -// match nep_commitment_proof.clone().proof.expect("Test failed") { -// Ics23Proof::Nonexist(nep) => nep, -// _ => unreachable!(), -// }; -// let subtree_root = if let Some(left) = &non_existence_proof.left { -// ics23::calculate_existence_root(left).unwrap() -// } else if let Some(right) = &non_existence_proof.right { -// ics23::calculate_existence_root(right).unwrap() -// } else { -// unreachable!() -// }; -// let (store_type, sub_key) = -// StoreType::sub_key(&ibc_non_key).expect("Test failed"); -// let specs = tree.ibc_proof_specs(); -// -// let nep_verification_res = ics23::verify_non_membership( -// &nep_commitment_proof, -// &specs[0], -// &subtree_root, -// sub_key.to_string().as_bytes(), -// ); -// assert!(nep_verification_res); -// let basetree_ep = nep.ops.get(1).unwrap(); -// let basetree_ep_commitment_proof = -// CommitmentProof::decode(&*basetree_ep.data).unwrap(); -// let basetree_ics23_ep = -// match basetree_ep_commitment_proof.clone().proof.unwrap() { -// Ics23Proof::Exist(ep) => ep, -// _ => unreachable!(), -// }; -// let basetree_root = -// ics23::calculate_existence_root(&basetree_ics23_ep).unwrap(); -// let basetree_verification_res = ics23::verify_membership( -// &basetree_ep_commitment_proof, -// &specs[1], -// &basetree_root, -// store_type.to_string().as_bytes(), -// &subtree_root, -// ); -// assert!(basetree_verification_res); -// } -// } +#[cfg(test)] +mod test { + use super::*; + use crate::ledger::storage::ics23_specs::{ibc_proof_specs, proof_specs}; + use crate::ledger::storage::traits::Sha256Hasher; + use crate::types::storage::KeySeg; + + #[test] + fn test_crud_value() { + let mut tree = MerkleTree::::default(); + let key_prefix: Key = + Address::Internal(InternalAddress::Ibc).to_db_key().into(); + let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); + let key_prefix: Key = + Address::Internal(InternalAddress::PoS).to_db_key().into(); + let pos_key = key_prefix.push(&"test".to_string()).unwrap(); + + assert!(!tree.has_key(&ibc_key).unwrap()); + assert!(!tree.has_key(&pos_key).unwrap()); + + // update IBC tree + tree.update(&ibc_key, [1u8; 8]).unwrap(); + assert!(tree.has_key(&ibc_key).unwrap()); + assert!(!tree.has_key(&pos_key).unwrap()); + // update another tree + tree.update(&pos_key, [2u8; 8]).unwrap(); + assert!(tree.has_key(&pos_key).unwrap()); + + // delete a value on IBC tree + tree.delete(&ibc_key).unwrap(); + assert!(!tree.has_key(&ibc_key).unwrap()); + assert!(tree.has_key(&pos_key).unwrap()); + } + + #[test] + fn test_restore_tree() { + let mut tree = MerkleTree::::default(); + + let key_prefix: Key = + Address::Internal(InternalAddress::Ibc).to_db_key().into(); + let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); + let key_prefix: Key = + Address::Internal(InternalAddress::PoS).to_db_key().into(); + let pos_key = key_prefix.push(&"test".to_string()).unwrap(); + + tree.update(&ibc_key, [1u8; 8]).unwrap(); + tree.update(&pos_key, [2u8; 8]).unwrap(); + + let stores_write = tree.stores(); + let mut stores_read = MerkleTreeStoresRead::default(); + for st in StoreType::iter() { + stores_read.set_root(st, stores_write.root(st).clone()); + stores_read.set_store(stores_write.store(st).to_owned()); + } + let restored_tree = MerkleTree::::new(stores_read); + assert!(restored_tree.has_key(&ibc_key).unwrap()); + assert!(restored_tree.has_key(&pos_key).unwrap()); + } + + #[test] + fn test_ibc_existence_proof() { + let mut tree = MerkleTree::::default(); + + let key_prefix: Key = + Address::Internal(InternalAddress::Ibc).to_db_key().into(); + let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); + let key_prefix: Key = + Address::Internal(InternalAddress::PoS).to_db_key().into(); + let pos_key = key_prefix.push(&"test".to_string()).unwrap(); + + let ibc_val = [1u8; 8].to_vec(); + tree.update(&ibc_key, ibc_val.clone()).unwrap(); + let pos_val = [2u8; 8].to_vec(); + tree.update(&pos_key, pos_val).unwrap(); + + let specs = ibc_proof_specs::(); + let proof = match tree + .get_sub_tree_existence_proof( + std::array::from_ref(&ibc_key), + vec![ibc_val.clone().into()], + ) + .unwrap(){ + MembershipProof::ICS23(proof) => proof, + _ => panic!("Test failed"), + }; + let proof = tree.get_tendermint_proof(&ibc_key, proof).unwrap(); + let (store_type, sub_key) = StoreType::sub_key(&ibc_key).unwrap(); + let paths = vec![sub_key.to_string(), store_type.to_string()]; + let mut sub_root = ibc_val.clone(); + let mut value = ibc_val; + // First, the sub proof is verified. Next the base proof is verified + // with the sub root + for ((p, spec), key) in + proof.ops.iter().zip(specs.iter()).zip(paths.iter()) + { + let commitment_proof = CommitmentProof::decode(&*p.data).unwrap(); + let existence_proof = match commitment_proof.clone().proof.unwrap() + { + Ics23Proof::Exist(ep) => ep, + _ => unreachable!(), + }; + sub_root = + ics23::calculate_existence_root(&existence_proof).unwrap(); + assert!(ics23::verify_membership( + &commitment_proof, + spec, + &sub_root, + key.as_bytes(), + &value, + )); + // for the verification of the base tree + value = sub_root.clone(); + } + // Check the base root + assert_eq!(sub_root, tree.root().0); + } + + #[test] + fn test_non_ibc_existence_proof() { + let mut tree = MerkleTree::::default(); + + let key_prefix: Key = + Address::Internal(InternalAddress::Ibc).to_db_key().into(); + let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); + let key_prefix: Key = + Address::Internal(InternalAddress::PoS).to_db_key().into(); + let pos_key = key_prefix.push(&"test".to_string()).unwrap(); + + let ibc_val = [1u8; 8].to_vec(); + tree.update(&ibc_key, ibc_val).unwrap(); + let pos_val = [2u8; 8].to_vec(); + tree.update(&pos_key, pos_val.clone()).unwrap(); + + let specs = proof_specs::(); + let proof = match tree.get_sub_tree_existence_proof( + std::array::from_ref(&pos_key), + vec![pos_val.clone().into()], + ) + .unwrap() + { + MembershipProof::ICS23(proof) => proof, + _ => panic!("Test failed"), + }; + + let proof = tree.get_tendermint_proof(&pos_key, proof).unwrap(); + let (store_type, sub_key) = StoreType::sub_key(&pos_key).unwrap(); + let paths = vec![sub_key.to_string(), store_type.to_string()]; + let mut sub_root = pos_val.clone(); + let mut value = pos_val; + // First, the sub proof is verified. Next the base proof is verified + // with the sub root + for ((p, spec), key) in + proof.ops.iter().zip(specs.iter()).zip(paths.iter()) + { + let commitment_proof = CommitmentProof::decode(&*p.data).unwrap(); + let existence_proof = match commitment_proof.clone().proof.unwrap() + { + Ics23Proof::Exist(ep) => ep, + _ => unreachable!(), + }; + sub_root = + ics23::calculate_existence_root(&existence_proof).unwrap(); + assert!(ics23::verify_membership( + &commitment_proof, + spec, + &sub_root, + key.as_bytes(), + &value, + )); + // for the verification of the base tree + value = sub_root.clone(); + } + // Check the base root + assert_eq!(sub_root, tree.root().0); + } + + #[test] + fn test_ibc_non_existence_proof() { + let mut tree = MerkleTree::::default(); + + let key_prefix: Key = + Address::Internal(InternalAddress::Ibc).to_db_key().into(); + let ibc_non_key = + key_prefix.push(&"test".to_string()).expect("Test failed"); + let key_prefix: Key = + Address::Internal(InternalAddress::Ibc).to_db_key().into(); + let ibc_key = + key_prefix.push(&"test2".to_string()).expect("Test failed"); + let ibc_val = [2u8; 8].to_vec(); + tree.update(&ibc_key, ibc_val).expect("Test failed"); + + let nep = tree + .get_non_existence_proof(&ibc_non_key) + .expect("Test failed"); + let subtree_nep = nep.ops.get(0).expect("Test failed"); + let nep_commitment_proof = + CommitmentProof::decode(&*subtree_nep.data).expect("Test failed"); + let non_existence_proof = + match nep_commitment_proof.clone().proof.expect("Test failed") { + Ics23Proof::Nonexist(nep) => nep, + _ => unreachable!(), + }; + let subtree_root = if let Some(left) = &non_existence_proof.left { + ics23::calculate_existence_root(left).unwrap() + } else if let Some(right) = &non_existence_proof.right { + ics23::calculate_existence_root(right).unwrap() + } else { + unreachable!() + }; + let (store_type, sub_key) = + StoreType::sub_key(&ibc_non_key).expect("Test failed"); + let specs = ibc_proof_specs::(); + + let nep_verification_res = ics23::verify_non_membership( + &nep_commitment_proof, + &specs[0], + &subtree_root, + sub_key.to_string().as_bytes(), + ); + assert!(nep_verification_res); + let basetree_ep = nep.ops.get(1).unwrap(); + let basetree_ep_commitment_proof = + CommitmentProof::decode(&*basetree_ep.data).unwrap(); + let basetree_ics23_ep = + match basetree_ep_commitment_proof.clone().proof.unwrap() { + Ics23Proof::Exist(ep) => ep, + _ => unreachable!(), + }; + let basetree_root = + ics23::calculate_existence_root(&basetree_ics23_ep).unwrap(); + let basetree_verification_res = ics23::verify_membership( + &basetree_ep_commitment_proof, + &specs[1], + &basetree_root, + store_type.to_string().as_bytes(), + &subtree_root, + ); + assert!(basetree_verification_res); + } +} diff --git a/shared/src/ledger/storage/mod.rs b/shared/src/ledger/storage/mod.rs index 74bde36b0f..1dd03af3d9 100644 --- a/shared/src/ledger/storage/mod.rs +++ b/shared/src/ledger/storage/mod.rs @@ -506,25 +506,47 @@ where (self.block.hash.clone(), BLOCK_HASH_LENGTH as _) } - /// Get the existence proof + /// Get a Tendermint-compatible existence proof. + /// + /// Proofs from the Ethereum bridge pool are not + /// Tendermint-compatible. Requesting for a key + /// belonging to the bridge pool will cause this + /// method to error. pub fn get_existence_proof( &self, key: &Key, value: MerkleValue, height: BlockHeight, - ) -> Result { + ) -> Result { if height >= self.get_block_height().0 { - Ok(self.block.tree.get_sub_tree_existence_proof( - array::from_ref(key), - vec![value], - )?) + if let MembershipProof::ICS23(proof) = self + .block + .tree + .get_sub_tree_existence_proof(array::from_ref(key), vec![value]) + .map_err(Error::MerkleTreeError)? { + self.block + .tree + .get_tendermint_proof(key, proof) + .map_err(Error::MerkleTreeError) + } else { + Err(Error::MerkleTreeError(MerkleTreeError::TendermintProof)) + } } else { match self.db.read_merkle_tree_stores(height)? { - Some(stores) => Ok(MerkleTree::::new(stores) - .get_sub_tree_existence_proof( - array::from_ref(key), - vec![value], - )?), + Some(stores) => { + let tree = MerkleTree::::new(stores); + if let MembershipProof::ICS23(proof) = tree + .get_sub_tree_existence_proof( + array::from_ref(key), + vec![value], + ) + .map_err(Error::MerkleTreeError)? { + tree.get_tendermint_proof(key, proof) + .map_err(Error::MerkleTreeError) + } else { + Err(Error::MerkleTreeError(MerkleTreeError::TendermintProof)) + } + } None => Err(Error::NoMerkleTree { height }), } } diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs index 907aab2ed9..fb7b5b662c 100644 --- a/shared/src/ledger/storage/traits.rs +++ b/shared/src/ledger/storage/traits.rs @@ -1,6 +1,6 @@ //! Traits needed to provide a uniform interface over //! all the different Merkle trees used for storage -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; use std::fmt; use arse_merkle_tree::traits::{Hasher, Value}; @@ -45,9 +45,10 @@ pub trait SubTreeWrite { impl<'a, H: StorageHasher + Default> SubTreeRead for &'a Smt { fn subtree_has_key(&self, key: &Key) -> Result { - self.get(&H::hash(key.to_string()).into()) - .and(Ok(true)) - .map_err(|err| Error::MerkleTree(err.to_string())) + match self.get(&H::hash(key.to_string()).into()) { + Ok(hash) => Ok(!hash.is_zero()), + Err(e) => Err(Error::MerkleTree(e.to_string())), + } } fn subtree_membership_proof( @@ -88,11 +89,10 @@ impl<'a, H: StorageHasher + Default> SubTreeWrite for &'a mut Smt { value: MerkleValue, ) -> Result { let value = match value { - MerkleValue::Bytes(bytes) => Hash::try_from(bytes.as_slice()) - .map_err(|_| Error::InvalidValue)?, + MerkleValue::Bytes(bytes) => H::hash(bytes.as_slice()), _ => return Err(Error::InvalidValue), }; - self.update(H::hash(key.to_string()).into(), value) + self.update(H::hash(key.to_string()).into(), value.into()) .map(Hash::from) .map_err(|err| Error::MerkleTree(err.to_string())) } @@ -108,9 +108,10 @@ impl<'a, H: StorageHasher + Default> SubTreeWrite for &'a mut Smt { impl<'a, H: StorageHasher + Default> SubTreeRead for &'a Amt { fn subtree_has_key(&self, key: &Key) -> Result { let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; - self.get(&key) - .and(Ok(true)) - .map_err(|err| Error::MerkleTree(err.to_string())) + match self.get(&key) { + Ok(hash) => Ok(!hash.is_zero()), + Err(e) => Err(Error::MerkleTree(e.to_string())), + } } fn subtree_membership_proof( @@ -237,6 +238,35 @@ impl TreeKey for StringKey { } } +impl Value for Hash { + fn as_slice(&self) -> &[u8] { + self.0.as_slice() + } + + fn zero() -> Self { + Hash([0u8; 32]) + } +} + +impl From for H256 { + fn from(hash: Hash) -> Self { + hash.0.into() + } +} + +impl From for Hash { + fn from(hash: H256) -> Self { + Self(hash.into()) + } +} + +impl From<&H256> for Hash { + fn from(hash: &H256) -> Self { + let hash = hash.to_owned(); + Self(hash.into()) + } +} + impl Value for TreeBytes { fn as_slice(&self) -> &[u8] { self.0.as_slice() @@ -262,7 +292,7 @@ impl Hasher for Sha256Hasher { self.0.update(h) } - fn finish(self) -> arse_merkle_tree::H256 { + fn finish(self) -> H256 { let hash = self.0.finalize(); let bytes: [u8; 32] = hash .as_slice() diff --git a/shared/src/types/hash.rs b/shared/src/types/hash.rs index 5a6abd146c..4e63af1ad9 100644 --- a/shared/src/types/hash.rs +++ b/shared/src/types/hash.rs @@ -4,7 +4,6 @@ use std::fmt::{self, Display}; use std::ops::Deref; use arse_merkle_tree::traits::Value; -use arse_merkle_tree::{Hash as TreeHash, H256}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use hex::FromHex; use serde::{Deserialize, Serialize}; @@ -133,38 +132,3 @@ impl From for TmHash { TmHash::Sha256(hash.0) } } - -impl From for Hash { - fn from(hash: H256) -> Self { - Hash(hash.into()) - } -} - -impl From<&H256> for Hash { - fn from(hash: &H256) -> Self { - let hash = *hash; - Hash(hash.into()) - } -} - -impl From for H256 { - fn from(hash: Hash) -> H256 { - hash.0.into() - } -} - -impl From for TreeHash { - fn from(hash: Hash) -> Self { - Self::from(hash.0) - } -} - -impl Value for Hash { - fn as_slice(&self) -> &[u8] { - self.0.as_slice() - } - - fn zero() -> Self { - Hash([0u8; 32]) - } -} diff --git a/tests/src/native_vp/mod.rs b/tests/src/native_vp/mod.rs index be450a7086..5540ac26d4 100644 --- a/tests/src/native_vp/mod.rs +++ b/tests/src/native_vp/mod.rs @@ -2,7 +2,7 @@ mod pos; use namada::ledger::native_vp::{Ctx, NativeVp}; use namada::ledger::storage::mockdb::MockDB; -use namada::ledger::storage::Sha256Hasher; +use namada::ledger::storage::traits::Sha256Hasher; use namada::vm::wasm::compilation_cache; use namada::vm::wasm::compilation_cache::common::Cache; use namada::vm::{wasm, WasmCacheRwAccess}; diff --git a/tests/src/native_vp/pos.rs b/tests/src/native_vp/pos.rs index be1844c6cd..7be49ac538 100644 --- a/tests/src/native_vp/pos.rs +++ b/tests/src/native_vp/pos.rs @@ -411,7 +411,7 @@ mod tests { // Use the tx_env to run PoS VP let tx_env = tx_host_env::take(); let vp_env = TestNativeVpEnv::new(tx_env); - let result = vp_env.validate_tx(PosVP::new, |_tx_data| {}); + let result: Result = vp_env.validate_tx(PosVP::new, |_tx_data| {}); // Put the tx_env back before checking the result tx_host_env::set(vp_env.tx_env); let result = diff --git a/tests/src/vm_host_env/ibc.rs b/tests/src/vm_host_env/ibc.rs index e1c372a85f..8e6fa0a254 100644 --- a/tests/src/vm_host_env/ibc.rs +++ b/tests/src/vm_host_env/ibc.rs @@ -59,7 +59,7 @@ use namada::ledger::ibc::vp::{ }; use namada::ledger::native_vp::{Ctx, NativeVp}; use namada::ledger::storage::mockdb::MockDB; -use namada::ledger::storage::Sha256Hasher; +use namada::ledger::storage::traits::Sha256Hasher; use namada::proto::Tx; use namada::tendermint_proto::Protobuf; use namada::types::address::{self, Address, InternalAddress}; diff --git a/tests/src/vm_host_env/vp.rs b/tests/src/vm_host_env/vp.rs index 61b87e1b3b..06cd6d0981 100644 --- a/tests/src/vm_host_env/vp.rs +++ b/tests/src/vm_host_env/vp.rs @@ -88,7 +88,7 @@ mod native_vp_host_env { // TODO replace with `std::concat_idents` once stabilized (https://github.com/rust-lang/rust/issues/29599) use concat_idents::concat_idents; - use namada::ledger::storage::Sha256Hasher; + use namada::ledger::storage::traits::Sha256Hasher; use namada::vm::host_env::*; use namada::vm::WasmCacheRwAccess; diff --git a/wasm/checksums.json b/wasm/checksums.json index 29ccd4fd2b..0c091181df 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,20 @@ { + "tx_bond.wasm": "tx_bond.aac575fac2ddaba8fca6f341b2ca6a77dd430767aae628e75aebf0b05470173f.wasm", "tx_bridge_pool.wasm": "tx_bridge_pool.e21563260c03cfdab1f195878f49bf93722027ad26fcd097cfebbc5c4d279082.wasm", - "tx_from_intent.wasm": "tx_from_intent.de38def08090ac1a912d24a1cf0dd03b0b1ad70eca06dcd6745af9c7175be450.wasm", - "tx_ibc.wasm": "tx_ibc.8fd090bdd02727239c63ff6a2a880124320d744972723315983ce855201c605e.wasm", - "tx_init_account.wasm": "tx_init_account.abfeeca2aeecdacf3ff3db022c9aaf85040b38164703a4ee7ad6e42afacdd961.wasm", - "tx_init_nft.wasm": "tx_init_nft.0be8aba244a529f8bb65692bbf0c939550ca9bdd00de6b8df68f1780dd8d7c2d.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.67cc820c203ed6f379110c94b7ad16544c03a4d94c77fbbacba1c02dd0869b0b.wasm", - "tx_init_validator.wasm": "tx_init_validator.c9d864bac4cc3090b456f07deb956b2763d8c9fbda38762953398332182ac791.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.453eed7e258e8bda5ff3136ca89e90f3dcc601d1e62dd0991c1d18e404e96d73.wasm", - "tx_transfer.wasm": "tx_transfer.cdad1f1189e5a56aa9cbd542fc983397fd24172c99368623b28001b6c440d2e1.wasm", - "tx_unbond.wasm": "tx_unbond.7498c085a34e8507d46e4eebbd9dcb442d3431685aba15da406f3b74d214e4cf.wasm", - "tx_update_vp.wasm": "tx_update_vp.0e6fe53decf185f6c8715b70a610177c035827370fe472e71a55ff5bf04d7273.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.cfa3277e9be0442f20496a115b31ec8ea96fbc98a26ea65129a68166464a4c40.wasm", - "tx_withdraw.wasm": "tx_withdraw.63b3513b411659e4ab6c63c61bb56aff33f6f39cb42d9f8618cd373320dcc087.wasm", - "vp_nft.wasm": "vp_nft.2f21e99208c9c0842106b67fa4f113e9aa76ce009a486788e5458247fd7ef1ba.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.7135a8139a99f1e6cdb3c44e5a6824ddfb8c3db158b3284191d4f53d18f38710.wasm", - "vp_token.wasm": "vp_token.0cd22c3ba1c234bfbfc3a0d0913a9dc230c22ec7f629ba74907e8af40de687a4.wasm", - "vp_user.wasm": "vp_user.112577f72fcaf46c25389f67a4a643e71d61f7fb01447970acdf96a8ad72e9ec.wasm" + "tx_from_intent.wasm": "tx_from_intent.4c77cf173ef5e3f71991aa2b5ea8a2ca4c81ed55367eb6b16cae899e6552fda2.wasm", + "tx_ibc.wasm": "tx_ibc.ad63ce4b85a0885124ab0ecec94824de76aa1ef276a0a91851c6159f7720a5f7.wasm", + "tx_init_account.wasm": "tx_init_account.14762c8749535ec551e8d8678f882297eda4786ed7e5417f925dfc555df060c5.wasm", + "tx_init_nft.wasm": "tx_init_nft.563859381ec97298028d1efa446a10152159d241ce776a06948df541258cbf01.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.28b5d79cfe0625c88d1537f93806fe2a773019b0869c379750f00d5eab127d68.wasm", + "tx_init_validator.wasm": "tx_init_validator.90a284f98ade8d39f834ffd80f395d1471a657a6a9c8e43fce248814a92591cb.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.9a392ed8d1aa98d3c767609d99fc9ba828426175160ea5ecabaed837e7045603.wasm", + "tx_transfer.wasm": "tx_transfer.39eb3118c1d59a567580bcb8a78d5639edba4dccd723867854f8739268b55f71.wasm", + "tx_unbond.wasm": "tx_unbond.b4e1d04dea54fcfde4faee0645a968f74328c07fd860bc4893640b9a5d7cd41f.wasm", + "tx_update_vp.wasm": "tx_update_vp.0af0bab850894a75585463b7569acf025dddb775cffbe1ae896d1ac7e39b350f.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.17caf0ac3b5ef72883f131996c2c0520d6512868372095f9f4091f0d400bb8c9.wasm", + "tx_withdraw.wasm": "tx_withdraw.ccb05868b2591271bdf50b2bfb6e985b5472551b760840c515c8c20fa554a3d1.wasm", + "vp_nft.wasm": "vp_nft.3ce385731fe6a691be4cbae0bc99e51d290bbf06310058a5d696b0877b669994.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.1f22309dfd457d3e6ff3b0af014193855b807fffbe32bec19e9486e9342ff0ce.wasm", + "vp_token.wasm": "vp_token.c0a629ec9f93db0f09ff56b7089813c0a87a5cd4ad2d8e35012819cdc9b2c63c.wasm", + "vp_user.wasm": "vp_user.43ca141419537eae40363ea0d87e10b04a8d0a507ee2182a65c6c02f5e42b264.wasm" } \ No newline at end of file diff --git a/wasm/tx_template/Cargo.lock b/wasm/tx_template/Cargo.lock index 3afe9398ee..6415ecf977 100644 --- a/wasm/tx_template/Cargo.lock +++ b/wasm/tx_template/Cargo.lock @@ -184,12 +184,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base64" version = "0.13.0" @@ -406,12 +400,6 @@ dependencies = [ "syn", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -546,18 +534,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "rand_core 0.6.3", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.3" @@ -568,16 +544,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -639,15 +605,6 @@ dependencies = [ "syn", ] -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", -] - [[package]] name = "derivative" version = "2.2.0" @@ -716,18 +673,6 @@ dependencies = [ "memmap2", ] -[[package]] -name = "ecdsa" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - [[package]] name = "ed25519" version = "1.4.0" @@ -770,24 +715,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "elliptic-curve" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "ff", - "generic-array", - "group", - "rand_core 0.6.3", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "enum-iterator" version = "0.7.0" @@ -911,16 +838,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "fixed-hash" version = "0.7.0" @@ -1070,17 +987,6 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "ff", - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "gumdrop" version = "0.8.0" @@ -1134,20 +1040,10 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "ibc" version = "0.14.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "bytes", "derive_more", @@ -1174,7 +1070,7 @@ dependencies = [ [[package]] name = "ibc-proto" version = "0.17.1" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "base64", "bytes", @@ -1305,19 +1201,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "k256" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", - "sec1", - "sha2 0.9.9", -] - [[package]] name = "keccak" version = "0.1.0" @@ -2181,17 +2064,6 @@ dependencies = [ "bytecheck", ] -[[package]] -name = "rfc6979" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - [[package]] name = "ripemd160" version = "0.9.1" @@ -2368,18 +2240,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" -dependencies = [ - "der", - "generic-array", - "subtle", - "zeroize", -] - [[package]] name = "semver" version = "0.11.0" @@ -2509,10 +2369,6 @@ name = "signature" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.3", -] [[package]] name = "simple-error" @@ -2634,7 +2490,7 @@ dependencies = [ [[package]] name = "tendermint" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "async-trait", "bytes", @@ -2642,12 +2498,10 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256", "num-traits", "once_cell", "prost", "prost-types", - "ripemd160", "serde", "serde_bytes", "serde_json", @@ -2664,7 +2518,7 @@ dependencies = [ [[package]] name = "tendermint-config" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "flex-error", "serde", @@ -2677,7 +2531,7 @@ dependencies = [ [[package]] name = "tendermint-light-client-verifier" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "derive_more", "flex-error", @@ -2690,7 +2544,7 @@ dependencies = [ [[package]] name = "tendermint-proto" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "bytes", "flex-error", @@ -2707,7 +2561,7 @@ dependencies = [ [[package]] name = "tendermint-rpc" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "bytes", "flex-error", @@ -2731,7 +2585,7 @@ dependencies = [ [[package]] name = "tendermint-testgen" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "ed25519-dalek", "gumdrop", diff --git a/wasm/vp_template/Cargo.lock b/wasm/vp_template/Cargo.lock index 711a7dfa61..3f0160f2e8 100644 --- a/wasm/vp_template/Cargo.lock +++ b/wasm/vp_template/Cargo.lock @@ -184,12 +184,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base64" version = "0.13.0" @@ -406,12 +400,6 @@ dependencies = [ "syn", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -546,18 +534,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "rand_core 0.6.3", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.3" @@ -568,16 +544,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -639,15 +605,6 @@ dependencies = [ "syn", ] -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", -] - [[package]] name = "derivative" version = "2.2.0" @@ -716,18 +673,6 @@ dependencies = [ "memmap2", ] -[[package]] -name = "ecdsa" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - [[package]] name = "ed25519" version = "1.4.0" @@ -770,24 +715,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "elliptic-curve" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "ff", - "generic-array", - "group", - "rand_core 0.6.3", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "enum-iterator" version = "0.7.0" @@ -911,16 +838,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "fixed-hash" version = "0.7.0" @@ -1070,17 +987,6 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "ff", - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "gumdrop" version = "0.8.0" @@ -1134,20 +1040,10 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "ibc" version = "0.14.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "bytes", "derive_more", @@ -1174,7 +1070,7 @@ dependencies = [ [[package]] name = "ibc-proto" version = "0.17.1" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "base64", "bytes", @@ -1305,19 +1201,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "k256" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", - "sec1", - "sha2 0.9.9", -] - [[package]] name = "keccak" version = "0.1.0" @@ -2181,17 +2064,6 @@ dependencies = [ "bytecheck", ] -[[package]] -name = "rfc6979" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - [[package]] name = "ripemd160" version = "0.9.1" @@ -2368,18 +2240,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" -dependencies = [ - "der", - "generic-array", - "subtle", - "zeroize", -] - [[package]] name = "semver" version = "0.11.0" @@ -2509,10 +2369,6 @@ name = "signature" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.3", -] [[package]] name = "simple-error" @@ -2634,7 +2490,7 @@ dependencies = [ [[package]] name = "tendermint" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "async-trait", "bytes", @@ -2642,12 +2498,10 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256", "num-traits", "once_cell", "prost", "prost-types", - "ripemd160", "serde", "serde_bytes", "serde_json", @@ -2664,7 +2518,7 @@ dependencies = [ [[package]] name = "tendermint-config" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "flex-error", "serde", @@ -2677,7 +2531,7 @@ dependencies = [ [[package]] name = "tendermint-light-client-verifier" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "derive_more", "flex-error", @@ -2690,7 +2544,7 @@ dependencies = [ [[package]] name = "tendermint-proto" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "bytes", "flex-error", @@ -2707,7 +2561,7 @@ dependencies = [ [[package]] name = "tendermint-rpc" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "bytes", "flex-error", @@ -2731,7 +2585,7 @@ dependencies = [ [[package]] name = "tendermint-testgen" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "ed25519-dalek", "gumdrop", diff --git a/wasm/wasm_source/Cargo.lock b/wasm/wasm_source/Cargo.lock index a71a76a13c..a156f2291b 100644 --- a/wasm/wasm_source/Cargo.lock +++ b/wasm/wasm_source/Cargo.lock @@ -193,12 +193,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base64" version = "0.13.0" @@ -417,12 +411,6 @@ dependencies = [ "syn", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -564,18 +552,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "rand_core 0.6.3", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.6" @@ -586,16 +562,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -656,15 +622,6 @@ dependencies = [ "syn", ] -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", -] - [[package]] name = "derivative" version = "2.2.0" @@ -733,18 +690,6 @@ dependencies = [ "memmap2", ] -[[package]] -name = "ecdsa" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - [[package]] name = "ed25519" version = "1.5.2" @@ -787,24 +732,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" -[[package]] -name = "elliptic-curve" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "ff", - "generic-array", - "group", - "rand_core 0.6.3", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "enum-iterator" version = "0.7.0" @@ -928,16 +855,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "fixed-hash" version = "0.7.0" @@ -1086,17 +1003,6 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "ff", - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "gumdrop" version = "0.8.1" @@ -1159,16 +1065,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "iana-time-zone" version = "0.1.47" @@ -1186,7 +1082,7 @@ dependencies = [ [[package]] name = "ibc" version = "0.14.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "bytes", "derive_more", @@ -1213,7 +1109,7 @@ dependencies = [ [[package]] name = "ibc-proto" version = "0.17.1" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "base64", "bytes", @@ -1343,19 +1239,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "k256" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", - "sec1", - "sha2 0.9.9", -] - [[package]] name = "keccak" version = "0.1.2" @@ -2238,17 +2121,6 @@ dependencies = [ "bytecheck", ] -[[package]] -name = "rfc6979" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - [[package]] name = "ripemd160" version = "0.9.1" @@ -2425,18 +2297,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" -dependencies = [ - "der", - "generic-array", - "subtle", - "zeroize", -] - [[package]] name = "semver" version = "0.11.0" @@ -2566,10 +2426,6 @@ name = "signature" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.3", -] [[package]] name = "simple-error" @@ -2685,7 +2541,7 @@ dependencies = [ [[package]] name = "tendermint" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "async-trait", "bytes", @@ -2693,12 +2549,10 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256", "num-traits", "once_cell", "prost", "prost-types", - "ripemd160", "serde", "serde_bytes", "serde_json", @@ -2715,7 +2569,7 @@ dependencies = [ [[package]] name = "tendermint-config" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "flex-error", "serde", @@ -2728,7 +2582,7 @@ dependencies = [ [[package]] name = "tendermint-light-client-verifier" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "derive_more", "flex-error", @@ -2741,7 +2595,7 @@ dependencies = [ [[package]] name = "tendermint-proto" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "bytes", "flex-error", @@ -2758,7 +2612,7 @@ dependencies = [ [[package]] name = "tendermint-rpc" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "bytes", "flex-error", @@ -2782,7 +2636,7 @@ dependencies = [ [[package]] name = "tendermint-testgen" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "ed25519-dalek", "gumdrop", diff --git a/wasm_for_tests/wasm_source/Cargo.lock b/wasm_for_tests/wasm_source/Cargo.lock index 654c0b9898..7521fbccca 100644 --- a/wasm_for_tests/wasm_source/Cargo.lock +++ b/wasm_for_tests/wasm_source/Cargo.lock @@ -184,12 +184,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - [[package]] name = "base64" version = "0.13.0" @@ -406,12 +400,6 @@ dependencies = [ "syn", ] -[[package]] -name = "const-oid" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -547,18 +535,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" -[[package]] -name = "crypto-bigint" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c6a1d5fa1de37e071642dfa44ec552ca5b299adb128fab16138e24b548fd21" -dependencies = [ - "generic-array", - "rand_core 0.6.3", - "subtle", - "zeroize", -] - [[package]] name = "crypto-common" version = "0.1.3" @@ -569,16 +545,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "crypto-mac" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -640,15 +606,6 @@ dependencies = [ "syn", ] -[[package]] -name = "der" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" -dependencies = [ - "const-oid", -] - [[package]] name = "derivative" version = "2.2.0" @@ -717,18 +674,6 @@ dependencies = [ "memmap2", ] -[[package]] -name = "ecdsa" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d69ae62e0ce582d56380743515fefaf1a8c70cec685d9677636d7e30ae9dc9" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - [[package]] name = "ed25519" version = "1.4.1" @@ -771,24 +716,6 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" -[[package]] -name = "elliptic-curve" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b477563c2bfed38a3b7a60964c49e058b2510ad3f12ba3483fd8f62c2306d6" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "ff", - "generic-array", - "group", - "rand_core 0.6.3", - "sec1", - "subtle", - "zeroize", -] - [[package]] name = "enum-iterator" version = "0.7.0" @@ -912,16 +839,6 @@ dependencies = [ "serde_bytes", ] -[[package]] -name = "ff" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" -dependencies = [ - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "fixed-hash" version = "0.7.0" @@ -1071,17 +988,6 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" -[[package]] -name = "group" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" -dependencies = [ - "ff", - "rand_core 0.6.3", - "subtle", -] - [[package]] name = "gumdrop" version = "0.8.1" @@ -1144,20 +1050,10 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "ibc" version = "0.14.0" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "bytes", "derive_more", @@ -1184,7 +1080,7 @@ dependencies = [ [[package]] name = "ibc-proto" version = "0.17.1" -source = "git+https://github.com/heliaxdev/ibc-rs?rev=9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d#9fcc1c8c19db6af50806ffe5b2f6c214adcbfd5d" +source = "git+https://github.com/heliaxdev/ibc-rs?rev=6255c4e01db11781e5a8cdb89737f55a8ad81d63#6255c4e01db11781e5a8cdb89737f55a8ad81d63" dependencies = [ "base64", "bytes", @@ -1315,19 +1211,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "k256" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19c3a5e0a0b8450278feda242592512e09f61c72e018b8cd5c859482802daf2d" -dependencies = [ - "cfg-if 1.0.0", - "ecdsa", - "elliptic-curve", - "sec1", - "sha2 0.9.9", -] - [[package]] name = "keccak" version = "0.1.0" @@ -2212,17 +2095,6 @@ dependencies = [ "bytecheck", ] -[[package]] -name = "rfc6979" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96ef608575f6392792f9ecf7890c00086591d29a83910939d430753f7c050525" -dependencies = [ - "crypto-bigint", - "hmac", - "zeroize", -] - [[package]] name = "ripemd160" version = "0.9.1" @@ -2399,18 +2271,6 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" -[[package]] -name = "sec1" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08da66b8b0965a5555b6bd6639e68ccba85e1e2506f5fbb089e93f8a04e1a2d1" -dependencies = [ - "der", - "generic-array", - "subtle", - "zeroize", -] - [[package]] name = "semver" version = "0.11.0" @@ -2540,10 +2400,6 @@ name = "signature" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" -dependencies = [ - "digest 0.9.0", - "rand_core 0.6.3", -] [[package]] name = "simple-error" @@ -2665,7 +2521,7 @@ dependencies = [ [[package]] name = "tendermint" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "async-trait", "bytes", @@ -2673,12 +2529,10 @@ dependencies = [ "ed25519-dalek", "flex-error", "futures", - "k256", "num-traits", "once_cell", "prost", "prost-types", - "ripemd160", "serde", "serde_bytes", "serde_json", @@ -2695,7 +2549,7 @@ dependencies = [ [[package]] name = "tendermint-config" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "flex-error", "serde", @@ -2708,7 +2562,7 @@ dependencies = [ [[package]] name = "tendermint-light-client-verifier" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "derive_more", "flex-error", @@ -2721,7 +2575,7 @@ dependencies = [ [[package]] name = "tendermint-proto" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "bytes", "flex-error", @@ -2738,7 +2592,7 @@ dependencies = [ [[package]] name = "tendermint-rpc" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "bytes", "flex-error", @@ -2762,7 +2616,7 @@ dependencies = [ [[package]] name = "tendermint-testgen" version = "0.23.5" -source = "git+https://github.com/heliaxdev/tendermint-rs?rev=95c52476bc37927218374f94ac8e2a19bd35bec9#95c52476bc37927218374f94ac8e2a19bd35bec9" +source = "git+https://github.com/heliaxdev/tendermint-rs?branch=bat/abciplus#2e9e0d058a68e2534974ff7d22b9058d4ebda3be" dependencies = [ "ed25519-dalek", "gumdrop", From 9bccd81502be42f992bb823081254780792615ea Mon Sep 17 00:00:00 2001 From: satan Date: Mon, 10 Oct 2022 11:05:02 +0200 Subject: [PATCH 11/28] [chore]: Merging in some changes from code review --- shared/src/ledger/storage/merkle_tree.rs | 77 +++++++++++++++++++++--- shared/src/ledger/storage/traits.rs | 15 ++--- 2 files changed, 78 insertions(+), 14 deletions(-) diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index ba20544d7d..5e1efa6c74 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -335,7 +335,12 @@ impl MerkleTree { /// Delete the value corresponding to the given key pub fn delete(&mut self, key: &Key) -> Result<()> { let (store_type, sub_key) = StoreType::sub_key(key)?; - self.tree_mut(&store_type).subtree_delete(&sub_key) + let sub_root = self.tree_mut(&store_type).subtree_delete(&sub_key)?; + if store_type != StoreType::Base { + let base_key = H::hash(&store_type.to_string()); + self.base.update(base_key.into(), sub_root)?; + } + Ok(()) } /// Get the root @@ -402,10 +407,12 @@ impl MerkleTree { ref mut right, .. } = ep; - let ep = left.as_mut().or(right.as_mut()).expect( - "A left or right existence proof should exist.", - ); - ep.leaf = Some(ibc_leaf_spec::()); + if let Some(left) = left.as_mut() { + left.leaf = Some(ibc_leaf_spec::()); + } + if let Some(right) = right.as_mut() { + right.leaf = Some(ibc_leaf_spec::()); + } } _ => unreachable!(), } @@ -580,6 +587,7 @@ mod test { let key_prefix: Key = Address::Internal(InternalAddress::Ibc).to_db_key().into(); let ibc_key = key_prefix.push(&"test".to_string()).unwrap(); + let ibc_non_key = key_prefix.push(&"test2".to_string()).unwrap(); let key_prefix: Key = Address::Internal(InternalAddress::PoS).to_db_key().into(); let pos_key = key_prefix.push(&"test".to_string()).unwrap(); @@ -595,10 +603,65 @@ mod test { tree.update(&pos_key, [2u8; 8]).unwrap(); assert!(tree.has_key(&pos_key).unwrap()); + // update IBC tree + tree.update(&ibc_non_key, [2u8; 8]).unwrap(); + assert!(tree.has_key(&ibc_non_key).unwrap()); + assert!(tree.has_key(&ibc_key).unwrap()); + assert!(tree.has_key(&pos_key).unwrap()); // delete a value on IBC tree - tree.delete(&ibc_key).unwrap(); - assert!(!tree.has_key(&ibc_key).unwrap()); + tree.delete(&ibc_non_key).unwrap(); + assert!(!tree.has_key(&ibc_non_key).unwrap()); + assert!(tree.has_key(&ibc_key).unwrap()); assert!(tree.has_key(&pos_key).unwrap()); + + // get and verify non-existence proof for the deleted key + let nep = tree + .get_non_existence_proof(&ibc_non_key) + .expect("Test failed"); + let subtree_nep = nep.ops.get(0).expect("Test failed"); + let nep_commitment_proof = + CommitmentProof::decode(&*subtree_nep.data).expect("Test failed"); + let non_existence_proof = + match nep_commitment_proof.clone().proof.expect("Test failed") { + Ics23Proof::Nonexist(nep) => nep, + _ => unreachable!(), + }; + let subtree_root = if let Some(left) = &non_existence_proof.left { + ics23::calculate_existence_root(left).unwrap() + } else if let Some(right) = &non_existence_proof.right { + ics23::calculate_existence_root(right).unwrap() + } else { + unreachable!() + }; + let (store_type, sub_key) = + StoreType::sub_key(&ibc_non_key).expect("Test failed"); + let specs = ibc_proof_specs::(); + + let nep_verification_res = ics23::verify_non_membership( + &nep_commitment_proof, + &specs[0], + &subtree_root, + sub_key.to_string().as_bytes(), + ); + assert!(nep_verification_res); + let basetree_ep = nep.ops.get(1).unwrap(); + let basetree_ep_commitment_proof = + CommitmentProof::decode(&*basetree_ep.data).unwrap(); + let basetree_ics23_ep = + match basetree_ep_commitment_proof.clone().proof.unwrap() { + Ics23Proof::Exist(ep) => ep, + _ => unreachable!(), + }; + let basetree_root = + ics23::calculate_existence_root(&basetree_ics23_ep).unwrap(); + let basetree_verification_res = ics23::verify_membership( + &basetree_ep_commitment_proof, + &specs[1], + &basetree_root, + store_type.to_string().as_bytes(), + &subtree_root, + ); + assert!(basetree_verification_res); } #[test] diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs index fb7b5b662c..5491b78685 100644 --- a/shared/src/ledger/storage/traits.rs +++ b/shared/src/ledger/storage/traits.rs @@ -40,7 +40,7 @@ pub trait SubTreeWrite { value: MerkleValue, ) -> Result; /// Delete a key from the sub-tree - fn subtree_delete(&mut self, key: &Key) -> Result<(), Error>; + fn subtree_delete(&mut self, key: &Key) -> Result; } impl<'a, H: StorageHasher + Default> SubTreeRead for &'a Smt { @@ -97,10 +97,10 @@ impl<'a, H: StorageHasher + Default> SubTreeWrite for &'a mut Smt { .map_err(|err| Error::MerkleTree(err.to_string())) } - fn subtree_delete(&mut self, key: &Key) -> Result<(), Error> { + fn subtree_delete(&mut self, key: &Key) -> Result { let value = Hash::zero(); self.update(H::hash(key.to_string()).into(), value) - .and(Ok(())) + .map(Hash::from) .map_err(|err| Error::MerkleTree(err.to_string())) } } @@ -156,11 +156,11 @@ impl<'a, H: StorageHasher + Default> SubTreeWrite for &'a mut Amt { .map_err(|err| Error::MerkleTree(err.to_string())) } - fn subtree_delete(&mut self, key: &Key) -> Result<(), Error> { + fn subtree_delete(&mut self, key: &Key) -> Result { let key = StringKey::try_from_bytes(key.to_string().as_bytes())?; let value = TreeBytes::zero(); self.update(key, value) - .and(Ok(())) + .map(Hash::from) .map_err(|err| Error::MerkleTree(format!("{:?}", err))) } } @@ -203,9 +203,10 @@ impl<'a> SubTreeWrite for &'a mut BridgePoolTree { } } - fn subtree_delete(&mut self, key: &Key) -> Result<(), Error> { + fn subtree_delete(&mut self, key: &Key) -> Result { self.delete_key(key) - .map_err(|err| Error::MerkleTree(err.to_string())) + .map_err(|err| Error::MerkleTree(err.to_string()))?; + Ok(self.root()) } } From 35bb9d4c2b5cfb257d898d322eabeb137c1072dd Mon Sep 17 00:00:00 2001 From: satan Date: Mon, 10 Oct 2022 14:56:17 +0200 Subject: [PATCH 12/28] [feat]: Small cleanups. Added the signed merkle tree root to accounts storage --- shared/src/ledger/storage/merkle_tree.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index 5e1efa6c74..21f16031ad 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -17,7 +17,7 @@ use thiserror::Error; use super::traits::{StorageHasher, SubTreeRead, SubTreeWrite}; use super::IBC_KEY_LIMIT; use crate::bytes::ByteBuf; -use crate::ledger::eth_bridge::storage::bridge_pool::BridgePoolTree; +use crate::ledger::eth_bridge::storage::bridge_pool::{BridgePoolTree, get_signed_root_key}; use crate::ledger::storage::ics23_specs::ibc_leaf_spec; use crate::ledger::storage::{ics23_specs, types}; use crate::types::address::{Address, InternalAddress}; @@ -177,7 +177,13 @@ impl StoreType { Ok((StoreType::Ibc, key.sub_key()?)) } InternalAddress::EthBridgePool => { - Ok((StoreType::BridgePool, key.sub_key()?)) + // the root of this sub-tree is kept in accounts + // storage along with a quorum of validator signatures + if *key == get_signed_root_key() { + Ok((StoreType::Account, key.clone())) + } else { + Ok((StoreType::BridgePool, key.sub_key()?)) + } } // use the same key for Parameters _ => Ok((StoreType::Account, key.clone())), From f3f1a32b2b3608328fcfade63fb25d55d3c63efe Mon Sep 17 00:00:00 2001 From: satan Date: Wed, 12 Oct 2022 10:39:22 +0200 Subject: [PATCH 13/28] [fix]: Fixed some broken imports --- apps/src/lib/node/ledger/protocol/mod.rs | 3 +- .../transactions/ethereum_events/events.rs | 3 +- .../transactions/ethereum_events/mod.rs | 5 +- .../transactions/ethereum_events/read.rs | 3 +- .../transactions/ethereum_events/update.rs | 3 +- apps/src/lib/node/ledger/shell/mod.rs | 8 +- .../lib/node/ledger/shell/prepare_proposal.rs | 3 +- .../shell/vote_extensions/eth_events.rs | 3 +- .../shell/vote_extensions/val_set_update.rs | 3 +- apps/src/lib/node/ledger/storage/mod.rs | 3 +- apps/src/lib/node/ledger/storage/rocksdb.rs | 3 +- .../ledger/eth_bridge/storage/bridge_pool.rs | 221 ++++++++++-------- shared/src/ledger/storage/merkle_tree.rs | 18 +- shared/src/ledger/storage/mod.rs | 10 +- shared/src/types/eth_bridge_pool.rs | 6 +- tests/src/native_vp/pos.rs | 3 +- 16 files changed, 178 insertions(+), 120 deletions(-) diff --git a/apps/src/lib/node/ledger/protocol/mod.rs b/apps/src/lib/node/ledger/protocol/mod.rs index 35ca06fc60..9ffc1cd367 100644 --- a/apps/src/lib/node/ledger/protocol/mod.rs +++ b/apps/src/lib/node/ledger/protocol/mod.rs @@ -12,8 +12,9 @@ use namada::ledger::ibc::vp::{Ibc, IbcToken}; use namada::ledger::native_vp::{self, NativeVp}; use namada::ledger::parameters::{self, ParametersVp}; use namada::ledger::pos::{self, PosVP}; +use namada::ledger::storage::traits::StorageHasher; use namada::ledger::storage::write_log::WriteLog; -use namada::ledger::storage::{DB, DBIter, Storage, traits::StorageHasher}; +use namada::ledger::storage::{DBIter, Storage, DB}; use namada::ledger::treasury::TreasuryVp; use namada::proto::{self, Tx}; use namada::types::address::{Address, InternalAddress}; diff --git a/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/events.rs b/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/events.rs index 2564830a2c..b639a01fd2 100644 --- a/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/events.rs +++ b/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/events.rs @@ -4,7 +4,8 @@ use std::collections::BTreeSet; use eyre::Result; use namada::ledger::eth_bridge::storage::wrapped_erc20s; -use namada::ledger::storage::{DBIter, Storage, StorageHasher, DB}; +use namada::ledger::storage::traits::StorageHasher; +use namada::ledger::storage::{DBIter, Storage, DB}; use namada::types::ethereum_events::{EthereumEvent, TransferToNamada}; use namada::types::storage::Key; diff --git a/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/mod.rs b/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/mod.rs index a9b24deb39..8d9ea01eff 100644 --- a/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/mod.rs +++ b/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/mod.rs @@ -14,7 +14,8 @@ use eth_msgs::{EthMsg, EthMsgUpdate}; use eyre::{eyre, Result}; use namada::ledger::eth_bridge::storage::eth_msgs::Keys; use namada::ledger::pos::types::WeightedValidator; -use namada::ledger::storage::{DBIter, Storage, StorageHasher, DB}; +use namada::ledger::storage::traits::StorageHasher; +use namada::ledger::storage::{DBIter, Storage, DB}; use namada::types::address::Address; use namada::types::ethereum_events::EthereumEvent; use namada::types::storage::{self, BlockHeight}; @@ -306,7 +307,7 @@ mod tests { use namada::ledger::pos::types::ValidatorSet; use namada::ledger::storage::mockdb::MockDB; use namada::ledger::storage::testing::TestStorage; - use namada::ledger::storage::Sha256Hasher; + use namada::ledger::storage::traits::Sha256Hasher; use namada::types::address; use namada::types::ethereum_events::testing::{ arbitrary_amount, arbitrary_eth_address, arbitrary_nonce, diff --git a/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/read.rs b/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/read.rs index 5f377f8133..90cc960509 100644 --- a/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/read.rs +++ b/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/read.rs @@ -1,7 +1,8 @@ //! Helpers for reading from storage use borsh::BorshDeserialize; use eyre::{eyre, Result}; -use namada::ledger::storage::{DBIter, Storage, StorageHasher, DB}; +use namada::ledger::storage::traits::StorageHasher; +use namada::ledger::storage::{DBIter, Storage, DB}; use namada::types::storage; use namada::types::token::Amount; diff --git a/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/update.rs b/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/update.rs index d6aebac3b6..092dada10a 100644 --- a/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/update.rs +++ b/apps/src/lib/node/ledger/protocol/transactions/ethereum_events/update.rs @@ -1,7 +1,8 @@ //! Helpers for writing to storage use borsh::{BorshDeserialize, BorshSerialize}; use eyre::Result; -use namada::ledger::storage::{DBIter, Storage, StorageHasher, DB}; +use namada::ledger::storage::traits::StorageHasher; +use namada::ledger::storage::{DBIter, Storage, DB}; use namada::types::storage; use namada::types::token::Amount; diff --git a/apps/src/lib/node/ledger/shell/mod.rs b/apps/src/lib/node/ledger/shell/mod.rs index 1f179c0db9..2936cf4db9 100644 --- a/apps/src/lib/node/ledger/shell/mod.rs +++ b/apps/src/lib/node/ledger/shell/mod.rs @@ -26,10 +26,9 @@ use namada::ledger::pos::namada_proof_of_stake::types::{ ActiveValidator, ValidatorSetUpdate, }; use namada::ledger::pos::namada_proof_of_stake::PosBase; +use namada::ledger::storage::traits::{Sha256Hasher, StorageHasher}; use namada::ledger::storage::write_log::WriteLog; -use namada::ledger::storage::{ - DBIter, traits::Sha256Hasher, Storage, traits::StorageHasher, DB, -}; +use namada::ledger::storage::{DBIter, Storage, DB}; use namada::ledger::{ibc, parameters, pos}; use namada::proto::{self, Tx}; use namada::types::chain::ChainId; @@ -760,7 +759,8 @@ mod test_utils { #[cfg(not(feature = "abcipp"))] use namada::ledger::pos::namada_proof_of_stake::types::VotingPower; use namada::ledger::storage::mockdb::MockDB; - use namada::ledger::storage::{BlockStateWrite, MerkleTree, traits::Sha256Hasher}; + use namada::ledger::storage::traits::Sha256Hasher; + use namada::ledger::storage::{BlockStateWrite, MerkleTree}; use namada::types::address::{xan, EstablishedAddressGen}; use namada::types::chain::ChainId; use namada::types::hash::Hash; diff --git a/apps/src/lib/node/ledger/shell/prepare_proposal.rs b/apps/src/lib/node/ledger/shell/prepare_proposal.rs index 6880bd0598..521c704dca 100644 --- a/apps/src/lib/node/ledger/shell/prepare_proposal.rs +++ b/apps/src/lib/node/ledger/shell/prepare_proposal.rs @@ -1,6 +1,7 @@ //! Implementation of the [`RequestPrepareProposal`] ABCI++ method for the Shell -use namada::ledger::storage::{DB, DBIter, traits::StorageHasher}; +use namada::ledger::storage::traits::StorageHasher; +use namada::ledger::storage::{DBIter, DB}; use namada::proto::Tx; use namada::types::storage::BlockHeight; use namada::types::transaction::tx_types::TxType; diff --git a/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs b/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs index 2ced18ae08..f1caae112a 100644 --- a/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs +++ b/apps/src/lib/node/ledger/shell/vote_extensions/eth_events.rs @@ -3,7 +3,8 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use namada::ledger::pos::namada_proof_of_stake::types::VotingPower; -use namada::ledger::storage::{DB, DBIter, traits::StorageHasher}; +use namada::ledger::storage::traits::StorageHasher; +use namada::ledger::storage::{DBIter, DB}; use namada::proto::Signed; use namada::types::ethereum_events::EthereumEvent; use namada::types::storage::BlockHeight; diff --git a/apps/src/lib/node/ledger/shell/vote_extensions/val_set_update.rs b/apps/src/lib/node/ledger/shell/vote_extensions/val_set_update.rs index 91d581337f..542bf6b81f 100644 --- a/apps/src/lib/node/ledger/shell/vote_extensions/val_set_update.rs +++ b/apps/src/lib/node/ledger/shell/vote_extensions/val_set_update.rs @@ -4,7 +4,8 @@ use std::collections::HashMap; use namada::ledger::pos::types::VotingPower; -use namada::ledger::storage::{DB, DBIter, traits::StorageHasher}; +use namada::ledger::storage::traits::StorageHasher; +use namada::ledger::storage::{DBIter, DB}; use namada::types::storage::BlockHeight; use namada::types::vote_extensions::validator_set_update; #[cfg(feature = "abcipp")] diff --git a/apps/src/lib/node/ledger/storage/mod.rs b/apps/src/lib/node/ledger/storage/mod.rs index 8017c6b7e4..373da98d5a 100644 --- a/apps/src/lib/node/ledger/storage/mod.rs +++ b/apps/src/lib/node/ledger/storage/mod.rs @@ -9,7 +9,8 @@ use arse_merkle_tree::blake2b::Blake2bHasher; use arse_merkle_tree::traits::Hasher; use arse_merkle_tree::H256; use blake2b_rs::{Blake2b, Blake2bBuilder}; -use namada::ledger::storage::{Storage, traits::StorageHasher}; +use namada::ledger::storage::traits::StorageHasher; +use namada::ledger::storage::Storage; #[derive(Default)] pub struct PersistentStorageHasher(Blake2bHasher); diff --git a/apps/src/lib/node/ledger/storage/rocksdb.rs b/apps/src/lib/node/ledger/storage/rocksdb.rs index 128900240c..069b6ed0a7 100644 --- a/apps/src/lib/node/ledger/storage/rocksdb.rs +++ b/apps/src/lib/node/ledger/storage/rocksdb.rs @@ -930,7 +930,8 @@ mod imp { #[cfg(test)] mod test { - use namada::ledger::storage::{MerkleTree, traits::Sha256Hasher}; + use namada::ledger::storage::traits::Sha256Hasher; + use namada::ledger::storage::MerkleTree; use namada::types::address::EstablishedAddressGen; use namada::types::storage::{BlockHash, Epoch, Epochs}; use tempfile::tempdir; diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index f900efb595..66cdc346ec 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -157,7 +157,10 @@ impl BridgePoolTree { for (key, value) in keys.iter().zip(values.iter()) { let hash = Self::parse_key(key)?; if hash != value.keccak256() { - return Err(eyre!("Hashes of keys did not match hashes of values.").into()); + return Err(eyre!( + "Hashes of keys did not match hashes of values." + ) + .into()); } leaves.insert(hash); } @@ -358,8 +361,8 @@ mod test_bridge_pool_tree { use proptest::prelude::*; use super::*; - use crate::types::ethereum_events::EthAddress; use crate::types::eth_bridge_pool::{GasFee, TransferToEthereum}; + use crate::types::ethereum_events::EthAddress; /// An established user address for testing & development fn bertha_address() -> Address { @@ -375,7 +378,7 @@ mod test_bridge_pool_tree { assert_eq!(tree.root().0, [0; 32]); let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([1;20]), + asset: EthAddress([1; 20]), recipient: EthAddress([2; 20]), amount: 1.into(), nonce: 42u64.into(), @@ -383,10 +386,11 @@ mod test_bridge_pool_tree { gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); - let root = KeccakHash::from(tree.update_key(&key).expect("Test failed")); + let root = + KeccakHash::from(tree.update_key(&key).expect("Test failed")); assert_eq!(root, transfer.keccak256()); } @@ -397,21 +401,23 @@ mod test_bridge_pool_tree { for i in 0..2 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); transfers.push(transfer); let _ = tree.update_key(&key).expect("Test failed"); } - let expected: Hash = hash_pair(transfers[0].keccak256(), transfers[1].keccak256()).into(); + let expected: Hash = + hash_pair(transfers[0].keccak256(), transfers[1].keccak256()) + .into(); assert_eq!(tree.root(), expected); } @@ -423,26 +429,29 @@ mod test_bridge_pool_tree { for i in 0..3 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); transfers.push(transfer); let _ = tree.update_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); - let hashes: BTreeSet = transfers.iter().map(|t| t.keccak256()).collect(); + let hashes: BTreeSet = + transfers.iter().map(|t| t.keccak256()).collect(); assert_eq!(hashes, tree.store); - let left_hash = hash_pair(transfers[0].keccak256(), transfers[1].keccak256()); - let right_hash = hash_pair(transfers[2].keccak256(), Default::default()); + let left_hash = + hash_pair(transfers[0].keccak256(), transfers[1].keccak256()); + let right_hash = + hash_pair(transfers[2].keccak256(), Default::default()); let expected: Hash = hash_pair(left_hash, right_hash).into(); assert_eq!(tree.root(), expected); } @@ -454,7 +463,7 @@ mod test_bridge_pool_tree { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([1;20]), + asset: EthAddress([1; 20]), recipient: EthAddress([2; 20]), amount: 1.into(), nonce: 42u64.into(), @@ -462,10 +471,11 @@ mod test_bridge_pool_tree { gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); - let root = KeccakHash::from(tree.update_key(&key).expect("Test failed")); + let root = + KeccakHash::from(tree.update_key(&key).expect("Test failed")); assert_eq!(root, transfer.keccak256()); tree.delete_key(&key).expect("Test failed"); assert_eq!(tree.root().0, [0; 32]); @@ -479,15 +489,15 @@ mod test_bridge_pool_tree { for i in 0..3 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); @@ -498,7 +508,9 @@ mod test_bridge_pool_tree { tree.delete_key(&Key::from(&transfers[1])) .expect("Test failed"); - let expected: Hash = hash_pair(transfers[0].keccak256(), transfers[2].keccak256()).into(); + let expected: Hash = + hash_pair(transfers[0].keccak256(), transfers[2].keccak256()) + .into(); assert_eq!(tree.root(), expected); } @@ -515,11 +527,14 @@ mod test_bridge_pool_tree { gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let expected = transfer.keccak256(); let key = Key::from(&transfer); - assert_eq!(BridgePoolTree::parse_key(&key).expect("Test failed"), expected); + assert_eq!( + BridgePoolTree::parse_key(&key).expect("Test failed"), + expected + ); } /// Test that parsing a key with multiple segments fails @@ -535,24 +550,31 @@ mod test_bridge_pool_tree { gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let hash = transfer.keccak256().to_string(); - let key = Key{segments: vec![DbKeySeg::AddressSeg(bertha_address()), DbKeySeg::StringSeg(hash)]}; + let key = Key { + segments: vec![ + DbKeySeg::AddressSeg(bertha_address()), + DbKeySeg::StringSeg(hash), + ], + }; assert!(BridgePoolTree::parse_key(&key).is_err()); } /// Test that parsing a key that is not a hash fails #[test] fn test_key_not_hash() { - let key = Key{segments: vec![DbKeySeg::StringSeg("bloop".into())]}; + let key = Key { + segments: vec![DbKeySeg::StringSeg("bloop".into())], + }; assert!(BridgePoolTree::parse_key(&key).is_err()); } /// Test that [`contains_key`] works correctly #[test] fn test_contains_key() { - let mut tree = BridgePoolTree::default(); + let mut tree = BridgePoolTree::default(); let transfer = PendingTransfer { transfer: TransferToEthereum { asset: EthAddress([1; 20]), @@ -563,10 +585,13 @@ mod test_bridge_pool_tree { gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; tree.update_key(&Key::from(&transfer)).expect("Test failed"); - assert!(tree.contains_key(&Key::from(&transfer)).expect("Test failed")); + assert!( + tree.contains_key(&Key::from(&transfer)) + .expect("Test failed") + ); let transfer = PendingTransfer { transfer: TransferToEthereum { asset: EthAddress([1; 20]), @@ -577,9 +602,13 @@ mod test_bridge_pool_tree { gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; - assert!(!tree.contains_key(&Key::from(&transfer)).expect("Test failed")); + assert!( + !tree + .contains_key(&Key::from(&transfer)) + .expect("Test failed") + ); } /// Test that the empty proof works. @@ -588,7 +617,9 @@ mod test_bridge_pool_tree { let tree = BridgePoolTree::default(); let keys = vec![]; let values = vec![]; - let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + let proof = tree + .get_membership_proof(&keys, values) + .expect("Test failed"); assert!(proof.verify(Default::default())); } @@ -600,17 +631,19 @@ mod test_bridge_pool_tree { asset: EthAddress([0; 20]), recipient: EthAddress([0; 20]), amount: 0.into(), - nonce: 0.into() + nonce: 0.into(), }, gas_fee: GasFee { amount: 0.into(), - payer: bertha_address() - } + payer: bertha_address(), + }, }; let mut tree = BridgePoolTree::default(); let key = Key::from(&transfer); let _ = tree.update_key(&key).expect("Test failed"); - let proof = tree.get_membership_proof(array::from_ref(&key), vec![transfer]).expect("Test failed"); + let proof = tree + .get_membership_proof(array::from_ref(&key), vec![transfer]) + .expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -623,15 +656,15 @@ mod test_bridge_pool_tree { for i in 0..2 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); @@ -639,11 +672,12 @@ mod test_bridge_pool_tree { let _ = tree.update_key(&key).expect("Test failed"); } let key = Key::from(&transfers[0]); - let proof = tree.get_membership_proof( - array::from_ref(&key), - vec![transfers.remove(0)] - ) - .expect("Test failed"); + let proof = tree + .get_membership_proof( + array::from_ref(&key), + vec![transfers.remove(0)], + ) + .expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -655,15 +689,15 @@ mod test_bridge_pool_tree { for i in 0..3 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); @@ -673,7 +707,9 @@ mod test_bridge_pool_tree { transfers.sort_by_key(|t| t.keccak256()); let keys = vec![Key::from(&transfers[0]), Key::from(&transfers[1])]; let values = vec![transfers[0].clone(), transfers[1].clone()]; - let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + let proof = tree + .get_membership_proof(&keys, values) + .expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -685,15 +721,15 @@ mod test_bridge_pool_tree { for i in 0..3 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); transfers.push(transfer); @@ -701,7 +737,9 @@ mod test_bridge_pool_tree { } let keys = vec![]; let values = vec![]; - let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + let proof = tree + .get_membership_proof(&keys, values) + .expect("Test failed"); assert!(proof.verify(tree.root().into())) } @@ -713,15 +751,15 @@ mod test_bridge_pool_tree { for i in 0..2 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); transfers.push(transfer); @@ -729,7 +767,9 @@ mod test_bridge_pool_tree { } transfers.sort_by_key(|t| t.keccak256()); let keys: Vec<_> = transfers.iter().map(Key::from).collect(); - let proof = tree.get_membership_proof(&keys, transfers).expect("Test failed"); + let proof = tree + .get_membership_proof(&keys, transfers) + .expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -741,15 +781,15 @@ mod test_bridge_pool_tree { for i in 0..3 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); transfers.push(transfer); @@ -757,7 +797,9 @@ mod test_bridge_pool_tree { } transfers.sort_by_key(|t| t.keccak256()); let keys: Vec<_> = transfers.iter().map(Key::from).collect(); - let proof = tree.get_membership_proof(&keys, transfers).expect("Test failed"); + let proof = tree + .get_membership_proof(&keys, transfers) + .expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -769,64 +811,57 @@ mod test_bridge_pool_tree { for i in 0..5 { let transfer = PendingTransfer { transfer: TransferToEthereum { - asset: EthAddress([i;20]), - recipient: EthAddress([i+1; 20]), + asset: EthAddress([i; 20]), + recipient: EthAddress([i + 1; 20]), amount: (i as u64).into(), nonce: 42u64.into(), }, gas_fee: GasFee { amount: 0.into(), payer: bertha_address(), - } + }, }; let key = Key::from(&transfer); transfers.push(transfer); let _ = tree.update_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); - let keys: Vec<_> = transfers - .iter() - .step_by(2) - .map(Key::from) - .collect(); - let values: Vec<_> = transfers - .iter() - .step_by(2) - .cloned() - .collect(); - let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + let keys: Vec<_> = transfers.iter().step_by(2).map(Key::from).collect(); + let values: Vec<_> = transfers.iter().step_by(2).cloned().collect(); + let proof = tree + .get_membership_proof(&keys, values) + .expect("Test failed"); assert!(proof.verify(tree.root().into())); } /// Create a random set of transfers. - fn random_transfers(number: usize) -> impl Strategy> { + fn random_transfers( + number: usize, + ) -> impl Strategy> { prop::collection::vec( - ( - prop::array::uniform20(0u8..), - prop::num::u64::ANY, - ), + (prop::array::uniform20(0u8..), prop::num::u64::ANY), 0..=number, ) - .prop_flat_map( | addrs | + .prop_flat_map(|addrs| { Just( - addrs.into_iter().map(| (addr, nonce)| - PendingTransfer { + addrs + .into_iter() + .map(|(addr, nonce)| PendingTransfer { transfer: TransferToEthereum { asset: EthAddress(addr), recipient: EthAddress(addr), amount: Default::default(), - nonce: nonce.into() + nonce: nonce.into(), }, gas_fee: GasFee { amount: Default::default(), - payer: bertha_address() - } - }, - ) - .dedup() - .collect::>() + payer: bertha_address(), + }, + }) + .dedup() + .collect::>(), ) - ) + }) } prop_compose! { @@ -843,7 +878,7 @@ mod test_bridge_pool_tree { } } - proptest!{ + proptest! { /// Given a random tree and a subset of leaves, /// verify that the constructed multi-proof correctly /// verifies. @@ -866,4 +901,4 @@ mod test_bridge_pool_tree { assert!(proof.verify(tree.root().into())); } } -} \ No newline at end of file +} diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index 21f16031ad..1d175e83d2 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -17,7 +17,9 @@ use thiserror::Error; use super::traits::{StorageHasher, SubTreeRead, SubTreeWrite}; use super::IBC_KEY_LIMIT; use crate::bytes::ByteBuf; -use crate::ledger::eth_bridge::storage::bridge_pool::{BridgePoolTree, get_signed_root_key}; +use crate::ledger::eth_bridge::storage::bridge_pool::{ + get_signed_root_key, BridgePoolTree, +}; use crate::ledger::storage::ics23_specs::ibc_leaf_spec; use crate::ledger::storage::{ics23_specs, types}; use crate::types::address::{Address, InternalAddress}; @@ -717,7 +719,8 @@ mod test { std::array::from_ref(&ibc_key), vec![ibc_val.clone().into()], ) - .unwrap(){ + .unwrap() + { MembershipProof::ICS23(proof) => proof, _ => panic!("Test failed"), }; @@ -770,11 +773,12 @@ mod test { tree.update(&pos_key, pos_val.clone()).unwrap(); let specs = proof_specs::(); - let proof = match tree.get_sub_tree_existence_proof( - std::array::from_ref(&pos_key), - vec![pos_val.clone().into()], - ) - .unwrap() + let proof = match tree + .get_sub_tree_existence_proof( + std::array::from_ref(&pos_key), + vec![pos_val.clone().into()], + ) + .unwrap() { MembershipProof::ICS23(proof) => proof, _ => panic!("Test failed"), diff --git a/shared/src/ledger/storage/mod.rs b/shared/src/ledger/storage/mod.rs index 1dd03af3d9..61f9ced6be 100644 --- a/shared/src/ledger/storage/mod.rs +++ b/shared/src/ledger/storage/mod.rs @@ -523,7 +523,8 @@ where .block .tree .get_sub_tree_existence_proof(array::from_ref(key), vec![value]) - .map_err(Error::MerkleTreeError)? { + .map_err(Error::MerkleTreeError)? + { self.block .tree .get_tendermint_proof(key, proof) @@ -540,11 +541,14 @@ where array::from_ref(key), vec![value], ) - .map_err(Error::MerkleTreeError)? { + .map_err(Error::MerkleTreeError)? + { tree.get_tendermint_proof(key, proof) .map_err(Error::MerkleTreeError) } else { - Err(Error::MerkleTreeError(MerkleTreeError::TendermintProof)) + Err(Error::MerkleTreeError( + MerkleTreeError::TendermintProof, + )) } } None => Err(Error::NoMerkleTree { height }), diff --git a/shared/src/types/eth_bridge_pool.rs b/shared/src/types/eth_bridge_pool.rs index e7c55df8d8..36a378b8db 100644 --- a/shared/src/types/eth_bridge_pool.rs +++ b/shared/src/types/eth_bridge_pool.rs @@ -68,7 +68,11 @@ impl keccak::encode::Encode for PendingTransfer { impl From<&PendingTransfer> for Key { fn from(transfer: &PendingTransfer) -> Self { - Key{segments: vec![DbKeySeg::StringSeg(transfer.keccak256().to_string())]} + Key { + segments: vec![DbKeySeg::StringSeg( + transfer.keccak256().to_string(), + )], + } } } diff --git a/tests/src/native_vp/pos.rs b/tests/src/native_vp/pos.rs index 7be49ac538..e7c7daf7c1 100644 --- a/tests/src/native_vp/pos.rs +++ b/tests/src/native_vp/pos.rs @@ -411,7 +411,8 @@ mod tests { // Use the tx_env to run PoS VP let tx_env = tx_host_env::take(); let vp_env = TestNativeVpEnv::new(tx_env); - let result: Result = vp_env.validate_tx(PosVP::new, |_tx_data| {}); + let result: Result = + vp_env.validate_tx(PosVP::new, |_tx_data| {}); // Put the tx_env back before checking the result tx_host_env::set(vp_env.tx_env); let result = From 2ef1f95b4f1230f0fe48a637ba1c70f77affa3ad Mon Sep 17 00:00:00 2001 From: satan Date: Wed, 12 Oct 2022 10:48:47 +0200 Subject: [PATCH 14/28] [fix]: Fixing broken doc link --- shared/src/ledger/eth_bridge/storage/bridge_pool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index 66cdc346ec..f1dfc181c9 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -127,7 +127,7 @@ impl BridgePoolTree { } } - /// Return the root as a [`Hash`] type. + /// Return the root as a [`struct@Hash`] type. pub fn root(&self) -> Hash { self.root.clone().into() } From 5b259eba91878e43484c45be6d5a3559a89fbf22 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 12 Oct 2022 09:16:07 +0000 Subject: [PATCH 15/28] [ci] wasm checksums update --- wasm/checksums.json | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/wasm/checksums.json b/wasm/checksums.json index 057829c654..558b72d3c0 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,20 +1,19 @@ { - "tx_bond.wasm": "tx_bond.aac575fac2ddaba8fca6f341b2ca6a77dd430767aae628e75aebf0b05470173f.wasm", "tx_bridge_pool.wasm": "tx_bridge_pool.e21563260c03cfdab1f195878f49bf93722027ad26fcd097cfebbc5c4d279082.wasm", - "tx_from_intent.wasm": "tx_from_intent.3b89f8ae7c2d0e78d813fd249bcfb80871205fa0eac306004184155df972bda5.wasm", - "tx_ibc.wasm": "tx_ibc.948b68260e10def4a1b80d0a13c8c02d25f18920cbbb6ef0febacd800cd2e4aa.wasm", - "tx_init_account.wasm": "tx_init_account.33ba50356486f46204bb311259446bad8217b3fad3338d3729097c4c27cf6123.wasm", - "tx_init_nft.wasm": "tx_init_nft.37dc3000a2365db54f0fbf550501e6d9ac6572820ce7a70dfa894e07e67bb764.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.f5db61cb13d2739fdb72e4f46b9f0413d41102d5b91b5b0c01fed87555c68723.wasm", - "tx_init_validator.wasm": "tx_init_validator.b564420e6a58e6a397df44c929e1e8e3d3297a76f17a008c0035cd95f46974d0.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.26733715c5ef27cb27a6f88cbef2d468f092e357c39f2272195b94db3a2ca63e.wasm", - "tx_transfer.wasm": "tx_transfer.eb6d5fa86d9276f3628e3e093acaf11a77b1f44d8016ac971803e8f4613bdc2f.wasm", - "tx_unbond.wasm": "tx_unbond.553d6ca840850f1e76c3fda04efc8d3a929b4e0e69c0129685f3871a060b3ed0.wasm", - "tx_update_vp.wasm": "tx_update_vp.8e12c05146f0189242f53ba0aa077729fb25b1617b179180b290a92f4d0117b1.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.0f6c8bb64f0b5121efffe1f72a8dfcd584b523979b7fdd3e73e93e61a46bf31b.wasm", - "tx_withdraw.wasm": "tx_withdraw.fdbdf0db6de1d53c259f84b503d807a67560a3b45f477301e9a0b20ea8275034.wasm", - "vp_nft.wasm": "vp_nft.b1387806bd245f55eb7ef6ba70f4e645eab7dcc048ac8d314d8162fdd021cb9d.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.356e4873a8d44eba2f5472c2d37485a30b24fd6785fe1dc017d031ec116dbe6f.wasm", - "vp_token.wasm": "vp_token.3f492f380226899d1c0da5d5b69a6de5e67b8a7ebfc5179a506bf38c23819c96.wasm", - "vp_user.wasm": "vp_user.c11d62664abc50e9b613acba04b040f93c2a8fe013a4a916e452c6323cb1bd29.wasm" + "tx_from_intent.wasm": "tx_from_intent.e767aa7d060b7fb2657d364f0cea06c20048b7c19e7799d932494a72a1de17b5.wasm", + "tx_ibc.wasm": "tx_ibc.3f8e471d8d99b238a7399b0aa1bbe41d4072554488eff5cc119b00c57b22345c.wasm", + "tx_init_account.wasm": "tx_init_account.4be0bb8d68dc00570b0a724ae46029eaee81f6dfc7202766a6657440769df69a.wasm", + "tx_init_nft.wasm": "tx_init_nft.d0d13453e56596f4d53c5971332c393b0136d58d2ced56074dc476f64b530282.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.f5447040cd013feaca417d5bac93a440312b930f997d3a565e81986dbb3d178c.wasm", + "tx_init_validator.wasm": "tx_init_validator.85db1169a7b37823bdb0eb30f719f36cf6ecff28a5bc4a3d543f6925c7e3a3fa.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.13ef749fad6f98b7e98c74039a65836777d3fe177a08f16dcea9b001fa39350c.wasm", + "tx_transfer.wasm": "tx_transfer.b2eb45f6f4327453e5b19ed822be4dd680ac255cd4e0f54a353c6a4bdebe4d5b.wasm", + "tx_unbond.wasm": "tx_unbond.9af49a6daeccf15a6b3bdbd241a7882f5ffe7b6cd2bcbc728940daad266c83a2.wasm", + "tx_update_vp.wasm": "tx_update_vp.a7b0c9370d60d4168a198af66ed5e3ce094e250e566bdff23ec0fbb2236d576e.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.6402700d3e400774d4a93946514d9c9e866cef5d42e48c824a2fe4f52224cb57.wasm", + "tx_withdraw.wasm": "tx_withdraw.6f0daba8ff3314202598898498dad586679b46700ddf63474a47efbc46281bae.wasm", + "vp_nft.wasm": "vp_nft.e3ca11213957817f55a30c365287d3cd03d7dbb96341940e00bfc818a442cb06.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.f4c080ef9463fe6eef3a066b13ee99fe79d1fb39825c8750d376d80873353e04.wasm", + "vp_token.wasm": "vp_token.a08656587dcaa572872f3757d05f30494b4add02d821c0101b4244a1068bfae2.wasm", + "vp_user.wasm": "vp_user.bde8e5cc24d67a85d4d9c56e884fd39b76e04ca5d040212ccf397d4c6b50801d.wasm" } \ No newline at end of file From 93000b0d28c9ed54b3a597b9cfddc7a99adda6bf Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 17 Oct 2022 14:54:57 +0000 Subject: [PATCH 16/28] [ci] wasm checksums update --- wasm/checksums.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/wasm/checksums.json b/wasm/checksums.json index 2634122c96..1250ca7e3e 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { "tx_bridge_pool.wasm": "tx_bridge_pool.e21563260c03cfdab1f195878f49bf93722027ad26fcd097cfebbc5c4d279082.wasm", - "tx_from_intent.wasm": "tx_from_intent.7a56e31fb9977d230d5d601129fd11e67bf54159ab2d694184fc934ec2244314.wasm", - "tx_ibc.wasm": "tx_ibc.fe0036ec90159b3e704247201345ddff0aea5fa2e234e85d0e4df895b509d692.wasm", - "tx_init_account.wasm": "tx_init_account.313e8ab8c7eac72e75f916c67a6c7ec2f204f77d60d89e825acc78b4856a70c5.wasm", - "tx_init_nft.wasm": "tx_init_nft.5339cef3b36a3a31ea370cd67e6a43f99e03d13032bb786335976dd251988d4e.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.d5598fcac82ebd5c618b84f4582992a2de80c2dfbb37f10fb574afaa36045ec2.wasm", - "tx_init_validator.wasm": "tx_init_validator.1e1374e7bcd0973cf7d3166085946ddf43443bb67037b56cfa6f2a5715d44ef2.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.15b0e03bc27c41feda24918f56263f85d84b26f43be831998c6c619baa92a601.wasm", - "tx_transfer.wasm": "tx_transfer.2195fe962f9cb0c776d8518d0df9a450cc2521510d60423b57f0e2744ce38564.wasm", - "tx_unbond.wasm": "tx_unbond.a7313bb14d1c3a852630f86fc07d5e048e5df19a8f4be193d95c21fbeb49ae03.wasm", - "tx_update_vp.wasm": "tx_update_vp.f21d0233f9629193cea49c9c3742c2cac6764b09dd0adc7360d1f649543f2c39.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.08daa0021aac28a1255ebb28005e1f07e01fc8118496934a0d46ee4456da7470.wasm", - "tx_withdraw.wasm": "tx_withdraw.0de22e367b9931045cf4c6b844cdd2e1390796e9cc7f8b15288d7753913e3ca9.wasm", - "vp_nft.wasm": "vp_nft.4656bec0cf0ff84b672605e45e25b16915a36ee982ffddf1ee0b7d6c72871e5a.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.41c53f6536966989374dfb4b732b389919c0b980fba316ed842dc4b889b3abc1.wasm", - "vp_token.wasm": "vp_token.6eff1ea735d6b79e72e9f860a261e3eb91004b829cda2e3e3cc8f1b24e3b6715.wasm", - "vp_user.wasm": "vp_user.7829b1e5eb367785abc50bb7eaefa917665bec380495c162e83e08eaa57065f7.wasm" + "tx_from_intent.wasm": "tx_from_intent.536ed89ef1c74d3c6b3e005d60cc53bbab7c36935b46bb69f7287de0a54f91e1.wasm", + "tx_ibc.wasm": "tx_ibc.790e710a87d31a215c19dd29d3c3723f6bb0e22482b3a368c21a367df99aefe8.wasm", + "tx_init_account.wasm": "tx_init_account.a50110eb561a84549708b98b5841358ed87de5a9b08f8a947711c5908eb13558.wasm", + "tx_init_nft.wasm": "tx_init_nft.bee3fbefc9e6319eea9244b9abc7fa5e80a62b43a003260803989856aef8d438.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.26ed1981f8f0ee5b9852dd96d7ad171707194056db5731e9915dbb1747892303.wasm", + "tx_init_validator.wasm": "tx_init_validator.8b37971addbd3ace29174db5f618f06b62115cd7b44ff1b7d756c9d4d81cbc56.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.659dbac8df06b8e6775e680ebb772c3d19733b9e14ea513c665a78ac70788610.wasm", + "tx_transfer.wasm": "tx_transfer.03a7bff45511f240ebdf92f5e4612e244cc937fda3a22ba0a77936e36d834f37.wasm", + "tx_unbond.wasm": "tx_unbond.74388ad956a8ed618974140836e97ae254ae9e8a3e24065908e3a318d55fd37b.wasm", + "tx_update_vp.wasm": "tx_update_vp.4e5d802da0ef98daa6c904522c6fd4964020cc9ce948f16579a6cec1793337b8.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.f3103ee1148954898e2cd92eb0134b34792e7a373a505f37544f389b3cd3cc88.wasm", + "tx_withdraw.wasm": "tx_withdraw.3e1619ad5db6dcb2146684bf54f2e383747fa81f1baf9d00005c4431a3d0a566.wasm", + "vp_nft.wasm": "vp_nft.31a3045be40eeabb48140d2f68db26006991dffb208f6bd394a0b6740cd5b4d0.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.d4b27eadcb98ed3664028bee05fe33f8acb7a59182ca22833a77df696d1cf369.wasm", + "vp_token.wasm": "vp_token.aea6ee5649995c6352d982687c30cfe44fcf05a0cd9cb9b0b48d80768633d098.wasm", + "vp_user.wasm": "vp_user.589011534fd04c4b44fb4412b2f58ea548628dc1ba4db5d45a9aaa1f9e6f0552.wasm" } \ No newline at end of file From 1ccb304447671d6c9495bee3782fd9ab94d2b167 Mon Sep 17 00:00:00 2001 From: satan Date: Tue, 18 Oct 2022 14:56:18 +0200 Subject: [PATCH 17/28] [fix]: Simplified some conversions, avoided unnecessary heap allocations --- shared/src/types/hash.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/shared/src/types/hash.rs b/shared/src/types/hash.rs index 4e63af1ad9..56654969fa 100644 --- a/shared/src/types/hash.rs +++ b/shared/src/types/hash.rs @@ -92,9 +92,7 @@ impl TryFrom for Hash { type Error = self::Error; fn try_from(string: String) -> HashResult { - let bytes: Vec = - Vec::from_hex(string).map_err(Error::FromStringError)?; - Self::try_from(bytes.as_slice()) + string.as_str().try_into() } } @@ -102,9 +100,10 @@ impl TryFrom<&str> for Hash { type Error = self::Error; fn try_from(string: &str) -> HashResult { - let bytes: Vec = - Vec::from_hex(string).map_err(Error::FromStringError)?; - Self::try_from(bytes.as_slice()) + Ok(Self( + <[u8; HASH_LENGTH]>::from_hex(string) + .map_err(Error::FromStringError)?, + )) } } From 038360dac981920ef804c1bca635bb5b011bf0de Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 18 Oct 2022 13:59:17 +0000 Subject: [PATCH 18/28] [ci] wasm checksums update --- wasm/checksums.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/wasm/checksums.json b/wasm/checksums.json index 1250ca7e3e..417c29a388 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,19 +1,19 @@ { "tx_bridge_pool.wasm": "tx_bridge_pool.e21563260c03cfdab1f195878f49bf93722027ad26fcd097cfebbc5c4d279082.wasm", - "tx_from_intent.wasm": "tx_from_intent.536ed89ef1c74d3c6b3e005d60cc53bbab7c36935b46bb69f7287de0a54f91e1.wasm", - "tx_ibc.wasm": "tx_ibc.790e710a87d31a215c19dd29d3c3723f6bb0e22482b3a368c21a367df99aefe8.wasm", - "tx_init_account.wasm": "tx_init_account.a50110eb561a84549708b98b5841358ed87de5a9b08f8a947711c5908eb13558.wasm", - "tx_init_nft.wasm": "tx_init_nft.bee3fbefc9e6319eea9244b9abc7fa5e80a62b43a003260803989856aef8d438.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.26ed1981f8f0ee5b9852dd96d7ad171707194056db5731e9915dbb1747892303.wasm", - "tx_init_validator.wasm": "tx_init_validator.8b37971addbd3ace29174db5f618f06b62115cd7b44ff1b7d756c9d4d81cbc56.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.659dbac8df06b8e6775e680ebb772c3d19733b9e14ea513c665a78ac70788610.wasm", - "tx_transfer.wasm": "tx_transfer.03a7bff45511f240ebdf92f5e4612e244cc937fda3a22ba0a77936e36d834f37.wasm", - "tx_unbond.wasm": "tx_unbond.74388ad956a8ed618974140836e97ae254ae9e8a3e24065908e3a318d55fd37b.wasm", - "tx_update_vp.wasm": "tx_update_vp.4e5d802da0ef98daa6c904522c6fd4964020cc9ce948f16579a6cec1793337b8.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.f3103ee1148954898e2cd92eb0134b34792e7a373a505f37544f389b3cd3cc88.wasm", - "tx_withdraw.wasm": "tx_withdraw.3e1619ad5db6dcb2146684bf54f2e383747fa81f1baf9d00005c4431a3d0a566.wasm", - "vp_nft.wasm": "vp_nft.31a3045be40eeabb48140d2f68db26006991dffb208f6bd394a0b6740cd5b4d0.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.d4b27eadcb98ed3664028bee05fe33f8acb7a59182ca22833a77df696d1cf369.wasm", - "vp_token.wasm": "vp_token.aea6ee5649995c6352d982687c30cfe44fcf05a0cd9cb9b0b48d80768633d098.wasm", - "vp_user.wasm": "vp_user.589011534fd04c4b44fb4412b2f58ea548628dc1ba4db5d45a9aaa1f9e6f0552.wasm" + "tx_from_intent.wasm": "tx_from_intent.37fcd749502d6874f00784c9c084cb0466908d6cd3b715f04caa5862b47385d8.wasm", + "tx_ibc.wasm": "tx_ibc.ca3b8328228baa5f815461bf9a9dadd142535fdbd5a164d8894a1003bf57d392.wasm", + "tx_init_account.wasm": "tx_init_account.6b2c033d3c973cdcb8c070cbbb0f864e67b42711d93291e36e7b76dc73af169e.wasm", + "tx_init_nft.wasm": "tx_init_nft.9296016fac6b3d834d74a239f83edb275987962d0cba98aa8268e1e0babee0df.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.2a312e8127a49a7a6bc7bb9242f5073ab51a0c6dda480d586cbce2fc6d8506c2.wasm", + "tx_init_validator.wasm": "tx_init_validator.6a476319971808794557e5ea111f1f86a91ee09bd83582056ac743f285d42eb0.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.7cdda2f5a2b951fd4d3b35a8ed6d252f54b0508839b0ffb2d82766faa09c5710.wasm", + "tx_transfer.wasm": "tx_transfer.cff70d53fc7a8b54f9b41ae518498119345e985d1f4cca2757760560d0a73d69.wasm", + "tx_unbond.wasm": "tx_unbond.50a1fdc2a18faf9873a391162e11454afebeffc8cdc946f0459ff53f55e09a90.wasm", + "tx_update_vp.wasm": "tx_update_vp.b0f682a2d5e621a3c5f76e4c2bf272d54e612fe63847e2d746a6d452cefc7823.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.48e6664b189ec7a2d18a4eec173911add5d9f1374ffb8904919f39660a411f96.wasm", + "tx_withdraw.wasm": "tx_withdraw.6d3e5bb0ef93e39d3781a33b6192a3804be614206127263fde048a5c85a4555c.wasm", + "vp_nft.wasm": "vp_nft.4f7f30282a66c2772a86b8a8f8d5e19944a66a0ee169db1ae662abda550a7f7e.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.279b012ef4c9a215c771141adf23126a0238da6dd033b971228640112b6bb3be.wasm", + "vp_token.wasm": "vp_token.447c5b3f55b2e7c66ee0094d8d58de8b01cda30ac177e29f14e69db44d909604.wasm", + "vp_user.wasm": "vp_user.7cfb15d4047480702f696b9576050ae22f1ca7cf1df454d457e5a8d61f766d8a.wasm" } \ No newline at end of file From 118c69933610cdf38823f85d696f3e32fec4063a Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 20 Oct 2022 11:23:05 +0200 Subject: [PATCH 19/28] [chore]: Handling code review comments --- .../ledger/eth_bridge/storage/bridge_pool.rs | 41 +++++++++---------- shared/src/ledger/storage/traits.rs | 6 +-- shared/src/types/storage.rs | 14 +++---- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index f1dfc181c9..29d307a71b 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -66,7 +66,7 @@ pub fn is_protected_storage(key: &Key) -> bool { pub struct BridgePoolTree { /// Root of the tree root: KeccakHash, - /// The underlying storage + /// The underlying storage, containing hashes of [`PendingTransfer`]s. store: BTreeSet, } @@ -88,7 +88,7 @@ impl BridgePoolTree { /// /// Returns the new root if successful. Will /// return an error if the key is malformed. - pub fn update_key(&mut self, key: &Key) -> Result { + pub fn insert_key(&mut self, key: &Key) -> Result { let hash = Self::parse_key(key)?; _ = self.store.insert(hash); self.root = self.compute_root(); @@ -104,7 +104,7 @@ impl BridgePoolTree { } /// Compute the root of the merkle tree - pub fn compute_root(&self) -> KeccakHash { + fn compute_root(&self) -> KeccakHash { let mut hashes: Vec = self.store.iter().cloned().collect(); while hashes.len() > 1 { let mut next_hashes = vec![]; @@ -242,14 +242,11 @@ impl BridgePoolTree { eyre!("Could not parse key segment as a hash").into() }) } - _ => Err(eyre!( - "Bridge pool keys should be strings, not addresses" - ) - .into()), + _ => Err(eyre!("Bridge pool keys should be strings.").into()), } } else { Err(eyre!( - "Key for the bridge pool should not have more than one segment" + "Key for the bridge pool should have exactly one segment." ) .into()) } @@ -390,7 +387,7 @@ mod test_bridge_pool_tree { }; let key = Key::from(&transfer); let root = - KeccakHash::from(tree.update_key(&key).expect("Test failed")); + KeccakHash::from(tree.insert_key(&key).expect("Test failed")); assert_eq!(root, transfer.keccak256()); } @@ -413,7 +410,7 @@ mod test_bridge_pool_tree { }; let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } let expected: Hash = hash_pair(transfers[0].keccak256(), transfers[1].keccak256()) @@ -441,7 +438,7 @@ mod test_bridge_pool_tree { }; let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); let hashes: BTreeSet = @@ -475,7 +472,7 @@ mod test_bridge_pool_tree { }; let key = Key::from(&transfer); let root = - KeccakHash::from(tree.update_key(&key).expect("Test failed")); + KeccakHash::from(tree.insert_key(&key).expect("Test failed")); assert_eq!(root, transfer.keccak256()); tree.delete_key(&key).expect("Test failed"); assert_eq!(tree.root().0, [0; 32]); @@ -502,7 +499,7 @@ mod test_bridge_pool_tree { let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); tree.delete_key(&Key::from(&transfers[1])) @@ -587,7 +584,7 @@ mod test_bridge_pool_tree { payer: bertha_address(), }, }; - tree.update_key(&Key::from(&transfer)).expect("Test failed"); + tree.insert_key(&Key::from(&transfer)).expect("Test failed"); assert!( tree.contains_key(&Key::from(&transfer)) .expect("Test failed") @@ -640,7 +637,7 @@ mod test_bridge_pool_tree { }; let mut tree = BridgePoolTree::default(); let key = Key::from(&transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); let proof = tree .get_membership_proof(array::from_ref(&key), vec![transfer]) .expect("Test failed"); @@ -669,7 +666,7 @@ mod test_bridge_pool_tree { let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } let key = Key::from(&transfers[0]); let proof = tree @@ -702,7 +699,7 @@ mod test_bridge_pool_tree { let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); let keys = vec![Key::from(&transfers[0]), Key::from(&transfers[1])]; @@ -733,7 +730,7 @@ mod test_bridge_pool_tree { }; let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } let keys = vec![]; let values = vec![]; @@ -763,7 +760,7 @@ mod test_bridge_pool_tree { }; let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); let keys: Vec<_> = transfers.iter().map(Key::from).collect(); @@ -793,7 +790,7 @@ mod test_bridge_pool_tree { }; let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); let keys: Vec<_> = transfers.iter().map(Key::from).collect(); @@ -823,7 +820,7 @@ mod test_bridge_pool_tree { }; let key = Key::from(&transfer); transfers.push(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); let keys: Vec<_> = transfers.iter().step_by(2).map(Key::from).collect(); @@ -887,7 +884,7 @@ mod test_bridge_pool_tree { let mut tree = BridgePoolTree::default(); for transfer in &transfers { let key = Key::from(transfer); - let _ = tree.update_key(&key).expect("Test failed"); + let _ = tree.insert_key(&key).expect("Test failed"); } to_prove.sort_by_key(|t| t.keccak256()); diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs index 5491b78685..67d77ac991 100644 --- a/shared/src/ledger/storage/traits.rs +++ b/shared/src/ledger/storage/traits.rs @@ -179,7 +179,7 @@ impl<'a> SubTreeRead for &'a BridgePoolTree { let values = values .into_iter() .filter_map(|val| match val { - MerkleValue::Transfer(transfer) => Some(transfer), + MerkleValue::BridgePoolTransfer(transfer) => Some(transfer), _ => None, }) .collect(); @@ -195,8 +195,8 @@ impl<'a> SubTreeWrite for &'a mut BridgePoolTree { key: &Key, value: MerkleValue, ) -> Result { - if let MerkleValue::Transfer(_) = value { - self.update_key(key) + if let MerkleValue::BridgePoolTransfer(_) = value { + self.insert_key(key) .map_err(|err| Error::MerkleTree(err.to_string())) } else { Err(Error::InvalidValue) diff --git a/shared/src/types/storage.rs b/shared/src/types/storage.rs index db7cada8ec..be15012cfa 100644 --- a/shared/src/types/storage.rs +++ b/shared/src/types/storage.rs @@ -33,8 +33,8 @@ pub enum Error { ParseAddressFromKey, #[error("Reserved prefix or string is specified: {0}")] InvalidKeySeg(String), - #[error("Could not parse string: '{0}' into requested type: {1}")] - ParseError(String, String), + #[error("Could not parse string into a key segment: {0}")] + ParseError(String), } /// Result for functions that may fail @@ -248,7 +248,7 @@ pub enum MerkleValue { /// raw bytes Bytes(Vec), /// A transfer to be put in the Ethereum bridge pool. - Transfer(PendingTransfer), + BridgePoolTransfer(PendingTransfer), } impl From for MerkleValue @@ -262,7 +262,7 @@ where impl From for MerkleValue { fn from(transfer: PendingTransfer) -> Self { - Self::Transfer(transfer) + Self::BridgePoolTransfer(transfer) } } @@ -626,9 +626,9 @@ impl KeySeg for Address { impl KeySeg for Hash { fn parse(seg: String) -> Result { - seg.clone() - .try_into() - .map_err(|_| Error::ParseError(seg, "Hash".into())) + seg.try_into().map_err(|e: crate::types::hash::Error| { + Error::ParseError(e.to_string()) + }) } fn raw(&self) -> String { From 0f595ccd17fdfb8835b92ffaea0d08959ecbeb96 Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 20 Oct 2022 11:42:22 +0200 Subject: [PATCH 20/28] [fix]: Added asset type to Pending Transfer serialization --- shared/src/types/eth_bridge_pool.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shared/src/types/eth_bridge_pool.rs b/shared/src/types/eth_bridge_pool.rs index 36a378b8db..904c2c7eec 100644 --- a/shared/src/types/eth_bridge_pool.rs +++ b/shared/src/types/eth_bridge_pool.rs @@ -5,7 +5,6 @@ use ethabi::token::Token; use crate::types::address::Address; use crate::types::ethereum_events::{EthAddress, Uint}; -use crate::types::keccak; use crate::types::keccak::encode::Encode; use crate::types::storage::{DbKeySeg, Key}; use crate::types::token::Amount; @@ -55,14 +54,15 @@ pub struct PendingTransfer { pub gas_fee: GasFee, } -impl keccak::encode::Encode for PendingTransfer { +impl Encode for PendingTransfer { fn tokenize(&self) -> Vec { - let from = Token::String(self.gas_fee.payer.to_string()); + let from = Token::Address(self.transfer.asset.0.into()); let fee = Token::Uint(u64::from(self.gas_fee.amount).into()); let to = Token::Address(self.transfer.recipient.0.into()); let amount = Token::Uint(u64::from(self.transfer.amount).into()); + let fee_from = Token::String(self.gas_fee.payer.to_string()); let nonce = Token::Uint(self.transfer.nonce.clone().into()); - vec![from, fee, to, amount, nonce] + vec![from, fee, to, amount, fee_from, nonce] } } From 645bfc2145e4c02069d27cd59671a48085b4fd1e Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 20 Oct 2022 14:31:28 +0200 Subject: [PATCH 21/28] [fix]: More code review fixes --- .../src/ledger/eth_bridge/bridge_pool_vp.rs | 1 + .../ledger/eth_bridge/storage/bridge_pool.rs | 21 +++++++------------ 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs index b7b8cf1cf2..3eada7068f 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs @@ -177,6 +177,7 @@ where tracing::debug!("The bridge pools escrow was not credited."); return Ok(false); } + tracing::info!("The Ethereum bridge pool VP accepted the transfer {:?}.", transfer); Ok(true) } diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index 29d307a71b..0a3afe7eda 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -108,14 +108,10 @@ impl BridgePoolTree { let mut hashes: Vec = self.store.iter().cloned().collect(); while hashes.len() > 1 { let mut next_hashes = vec![]; - let left_leaves = hashes.iter().step_by(2); - let mut right_leaves = hashes.iter(); - _ = right_leaves.next(); - let mut right_leaves = right_leaves.step_by(2); - - for left in left_leaves { - let right = right_leaves.next().cloned().unwrap_or_default(); - next_hashes.push(hash_pair(left.clone(), right)); + for pair in hashes.chunks(2) { + let left = pair[0].clone(); + let right = pair.get(1).cloned().unwrap_or_default(); + next_hashes.push(hash_pair(left, right)); } hashes = next_hashes; } @@ -182,13 +178,10 @@ impl BridgePoolTree { while hashes.len() > 1 { let mut next_hashes = vec![]; - let left_leaves = hashes.iter().step_by(2); - let mut right_leaves = hashes.iter(); - _ = right_leaves.next(); - let mut right_leaves = right_leaves.step_by(2); - for left in left_leaves { - let right = right_leaves.next().cloned().unwrap_or_default(); + for pair in hashes.chunks(2) { + let left = pair[0].clone(); + let right = pair.get(1).cloned().unwrap_or_default(); match (left, right) { (Node::OnPath(left), Node::OnPath(right)) => { flags.push(true); From 49e08d0f948dddc4012e36b0d31129a3818b821a Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 20 Oct 2022 14:45:22 +0200 Subject: [PATCH 22/28] [fix]: Fixed an import --- shared/src/ledger/storage/merkle_tree.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared/src/ledger/storage/merkle_tree.rs b/shared/src/ledger/storage/merkle_tree.rs index 1d175e83d2..3add9dd7f0 100644 --- a/shared/src/ledger/storage/merkle_tree.rs +++ b/shared/src/ledger/storage/merkle_tree.rs @@ -11,7 +11,6 @@ use borsh::{BorshDeserialize, BorshSerialize}; use ics23::commitment_proof::Proof as Ics23Proof; use ics23::{CommitmentProof, ExistenceProof, NonExistenceProof}; use prost::Message; -use tendermint::merkle::proof::{Proof, ProofOp}; use thiserror::Error; use super::traits::{StorageHasher, SubTreeRead, SubTreeWrite}; @@ -22,6 +21,7 @@ use crate::ledger::eth_bridge::storage::bridge_pool::{ }; use crate::ledger::storage::ics23_specs::ibc_leaf_spec; use crate::ledger::storage::{ics23_specs, types}; +use crate::tendermint::merkle::proof::{Proof, ProofOp}; use crate::types::address::{Address, InternalAddress}; use crate::types::hash::Hash; use crate::types::keccak::KeccakHash; From 09677d531fa4ebd3466079684bb7cf9b6a015c04 Mon Sep 17 00:00:00 2001 From: satan Date: Thu, 20 Oct 2022 14:46:17 +0200 Subject: [PATCH 23/28] [fix]: Formatting --- shared/src/ledger/eth_bridge/bridge_pool_vp.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs index 3eada7068f..0624a83ae1 100644 --- a/shared/src/ledger/eth_bridge/bridge_pool_vp.rs +++ b/shared/src/ledger/eth_bridge/bridge_pool_vp.rs @@ -177,7 +177,10 @@ where tracing::debug!("The bridge pools escrow was not credited."); return Ok(false); } - tracing::info!("The Ethereum bridge pool VP accepted the transfer {:?}.", transfer); + tracing::info!( + "The Ethereum bridge pool VP accepted the transfer {:?}.", + transfer + ); Ok(true) } From 1d15e12d450212c93d1784cc82489337e6a0f0a5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 20 Oct 2022 13:33:49 +0000 Subject: [PATCH 24/28] [ci] wasm checksums update --- wasm/checksums.json | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/wasm/checksums.json b/wasm/checksums.json index d61712a5fd..f555b3064e 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,20 +1,20 @@ { - "tx_bond.wasm": "tx_bond.bb67d406e6c31218d32667ef8debed9be77dbadb33ee52a30d9fc377e3f6876c.wasm", + "tx_bond.wasm": "tx_bond.d0ce8b21186695f0b14c6f8f1649b73e61e91dd3c357207088f23992127ce031.wasm", "tx_bridge_pool.wasm": "tx_bridge_pool.e21563260c03cfdab1f195878f49bf93722027ad26fcd097cfebbc5c4d279082.wasm", - "tx_from_intent.wasm": "tx_from_intent.9915822bea588b0a18b4ec51bc249e88fdc3041bc3eddaaa2cc880dcd23c5eb0.wasm", - "tx_ibc.wasm": "tx_ibc.913192b268db668ebba6b415eea106c19e742b9b6be6ebb795a661dca82482af.wasm", - "tx_init_account.wasm": "tx_init_account.bd544ce16dae46177f9d9bd5281a53b4f4fe741833013a1f412b1f104c4bf6a6.wasm", - "tx_init_nft.wasm": "tx_init_nft.1f1b18628e97758d837d0f25c313979cc529abc56797be240ce4c74032d603c5.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.ad5ba0ef45cef6b59dab228dfaeb0dc643235639851c1adcff5d52152d2c01f5.wasm", - "tx_init_validator.wasm": "tx_init_validator.9b1ddb7e6dca6beadbf42c4da91771c92228562f4239494e4e56d57fd3c3b538.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.bd061f19c4d2e5801f671adb60e7e4d787a6f493a28c29f20a57e4a256a8dcbc.wasm", - "tx_transfer.wasm": "tx_transfer.1a8d43355f663c040a29d6e10e6cdfe6c73634aa5cd6863e1f3f5d58fe9ec560.wasm", - "tx_unbond.wasm": "tx_unbond.84a2a809d5b617740b991ddc5b88ad213ffa17aa178afe1f657b90cecebbaa7a.wasm", - "tx_update_vp.wasm": "tx_update_vp.84b896bce441e449cdbfa2401f2da8ea6f0c10725c1a8d9e1a03763b49056817.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.8b171e9bdc02f6321f0b7ae6a881d00d26d7c5ecb00bb7aa0d77e411767517c9.wasm", - "tx_withdraw.wasm": "tx_withdraw.aede879ea5c81b4e479d89b2e9c5d9e5d80bf7e0a9e8a0a8c7bf7f2bb2b049f5.wasm", - "vp_nft.wasm": "vp_nft.87b7fc9e596891dd676294e18a467fd8ef16c372a3e22f7876b125fb9c31d606.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.3ed495ea630de4a8d5459e09882c1862e768b826654aa1b700ed13e1e5cf8827.wasm", - "vp_token.wasm": "vp_token.b95cfb6bff76ffec7034f29453482937297cf713fd7cfd3f4f7045a2cb044bca.wasm", - "vp_user.wasm": "vp_user.fac7690818a1bc043cdb13d65b7f9d687343845c2e31e3eed841dc074803bff9.wasm" + "tx_from_intent.wasm": "tx_from_intent.202f60934158067bec29454b4dd899ea902158e8321e51b6a479d94d8d1677c1.wasm", + "tx_ibc.wasm": "tx_ibc.a5a14d5c6061cbcfad16242ef71d9a949527c3f47453491cbe216d4da3c3bf52.wasm", + "tx_init_account.wasm": "tx_init_account.b2a97bd164b7c4804c2ab08a478bdb8235386be0d07d05f66ff3663868dc1dfc.wasm", + "tx_init_nft.wasm": "tx_init_nft.ba4c2519c1de43c1c638cfbcdbb734e7f1b6fbc3e960fd21f305dd8a1e6ac1f5.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.a2a3a6bf3972001aae12fb423fdc97eda6d4b017d8409d5f4b721b4eb03e0d37.wasm", + "tx_init_validator.wasm": "tx_init_validator.012e64f8736402e9e9fefb667ea684bb9db15f1bb25d9d175b4ba193d724e583.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.b0715685db7b04cf7d9b8ec5ec57c63927e9133edfb9e68055c618c5d879ace7.wasm", + "tx_transfer.wasm": "tx_transfer.5692122746b321e787e1965d1f67f9f450ff8b33f1f1d24f2a3260034072c16b.wasm", + "tx_unbond.wasm": "tx_unbond.b167452a7e135d0c942d7c6fc9a03f37ef4255844c02e00158b91d59fed86939.wasm", + "tx_update_vp.wasm": "tx_update_vp.b0f682a2d5e621a3c5f76e4c2bf272d54e612fe63847e2d746a6d452cefc7823.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.9444e00877c7c5b9d0da568dbfb7e9082ad4508e331e63f398c7fe75c3041e29.wasm", + "tx_withdraw.wasm": "tx_withdraw.4d49f78c85574c176c65d0aa3ab1002540ca5c660768f2833047e5bc380c52f7.wasm", + "vp_nft.wasm": "vp_nft.916a59e2abdac12f165ec07c783edb11642e03b911c41bc5a39d3c622b05ccdd.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.72bea74cb811103c258477bc155dc67c06ee6c14c105b8a5598b79519949b0b6.wasm", + "vp_token.wasm": "vp_token.886885caefe8e264644126bdb329d3e564e7ea9015df3093001c1a297dc35709.wasm", + "vp_user.wasm": "vp_user.bc69d9c0eb26a25f55ace17319f3e77ea8bda00c53c3222949f2b22d8e62cae6.wasm" } \ No newline at end of file From dc283a667884952b538a5ce4ef6e1c868670710d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 21 Oct 2022 09:07:03 +0000 Subject: [PATCH 25/28] [ci] wasm checksums update --- wasm/checksums.json | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/wasm/checksums.json b/wasm/checksums.json index f555b3064e..7a6840ef5f 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,20 +1,20 @@ { - "tx_bond.wasm": "tx_bond.d0ce8b21186695f0b14c6f8f1649b73e61e91dd3c357207088f23992127ce031.wasm", + "tx_bond.wasm": "tx_bond.870a6cd86c7725df65306a4ef49ae05f39ac5d2f7c39bf12c901def38587c016.wasm", "tx_bridge_pool.wasm": "tx_bridge_pool.e21563260c03cfdab1f195878f49bf93722027ad26fcd097cfebbc5c4d279082.wasm", - "tx_from_intent.wasm": "tx_from_intent.202f60934158067bec29454b4dd899ea902158e8321e51b6a479d94d8d1677c1.wasm", - "tx_ibc.wasm": "tx_ibc.a5a14d5c6061cbcfad16242ef71d9a949527c3f47453491cbe216d4da3c3bf52.wasm", - "tx_init_account.wasm": "tx_init_account.b2a97bd164b7c4804c2ab08a478bdb8235386be0d07d05f66ff3663868dc1dfc.wasm", - "tx_init_nft.wasm": "tx_init_nft.ba4c2519c1de43c1c638cfbcdbb734e7f1b6fbc3e960fd21f305dd8a1e6ac1f5.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.a2a3a6bf3972001aae12fb423fdc97eda6d4b017d8409d5f4b721b4eb03e0d37.wasm", - "tx_init_validator.wasm": "tx_init_validator.012e64f8736402e9e9fefb667ea684bb9db15f1bb25d9d175b4ba193d724e583.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.b0715685db7b04cf7d9b8ec5ec57c63927e9133edfb9e68055c618c5d879ace7.wasm", - "tx_transfer.wasm": "tx_transfer.5692122746b321e787e1965d1f67f9f450ff8b33f1f1d24f2a3260034072c16b.wasm", - "tx_unbond.wasm": "tx_unbond.b167452a7e135d0c942d7c6fc9a03f37ef4255844c02e00158b91d59fed86939.wasm", - "tx_update_vp.wasm": "tx_update_vp.b0f682a2d5e621a3c5f76e4c2bf272d54e612fe63847e2d746a6d452cefc7823.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.9444e00877c7c5b9d0da568dbfb7e9082ad4508e331e63f398c7fe75c3041e29.wasm", - "tx_withdraw.wasm": "tx_withdraw.4d49f78c85574c176c65d0aa3ab1002540ca5c660768f2833047e5bc380c52f7.wasm", - "vp_nft.wasm": "vp_nft.916a59e2abdac12f165ec07c783edb11642e03b911c41bc5a39d3c622b05ccdd.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.72bea74cb811103c258477bc155dc67c06ee6c14c105b8a5598b79519949b0b6.wasm", - "vp_token.wasm": "vp_token.886885caefe8e264644126bdb329d3e564e7ea9015df3093001c1a297dc35709.wasm", - "vp_user.wasm": "vp_user.bc69d9c0eb26a25f55ace17319f3e77ea8bda00c53c3222949f2b22d8e62cae6.wasm" + "tx_from_intent.wasm": "tx_from_intent.f14bd1cf1bc9adce29ff5161d36cade38f75db58daaab0ac4446aeb3752ca491.wasm", + "tx_ibc.wasm": "tx_ibc.d88b6ea37611c9e82d012b468475a2dfe125d5f0ecf8162ee361a2e07ac48a7c.wasm", + "tx_init_account.wasm": "tx_init_account.1424aad69e094e6ddbbcc41c28484675d2ce181699d5820b365cade406a33e3a.wasm", + "tx_init_nft.wasm": "tx_init_nft.b6d193bf41c5b105de075ed832ed9ac5bb0ee03943c0f70ace1888474f50ece7.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.951e3667382e0d81de17ebda9248046a8f1cc2d7e714b0cfa7ae58920c0d02d6.wasm", + "tx_init_validator.wasm": "tx_init_validator.d9ec814be773d6bfd6c36ddb37ace2463effef02d7e089495c3f74de43de556f.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.90b8cf9d1f52b758ae419cefaaa51b270d7492877348ea02357d589f83695099.wasm", + "tx_transfer.wasm": "tx_transfer.ad9707d3e02d01b261675fdb09eab6aedeebea0b8035726df76f68c7279b864b.wasm", + "tx_unbond.wasm": "tx_unbond.f73b997890f6ad61289fdfa01770940bc26e28bf06a8a2e856d2615acdcbe6ae.wasm", + "tx_update_vp.wasm": "tx_update_vp.4e5d802da0ef98daa6c904522c6fd4964020cc9ce948f16579a6cec1793337b8.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.25bb52d647106263537467e229ddbc1ef57970c222d49830d1bc182727afe4f4.wasm", + "tx_withdraw.wasm": "tx_withdraw.ebe91941b7f8559e651ceeba786d5cf08fba7ee17d2991ef460cbf65e6501664.wasm", + "vp_nft.wasm": "vp_nft.e8bcdf806148418e765aad6fa509993c490a7c2fb7cbc9abe8e469babd371e05.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.d210846a57a8290b726689c50d8002ce374e54c5af08ca7b4edc852832cd42d8.wasm", + "vp_token.wasm": "vp_token.e2d4cebc4c592ec68a452e1ef55a6bb6b16bd0cf7d77ec3527b4cde82d243251.wasm", + "vp_user.wasm": "vp_user.856857cea31ce03e076dcb1a9e5d2a9cf30d3c883365e7230f0c8fa1d4c1dc8a.wasm" } \ No newline at end of file From 4e208f968eb58b2ab56d9dbf05dae90f0a7b99dd Mon Sep 17 00:00:00 2001 From: satan Date: Mon, 24 Oct 2022 16:46:22 +0200 Subject: [PATCH 26/28] [fix]: Some code review changes --- .../ledger/eth_bridge/storage/bridge_pool.rs | 108 ++++++------------ shared/src/ledger/storage/traits.rs | 4 +- 2 files changed, 37 insertions(+), 75 deletions(-) diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index 0a3afe7eda..e03d499af3 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -60,6 +60,8 @@ pub fn is_protected_storage(key: &Key) -> bool { } /// A simple Merkle tree for the Ethereum bridge pool +/// +/// Note that an empty tree has root [0u8; 20] by definition. #[derive( Debug, Default, Clone, BorshSerialize, BorshDeserialize, BorshSchema, )] @@ -67,13 +69,16 @@ pub struct BridgePoolTree { /// Root of the tree root: KeccakHash, /// The underlying storage, containing hashes of [`PendingTransfer`]s. - store: BTreeSet, + leaves: BTreeSet, } impl BridgePoolTree { /// Create a new merkle tree for the Ethereum bridge pool pub fn new(root: KeccakHash, store: BTreeSet) -> Self { - Self { root, store } + Self { + root, + leaves: store, + } } /// Parse the key to ensure it is of the correct type. @@ -81,7 +86,7 @@ impl BridgePoolTree { /// If it is, it can be converted to a hash. /// Checks if the hash is in the tree. pub fn contains_key(&self, key: &Key) -> Result { - Ok(self.store.contains(&Self::parse_key(key)?)) + Ok(self.leaves.contains(&Self::parse_key(key)?)) } /// Update the tree with a new value. @@ -90,7 +95,7 @@ impl BridgePoolTree { /// return an error if the key is malformed. pub fn insert_key(&mut self, key: &Key) -> Result { let hash = Self::parse_key(key)?; - _ = self.store.insert(hash); + _ = self.leaves.insert(hash); self.root = self.compute_root(); Ok(self.root()) } @@ -98,14 +103,14 @@ impl BridgePoolTree { /// Delete a key from storage and update the root pub fn delete_key(&mut self, key: &Key) -> Result<(), Error> { let hash = Self::parse_key(key)?; - _ = self.store.remove(&hash); + _ = self.leaves.remove(&hash); self.root = self.compute_root(); Ok(()) } /// Compute the root of the merkle tree fn compute_root(&self) -> KeccakHash { - let mut hashes: Vec = self.store.iter().cloned().collect(); + let mut hashes: Vec = self.leaves.iter().cloned().collect(); while hashes.len() > 1 { let mut next_hashes = vec![]; for pair in hashes.chunks(2) { @@ -130,48 +135,32 @@ impl BridgePoolTree { /// Get a reference to the backing store pub fn store(&self) -> &BTreeSet { - &self.store + &self.leaves } /// Create a batched membership proof for the provided keys pub fn get_membership_proof( &self, - keys: &[Key], mut values: Vec, ) -> Result { - if values.len() != keys.len() { - return Err(eyre!( - "The number of leaves and leaf hashes must be equal." - ) - .into()); - } // sort the values according to their hash values values.sort_by_key(|transfer| transfer.keccak256()); // get the leaf hashes - let mut leaves: BTreeSet = Default::default(); - for (key, value) in keys.iter().zip(values.iter()) { - let hash = Self::parse_key(key)?; - if hash != value.keccak256() { - return Err(eyre!( - "Hashes of keys did not match hashes of values." - ) - .into()); - } - leaves.insert(hash); - } + let leaves: BTreeSet = + values.iter().map(|v| v.keccak256()).collect(); let mut proof_hashes = vec![]; let mut flags = vec![]; let mut hashes: Vec<_> = self - .store + .leaves .iter() .cloned() .map(|hash| { if leaves.contains(&hash) { Node::OnPath(hash) } else { - Node::Sibling(hash) + Node::OffPath(hash) } }) .collect(); @@ -188,20 +177,20 @@ impl BridgePoolTree { next_hashes .push(Node::OnPath(hash_pair(left.clone(), right))); } - (Node::OnPath(hash), Node::Sibling(sib)) => { + (Node::OnPath(hash), Node::OffPath(sib)) => { flags.push(false); proof_hashes.push(sib.clone()); next_hashes .push(Node::OnPath(hash_pair(hash.clone(), sib))); } - (Node::Sibling(sib), Node::OnPath(hash)) => { + (Node::OffPath(sib), Node::OnPath(hash)) => { flags.push(false); proof_hashes.push(sib.clone()); next_hashes .push(Node::OnPath(hash_pair(hash, sib.clone()))); } - (Node::Sibling(left), Node::Sibling(right)) => { - next_hashes.push(Node::Sibling(hash_pair( + (Node::OffPath(left), Node::OffPath(right)) => { + next_hashes.push(Node::OffPath(hash_pair( left.clone(), right, ))); @@ -264,12 +253,12 @@ enum Node { /// Node is on a path from root to leaf in proof OnPath(KeccakHash), /// Node is not on a path from root to leaf in proof - Sibling(KeccakHash), + OffPath(KeccakHash), } impl Default for Node { fn default() -> Self { - Self::Sibling(Default::default()) + Self::OffPath(Default::default()) } } @@ -279,7 +268,9 @@ pub struct BridgePoolProof { pub proof: Vec, /// The leaves; must be sorted pub leaves: Vec, - /// flags to indicate how to combine hashes + /// Flags to indicate how to combine hashes. + /// Flags are used to indicate which consecutive + /// pairs of leaves in `leaves` are siblings. pub flags: Vec, } @@ -345,7 +336,6 @@ impl BridgePoolProof { #[cfg(test)] mod test_bridge_pool_tree { - use std::array; use itertools::Itertools; use proptest::prelude::*; @@ -436,7 +426,7 @@ mod test_bridge_pool_tree { transfers.sort_by_key(|t| t.keccak256()); let hashes: BTreeSet = transfers.iter().map(|t| t.keccak256()).collect(); - assert_eq!(hashes, tree.store); + assert_eq!(hashes, tree.leaves); let left_hash = hash_pair(transfers[0].keccak256(), transfers[1].keccak256()); @@ -605,11 +595,8 @@ mod test_bridge_pool_tree { #[test] fn test_empty_proof() { let tree = BridgePoolTree::default(); - let keys = vec![]; let values = vec![]; - let proof = tree - .get_membership_proof(&keys, values) - .expect("Test failed"); + let proof = tree.get_membership_proof(values).expect("Test failed"); assert!(proof.verify(Default::default())); } @@ -632,7 +619,7 @@ mod test_bridge_pool_tree { let key = Key::from(&transfer); let _ = tree.insert_key(&key).expect("Test failed"); let proof = tree - .get_membership_proof(array::from_ref(&key), vec![transfer]) + .get_membership_proof(vec![transfer]) .expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -661,12 +648,8 @@ mod test_bridge_pool_tree { transfers.push(transfer); let _ = tree.insert_key(&key).expect("Test failed"); } - let key = Key::from(&transfers[0]); let proof = tree - .get_membership_proof( - array::from_ref(&key), - vec![transfers.remove(0)], - ) + .get_membership_proof(vec![transfers.remove(0)]) .expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -695,11 +678,8 @@ mod test_bridge_pool_tree { let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); - let keys = vec![Key::from(&transfers[0]), Key::from(&transfers[1])]; let values = vec![transfers[0].clone(), transfers[1].clone()]; - let proof = tree - .get_membership_proof(&keys, values) - .expect("Test failed"); + let proof = tree.get_membership_proof(values).expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -725,11 +705,8 @@ mod test_bridge_pool_tree { transfers.push(transfer); let _ = tree.insert_key(&key).expect("Test failed"); } - let keys = vec![]; let values = vec![]; - let proof = tree - .get_membership_proof(&keys, values) - .expect("Test failed"); + let proof = tree.get_membership_proof(values).expect("Test failed"); assert!(proof.verify(tree.root().into())) } @@ -756,10 +733,7 @@ mod test_bridge_pool_tree { let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); - let keys: Vec<_> = transfers.iter().map(Key::from).collect(); - let proof = tree - .get_membership_proof(&keys, transfers) - .expect("Test failed"); + let proof = tree.get_membership_proof(transfers).expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -786,10 +760,7 @@ mod test_bridge_pool_tree { let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); - let keys: Vec<_> = transfers.iter().map(Key::from).collect(); - let proof = tree - .get_membership_proof(&keys, transfers) - .expect("Test failed"); + let proof = tree.get_membership_proof(transfers).expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -816,11 +787,8 @@ mod test_bridge_pool_tree { let _ = tree.insert_key(&key).expect("Test failed"); } transfers.sort_by_key(|t| t.keccak256()); - let keys: Vec<_> = transfers.iter().step_by(2).map(Key::from).collect(); let values: Vec<_> = transfers.iter().step_by(2).cloned().collect(); - let proof = tree - .get_membership_proof(&keys, values) - .expect("Test failed"); + let proof = tree.get_membership_proof(values).expect("Test failed"); assert!(proof.verify(tree.root().into())); } @@ -881,13 +849,7 @@ mod test_bridge_pool_tree { } to_prove.sort_by_key(|t| t.keccak256()); - let mut keys = vec![]; - let mut values = vec![]; - for transfer in to_prove.into_iter() { - keys.push(Key::from(&transfer)); - values.push(transfer); - } - let proof = tree.get_membership_proof(&keys, values).expect("Test failed"); + let proof = tree.get_membership_proof(to_prove).expect("Test failed"); assert!(proof.verify(tree.root().into())); } } diff --git a/shared/src/ledger/storage/traits.rs b/shared/src/ledger/storage/traits.rs index 67d77ac991..ee9805a8ee 100644 --- a/shared/src/ledger/storage/traits.rs +++ b/shared/src/ledger/storage/traits.rs @@ -173,7 +173,7 @@ impl<'a> SubTreeRead for &'a BridgePoolTree { fn subtree_membership_proof( &self, - keys: &[Key], + _: &[Key], values: Vec, ) -> Result { let values = values @@ -183,7 +183,7 @@ impl<'a> SubTreeRead for &'a BridgePoolTree { _ => None, }) .collect(); - self.get_membership_proof(keys, values) + self.get_membership_proof(values) .map(Into::into) .map_err(|err| Error::MerkleTree(err.to_string())) } From 3c0be07ba1fc5a18f00792691cb7c08a900c365d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 24 Oct 2022 15:17:09 +0000 Subject: [PATCH 27/28] [ci] wasm checksums update --- wasm/checksums.json | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/wasm/checksums.json b/wasm/checksums.json index 7a6840ef5f..a320c8c877 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -1,20 +1,20 @@ { - "tx_bond.wasm": "tx_bond.870a6cd86c7725df65306a4ef49ae05f39ac5d2f7c39bf12c901def38587c016.wasm", + "tx_bond.wasm": "tx_bond.921a2553de5b15305df8708f7bfba49d8174d0a1ff5eaded66fc9e47da8e16ea.wasm", "tx_bridge_pool.wasm": "tx_bridge_pool.e21563260c03cfdab1f195878f49bf93722027ad26fcd097cfebbc5c4d279082.wasm", - "tx_from_intent.wasm": "tx_from_intent.f14bd1cf1bc9adce29ff5161d36cade38f75db58daaab0ac4446aeb3752ca491.wasm", - "tx_ibc.wasm": "tx_ibc.d88b6ea37611c9e82d012b468475a2dfe125d5f0ecf8162ee361a2e07ac48a7c.wasm", - "tx_init_account.wasm": "tx_init_account.1424aad69e094e6ddbbcc41c28484675d2ce181699d5820b365cade406a33e3a.wasm", - "tx_init_nft.wasm": "tx_init_nft.b6d193bf41c5b105de075ed832ed9ac5bb0ee03943c0f70ace1888474f50ece7.wasm", - "tx_init_proposal.wasm": "tx_init_proposal.951e3667382e0d81de17ebda9248046a8f1cc2d7e714b0cfa7ae58920c0d02d6.wasm", - "tx_init_validator.wasm": "tx_init_validator.d9ec814be773d6bfd6c36ddb37ace2463effef02d7e089495c3f74de43de556f.wasm", - "tx_mint_nft.wasm": "tx_mint_nft.90b8cf9d1f52b758ae419cefaaa51b270d7492877348ea02357d589f83695099.wasm", - "tx_transfer.wasm": "tx_transfer.ad9707d3e02d01b261675fdb09eab6aedeebea0b8035726df76f68c7279b864b.wasm", - "tx_unbond.wasm": "tx_unbond.f73b997890f6ad61289fdfa01770940bc26e28bf06a8a2e856d2615acdcbe6ae.wasm", - "tx_update_vp.wasm": "tx_update_vp.4e5d802da0ef98daa6c904522c6fd4964020cc9ce948f16579a6cec1793337b8.wasm", - "tx_vote_proposal.wasm": "tx_vote_proposal.25bb52d647106263537467e229ddbc1ef57970c222d49830d1bc182727afe4f4.wasm", - "tx_withdraw.wasm": "tx_withdraw.ebe91941b7f8559e651ceeba786d5cf08fba7ee17d2991ef460cbf65e6501664.wasm", - "vp_nft.wasm": "vp_nft.e8bcdf806148418e765aad6fa509993c490a7c2fb7cbc9abe8e469babd371e05.wasm", - "vp_testnet_faucet.wasm": "vp_testnet_faucet.d210846a57a8290b726689c50d8002ce374e54c5af08ca7b4edc852832cd42d8.wasm", - "vp_token.wasm": "vp_token.e2d4cebc4c592ec68a452e1ef55a6bb6b16bd0cf7d77ec3527b4cde82d243251.wasm", - "vp_user.wasm": "vp_user.856857cea31ce03e076dcb1a9e5d2a9cf30d3c883365e7230f0c8fa1d4c1dc8a.wasm" + "tx_from_intent.wasm": "tx_from_intent.f3dc53d17cf0e698fcaab3c07039d90bf5dec9afc097ee3bc409427162ade54e.wasm", + "tx_ibc.wasm": "tx_ibc.1137cd5dfb5f7b1d2101f36d69c73f42c36d463683eb3f6db05293a78a05d31c.wasm", + "tx_init_account.wasm": "tx_init_account.184180f1b0f798b7929873165e9aaa0b9027bc122d3d7f66b8a5b9663eb886d5.wasm", + "tx_init_nft.wasm": "tx_init_nft.6fe64086099e6175df889e5c068bd5038d6f666288f6e97af0009aa11e4270b0.wasm", + "tx_init_proposal.wasm": "tx_init_proposal.48c78758fdcb20b20405be265ec0a18224b48e99ffb08651543db1f972761416.wasm", + "tx_init_validator.wasm": "tx_init_validator.610a72775cbdd0b5e34e71eca29545acf5dcf6b16ab887e778d75d8fc5ab086b.wasm", + "tx_mint_nft.wasm": "tx_mint_nft.3e67ffb6b3c974df2c74479ad49d97b6e8301ef7b369dceeb02223c771a4bf65.wasm", + "tx_transfer.wasm": "tx_transfer.c31c6f1b912a5cf161c2b2623044a27b2b6ee37ef226a0ae3c9b6ec75e95d9a9.wasm", + "tx_unbond.wasm": "tx_unbond.247505c2aee9e7fabf928f436f9220f6a09220d0276c6cdab30eae10baededbb.wasm", + "tx_update_vp.wasm": "tx_update_vp.308c3066cc935b84ddb6e884008acacedaca6cb2fd302530fde0faa712672f73.wasm", + "tx_vote_proposal.wasm": "tx_vote_proposal.8e28f8c76eaebc1302247e34bc9c7f2744495dc802934cfb309b825c8e5d31d4.wasm", + "tx_withdraw.wasm": "tx_withdraw.8ce1e6063155e2876f1c2044c9f09d643b56a55a2b9be95cf41452b4ebdfb20c.wasm", + "vp_nft.wasm": "vp_nft.957258593d899af1d6368afdefb6f158a65da28c6656a2b901c5cf97dd1f23e4.wasm", + "vp_testnet_faucet.wasm": "vp_testnet_faucet.eaad3bffc9b20a831db37d18c82930e037ea079e7152b7e683eff8b98dacd7bf.wasm", + "vp_token.wasm": "vp_token.a4cd361ad211e05c691eab70127813e348216f6a793c2566a1f5ee2f88256596.wasm", + "vp_user.wasm": "vp_user.76d5d421abf1a78c55045ba905c8330cee12cbddf03c01f41bb46b7b24bbb1a3.wasm" } \ No newline at end of file From c6452baf7757c8be5646148e1ed6d58cb4de1023 Mon Sep 17 00:00:00 2001 From: Jacob Turner Date: Tue, 25 Oct 2022 10:43:34 +0200 Subject: [PATCH 28/28] Update shared/src/ledger/eth_bridge/storage/bridge_pool.rs Co-authored-by: James --- shared/src/ledger/eth_bridge/storage/bridge_pool.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs index e03d499af3..0e7d67eae6 100644 --- a/shared/src/ledger/eth_bridge/storage/bridge_pool.rs +++ b/shared/src/ledger/eth_bridge/storage/bridge_pool.rs @@ -268,7 +268,6 @@ pub struct BridgePoolProof { pub proof: Vec, /// The leaves; must be sorted pub leaves: Vec, - /// Flags to indicate how to combine hashes. /// Flags are used to indicate which consecutive /// pairs of leaves in `leaves` are siblings. pub flags: Vec,