diff --git a/Cargo.lock b/Cargo.lock index 98fc7d051..2562ecfbe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -929,6 +929,18 @@ dependencies = [ "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethbloom" +version = "0.8.1" +source = "git+https://github.com/paritytech/parity-common.git#92ec1826884281820ebbbfc428e6c0fbdcccb9bf" +dependencies = [ + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.5.1 (git+https://github.com/paritytech/parity-common.git)", + "impl-rlp 0.2.1 (git+https://github.com/paritytech/parity-common.git)", + "impl-serde 0.2.3 (git+https://github.com/paritytech/parity-common.git)", + "tiny-keccak 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethbloom" version = "0.8.1" @@ -1051,6 +1063,17 @@ dependencies = [ "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fixed-hash" +version = "0.5.1" +source = "git+https://github.com/paritytech/parity-common.git#92ec1826884281820ebbbfc428e6c0fbdcccb9bf" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fixed-hash" version = "0.5.1" @@ -1634,6 +1657,14 @@ dependencies = [ "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "impl-rlp" +version = "0.2.1" +source = "git+https://github.com/paritytech/parity-common.git#92ec1826884281820ebbbfc428e6c0fbdcccb9bf" +dependencies = [ + "rlp 0.4.4 (git+https://github.com/paritytech/parity-common.git)", +] + [[package]] name = "impl-rlp" version = "0.2.1" @@ -1642,6 +1673,14 @@ dependencies = [ "rlp 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "impl-serde" +version = "0.2.3" +source = "git+https://github.com/paritytech/parity-common.git#92ec1826884281820ebbbfc428e6c0fbdcccb9bf" +dependencies = [ + "serde 1.0.102 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "impl-serde" version = "0.2.3" @@ -3714,6 +3753,14 @@ dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rlp" +version = "0.4.4" +source = "git+https://github.com/paritytech/parity-common.git#92ec1826884281820ebbbfc428e6c0fbdcccb9bf" +dependencies = [ + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rlp_derive" version = "0.1.0" @@ -4128,6 +4175,8 @@ dependencies = [ name = "sr-eth-primitives" version = "0.1.0" dependencies = [ + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethbloom 0.8.1 (git+https://github.com/paritytech/parity-common.git)", "ethbloom 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4138,6 +4187,7 @@ dependencies = [ "keccak-hasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-crypto 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "primitive-types 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rlp_derive 0.1.0 (git+https://github.com/paritytech/parity-ethereum.git)", "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4146,6 +4196,7 @@ dependencies = [ "sr-std 2.0.0 (git+https://github.com/darwinia-network/substrate.git?branch=darwinia-develop)", "srml-support 2.0.0 (git+https://github.com/darwinia-network/substrate.git?branch=darwinia-develop)", "substrate-primitives 2.0.0 (git+https://github.com/darwinia-network/substrate.git?branch=darwinia-develop)", + "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "triehash-ethereum 0.2.0 (git+https://github.com/paritytech/parity-ethereum.git)", ] @@ -6010,6 +6061,14 @@ dependencies = [ "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tiny-keccak" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "tokio" version = "0.1.22" @@ -6320,7 +6379,7 @@ name = "twox-hash" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6938,6 +6997,7 @@ dependencies = [ "checksum erased-serde 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3beee4bc16478a1b26f2e80ad819a52d24745e292f521a63c16eea5f74b7eb60" "checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "checksum ethbloom 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a6294da962646baa738414e8e718d1a1f0360a51d92de89ccbf91870418f5360" +"checksum ethbloom 0.8.1 (git+https://github.com/paritytech/parity-common.git)" = "" "checksum ethbloom 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "32cfe1c169414b709cf28aa30c74060bdb830a03a8ba473314d079ac79d80a5f" "checksum ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e742184dc63a01c8ea0637369f8faa27c40f537949908a237f95c05e68d2c96" "checksum ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba744248e3553a393143d5ebb68939fc3a4ec0c22a269682535f5ffe7fed728c" @@ -6950,6 +7010,7 @@ dependencies = [ "checksum finality-grandpa 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "34754852da8d86bc509715292c73140a5b678656d0b16132acd6737bdb5fd5f8" "checksum fixed-hash 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7afe6ce860afb14422711595a7b26ada9ed7de2f43c0b2ab79d09ee196287273" "checksum fixed-hash 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "516877b7b9a1cc2d0293cbce23cd6203f0edbfd4090e6ca4489fecb5aa73050e" +"checksum fixed-hash 0.5.1 (git+https://github.com/paritytech/parity-common.git)" = "" "checksum fixed-hash 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72fe7539e2c5692c6989f2f9c0457e42f1e5768f96b85c87d273574670ae459f" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd6d6f4752952feb71363cffc9ebac9411b75b87c6ab6058c40c8900cf43c0f" @@ -7013,7 +7074,9 @@ dependencies = [ "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" "checksum impl-codec 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1be51a921b067b0eaca2fad532d9400041561aa922221cc65f95a85641c6bf53" +"checksum impl-rlp 0.2.1 (git+https://github.com/paritytech/parity-common.git)" = "" "checksum impl-rlp 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8f7a72f11830b52333f36e3b09a288333888bf54380fd0ac0790a3c31ab0f3c5" +"checksum impl-serde 0.2.3 (git+https://github.com/paritytech/parity-common.git)" = "" "checksum impl-serde 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "58e3cae7e99c7ff5a995da2cf78dd0a5383740eda71d98cf7b1910c301ac69b8" "checksum impl-trait-for-tuples 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ef5550a42e3740a0e71f909d4c861056a284060af885ae7aa6242820f920d9d" "checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" @@ -7194,6 +7257,7 @@ dependencies = [ "checksum ring 0.16.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6747f8da1f2b1fabbee1aaa4eb8a11abf9adef0bf58a41cee45db5d59cecdfac" "checksum ripemd160 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad5112e0dbbb87577bfbc56c42450235e3012ce336e29c5befd7807bd626da4a" "checksum rlp 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8376a3f725ebb53f69263bbebb42196361fdfd551212409c8a721239aab4f09f" +"checksum rlp 0.4.4 (git+https://github.com/paritytech/parity-common.git)" = "" "checksum rlp_derive 0.1.0 (git+https://github.com/paritytech/parity-ethereum.git)" = "" "checksum rocksdb 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f1651697fefd273bfb4fd69466cc2a9d20de557a0213b97233b22b5e95924b5e" "checksum rpassword 4.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f072d931f11a96546efd97642e1e75e807345aced86b947f9239102f262d0fcd" @@ -7366,6 +7430,7 @@ dependencies = [ "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tiny-bip39 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c5676413eaeb1ea35300a0224416f57abc3bd251657e0fafc12c47ff98c060" "checksum tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8a021c69bb74a44ccedb824a046447e2c84a01df9e5c20779750acb38e11b2" +"checksum tiny-keccak 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2953ca5148619bc99695c1274cb54c5275bbb913c6adad87e72eaf8db9787f69" "checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" "checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46" "checksum tokio-codec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5c501eceaf96f0e1793cf26beb63da3d11c738c4a943fdf3746d81d64684c39f" diff --git a/core/sr-eth-primitives/Cargo.toml b/core/sr-eth-primitives/Cargo.toml index 0c9ffce50..f3509a790 100644 --- a/core/sr-eth-primitives/Cargo.toml +++ b/core/sr-eth-primitives/Cargo.toml @@ -8,6 +8,7 @@ edition = "2018" [dependencies] +tiny-keccak = { version = "1.5", features = ["keccak"] } serde = { version = "1.0.101", optional = true, features = ["derive"] } codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] } rstd = { package = "sr-std", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop", default-features = false } @@ -16,13 +17,15 @@ substrate-primitives = {git = "https://github.com/darwinia-network/substrate.git rlp = { version = "0.4.3", optional = true } parity-crypto = { version = "0.4.2", features = ["publickey"] } rlp_derive = { git = "https://github.com/paritytech/parity-ethereum.git", default-features = false } +primitive-types = { version = "0.6.0", default-feature = false, features = ["codec", "rlp"] } ethereum-types = { version = "0.8.0", default-feature = false, features = ["serialize"] } keccak-hash = "0.4.0" ethbloom = { version = "0.8", default-features = false, features = ["serialize"] } impl-codec = { version = "0.4", default-features = false, optional = true } fixed-hash = { version = "0.4", default-features = false} impl-rlp = { version = "0.2", default-features = false, optional = true } - +hbloom = { package = 'ethbloom', git ="https://github.com/paritytech/parity-common.git", default-features = false} +crunchy = { version = "0.2.2", default-features = false, features = ["limit_256"] } [dev-dependencies] support = { package = "srml-support", git = "https://github.com/darwinia-network/substrate.git", branch = "darwinia-develop"} @@ -42,14 +45,20 @@ std = [ "substrate-primitives/std", "rlp/std", "keccak-hash/std", - "ethereum-types/std", + "primitive-types/std", + "primitive-types/serde", + "primitive-types/byteorder", + "primitive-types/rustc-hex", + "primitive-types/libc", "parity-crypto/publickey", - "ethereum-types/std", - "ethereum-types/serialize", "ethbloom/std", "ethbloom/serialize", + "ethereum-types/std", "impl-codec/std", "fixed-hash/std", - "impl-rlp/std" + "impl-rlp/std", + "hbloom/std", + "hbloom/serialize", + "crunchy/std", ] diff --git a/core/sr-eth-primitives/src/error.rs b/core/sr-eth-primitives/src/error.rs index 82894edc0..699912059 100644 --- a/core/sr-eth-primitives/src/error.rs +++ b/core/sr-eth-primitives/src/error.rs @@ -2,7 +2,7 @@ use super::*; #[cfg(feature = "std")] use std::error::Error; -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Encode, Decode)] /// Error indicating value found is outside of a valid range. pub struct OutOfBounds { /// Minimum allowed value. @@ -13,7 +13,7 @@ pub struct OutOfBounds { pub found: T, } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Encode, Decode)] /// Error indicating an expected value was not found. pub struct Mismatch { /// Value expected. diff --git a/core/sr-eth-primitives/src/lib.rs b/core/sr-eth-primitives/src/lib.rs index 3ae15ba4d..d2f56d727 100644 --- a/core/sr-eth-primitives/src/lib.rs +++ b/core/sr-eth-primitives/src/lib.rs @@ -17,109 +17,26 @@ pub mod keccak; pub mod pow; pub mod receipt; pub mod transaction; +pub mod types; pub use codec::{Decode, Encode}; -pub use ethereum_types::{Address, BigEndianHash, Bloom, BloomInput, H160, H256, H64, U128, U256, U512}; +pub use ethereum_types::BigEndianHash; +pub use impl_codec::impl_fixed_hash_codec; pub use keccak_hash::keccak; +pub use primitive_types::{H160, H256, U128, U256, U512}; pub use rlp::{self, DecoderError, Encodable, Rlp, RlpStream}; pub type Bytes = Vec; - +pub type Address = H160; pub type BlockNumber = u64; -pub struct BestBLock { + +#[derive(Clone, Copy, Eq, PartialEq, Encode, Decode)] +pub struct BestBlock { height: u64, // enough for ethereum poa network (kovan) hash: H256, total_difficulty: U256, } -// TODO: later rewrite Bloom to impl Encode and Decode -//pub use ethbloom::{BloomRef, Input}; -// -//// 3 according to yellowpaper -//const BLOOM_BITS: u32 = 3; -//const BLOOM_SIZE: usize = 256; -// -//construct_fixed_hash! {pub struct Bloom(BLOOM_SIZE);} -//impl_fixed_hash_rlp!(Bloom, BLOOM_SIZE); -//impl_fixed_hash_codec!(Bloom, BLOOM_SIZE); -// -//impl<'a> From> for Bloom { -// fn from(input: Input<'a>) -> Bloom { -// let mut bloom = Bloom::default(); -// bloom.accrue(input); -// bloom -// } -//} -// -//impl Bloom { -// pub fn is_empty(&self) -> bool { -// self.0.iter().all(|x| *x == 0) -// } -// -// pub fn contains_input(&self, input: Input<'_>) -> bool { -// let bloom: Bloom = input.into(); -// self.contains_bloom(&bloom) -// } -// -// pub fn contains_bloom<'a, B>(&self, bloom: B) -> bool -// where -// BloomRef<'a>: From, -// { -// let bloom_ref: BloomRef = bloom.into(); -// // workaround for https://github.com/rust-lang/rust/issues/43644 -// self.contains_bloom_ref(bloom_ref) -// } -// -// fn contains_bloom_ref(&self, bloom: BloomRef) -> bool { -// let self_ref: BloomRef = self.into(); -// self_ref.contains_bloom(bloom) -// } -// -// pub fn accrue(&mut self, input: Input<'_>) { -// let p = BLOOM_BITS; -// -// 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: Hash = input.into(); -// -// // must be a power of 2 -// assert_eq!(m & (m - 1), 0); -// // out of range -// assert!(p * bloom_bytes <= hash.len() as u32); -// -// let mut ptr = 0; -// -// assert_eq!(BLOOM_BITS, 3); -// unroll! { -// for i in 0..3 { -// let _ = i; -// let mut index = 0 as usize; -// 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); -// } -// } -// } -// -// pub fn accrue_bloom<'a, B>(&mut self, bloom: B) -// where -// BloomRef<'a>: From, -// { -// let bloom_ref: BloomRef = bloom.into(); -// assert_eq!(self.0.len(), BLOOM_SIZE); -// assert_eq!(bloom_ref.0.len(), BLOOM_SIZE); -// for i in 0..BLOOM_SIZE { -// self.0[i] |= bloom_ref.0[i]; -// } -// } -// -// pub fn data(&self) -> &[u8; BLOOM_SIZE] { -// &self.0 -// } -//} +construct_fixed_hash! {pub struct H64(8);} +impl_fixed_hash_rlp!(H64, 8); +impl_fixed_hash_codec!(H64, 8); diff --git a/core/sr-eth-primitives/src/pow.rs b/core/sr-eth-primitives/src/pow.rs index d1e8d3d26..6e583fa73 100644 --- a/core/sr-eth-primitives/src/pow.rs +++ b/core/sr-eth-primitives/src/pow.rs @@ -9,12 +9,13 @@ use rstd::collections::btree_map::BTreeMap; use rstd::mem; use rstd::result; use sr_primitives::traits::Saturating; +use types::Bloom; pub const MINIMUM_DIFFICULTY: u128 = 131072; // TODO: please keep an eye on this. // it might change due to ethereum's upgrade pub const PROGPOW_TRANSITION: u64 = u64::max_value(); -pub const DIFFICULTY_HARDFORK_TRANSITION: u64 = 23001; +//pub const DIFFICULTY_HARDFORK_TRANSITION: u64 = 0x59d9; pub const DIFFICULTY_HARDFORK_BOUND_DIVISOR: u128 = 0x0200; pub const DIFFICULTY_BOUND_DIVISOR: u128 = 0x0800; pub const EXPIP2_TRANSITION: u64 = 0xc3500; @@ -24,11 +25,16 @@ pub const HOMESTEAD_TRANSITION: u64 = 0x30d40; pub const EIP100B_TRANSITION: u64 = 0xC3500; pub const DIFFICULTY_INCREMENT_DIVISOR: u64 = 0x3C; pub const METROPOLIS_DIFFICULTY_INCREMENT_DIVISOR: u64 = 0x1E; + pub const BOMB_DEFUSE_TRANSITION: u64 = 0x30d40; -pub const ECIP1010_PAUSE_TRANSITION: u64 = 3000000; -pub const ECIP1010_CONTINUE_TRANSITION: u64 = 5000000; +// 3,000,000 +pub const ECIP1010_PAUSE_TRANSITION: u64 = 0x2dc6c0; +// 5,000,000 +pub const ECIP1010_CONTINUE_TRANSITION: u64 = 0x4c4b40; + +pub const DIFFICULTY_HARDFORK_TRANSITION: u64 = u64::max_value(); -#[derive(Default, PartialEq, Eq, Clone)] +#[derive(Default, PartialEq, Eq, Clone, Encode, Decode)] pub struct EthHeader { parent_hash: H256, timestamp: u64, @@ -57,7 +63,7 @@ where } } -#[derive(Clone, Copy)] +#[derive(PartialEq, Eq, Clone, Encode, Decode, Copy)] enum Seal { /// The seal/signature is included. With, @@ -65,7 +71,7 @@ enum Seal { Without, } -#[derive(PartialEq)] +#[derive(PartialEq, Eq, Clone, Encode, Decode)] pub struct EthashSeal { /// Ethash seal mix_hash pub mix_hash: H256, @@ -426,12 +432,12 @@ mod tests { let mixh2 = H256::from(hex!("0ea8027f96c18f474e9bc74ff71d29aacd3f485d5825be0a8dde529eb82a47ed")); let nonce2 = H64::from(hex!("55859dc00728f99a")); let header2 = EthHeader { - parent_hash: H256::from(hex!("0b2d720b8d3b6601e4207ef926b0c228735aa1d58301a23d58f9cb51ac2288d8")), + parent_hash: H256::from(hex!("b80bf91d6f459227a9c617c5d9823ff0b07f1098ea16788676f0b804ecd42f3b")), timestamp: 0x5ddb67a3, number: 0x8947aa, author: Address::from(hex!("d224ca0c819e8e97ba0136b3b95ceff503b79f53")), transactions_root: H256::from(hex!("efebac0e71cc2de04cf2f509bb038a82bbe92a659e010061b49b5387323b5ea6")), - uncles_hash: H256::from(hex!("b80bf91d6f459227a9c617c5d9823ff0b07f1098ea16788676f0b804ecd42f3b")), + uncles_hash: H256::from(hex!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347")), extra_data: "7575706f6f6c2e636e2d3163613037623939".from_hex().unwrap(), state_root: H256::from(hex!("5dfc6357dda61a7f927292509afacd51453ff158342eb9628ccb419fbe91c638")), receipts_root: H256::from(hex!("3fbd99e253ff45045eec1e0011ac1b45fa0bccd641a356727defee3b166dd3bf")), diff --git a/core/sr-eth-primitives/src/receipt.rs b/core/sr-eth-primitives/src/receipt.rs index 82cdc2d6c..4d55d8a6b 100644 --- a/core/sr-eth-primitives/src/receipt.rs +++ b/core/sr-eth-primitives/src/receipt.rs @@ -4,8 +4,9 @@ use rlp::{self, Decodable, DecoderError, Encodable, Rlp, RlpStream}; use rstd::ops::Deref; use rstd::prelude::*; use substrate_primitives::RuntimeDebug; +use types::{Bloom, Input as BloomInput}; -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug)] +#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode)] pub enum TransactionOutcome { /// Status and state root are unknown under EIP-98 rules. Unknown, @@ -15,7 +16,7 @@ pub enum TransactionOutcome { StatusCode(u8), } -#[derive(PartialEq, Eq, Clone, Encode, Decode, RuntimeDebug, RlpEncodable, RlpDecodable)] +#[derive(PartialEq, Eq, Clone, RuntimeDebug, RlpEncodable, RlpDecodable, Encode, Decode)] pub struct LogEntry { /// The address of the contract executing at the point of the `LOG` operation. pub address: Address, @@ -38,7 +39,7 @@ impl LogEntry { } // TODO: impl Bloom with codec::Encode and codec::Decode -#[derive(PartialEq, Eq, Clone, RuntimeDebug)] +#[derive(PartialEq, Eq, Clone, RuntimeDebug, Encode, Decode)] pub struct Receipt { /// The total gas used in the block following execution of the transaction. pub gas_used: U256, @@ -115,7 +116,8 @@ impl Decodable for Receipt { #[cfg(test)] mod tests { - use super::{Address, Bloom, LogEntry, Receipt, TransactionOutcome, H256, U128, U256}; + use super::{Address, LogEntry, Receipt, TransactionOutcome, H256, U128, U256}; + use ethbloom::Bloom; use hex_literal::*; use rustc_hex::FromHex; use std::str::FromStr; diff --git a/core/sr-eth-primitives/src/types.rs b/core/sr-eth-primitives/src/types.rs new file mode 100644 index 000000000..36c9329d0 --- /dev/null +++ b/core/sr-eth-primitives/src/types.rs @@ -0,0 +1,258 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use core::{mem, ops}; + +use crunchy::unroll; +use fixed_hash::*; +use impl_rlp::impl_fixed_hash_rlp; +#[cfg(feature = "serialize")] +use impl_serde::impl_fixed_hash_serde; +use tiny_keccak::keccak256; + +// 3 according to yellowpaper +const BLOOM_BITS: u32 = 3; +const BLOOM_SIZE: usize = 256; + +construct_fixed_hash! { + /// Bloom hash type with 256 bytes (2048 bits) size. + pub struct Bloom(BLOOM_SIZE); +} +impl_fixed_hash_rlp!(Bloom, BLOOM_SIZE); +impl_fixed_hash_codec!(Bloom, BLOOM_SIZE); + +/// Returns log2. +fn log2(x: usize) -> u32 { + if x <= 1 { + return 0; + } + + let n = x.leading_zeros(); + mem::size_of::() as u32 * 8 - n +} + +pub enum Input<'a> { + Raw(&'a [u8]), + Hash(&'a [u8; 32]), +} + +enum Hash<'a> { + Ref(&'a [u8; 32]), + Owned([u8; 32]), +} + +impl<'a> From> for Hash<'a> { + fn from(input: Input<'a>) -> Self { + match input { + Input::Raw(raw) => Hash::Owned(keccak256(raw)), + Input::Hash(hash) => Hash::Ref(hash), + } + } +} + +impl<'a> ops::Index for Hash<'a> { + type Output = u8; + + fn index(&self, index: usize) -> &u8 { + match *self { + Hash::Ref(r) => &r[index], + Hash::Owned(ref hash) => &hash[index], + } + } +} + +impl<'a> Hash<'a> { + fn len(&self) -> usize { + match *self { + Hash::Ref(r) => r.len(), + Hash::Owned(ref hash) => hash.len(), + } + } +} + +impl<'a> PartialEq> for Bloom { + fn eq(&self, other: &BloomRef<'a>) -> bool { + let s_ref: &[u8] = &self.0; + let o_ref: &[u8] = other.0; + s_ref.eq(o_ref) + } +} + +impl<'a> From> for Bloom { + fn from(input: Input<'a>) -> Bloom { + let mut bloom = Bloom::default(); + bloom.accrue(input); + bloom + } +} + +impl Bloom { + pub fn is_empty(&self) -> bool { + self.0.iter().all(|x| *x == 0) + } + + pub fn contains_input(&self, input: Input<'_>) -> bool { + let bloom: Bloom = input.into(); + self.contains_bloom(&bloom) + } + + pub fn contains_bloom<'a, B>(&self, bloom: B) -> bool + where + BloomRef<'a>: From, + { + let bloom_ref: BloomRef = bloom.into(); + // workaround for https://github.com/rust-lang/rust/issues/43644 + self.contains_bloom_ref(bloom_ref) + } + + fn contains_bloom_ref(&self, bloom: BloomRef) -> bool { + let self_ref: BloomRef = self.into(); + self_ref.contains_bloom(bloom) + } + + pub fn accrue(&mut self, input: Input<'_>) { + let p = BLOOM_BITS; + + 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: Hash = input.into(); + + // must be a power of 2 + assert_eq!(m & (m - 1), 0); + // out of range + assert!(p * bloom_bytes <= hash.len() as u32); + + let mut ptr = 0; + + assert_eq!(BLOOM_BITS, 3); + unroll! { + for i in 0..3 { + let _ = i; + let mut index = 0 as usize; + 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); + } + } + } + + pub fn accrue_bloom<'a, B>(&mut self, bloom: B) + where + BloomRef<'a>: From, + { + let bloom_ref: BloomRef = bloom.into(); + assert_eq!(self.0.len(), BLOOM_SIZE); + assert_eq!(bloom_ref.0.len(), BLOOM_SIZE); + for i in 0..BLOOM_SIZE { + self.0[i] |= bloom_ref.0[i]; + } + } + + pub fn data(&self) -> &[u8; BLOOM_SIZE] { + &self.0 + } +} + +#[derive(Clone, Copy)] +pub struct BloomRef<'a>(&'a [u8; BLOOM_SIZE]); + +impl<'a> BloomRef<'a> { + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn is_empty(&self) -> bool { + self.0.iter().all(|x| *x == 0) + } + + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn contains_input(&self, input: Input<'_>) -> bool { + let bloom: Bloom = input.into(); + self.contains_bloom(&bloom) + } + + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn contains_bloom<'b, B>(&self, bloom: B) -> bool + where + BloomRef<'b>: From, + { + let bloom_ref: BloomRef = bloom.into(); + assert_eq!(self.0.len(), BLOOM_SIZE); + assert_eq!(bloom_ref.0.len(), BLOOM_SIZE); + for i in 0..BLOOM_SIZE { + let a = self.0[i]; + let b = bloom_ref.0[i]; + if (a & b) != b { + return false; + } + } + true + } + + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn data(&self) -> &'a [u8; BLOOM_SIZE] { + self.0 + } +} + +impl<'a> From<&'a [u8; BLOOM_SIZE]> for BloomRef<'a> { + fn from(data: &'a [u8; BLOOM_SIZE]) -> Self { + BloomRef(data) + } +} + +impl<'a> From<&'a Bloom> for BloomRef<'a> { + fn from(bloom: &'a Bloom) -> Self { + BloomRef(&bloom.0) + } +} + +#[cfg(feature = "serialize")] +impl_fixed_hash_serde!(Bloom, BLOOM_SIZE); + +#[cfg(test)] +mod tests { + use super::{Bloom, Input}; + use core::str::FromStr; + use hex_literal::hex; + + #[test] + fn it_works() { + let bloom = Bloom::from_str( + "00000000000000000000000000000000\ + 00000000100000000000000000000000\ + 00000000000000000000000000000000\ + 00000000000000000000000000000000\ + 00000000000000000000000000000000\ + 00000000000000000000000000000000\ + 00000002020000000000000000000000\ + 00000000000000000000000800000000\ + 10000000000000000000000000000000\ + 00000000000000000000001000000000\ + 00000000000000000000000000000000\ + 00000000000000000000000000000000\ + 00000000000000000000000000000000\ + 00000000000000000000000000000000\ + 00000000000000000000000000000000\ + 00000000000000000000000000000000", + ) + .unwrap(); + let address = hex!("ef2d6d194084c2de36e0dabfce45d046b37d1106"); + let topic = hex!("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc"); + + let mut my_bloom = Bloom::default(); + assert!(!my_bloom.contains_input(Input::Raw(&address))); + assert!(!my_bloom.contains_input(Input::Raw(&topic))); + + my_bloom.accrue(Input::Raw(&address)); + assert!(my_bloom.contains_input(Input::Raw(&address))); + assert!(!my_bloom.contains_input(Input::Raw(&topic))); + + my_bloom.accrue(Input::Raw(&topic)); + assert!(my_bloom.contains_input(Input::Raw(&address))); + assert!(my_bloom.contains_input(Input::Raw(&topic))); + assert_eq!(my_bloom, bloom); + } +}