Skip to content

Commit

Permalink
cf-solana: drop Hash type
Browse files Browse the repository at this point in the history
Replace types::Hash type with lib::hash::CryptoHash.  Turns out, lack
of conversion between it and solana_program’s Hash types isn’t a big
deal at all.  And with CryptoHash now being bytemuck::Pod and Zeroable
there’s no longer need for this custom type.  Replace its uses with
CryptoHash.
  • Loading branch information
mina86 committed Sep 1, 2024
1 parent 84ee045 commit ba8f826
Show file tree
Hide file tree
Showing 12 changed files with 78 additions and 262 deletions.
4 changes: 1 addition & 3 deletions common/cf-guest/src/client/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,7 @@ impl TestContext {
this
}

fn genesis_hash(&self) -> CryptoHash {
self.client_state.genesis_hash
}
fn genesis_hash(&self) -> CryptoHash { self.client_state.genesis_hash }

fn generate_next(
&self,
Expand Down
6 changes: 1 addition & 5 deletions common/cf-guest/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,11 +372,7 @@ mod tests {
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,
}
IbcProof { proof: buf, root: hdr.calc_hash(), value: proof.value }
}

fn generate(
Expand Down
24 changes: 10 additions & 14 deletions common/cf-solana/src/blake3.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
pub use ::blake3::Hasher;

use crate::types::Hash;
use lib::hash::CryptoHash;

/// Calculates Blake3 hash of given byte slice.
///
/// 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.
#[allow(dead_code)]
pub fn hash(bytes: &[u8]) -> Hash {
pub fn hash(bytes: &[u8]) -> CryptoHash {
if cfg!(target_os = "solana-program") &&
(cfg!(feature = "solana-program") ||
cfg!(feature = "solana-program-2"))
{
hashv(&[bytes])
} else {
Hash(::blake3::hash(bytes).into())
CryptoHash(::blake3::hash(bytes).into())
}
}

Expand All @@ -25,22 +24,19 @@ pub fn hash(bytes: &[u8]) -> Hash {
/// program, this is using Solana’s `sol_blake3` syscall. Otherwise, the
/// calculation is done by `blake3` crate.
#[allow(dead_code)]
pub fn hashv(slices: &[&[u8]]) -> Hash {
pub fn hashv(slices: &[&[u8]]) -> CryptoHash {
#[cfg(all(target_os = "solana-program", feature = "solana-program-2"))]
return Hash(solana_program_2::blake3::hashv(slices).0);
return CryptoHash(solana_program_2::blake3::hashv(slices).0);
#[cfg(all(
target_os = "solana-program",
feature = "solana-program",
not(feature = "solana-program-2")
))]
return Hash(solana_program::blake3::hashv(slices).0);
return CryptoHash(solana_program::blake3::hashv(slices).0);

#[allow(dead_code)]
{
let mut hasher = Hasher::default();
for bytes in slices {
hasher.update(bytes);
}
hasher.finalize().into()
let mut hasher = Hasher::default();
for bytes in slices {
hasher.update(bytes);
}
CryptoHash(hasher.finalize().into())
}
4 changes: 1 addition & 3 deletions common/cf-solana/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,7 @@ impl TryFrom<&crate::Header> for ConsensusState {

fn try_from(header: &crate::Header) -> Result<Self, Self::Error> {
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),
)
}
}
Expand Down
7 changes: 4 additions & 3 deletions common/cf-solana/src/header.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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,
Expand All @@ -39,7 +40,7 @@ impl Header {
// 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)> {
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);
Expand Down
79 changes: 33 additions & 46 deletions common/cf-solana/src/proof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -48,7 +48,7 @@ pub struct MerkleProof {
path: MerklePath,

/// Sibling hashes at each level concatenated into a single vector.
siblings: Vec<Hash>,
siblings: Vec<CryptoHash>,
}

/// Iterator over levels stored in a Merkle proof.
Expand All @@ -61,7 +61,7 @@ pub struct MerkleProof {
/// the node itself.
pub struct ProofLevels<'a> {
path: &'a [u8],
siblings: &'a [Hash],
siblings: &'a [CryptoHash],
}


Expand All @@ -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 =
Expand All @@ -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);
Expand All @@ -100,7 +100,7 @@ impl MerkleProof {
for hash in tail {
hasher.update(hash.as_ref());
}
hash = hasher.build().into();
hash = hasher.build();
}
hash
}
Expand All @@ -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);
Expand Down Expand Up @@ -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 {
Expand All @@ -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<Self::Item> {
let ((index, len), path_tail) = match self.path.split_first() {
Expand Down Expand Up @@ -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 }))
}
Expand All @@ -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())
}

Expand Down Expand Up @@ -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,
Expand All @@ -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())
}
}
Expand All @@ -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.
///
Expand All @@ -382,12 +382,12 @@ pub struct DeltaHashProof {
feature = "serde",
serde(skip_serializing_if = "Option::is_none", default)
)]
pub epoch_accounts_hash: Option<Hash>,
pub epoch_accounts_hash: Option<CryptoHash>,
}

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(&[
Expand All @@ -402,7 +402,6 @@ impl DeltaHashProof {
}
None => hash,
}
.into()
}

/// Serialises the object into a binary format.
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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.
Expand All @@ -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<Hash> = lib::par::chunks(accounts, MERKLE_FANOUT)
fn compute_merkle_root(accounts: &mut [(PubKey, CryptoHash)]) -> CryptoHash {
let mut hashes: Vec<CryptoHash> = 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();

Expand All @@ -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);
Expand All @@ -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<Hash> =
let mut current_hashes: Vec<CryptoHash> =
accounts.iter().map(|&(_pubkey, hash)| hash).collect();
while current_hashes.len() > 1 {
let chunk_index = pos / MERKLE_FANOUT;
Expand All @@ -593,14 +592,14 @@ fn generate_merkle_proof(
proof
}

fn compute_hashes_at_next_level(hashes: &[Hash]) -> Vec<Hash> {
fn compute_hashes_at_next_level(hashes: &[CryptoHash]) -> Vec<CryptoHash> {
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()
}
Expand All @@ -610,21 +609,9 @@ fn compute_hashes_at_next_level(hashes: &[Hash]) -> Vec<Hash> {
// ========== 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)
}
}

Expand Down
Loading

0 comments on commit ba8f826

Please sign in to comment.