diff --git a/common/cf-guest/src/client.rs b/common/cf-guest/src/client.rs index 3502bc60..3d5178df 100644 --- a/common/cf-guest/src/client.rs +++ b/common/cf-guest/src/client.rs @@ -46,7 +46,7 @@ impl ClientState { is_frozen: bool, ) -> Self { let prev_epoch_commitment = - prev_epoch_commitment.unwrap_or_else(|| epoch_commitment.clone()); + prev_epoch_commitment.unwrap_or(epoch_commitment); Self { genesis_hash, latest_height, @@ -60,11 +60,11 @@ impl ClientState { #[cfg(test)] pub fn from_genesis(genesis: &guestchain::BlockHeader) -> Self { - let epoch_commitment = genesis.next_epoch_commitment.clone().unwrap(); - let prev_epoch_commitment = epoch_commitment.clone(); + let epoch_commitment = genesis.next_epoch_commitment.unwrap(); + let prev_epoch_commitment = epoch_commitment; Self { genesis_hash: genesis.calc_hash(), - latest_height: genesis.block_height.into(), + latest_height: genesis.block_height, trusting_period_ns: 24 * 3600 * 1_000_000_000, epoch_commitment, prev_epoch_commitment, @@ -89,8 +89,8 @@ impl ClientState { // accept headers from Epoch which has just ended (i.e. this header // is the last block of) and the Epoch that has just started. if let Some(ref next) = header.block_header.next_epoch_commitment { - this.prev_epoch_commitment = this.epoch_commitment.clone(); - this.epoch_commitment = next.clone(); + this.prev_epoch_commitment = this.epoch_commitment; + this.epoch_commitment = *next; } } this @@ -139,7 +139,7 @@ impl TryFrom<&proto::ClientState> for ClientState { let genesis_hash = make_hash(&msg.genesis_hash)?; let epoch_commitment = make_hash(&msg.epoch_commitment)?; let prev_epoch_commitment = if msg.prev_epoch_commitment.is_empty() { - epoch_commitment.clone() + epoch_commitment } else { make_hash(&msg.prev_epoch_commitment)? }; diff --git a/common/cf-guest/src/client/tests.rs b/common/cf-guest/src/client/tests.rs index 0ee5045b..5f285881 100644 --- a/common/cf-guest/src/client/tests.rs +++ b/common/cf-guest/src/client/tests.rs @@ -87,12 +87,7 @@ fn test_header_misbehaviour() { let (fp, mut header) = { let current = current.unwrap_or(&ctx.genesis); let host_height = u64::from(current.host_height) + 1; - ctx.generate_next( - current, - host_height.into(), - timestamp, - state_root, - ) + ctx.generate_next(current, host_height, timestamp, state_root) }; header.signatures.push((0, ctx.sign(0, &fp))); header.signatures.push((1, ctx.sign(1, &fp))); @@ -200,7 +195,7 @@ impl TestContext { let validators = epoch .validators() .iter() - .map(|validator| MockSigner(validator.pubkey.clone())) + .map(|validator| MockSigner(validator.pubkey)) .collect::>(); let genesis = guestchain::BlockHeader::generate_genesis( @@ -231,9 +226,7 @@ impl TestContext { this } - fn genesis_hash(&self) -> CryptoHash { - self.client_state.genesis_hash.clone() - } + fn genesis_hash(&self) -> CryptoHash { self.client_state.genesis_hash } fn generate_next( &self, diff --git a/common/cf-guest/src/header.rs b/common/cf-guest/src/header.rs index e7df4978..e0d62e89 100644 --- a/common/cf-guest/src/header.rs +++ b/common/cf-guest/src/header.rs @@ -125,7 +125,7 @@ impl Header { base: Option<&Self>, ) -> Result { let genesis_hash = if msg.genesis_hash.is_empty() { - base.ok_or(proto::BadMessage)?.genesis_hash.clone() + base.ok_or(proto::BadMessage)?.genesis_hash } else { lib::hash::CryptoHash::try_from(msg.genesis_hash.as_slice()) .map_err(|_| proto::BadMessage)? @@ -138,7 +138,7 @@ impl Header { let (epoch_commitment, epoch) = if msg.epoch.is_empty() { let base = base.ok_or(proto::BadMessage)?; - (base.epoch_commitment.clone(), base.epoch.clone()) + (base.epoch_commitment, base.epoch.clone()) } else { let bytes = msg.epoch.as_slice(); let epoch = borsh::BorshDeserialize::try_from_slice(bytes) diff --git a/common/cf-guest/src/proof.rs b/common/cf-guest/src/proof.rs index 9c52a5b7..0b2a0ef1 100644 --- a/common/cf-guest/src/proof.rs +++ b/common/cf-guest/src/proof.rs @@ -126,7 +126,7 @@ impl<'a> GenerateContext for &'a BlockHeader { impl GenerateContext for () { fn get_root(self, root: &CryptoHash) -> Result { - Ok(root.clone()) + Ok(*root) } fn serialise_proof( self, @@ -282,7 +282,7 @@ fn verify_impl( } else { let proof: sealable_trie::proof::Proof = borsh::BorshDeserialize::deserialize_reader(&mut proof_bytes)?; - (root.clone(), proof) + (*root, proof) }; let value = if let Some(value) = value { @@ -356,7 +356,7 @@ mod tests { impl Trie { fn set(&mut self, key: &[u8], value: CryptoHash) { self.trie.set(key, &value).unwrap(); - self.header.state_root = self.trie.hash().clone(); + self.header.state_root = *self.trie.hash(); } fn root(&self) -> &CryptoHash { self.trie.hash() } @@ -369,14 +369,10 @@ mod tests { ) -> IbcProof { let mut bytes = proof.proof.as_slice(); let mut hdr = BlockHeader::deserialize_reader(&mut bytes).unwrap(); - hdr.state_root = state_root.clone(); + hdr.state_root = *state_root; let mut buf = borsh::to_vec(&hdr).unwrap(); buf.extend_from_slice(bytes); - IbcProof { - proof: buf, - root: hdr.calc_hash(), - value: proof.value.clone(), - } + IbcProof { proof: buf, root: hdr.calc_hash(), value: proof.value } } fn generate( @@ -421,7 +417,7 @@ mod tests { guestchain::BlockHeight::from(0), guestchain::HostHeight::from(42), core::num::NonZeroU64::new(24).unwrap(), - trie.hash().clone(), + *trie.hash(), CryptoHash::test(86), ), trie, @@ -443,7 +439,7 @@ mod tests { // Verify non-membership fails if value is inserted. let key = trie_ids::PathInfo::try_from(path.clone()).unwrap().key; - trie.set(&key, stored_hash.clone()); + trie.set(&key, *stored_hash); if for_block { // Generate proof with block header with new state root, but use the @@ -576,7 +572,7 @@ mod tests { for_block, &[], &proof.proof, - &CryptoHash::test(11).as_slice(), + CryptoHash::test(11).as_slice(), path.clone(), Some(value), ) diff --git a/common/cf-solana/src/blake3.rs b/common/cf-solana/src/blake3.rs index 977ca569..3a6c6140 100644 --- a/common/cf-solana/src/blake3.rs +++ b/common/cf-solana/src/blake3.rs @@ -1,6 +1,5 @@ pub use ::blake3::Hasher; - -use crate::types::Hash; +use lib::hash::CryptoHash; const CONSIDER_SOL: bool = !cfg!(feature = "no-blake3-syscall") && cfg!(target_os = "solana-program"); @@ -13,11 +12,11 @@ const USE_SOL: bool = CONSIDER_SOL && HAS_SOL; /// When `solana-program` or `solana-program-2` feature is enabled and /// building a solana program, this is using Solana’s `sol_blake3` syscall. /// Otherwise, the calculation is done by `blake3` crate. -pub fn hash(bytes: &[u8]) -> Hash { +pub fn hash(bytes: &[u8]) -> CryptoHash { if USE_SOL { hashv(&[bytes]) } else { - Hash(::blake3::hash(bytes).into()) + CryptoHash(::blake3::hash(bytes).into()) } } @@ -27,17 +26,17 @@ pub fn hash(bytes: &[u8]) -> Hash { /// program, this is using Solana’s `sol_blake3` syscall. Otherwise, the /// calculation is done by `blake3` crate. #[allow(unreachable_code)] -pub fn hashv(slices: &[&[u8]]) -> Hash { +pub fn hashv(slices: &[&[u8]]) -> CryptoHash { if USE_SOL { #[cfg(feature = "solana-program-2")] - return Hash(solana_program_2::blake3::hashv(slices).0); + return CryptoHash(solana_program_2::blake3::hashv(slices).0); #[cfg(feature = "solana-program")] - return Hash(solana_program::blake3::hashv(slices).0); + return CryptoHash(solana_program::blake3::hashv(slices).0); } let mut hasher = Hasher::default(); for bytes in slices { hasher.update(bytes); } - hasher.finalize().into() + CryptoHash(hasher.finalize().into()) } diff --git a/common/cf-solana/src/consensus.rs b/common/cf-solana/src/consensus.rs index 6ea6eced..fbf52071 100644 --- a/common/cf-solana/src/consensus.rs +++ b/common/cf-solana/src/consensus.rs @@ -47,9 +47,7 @@ impl TryFrom<&crate::Header> for ConsensusState { fn try_from(header: &crate::Header) -> Result { header.decode_witness().ok_or(proto::BadMessage).map( - |(trie_root, timestamp_sec)| { - Self::new(trie_root.into(), timestamp_sec) - }, + |(trie_root, timestamp_sec)| Self::new(trie_root, timestamp_sec), ) } } diff --git a/common/cf-solana/src/header.rs b/common/cf-solana/src/header.rs index d0355e98..01c1a41d 100644 --- a/common/cf-solana/src/header.rs +++ b/common/cf-solana/src/header.rs @@ -1,7 +1,8 @@ use alloc::vec::Vec; use core::num::NonZeroU64; -use crate::types::Hash; +use lib::hash::CryptoHash; + use crate::{proof, proto}; /// The consensus header of the guest blockchain. @@ -14,7 +15,7 @@ pub struct Header { pub slot: NonZeroU64, /// Slot’s bank hash. - pub bank_hash: Hash, + pub bank_hash: CryptoHash, /// Proof of the accounts delta hash. pub delta_hash_proof: proof::DeltaHashProof, @@ -33,13 +34,12 @@ impl Header { /// trie and Solana block timestamp in seconds. /// /// Returns None if the witness account data has unexpected format - /// (e.g. it’s not 40-byte long). See `WitnessedData` in - /// `solana-witnessed-trie`. - // TODO(mina86): Ideally we would use wittrie::api::WitnessedData here but - // wittrie depends on Solana and we don’t want to introduce required Solana - // dependencies here. Moving WitnessData to a crate in common/ is an option - // but for the time being we’re duplicating the logic here. - pub fn decode_witness(&self) -> Option<(&Hash, NonZeroU64)> { + /// (e.g. it’s not 40-byte long). See `witness::Data` in solana-trie. + // TODO(mina86): Ideally we would use solana_trie::witness::Data here but + // solana_trie depends on Solana and we don’t want to introduce required + // Solana dependencies here. Moving witness::Data to a crate in common/ is + // an option but for the time being we’re duplicating the logic here. + pub fn decode_witness(&self) -> Option<(&CryptoHash, NonZeroU64)> { let data = self.witness_proof.account_hash_data.data().try_into().ok()?; let (root, rest) = stdx::split_array_ref::<32, 8, 40>(data); diff --git a/common/cf-solana/src/proof.rs b/common/cf-solana/src/proof.rs index 78186f9d..5f447dbf 100644 --- a/common/cf-solana/src/proof.rs +++ b/common/cf-solana/src/proof.rs @@ -10,7 +10,7 @@ use lib::par::prelude::*; #[cfg(test)] mod tests; -use crate::types::{Hash, PubKey}; +use crate::types::PubKey; /// The fanout of a accounts delta Merkle tree. /// @@ -48,7 +48,7 @@ pub struct MerkleProof { path: MerklePath, /// Sibling hashes at each level concatenated into a single vector. - siblings: Vec, + siblings: Vec, } /// Iterator over levels stored in a Merkle proof. @@ -61,7 +61,7 @@ pub struct MerkleProof { /// the node itself. pub struct ProofLevels<'a> { path: &'a [u8], - siblings: &'a [Hash], + siblings: &'a [CryptoHash], } @@ -74,9 +74,9 @@ impl MerkleProof { /// and the new proof. Otherwise, if given `pubkey` does not exist in /// `accounts`, returns `None`. `accounts` is sorted in either case. pub fn generate( - accounts: &mut [(PubKey, Hash)], + accounts: &mut [(PubKey, CryptoHash)], pubkey: &PubKey, - ) -> Option<(Hash, MerkleProof)> { + ) -> Option<(CryptoHash, MerkleProof)> { lib::par::sort_unstable_by(accounts, |a, b| a.0.cmp(&b.0)); let pos = @@ -88,7 +88,7 @@ impl MerkleProof { /// Calculates expected commitment root assuming that the proof is for /// account with hash specified by `account`. - pub fn expected_root(&self, account: Hash) -> Hash { + pub fn expected_root(&self, account: CryptoHash) -> CryptoHash { let mut hash = account; for (idx_in_chunk, siblings) in self.levels() { let (head, tail) = siblings.split_at(idx_in_chunk); @@ -100,7 +100,7 @@ impl MerkleProof { for hash in tail { hasher.update(hash.as_ref()); } - hash = hasher.build().into(); + hash = hasher.build(); } hash } @@ -121,7 +121,7 @@ impl MerkleProof { /// `chunk` are all hashes in a node at the level (as such it may be at most /// [`MERKLE_FANOUT`] elements) while `idx_in_chunk` is index of the child /// that is being proven in the chunk. - pub fn push_level(&mut self, chunk: &[Hash], idx_in_chunk: usize) { + pub fn push_level(&mut self, chunk: &[CryptoHash], idx_in_chunk: usize) { assert!(idx_in_chunk < chunk.len()); let len = chunk.len() - 1; self.siblings.reserve(len); @@ -175,7 +175,7 @@ impl MerkleProof { let (path, bytes) = stdx::split_at_checked(bytes, depth.into())?; let path = MerklePath::try_from(path).ok()?; let (siblings, bytes) = stdx::as_chunks::<32, u8>(bytes); - let siblings = bytemuck::cast_slice::<[u8; 32], Hash>(siblings); + let siblings = bytemuck::cast_slice::<[u8; 32], CryptoHash>(siblings); let siblings_count: usize = path.iter().map(|byte| Self::unpack_index_len(*byte).1).sum(); if bytes.is_empty() && siblings.len() == siblings_count { @@ -187,7 +187,7 @@ impl MerkleProof { } impl<'a> core::iter::Iterator for ProofLevels<'a> { - type Item = (usize, &'a [Hash]); + type Item = (usize, &'a [CryptoHash]); fn next(&mut self) -> Option { let ((index, len), path_tail) = match self.path.split_first() { @@ -264,8 +264,8 @@ impl AccountHashData { /// `accounts`, returns `None`. `accounts` is sorted in either case. pub fn generate_proof( self, - accounts: &mut [(PubKey, Hash)], - ) -> Option<(Hash, AccountProof)> { + accounts: &mut [(PubKey, CryptoHash)], + ) -> Option<(CryptoHash, AccountProof)> { let (root, proof) = MerkleProof::generate(accounts, self.key())?; Some((root, AccountProof { account_hash_data: self, proof })) } @@ -284,7 +284,7 @@ impl AccountHashData { pub fn key(&self) -> &PubKey { self.get::<32>(self.0.len() - 32).into() } /// Returns hash of the account. - pub fn calculate_hash(&self) -> Hash { + pub fn calculate_hash(&self) -> CryptoHash { crate::blake3::hash(self.0.as_slice()) } @@ -343,14 +343,14 @@ impl AccountProof { /// and the new proof. Otherwise, if the account does not exist in /// `accounts`, returns `None`. `accounts` is sorted in either case. pub fn generate( - accounts: &mut [(PubKey, Hash)], + accounts: &mut [(PubKey, CryptoHash)], lamports: u64, owner: &PubKey, executable: bool, rent_epoch: u64, data: &[u8], pubkey: &PubKey, - ) -> Option<(Hash, AccountProof)> { + ) -> Option<(CryptoHash, AccountProof)> { let (root, proof) = MerkleProof::generate(accounts, pubkey)?; let account_hash_data = AccountHashData::new( lamports, owner, executable, rent_epoch, data, pubkey, @@ -359,7 +359,7 @@ impl AccountProof { } /// Calculates expected commitment root for this account proof. - pub fn expected_root(&self) -> Hash { + pub fn expected_root(&self) -> CryptoHash { self.proof.expected_root(self.account_hash_data.calculate_hash()) } } @@ -369,10 +369,10 @@ impl AccountProof { #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DeltaHashProof { - pub parent_blockhash: Hash, - pub accounts_delta_hash: Hash, + pub parent_blockhash: CryptoHash, + pub accounts_delta_hash: CryptoHash, pub num_sigs: u64, - pub blockhash: Hash, + pub blockhash: CryptoHash, /// Epoch accounts hash, i.e. hash of all the accounts. /// @@ -382,12 +382,12 @@ pub struct DeltaHashProof { feature = "serde", serde(skip_serializing_if = "Option::is_none", default) )] - pub epoch_accounts_hash: Option, + pub epoch_accounts_hash: Option, } impl DeltaHashProof { /// Calculates bank hash. - pub fn calculate_bank_hash(&self) -> Hash { + pub fn calculate_bank_hash(&self) -> CryptoHash { // See hash_internal_state function in bank.rs source file of // solana-runtime crate. let hash = CryptoHash::digestv(&[ @@ -402,7 +402,6 @@ impl DeltaHashProof { } None => hash, } - .into() } /// Serialises the object into a binary format. @@ -486,11 +485,11 @@ pub fn hash_account( rent_epoch: u64, data: &[u8], pubkey: &PubKey, -) -> Hash { +) -> CryptoHash { // See hash_account_data function in sources of solana-accounts-db crate. if lamports == 0 { - return Hash::default(); + return CryptoHash::default(); } let mut hasher = crate::blake3::Hasher::default(); @@ -519,7 +518,7 @@ pub fn hash_account( buffer.try_extend_from_slice(pubkey.as_ref()).unwrap(); hasher.update(&buffer); - hasher.finalize().into() + CryptoHash(hasher.finalize().into()) } /// Computes Merkle root of given hashes. @@ -530,14 +529,14 @@ pub fn hash_account( /// This is similar to [`AccountsHasher::accumulate_account_hashes`] method but /// we reimplement it because that method takes ownership of hashes which is /// something we need to keep. -fn compute_merkle_root(accounts: &mut [(PubKey, Hash)]) -> Hash { - let mut hashes: Vec = lib::par::chunks(accounts, MERKLE_FANOUT) +fn compute_merkle_root(accounts: &mut [(PubKey, CryptoHash)]) -> CryptoHash { + let mut hashes: Vec = lib::par::chunks(accounts, MERKLE_FANOUT) .map(|chunk| { let mut hasher = CryptoHash::builder(); for item in chunk { hasher.update(item.1.as_ref()); } - Hash::from(hasher.build()) + hasher.build() }) .collect(); @@ -554,7 +553,7 @@ fn compute_merkle_root(accounts: &mut [(PubKey, Hash)]) -> Hash { for item in hashes[idx..].iter().take(MERKLE_FANOUT) { hasher.update(item.as_ref()); } - hashes[out] = hasher.build().into(); + hashes[out] = hasher.build(); out += 1; } hashes.truncate(out); @@ -568,12 +567,12 @@ fn compute_merkle_root(accounts: &mut [(PubKey, Hash)]) -> Hash { /// The `accounts` **must be** sorted by the public key. This *does not* sort /// the accounts. Panics if `pos >= accounts.len()`. fn generate_merkle_proof( - accounts: &[(PubKey, Hash)], + accounts: &[(PubKey, CryptoHash)], mut pos: usize, ) -> MerkleProof { let mut proof = MerkleProof::default(); - let mut current_hashes: Vec = + let mut current_hashes: Vec = accounts.iter().map(|&(_pubkey, hash)| hash).collect(); while current_hashes.len() > 1 { let chunk_index = pos / MERKLE_FANOUT; @@ -593,14 +592,14 @@ fn generate_merkle_proof( proof } -fn compute_hashes_at_next_level(hashes: &[Hash]) -> Vec { +fn compute_hashes_at_next_level(hashes: &[CryptoHash]) -> Vec { lib::par::chunks(hashes, MERKLE_FANOUT) .map(|chunk| { let mut hasher = CryptoHash::builder(); for hash in chunk { hasher.update(hash.as_ref()); } - hasher.build().into() + hasher.build() }) .collect() } @@ -610,21 +609,9 @@ fn compute_hashes_at_next_level(hashes: &[Hash]) -> Vec { // ========== Miscellaneous ==================================================== // -impl core::fmt::Display for Hash { - fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { - <&lib::hash::CryptoHash>::from(self).fmt(fmtr) - } -} - impl core::fmt::Display for PubKey { fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { - <&lib::hash::CryptoHash>::from(&self.0).fmt_bs58(fmtr) - } -} - -impl core::fmt::Debug for Hash { - fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { - core::fmt::Display::fmt(self, fmtr) + <&CryptoHash>::from(&self.0).fmt_bs58(fmtr) } } diff --git a/common/cf-solana/src/proof/tests.rs b/common/cf-solana/src/proof/tests.rs index d71c3a14..214bd263 100644 --- a/common/cf-solana/src/proof/tests.rs +++ b/common/cf-solana/src/proof/tests.rs @@ -19,8 +19,8 @@ fn test_consts_sanity() { assert_eq!(size_of::<$golden>(), size_of::<$our>()); }; } - assert_same_size!(solana_program_2::hash::Hash, Hash); - assert_same_size!(solana_program_2::blake3::Hash, Hash); + assert_same_size!(solana_program_2::hash::Hash, CryptoHash); + assert_same_size!(solana_program_2::blake3::Hash, CryptoHash); assert_same_size!(Pubkey, PubKey); } @@ -39,9 +39,9 @@ fn generate>(rng: &mut impl rand::Rng) -> T { } /// Generates random accounts. -fn make_accounts(rng: &mut impl rand::Rng) -> Vec<(PubKey, Hash)> { +fn make_accounts(rng: &mut impl rand::Rng) -> Vec<(PubKey, CryptoHash)> { let count = if cfg!(miri) { 50 } else { 1000 }; - (0..count).map(|_| (generate(rng), Hash(generate(rng)))).collect() + (0..count).map(|_| (generate(rng), CryptoHash(generate(rng)))).collect() } /// Tests Merkle tree root calculation. @@ -49,7 +49,7 @@ fn make_accounts(rng: &mut impl rand::Rng) -> Vec<(PubKey, Hash)> { fn test_root() { let mut rng = make_rng(); let mut accounts = make_accounts(&mut rng); - let leaf = accounts[0].0.clone(); + let leaf = accounts[0].0; // Note that we on purpose leav accounts unsorted to make sure the // function sorts the elements before calculating the root and proof. let (got, _) = MerkleProof::generate(&mut accounts, &leaf).unwrap(); @@ -57,7 +57,7 @@ fn test_root() { // accumulate_account_hashes fails Miri tests inside of crossbeam crate // so we’re using hard-coded expected hash in Miri and compare to // upstream in non-Miri runs only. - let want = Hash::from(if cfg!(miri) { + let want = CryptoHash::from(if cfg!(miri) { // Accounts generation is deterministic thus this is known as well. [ 0x2a, 0x65, 0x5e, 0xb9, 0x96, 0x40, 0x8e, 0xd1, 0xb9, 0x7c, 0x5a, @@ -96,7 +96,7 @@ fn test_proof_verification() { #[cfg(not(miri))] let indexes = indexes.chain((0..100).map(|_| rng.gen_range(0..len))); for index in indexes { - let (leaf_pubkey, leaf_hash) = accounts[index].clone(); + let (leaf_pubkey, leaf_hash) = accounts[index]; let (root, proof) = MerkleProof::generate(&mut accounts, &leaf_pubkey).unwrap(); assert_eq!(root, proof.expected_root(leaf_hash), "index: {index}"); @@ -110,16 +110,16 @@ fn test_invalid_proof_verification() { let mut accounts = make_accounts(&mut rng); let index = rng.gen_range(0..accounts.len()); - let (leaf_pubkey, leaf_hash) = accounts[index].clone(); + let (leaf_pubkey, leaf_hash) = accounts[index]; let (root, mut proof) = MerkleProof::generate(&mut accounts, &leaf_pubkey).unwrap(); // Sanity check. - assert_eq!(root, proof.expected_root(leaf_hash.clone())); + assert_eq!(root, proof.expected_root(leaf_hash)); // Check invalid leaf hash. - assert_ne!(root, proof.expected_root(Hash(generate(&mut rng)))); + assert_ne!(root, proof.expected_root(CryptoHash(generate(&mut rng)))); // Check invalid index in level. proof.path[0] = { @@ -127,7 +127,7 @@ fn test_invalid_proof_verification() { let idx = if idx == 0 { 1 } else { 0 }; MerkleProof::pack_index_len(idx, len) }; - assert_ne!(root, proof.expected_root(leaf_hash.clone())); + assert_ne!(root, proof.expected_root(leaf_hash)); } #[cfg(not(miri))] // Miri fails on FFI in blake3 crate @@ -229,7 +229,7 @@ mod hash_account { let mut rng = make_rng(); let mut accounts = make_accounts(&mut rng); - accounts[0] = (pubkey.clone().into(), Hash(WANT)); + accounts[0] = (pubkey.into(), CryptoHash(WANT)); let (root, proof) = AccountProof::generate( &mut accounts, diff --git a/common/cf-solana/src/serde_impl.rs b/common/cf-solana/src/serde_impl.rs index b67ffabc..2993cc95 100644 --- a/common/cf-solana/src/serde_impl.rs +++ b/common/cf-solana/src/serde_impl.rs @@ -2,28 +2,10 @@ use core::fmt; use base64::engine::general_purpose::STANDARD as BASE64_ENGINE; use base64::Engine; -use lib::hash::CryptoHash; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; use crate::proof::{AccountHashData, MerkleProof}; -use crate::types::{Hash, PubKey}; - - -// -// ========== Hash ============================================================= -// - -impl Serialize for Hash { - fn serialize(&self, ser: S) -> Result { - <&CryptoHash>::from(self).serialize(ser) - } -} - -impl<'de> Deserialize<'de> for Hash { - fn deserialize>(de: D) -> Result { - CryptoHash::deserialize(de).map(Self::from) - } -} +use crate::types::PubKey; // diff --git a/common/cf-solana/src/types.rs b/common/cf-solana/src/types.rs index 9f8fb3a8..08d0a8e1 100644 --- a/common/cf-solana/src/types.rs +++ b/common/cf-solana/src/types.rs @@ -1,38 +1,4 @@ use bytemuck::TransparentWrapper; -use lib::hash::CryptoHash; - -/// Cryptographically secure hash. -/// -/// The type is completely algorithm agnostic. It does not provide any methods -/// for computing the hash and in particular may store SHA2 or Blake3 digest. -/// This is in contrast to `solana_program::hash::Hash` or -/// `solana_program::blake3::Hash` which are more strongly typed. -/// -/// We’re using a separate type rather than [`CryptoHash`] because we want to -/// have convenient conversion function between our type and Solana’s types. -/// Another aspect is that [`CryptoHash`] is (so far) only used for SHA2 hashes -/// while this type is also used for Blake3 hashes. This is something that we -/// may end up revisiting. -#[derive( - Clone, - Copy, - Default, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - bytemuck::TransparentWrapper, - bytemuck::Pod, - bytemuck::Zeroable, - derive_more::AsRef, - derive_more::AsMut, - derive_more::From, - derive_more::Into, -)] -#[into(owned, ref, ref_mut)] -#[repr(transparent)] -pub struct Hash(pub [u8; 32]); /// Solana public key also used as account address. #[derive( @@ -57,143 +23,36 @@ pub struct Hash(pub [u8; 32]); pub struct PubKey(pub [u8; 32]); -impl From for Hash { - fn from(hash: CryptoHash) -> Hash { Hash(hash.into()) } +impl<'a> From<&'a [u8; 32]> for &'a PubKey { + fn from(bytes: &'a [u8; 32]) -> Self { ::wrap_ref(bytes) } } -impl<'a> From<&'a CryptoHash> for &'a Hash { - fn from(hash: &'a CryptoHash) -> &'a Hash { - Hash::wrap_ref(hash.as_array()) - } -} - -impl From for CryptoHash { - fn from(hash: Hash) -> Self { Self(hash.0) } -} - -impl<'a> From<&'a Hash> for &'a CryptoHash { - fn from(hash: &'a Hash) -> Self { Self::from(&hash.0) } +impl<'a> From<&'a mut [u8; 32]> for &'a mut PubKey { + fn from(bytes: &'a mut [u8; 32]) -> Self { ::wrap_mut(bytes) } } +impl<'a> TryFrom<&'a [u8]> for &'a PubKey { + type Error = core::array::TryFromSliceError; -impl From<::blake3::Hash> for Hash { - fn from(hash: ::blake3::Hash) -> Hash { Hash(hash.into()) } -} - -impl<'a> From<&'a ::blake3::Hash> for &'a Hash { - fn from(hash: &'a ::blake3::Hash) -> &'a Hash { - Hash::wrap_ref(hash.as_bytes()) + #[inline] + fn try_from(bytes: &'a [u8]) -> Result { + <&[u8; 32]>::try_from(bytes).map(Into::into) } } -impl From for ::blake3::Hash { - fn from(hash: Hash) -> Self { Self::from(hash.0) } -} - - -macro_rules! impl_ref_conversion { - ($ty:ty) => { - impl<'a> From<&'a [u8; 32]> for &'a $ty { - fn from(bytes: &'a [u8; 32]) -> Self { <$ty>::wrap_ref(bytes) } - } - - impl<'a> From<&'a mut [u8; 32]> for &'a mut $ty { - fn from(bytes: &'a mut [u8; 32]) -> Self { <$ty>::wrap_mut(bytes) } - } - - impl<'a> TryFrom<&'a [u8]> for &'a $ty { - type Error = core::array::TryFromSliceError; - - #[inline] - fn try_from(bytes: &'a [u8]) -> Result { - <&[u8; 32]>::try_from(bytes).map(Into::into) - } - } - - impl<'a> TryFrom<&'a [u8]> for $ty { - type Error = core::array::TryFromSliceError; +impl<'a> TryFrom<&'a [u8]> for PubKey { + type Error = core::array::TryFromSliceError; - #[inline] - fn try_from(bytes: &'a [u8]) -> Result { - <&Self>::try_from(bytes).map(Clone::clone) - } - } - }; + #[inline] + fn try_from(bytes: &'a [u8]) -> Result { + <&Self>::try_from(bytes).copied() + } } -impl_ref_conversion!(Hash); -impl_ref_conversion!(PubKey); - #[allow(unused_macros)] macro_rules! impl_sol_conversions { ($crt:ident) => { - // ========== $crt::hash::Hash ========== - - impl From<$crt::hash::Hash> for Hash { - fn from(obj: $crt::hash::Hash) -> Hash { obj.to_bytes().into() } - } - - impl<'a> From<&'a $crt::hash::Hash> for &'a Hash { - fn from(obj: &'a $crt::hash::Hash) -> &'a Hash { - <&[u8; 32]>::try_from(obj.as_ref()).unwrap().into() - } - } - - impl From for $crt::hash::Hash { - fn from(obj: Hash) -> Self { Self::from(obj.0) } - } - - impl<'a> From<&'a Hash> for &'a $crt::hash::Hash { - fn from(obj: &'a Hash) -> Self { - let obj = &obj.0 as *const [u8; 32] as *const $crt::hash::Hash; - // SAFETY: $crt::hash::Hash is repr(transparent) - unsafe { &*obj } - } - } - - // ========== $crt::blake3::Hash ========== - - impl From<$crt::blake3::Hash> for Hash { - fn from(hash: $crt::blake3::Hash) -> Hash { hash.to_bytes().into() } - } - - impl<'a> From<&'a $crt::blake3::Hash> for &'a Hash { - fn from(hash: &'a $crt::blake3::Hash) -> &'a Hash { - (&hash.0).into() - } - } - - impl<'a> From<&'a mut $crt::blake3::Hash> for &'a mut Hash { - fn from(hash: &'a mut $crt::blake3::Hash) -> &'a mut Hash { - (&mut hash.0).into() - } - } - - impl From for $crt::blake3::Hash { - fn from(hash: Hash) -> Self { Self(hash.0) } - } - - impl<'a> From<&'a Hash> for &'a $crt::blake3::Hash { - fn from(hash: &'a Hash) -> Self { - let hash = - &hash.0 as *const [u8; 32] as *const $crt::blake3::Hash; - // SAFETY: $crt::hash::Hash is repr(transparent) - unsafe { &*hash } - } - } - - impl<'a> From<&'a mut Hash> for &'a mut $crt::blake3::Hash { - fn from(hash: &'a mut Hash) -> Self { - let hash = - &mut hash.0 as *mut [u8; 32] as *mut $crt::blake3::Hash; - // SAFETY: $crt::hash::Hash is repr(transparent) - unsafe { &mut *hash } - } - } - - // ========== $crt::pubkey::Pubkey ========== - impl From<$crt::pubkey::Pubkey> for PubKey { fn from(obj: $crt::pubkey::Pubkey) -> PubKey { obj.to_bytes().into() diff --git a/common/guestchain/src/block.rs b/common/guestchain/src/block.rs index 478ee294..cadf870f 100644 --- a/common/guestchain/src/block.rs +++ b/common/guestchain/src/block.rs @@ -221,8 +221,8 @@ impl BlockHeader { // with epoch id equal to self’s block hash. Otherwise, epoch doesn’t // change and the new block uses the same epoch id as self. let epoch_id = match self.next_epoch_commitment.is_some() { - false => self.epoch_id.clone(), - true => prev_block_hash.clone(), + false => self.epoch_id, + true => prev_block_hash, }; let next_epoch_commitment = next_epoch.as_ref().map(crate::Epoch::calc_commitment); @@ -354,11 +354,11 @@ fn test_block_generation() { assert!(genesis.is_genesis()); let mut block = genesis.clone(); - block.prev_block_hash = genesis_hash.clone(); + block.prev_block_hash = genesis_hash; assert!(!block.is_genesis()); let mut block = genesis.clone(); - block.epoch_id = genesis_hash.clone(); + block.epoch_id = genesis_hash; assert!(!block.is_genesis()); assert_eq!(genesis_hash, genesis.calc_hash()); diff --git a/common/guestchain/src/candidates/tests.rs b/common/guestchain/src/candidates/tests.rs index ce49383c..83805469 100644 --- a/common/guestchain/src/candidates/tests.rs +++ b/common/guestchain/src/candidates/tests.rs @@ -325,12 +325,11 @@ impl TestCtx { let count = self.candidates.candidates.len(); let head_stake = self.candidates.head_stake; - let res = - self.candidates.update(&self.config, pubkey.clone(), |_| Ok(0)); + let res = self.candidates.update(&self.config, pubkey, |_| Ok(0)); self.check(); if let Err(err) = res { - let old_stake = self.by_key.get(&pubkey).unwrap().clone(); + let old_stake = *self.by_key.get(&pubkey).unwrap(); assert_eq!(count, self.candidates.candidates.len()); assert_eq!(head_stake, self.candidates.head_stake); @@ -373,9 +372,8 @@ impl TestCtx { let count = self.candidates.candidates.len(); let head_stake = self.candidates.head_stake; - let res = self - .candidates - .update(&self.config, pubkey.clone(), |_| Ok(new_stake)); + let res = + self.candidates.update(&self.config, pubkey, |_| Ok(new_stake)); self.check(); if let Err(err) = res { @@ -383,7 +381,7 @@ impl TestCtx { assert_eq!(head_stake, self.candidates.head_stake); self.verify_update_error(err, pubkey, new_stake); } else { - let entry = self.by_key.entry(pubkey.clone()); + let entry = self.by_key.entry(pubkey); let new = matches!(&entry, Entry::Vacant(_)); assert_eq!( count + usize::from(new), @@ -424,7 +422,7 @@ impl TestCtx { .candidates .candidates .get(usize::from(self.config.max_validators.get())); - let kicked_out = last.clone().map_or(false, |candidiate| { + let kicked_out = last.map_or(false, |candidiate| { candidiate < &Candidate { pubkey, @@ -455,7 +453,7 @@ impl TestCtx { let this = unsafe { &mut *this }; match stake { 0 => this.test_remove(pubkey), - _ => this.test_update(pubkey.clone(), u128::from(stake)), + _ => this.test_update(pubkey, u128::from(stake)), } }); diff --git a/common/guestchain/src/manager.rs b/common/guestchain/src/manager.rs index eb0a7412..e2de9d5a 100644 --- a/common/guestchain/src/manager.rs +++ b/common/guestchain/src/manager.rs @@ -437,7 +437,7 @@ fn test_generate() { let signature = crate::block::Fingerprint::new(&mgr.genesis, mgr.head().1) .sign(&validator.pubkey().make_signer()); - mgr.add_signature(validator.pubkey().clone(), &signature, &()) + mgr.add_signature(*validator.pubkey(), &signature, &()) } mgr.generate_next(5.into(), two, CryptoHash::test(1)).unwrap(); @@ -468,7 +468,7 @@ fn test_generate() { ); assert_eq!( Err(AddSignatureError::BadSignature), - mgr.add_signature(bob.pubkey().clone(), &signature, &()) + mgr.add_signature(*bob.pubkey(), &signature, &()) ); assert_eq!( diff --git a/common/lib/src/hash.rs b/common/lib/src/hash.rs index 8e935eff..b4bdd45d 100644 --- a/common/lib/src/hash.rs +++ b/common/lib/src/hash.rs @@ -7,14 +7,17 @@ use bytemuck::TransparentWrapper; /// A cryptographic hash. #[derive( Clone, + Copy, Default, PartialEq, Eq, - derive_more::AsRef, + bytemuck::Pod, + bytemuck::TransparentWrapper, + bytemuck::Zeroable, derive_more::AsMut, + derive_more::AsRef, derive_more::From, derive_more::Into, - bytemuck::TransparentWrapper, )] #[cfg_attr( feature = "borsh", @@ -143,7 +146,7 @@ impl core::fmt::Debug for CryptoHash { impl<'a> From<&'a [u8; CryptoHash::LENGTH]> for CryptoHash { #[inline] fn from(hash: &'a [u8; CryptoHash::LENGTH]) -> Self { - <&CryptoHash>::from(hash).clone() + *<&CryptoHash>::from(hash) } } @@ -387,6 +390,6 @@ mod serde_impl { assert_eq!(hash, got); let serialised = "\"47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hS\""; - serde_json::from_str::(&serialised).unwrap_err(); + serde_json::from_str::(serialised).unwrap_err(); } } diff --git a/common/memory/src/lib.rs b/common/memory/src/lib.rs index f8a7713a..643a3dbe 100644 --- a/common/memory/src/lib.rs +++ b/common/memory/src/lib.rs @@ -386,8 +386,8 @@ mod test_write_log { let mut wlog = WriteLog::new(&mut alloc); let new_ptrs = (10..20).map(|num| wlog.alloc(num).unwrap()).collect::>(); - assert_nodes(20, &wlog.allocator(), &ptrs, 0); - assert_nodes(20, &wlog.allocator(), &new_ptrs, 10); + assert_nodes(20, wlog.allocator(), &ptrs, 0); + assert_nodes(20, wlog.allocator(), &new_ptrs, 10); wlog.commit(); assert_nodes(20, &alloc, &ptrs, 0); assert_nodes(20, &alloc, &new_ptrs, 10); @@ -399,8 +399,8 @@ mod test_write_log { let mut wlog = WriteLog::new(&mut alloc); let new_ptrs = (10..20).map(|num| wlog.alloc(num).unwrap()).collect::>(); - assert_nodes(20, &wlog.allocator(), &ptrs, 0); - assert_nodes(20, &wlog.allocator(), &new_ptrs, 10); + assert_nodes(20, wlog.allocator(), &ptrs, 0); + assert_nodes(20, wlog.allocator(), &new_ptrs, 10); core::mem::drop(wlog); assert_nodes(10, &alloc, &ptrs, 0); } diff --git a/common/sealable-trie/src/bits.rs b/common/sealable-trie/src/bits.rs index dbf016c5..18fe1918 100644 --- a/common/sealable-trie/src/bits.rs +++ b/common/sealable-trie/src/bits.rs @@ -993,7 +993,7 @@ mod test_pop { op: impl Fn(&mut Owned) -> R, ) -> R { let result = op(bits); - assert_eq!(bits.len() == 0, bits.bytes.is_empty()); + assert_eq!(bits.is_empty(), bits.bytes.is_empty()); result } diff --git a/common/sealable-trie/src/bits/ext_key.rs b/common/sealable-trie/src/bits/ext_key.rs index decdf326..b5910254 100644 --- a/common/sealable-trie/src/bits/ext_key.rs +++ b/common/sealable-trie/src/bits/ext_key.rs @@ -218,12 +218,12 @@ fn test_encode() { assert_eq!(slice, round_trip); } - test(&[0, 1 * 8 + 0, 0x80], U3::_0, 1, &[0x80]); - test(&[0, 1 * 8 + 0, 0x80], U3::_0, 1, &[0xFF]); - test(&[0, 1 * 8 + 4, 0x08], U3::_4, 1, &[0xFF]); - test(&[0, 9 * 8 + 0, 0xFF, 0x80], U3::_0, 9, &[0xFF, 0xFF]); + test(&[0, 8, 0x80], U3::_0, 1, &[0x80]); + test(&[0, 8, 0x80], U3::_0, 1, &[0xFF]); + test(&[0, 8 + 4, 0x08], U3::_4, 1, &[0xFF]); + test(&[0, 9 * 8, 0xFF, 0x80], U3::_0, 9, &[0xFF, 0xFF]); test(&[0, 9 * 8 + 4, 0x0F, 0xF8], U3::_4, 9, &[0xFF, 0xFF]); - test(&[0, 17 * 8 + 0, 0xFF, 0xFF, 0x80], U3::_0, 17, &[0xFF, 0xFF, 0xFF]); + test(&[0, 17 * 8, 0xFF, 0xFF, 0x80], U3::_0, 17, &[0xFF, 0xFF, 0xFF]); test(&[0, 17 * 8 + 4, 0x0F, 0xFF, 0xF8], U3::_4, 17, &[0xFF, 0xFF, 0xFF]); let mut want = [0xFF; 36]; diff --git a/common/sealable-trie/src/nodes/stress_tests.rs b/common/sealable-trie/src/nodes/stress_tests.rs index 272386ec..76ff73f6 100644 --- a/common/sealable-trie/src/nodes/stress_tests.rs +++ b/common/sealable-trie/src/nodes/stress_tests.rs @@ -108,7 +108,7 @@ fn gen_random_node<'a>( let (key, right) = stdx::split_array_ref::<34, 32, 66>(buf); let (_, left) = stdx::split_array_ref::<2, 32, 34>(key); if rng.gen::() & 1 == 0 { - let children = [rand_ref(rng, &left), rand_ref(rng, &right)]; + let children = [rand_ref(rng, left), rand_ref(rng, right)]; Node::Branch { children } } else { let offset = U3::wrap(rng.gen::()); @@ -116,7 +116,7 @@ fn gen_random_node<'a>( let length = rng.gen_range(1..=max_length - u16::from(offset)); Node::Extension { key: bits::ExtKey::new(key, offset, length).unwrap(), - child: rand_ref(rng, &right), + child: rand_ref(rng, right), } } } diff --git a/common/sealable-trie/src/proof.rs b/common/sealable-trie/src/proof.rs index 3f573d90..294da36c 100644 --- a/common/sealable-trie/src/proof.rs +++ b/common/sealable-trie/src/proof.rs @@ -112,7 +112,7 @@ impl Membership { if *root_hash == crate::trie::EMPTY_TRIE_ROOT { false } else if let Some(key) = bits::Slice::from_bytes(key) { - let want = OwnedRef::value(value_hash.clone()); + let want = OwnedRef::value(*value_hash); verify_impl(root_hash, key, want, &self.0).is_some() } else { false @@ -190,7 +190,7 @@ impl NonMembership { // We’re converting non-membership proof into proof that at // key[..(key.len() - len)] a `hash` value is stored. key.pop_back_slice(len.get())?; - Some((key, OwnedRef::value(hash.clone()))) + Some((key, OwnedRef::value(*hash))) } } } @@ -339,8 +339,8 @@ impl OwnedRef { impl<'a, P, S> From<&'a Reference<'a, P, S>> for OwnedRef { fn from(rf: &'a Reference<'a, P, S>) -> OwnedRef { let (is_value, hash) = match rf { - Reference::Node(node) => (false, node.hash.clone()), - Reference::Value(value) => (true, value.hash.clone()), + Reference::Node(node) => (false, *node.hash), + Reference::Value(value) => (true, *value.hash), }; Self { is_value, hash } } @@ -423,7 +423,7 @@ fn test_simple_success() { ); let (got, proof) = trie.prove(key.as_bytes()).unwrap(); - assert_eq!(Some(hash.clone()), got, "Failed getting {key}"); + assert_eq!(Some(hash), got, "Failed getting {key}"); assert!( proof.verify(trie.hash(), key.as_bytes(), Some(&hash)), "Failed verifying {key} → {hash} get proof: {proof:?}", diff --git a/common/sealable-trie/src/trie.rs b/common/sealable-trie/src/trie.rs index c1b9c132..4f1a1513 100644 --- a/common/sealable-trie/src/trie.rs +++ b/common/sealable-trie/src/trie.rs @@ -184,7 +184,7 @@ impl> Trie { let mut proof = include_proof.then(proof::Proof::builder); let mut node_ptr = self.root_ptr; - let mut node_hash = self.root_hash.clone(); + let mut node_hash = self.root_hash; loop { let node = self.alloc.get(node_ptr.ok_or(Error::Sealed)?); let node = node.decode()?; @@ -215,17 +215,18 @@ impl> Trie { match child { Reference::Node(node) => { node_ptr = node.ptr; - node_hash = node.hash.clone(); + node_hash = *node.hash; } Reference::Value(value) => { return if value.is_sealed { Err(Error::Sealed) } else if let Some(len) = NonZeroU16::new(key.len()) { - let proof = proof!(proof rev.lookup_key_left(len, value.hash.clone())); + let proof = + proof!(proof rev.lookup_key_left(len, *value.hash)); Ok((None, proof)) } else { let proof = proof!(proof rev.build()); - Ok((Some(value.hash.clone()), proof)) + Ok((Some(*value.hash), proof)) }; } }; diff --git a/common/sealable-trie/src/trie/del.rs b/common/sealable-trie/src/trie/del.rs index 2ad79f1a..e83d9eea 100644 --- a/common/sealable-trie/src/trie/del.rs +++ b/common/sealable-trie/src/trie/del.rs @@ -226,14 +226,12 @@ impl OwnedRef { } impl From> for OwnedRef { - fn from(nref: NodeRef) -> OwnedRef { - Self::Node(nref.ptr, nref.hash.clone()) - } + fn from(nref: NodeRef) -> OwnedRef { Self::Node(nref.ptr, *nref.hash) } } impl From> for OwnedRef { fn from(vref: ValueRef) -> OwnedRef { - Self::Value(vref.is_sealed, vref.hash.clone()) + Self::Value(vref.is_sealed, *vref.hash) } } diff --git a/common/sealable-trie/src/trie/iter.rs b/common/sealable-trie/src/trie/iter.rs index 82a7f810..a80860c3 100644 --- a/common/sealable-trie/src/trie/iter.rs +++ b/common/sealable-trie/src/trie/iter.rs @@ -127,7 +127,7 @@ fn get_subtrie_root>( return GetSubtrieRootResult::Single(Entry { is_sealed: value.is_sealed, sub_key: prefix, - hash: Some(value.hash.clone()), + hash: Some(*value.hash), }); } Reference::Value(_) => { @@ -214,7 +214,7 @@ impl<'a, A: memory::Allocator> Context<'a, A> { self.entries.push(Entry { is_sealed, sub_key: self.prefix.clone(), - hash: Some(hash.clone()), + hash: Some(*hash), }); self.prefix.truncate(len); } diff --git a/common/sealable-trie/src/trie/set.rs b/common/sealable-trie/src/trie/set.rs index b22081ab..aeaa4908 100644 --- a/common/sealable-trie/src/trie/set.rs +++ b/common/sealable-trie/src/trie/set.rs @@ -199,7 +199,7 @@ impl<'a, A: memory::Allocator> Context<'a, A> { // It’s a value reference so we just need to update it. We know // key is empty so there's nothing complex we need to do. Just // return new value reference. - Ok(OwnedRef::Value(self.value_hash.clone())) + Ok(OwnedRef::Value(*self.value_hash)) } } } @@ -213,7 +213,7 @@ impl<'a, A: memory::Allocator> Context<'a, A> { /// of the key) and returns reference to the first ancestor node. fn insert_value(&mut self) -> Result { let mut ptr: Option = None; - let mut hash = self.value_hash.clone(); + let mut hash = *self.value_hash; for chunk in self.key.chunks().rev() { let child = match ptr { None => Reference::value(false, &hash), diff --git a/common/sealable-trie/src/trie/tests.rs b/common/sealable-trie/src/trie/tests.rs index a9e93640..71adf11a 100644 --- a/common/sealable-trie/src/trie/tests.rs +++ b/common/sealable-trie/src/trie/tests.rs @@ -141,7 +141,7 @@ fn make_trie(small: bool, sealed: bool) -> (TestTrie, &'static [u8]) { #[test] fn test_seal() { let (mut trie, keys) = make_trie(false, false); - let hash = trie.hash().clone(); + let hash = *trie.hash(); for b in keys { trie.seal(core::slice::from_ref(b), true); } @@ -152,7 +152,7 @@ fn test_seal() { #[test] fn test_seal_small() { let (mut trie, keys) = make_trie(true, false); - let hash = trie.hash().clone(); + let hash = *trie.hash(); for b in keys { trie.seal(core::slice::from_ref(b), true); } @@ -324,8 +324,7 @@ fn stress_test() { // Now insert and delete keys randomly total of count times. On average // that means count/2 deletions and count/2 new insertions. - let mut keys = - trie.mapping.keys().map(|key| key.clone()).collect::>(); + let mut keys = trie.mapping.keys().cloned().collect::>(); for _ in 0..count { let idx = if keys.is_empty() { 1 @@ -619,7 +618,7 @@ impl TestTrie { fn check_all_reads(&self) { for (key, value) in self.mapping.iter() { - let got = self.trie.get(&key).unwrap_or_else(|err| { + let got = self.trie.get(key).unwrap_or_else(|err| { panic!("Failed getting ‘{key:?}’: {err}") }); assert_eq!(Some(value), got.as_ref(), "Invalid value at ‘{key:?}’"); diff --git a/solana/solana-ibc/programs/solana-ibc/src/chain.rs b/solana/solana-ibc/programs/solana-ibc/src/chain.rs index 24fda8fe..d57ef6a4 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/chain.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/chain.rs @@ -77,7 +77,7 @@ impl ChainData { 1.into(), host_height, host_timestamp, - trie.hash().clone(), + *trie.hash(), genesis_epoch, ) .map_err(|err| Error::Internal(err.into()))?; @@ -149,7 +149,7 @@ impl ChainData { let block_hash = header.calc_hash(); if res.got_new_signature() { events::emit(events::BlockSigned { - block_hash: block_hash.clone(), + block_hash, block_height: header.block_height, pubkey, signature: signature.clone(), @@ -299,7 +299,7 @@ impl ChainData { pub fn genesis(&self) -> Result { let inner = self.get()?; - Ok(inner.manager.genesis().clone()) + Ok(*inner.manager.genesis()) } pub fn sig_verify_program_id(&self) -> Result { @@ -371,7 +371,7 @@ impl ChainInner { let res = self.manager.generate_next( host_height, host_timestamp, - trie.hash().clone(), + *trie.hash(), ); match res { Ok(_) => { diff --git a/solana/solana-ibc/programs/solana-ibc/src/storage.rs b/solana/solana-ibc/programs/solana-ibc/src/storage.rs index a57fac5c..178f810f 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/storage.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/storage.rs @@ -391,7 +391,7 @@ impl PrivateStorage { /// Provable storage, i.e. the trie, held in an account. pub type TrieAccount<'a, 'b> = - solana_trie::TrieAccount>; + solana_trie::TrieAccount<'a, solana_trie::ResizableAccount<'a, 'b>>; /// Checks contents of given unchecked account and returns a trie if it’s valid. /// diff --git a/solana/solana-ibc/programs/solana-ibc/src/tests.rs b/solana/solana-ibc/programs/solana-ibc/src/tests.rs index 77abd998..0f7ed436 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/tests.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/tests.rs @@ -77,7 +77,7 @@ macro_rules! make_message { #[ignore = "Requires local validator to run"] fn anchor_test_deliver() -> Result<()> { let authority = Rc::new(read_keypair_file("../../keypair.json").unwrap()); - println!("This is pubkey {}", authority.pubkey().to_string()); + println!("This is pubkey {}", authority.pubkey()); let lamports = 2_000_000_000; let client = Client::new_with_options( @@ -190,7 +190,7 @@ fn anchor_test_deliver() -> Result<()> { let chain_account: chain::ChainData = program.account(chain).unwrap(); let genesis_hash = chain_account.genesis().unwrap(); - println!("This is genesis hash {}", genesis_hash.to_string()); + println!("This is genesis hash {}", genesis_hash); /* * Create New Mock Client @@ -439,7 +439,7 @@ fn anchor_test_deliver() -> Result<()> { token_metadata_program: anchor_spl::metadata::ID, }) .args(instruction::InitMint { - hashed_full_denom: hashed_full_denom_on_source.clone(), + hashed_full_denom: hashed_full_denom_on_source, token_name: TOKEN_NAME.to_string(), token_symbol: TOKEN_SYMBOL.to_string(), token_uri: TOKEN_URI.to_string(), @@ -534,7 +534,7 @@ fn anchor_test_deliver() -> Result<()> { token_program: Some(anchor_spl::token::ID), }) .args(instruction::SendTransfer { - hashed_full_denom: hashed_denom.clone(), + hashed_full_denom: hashed_denom, msg: msg_transfer, }) .payer(authority.clone()) @@ -929,7 +929,7 @@ fn construct_packet_from_denom( }; let packet_data = ibc::apps::transfer::types::packet::PacketData { - token: token.into(), + token, sender: ibc::Signer::from(sender_token_address.to_string()), // Should be a token account receiver: ibc::Signer::from(receiver_token_address.to_string()), // Should be a token account memo: memo.into(), @@ -937,7 +937,9 @@ fn construct_packet_from_denom( let serialized_data = serde_json::to_vec(&packet_data).unwrap(); - let packet = ibc::Packet { + + + ibc::Packet { seq_on_a: sequence.into(), port_id_on_a: port_id.clone(), chan_id_on_a: channel_id_on_a, @@ -946,9 +948,7 @@ fn construct_packet_from_denom( data: serialized_data.clone(), timeout_height_on_b: max_timeout_height(), timeout_timestamp_on_b: ibc::Timestamp::none(), - }; - - packet + } } fn construct_transfer_packet_from_denom( @@ -974,7 +974,7 @@ fn construct_transfer_packet_from_denom( println!("This is token {:?}", token); let packet_data = ibc::apps::transfer::types::packet::PacketData { - token: token.into(), + token, sender: ibc::Signer::from(sender_address.to_string()), // Should be a token account receiver: ibc::Signer::from(receiver_address.to_string()), // Should be a token account memo: String::from("Sending a transfer").into(), diff --git a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs index 341843ac..5d1864b5 100644 --- a/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs +++ b/solana/solana-ibc/programs/solana-ibc/src/transfer/impls.rs @@ -655,7 +655,7 @@ mod tests { Some(dst.chars().filter(|chr| *chr != '_').collect::()) .map(|val| val.parse::().ok()); let got = convert_decimals(&src, input_decimals, output_decimals); - let got = got.and_then(|val| Some(check_amount_overflow(val).ok())); + let got = got.map(|val| check_amount_overflow(val).ok()); assert_eq!( want, got, "{src} {input_decimals} → {dst} {output_decimals}" diff --git a/solana/trie-geyser-plugin/Cargo.lock b/solana/trie-geyser-plugin/Cargo.lock index 9a487b64..4248462a 100644 --- a/solana/trie-geyser-plugin/Cargo.lock +++ b/solana/trie-geyser-plugin/Cargo.lock @@ -42,7 +42,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cipher", "cpufeatures", "opaque-debug", @@ -79,7 +79,7 @@ version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "once_cell", "version_check", "zerocopy", @@ -237,7 +237,7 @@ dependencies = [ "bincode", "borsh 0.10.3", "bytemuck", - "solana-program", + "solana-program 2.0.0", "thiserror", ] @@ -466,7 +466,7 @@ checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", - "cfg-if", + "cfg-if 1.0.0", "libc", "miniz_oxide", "object", @@ -554,7 +554,7 @@ dependencies = [ "arrayref", "arrayvec", "cc", - "cfg-if", + "cfg-if 1.0.0", "constant_time_eq", "digest 0.10.7", ] @@ -737,6 +737,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +[[package]] +name = "bstr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -864,11 +874,17 @@ dependencies = [ "prost-build", "proto-utils", "serde", - "solana-program", + "solana-program 2.0.0", "stdx", "trie-ids", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.0" @@ -924,7 +940,7 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen", ] @@ -1007,7 +1023,7 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1146,11 +1162,11 @@ version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "hashbrown 0.14.5", "lock_api", "once_cell", - "parking_lot_core", + "parking_lot_core 0.9.10", "rayon", ] @@ -1310,7 +1326,7 @@ version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1380,7 +1396,7 @@ version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall 0.4.1", "windows-sys 0.52.0", @@ -1423,9 +1439,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "percent-encoding", + "percent-encoding 2.3.1", ] +[[package]] +name = "futures" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a471a38ef8ed83cd6e40aa59c1ffe17db6855c18e3604d9c4ed8c08ebc28678" + [[package]] name = "futures" version = "0.3.30" @@ -1434,6 +1456,7 @@ checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", + "futures-executor", "futures-io", "futures-sink", "futures-task", @@ -1456,12 +1479,35 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", + "num_cpus", +] + [[package]] name = "futures-io" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.71", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -1480,8 +1526,11 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ + "futures 0.1.31", + "futures-channel", "futures-core", "futures-io", + "futures-macro", "futures-sink", "futures-task", "memchr", @@ -1517,7 +1566,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.9.0+wasi-snapshot-preview1", @@ -1530,7 +1579,7 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -1543,6 +1592,19 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +[[package]] +name = "globset" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + [[package]] name = "goblin" version = "0.5.4" @@ -1590,7 +1652,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.11", "tracing", ] @@ -2007,6 +2069,17 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "idna" version = "0.5.0" @@ -2049,6 +2122,15 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -2088,6 +2170,108 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonrpc-client-transports" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b99d4207e2a04fb4581746903c2bb7eb376f88de9c699d0f3e10feeac0cd3a" +dependencies = [ + "derive_more", + "futures 0.3.30", + "jsonrpc-core", + "jsonrpc-pubsub", + "log", + "serde", + "serde_json", + "url 1.7.2", +] + +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures 0.3.30", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "jsonrpc-core-client" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b51da17abecbdab3e3d4f26b01c5ec075e88d3abe3ab3b05dc9aa69392764ec0" +dependencies = [ + "futures 0.3.30", + "jsonrpc-client-transports", +] + +[[package]] +name = "jsonrpc-derive" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b939a78fa820cdfcb7ee7484466746a7377760970f6f9c6fe19f9edcc8a38d2" +dependencies = [ + "proc-macro-crate 0.1.5", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "jsonrpc-http-server" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1dea6e07251d9ce6a552abfb5d7ad6bc290a4596c8dcc3d795fae2bbdc1f3ff" +dependencies = [ + "futures 0.3.30", + "hyper", + "jsonrpc-core", + "jsonrpc-server-utils", + "log", + "net2", + "parking_lot 0.11.2", + "unicase", +] + +[[package]] +name = "jsonrpc-pubsub" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240f87695e6c6f62fb37f05c02c04953cf68d6408b8c1c89de85c7a0125b1011" +dependencies = [ + "futures 0.3.30", + "jsonrpc-core", + "lazy_static", + "log", + "parking_lot 0.11.2", + "rand 0.7.3", + "serde", +] + +[[package]] +name = "jsonrpc-server-utils" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4fdea130485b572c39a460d50888beb00afb3e35de23ccd7fad8ff19f0e0d4" +dependencies = [ + "bytes", + "futures 0.3.30", + "globset", + "jsonrpc-core", + "lazy_static", + "log", + "tokio", + "tokio-stream", + "tokio-util 0.6.10", + "unicase", +] + [[package]] name = "keccak" version = "0.1.5" @@ -2115,6 +2299,7 @@ dependencies = [ "rayon", "serde", "sha2 0.10.8", + "solana-program 1.18.23", "stdx", ] @@ -2226,6 +2411,12 @@ dependencies = [ "libc", ] +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + [[package]] name = "memchr" version = "2.7.4" @@ -2322,6 +2513,17 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03" +[[package]] +name = "net2" +version = "0.2.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b13b648036a2339d06de780866fbdfda0dde886de7b3af2ddeba8b14f4ee34ac" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "winapi", +] + [[package]] name = "num" version = "0.2.1" @@ -2488,6 +2690,17 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + [[package]] name = "parking_lot" version = "0.12.3" @@ -2495,7 +2708,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", - "parking_lot_core", + "parking_lot_core 0.9.10", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", ] [[package]] @@ -2504,7 +2731,7 @@ version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall 0.5.3", "smallvec", @@ -2535,6 +2762,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2600,7 +2833,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "opaque-debug", "universal-hash", @@ -2749,7 +2982,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" dependencies = [ - "percent-encoding", + "percent-encoding 2.3.1", ] [[package]] @@ -2872,6 +3105,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.4.1" @@ -2941,7 +3183,7 @@ dependencies = [ "log", "mime", "once_cell", - "percent-encoding", + "percent-encoding 2.3.1", "pin-project-lite", "rustls", "rustls-pemfile", @@ -2952,9 +3194,9 @@ dependencies = [ "system-configuration", "tokio", "tokio-rustls", - "tokio-util", + "tokio-util 0.7.11", "tower-service", - "url", + "url 2.5.2", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -2969,7 +3211,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.0", "getrandom 0.2.15", "libc", "spin", @@ -3127,7 +3369,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" dependencies = [ - "parking_lot", + "parking_lot 0.12.3", ] [[package]] @@ -3222,7 +3464,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.9.0", "opaque-debug", @@ -3234,7 +3476,7 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "cpufeatures", "digest 0.10.7", ] @@ -3379,8 +3621,8 @@ dependencies = [ "smallvec", "solana-bucket-map", "solana-config-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-frozen-abi 2.0.0", + "solana-frozen-abi-macro 2.0.0", "solana-measure", "solana-metrics", "solana-nohash-hasher", @@ -3447,6 +3689,31 @@ dependencies = [ "solana-sdk", ] +[[package]] +name = "solana-frozen-abi" +version = "1.18.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bfcde2fc6946c99c7e3400fadd04d1628d675bfd66cb34d461c0f3224bd27d1" +dependencies = [ + "block-buffer 0.10.4", + "bs58 0.4.0", + "bv", + "either", + "generic-array", + "im", + "lazy_static", + "log", + "memmap2", + "rustc_version", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.10.8", + "solana-frozen-abi-macro 1.18.23", + "subtle", + "thiserror", +] + [[package]] name = "solana-frozen-abi" version = "2.0.0" @@ -3465,11 +3732,23 @@ dependencies = [ "serde_bytes", "serde_derive", "sha2 0.10.8", - "solana-frozen-abi-macro", + "solana-frozen-abi-macro 2.0.0", "subtle", "thiserror", ] +[[package]] +name = "solana-frozen-abi-macro" +version = "1.18.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5024d241425f4e99f112ee03bfa89e526c86c7ca9bd7e13448a7f2dffb7e060" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.71", +] + [[package]] name = "solana-frozen-abi-macro" version = "2.0.0" @@ -3543,6 +3822,61 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" +[[package]] +name = "solana-program" +version = "1.18.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76056fecde0fe0ece8b457b719729c17173333471c72ad41969982975a10d6e0" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "base64 0.21.7", + "bincode", + "bitflags 2.6.0", + "blake3", + "borsh 0.10.3", + "borsh 0.9.3", + "borsh 1.5.1", + "bs58 0.4.0", + "bv", + "bytemuck", + "cc", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.2.15", + "itertools", + "js-sys", + "lazy_static", + "libc", + "libsecp256k1", + "light-poseidon", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive 0.4.2", + "num-traits", + "parking_lot 0.12.3", + "rand 0.8.5", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-frozen-abi 1.18.23", + "solana-frozen-abi-macro 1.18.23", + "solana-sdk-macro 1.18.23", + "thiserror", + "tiny-bip39", + "wasm-bindgen", + "zeroize", +] + [[package]] name = "solana-program" version = "2.0.0" @@ -3578,7 +3912,7 @@ dependencies = [ "num-bigint 0.4.6", "num-derive 0.4.2", "num-traits", - "parking_lot", + "parking_lot 0.12.3", "rand 0.8.5", "rustc_version", "rustversion", @@ -3588,9 +3922,9 @@ dependencies = [ "serde_json", "sha2 0.10.8", "sha3 0.10.8", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-sdk-macro", + "solana-frozen-abi 2.0.0", + "solana-frozen-abi-macro 2.0.0", + "solana-sdk-macro 2.0.0", "thiserror", "tiny-bip39", "wasm-bindgen", @@ -3615,8 +3949,8 @@ dependencies = [ "rand 0.8.5", "rustc_version", "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-frozen-abi 2.0.0", + "solana-frozen-abi-macro 2.0.0", "solana-measure", "solana-metrics", "solana-sdk", @@ -3678,16 +4012,29 @@ dependencies = [ "sha2 0.10.8", "sha3 0.10.8", "siphasher", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-frozen-abi 2.0.0", + "solana-frozen-abi-macro 2.0.0", "solana-logger", - "solana-program", - "solana-sdk-macro", + "solana-program 2.0.0", + "solana-sdk-macro 2.0.0", "thiserror", "uriparse", "wasm-bindgen", ] +[[package]] +name = "solana-sdk-macro" +version = "1.18.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8613ca80150f7e277e773620ba65d2c5fcc3a08eb8026627d601421ab43aef" +dependencies = [ + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.71", +] + [[package]] name = "solana-sdk-macro" version = "2.0.0" @@ -3730,8 +4077,8 @@ dependencies = [ "percentage", "rustc_version", "solana-bpf-loader-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-frozen-abi 2.0.0", + "solana-frozen-abi-macro 2.0.0", "solana-loader-v4-program", "solana-measure", "solana-metrics", @@ -3777,6 +4124,18 @@ dependencies = [ "thiserror", ] +[[package]] +name = "solana-trie" +version = "0.0.3" +dependencies = [ + "bytemuck", + "lib", + "memory", + "sealable-trie", + "solana-program 1.18.23", + "stdx", +] + [[package]] name = "solana-vote-program" version = "2.0.0" @@ -3789,10 +4148,10 @@ dependencies = [ "rustc_version", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", + "solana-frozen-abi 2.0.0", + "solana-frozen-abi-macro 2.0.0", "solana-metrics", - "solana-program", + "solana-program 2.0.0", "solana-program-runtime", "solana-sdk", "thiserror", @@ -3807,7 +4166,8 @@ dependencies = [ "cf-solana", "derive_more", "lib", - "solana-program", + "solana-program 2.0.0", + "solana-trie", "stdx", "strum 0.25.0", ] @@ -3833,7 +4193,7 @@ dependencies = [ "serde", "serde_json", "sha3 0.9.1", - "solana-program", + "solana-program 2.0.0", "solana-sdk", "subtle", "thiserror", @@ -3885,7 +4245,7 @@ dependencies = [ "borsh 1.5.1", "num-derive 0.4.2", "num-traits", - "solana-program", + "solana-program 2.0.0", "spl-token", "spl-token-2022", "thiserror", @@ -3898,7 +4258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a38ea8b6dedb7065887f12d62ed62c1743aa70749e8558f963609793f6fb12bc" dependencies = [ "bytemuck", - "solana-program", + "solana-program 2.0.0", "spl-discriminator-derive", ] @@ -3932,7 +4292,7 @@ version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0dba2f2bb6419523405d21c301a32c9f9568354d4742552e7972af801f4bdb3" dependencies = [ - "solana-program", + "solana-program 2.0.0", ] [[package]] @@ -3944,7 +4304,7 @@ dependencies = [ "borsh 1.5.1", "bytemuck", "bytemuck_derive", - "solana-program", + "solana-program 2.0.0", "solana-zk-token-sdk", "spl-program-error", ] @@ -3957,7 +4317,7 @@ checksum = "d7b28bed65356558133751cc32b48a7a5ddfc59ac4e941314630bbed1ac10532" dependencies = [ "num-derive 0.4.2", "num-traits", - "solana-program", + "solana-program 2.0.0", "spl-program-error-derive", "thiserror", ] @@ -3981,7 +4341,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37a75a5f0fcc58126693ed78a17042e9dc53f07e357d6be91789f7d62aff61a4" dependencies = [ "bytemuck", - "solana-program", + "solana-program 2.0.0", "spl-discriminator", "spl-pod", "spl-program-error", @@ -3999,7 +4359,7 @@ dependencies = [ "num-derive 0.4.2", "num-traits", "num_enum", - "solana-program", + "solana-program 2.0.0", "thiserror", ] @@ -4014,7 +4374,7 @@ dependencies = [ "num-derive 0.4.2", "num-traits", "num_enum", - "solana-program", + "solana-program 2.0.0", "solana-security-txt", "solana-zk-token-sdk", "spl-memo", @@ -4034,7 +4394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8752b85a5ecc1d9f3a43bce3dd9a6a053673aacf5deb513d1cbb88d3534ffd" dependencies = [ "bytemuck", - "solana-program", + "solana-program 2.0.0", "spl-discriminator", "spl-pod", "spl-program-error", @@ -4047,7 +4407,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6c2318ddff97e006ed9b1291ebec0750a78547f870f62a69c56fe3b46a5d8fc" dependencies = [ "borsh 1.5.1", - "solana-program", + "solana-program 2.0.0", "spl-discriminator", "spl-pod", "spl-program-error", @@ -4062,7 +4422,7 @@ checksum = "a110f33d941275d9f868b96daaa993f1e73b6806cc8836e43075b4d3ad8338a7" dependencies = [ "arrayref", "bytemuck", - "solana-program", + "solana-program 2.0.0", "spl-discriminator", "spl-pod", "spl-program-error", @@ -4077,7 +4437,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdcd73ec187bc409464c60759232e309f83b52a18a9c5610bf281c9c6432918c" dependencies = [ "bytemuck", - "solana-program", + "solana-program 2.0.0", "spl-discriminator", "spl-pod", "spl-program-error", @@ -4242,7 +4602,7 @@ version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "rustix", "windows-sys 0.52.0", @@ -4259,7 +4619,7 @@ dependencies = [ "ed25519 2.2.3", "ed25519-consensus", "flex-error", - "futures", + "futures 0.3.30", "num-traits", "once_cell", "prost", @@ -4410,6 +4770,7 @@ dependencies = [ "bytes", "libc", "mio", + "num_cpus", "pin-project-lite", "socket2", "windows-sys 0.48.0", @@ -4425,6 +4786,31 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.11" @@ -4516,6 +4902,15 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-bidi" version = "0.3.15" @@ -4584,6 +4979,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", +] + [[package]] name = "url" version = "2.5.2" @@ -4591,8 +4997,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" dependencies = [ "form_urlencoded", - "idna", - "percent-encoding", + "idna 0.5.0", + "percent-encoding 2.3.1", ] [[package]] @@ -4634,7 +5040,7 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -4659,7 +5065,7 @@ version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "wasm-bindgen", "web-sys", @@ -4904,13 +5310,25 @@ version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "windows-sys 0.48.0", ] [[package]] name = "witnessed-trie-geyser" version = "0.0.0" +dependencies = [ + "cf-solana", + "jsonrpc-core", + "jsonrpc-core-client", + "jsonrpc-derive", + "serde", + "serde_json", +] + +[[package]] +name = "witnessed-trie-geyser-plugin" +version = "0.0.0" dependencies = [ "arrayvec", "borsh 1.5.1", @@ -4918,6 +5336,7 @@ dependencies = [ "crossbeam-channel", "derive_more", "hex 0.4.3 (git+https://github.com/mina86/rust-hex.git?branch=main)", + "jsonrpc-http-server", "log", "rand 0.8.5", "rand_chacha 0.3.1", @@ -4928,6 +5347,7 @@ dependencies = [ "solana-sdk", "solana-transaction-status", "solana-witnessed-trie", + "witnessed-trie-geyser", ] [[package]] diff --git a/solana/trie-geyser-plugin/src/worker.rs b/solana/trie-geyser-plugin/src/worker.rs index 36d99047..c09b3ebc 100644 --- a/solana/trie-geyser-plugin/src/worker.rs +++ b/solana/trie-geyser-plugin/src/worker.rs @@ -203,10 +203,10 @@ impl Worker { // Calculate bankhash based on accounts_delta_hash and information // extracted from the block. let delta_hash_proof = cf_solana::proof::DeltaHashProof { - parent_blockhash: block.parent_blockhash.into(), + parent_blockhash: block.parent_blockhash.to_bytes().into(), accounts_delta_hash, num_sigs: entry.num_sigs, - blockhash: block.blockhash.into(), + blockhash: block.blockhash.to_bytes().into(), // TODO(mina86): Once every epoch, Solana validators calculate // Merkle tree of all accounts. When that happens, bank_hash is // further calculated as hashv(&[bank_hash, all_accounts_hash]). diff --git a/solana/trie/src/account.rs b/solana/trie/src/account.rs index 2dc06106..5053ab99 100644 --- a/solana/trie/src/account.rs +++ b/solana/trie/src/account.rs @@ -7,6 +7,7 @@ use solana_program::rent::Rent; use solana_program::system_instruction::MAX_PERMITTED_DATA_LENGTH; use solana_program::sysvar::Sysvar; +/// An account backing a Trie which can be resized. #[derive(Debug)] pub struct ResizableAccount<'a, 'info> { account: &'a AccountInfo<'info>, diff --git a/solana/trie/src/header.rs b/solana/trie/src/header.rs index 323ed967..8a1dc314 100644 --- a/solana/trie/src/header.rs +++ b/solana/trie/src/header.rs @@ -98,7 +98,7 @@ fn test_header_encoding() { let hdr = Header { root_ptr: Ptr::new(420).unwrap(), - root_hash: ONE.clone(), + root_hash: ONE, next_block: 42, first_free: 24, }; diff --git a/solana/trie/src/lib.rs b/solana/trie/src/lib.rs index ae06d695..6e7c5e11 100644 --- a/solana/trie/src/lib.rs +++ b/solana/trie/src/lib.rs @@ -1,3 +1,4 @@ +use core::cell::RefMut; use core::mem::ManuallyDrop; #[cfg(test)] @@ -5,11 +6,13 @@ use pretty_assertions::assert_eq; use solana_program::account_info::AccountInfo; use solana_program::program_error::ProgramError; use solana_program::pubkey::Pubkey; +use solana_program::sysvar::Sysvar; mod account; mod alloc; mod data_ref; mod header; +pub mod witness; pub use account::ResizableAccount; pub use data_ref::DataRef; @@ -17,12 +20,14 @@ pub use sealable_trie::Trie; /// Trie stored in a Solana account. -#[derive(Debug)] -pub struct TrieAccount( - ManuallyDrop>>, -); +pub struct TrieAccount<'a, D: DataRef + Sized>(ManuallyDrop>); -impl TrieAccount { +struct Inner<'a, D: DataRef + Sized> { + trie: sealable_trie::Trie>, + witness: Option>, +} + +impl<'a, D: DataRef + Sized> TrieAccount<'a, D> { /// Creates a new TrieAccount from data in an account. /// /// If the data in the account isn’t initialised (i.e. has zero @@ -30,11 +35,31 @@ impl TrieAccount { pub fn new(data: D) -> Option { let (alloc, root) = alloc::Allocator::new(data)?; let trie = sealable_trie::Trie::from_parts(alloc, root.0, root.1); - Some(Self(ManuallyDrop::new(trie))) + Some(Self(ManuallyDrop::new(Inner { trie, witness: None }))) + } + + /// Returns witness data if any. + pub fn witness(&self) -> Option<&RefMut<'a, witness::Data>> { + self.0.witness.as_ref() + } + + /// Sets the witness account. + /// + /// `witness` must be initialised, owned by `owner` and exactly 40 bytes + /// (see [`witness::Data::SIZE`]). Witness is updated automatically once + /// this object is dropped. + pub fn with_witness_account<'info>( + mut self, + witness: &'a AccountInfo<'info>, + owner: &Pubkey, + ) -> Result { + check_account(witness, owner)?; + self.0.witness = Some(witness::Data::from_account_info(witness)?); + Ok(self) } } -impl<'a, 'b> TrieAccount> { +impl<'a, 'info> TrieAccount<'a, RefMut<'a, &'info mut [u8]>> { /// Creates a new TrieAccount from data in an account specified by given /// info. /// @@ -43,7 +68,7 @@ impl<'a, 'b> TrieAccount> { /// Created TrieAccount holds exclusive reference on the account’s data thus /// no other code can access it while this object is alive. pub fn from_account_info( - account: &'a AccountInfo<'b>, + account: &'a AccountInfo<'info>, owner: &Pubkey, ) -> Result { check_account(account, owner)?; @@ -52,7 +77,7 @@ impl<'a, 'b> TrieAccount> { } } -impl<'a, 'b> TrieAccount> { +impl<'a, 'info> TrieAccount<'a, ResizableAccount<'a, 'info>> { /// Creates a new TrieAccount from data in an account specified by given /// info. /// @@ -64,9 +89,9 @@ impl<'a, 'b> TrieAccount> { /// If the account needs to increase in size, `payer`’s account is used to /// transfer lamports necessary to keep the account rent-exempt. pub fn from_account_with_payer( - account: &'a AccountInfo<'b>, + account: &'a AccountInfo<'info>, owner: &Pubkey, - payer: &'a AccountInfo<'b>, + payer: &'a AccountInfo<'info>, ) -> Result { check_account(account, owner)?; let data = ResizableAccount::new(account, payer)?; @@ -90,13 +115,22 @@ fn check_account( } } -impl core::ops::Drop for TrieAccount { +impl<'a, D: DataRef + Sized> core::ops::Drop for TrieAccount<'a, D> { /// Updates the header in the Solana account. fn drop(&mut self) { // SAFETY: Once we’re done with self.0 we are dropped and no one else is // going to have access to self.0. - let trie = unsafe { ManuallyDrop::take(&mut self.0) }; + let Inner { trie, witness } = + unsafe { ManuallyDrop::take(&mut self.0) }; let (mut alloc, root_ptr, root_hash) = trie.into_parts(); + + // Update witness + if let Some(mut witness) = witness { + let clock = solana_program::clock::Clock::get().unwrap(); + *witness = witness::Data::new(root_hash, &clock); + } + + // Update header let hdr = header::Header { root_ptr, root_hash, @@ -108,16 +142,28 @@ impl core::ops::Drop for TrieAccount { } } -impl core::ops::Deref for TrieAccount { +impl<'a, D: DataRef> core::ops::Deref for TrieAccount<'a, D> { type Target = sealable_trie::Trie>; - fn deref(&self) -> &Self::Target { &self.0 } + fn deref(&self) -> &Self::Target { &self.0.trie } } -impl core::ops::DerefMut for TrieAccount { - fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } +impl<'a, D: DataRef> core::ops::DerefMut for TrieAccount<'a, D> { + fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0.trie } } +impl core::fmt::Debug for TrieAccount<'_, D> { + fn fmt(&self, fmtr: &mut core::fmt::Formatter) -> core::fmt::Result { + let mut fmtr = fmtr.debug_struct("TrieAccount"); + fmtr.field("trie", &self.0.trie); + if let Some(witness) = self.0.witness.as_ref() { + let root: &witness::Data = witness; + fmtr.field("witness", root); + } + fmtr.finish() + } +} + #[test] fn test_trie_sanity() { const ONE: lib::hash::CryptoHash = lib::hash::CryptoHash([1; 32]); @@ -142,12 +188,12 @@ fn test_trie_sanity() { assert_eq!(Ok(None), trie.get(&[0])); assert_eq!(Ok(()), trie.set(&[0], &ONE)); - assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); + assert_eq!(Ok(Some(ONE)), trie.get(&[0])); } { let mut trie = TrieAccount::new(account.data.borrow_mut()).unwrap(); - assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); + assert_eq!(Ok(Some(ONE)), trie.get(&[0])); assert_eq!(Ok(()), trie.seal(&[0])); assert_eq!(Err(sealable_trie::Error::Sealed), trie.get(&[0])); @@ -163,7 +209,7 @@ fn test_trie_resize() { let mut trie = TrieAccount::new(&mut data).unwrap(); assert_eq!(Ok(None), trie.get(&[0])); assert_eq!(Ok(()), trie.set(&[0], &ONE)); - assert_eq!(Ok(Some(ONE.clone())), trie.get(&[0])); + assert_eq!(Ok(Some(ONE)), trie.get(&[0])); } #[rustfmt::skip] assert_eq!([ diff --git a/solana/trie/src/witness.rs b/solana/trie/src/witness.rs new file mode 100644 index 00000000..253045c1 --- /dev/null +++ b/solana/trie/src/witness.rs @@ -0,0 +1,135 @@ +use core::cell::RefMut; + +use lib::hash::CryptoHash; +use solana_program::account_info::AccountInfo; +use solana_program::program_error::ProgramError; + +/// Encoding of the data in witness account. +#[derive(Clone, Copy, Debug, bytemuck::Pod, bytemuck::Zeroable)] +#[repr(C)] +pub struct Data { + /// The root of the sealable trie. + pub trie_root: CryptoHash, + + /// Rest of the witness account encoding Solana block timestamp. + /// + /// The timestamp is encoded using only six bytes. The seventh byte is + /// a single byte of a slot number and the last byte is always zero. + /// + /// Single byte of slot is included so that data of the account changes for + /// every slot even if two slots are created at the same second. + /// + /// The last byte is zero for potential future use. + rest: [u8; 8], +} + +impl Data { + /// Size of the witness account data. + pub const SIZE: usize = core::mem::size_of::(); + + /// Formats new witness account data with timestamp and slot number taken + /// from Solana clock. + pub fn new( + trie_root: CryptoHash, + clock: &solana_program::clock::Clock, + ) -> Self { + let mut rest = clock.unix_timestamp.to_le_bytes(); + rest[6] = clock.slot as u8; + rest[7] = 0; + Self { trie_root, rest } + } + + /// Returns root of the saleable trie and Solana block timestamp in seconds. + /// + /// Returns `Err` if the account data is malformed. The error holds + /// reference to the full data of the account. This happens if the last + /// byte of the data is non-zero. + pub fn decode(&self) -> Result<(&CryptoHash, u64), &[u8; Data::SIZE]> { + if self.rest[7] != 0 { + return Err(bytemuck::cast_ref(self)); + } + let timestamp = u64::from_le_bytes(self.rest) & 0xffff_ffff_ffff; + Ok((&self.trie_root, timestamp)) + } + + /// Creates a new borrowed reference to the data held in given account. + /// + /// Checks that the account is mutable and exactly [`Data::SIZE`] bytes. If + /// so, updates the timestamp and slot of the account and returns reference + /// to the trie’s root held inside of the account. + pub(crate) fn from_account_info<'a>( + witness: &'a AccountInfo<'_>, + ) -> Result, ProgramError> { + RefMut::filter_map(witness.try_borrow_mut_data()?, |data| { + let data: &mut [u8] = data; + <&mut Data>::try_from(data).ok() + }) + .map_err(|_| ProgramError::InvalidAccountData) + } +} + + + +impl From<[u8; Data::SIZE]> for Data { + fn from(bytes: [u8; Data::SIZE]) -> Self { bytemuck::cast(bytes) } +} + +impl<'a> From<&'a [u8; Data::SIZE]> for &'a Data { + fn from(bytes: &'a [u8; Data::SIZE]) -> Self { bytemuck::cast_ref(bytes) } +} + +impl<'a> From<&'a [u8; Data::SIZE]> for Data { + fn from(bytes: &'a [u8; Data::SIZE]) -> Self { *bytemuck::cast_ref(bytes) } +} + +impl<'a> TryFrom<&'a [u8]> for &'a Data { + type Error = core::array::TryFromSliceError; + + fn try_from(bytes: &'a [u8]) -> Result { + <&[u8; Data::SIZE]>::try_from(bytes).map(Self::from) + } +} + +impl<'a> TryFrom<&'a [u8]> for Data { + type Error = core::array::TryFromSliceError; + + fn try_from(bytes: &'a [u8]) -> Result { + <&[u8; Data::SIZE]>::try_from(bytes).map(Data::from) + } +} + +impl<'a> From<&'a mut [u8; Data::SIZE]> for &'a mut Data { + fn from(bytes: &'a mut [u8; Data::SIZE]) -> Self { + bytemuck::cast_mut(bytes) + } +} + +impl<'a> TryFrom<&'a mut [u8]> for &'a mut Data { + type Error = core::array::TryFromSliceError; + + fn try_from(bytes: &'a mut [u8]) -> Result { + <&mut [u8; Data::SIZE]>::try_from(bytes).map(Self::from) + } +} + + +impl From for [u8; Data::SIZE] { + fn from(data: Data) -> Self { bytemuck::cast(data) } +} + +impl<'a> From<&'a Data> for &'a [u8; Data::SIZE] { + fn from(bytes: &'a Data) -> Self { bytes.as_ref() } +} + +impl<'a> From<&'a mut Data> for &'a mut [u8; Data::SIZE] { + fn from(bytes: &'a mut Data) -> Self { bytes.as_mut() } +} + + +impl AsRef<[u8; Data::SIZE]> for Data { + fn as_ref(&self) -> &[u8; Data::SIZE] { bytemuck::cast_ref(self) } +} + +impl AsMut<[u8; Data::SIZE]> for Data { + fn as_mut(&mut self) -> &mut [u8; Data::SIZE] { bytemuck::cast_mut(self) } +} diff --git a/solana/witnessed-trie/Cargo.toml b/solana/witnessed-trie/Cargo.toml index cf723cb2..f1c98bde 100644 --- a/solana/witnessed-trie/Cargo.toml +++ b/solana/witnessed-trie/Cargo.toml @@ -21,7 +21,7 @@ cf-solana = { workspace = true, optional = true } lib.workspace = true memory = { workspace = true, optional = true } sealable-trie = { workspace = true, optional = true } -solana-trie = { workspace = true, optional = true } +solana-trie.workspace = true stdx.workspace = true [dev-dependencies] @@ -45,5 +45,4 @@ contract = [ "hex", "memory", "sealable-trie", - "solana-trie", ] diff --git a/solana/witnessed-trie/src/api.rs b/solana/witnessed-trie/src/api.rs index d8fce1bb..408492e5 100644 --- a/solana/witnessed-trie/src/api.rs +++ b/solana/witnessed-trie/src/api.rs @@ -2,6 +2,7 @@ use lib::hash::CryptoHash; use solana_program::pubkey::{Pubkey, MAX_SEED_LEN}; #[cfg(all(not(feature = "api"), feature = "api2"))] use solana_program_2 as solana_program; +pub use solana_trie::witness::Data as WitnessData; use crate::utils; @@ -133,7 +134,7 @@ impl<'a> Op<'a> { /// Converts `self` to [`OwnedOp`] by allocating buffers an heap. pub fn to_owned(&self) -> OwnedOp { match self { - Self::Set(key, hash) => OwnedOp::Set(key.to_vec(), (*hash).clone()), + Self::Set(key, hash) => OwnedOp::Set(key.to_vec(), *(*hash)), Self::Del(key) => OwnedOp::Del(key.to_vec()), Self::Seal(key) => OwnedOp::Seal(key.to_vec()), } @@ -220,66 +221,6 @@ impl From for ParseError { } -/// Encoding of the data in witness account. -#[derive(Clone, Copy, bytemuck::Zeroable, bytemuck::Pod)] -#[repr(C)] -pub struct WitnessedData { - /// The root of the sealable trie. - trie_root: [u8; 32], - - /// Rest of the witness account encoding Solana block timestamp. - /// - /// The timestamp is encoded using only six bytes. The seventh byte is - /// a single byte of a slot number and the last byte is always zero. - /// - /// Single byte of slot is included so that data of the account changes for - /// every slot even if two slots are created at the same second. - /// - /// The last byte is zero for potential future use. - rest: [u8; 8], -} - -impl WitnessedData { - /// Formats new witness account data with timestamp and slot number taken - /// from Solana clock. - pub fn new( - trie_root: &CryptoHash, - clock: &solana_program::clock::Clock, - ) -> Self { - let mut rest = clock.unix_timestamp.to_le_bytes(); - rest[6] = clock.slot as u8; - rest[7] = 0; - Self { trie_root: trie_root.into(), rest } - } - - /// Returns root of the saleable trie and Solana block timestamp in seconds. - /// - /// Returns `Err` if the account data is malformed. The error holds - /// reference to the full data of the account. This happens if the last - /// byte of the data is non-zero. - pub fn decode(&self) -> Result<(&CryptoHash, u64), &[u8; 40]> { - if self.rest[7] != 0 { - return Err(bytemuck::cast_ref(self)); - } - let timestamp = u64::from_le_bytes(self.rest) & 0xffff_ffff_ffff; - Ok(((&self.trie_root).into(), timestamp)) - } -} - -impl From<[u8; 40]> for WitnessedData { - fn from(bytes: [u8; 40]) -> Self { bytemuck::cast(bytes) } -} - -impl From for [u8; 40] { - fn from(data: WitnessedData) -> Self { bytemuck::cast(data) } -} - -impl AsRef<[u8; 40]> for WitnessedData { - fn as_ref(&self) -> &[u8; 40] { bytemuck::cast_ref(self) } -} - - - /// Value returned from the contract in return data. /// /// It holds information about the witness account needed to compute its hash @@ -300,7 +241,7 @@ pub struct ReturnData { pub lamports: [u8; 8], pub rent_epoch: [u8; 8], #[deref] - pub data: WitnessedData, + pub data: WitnessData, } impl ReturnData { @@ -346,7 +287,7 @@ fn test_hash_account() { solana_program::pubkey!("ENEWG4MWwJQUfJxDgqarJQ1bf2P4fADsCYsPCjvLRaa2"); const OWNER: Pubkey = solana_program::pubkey!("4FjVmuvPYnE1fqBtvjGh5JF7QDwUmyBZ5wv1uygHvTey"); - const DATA: [u8; 40] = [ + const DATA: [u8; WitnessData::SIZE] = [ 0xa9, 0x1e, 0x26, 0xed, 0x91, 0x28, 0xdd, 0x6f, 0xed, 0xa2, 0xe8, 0x6a, 0xf7, 0x9b, 0xe2, 0xe1, 0x77, 0x89, 0xaf, 0x08, 0x72, 0x08, 0x69, 0x22, 0x13, 0xd3, 0x95, 0x5e, 0x07, 0x4c, 0xee, 0x9c, 1, 2, 3, 4, 5, 6, 7, 8, diff --git a/solana/witnessed-trie/src/contract.rs b/solana/witnessed-trie/src/contract.rs index 42616062..06d22229 100644 --- a/solana/witnessed-trie/src/contract.rs +++ b/solana/witnessed-trie/src/contract.rs @@ -1,7 +1,6 @@ use solana_program::account_info::AccountInfo; use solana_program::program_error::ProgramError; use solana_program::pubkey::Pubkey; -use solana_program::sysvar::Sysvar; use crate::{accounts, api, utils}; @@ -40,6 +39,7 @@ pub(crate) fn process_instruction( ) -> Result { let data = api::Data::from_slice(instruction)?; + // Get the accounts (trie root and witness) let (mut trie, witness) = { let accounts = &mut accounts.iter(); let payer = accounts::get_payer(accounts)?; @@ -52,7 +52,8 @@ pub(crate) fn process_instruction( )?; let witness = accounts::get_witness(payer, accounts, program_id, root)?; let trie = solana_trie::TrieAccount::new(root.try_borrow_mut_data()?) - .ok_or(ProgramError::InvalidAccountData)?; + .ok_or(ProgramError::InvalidAccountData)? + .with_witness_account(witness, program_id)?; (trie, witness) }; @@ -70,22 +71,15 @@ pub(crate) fn process_instruction( })?; } - // Update witness - let clock = solana_program::clock::Clock::get()?; - let data = api::WitnessedData::new(trie.hash(), &clock); - - { - let mut dst = witness.try_borrow_mut_data()?; - let dst: &mut [u8] = &mut dst; - let dst: &mut [u8; 40] = dst.try_into().unwrap(); - *dst = data.into(); - } + // Drop the trie so that witness is updated. + core::mem::drop(trie); // Return enough information so that witness account can be hashed. let ret = api::ReturnData { lamports: witness.lamports().to_le_bytes(), rent_epoch: witness.rent_epoch.to_le_bytes(), - data, + data: api::WitnessData::try_from(&**witness.try_borrow_data()?) + .unwrap(), }; solana_program::program::set_return_data(bytemuck::bytes_of(&ret));