diff --git a/Cargo.lock b/Cargo.lock index 0942802c35..f4aa819900 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -230,6 +230,18 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "auto_impl" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a8c1df849285fbacd587de7818cc7d13be6cd2cbcd47a04fb1801b0e2706e33" +dependencies = [ + "proc-macro-error", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 1.0.109", +] + [[package]] name = "autocfg" version = "0.1.8" @@ -678,12 +690,6 @@ dependencies = [ "iovec", ] -[[package]] -name = "bytes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0dcbc35f504eb6fc275a6d20e4ebcda18cf50d40ba6fabff8c711fa16cb3b16" - [[package]] name = "bytes" version = "1.4.0" @@ -1899,7 +1905,7 @@ name = "evm" version = "0.35.0" source = "git+https://github.com/velas/evm?tag=v0.35-with-traces#90a980bb9d7ccbb21b2897e71b889847f7beeade" dependencies = [ - "auto_impl", + "auto_impl 0.5.0", "environmental", "ethereum", "evm-core", @@ -2046,7 +2052,7 @@ name = "evm-runtime" version = "0.35.0" source = "git+https://github.com/velas/evm?tag=v0.35-with-traces#90a980bb9d7ccbb21b2897e71b889847f7beeade" dependencies = [ - "auto_impl", + "auto_impl 0.5.0", "environmental", "evm-core", "primitive-types 0.11.1", @@ -2061,14 +2067,16 @@ dependencies = [ "auto_enums", "bincode", "borsh", - "bytes 0.6.0", + "bytes 1.4.0", "criterion", "dashmap 4.0.2", "derivative", "derive_more", + "etcommon-hexutil", "ethabi", "ethbloom 0.11.1", "evm", + "fastrlp", "fixed-hash 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex", "impl-rlp 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2142,6 +2150,32 @@ dependencies = [ "instant", ] +[[package]] +name = "fastrlp" +version = "0.3.0" +source = "git+https://github.com/velas/fastrlp?tag=second_release_candidate#7a967beb99c5627b90013a3ba0b4b74577797bc4" +dependencies = [ + "arrayvec 0.7.2", + "auto_impl 1.0.1", + "bytes 1.4.0", + "ethbloom 0.11.1", + "ethereum", + "fastrlp-derive", + "primitive-types 0.11.1", + "thiserror", +] + +[[package]] +name = "fastrlp-derive" +version = "0.2.0" +source = "git+https://github.com/velas/fastrlp?tag=second_release_candidate#7a967beb99c5627b90013a3ba0b4b74577797bc4" +dependencies = [ + "bytes 1.4.0", + "proc-macro2 1.0.56", + "quote 1.0.26", + "syn 2.0.15", +] + [[package]] name = "fd-lock" version = "3.0.6" @@ -5461,9 +5495,9 @@ dependencies = [ [[package]] name = "scale-info" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cfdffd972d76b22f3d7f81c8be34b2296afd3a25e0a547bd9abe340a4dbbe97" +checksum = "dfdef77228a4c05dc94211441595746732131ad7f6530c6c18f045da7b7ab937" dependencies = [ "bitvec 1.0.1", "cfg-if 1.0.0", @@ -5474,9 +5508,9 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61fa974aea2d63dd18a4ec3a49d59af9f34178c73a4f56d2f18205628d00681e" +checksum = "53012eae69e5aa5c14671942a5dd47de59d4cdcff8532a6dd0e081faf1119482" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2 1.0.56", @@ -7359,7 +7393,6 @@ dependencies = [ "primitive-types 0.8.0", "prost 0.11.9", "rangemap", - "rlp", "rocksdb", "serde", "serde_json", @@ -7761,6 +7794,7 @@ dependencies = [ "solana-sdk", "solana-transaction-status", "tonic-build 0.8.4", + "triedb", ] [[package]] @@ -9105,13 +9139,16 @@ checksum = "0de5f738ceab88e2491a94ddc33c3feeadfa95fedc60363ef110845df12f3878" [[package]] name = "triedb" version = "0.5.0" -source = "git+https://github.com/velas/triedb?tag=rocksdb-v0.20.1-orth#48ad76f5c1491234840676d2721cc5287462f3d3" +source = "git+https://github.com/velas/triedb?tag=fast_rlp#a0019f6073a081bc9f177b4b7fb41362fb5d6649" dependencies = [ "anyhow", + "backtrace", "bincode", + "bytes 1.4.0", "dashmap 4.0.2", "derivative", "etcommon-hexutil", + "fastrlp", "log 0.4.17", "primitive-types 0.11.1", "rayon", diff --git a/evm-utils/evm-state/Cargo.toml b/evm-utils/evm-state/Cargo.toml index a621fd0da7..bcbc70d45d 100644 --- a/evm-utils/evm-state/Cargo.toml +++ b/evm-utils/evm-state/Cargo.toml @@ -12,7 +12,7 @@ rand2 = { version = "=0.6.1", package = "rand" } rocksdb = { package = "rocksdb", version = "0.20.1", default-features = false } # rocksdb = { version = "0.16.0", default-features = false } -triedb = { git = "https://github.com/velas/triedb", tag = "rocksdb-v0.20.1-orth", features = ["rocksdb"] } +triedb = { git = "https://github.com/velas/triedb", tag = "fast_rlp", features = ["rocksdb"] } # triedb = { path = "../../../triedb", features = ["rocksdb"] } primitive-types = { version = "0.11.0", features = ["borsh"] } @@ -20,16 +20,18 @@ keccak-hash = "0.9.0" log = "0.4.11" simple_logger = "2.2" hex = "0.4.2" +etcommon-hexutil = "0.2.4" serde = "1.0" sha3 = "0.9.1" rand = "0.8.3" rlp = "0.5.0" +fastrlp = { git = "https://github.com/velas/fastrlp", tag="second_release_candidate", features = ["derive", "handle-thiserror"] } thiserror = "1.0.22" anyhow = "1.0.34" bincode = "1.3.1" borsh = "0.9.3" lazy_static = "1.4.0" -bytes = "0.6.0" +bytes = "1" snafu = "0.7" derive_more = "0.99.11" tempfile = "3.1.0" diff --git a/evm-utils/evm-state/src/lib.rs b/evm-utils/evm-state/src/lib.rs index b9f895dfd8..b078b77bf9 100644 --- a/evm-utils/evm-state/src/lib.rs +++ b/evm-utils/evm-state/src/lib.rs @@ -18,6 +18,8 @@ pub use ethbloom::Bloom; pub use traces::*; pub use transactions::*; pub use types::*; +#[cfg(test)] +mod rlp_roundtrip_tests; pub use { context::{ChainContext, EvmConfig}, diff --git a/evm-utils/evm-state/src/rlp_roundtrip_tests.rs b/evm-utils/evm-state/src/rlp_roundtrip_tests.rs new file mode 100644 index 0000000000..c3160f38f9 --- /dev/null +++ b/evm-utils/evm-state/src/rlp_roundtrip_tests.rs @@ -0,0 +1,497 @@ +use std::convert::TryInto; + +use crate::{transaction_roots::EthereumReceipt, TransactionAction, UnsignedTransaction, UnsignedTransactionWithCaller, Transaction, TransactionSignature, TransactionInReceipt}; + +use super::types::Account; + +use ethbloom::Bloom; +use evm::backend::Log; +use keccak_hash::H256; +use primitive_types::{U256, H160}; +use rlp::{Decodable as DecodableOld, DecoderError as OldDecoderError, Rlp}; + +use triedb::rlp::{Encodable, Decodable, DecoderError}; + +fn decode_old(bytes: &[u8]) -> Result { + + ::decode(&Rlp::new(bytes)) +} + + pub fn decode<'a, T: Decodable<'a>>(mut val: &'a [u8]) -> Result { + Decodable::decode(&mut val) +} + +pub use rlp::encode as encode_old; + +pub fn encode(val: &V) -> Vec { + let mut vec_buffer = Vec::with_capacity(val.length()); + val.encode(&mut vec_buffer); + vec_buffer +} + +macro_rules! check_roundtrip { + ($v: expr => $type: ty) => {{ + let old_rlp_raw: Vec; + let rlp_raw; + { + old_rlp_raw = encode_old(&$v).to_vec(); + dbg!(hexutil::to_hex(&old_rlp_raw)); + let decoded_node: $type = decode_old(&old_rlp_raw).unwrap(); + assert_eq!(decoded_node, $v); + } + { + rlp_raw = encode(&$v); + dbg!(hexutil::to_hex(&rlp_raw)); + let decoded_node: $type = decode(&rlp_raw).unwrap(); + assert_eq!(decoded_node, $v); + } + + { + assert_eq!(old_rlp_raw, rlp_raw); + } + }}; +} + +#[test] +fn test_check_account_roundtrip() { + let acc = Account { + nonce: U256([27;4]), + balance: U256([24;4]), + storage_root: H256([7; 32]), + code_hash: H256([2; 32]), + + }; + + check_roundtrip!(acc => Account); + let acc = Account { + nonce: U256([21;4]), + balance: U256([23;4]), + storage_root: H256([8; 32]), + code_hash: H256([123; 32]), + + }; + + check_roundtrip!(acc => Account); + +} + +#[test] +fn test_check_log_roundtrip() { + let acc = Log { + address: H160([23; 20]), + topics: vec![H256([37; 32]), H256([173;32]), H256([21; 32])], + data: vec![0, 123, 12, 17, 19, 244], + + }; + + check_roundtrip!(acc => Log); + let acc = Log { + address: H160([23; 20]), + topics: vec![], + data: vec![], + + }; + + check_roundtrip!(acc => Log); + +} +#[test] +fn test_check_bloom_roundtrip() { + let mut acc = [10; 256]; + for i in 0..256 { + acc[i] = i as u8; + } + let bloomy = Bloom(acc); + + check_roundtrip!(bloomy => Bloom); +} + +#[test] +fn test_check_ethereum_receipt_roundtrip() { + let mut acc = [10; 256]; + for i in 0..256 { + acc[i] = i as u8; + } + let bloomy = Bloom(acc); + let mut h160_special = [0; 20]; + for i in 0..20 { + h160_special[i] = i as u8; + } + let log1 = Log { + address: H160(h160_special), + topics: vec![H256([37; 32]), H256([173;32]), H256([21; 32])], + data: vec![0, 123, 12, 17, 19, 244], + + }; + let log2 = Log { + address: H160([38; 20]), + topics: vec![H256([27; 32]), H256([173;32]), H256([24; 32])], + data: vec![0, 123, 12, 17, 111, 244], + + }; + + let receipt = EthereumReceipt { + log_bloom: bloomy, + logs: vec![log1, log2], + status: 7, + gas_used: U256([23;4]), + + }; + + check_roundtrip!(receipt => EthereumReceipt); +} + +#[test] +fn test_check_tranaaction_action_roundtrip() { + let ta1 = TransactionAction::Create; + + + check_roundtrip!(ta1 => TransactionAction); + + let ta2 = TransactionAction::Call(H160([56; 20])); + + check_roundtrip!(ta2 => TransactionAction); + +} + +#[test] +fn test_check_unsigned_transaction_roundtrip() { + let ta2 = TransactionAction::Call(H160([56; 20])); + + let ut2 = UnsignedTransaction { + nonce: U256([46;4]), + gas_price: U256([543; 4]), + gas_limit: U256([342;4]), + action: ta2, + value: U256([20000; 4]), + input: vec![34, 45, 12, 123, 243], + }; + + check_roundtrip!(ut2 => UnsignedTransaction); + let ta1 = TransactionAction::Create; + + let ut1 = UnsignedTransaction { + nonce: U256([46;4]), + gas_price: U256([543; 4]), + gas_limit: U256([342;4]), + action: ta1, + value: U256([23000;4]), + input: vec![34, 45, 12, 123, 243], + }; + check_roundtrip!(ut1 => UnsignedTransaction); + +} + +#[test] +fn test_check_unsigned_transaction_with_caller_roundtrip1() { + let ta = TransactionAction::Call(H160([56; 20])); + + let ut = UnsignedTransaction { + nonce: U256([46;4]), + gas_price: U256([543; 4]), + gas_limit: U256([342;4]), + action: ta, + value: U256([20000; 4]), + input: vec![34, 45, 12, 123, 243], + }; + + let ut_c = UnsignedTransactionWithCaller { + unsigned_tx: ut, + caller: H160([23; 20]), + chain_id: 24, + signed_compatible: true, + + }; + let old_rlp_raw: Vec; + let rlp_raw; + { + old_rlp_raw = encode_old(&ut_c).to_vec(); + dbg!(hexutil::to_hex(&old_rlp_raw)); + let rlp = Rlp::new(&old_rlp_raw); + let decoded_node: UnsignedTransactionWithCaller = UnsignedTransactionWithCaller::decode_old(&rlp, true).unwrap(); + assert_eq!(decoded_node, ut_c); + } + { + rlp_raw = encode(&ut_c); + dbg!(hexutil::to_hex(&rlp_raw)); + let decoded_node: UnsignedTransactionWithCaller = UnsignedTransactionWithCaller::decode(&mut rlp_raw.as_ref(), true).unwrap(); + assert_eq!(decoded_node, ut_c); + } + + { + assert_eq!(old_rlp_raw, rlp_raw); + } +} + +#[test] +fn test_check_unsigned_transaction_with_caller_roundtrip2() { + let ta = TransactionAction::Create; + + let ut = UnsignedTransaction { + nonce: U256([46;4]), + gas_price: U256([543; 4]), + gas_limit: U256([342;4]), + action: ta, + value: U256([23000;4]), + input: vec![34, 45, 12, 123, 243], + }; + + let ut_c = UnsignedTransactionWithCaller { + unsigned_tx: ut, + caller: H160([23; 20]), + chain_id: 24, + signed_compatible: false, + + }; + let old_rlp_raw: Vec; + let rlp_raw; + { + old_rlp_raw = encode_old(&ut_c).to_vec(); + dbg!(hexutil::to_hex(&old_rlp_raw)); + let rlp = Rlp::new(&old_rlp_raw); + let decoded_node: UnsignedTransactionWithCaller = UnsignedTransactionWithCaller::decode_old(&rlp, false).unwrap(); + assert_eq!(decoded_node, ut_c); + } + { + rlp_raw = encode(&ut_c); + dbg!(hexutil::to_hex(&rlp_raw)); + let decoded_node: UnsignedTransactionWithCaller = UnsignedTransactionWithCaller::decode(&mut rlp_raw.as_ref(), false).unwrap(); + assert_eq!(decoded_node, ut_c); + } + + { + assert_eq!(old_rlp_raw, rlp_raw); + } +} + +#[test] +fn test_check_transaction_roundtrip() { + + let ta1 = TransactionAction::Create; + let tx1 = Transaction{ + nonce: U256([72; 4]), + gas_price: U256([3213;4]), + gas_limit: U256([4324; 4]), + action: ta1, + value: U256([7732; 4]), + signature: TransactionSignature { + v: 88979, + r: H256([34; 32]), + s: H256([78; 32]), + }, + input: vec![32, 31, 0, 34, 76, 173], + + }; + + check_roundtrip!(tx1 => Transaction); + + let ta2 = TransactionAction::Call(H160([56; 20])); + let tx2 = Transaction{ + nonce: U256([79; 4]), + gas_price: U256([3013;4]), + gas_limit: U256([4124; 4]), + action: ta2, + value: U256([7832; 4]), + signature: TransactionSignature { + v: 88979, + r: H256([38; 32]), + s: H256([76; 32]), + }, + input: vec![32, 31, 0, 34, 76, 173], + + }; + + check_roundtrip!(tx2 => Transaction); + +} + +#[test] +fn test_check_transaction_in_receipt_roundtrip1() { + + let ta = TransactionAction::Create; + let tx = Transaction{ + nonce: U256([72; 4]), + gas_price: U256([3213;4]), + gas_limit: U256([4324; 4]), + action: ta, + value: U256([7732; 4]), + signature: TransactionSignature { + v: 88979, + r: H256([34; 32]), + s: H256([78; 32]), + }, + input: vec![32, 31, 0, 34, 76, 173], + + }; + + let tx_in_rec1 = TransactionInReceipt::Signed(tx); + + check_roundtrip!(tx_in_rec1 => TransactionInReceipt); + +} + +#[test] +fn test_check_transaction_in_receipt_roundtrip2() { + let ta = TransactionAction::Create; + + let ut = UnsignedTransaction { + nonce: U256([46;4]), + gas_price: U256([543; 4]), + gas_limit: U256([342;4]), + action: ta, + value: U256([23000;4]), + input: vec![34, 45, 12, 123, 243], + }; + + let ut_c = UnsignedTransactionWithCaller { + unsigned_tx: ut, + caller: H160([23; 20]), + chain_id: 24, + signed_compatible: false, + + }; + + let tx_in_rec2 = TransactionInReceipt::Unsigned(ut_c); + + + check_roundtrip!(tx_in_rec2 => TransactionInReceipt); +} + +#[test] +fn test_check_transaction_in_receipt_roundtrip3() { + let ta2 = TransactionAction::Call(H160([56; 20])); + + let ut2 = UnsignedTransaction { + nonce: U256([46;4]), + gas_price: U256([543; 4]), + gas_limit: U256([342;4]), + action: ta2, + value: U256([20000; 4]), + input: vec![34, 45, 12, 123, 243], + }; + + let ut_c2 = UnsignedTransactionWithCaller { + unsigned_tx: ut2, + caller: H160([23; 20]), + chain_id: 24, + signed_compatible: true, + + }; + let tx_in_rec3 = TransactionInReceipt::Unsigned(ut_c2); + + check_roundtrip!(tx_in_rec3 => TransactionInReceipt); + +} + +#[test] +fn test_check_transaction_in_receipt_roundtrip4() { + + let ta = TransactionAction::Call(H160([10; 20])); + let tx = Transaction{ + nonce: U256([72; 4]), + gas_price: U256([3213;4]), + gas_limit: U256([4324; 4]), + action: ta, + value: U256([7732; 4]), + signature: TransactionSignature { + v: 88979, + r: H256([34; 32]), + s: H256([78; 32]), + }, + input: vec![32, 31, 0, 34, 76, 173], + + }; + + let tx_in_rec1 = TransactionInReceipt::Signed(tx); + + check_roundtrip!(tx_in_rec1 => TransactionInReceipt); + +} + +#[test] +fn test_check_unsigned_transaction_with_caller_tx_id_hash() { + let ta2 = TransactionAction::Call(H160([56; 20])); + + let ut2 = UnsignedTransaction { + nonce: U256([46;4]), + gas_price: U256([543; 4]), + gas_limit: U256([342;4]), + action: ta2, + value: U256([20000; 4]), + input: vec![34, 45, 12, 123, 243], + }; + + let ut_c2 = UnsignedTransactionWithCaller { + unsigned_tx: ut2, + caller: H160([23; 20]), + chain_id: 24, + signed_compatible: true, + + }; + + let old = ut_c2.tx_id_hash_old(); + let new = ut_c2.tx_id_hash(); + + assert_eq!(old, new); +} + + +#[test] +fn test_check_transaction_in_receipt_roundtrip5() { + let ta_inner = hexutil::read_hex("5c44f6325198ac3d4007727211040311e9e6a1f0").unwrap(); + let r_inner = hexutil::read_hex("ed30d3b0afdffef99887e8fcba2de50f3b390286ae2047588ceb1b989ae52dbd").unwrap(); + let s_inner = hexutil::read_hex("1aa5f7e761f7866ee87381e6e1d8efbcdb02daa7f752c3c0478854da0eafc170").unwrap(); + let ta = TransactionAction::Call(H160(ta_inner.try_into().unwrap())); + + let tx = Transaction{ + nonce: U256::from_dec_str("2787").unwrap(), + gas_price: U256::from_dec_str("3000000000").unwrap(), + gas_limit: U256::from_dec_str("45348").unwrap(), + action: ta, + value: U256::from_dec_str("0").unwrap(), + signature: TransactionSignature { + v: 247, + r: H256(r_inner.try_into().unwrap()), + s: H256(s_inner.try_into().unwrap()), + }, + input: vec![162, 44, 180, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 126, 29, 14, 117, 75, 59, 62, 29, 25, 113, 208, 49, 29, 132, 62, 179, 181, 26, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + + }; + + let tx_in_rec1 = TransactionInReceipt::Signed(tx); + + check_roundtrip!(tx_in_rec1 => TransactionInReceipt); + +} + +#[test] +fn test_check_transaction_in_receipt_roundtrip6() { + let ta_inner = hexutil::read_hex("c848e8767a209ec1538f7bc8a5d849ea521443dc").unwrap(); + + let r_inner = hexutil::read_hex("e8f46e259e3f8586a25a0f6037e13dbeb59123d7faa7a65e8d8c9edf6338433e").unwrap(); + let s_inner = hexutil::read_hex("7316d2aaacdb75a1d25b12d3843fd30e16d11aecf68974f0c96f6d33299b6cf6").unwrap(); + let ta = TransactionAction::Call(H160(ta_inner.try_into().unwrap())); + + let tx = Transaction{ + nonce: U256::from_dec_str("975723").unwrap(), + gas_price: U256::from_dec_str("5000000000").unwrap(), + gas_limit: U256::from_dec_str("700000").unwrap(), + action: ta, + value: U256::from_dec_str("0").unwrap(), + signature: TransactionSignature { + v: 248, + r: H256(r_inner.try_into().unwrap()), + s: H256(s_inner.try_into().unwrap()), + }, + input: vec![70, + 65, + 37, + 125], + + }; + + let tx_in_rec1 = TransactionInReceipt::Signed(tx); + + check_roundtrip!(tx_in_rec1 => TransactionInReceipt); + +} \ No newline at end of file diff --git a/evm-utils/evm-state/src/storage/inspectors.rs b/evm-utils/evm-state/src/storage/inspectors.rs index 3ae01711e1..48f583d39f 100644 --- a/evm-utils/evm-state/src/storage/inspectors.rs +++ b/evm-utils/evm-state/src/storage/inspectors.rs @@ -49,7 +49,7 @@ pub mod encoding { where T: DataInspector, K: TryFromSlice, - V: rlp::Decodable, + V: for<'r> triedb::rlp::Decodable<'r>, { fn inspect_data_raw>(&self, key: Vec, value: Data) -> Result<()> { let key = TryFromSlice::try_from_slice(&key)?; @@ -93,11 +93,11 @@ pub mod encoding { fn data_from_bytes, Value>(data: Data) -> Result where - Value: rlp::Decodable, + Value: for<'r> triedb::rlp::Decodable<'r>, { - let rlp = rlp::Rlp::new(data.as_ref()); - trace!("rlp: {:?}", rlp); - let t = Value::decode(&rlp)?; + trace!("rlp: {:?}", hexutil::to_hex(data.as_ref())); + + let t = triedb::rlp::decode(data.as_ref())?; Ok(t) } } diff --git a/evm-utils/evm-state/src/storage/mod.rs b/evm-utils/evm-state/src/storage/mod.rs index 8a9baa971f..ae67436c74 100644 --- a/evm-utils/evm-state/src/storage/mod.rs +++ b/evm-utils/evm-state/src/storage/mod.rs @@ -14,7 +14,7 @@ use derive_more::{AsRef, Deref}; use itertools::Itertools; use lazy_static::lazy_static; use log::*; -use rlp::{Decodable, Encodable}; +use rlp::{Decodable as DecodableOld, Encodable as EncodableOld}; use rocksdb::{ backup::{BackupEngine, BackupEngineOptions, RestoreOptions}, ColumnFamily, ColumnFamilyDescriptor, Env, IteratorMode, OptimisticTransactionDB, @@ -33,6 +33,7 @@ use triedb::{ gc::{DatabaseTrieMut, DbCounter, TrieCollection}, rocksdb::{RocksDatabaseHandle, RocksDatabaseHandleGC, RocksHandle, SyncRocksHandle}, FixedSecureTrieMut, + rlp::{Encodable, Decodable}, }; pub mod inspectors; @@ -391,7 +392,7 @@ impl Storage { } } - pub fn typed_for, V: Encodable + Decodable>( + pub fn typed_for, V: Encodable + for<'r> Decodable<'r>>( &self, root: H256, ) -> FixedSecureTrieMut>, K, V> { @@ -477,7 +478,7 @@ impl Storage { { let mut account: Account = accounts .get(address.as_bytes()) - .and_then(|accounts| rlp::decode(&accounts).ok()) + .and_then(|accounts| triedb::rlp::decode(&accounts).ok()) .unwrap_or_default(); account.nonce = nonce; @@ -506,7 +507,7 @@ impl Storage { .apply_increase(storage_patch, |_| vec![]) .leak_root() } - accounts.insert(address.as_bytes(), &rlp::encode(&account)); + accounts.insert(address.as_bytes(), &triedb::rlp::encode(&account)); } else { accounts.delete(address.as_bytes()); } @@ -752,7 +753,7 @@ impl Storage { static SECONDARY_MODE_PATH_SUFFIX: &str = "velas-secondary"; pub fn account_extractor(data: &[u8]) -> Vec { - if let Ok(account) = rlp::decode::(data) { + if let Ok(account) = triedb::rlp::decode::(data) { vec![account.storage_root] } else { vec![] // this trie is mixed collection, and can contain storage values among with accounts @@ -957,7 +958,7 @@ impl std::fmt::Debug for DbWithClose { } pub trait SubStorage { const COLUMN_NAME: &'static str; - type Key: Encodable + Decodable; + type Key: EncodableOld + DecodableOld; type Value: Serialize + DeserializeOwned; } diff --git a/evm-utils/evm-state/src/storage/walker.rs b/evm-utils/evm-state/src/storage/walker.rs index 90887e1b94..2f01ba2024 100644 --- a/evm-utils/evm-state/src/storage/walker.rs +++ b/evm-utils/evm-state/src/storage/walker.rs @@ -1,7 +1,6 @@ use std::{borrow::Borrow, sync::Arc}; use primitive_types::H256; -use rlp::Rlp; use triedb::merkle::{MerkleNode, MerkleValue, Leaf, Extension, Branch}; use anyhow::{anyhow, Result}; @@ -58,9 +57,7 @@ where .ok_or_else(|| anyhow!("hash {:?} not found in database", hash))?; trace!("raw bytes: {:?}", bytes); - let rlp = Rlp::new(bytes.as_slice()); - trace!("rlp: {:?}", rlp); - let node = MerkleNode::decode(&rlp)?; + let node = triedb::rlp::decode(&bytes)?; debug!("node: {:?}", node); self.process_node(nibble, &node)?; diff --git a/evm-utils/evm-state/src/transactions.rs b/evm-utils/evm-state/src/transactions.rs index 8158777a8a..2cacb180f5 100644 --- a/evm-utils/evm-state/src/transactions.rs +++ b/evm-utils/evm-state/src/transactions.rs @@ -1,10 +1,12 @@ use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use bytes::{BufMut, Buf, BytesMut}; use evm::{backend::Log, ExitReason, ExitRevert}; use primitive_types::{H160, H256, U256}; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; +use rlp::{Decodable as DecodableOld, DecoderError, Encodable as EncodableOld, Rlp, RlpStream}; use serde::{Deserialize, Serialize}; use sha3::{Digest, Keccak256}; use std::str::FromStr; +use triedb::rlp::{Encodable, Decodable}; use crate::error::*; use secp256k1::{ @@ -127,6 +129,7 @@ impl Transaction { Serialize, Deserialize, )] +#[derive(Decodable, Encodable)] pub struct UnsignedTransaction { pub nonce: U256, pub gas_price: U256, @@ -152,7 +155,8 @@ impl UnsignedTransaction { s.append(&0u8); } } - + + pub fn signing_hash(&self, chain_id: Option) -> H256 { let mut stream = RlpStream::new(); self.signing_rlp_append(&mut stream, chain_id); @@ -296,7 +300,7 @@ impl TransactionSignature { } } -impl Encodable for TransactionAction { +impl EncodableOld for TransactionAction { fn rlp_append(&self, s: &mut RlpStream) { match self { TransactionAction::Call(address) => { @@ -309,7 +313,7 @@ impl Encodable for TransactionAction { } } -impl Decodable for TransactionAction { +impl DecodableOld for TransactionAction { fn decode(rlp: &Rlp<'_>) -> Result { Ok(if rlp.is_empty() { if rlp.is_data() { @@ -322,8 +326,48 @@ impl Decodable for TransactionAction { }) } } +impl Encodable for TransactionAction { -impl Encodable for Transaction { + fn encode(&self,out: &mut dyn BufMut) { + match self { + TransactionAction::Create => { + let empty : &[u8] = &[]; + empty.encode(out); + }, + TransactionAction::Call(address) => { + address.encode(out); + }, + } + } + fn length(&self) -> usize { + match self { + TransactionAction::Create => { + let empty : &[u8] = &[]; + empty.length() + }, + TransactionAction::Call(address) => { + address.length() + }, + } + + } +} + +impl<'de> Decodable<'de> for TransactionAction { + fn decode(buf: &mut &'de [u8]) -> Result { + let mut buf_view = *buf; + let h = fastrlp::Header::decode(&mut buf_view)?; + if h.payload_length == 0 { + let _h = fastrlp::Header::decode(buf)?; + return Ok(Self::Create); + } + let address : H160 = ::decode(buf)?; + Ok(TransactionAction::Call(address)) + + } +} + +impl EncodableOld for Transaction { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(9); s.append(&self.nonce); @@ -338,7 +382,76 @@ impl Encodable for Transaction { } } -impl Decodable for Transaction { +impl Encodable for Transaction { + fn encode(&self,out: &mut dyn BufMut) { + + let len = self.nonce.length() + self.gas_price.length() + + self.gas_limit.length() + self.action.length() + + self.value.length() + self.input.length() + + self.signature.v.length() + self.signature.r.length() + self.signature.s.length() ; + fastrlp::Header { + list: true, + payload_length: len, + }.encode(out); + self.nonce.encode(out); + self.gas_price.encode(out); + self.gas_limit.encode(out); + self.action.encode(out); + self.value.encode(out); + self.input.encode(out); + self.signature.v.encode(out); + self.signature.r.encode(out); + self.signature.s.encode(out); + } + + fn length(&self) -> usize { + + let len = self.nonce.length() + self.gas_price.length() + + self.gas_limit.length() + self.action.length() + + self.value.length() + self.input.length() + + self.signature.v.length() + self.signature.r.length() + self.signature.s.length() ; + fastrlp::Header { + list: true, + payload_length: len, + } + .length() + + len + + } +} + +impl<'de> Decodable<'de> for Transaction { + fn decode(buf: &mut &'de [u8]) -> Result { + let h = fastrlp::Header::decode(buf)?; + if !h.list { + return Err(fastrlp::DecodeError::UnexpectedString); + } + let payload_view = &mut &buf[..h.payload_length]; + let cnt = fastrlp::count(payload_view)?; + if cnt!= 9 { + return Err(fastrlp::DecodeError::ListLengthMismatch { expected: 9, got: cnt }); + } + + let nonce = fastrlp::Decodable::decode(payload_view)?; + let gas_price = fastrlp::Decodable::decode(payload_view)?; + let gas_limit = fastrlp::Decodable::decode(payload_view)?; + let action = fastrlp::Decodable::decode(payload_view)?; + let value = fastrlp::Decodable::decode(payload_view)?; + let input= fastrlp::Decodable::decode(payload_view)?; + let v= fastrlp::Decodable::decode(payload_view)?; + let r = fastrlp::Decodable::decode(payload_view)?; + let s = fastrlp::Decodable::decode(payload_view)?; + debug_assert!(payload_view.is_empty()); + buf.advance(h.payload_length); + Ok(Self { + nonce, gas_price, gas_limit, action, value, input, + signature: TransactionSignature { v, r, s}, + }) + } +} + +#[cfg(test)] +impl DecodableOld for Transaction { fn decode(rlp: &Rlp<'_>) -> Result { Ok(Self { nonce: rlp.val_at(0)?, @@ -356,7 +469,8 @@ impl Decodable for Transaction { } } -impl Encodable for UnsignedTransaction { +#[cfg(test)] +impl EncodableOld for UnsignedTransaction { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(6); s.append(&self.nonce); @@ -368,7 +482,9 @@ impl Encodable for UnsignedTransaction { } } -impl Decodable for UnsignedTransaction { + +#[cfg(test)] +impl DecodableOld for UnsignedTransaction { fn decode(rlp: &Rlp<'_>) -> Result { Ok(Self { nonce: rlp.val_at(0)?, @@ -410,6 +526,78 @@ impl TransactionInReceipt { } impl Encodable for TransactionInReceipt { + + fn encode(&self,out: &mut dyn BufMut) { + match self { + TransactionInReceipt::Signed(tx) => { + tx.encode(out); + }, + TransactionInReceipt::Unsigned(tx) => { + tx.encode(out); + }, + } + } + fn length(&self) -> usize { + match self { + TransactionInReceipt::Signed(tx) => { + tx.length() + }, + TransactionInReceipt::Unsigned(tx) => { + tx.length() + }, + } + } +} + +pub fn consume(buf: &mut &[u8]) -> Result<(), triedb::rlp::decode::DecodeError> { + let h = fastrlp::Header::decode(buf)?; + + buf.advance(h.payload_length); + Ok(()) + + +} +impl<'de> Decodable<'de> for TransactionInReceipt { + fn decode(buf: &mut &'de [u8]) -> Result { + let mut count_view = *buf; + let h = fastrlp::Header::decode(&mut count_view)?; + if !h.list { + return Err(fastrlp::DecodeError::UnexpectedString); + } + let count_view = &mut &count_view[..h.payload_length]; + let cnt = fastrlp::count(count_view)?; + + let res = match cnt { + 8 => { + TransactionInReceipt::Unsigned(UnsignedTransactionWithCaller::decode(buf, false)?) + }, + 9 => { + for _repeat in 0..8 { + consume(count_view)?; + } + let res: Result = fastrlp::Decodable::decode(count_view); + match (count_view.is_empty(), res) { + (true, Ok(UNSIGNED_TX_MARKER)) => { + TransactionInReceipt::Unsigned(UnsignedTransactionWithCaller::decode(buf, true)?) + }, + _ => { + TransactionInReceipt::Signed(::decode(buf)?) + } + + } + + }, + _ => return Err(fastrlp::DecodeError::Custom( + "list len must be either 8 or 9 for TransactionInReceipt" + ) ), + + }; + Ok(res) + } +} + +#[cfg(test)] +impl EncodableOld for TransactionInReceipt { fn rlp_append(&self, s: &mut RlpStream) { match self { TransactionInReceipt::Signed(tx) => { @@ -434,18 +622,19 @@ impl From for TransactionInReceipt { } } -impl Decodable for TransactionInReceipt { +#[cfg(test)] +impl DecodableOld for TransactionInReceipt { fn decode(rlp: &Rlp<'_>) -> Result { let items = rlp.item_count()?; Ok(match items { - 8 => TransactionInReceipt::Unsigned(UnsignedTransactionWithCaller::decode(rlp, false)?), + 8 => TransactionInReceipt::Unsigned(UnsignedTransactionWithCaller::decode_old(rlp, false)?), 9 => { if rlp.val_at::(8) == Ok(0x1u8) { - TransactionInReceipt::Unsigned(UnsignedTransactionWithCaller::decode( + TransactionInReceipt::Unsigned(UnsignedTransactionWithCaller::decode_old( rlp, true, )?) } else { - TransactionInReceipt::Signed(Transaction::decode(rlp)?) + TransactionInReceipt::Signed(::decode(rlp)?) } } _ => return Err(DecoderError::RlpInvalidLength), @@ -463,7 +652,8 @@ pub struct UnsignedTransactionWithCaller { pub signed_compatible: bool, } -impl Encodable for UnsignedTransactionWithCaller { +#[cfg(test)] +impl EncodableOld for UnsignedTransactionWithCaller { fn rlp_append(&self, s: &mut RlpStream) { let chain_id = self.chain_id; if self.signed_compatible { @@ -491,8 +681,100 @@ impl Encodable for UnsignedTransactionWithCaller { } } +impl Encodable for UnsignedTransactionWithCaller { + + fn encode(&self,out: &mut dyn BufMut) { + let chain_id = self.chain_id; + if self.signed_compatible { + let len = self.unsigned_tx.nonce.length() + + self.unsigned_tx.gas_price.length() + + self.unsigned_tx.gas_limit.length() + + self.unsigned_tx.action.length()+ + self.unsigned_tx.value.length()+ + self.unsigned_tx.input.length()+ + chain_id.length() + + self.caller.length() + + UNSIGNED_TX_MARKER.length(); + fastrlp::Header { + list: true, + payload_length: len, + }.encode(out); + self.unsigned_tx.nonce.encode(out); + self.unsigned_tx.gas_price.encode(out); + self.unsigned_tx.gas_limit.encode(out); + self.unsigned_tx.action.encode(out); + self.unsigned_tx.value.encode(out); + self.unsigned_tx.input.encode(out); + chain_id.encode(out); + self.caller.encode(out); + UNSIGNED_TX_MARKER.encode(out); + } else { + let len = self.unsigned_tx.nonce.length() + + self.unsigned_tx.gas_price.length() + + self.unsigned_tx.gas_limit.length() + + self.unsigned_tx.action.length()+ + self.unsigned_tx.value.length()+ + self.unsigned_tx.input.length()+ + self.caller.length() + + chain_id.length(); + fastrlp::Header { + list: true, + payload_length: len, + }.encode(out); + self.unsigned_tx.nonce.encode(out); + self.unsigned_tx.gas_price.encode(out); + self.unsigned_tx.gas_limit.encode(out); + self.unsigned_tx.action.encode(out); + self.unsigned_tx.value.encode(out); + self.unsigned_tx.input.encode(out); + self.caller.encode(out); + chain_id.encode(out); + + } + + } + fn length(&self) -> usize { + let chain_id = self.chain_id; + if self.signed_compatible { + let len = self.unsigned_tx.nonce.length() + + self.unsigned_tx.gas_price.length() + + self.unsigned_tx.gas_limit.length() + + self.unsigned_tx.action.length()+ + self.unsigned_tx.value.length()+ + self.unsigned_tx.input.length()+ + chain_id.length() + + self.caller.length() + + UNSIGNED_TX_MARKER.length(); + fastrlp::Header { + list: true, + payload_length: len, + } + .length() + + len + } else { + let len = self.unsigned_tx.nonce.length() + + self.unsigned_tx.gas_price.length() + + self.unsigned_tx.gas_limit.length() + + self.unsigned_tx.action.length()+ + self.unsigned_tx.value.length()+ + self.unsigned_tx.input.length()+ + self.caller.length() + + chain_id.length(); + fastrlp::Header { + list: true, + payload_length: len, + } + .length() + + len + + } + } +} + impl UnsignedTransactionWithCaller { - pub fn tx_id_hash(&self) -> H256 { + + #[cfg(test)] + pub fn tx_id_hash_old(&self) -> H256 { // old transaction hash was calculated with different rlp structure, use signing_hash to be compatible if !self.signed_compatible { return self.unsigned_tx.signing_hash(Some(self.chain_id)); @@ -501,7 +783,19 @@ impl UnsignedTransactionWithCaller { self.rlp_append(&mut stream); H256::from_slice(Keccak256::digest(stream.as_raw()).as_slice()) } - fn decode(rlp: &Rlp<'_>, signed_compatible: bool) -> Result { + pub fn tx_id_hash(&self) -> H256 { + + if !self.signed_compatible { + return self.unsigned_tx.signing_hash(Some(self.chain_id)); + } + let mut buf = BytesMut::with_capacity(1024); + self.encode(&mut buf); + + H256::from_slice(Keccak256::digest(buf.as_ref()).as_slice()) + + } + #[cfg(test)] + pub(super) fn decode_old(rlp: &Rlp<'_>, signed_compatible: bool) -> Result { let nonce = rlp.val_at(0)?; let gas_price = rlp.val_at(1)?; let gas_limit = rlp.val_at(2)?; @@ -540,6 +834,58 @@ impl UnsignedTransactionWithCaller { }) } } + + pub(super) fn decode(buf: &mut &[u8], signed_compatible: bool) -> Result { + let h = fastrlp::Header::decode(buf)?; + if !h.list { + return Err(fastrlp::DecodeError::UnexpectedString); + } + let payload_view = &mut &buf[..h.payload_length]; + let cnt = fastrlp::count(payload_view)?; + let expected_cnt = if signed_compatible { + 9 + } else { + 8 + }; + + if cnt!= expected_cnt { + return Err(fastrlp::DecodeError::ListLengthMismatch { expected: expected_cnt, got: cnt }); + } + let nonce = fastrlp::Decodable::decode(payload_view)?; + let gas_price = fastrlp::Decodable::decode(payload_view)?; + let gas_limit = fastrlp::Decodable::decode(payload_view)?; + let action = fastrlp::Decodable::decode(payload_view)?; + let value = fastrlp::Decodable::decode(payload_view)?; + let input = fastrlp::Decodable::decode(payload_view)?; + let (chain_id, caller) = if signed_compatible { + let chain_id = fastrlp::Decodable::decode(payload_view)?; + let caller = fastrlp::Decodable::decode(payload_view)?; + let _marker: u8 = fastrlp::Decodable::decode(payload_view)?; + debug_assert_eq!(_marker, UNSIGNED_TX_MARKER); + (chain_id, caller) + } else { + let caller = fastrlp::Decodable::decode(payload_view)?; + let chain_id = fastrlp::Decodable::decode(payload_view)?; + (chain_id, caller) + + }; + debug_assert!(payload_view.is_empty()); + buf.advance(h.payload_length); + + Ok(Self { + unsigned_tx: UnsignedTransaction { + nonce, + gas_price, + gas_limit, + action, + value, + input, + }, + caller, + chain_id, + signed_compatible, + }) + } } // TODO: Work on logs and state_root. diff --git a/evm-utils/evm-state/src/types.rs b/evm-utils/evm-state/src/types.rs index 662dc54701..ace06ad8ff 100644 --- a/evm-utils/evm-state/src/types.rs +++ b/evm-utils/evm-state/src/types.rs @@ -1,11 +1,13 @@ +use bytes::{BufMut, Buf}; use derive_more::{AsRef, From, Into}; use itertools::Itertools; -use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; +use rlp::{Decodable as DecodableOld, DecoderError as OldDecoderError, Encodable as EncodableOld, Rlp, RlpStream}; use serde::{Deserialize, Serialize}; use sha3::{Digest, Keccak256}; use triedb::empty_trie_hash; +use triedb::rlp::{Encodable, Decodable}; use crate::TransactionReceipt; use auto_enums::auto_enum; @@ -93,7 +95,7 @@ impl AccountState { } } -impl Encodable for AccountState { +impl EncodableOld for AccountState { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(3) .append(&self.nonce) @@ -102,8 +104,8 @@ impl Encodable for AccountState { } } -impl Decodable for AccountState { - fn decode(rlp: &Rlp) -> Result { +impl DecodableOld for AccountState { + fn decode(rlp: &Rlp) -> Result { Ok(Self { nonce: rlp.val_at(0)?, balance: rlp.val_at(1)?, @@ -133,15 +135,15 @@ impl Code { } } -impl Encodable for Code { +impl EncodableOld for Code { fn rlp_append(&self, s: &mut RlpStream) { self.0.rlp_append(s) } } -impl Decodable for Code { - fn decode(rlp: &Rlp) -> Result { - <_>::decode(rlp).map(Self) +impl DecodableOld for Code { + fn decode(rlp: &Rlp) -> Result { + as rlp::Decodable>::decode(rlp).map(Self) } } @@ -154,6 +156,7 @@ pub struct Account { pub code_hash: H256, } + impl Account { pub fn is_empty(&self) -> bool { self.nonce == U256::zero() @@ -174,7 +177,8 @@ impl Default for Account { } } -impl Encodable for Account { +#[cfg(test)] +impl EncodableOld for Account { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(4) .append(&self.nonce) @@ -183,9 +187,63 @@ impl Encodable for Account { .append(&self.code_hash); } } +impl Encodable for Account { + fn encode(&self,out: &mut dyn BufMut) { + + let len = self.nonce.length() + self.balance.length() + self.storage_root.length() + self.code_hash.length(); + fastrlp::Header { + list: true, + payload_length: len, + }.encode(out); + self.nonce.encode(out); + self.balance.encode(out); + self.storage_root.encode(out); + self.code_hash.encode(out); + } + + fn length(&self) -> usize { + + let len = self.nonce.length() + self.balance.length() + self.storage_root.length() + self.code_hash.length(); + fastrlp::Header { + list: true, + payload_length: len, + } + .length() + + len + + } +} + + +impl<'de> Decodable<'de> for Account { + fn decode(buf: &mut &'de [u8]) -> Result { + let h = fastrlp::Header::decode(buf)?; + if !h.list { + return Err(fastrlp::DecodeError::UnexpectedString); + } + let payload_view = &mut &buf[..h.payload_length]; + let cnt = fastrlp::count(payload_view)?; + if cnt!= 4 { + return Err(fastrlp::DecodeError::ListLengthMismatch { expected: 4, got: cnt }); + } + + let nonce = fastrlp::Decodable::decode(payload_view)?; + let balance = fastrlp::Decodable::decode(payload_view)?; + let storage_root= fastrlp::Decodable::decode(payload_view)?; + let code_hash = fastrlp::Decodable::decode(payload_view)?; + + debug_assert!(payload_view.is_empty()); + buf.advance(h.payload_length); + Ok(Self { + nonce, balance, storage_root, code_hash, + }) + } +} + -impl Decodable for Account { - fn decode(rlp: &Rlp) -> Result { +#[cfg(test)] +impl DecodableOld for Account { + fn decode(rlp: &Rlp) -> Result { Ok(Self { nonce: rlp.val_at(0)?, balance: rlp.val_at(1)?, @@ -453,7 +511,7 @@ pub struct Block { pub transactions: Vec<(crate::H256, TransactionReceipt)>, } -impl Encodable for BlockHeader { +impl EncodableOld for BlockHeader { fn rlp_append(&self, s: &mut RlpStream) { match self.version { BlockVersion::InitVersion => self.rlp_append_legacy(s), @@ -477,15 +535,19 @@ impl From> for Option { } } -mod transaction_roots { +pub(super) mod transaction_roots { use crate::{Log, TransactionReceipt, H256, U256}; + use bytes::{BufMut, Buf}; use ethbloom::Bloom; - use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; + #[cfg(test)] + use rlp::{Decodable as DecodableOld, DecoderError as OldDecoderError, Encodable as EncodableOld, Rlp, RlpStream}; use triedb::gc::{MapWithCounterCached, TrieCollection}; use triedb::FixedTrieMut; + use triedb::rlp::{Encodable, Decodable}; + - #[derive(Clone, Debug)] + #[derive(Clone, Debug, PartialEq,)] pub struct EthereumReceipt { pub gas_used: U256, pub log_bloom: Bloom, @@ -504,7 +566,61 @@ mod transaction_roots { } } + impl Encodable for EthereumReceipt { + fn encode(&self,out: &mut dyn BufMut) { + let len = self.status.length() + self.gas_used.length() + self.log_bloom.length() + self.logs.length(); + fastrlp::Header { + list: true, + payload_length: len, + }.encode(out); + self.status.encode(out); + self.gas_used.encode(out); + self.log_bloom.encode(out); + self.logs.encode(out); + } + + fn length(&self) -> usize { + let len = self.status.length() + self.gas_used.length() + self.log_bloom.length() + self.logs.length(); + fastrlp::Header { + list: true, + payload_length: len, + } + .length() + + len + + } + } + + + + impl<'de> Decodable<'de> for EthereumReceipt { + fn decode(buf: &mut &'de [u8]) -> Result { + let h = fastrlp::Header::decode(buf)?; + if !h.list { + return Err(fastrlp::DecodeError::UnexpectedString); + } + let payload_view = &mut &buf[..h.payload_length]; + let cnt = fastrlp::count(payload_view)?; + if cnt!= 4 { + return Err(fastrlp::DecodeError::ListLengthMismatch { expected: 4, got: cnt }); + } + + let status = fastrlp::Decodable::decode(payload_view)?; + let gas_used = fastrlp::Decodable::decode(payload_view)?; + let log_bloom= fastrlp::Decodable::decode(payload_view)?; + let logs = fastrlp::Decodable::decode(payload_view)?; + + debug_assert!(payload_view.is_empty()); + buf.advance(h.payload_length); + Ok(Self { + status, gas_used, log_bloom, logs, + }) + } + } + + #[cfg(test)] + impl EncodableOld for EthereumReceipt { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(4); s.append(&self.status); @@ -514,8 +630,9 @@ mod transaction_roots { } } - impl Decodable for EthereumReceipt { - fn decode(rlp: &Rlp<'_>) -> Result { + #[cfg(test)] + impl DecodableOld for EthereumReceipt { + fn decode(rlp: &Rlp<'_>) -> Result { Ok(EthereumReceipt { gas_used: rlp.val_at(1)?, log_bloom: rlp.val_at(2)?, @@ -637,7 +754,7 @@ mod tests { pub nonce: H64, } - impl Encodable for Header { + impl EncodableOld for Header { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(15); s.append(&self.parent_hash); @@ -658,8 +775,8 @@ mod tests { } } - impl Decodable for Header { - fn decode(rlp: &Rlp) -> Result { + impl DecodableOld for Header { + fn decode(rlp: &Rlp) -> Result { Ok(Self { parent_hash: rlp.val_at(0)?, ommers_hash: rlp.val_at(1)?, diff --git a/ledger-tool/Cargo.toml b/ledger-tool/Cargo.toml index e2627343fd..cf5691cd48 100644 --- a/ledger-tool/Cargo.toml +++ b/ledger-tool/Cargo.toml @@ -41,7 +41,7 @@ tokio = { version = "1.14.1", features = ["full"] } evm-state = { path = "../evm-utils/evm-state" } evm-rpc = { path = "../evm-utils/evm-rpc" } solana-evm-loader-program = { path = "../evm-utils/programs/evm_loader" } -triedb = { git = "https://github.com/velas/triedb", tag = "rocksdb-v0.20.1-orth", features = ["rocksdb"] } +triedb = { git = "https://github.com/velas/triedb", tag = "fast_rlp", features = ["rocksdb"] } rlp = "0.5.0" anyhow = "1.0.43" rayon = "1.5.0" diff --git a/replica-lib/Cargo.toml b/replica-lib/Cargo.toml index 6ec6214c51..bf3f477d7f 100644 --- a/replica-lib/Cargo.toml +++ b/replica-lib/Cargo.toml @@ -26,7 +26,6 @@ clap = "2.33.1" sha3 = "0.9.1" -rlp = "0.5.0" tokio = { version = "1.14.1", features = ["full", "time"] } tonic = { version = "0.8.1", features = ["tls", "transport", "gzip"] } @@ -41,7 +40,7 @@ evm-rpc = { path = "../evm-utils/evm-rpc" } primitive-types = "0.8.0" rocksdb = { package = "rocksdb", version = "0.20.1", default-features = false } -triedb = { git = "https://github.com/velas/triedb", tag = "rocksdb-v0.20.1-orth", features = ["rocksdb"] } +triedb = { git = "https://github.com/velas/triedb", tag = "fast_rlp", features = ["rocksdb"] } rangemap = { version = "1.3.0", features = ["serde1"]} diff --git a/replica-lib/src/triedb/client/sync/bootstrap/helpers.rs b/replica-lib/src/triedb/client/sync/bootstrap/helpers.rs index bad16c4a50..a7942d60b9 100644 --- a/replica-lib/src/triedb/client/sync/bootstrap/helpers.rs +++ b/replica-lib/src/triedb/client/sync/bootstrap/helpers.rs @@ -1,8 +1,7 @@ use evm_state::{storage::account_extractor, H256}; -use rlp::Rlp; use sha3::{Digest, Keccak256}; -use triedb::{gc::ReachableHashes, merkle::MerkleNode}; +use triedb::gc::ReachableHashes; use crate::triedb::{error::client, MAX_CHUNK_HASHES}; @@ -21,7 +20,7 @@ fn map_node_to_next_layer( parent: &((H256, bool), Vec), ) -> Result, triedb::Error> { let ((_hash, direct), node) = parent; - let node = MerkleNode::decode(&Rlp::new(node))?; + let node = triedb::rlp::decode(node)?; let (direct_childs, indirect_childs) = if *direct { ReachableHashes::collect(&node, account_extractor).childs() diff --git a/storage-proto/Cargo.toml b/storage-proto/Cargo.toml index 9dd5f933ab..affae16421 100644 --- a/storage-proto/Cargo.toml +++ b/storage-proto/Cargo.toml @@ -19,6 +19,7 @@ solana-sdk = { path = "../sdk", version = "=1.9.29" } solana-transaction-status = { path = "../transaction-status", version = "=1.9.29" } rlp = "0.5.0" +triedb = { git = "https://github.com/velas/triedb", tag = "fast_rlp", features = ["rocksdb"] } evm-state = { path = "../evm-utils/evm-state" } [dev-dependencies] enum-iterator = "0.7.0" diff --git a/storage-proto/src/convert.rs b/storage-proto/src/convert.rs index 36640f9eaf..bef72ef79e 100644 --- a/storage-proto/src/convert.rs +++ b/storage-proto/src/convert.rs @@ -1097,9 +1097,9 @@ impl TryFrom for evm_state::TransactionInRe impl From for generated_evm::Transaction { fn from(tx: evm_state::Transaction) -> Self { - let bytes = rlp::encode(&tx); + let bytes = triedb::rlp::encode(&tx); Self { - rlp_encoded_body: bytes.to_vec(), + rlp_encoded_body: bytes, } } } @@ -1107,7 +1107,7 @@ impl From for generated_evm::Transaction { impl TryFrom for evm_state::Transaction { type Error = &'static str; fn try_from(tx: generated_evm::Transaction) -> Result { - rlp::decode(&tx.rlp_encoded_body).map_err(|_| "Failed to deserialize rlp tx body") + triedb::rlp::decode(&tx.rlp_encoded_body).map_err(|_| "Failed to deserialize rlp tx body") } } @@ -1115,9 +1115,9 @@ impl From for generated_evm::UnsignedTransactionWithCaller { fn from(unsigned: evm_state::UnsignedTransactionWithCaller) -> Self { - let bytes = rlp::encode(&unsigned.unsigned_tx); + let bytes = triedb::rlp::encode(&unsigned.unsigned_tx); Self { - rlp_encoded_body: bytes.to_vec(), + rlp_encoded_body: bytes, chain_id: unsigned.chain_id, caller: unsigned.caller.into_vec(), signed_compatible: unsigned.signed_compatible, @@ -1136,7 +1136,7 @@ impl TryFrom chain_id: unsigned.chain_id, signed_compatible: unsigned.signed_compatible, caller: convert_from_bytes(unsigned.caller)?, - unsigned_tx: rlp::decode(&unsigned.rlp_encoded_body) + unsigned_tx: triedb::rlp::decode(&unsigned.rlp_encoded_body) .map_err(|_| "Failed to deserialize rlp tx body")?, }) }