From 59e36b41496fbf8d8299369ef86e79a4a1d23f40 Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Thu, 3 Nov 2022 13:12:22 +0000 Subject: [PATCH 1/9] cache code size/hash in storage --- Cargo.lock | 1 + frame/evm/Cargo.toml | 1 + frame/evm/src/lib.rs | 39 ++++++++++++++++++++++++++++++++++- frame/evm/src/runner/stack.rs | 8 +++++++ 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 452e6d6cf8..35d00d8fc8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4576,6 +4576,7 @@ dependencies = [ "rlp", "scale-info", "serde", + "sha3 0.10.1", "sp-core", "sp-io", "sp-runtime", diff --git a/frame/evm/Cargo.toml b/frame/evm/Cargo.toml index bf505019aa..b9105ee362 100644 --- a/frame/evm/Cargo.toml +++ b/frame/evm/Cargo.toml @@ -17,6 +17,7 @@ evm = { version = "0.36.0", default-features = false, features = ["with-codec"] hex = { version = "0.4.3", default-features = false, features = ["alloc"] } log = { version = "0.4.17", default-features = false } serde = { version = "1.0.144", optional = true, features = ["derive"] } +sha3 = { version = "0.10", default-features = false } # Parity codec = { package = "parity-scale-codec", version = "3.2.1", default-features = false, features = ["derive"] } diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 1cef72ea24..ef6d4c7346 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -73,7 +73,8 @@ use frame_support::{ weights::Weight, }; use frame_system::RawOrigin; -use sp_core::{Hasher, H160, H256, U256}; +use scale_info::TypeInfo; +use sp_core::{Decode, Encode, Hasher, H160, H256, U256}; use sp_runtime::{ traits::{BadOrigin, Saturating, UniqueSaturatedInto, Zero}, AccountId32, DispatchErrorWithPostInfo, @@ -494,6 +495,11 @@ pub mod pallet { #[pallet::getter(fn account_codes)] pub type AccountCodes = StorageMap<_, Blake2_128Concat, H160, Vec, ValueQuery>; + #[pallet::storage] + #[pallet::getter(fn account_codes_metadata)] + pub type AccountCodesMetadata = + StorageMap<_, Blake2_128Concat, H160, CodeMetadata, OptionQuery>; + #[pallet::storage] #[pallet::getter(fn account_storages)] pub type AccountStorages = @@ -508,6 +514,12 @@ pub type BalanceOf = type NegativeImbalanceOf = ::AccountId>>::NegativeImbalance; +#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +pub struct CodeMetadata { + pub size: u64, + pub hash: H256, +} + pub trait EnsureAddressOrigin { /// Success return type. type Success; @@ -684,6 +696,7 @@ impl Pallet { } >::remove(address); + >::remove(address); #[allow(deprecated)] let _ = >::remove_prefix(address, None); } @@ -700,6 +713,30 @@ impl Pallet { } >::insert(address, code); + + // Update metadata. + let _ = Self::account_code_metadata(address); + } + + /// Get the account metadata (hash and size) from storage if it exists, + /// or compute it from code and store it if it doesn't exist. + pub fn account_code_metadata(address: H160) -> CodeMetadata { + use sha3::Digest; + + if let Some(meta) = >::get(&address) { + return meta; + } + + let code = >::get(&address); + + let size = code.len() as u64; + let hash = H256::from_slice(sha3::Keccak256::digest(&code).as_slice()); + + let meta = CodeMetadata { size, hash }; + + >::insert(address, meta.clone()); + + meta } /// Get the account basic in EVM format. diff --git a/frame/evm/src/runner/stack.rs b/frame/evm/src/runner/stack.rs index 61bf087ede..f793caaea6 100644 --- a/frame/evm/src/runner/stack.rs +++ b/frame/evm/src/runner/stack.rs @@ -805,6 +805,14 @@ where self.substate .recursive_is_cold(&|a: &Accessed| a.accessed_storage.contains(&(address, key))) } + + fn code_size(&self, address: H160) -> U256 { + U256::from(>::account_code_metadata(address).size) + } + + fn code_hash(&self, address: H160) -> H256 { + >::account_code_metadata(address).hash + } } #[cfg(feature = "forbid-evm-reentrancy")] From 0dfb2e0e9533d154fca52c68f004939ec8e68e5a Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Mon, 27 Mar 2023 12:08:39 +0200 Subject: [PATCH 2/9] use in-memory code --- frame/evm/src/lib.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 4d1e69539e..90d81e62d5 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -532,6 +532,17 @@ pub struct CodeMetadata { pub hash: H256, } +impl CodeMetadata { + fn from_code(code: &[u8]) -> Self { + use sha3::Digest; + + let size = code.len() as u64; + let hash = H256::from_slice(sha3::Keccak256::digest(&code).as_slice()); + + Self { size, hash } + } +} + pub trait EnsureAddressOrigin { /// Success return type. type Success; @@ -745,27 +756,21 @@ impl Pallet { >::insert(address, code); // Update metadata. - let _ = Self::account_code_metadata(address); + let meta = CodeMetadata::from_code(&code); + >::insert(address, meta.clone()); } /// Get the account metadata (hash and size) from storage if it exists, /// or compute it from code and store it if it doesn't exist. pub fn account_code_metadata(address: H160) -> CodeMetadata { - use sha3::Digest; - if let Some(meta) = >::get(&address) { return meta; } let code = >::get(&address); - - let size = code.len() as u64; - let hash = H256::from_slice(sha3::Keccak256::digest(&code).as_slice()); - - let meta = CodeMetadata { size, hash }; + let meta = CodeMetadata::from_code(&code); >::insert(address, meta.clone()); - meta } From 0b860ef415dc63000c514534c2c32222f97c1001 Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Mon, 27 Mar 2023 12:17:36 +0200 Subject: [PATCH 3/9] don't clone metadata --- frame/evm/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 90d81e62d5..f2d208d2be 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -526,7 +526,7 @@ pub type BalanceOf = type NegativeImbalanceOf = ::AccountId>>::NegativeImbalance; -#[derive(Clone, Eq, PartialEq, Encode, Decode, TypeInfo)] +#[derive(Clone, Copy, Eq, PartialEq, Encode, Decode, TypeInfo)] pub struct CodeMetadata { pub size: u64, pub hash: H256, @@ -757,7 +757,7 @@ impl Pallet { // Update metadata. let meta = CodeMetadata::from_code(&code); - >::insert(address, meta.clone()); + >::insert(address, meta); } /// Get the account metadata (hash and size) from storage if it exists, @@ -770,7 +770,7 @@ impl Pallet { let code = >::get(&address); let meta = CodeMetadata::from_code(&code); - >::insert(address, meta.clone()); + >::insert(address, meta); meta } From 02b84852a6a5aa5103f45e7987e1748cd415eb35 Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Mon, 3 Apr 2023 11:42:29 +0200 Subject: [PATCH 4/9] bump evm --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ceb42d3fda..755ff88356 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,7 +41,7 @@ bn = { package = "substrate-bn", version = "0.6", default-features = false } environmental = { version = "1.1.3", default-features = false } ethereum = { version = "0.14.0", default-features = false } ethereum-types = { version = "0.14.1", default-features = false } -evm = { version = "0.37.0", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "775c477dfc5d2c9772b94a776f6d5205c5b08954", default-features = false } impl-serde = { version = "0.4.0", default-features = false } jsonrpsee = "0.16.2" kvdb-rocksdb = "0.17.0" From 40f96da0b27d123f0ace56d1537801584e0d766d Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Mon, 3 Apr 2023 11:42:43 +0200 Subject: [PATCH 5/9] don't cache empty code metadata + tests --- Cargo.lock | 19 +++++++++++-------- frame/evm/Cargo.toml | 1 + frame/evm/src/lib.rs | 19 ++++++++++++++++--- frame/evm/src/tests.rs | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b1d31aff7..ab3d4f755f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1791,8 +1791,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "evm" version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4448c65b71e8e2b9718232d84d09045eeaaccb2320494e6bd6dbf7e58fec8ff" +source = "git+https://github.com/rust-blockchain/evm?rev=775c477dfc5d2c9772b94a776f6d5205c5b08954#775c477dfc5d2c9772b94a776f6d5205c5b08954" dependencies = [ "auto_impl", "environmental", @@ -1812,8 +1811,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c51bec0eb68a891c2575c758eaaa1d61373fc51f7caaf216b1fb5c3fea3b5d" +source = "git+https://github.com/rust-blockchain/evm?rev=775c477dfc5d2c9772b94a776f6d5205c5b08954#775c477dfc5d2c9772b94a776f6d5205c5b08954" dependencies = [ "parity-scale-codec", "primitive-types", @@ -1824,8 +1822,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8b93c59c54fc26522d842f0e0d3f8e8be331c776df18ff3e540b53c2f64d509" +source = "git+https://github.com/rust-blockchain/evm?rev=775c477dfc5d2c9772b94a776f6d5205c5b08954#775c477dfc5d2c9772b94a776f6d5205c5b08954" dependencies = [ "environmental", "evm-core", @@ -1836,8 +1833,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79b9459ce64f1a28688397c4013764ce53cd57bb84efc16b5187fa9b05b13ad" +source = "git+https://github.com/rust-blockchain/evm?rev=775c477dfc5d2c9772b94a776f6d5205c5b08954#775c477dfc5d2c9772b94a776f6d5205c5b08954" dependencies = [ "auto_impl", "environmental", @@ -2944,6 +2940,12 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hex-literal" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebdb29d2ea9ed0083cd8cece49bbd968021bd99b0849edb4a9a7ee0fdf6a4e0" + [[package]] name = "hkdf" version = "0.12.3" @@ -4894,6 +4896,7 @@ dependencies = [ "frame-support", "frame-system", "hex", + "hex-literal", "impl-trait-for-tuples", "log", "pallet-balances", diff --git a/frame/evm/Cargo.toml b/frame/evm/Cargo.toml index 972b0d6fb8..c2a916480e 100644 --- a/frame/evm/Cargo.toml +++ b/frame/evm/Cargo.toml @@ -15,6 +15,7 @@ targets = ["x86_64-unknown-linux-gnu"] environmental = { workspace = true, optional = true } evm = { workspace = true, features = ["with-codec"] } hex = { version = "0.4.3", default-features = false, features = ["alloc"] } +hex-literal = { version = "0.3.4" } impl-trait-for-tuples = "0.2.2" log = { workspace = true } rlp = { workspace = true } diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index f2d208d2be..cc5e864b2e 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -526,7 +526,7 @@ pub type BalanceOf = type NegativeImbalanceOf = ::AccountId>>::NegativeImbalance; -#[derive(Clone, Copy, Eq, PartialEq, Encode, Decode, TypeInfo)] +#[derive(Debug, Clone, Copy, Eq, PartialEq, Encode, Decode, TypeInfo)] pub struct CodeMetadata { pub size: u64, pub hash: H256, @@ -753,11 +753,11 @@ impl Pallet { let _ = frame_system::Pallet::::inc_sufficients(&account_id); } - >::insert(address, code); - // Update metadata. let meta = CodeMetadata::from_code(&code); >::insert(address, meta); + + >::insert(address, code); } /// Get the account metadata (hash and size) from storage if it exists, @@ -768,6 +768,19 @@ impl Pallet { } let code = >::get(&address); + + // If code is empty we return precomputed hash for empty code. + // We don't store it as this address could get code deployed in the future. + if code.is_empty() { + return CodeMetadata { + size: 0, + hash: hex_literal::hex!( + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + ) + .into(), + }; + } + let meta = CodeMetadata::from_code(&code); >::insert(address, meta); diff --git a/frame/evm/src/tests.rs b/frame/evm/src/tests.rs index 65fc0e033b..2604b7c627 100644 --- a/frame/evm/src/tests.rs +++ b/frame/evm/src/tests.rs @@ -651,3 +651,40 @@ fn eip3607_transaction_from_precompile() { .is_ok()); }); } + +#[test] +fn metadata_code_gets_cached() { + new_test_ext().execute_with(|| { + let address = H160::repeat_byte(0xaa); + + crate::Pallet::::create_account(address, b"Exemple".to_vec()); + + let metadata = crate::Pallet::::account_code_metadata(address); + assert_eq!(metadata.size, 7); + assert_eq!( + metadata.hash, + hex_literal::hex!("e8396a990fe08f2402e64a00647e41dadf360ba078a59ba79f55e876e67ed4bc") + .into() + ); + + let metadata2 = >::get(&address).expect("to have metadata set"); + assert_eq!(metadata, metadata2); + }); +} + +#[test] +fn metadata_empty_dont_code_gets_cached() { + new_test_ext().execute_with(|| { + let address = H160::repeat_byte(0xaa); + + let metadata = crate::Pallet::::account_code_metadata(address); + assert_eq!(metadata.size, 0); + assert_eq!( + metadata.hash, + hex_literal::hex!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") + .into() + ); + + assert!(>::get(&address).is_none()); + }); +} From b6ea1c1677c57bb81b5eb0dc52bc9d70d5f6ea0a Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Mon, 3 Apr 2023 12:10:20 +0200 Subject: [PATCH 6/9] clippy --- frame/evm/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index cc5e864b2e..338207656b 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -537,7 +537,7 @@ impl CodeMetadata { use sha3::Digest; let size = code.len() as u64; - let hash = H256::from_slice(sha3::Keccak256::digest(&code).as_slice()); + let hash = H256::from_slice(sha3::Keccak256::digest(code).as_slice()); Self { size, hash } } @@ -763,11 +763,11 @@ impl Pallet { /// Get the account metadata (hash and size) from storage if it exists, /// or compute it from code and store it if it doesn't exist. pub fn account_code_metadata(address: H160) -> CodeMetadata { - if let Some(meta) = >::get(&address) { + if let Some(meta) = >::get(address) { return meta; } - let code = >::get(&address); + let code = >::get(address); // If code is empty we return precomputed hash for empty code. // We don't store it as this address could get code deployed in the future. From 2c333991ce47faafc2181fa8c3a8e5854cc825a6 Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Wed, 5 Apr 2023 10:55:00 +0200 Subject: [PATCH 7/9] remove deprecated getter attribute --- frame/evm/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 338207656b..e01736d414 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -508,7 +508,6 @@ pub mod pallet { pub type AccountCodes = StorageMap<_, Blake2_128Concat, H160, Vec, ValueQuery>; #[pallet::storage] - #[pallet::getter(fn account_codes_metadata)] pub type AccountCodesMetadata = StorageMap<_, Blake2_128Concat, H160, CodeMetadata, OptionQuery>; From 6b3cb91f3c7bda7f2fcb7b4d2d7b80593b860f8c Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Thu, 25 May 2023 12:07:06 +0200 Subject: [PATCH 8/9] remove dep on sha3 crate --- Cargo.lock | 1 - frame/evm/Cargo.toml | 1 - frame/evm/src/lib.rs | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d1a846a8d..9c9dec411f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5117,7 +5117,6 @@ dependencies = [ "parity-scale-codec", "rlp", "scale-info", - "sha3", "sp-core", "sp-io", "sp-runtime", diff --git a/frame/evm/Cargo.toml b/frame/evm/Cargo.toml index b7c8c62336..b3d4ac5302 100644 --- a/frame/evm/Cargo.toml +++ b/frame/evm/Cargo.toml @@ -21,7 +21,6 @@ log = { workspace = true } rlp = { workspace = true } scale-codec = { package = "parity-scale-codec", workspace = true } scale-info = { workspace = true } -sha3 = { version = "0.10", default-features = false } # Substrate frame-benchmarking = { workspace = true, optional = true } frame-support = { workspace = true } diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index f8aed6eecc..22193fd44e 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -538,10 +538,8 @@ pub struct CodeMetadata { impl CodeMetadata { fn from_code(code: &[u8]) -> Self { - use sha3::Digest; - let size = code.len() as u64; - let hash = H256::from_slice(sha3::Keccak256::digest(code).as_slice()); + let hash = H256::from_slice(sp_io::hashing::keccak_256(code).as_slice()); Self { size, hash } } From ffb58e50c95a0151cb6da4d963f013e122e89a76 Mon Sep 17 00:00:00 2001 From: nanocryk <6422796+nanocryk@users.noreply.github.com> Date: Thu, 25 May 2023 15:09:28 +0200 Subject: [PATCH 9/9] feedback --- frame/evm/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index 22193fd44e..2100a29ce7 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -539,7 +539,7 @@ pub struct CodeMetadata { impl CodeMetadata { fn from_code(code: &[u8]) -> Self { let size = code.len() as u64; - let hash = H256::from_slice(sp_io::hashing::keccak_256(code).as_slice()); + let hash = H256::from(sp_io::hashing::keccak_256(code)); Self { size, hash } } @@ -775,12 +775,12 @@ impl Pallet { // If code is empty we return precomputed hash for empty code. // We don't store it as this address could get code deployed in the future. if code.is_empty() { + const EMPTY_CODE_HASH: [u8; 32] = hex_literal::hex!( + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" + ); return CodeMetadata { size: 0, - hash: hex_literal::hex!( - "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" - ) - .into(), + hash: EMPTY_CODE_HASH.into(), }; }