Skip to content

Commit

Permalink
Feat: core hashchain logic
Browse files Browse the repository at this point in the history
  • Loading branch information
birchmd committed Aug 8, 2023
1 parent 2e1f1a0 commit 5774e0d
Show file tree
Hide file tree
Showing 9 changed files with 997 additions and 0 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.0-
evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.0-aurora", default-features = false, features = ["std"] }
evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.0-aurora", default-features = false, features = ["std", "tracing"] }
evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.0-aurora", default-features = false, features = ["std", "tracing"] }
fixed-hash = { version = "0.8.0", default-features = false}
git2 = "0.17"
hex = { version = "0.4", default-features = false, features = ["alloc"] }
ibig = { version = "0.3", default-features = false, features = ["num-traits"] }
impl-serde = { version = "0.4.0", default-features = false}
lazy_static = "1"
libsecp256k1 = { version = "0.7", default-features = false }
near-crypto = "0.17"
Expand Down Expand Up @@ -71,6 +73,7 @@ workspaces = "0.7"
resolver = "2"
members = [
"engine",
"engine-hashchain",
"engine-test-doubles",
"engine-modexp",
"engine-precompiles",
Expand Down
22 changes: 22 additions & 0 deletions engine-hashchain/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "aurora-engine-hashchain"
version = "1.0.0"
authors.workspace = true
edition.workspace = true
readme.workspace = true
homepage.workspace = true
repository.workspace = true
license.workspace = true
publish.workspace = true
autobenches = false

[dependencies]
aurora-engine-types.workspace = true
aurora-engine-sdk.workspace = true
fixed-hash.workspace = true
impl-serde.workspace = true

[features]
default = ["std"]
std = ["aurora-engine-types/std", "aurora-engine-sdk/std", "fixed-hash/std", "impl-serde/std"]
borsh-compat = ["aurora-engine-types/borsh-compat", "aurora-engine-sdk/borsh-compat"]
86 changes: 86 additions & 0 deletions engine-hashchain/src/bloom.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//! Based on Parity Common Eth Bloom implementation
//! Link: <https://github.com/paritytech/parity-common/blob/master/ethbloom/src/lib.rs>
//!
//! Reimplemented here since there is a large mismatch in types and dependencies.
#![allow(clippy::expl_impl_clone_on_copy)]

use aurora_engine_sdk::keccak;
use aurora_engine_types::borsh::{self, BorshDeserialize, BorshSerialize};
use aurora_engine_types::parameters::engine::ResultLog;
use fixed_hash::construct_fixed_hash;
use impl_serde::impl_fixed_hash_serde;

const BLOOM_SIZE: usize = 256;
const BLOOM_BITS: u32 = 3;

construct_fixed_hash! {
/// Bloom hash type with 256 bytes (2048 bits) size.
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Bloom(BLOOM_SIZE);
}

impl_fixed_hash_serde!(Bloom, BLOOM_SIZE);

/// Returns log2.
const fn log2(x: usize) -> u32 {
if x <= 1 {
return 0;
}

let n = x.leading_zeros();
usize::BITS - n
}

impl Bloom {
/// Add a new element to the bloom filter
#[allow(clippy::as_conversions)]
pub fn accrue(&mut self, input: &[u8]) {
let m = self.0.len();
let bloom_bits = m * 8;
let mask = bloom_bits - 1;
let bloom_bytes = (log2(bloom_bits) + 7) / 8;
let hash = keccak(input);
let mut ptr = 0;

for i in 0..BLOOM_BITS {
let _ = i;
let mut index = 0;
for _ in 0..bloom_bytes {
index = (index << 8) | hash[ptr] as usize;
ptr += 1;
}
index &= mask;
self.0[m - 1 - index / 8] |= 1 << (index % 8);
}
}

/// Merge two bloom filters
pub fn accrue_bloom(&mut self, bloom: &Self) {
for i in 0..BLOOM_SIZE {
self.0[i] |= bloom.0[i];
}
}
}

#[must_use]
pub fn get_logs_bloom(logs: &[ResultLog]) -> Bloom {
let mut logs_bloom = Bloom::default();

for log in logs {
logs_bloom.accrue_bloom(&get_log_bloom(log));
}

logs_bloom
}

#[must_use]
pub fn get_log_bloom(log: &ResultLog) -> Bloom {
let mut log_bloom = Bloom::default();

log_bloom.accrue(log.address.as_bytes());
for topic in &log.topics {
log_bloom.accrue(&topic[..]);
}

log_bloom
}
33 changes: 33 additions & 0 deletions engine-hashchain/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
pub const ERR_STATE_NOT_FOUND: &[u8; 19] = b"ERR_STATE_NOT_FOUND";
pub const ERR_STATE_SERIALIZATION_FAILED: &[u8; 26] = b"ERR_STATE_SERIALIZE_FAILED";
pub const ERR_STATE_CORRUPTED: &[u8; 19] = b"ERR_STATE_CORRUPTED";
pub const ERR_BLOCK_HEIGHT_INCORRECT: &[u8; 26] = b"ERR_BLOCK_HEIGHT_INCORRECT";
pub const ERR_REQUIRES_FEATURE_INTEGRATION_TEST: &[u8; 37] =
b"ERR_REQUIRES_FEATURE_INTEGRATION_TEST";

#[derive(Debug)]
/// Blockchain Hashchain Error
pub enum BlockchainHashchainError {
/// The state is missing from storage, need to initialize with contract `new` method.
NotFound,
/// The state serialized had failed.
SerializationFailed,
/// The state is corrupted, possibly due to failed state migration.
DeserializationFailed,
/// The block height is incorrect regarding the current block height.
BlockHeightIncorrect,
/// Some functionality requires integration-test feature.
RequiresFeatureIntegrationTest,
}

impl AsRef<[u8]> for BlockchainHashchainError {
fn as_ref(&self) -> &[u8] {
match self {
Self::NotFound => ERR_STATE_NOT_FOUND,
Self::SerializationFailed => ERR_STATE_SERIALIZATION_FAILED,
Self::DeserializationFailed => ERR_STATE_CORRUPTED,
Self::BlockHeightIncorrect => ERR_BLOCK_HEIGHT_INCORRECT,
Self::RequiresFeatureIntegrationTest => ERR_REQUIRES_FEATURE_INTEGRATION_TEST,
}
}
}
Loading

0 comments on commit 5774e0d

Please sign in to comment.