Skip to content

Commit

Permalink
Update contract id to use celestia specs BMT (#48)
Browse files Browse the repository at this point in the history
Closes #49
  • Loading branch information
vlopes11 authored Nov 18, 2021
1 parent bfbc669 commit 9cf8183
Show file tree
Hide file tree
Showing 11 changed files with 31 additions and 93 deletions.
1 change: 1 addition & 0 deletions .github/workflows/cargo_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
with:
ssh-private-key: |
${{ secrets.PRIVATE_KEY_FUEL_ASM }}
${{ secrets.PRIVATE_KEY_FUEL_MERKLE }}
${{ secrets.PRIVATE_KEY_FUEL_STORAGE }}
${{ secrets.PRIVATE_KEY_FUEL_TX }}
${{ secrets.PRIVATE_KEY_FUEL_TYPES }}
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ description = "FuelVM interpreter."

[dependencies]
fuel-asm = { git = "ssh://[email protected]/FuelLabs/fuel-asm.git" }
fuel-merkle = { git = "ssh://[email protected]/FuelLabs/fuel-merkle.git" }
fuel-storage = { git = "ssh://[email protected]/FuelLabs/fuel-storage.git" }
fuel-tx = { git = "ssh://[email protected]/FuelLabs/fuel-tx.git" }
fuel-types = { git = "ssh://[email protected]/FuelLabs/fuel-types.git" }
Expand Down
1 change: 0 additions & 1 deletion src/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::contract::Contract;
use fuel_types::bytes::{self, SizedBytes};
use fuel_types::{Color, ContractId, Word};

use std::convert::TryFrom;
use std::io::{self, Write};
use std::mem;

Expand Down
1 change: 0 additions & 1 deletion src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use fuel_tx::{Transaction, ValidationError};
use fuel_types::{Bytes32, ContractId, Salt};

use std::cmp;
use std::convert::TryFrom;

#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde-types", derive(serde::Serialize, serde::Deserialize))]
Expand Down
112 changes: 29 additions & 83 deletions src/crypto.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use fuel_tx::crypto::Hasher;
use fuel_merkle::binary::MerkleTree;
use fuel_merkle::common::StorageMap;
use fuel_types::{Bytes32, Bytes64};
use secp256k1::recovery::{RecoverableSignature, RecoveryId};
use secp256k1::Error as Secp256k1Error;
use secp256k1::{Message, Secp256k1, SecretKey};

use std::convert::TryFrom;
use std::mem;

/// Sign a given message and compress the `v` to the signature
///
/// The compression scheme is described in
Expand Down Expand Up @@ -47,60 +45,21 @@ pub fn secp256k1_sign_compact_recover(signature: &[u8], message: &[u8]) -> Resul
Ok(pk)
}

/// Calculate a binary merkle root
///
/// The space complexity of this operation is O(n). This means it expects small
/// sets. For bigger sets (e.g. blockchain state), use a storage backed merkle
/// implementation
/// Calculate a binary merkle root with in-memory storage
pub fn ephemeral_merkle_root<L, I>(mut leaves: I) -> Bytes32
where
L: AsRef<[u8]>,
I: Iterator<Item = L> + ExactSizeIterator,
{
let mut hasher = Hasher::default();
let mut width = leaves.len().next_power_of_two();
let mut len = leaves.len() as f32;

if width <= 2 {
return leaves.collect::<Hasher>().digest();
}

width /= 2;
len /= 2.0;

let mut current = vec![Bytes32::default(); width];

// Drain the leaves
current.iter_mut().for_each(|l| {
hasher.reset();

leaves.next().map(|a| hasher.input(a));
leaves.next().map(|b| hasher.input(b));

*l = hasher.digest();
});

let mut next = current.clone();

// Cheap loop with no realloc
while width > 1 {
mem::swap(&mut current, &mut next);

let mut c = current.iter().take(len.ceil() as usize);

width /= 2;
len /= 2.0;
next.iter_mut().take(width).for_each(|n| {
hasher.reset();

c.next().map(|a| hasher.input(a));
c.next().map(|b| hasher.input(b));

*n = hasher.digest();
});
}

next[0]
let mut storage = StorageMap::new();
let mut tree = MerkleTree::new(&mut storage);

// TODO fuel-merkle should have infallible in-memory struct
leaves
.try_for_each(|l| tree.push(l.as_ref()))
.and_then(|_| tree.root())
.expect("In-memory impl should be infallible")
.into()
}

#[cfg(all(test, feature = "random"))]
Expand All @@ -113,8 +72,6 @@ mod tests {
use rand::{Rng, RngCore, SeedableRng};
use secp256k1::PublicKey;

use std::convert::TryFrom;

#[test]
fn ecrecover() {
let secp = Secp256k1::new();
Expand Down Expand Up @@ -145,7 +102,12 @@ mod tests {
fn ephemeral_merkle_root_works() {
let mut rng = StdRng::seed_from_u64(2322u64);

const LEAF_PREFIX: u8 = 0x00;
const NODE_PREFIX: u8 = 0x01;

// Test for 0 leaves
//
// Expected root is `h()`
let empty: Vec<Address> = vec![];

let root = ephemeral_merkle_root(empty.iter());
Expand All @@ -162,38 +124,22 @@ mod tests {

let initial = [a, b, c, d, e];

let a = [a, b].iter().collect::<Hasher>().digest();
let b = [c, d].iter().collect::<Hasher>().digest();
let c = [e].iter().collect::<Hasher>().digest();
let a = Hasher::default().chain(&[LEAF_PREFIX]).chain(a).digest();
let b = Hasher::default().chain(&[LEAF_PREFIX]).chain(b).digest();
let c = Hasher::default().chain(&[LEAF_PREFIX]).chain(c).digest();
let d = Hasher::default().chain(&[LEAF_PREFIX]).chain(d).digest();
let e = Hasher::default().chain(&[LEAF_PREFIX]).chain(e).digest();

let a = Hasher::default().chain(&[NODE_PREFIX]).extend_chain([a, b]).digest();
let b = Hasher::default().chain(&[NODE_PREFIX]).extend_chain([c, d]).digest();
let c = e;

let a = [a, b].iter().collect::<Hasher>().digest();
let b = [c].iter().collect::<Hasher>().digest();
let a = Hasher::default().chain(&[NODE_PREFIX]).extend_chain([a, b]).digest();
let b = c;

let root = [a, b].iter().collect::<Hasher>().digest();
let root = Hasher::default().chain(&[NODE_PREFIX]).extend_chain([a, b]).digest();
let root_p = ephemeral_merkle_root(initial.iter());

assert_eq!(root, root_p);

// Test for n leaves
let mut inputs = vec![Address::default(); 64];

inputs.iter_mut().for_each(|i| *i = rng.gen());

(0..65).into_iter().for_each(|w| {
let initial: Vec<&Address> = inputs.iter().take(w).collect();
let mut level: Vec<Bytes32> = initial
.chunks(2)
.map(|c| c.iter().collect::<Hasher>().digest())
.collect();

while level.len() > 1 {
level = level.chunks(2).map(|c| c.iter().collect::<Hasher>().digest()).collect();
}

let root = level.first().copied().unwrap_or(empty);
let root_p = ephemeral_merkle_root(initial.iter());

assert_eq!(root, root_p);
});
}
}
2 changes: 0 additions & 2 deletions src/interpreter/executors/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ use fuel_tx::{Input, Output, Receipt, Transaction};
use fuel_types::bytes::SerializableVec;
use fuel_types::Word;

use std::convert::TryFrom;

impl<S> Interpreter<S>
where
S: InterpreterStorage,
Expand Down
1 change: 0 additions & 1 deletion src/interpreter/flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ use fuel_types::bytes::SerializableVec;
use fuel_types::{Bytes32, Color, RegisterId, Word};

use std::cmp;
use std::convert::TryFrom;

impl<S> Interpreter<S>
where
Expand Down
1 change: 0 additions & 1 deletion src/interpreter/internal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use fuel_tx::consts::*;
use fuel_tx::Transaction;
use fuel_types::{Bytes32, Color, ContractId, RegisterId, Word};

use std::convert::TryFrom;
use std::mem;

const WORD_SIZE: usize = mem::size_of::<Word>();
Expand Down
1 change: 0 additions & 1 deletion src/interpreter/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::error::InterpreterError;

use fuel_types::{RegisterId, Word};

use std::convert::TryFrom;
use std::{ops, ptr};

// Memory bounds must be manually checked and cannot follow general PartialEq
Expand Down
2 changes: 0 additions & 2 deletions src/interpreter/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use crate::error::InterpreterError;

use fuel_types::{Immediate18, RegisterId, Word};

use std::convert::TryFrom;

const IS_CALLER_EXTERNAL: Immediate18 = 0x000001;
const GET_CALLER: Immediate18 = 0x000002;

Expand Down
1 change: 0 additions & 1 deletion tests/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use fuel_vm::consts::*;
use fuel_vm::crypto;
use fuel_vm::prelude::*;

use std::convert::TryFrom;
use std::str::FromStr;

#[test]
Expand Down

0 comments on commit 9cf8183

Please sign in to comment.