From e666a3c039f3b3e18d20dedd39163b4e7df22827 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 11 Jan 2024 20:33:10 +0800 Subject: [PATCH 01/22] update PrecompileHandle ref: https://github.com/rust-ethereum/evm/pull/122 --- Cargo.lock | 40 ++- modules/evm-utility/Cargo.toml | 11 +- modules/evm/src/precompiles/blake2/mod.rs | 57 ++-- modules/evm/src/precompiles/bn128.rs | 60 ++--- modules/evm/src/precompiles/mod.rs | 108 +++++++- modules/evm/src/precompiles/modexp.rs | 178 +++++++++---- modules/evm/src/runner/state.rs | 252 ++++++++++++++---- runtime/common/src/precompile/dex.rs | 88 ++---- runtime/common/src/precompile/evm.rs | 69 ++--- runtime/common/src/precompile/evm_accounts.rs | 57 ++-- runtime/common/src/precompile/homa.rs | 60 ++--- runtime/common/src/precompile/honzon.rs | 61 ++--- runtime/common/src/precompile/incentives.rs | 83 +++--- runtime/common/src/precompile/input.rs | 52 ++-- .../common/src/precompile/liquid_crowdloan.rs | 52 ++-- runtime/common/src/precompile/mod.rs | 99 +++---- .../common/src/precompile/multicurrency.rs | 120 ++++----- runtime/common/src/precompile/nft.rs | 41 +-- runtime/common/src/precompile/oracle.rs | 56 ++-- runtime/common/src/precompile/schedule.rs | 68 ++--- runtime/common/src/precompile/stable_asset.rs | 173 +++++------- runtime/common/src/precompile/tests.rs | 36 ++- runtime/common/src/precompile/xtokens.rs | 103 ++----- 23 files changed, 947 insertions(+), 977 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 418ebf8471..5e613b8445 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3531,6 +3531,24 @@ dependencies = [ "triehash", ] +[[package]] +name = "ethereum" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e04d24d20b8ff2235cffbf242d5092de3aa45f77c5270ddbfadd2778ca13fea" +dependencies = [ + "bytes", + "ethereum-types", + "hash-db 0.16.0", + "hash256-std-hasher", + "parity-scale-codec", + "rlp", + "scale-info", + "serde", + "sha3", + "trie-root", +] + [[package]] name = "ethereum-types" version = "0.14.1" @@ -3587,12 +3605,12 @@ dependencies = [ [[package]] name = "evm" -version = "0.36.0" -source = "git+https://github.com/rust-blockchain/evm?rev=13240a8a551586fdef0b5028ed73af80b248092a#13240a8a551586fdef0b5028ed73af80b248092a" +version = "0.37.0" +source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" dependencies = [ "auto_impl", "environmental", - "ethereum", + "ethereum 0.14.0", "evm-core", "evm-gasometer", "evm-runtime", @@ -3607,8 +3625,8 @@ dependencies = [ [[package]] name = "evm-core" -version = "0.36.0" -source = "git+https://github.com/rust-blockchain/evm?rev=13240a8a551586fdef0b5028ed73af80b248092a#13240a8a551586fdef0b5028ed73af80b248092a" +version = "0.37.0" +source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3618,8 +3636,8 @@ dependencies = [ [[package]] name = "evm-gasometer" -version = "0.36.0" -source = "git+https://github.com/rust-blockchain/evm?rev=13240a8a551586fdef0b5028ed73af80b248092a#13240a8a551586fdef0b5028ed73af80b248092a" +version = "0.37.0" +source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" dependencies = [ "environmental", "evm-core", @@ -3633,7 +3651,7 @@ version = "0.13.1" dependencies = [ "acala-primitives", "env_logger", - "ethereum", + "ethereum 0.14.0", "ethjson", "frame-support", "frame-system", @@ -3665,8 +3683,8 @@ dependencies = [ [[package]] name = "evm-runtime" -version = "0.36.0" -source = "git+https://github.com/rust-blockchain/evm?rev=13240a8a551586fdef0b5028ed73af80b248092a#13240a8a551586fdef0b5028ed73af80b248092a" +version = "0.37.0" +source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" dependencies = [ "auto_impl", "environmental", @@ -6962,7 +6980,7 @@ dependencies = [ name = "module-evm-utility" version = "2.23.0" dependencies = [ - "ethereum", + "ethereum 0.15.0", "evm", "evm-gasometer", "evm-runtime", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index e995b74160..76208f221c 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,10 +9,13 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "13240a8a551586fdef0b5028ed73af80b248092a", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "13240a8a551586fdef0b5028ed73af80b248092a", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "13240a8a551586fdef0b5028ed73af80b248092a", default-features = false } -ethereum = { version = "0.14.0", default-features = false, features = ["with-codec"] } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355", default-features = false } +#evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } +#evm-gasometer = { version = "0.41.0", default-features = false } +#evm-runtime = { version = "0.41.0", default-features = false } +ethereum = { version = "0.15.0", default-features = false, features = ["with-codec"] } [features] default = ["std"] diff --git a/modules/evm/src/precompiles/blake2/mod.rs b/modules/evm/src/precompiles/blake2/mod.rs index dc2808c3b6..befebe5e4b 100644 --- a/modules/evm/src/precompiles/blake2/mod.rs +++ b/modules/evm/src/precompiles/blake2/mod.rs @@ -17,8 +17,8 @@ // along with this program. If not, see . use super::Precompile; -use crate::runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}; -use module_evm_utility::evm::{Context, ExitError, ExitSucceed}; +use crate::runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; +use module_evm_utility::evm::{ExitError, ExitSucceed}; mod eip_152; @@ -32,9 +32,10 @@ impl Precompile for Blake2F { /// Format of `input`: /// [4 bytes for rounds][64 bytes for h][128 bytes for m][8 bytes for t_0][8 bytes for t_1][1 /// byte for f] - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { const BLAKE2_F_ARG_LEN: usize = 213; + let input = handle.input(); if input.len() != BLAKE2_F_ARG_LEN { return Err(PrecompileFailure::Error { exit_status: ExitError::Other( @@ -48,13 +49,8 @@ impl Precompile for Blake2F { let rounds: u32 = u32::from_be_bytes(rounds_buf); let gas_cost: u64 = (rounds as u64) * Blake2F::GAS_COST_PER_ROUND; - if let Some(gas_left) = target_gas { - if gas_left < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } + handle.record_cost(gas_cost)?; + let input = handle.input(); // we use from_le_bytes below to effectively swap byte order to LE if architecture is BE @@ -107,9 +103,7 @@ impl Precompile for Blake2F { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: output_buf.to_vec(), - logs: Default::default(), }) } } @@ -117,7 +111,10 @@ impl Precompile for Blake2F { #[cfg(test)] mod tests { use super::*; + use crate::precompiles::tests::MockPrecompileHandle; + use frame_support::assert_ok; use hex_literal::hex; + use module_evm_utility::evm::Context; use sp_core::U256; fn get_context() -> Context { @@ -132,8 +129,10 @@ mod tests { fn blake2f_cost() { // 5 rounds let input = hex!("0000000548c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); - let result = Blake2F::execute(&input[..], None, &get_context(), false).unwrap(); - assert_eq!(result.cost, 5); + let context = get_context(); + let mut mock_handle = MockPrecompileHandle::new(&input[..], None, &context, false); + assert_ok!(Blake2F::execute(&mut mock_handle)); + assert_eq!(mock_handle.gas_used, 5); } #[test] @@ -144,15 +143,24 @@ mod tests { // invalid input (too short) let input = hex!("00"); - assert_eq!(Blake2F::execute(&input[..], None, &get_context(), false), err); + assert_eq!( + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)), + err + ); // Test vector 1 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-1 let input = hex!("00000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); - assert_eq!(Blake2F::execute(&input[..], None, &get_context(), false), err); + assert_eq!( + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)), + err + ); // Test vector 2 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-2 let input = hex!("000000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); - assert_eq!(Blake2F::execute(&input[..], None, &get_context(), false), err); + assert_eq!( + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)), + err + ); } #[test] @@ -163,7 +171,10 @@ mod tests { // Test vector 3 and expected output from https://github.com/ethereum/EIPs/blob/master/EIPS/eip-152.md#test-vector-3 let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000002"); - assert_eq!(Blake2F::execute(&input[..], None, &get_context(), false), err); + assert_eq!( + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)), + err + ); } #[test] @@ -172,7 +183,7 @@ mod tests { let input = hex!("0000000048c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let expected = hex!("08c9bcf367e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d282e6ad7f520e511f6c3e2b8c68059b9442be0454267ce079217e1319cde05b"); assert_eq!( - Blake2F::execute(&input[..], None, &get_context(), false) + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected @@ -185,7 +196,7 @@ mod tests { let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let expected = hex!("ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923"); assert_eq!( - Blake2F::execute(&input[..], None, &get_context(), false) + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected @@ -198,7 +209,7 @@ mod tests { let input = hex!("0000000c48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000"); let expected = hex!("75ab69d3190a562c51aef8d88f1c2775876944407270c42c9844252c26d2875298743e7f6d5ea2f2d3e8d226039cd31b4e426ac4f2d3d666a610c2116fde4735"); assert_eq!( - Blake2F::execute(&input[..], None, &get_context(), false) + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected @@ -211,7 +222,7 @@ mod tests { let input = hex!("0000000148c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let expected = hex!("b63a380cb2897d521994a85234ee2c181b5f844d2c624c002677e9703449d2fba551b3a8333bcdf5f2f7e08993d53923de3d64fcc68c034e717b9293fed7a421"); assert_eq!( - Blake2F::execute(&input[..], None, &get_context(), false) + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected @@ -226,7 +237,7 @@ mod tests { let input = hex!("ffffffff48c9bdf267e6096a3ba7ca8485ae67bb2bf894fe72f36e3cf1361d5f3af54fa5d182e6ad7f520e511f6c3e2b8c68059b6bbd41fbabd9831f79217e1319cde05b61626300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001"); let expected = hex!("fc59093aafa9ab43daae0e914c57635c5402d8e3d2130eb9b3cc181de7f0ecf9b22bf99a7815ce16419e200e01846e6b5df8cc7703041bbceb571de6631d2615"); assert_eq!( - Blake2F::execute(&input[..], None, &get_context(), false) + Blake2F::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected diff --git a/modules/evm/src/precompiles/bn128.rs b/modules/evm/src/precompiles/bn128.rs index 26d2c35b34..9ccd3bcdf1 100644 --- a/modules/evm/src/precompiles/bn128.rs +++ b/modules/evm/src/precompiles/bn128.rs @@ -17,8 +17,8 @@ // along with this program. If not, see . use super::Precompile; -use crate::runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}; -use module_evm_utility::evm::{Context, ExitError, ExitSucceed}; +use crate::runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; +use module_evm_utility::evm::{ExitError, ExitSucceed}; use sp_core::U256; use sp_std::vec::Vec; @@ -67,9 +67,13 @@ impl Bn128Add { } impl Precompile for Bn128Add { - fn execute(input: &[u8], _target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { use bn::AffineG1; + handle.record_cost(Bn128Add::GAS_COST)?; + + let input = handle.input(); + let p1 = read_point(input, 0)?; let p2 = read_point(input, 64)?; @@ -90,9 +94,7 @@ impl Precompile for Bn128Add { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: Bn128Add::GAS_COST, output: buf.to_vec(), - logs: Default::default(), }) } } @@ -105,9 +107,13 @@ impl Bn128Mul { } impl Precompile for Bn128Mul { - fn execute(input: &[u8], _target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { use bn::AffineG1; + handle.record_cost(Bn128Mul::GAS_COST)?; + + let input = handle.input(); + let p = read_point(input, 0)?; let fr = read_fr(input, 64)?; @@ -128,9 +134,7 @@ impl Precompile for Bn128Mul { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: Bn128Mul::GAS_COST, output: buf.to_vec(), - logs: Default::default(), }) } } @@ -145,17 +149,10 @@ impl Bn128Pairing { } impl Precompile for Bn128Pairing { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { use bn::{pairing_batch, AffineG1, AffineG2, Fq, Fq2, Group, Gt, G1, G2}; - if let Some(gas_left) = target_gas { - if gas_left < Bn128Pairing::BASE_GAS_COST { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - + let input = handle.input(); if input.len() % 192 != 0 { return Err(PrecompileFailure::Error { exit_status: ExitError::Other("Invalid input length, must be multiple of 192 (3 * (32*2))".into()), @@ -169,13 +166,6 @@ impl Precompile for Bn128Pairing { let elements = input.len() / 192; let gas_cost: u64 = Bn128Pairing::BASE_GAS_COST + (elements as u64 * Bn128Pairing::GAS_COST_PER_PAIRING); - if let Some(gas_left) = target_gas { - if gas_left < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } let mut vals = Vec::new(); for idx in 0..elements { @@ -236,14 +226,14 @@ impl Precompile for Bn128Pairing { } }; + handle.record_cost(gas_cost)?; + let mut buf = [0u8; 32]; ret_val.to_big_endian(&mut buf); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: buf.to_vec(), - logs: Default::default(), }) } } @@ -251,7 +241,9 @@ impl Precompile for Bn128Pairing { #[cfg(test)] mod tests { use super::*; + use crate::precompiles::tests::MockPrecompileHandle; use hex_literal::hex; + use module_evm_utility::evm::Context; fn get_context() -> Context { Context { @@ -278,7 +270,7 @@ mod tests { "}; assert_eq!( - Bn128Add::execute(&input[..], None, &get_context(), false) + Bn128Add::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected @@ -295,7 +287,7 @@ mod tests { "}; assert_eq!( - Bn128Add::execute(&input[..], None, &get_context(), false) + Bn128Add::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected @@ -312,7 +304,7 @@ mod tests { "}; assert_eq!( - Bn128Add::execute(&input[..], None, &get_context(), false), + Bn128Add::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)), Err(PrecompileFailure::Error { exit_status: ExitError::Other("Invalid curve point".into()) }) @@ -336,7 +328,7 @@ mod tests { "}; assert_eq!( - Bn128Mul::execute(&input[..], None, &get_context(), false) + Bn128Mul::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected @@ -352,7 +344,7 @@ mod tests { "}; assert_eq!( - Bn128Mul::execute(&input[..], None, &get_context(), false), + Bn128Mul::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)), Err(PrecompileFailure::Error { exit_status: ExitError::Other("Invalid curve point".into()) }) @@ -370,7 +362,7 @@ mod tests { "}; assert_eq!( - Bn128Pairing::execute(&input[..], None, &get_context(), false) + Bn128Pairing::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)) .unwrap() .output, expected @@ -390,7 +382,7 @@ mod tests { "}; assert_eq!( - Bn128Pairing::execute(&input[..], None, &get_context(), false), + Bn128Pairing::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)), Err(PrecompileFailure::Error { exit_status: ExitError::Other("Invalid b argument - not on curve".into()) }) @@ -407,7 +399,7 @@ mod tests { "}; assert_eq!( - Bn128Pairing::execute(&input[..], None, &get_context(), false), + Bn128Pairing::execute(&mut MockPrecompileHandle::new(&input[..], None, &get_context(), false)), Err(PrecompileFailure::Error { exit_status: ExitError::Other("Invalid input length, must be multiple of 192 (3 * (32*2))".into()) }) diff --git a/modules/evm/src/precompiles/mod.rs b/modules/evm/src/precompiles/mod.rs index e5a7287d2b..788a381dbd 100644 --- a/modules/evm/src/precompiles/mod.rs +++ b/modules/evm/src/precompiles/mod.rs @@ -18,8 +18,8 @@ //! Builtin precompiles. -use crate::runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}; -use module_evm_utility::evm::{Context, ExitError, ExitSucceed}; +use crate::runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; +use module_evm_utility::evm::{ExitError, ExitSucceed}; use sp_std::vec::Vec; mod blake2; @@ -47,7 +47,7 @@ pub trait Precompile { /// Try to execute the precompile. Calculate the amount of gas needed with given `input` and /// `target_gas`. Return `Ok(status, output, gas_used)` if the execution is /// successful. Otherwise return `Err(_)`. - fn execute(input: &[u8], target_gas: Option, context: &Context, is_static: bool) -> PrecompileResult; + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult; } pub trait LinearCostPrecompile { @@ -58,16 +58,13 @@ pub trait LinearCostPrecompile { } impl Precompile for T { - fn execute(input: &[u8], target_gas: Option, _: &Context, _: bool) -> PrecompileResult { - let cost = ensure_linear_cost(target_gas, input.len() as u64, T::BASE, T::WORD)?; - - let (exit_status, output) = T::execute(input, cost)?; - Ok(PrecompileOutput { - exit_status, - cost, - output, - logs: Default::default(), - }) + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let target_gas = handle.gas_limit(); + let cost = ensure_linear_cost(target_gas, handle.input().len() as u64, T::BASE, T::WORD)?; + + handle.record_cost(cost)?; + let (exit_status, output) = T::execute(handle.input(), cost)?; + Ok(PrecompileOutput { exit_status, output }) } } @@ -94,3 +91,88 @@ fn ensure_linear_cost(target_gas: Option, len: u64, base: u64, word: u64) - Ok(cost) } + +pub mod tests { + use crate::{runner::state::PrecompileHandle, ExitError, ExitReason}; + use module_evm_utility::evm::{Context, Transfer}; + use sp_core::{H160, H256}; + use sp_std::vec::Vec; + + pub struct MockPrecompileHandle<'inner> { + pub input: &'inner [u8], + pub code_address: H160, + pub gas_limit: Option, + pub gas_used: u64, + pub context: &'inner Context, + pub is_static: bool, + } + + impl<'inner> MockPrecompileHandle<'inner> { + pub fn new(input: &'inner [u8], gas_limit: Option, context: &'inner Context, is_static: bool) -> Self { + Self { + input, + code_address: H160::default(), + gas_limit, + gas_used: 0, + context, + is_static, + } + } + } + + impl<'inner> PrecompileHandle for MockPrecompileHandle<'inner> { + fn call( + &mut self, + _: H160, + _: Option, + _: Vec, + _: Option, + _: bool, + _: &Context, + ) -> (ExitReason, Vec) { + unimplemented!() + } + + fn record_cost(&mut self, cost: u64) -> Result<(), ExitError> { + self.gas_used += cost; + + if let Some(gas_limit) = self.gas_limit { + if self.gas_used > gas_limit { + Err(ExitError::OutOfGas) + } else { + Ok(()) + } + } else { + Ok(()) + } + } + + fn remaining_gas(&self) -> u64 { + unimplemented!() + } + + fn log(&mut self, _address: H160, _topics: Vec, _data: Vec) -> Result<(), ExitError> { + unimplemented!() + } + + fn code_address(&self) -> H160 { + self.code_address + } + + fn input(&self) -> &[u8] { + self.input + } + + fn context(&self) -> &Context { + self.context + } + + fn is_static(&self) -> bool { + self.is_static + } + + fn gas_limit(&self) -> Option { + self.gas_limit + } + } +} diff --git a/modules/evm/src/precompiles/modexp.rs b/modules/evm/src/precompiles/modexp.rs index c2f6ffb756..772e092d67 100644 --- a/modules/evm/src/precompiles/modexp.rs +++ b/modules/evm/src/precompiles/modexp.rs @@ -17,8 +17,8 @@ // along with this program. If not, see . use super::Precompile; -use crate::runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}; -use module_evm_utility::evm::{Context, ExitError, ExitSucceed}; +use crate::runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; +use module_evm_utility::evm::{ExitError, ExitSucceed}; use num::{BigUint, One, Zero}; use sp_core::U256; use sp_runtime::traits::UniqueSaturatedInto; @@ -269,7 +269,10 @@ impl ModexpImpl for Modexp { } impl Precompile for IstanbulModexp { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let input = handle.input(); + let target_gas = handle.gas_limit(); + if input.len() as u64 > MAX_LENGTH { return Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas, @@ -284,17 +287,21 @@ impl Precompile for IstanbulModexp { } } + let output = Self::execute_modexp(input); + handle.record_cost(cost.as_u64())?; + Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: cost.as_u64(), - output: Self::execute_modexp(input), - logs: Default::default(), + output, }) } } impl Precompile for Modexp { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let input = handle.input(); + let target_gas = handle.gas_limit(); + if input.len() as u64 > MAX_LENGTH { return Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas, @@ -320,11 +327,12 @@ impl Precompile for Modexp { } } + let output = Self::execute_modexp(input); + handle.record_cost(cost.as_u64())?; + Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: cost.as_u64(), - output: Self::execute_modexp(input), - logs: Default::default(), + output, }) } } @@ -332,7 +340,9 @@ impl Precompile for Modexp { #[cfg(test)] mod tests { use super::*; + use crate::precompiles::tests::MockPrecompileHandle; use hex_literal::hex; + use module_evm_utility::evm::Context; fn get_context() -> Context { Context { @@ -345,19 +355,17 @@ mod tests { #[test] fn handle_min_gas() { assert_eq!( - Modexp::execute(&[], Some(199), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new(&[], Some(199), &get_context(), false)), Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas }) ); assert_eq!( - Modexp::execute(&[], Some(200), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new(&[], Some(200), &get_context(), false)), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: [0u8; 0].to_vec(), - logs: Default::default(), }) ); } @@ -365,12 +373,10 @@ mod tests { #[test] fn test_empty_input() { assert_eq!( - Modexp::execute(&[], None, &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new(&[], None, &get_context(), false)), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: [0u8; 0].to_vec(), - logs: Default::default(), }) ); } @@ -384,12 +390,10 @@ mod tests { "}; assert_eq!( - Modexp::execute(&input, None, &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new(&input, None, &get_context(), false)), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: [0u8; 1].to_vec(), - logs: Default::default(), }) ); } @@ -403,7 +407,12 @@ mod tests { "}; assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas, }) @@ -419,7 +428,12 @@ mod tests { "}; assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas, }) @@ -434,7 +448,12 @@ mod tests { 00000000000000000000000000000000000000000000000000000000503c8ac3 "}; assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas, }) @@ -455,12 +474,15 @@ mod tests { // 3 ^ 5 % 7 == 5 assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: vec![5], - logs: Default::default(), }) ); } @@ -482,22 +504,28 @@ mod tests { U256::from(10055u64).to_big_endian(&mut output); assert_eq!( - IstanbulModexp::execute(&input, Some(100_000), &get_context(), false), + IstanbulModexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 204, output: output.to_vec(), - logs: Default::default(), }) ); assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: output.to_vec(), - logs: Default::default(), }) ); } @@ -517,22 +545,28 @@ mod tests { U256::from(1u64).to_big_endian(&mut output); assert_eq!( - IstanbulModexp::execute(&input, Some(100_000), &get_context(), false), + IstanbulModexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 13056, output: output.to_vec(), - logs: Default::default(), }) ); assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 1360, output: output.to_vec(), - logs: Default::default(), }) ); } @@ -551,22 +585,28 @@ mod tests { let expected = hex!("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab"); assert_eq!( - IstanbulModexp::execute(&input, Some(100_000), &get_context(), false), + IstanbulModexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 768, output: expected.to_vec(), - logs: Default::default(), }) ); assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: expected.to_vec(), - logs: Default::default(), }) ); } @@ -582,12 +622,15 @@ mod tests { "}; assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: [0u8; 0].to_vec(), - logs: Default::default(), }) ); } @@ -610,12 +653,15 @@ mod tests { ]; assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: [0u8; 1].to_vec(), - logs: Default::default(), }) ); } @@ -625,34 +671,50 @@ mod tests { let input = vec![0u8; 1025]; assert_eq!( - IstanbulModexp::execute(&input[..1024], Some(100_000), &get_context(), false), + IstanbulModexp::execute(&mut MockPrecompileHandle::new( + &input[..1024], + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 0, output: [0u8; 0].to_vec(), - logs: Default::default(), }) ); assert_eq!( - Modexp::execute(&input[..1024], Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input[..1024], + Some(100_000), + &get_context(), + false + )), Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 200, output: [0u8; 0].to_vec(), - logs: Default::default(), }) ); assert_eq!( - IstanbulModexp::execute(&input, Some(100_000), &get_context(), false), + IstanbulModexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas, }) ); assert_eq!( - Modexp::execute(&input, Some(100_000), &get_context(), false), + Modexp::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &get_context(), + false + )), Err(PrecompileFailure::Error { exit_status: ExitError::OutOfGas, }) diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index ec5f2d726d..1dd9de2b06 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -21,7 +21,6 @@ use crate::{encode_revert_message, StorageMeter}; use core::{cmp::min, convert::Infallible}; use module_evm_utility::{ - ethereum::Log, evm::{ backend::Backend, Capture, Config, Context, CreateScheme, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, Opcode, Runtime, Stack, Transfer, @@ -343,9 +342,7 @@ pub trait StackState<'config>: Backend + CustomStackState { #[derive(Debug, Eq, PartialEq, Clone)] pub struct PrecompileOutput { pub exit_status: ExitSucceed, - pub cost: u64, pub output: Vec, - pub logs: Vec, } /// Data returned by a precompile in case of failure. @@ -353,17 +350,58 @@ pub struct PrecompileOutput { pub enum PrecompileFailure { /// Reverts the state changes and consume all the gas. Error { exit_status: ExitError }, - /// Reverts the state changes and consume the provided `cost`. + /// Reverts the state changes. /// Returns the provided error message. - Revert { - exit_status: ExitRevert, - output: Vec, - cost: u64, - }, + Revert { exit_status: ExitRevert, output: Vec }, /// Mark this failure as fatal, and all EVM execution stacks must be exited. Fatal { exit_status: ExitFatal }, } +impl From for PrecompileFailure { + fn from(error: ExitError) -> PrecompileFailure { + PrecompileFailure::Error { exit_status: error } + } +} + +/// Handle provided to a precompile to interact with the EVM. +pub trait PrecompileHandle { + /// Perform subcall in provided context. + /// Precompile specifies in which context the subcall is executed. + fn call( + &mut self, + to: H160, + transfer: Option, + input: Vec, + gas_limit: Option, + is_static: bool, + context: &Context, + ) -> (ExitReason, Vec); + + /// Record cost to the Runtime gasometer. + fn record_cost(&mut self, cost: u64) -> Result<(), ExitError>; + + /// Retreive the remaining gas. + fn remaining_gas(&self) -> u64; + + /// Record a log. + fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError>; + + /// Retreive the code address (what is the address of the precompile being called). + fn code_address(&self) -> H160; + + /// Retreive the input data the precompile is called with. + fn input(&self) -> &[u8]; + + /// Retreive the context in which the precompile is executed. + fn context(&self) -> &Context; + + /// Is the precompile call is done statically. + fn is_static(&self) -> bool; + + /// Retreive the gas limit of this call. + fn gas_limit(&self) -> Option; +} + /// A precompile result. pub type PrecompileResult = Result; @@ -373,14 +411,7 @@ pub type PrecompileResult = Result; pub trait PrecompileSet { /// Tries to execute a precompile in the precompile set. /// If the provided address is not a precompile, returns None. - fn execute( - &self, - address: H160, - input: &[u8], - gas_limit: Option, - context: &Context, - is_static: bool, - ) -> Option; + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option; /// Check if the given address is a precompile. Should only be called to /// perform the check while not executing the precompile afterward, since @@ -389,7 +420,7 @@ pub trait PrecompileSet { } impl PrecompileSet for () { - fn execute(&self, _: H160, _: &[u8], _: Option, _: &Context, _: bool) -> Option { + fn execute(&self, _: &mut impl PrecompileHandle) -> Option { None } @@ -403,19 +434,28 @@ impl PrecompileSet for () { /// * Gas limit /// * Context /// * Is static -pub type PrecompileFn = fn(&[u8], Option, &Context, bool) -> PrecompileResult; +/// +/// In case of success returns the output and the cost. +pub type PrecompileFn = fn(&[u8], Option, &Context, bool) -> Result<(PrecompileOutput, u64), PrecompileFailure>; impl PrecompileSet for BTreeMap { - fn execute( - &self, - address: H160, - input: &[u8], - gas_limit: Option, - context: &Context, - is_static: bool, - ) -> Option { - self.get(&address) - .map(|precompile| (*precompile)(input, gas_limit, context, is_static)) + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { + let address = handle.code_address(); + + self.get(&address).map(|precompile| { + let input = handle.input(); + let gas_limit = handle.gas_limit(); + let context = handle.context(); + let is_static = handle.is_static(); + + match (*precompile)(input, gas_limit, context, is_static) { + Ok((output, cost)) => { + handle.record_cost(cost)?; + Ok(output) + } + Err(err) => Err(err), + } + }) } /// Check if the given address is a precompile. Should only be called to @@ -1015,27 +1055,17 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu // reflect both the is_static parameter of this call and the is_static // of the caller context. let precompile_is_static = self.state.metadata().is_static(); - if let Some(result) = - self.precompile_set - .execute(code_address, &input, Some(gas_limit), &context, precompile_is_static) - { + if let Some(result) = self.precompile_set.execute(&mut StackExecutorHandle { + executor: self, + code_address, + input: &input, + gas_limit: Some(gas_limit), + context: &context, + is_static: precompile_is_static, + }) { return match result { - Ok(PrecompileOutput { - exit_status, - output, - cost, - logs, - }) => { - for Log { address, topics, data } in logs { - match self.log(address, topics, data) { - Ok(_) => continue, - Err(error) => { - return Capture::Exit((ExitReason::Error(error), output)); - } - } - } - - let _ = self.state.metadata_mut().gasometer.record_cost(cost); + Ok(PrecompileOutput { exit_status, output }) => { + // let _ = self.exit_substate(StackExitKind::Succeeded); let e = self.exit_substate(StackExitKind::Succeeded); try_or_fail!(e); Capture::Exit((ExitReason::Succeed(exit_status), output)) @@ -1044,13 +1074,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu let _ = self.exit_substate(StackExitKind::Failed); Capture::Exit((ExitReason::Error(exit_status), Vec::new())) } - Err(PrecompileFailure::Revert { - exit_status, - output, - cost, - }) => { - let _ = self.state.metadata_mut().gasometer.record_cost(cost); + Err(PrecompileFailure::Revert { exit_status, output }) => { let _ = self.exit_substate(StackExitKind::Reverted); + // Capture::Exit((ExitReason::Revert(exit_status), output)) Capture::Exit((ExitReason::Revert(exit_status), encode_revert_message(&output))) } Err(PrecompileFailure::Fatal { exit_status }) => { @@ -1075,6 +1101,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu match reason { ExitReason::Succeed(s) => { + // let _ = self.exit_substate(StackExitKind::Succeeded); let e = self.exit_substate(StackExitKind::Succeeded); try_or_fail!(e); Capture::Exit((ExitReason::Succeed(s), runtime.machine().return_value())) @@ -1328,3 +1355,118 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler Ok(()) } } + +struct StackExecutorHandle<'inner, 'config, 'precompiles, S, P> { + executor: &'inner mut StackExecutor<'config, 'precompiles, S, P>, + code_address: H160, + input: &'inner [u8], + gas_limit: Option, + context: &'inner Context, + is_static: bool, +} + +impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> PrecompileHandle + for StackExecutorHandle<'inner, 'config, 'precompiles, S, P> +{ + // Perform subcall in provided context. + /// Precompile specifies in which context the subcall is executed. + fn call( + &mut self, + code_address: H160, + transfer: Option, + input: Vec, + gas_limit: Option, + is_static: bool, + context: &Context, + ) -> (ExitReason, Vec) { + // For normal calls the cost is recorded at opcode level. + // Since we don't go through opcodes we need manually record the call + // cost. Not doing so will make the code panic as recording the call stipend + // will do an underflow. + let gas_cost = gasometer::GasCost::Call { + value: transfer.clone().map(|x| x.value).unwrap_or_else(U256::zero), + gas: U256::from(gas_limit.unwrap_or(u64::MAX)), + target_is_cold: self.executor.is_cold(code_address, None), + target_exists: self.executor.exists(code_address), + }; + + // We record the length of the input. + let memory_cost = Some(gasometer::MemoryCost { + offset: U256::zero(), + len: input.len().into(), + }); + + if let Err(error) = self + .executor + .state + .metadata_mut() + .gasometer + .record_dynamic_cost(gas_cost, memory_cost) + { + return (ExitReason::Error(error), Vec::new()); + } + + event!(PrecompileSubcall { + code_address: code_address.clone(), + transfer: &transfer, + input: &input, + target_gas: gas_limit, + is_static, + context + }); + + // Perform the subcall + match Handler::call( + self.executor, + code_address, + transfer, + input, + gas_limit, + is_static, + context.clone(), + ) { + Capture::Exit((s, v)) => (s, v), + Capture::Trap(_) => unreachable!("Trap is infaillible since StackExecutor is sync"), + } + } + + /// Record cost to the Runtime gasometer. + fn record_cost(&mut self, cost: u64) -> Result<(), ExitError> { + self.executor.state.metadata_mut().gasometer.record_cost(cost) + } + + /// Retreive the remaining gas. + fn remaining_gas(&self) -> u64 { + self.executor.state.metadata().gasometer.gas() + } + + /// Record a log. + fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError> { + Handler::log(self.executor, address, topics, data) + } + + /// Retreive the code address (what is the address of the precompile being called). + fn code_address(&self) -> H160 { + self.code_address + } + + /// Retreive the input data the precompile is called with. + fn input(&self) -> &[u8] { + self.input + } + + /// Retreive the context in which the precompile is executed. + fn context(&self) -> &Context { + self.context + } + + /// Is the precompile call is done statically. + fn is_static(&self) -> bool { + self.is_static + } + + /// Retreive the gas limit of this call. + fn gas_limit(&self) -> Option { + self.gas_limit + } +} diff --git a/runtime/common/src/precompile/dex.rs b/runtime/common/src/precompile/dex.rs index 19189b53e2..c868802b04 100644 --- a/runtime/common/src/precompile/dex.rs +++ b/runtime/common/src/precompile/dex.rs @@ -16,17 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputPricer, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use frame_support::traits::Get; use module_dex::WeightInfo; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_support::{DEXManager, SwapLimit}; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -64,23 +61,16 @@ where Runtime: module_evm::Config + module_dex::Config + module_prices::Config, module_dex::Pallet: DEXManager, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::< Action, Runtime::AccountId, Runtime::AddressMapping, ::Erc20InfoMapping, - >::new(input, target_gas_limit(target_gas)); - - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } + >::new(handle.input()); let action = input.action()?; @@ -102,9 +92,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint_tuple(vec![balance_a, balance_b]), - logs: Default::default(), }) } Action::GetLiquidityTokenAddress => { @@ -122,9 +110,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_address(address), - logs: Default::default(), }) } Action::GetSwapTargetAmount => { @@ -148,9 +134,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(target), - logs: Default::default(), }) } Action::GetSwapSupplyAmount => { @@ -174,9 +158,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(supply), - logs: Default::default(), }) } Action::SwapWithExactSupply => { @@ -198,17 +180,15 @@ where let (_, value) = as DEXManager>::swap_with_specific_path(&who, &path, SwapLimit::ExactSupply(supply_amount, min_target_amount)) .map_err(|e| - PrecompileFailure::Revert { - exit_status: ExitRevert::Reverted, - output: Into::<&str>::into(e).as_bytes().to_vec(), - cost: target_gas_limit(target_gas).unwrap_or_default(), - })?; + PrecompileFailure::Revert { + exit_status: ExitRevert::Reverted, + output: Into::<&str>::into(e).as_bytes().to_vec(), + } + )?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(value), - logs: Default::default(), }) } Action::SwapWithExactTarget => { @@ -230,17 +210,15 @@ where let (value, _) = as DEXManager>::swap_with_specific_path(&who, &path, SwapLimit::ExactTarget(max_supply_amount, target_amount)) .map_err(|e| - PrecompileFailure::Revert { - exit_status: ExitRevert::Reverted, - output: Output::encode_error_msg("DEX SwapWithExactTarget failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), - })?; + PrecompileFailure::Revert { + exit_status: ExitRevert::Reverted, + output: Output::encode_error_msg("DEX SwapWithExactTarget failed", e), + } + )?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(value), - logs: Default::default(), }) } Action::AddLiquidity => { @@ -269,14 +247,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("DEX AddLiquidity failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::RemoveLiquidity => { @@ -305,14 +280,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("DEX RemoveLiquidity failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } } @@ -327,14 +299,13 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input< + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::< Action, Runtime::AccountId, Runtime::AddressMapping, ::Erc20InfoMapping, - >, - ) -> Result { + >::new(handle.input()); let action = input.action()?; let cost: u64 = match action { @@ -483,7 +454,7 @@ mod tests { use crate::precompile::mock::{alice_evm_addr, new_test_ext, DexModule, RuntimeOrigin, Test, ALICE, AUSD, DOT}; use frame_support::{assert_noop, assert_ok}; use hex_literal::hex; - use module_evm::ExitRevert; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context, ExitRevert}; type DEXPrecompile = crate::DEXPrecompile; @@ -525,7 +496,7 @@ mod tests { 00000000000000000000000000000000 000000000000000000000000000f4240 "}; - let resp = DEXPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = DEXPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -567,7 +538,7 @@ mod tests { 000000000000000000000000 0000000000000000000200000000010000000002 "}; - let resp = DEXPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = DEXPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -581,11 +552,10 @@ mod tests { "}; assert_noop!( - DEXPrecompile::execute(&input, Some(10_000), &context, false), + DEXPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(10_000), &context, false)), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid currency id".into(), - cost: target_gas_limit(Some(10_000)).unwrap(), } ); }); @@ -633,7 +603,7 @@ mod tests { 00000000000000000000000000000000 000000000000000000000000000003dd "}; - let resp = DEXPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = DEXPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -681,7 +651,7 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000001 "}; - let resp = DEXPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = DEXPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -733,7 +703,7 @@ mod tests { 00000000000000000000000000000000 000000000000000000000000000003dd "}; - let resp = DEXPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = DEXPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -785,7 +755,7 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000001 "}; - let resp = DEXPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = DEXPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); diff --git a/runtime/common/src/precompile/evm.rs b/runtime/common/src/precompile/evm.rs index 3d533b0aa0..a2daba7aa9 100644 --- a/runtime/common/src/precompile/evm.rs +++ b/runtime/common/src/precompile/evm.rs @@ -18,14 +18,13 @@ use super::{ input::{Input, InputPricer, InputT, Output}, - target_gas_limit, weights::PrecompileWeights, }; use crate::WeightToGas; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, WeightInfo, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, WeightInfo, }; use module_support::EVMManager; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -67,22 +66,14 @@ where Runtime: module_evm::Config + module_prices::Config, module_evm::Pallet: EVMManager, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -90,18 +81,14 @@ where let output = module_evm::Pallet::::query_new_contract_extra_bytes(); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(output), - logs: Default::default(), }) } Action::QueryStorageDepositPerByte => { let deposit = module_evm::Pallet::::query_storage_deposit_per_byte(); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(deposit), - logs: Default::default(), }) } Action::QueryMaintainer => { @@ -111,33 +98,26 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Into::<&str>::into(e).as_bytes().to_vec(), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_address(maintainer), - logs: Default::default(), }) } Action::QueryDeveloperDeposit => { let deposit = module_evm::Pallet::::query_developer_deposit(); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(deposit), - logs: Default::default(), }) } Action::QueryPublicationFee => { let fee = module_evm::Pallet::::query_publication_fee(); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(fee), - logs: Default::default(), }) } Action::TransferMaintainer => { @@ -159,14 +139,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Evm TransferMaintainer failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::PublishContract => { @@ -176,15 +153,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Evm PublishContract failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::DisableDeveloperAccount => { @@ -193,15 +167,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Evm DisableDeveloperAccount failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::EnableDeveloperAccount => { @@ -210,15 +181,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Evm EnableDeveloperAccount failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::QueryDeveloperStatus => { @@ -226,9 +194,7 @@ where let developer_status = >::query_developer_status(who); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bool(developer_status), - logs: Default::default(), }) } } @@ -243,9 +209,10 @@ where { const BASE_COST: u64 = 50; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); let action = input.action()?; let cost = match action { Action::QueryNewContractExtraBytes => { @@ -315,7 +282,7 @@ mod tests { }; use frame_support::assert_ok; use hex_literal::hex; - use module_evm::{ExitReason, Runner}; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context, ExitError, ExitReason, Runner}; use sp_core::H160; type EVMPrecompile = crate::EVMPrecompile; @@ -341,7 +308,7 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000000 "}; - let resp = EVMPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = EVMPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -352,7 +319,7 @@ mod tests { 000000000000000000000000 1000000000000000000000000000000000000001 "}; - let resp = EVMPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = EVMPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, [0u8; 0].to_vec()); @@ -370,7 +337,7 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000001 "}; - let resp = EVMPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = EVMPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -383,7 +350,7 @@ mod tests { 000000000000000000000000 1000000000000000000000000000000000000001 "}; - let resp = EVMPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = EVMPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, [0u8; 0].to_vec()); @@ -401,7 +368,7 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000000 "}; - let resp = EVMPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = EVMPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -492,7 +459,7 @@ mod tests { "}; // publish contract with precompile - let resp = EVMPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = EVMPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, [0u8; 0].to_vec()); diff --git a/runtime/common/src/precompile/evm_accounts.rs b/runtime/common/src/precompile/evm_accounts.rs index 3cf4fa774d..14e6ffaa18 100644 --- a/runtime/common/src/precompile/evm_accounts.rs +++ b/runtime/common/src/precompile/evm_accounts.rs @@ -16,16 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputT, Output}; use crate::WeightToGas; use frame_support::{pallet_prelude::IsType, traits::Get}; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_evm_accounts::WeightInfo; use module_support::EVMAccountsManager; @@ -57,22 +54,14 @@ where Runtime: module_evm_accounts::Config + module_prices::Config, module_evm_accounts::Pallet: EVMAccountsManager, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -82,9 +71,7 @@ where let output = module_evm_accounts::Pallet::::get_account_id(&address); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_fixed_bytes(output.into().as_ref()), - logs: Default::default(), }) } Action::GetEvmAddress => { @@ -100,9 +87,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_address(address), - logs: Default::default(), }) } Action::ClaimDefaultEvmAddress => { @@ -118,15 +103,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("EvmAccounts ClaimDefaultEvmAddress failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_address(address), - logs: Default::default(), }) } } @@ -141,9 +123,10 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); let action = input.action()?; let cost = match action { Action::GetAccountId => { @@ -172,6 +155,7 @@ mod tests { use crate::precompile::mock::{alice_evm_addr, new_test_ext, EvmAddress, Test, ALICE}; use frame_support::assert_noop; use hex_literal::hex; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context}; use parity_scale_codec::Encode; use sp_core::blake2_256; use std::str::FromStr; @@ -199,7 +183,8 @@ mod tests { 65766d3a 1000000000000000000000000000000000000001 0000000000000000 "}; - let resp = EVMAccountsPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + EVMAccountsPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -226,7 +211,8 @@ mod tests { 000000000000000000000000 1000000000000000000000000000000000000001 "}; - let resp = EVMAccountsPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + EVMAccountsPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -242,7 +228,8 @@ mod tests { 000000000000000000000000 0000000000000000000000000000000000000000 "}; - let resp = EVMAccountsPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + EVMAccountsPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -276,17 +263,17 @@ mod tests { 000000000000000000000000 8f2703bbe0abeaf09b384374959ffac5f7d0d69f "}; - let resp = EVMAccountsPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + EVMAccountsPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); // call again, the evm address already mapped assert_noop!( - EVMAccountsPrecompile::execute(&input, Some(100_000), &context, false), + EVMAccountsPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(100_000), &context, false)), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "EvmAccounts ClaimDefaultEvmAddress failed: AccountIdHasMapped".into(), - cost: target_gas_limit(Some(100_000)).unwrap(), } ); }); diff --git a/runtime/common/src/precompile/homa.rs b/runtime/common/src/precompile/homa.rs index dcbb0e0e3f..62eb56ce30 100644 --- a/runtime/common/src/precompile/homa.rs +++ b/runtime/common/src/precompile/homa.rs @@ -16,16 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputPricer, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use frame_support::traits::Get; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_support::HomaManager; @@ -66,23 +63,16 @@ where Runtime: module_evm::Config + module_homa::Config + module_prices::Config, module_homa::Pallet: HomaManager, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::< Action, Runtime::AccountId, ::AddressMapping, Runtime::Erc20InfoMapping, - >::new(input, target_gas_limit(target_gas)); - - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } + >::new(handle.input()); let action = input.action()?; @@ -101,15 +91,12 @@ where |e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Homa Mint failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), }, )?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::RequestRedeem => { @@ -129,14 +116,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Homa RequestRedeem failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::GetExchangeRate => { @@ -144,18 +128,14 @@ where as HomaManager>::get_exchange_rate(); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(rate.into_inner()), - logs: Default::default(), }) } Action::GetEstimatedRewardRate => { let rate = as HomaManager>::get_estimated_reward_rate(); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(rate.into_inner()), - logs: Default::default(), }) } Action::GetCommissionRate => { @@ -163,9 +143,7 @@ where as HomaManager>::get_commission_rate(); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(rate.into_inner()), - logs: Default::default(), }) } Action::GetFastMatchFee => { @@ -173,9 +151,7 @@ where as HomaManager>::get_fast_match_fee(); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(rate.into_inner()), - logs: Default::default(), }) } } @@ -190,9 +166,10 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); let action = input.action()?; let cost: u64 = match action { @@ -240,6 +217,7 @@ mod tests { }; use frame_support::assert_ok; use hex_literal::hex; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context}; use sp_runtime::{FixedPointNumber, FixedU128}; type HomaPrecompile = super::HomaPrecompile; @@ -283,7 +261,7 @@ mod tests { 00000000000000000000000000000000 0000000000000000000000003b9aca00 "}; - let res = HomaPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HomaPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); }); @@ -332,7 +310,7 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000000 "}; - let res = HomaPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HomaPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); }); @@ -355,7 +333,7 @@ mod tests { // encoded value of FixedU128::saturating_from_rational(1,10); let expected_output = hex! {"00000000000000000000000000000000 0000000000000000016345785d8a0000"}.to_vec(); - let res = HomaPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HomaPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output); }); @@ -386,7 +364,7 @@ mod tests { // encoded value of FixedU128::saturating_from_rational(1,10); let expected_output = hex! {"00000000000000000000000000000000 0000000000000000016345785d8a0000"}.to_vec(); - let res = HomaPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HomaPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output); }); @@ -415,7 +393,7 @@ mod tests { // encoded value of FixedU128::saturating_from_rational(1,10); let expected_output = hex! {"00000000000000000000000000000000 0000000000000000016345785d8a0000"}.to_vec(); - let res = HomaPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HomaPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output); }); @@ -444,7 +422,7 @@ mod tests { // encoded value of FixedU128::saturating_from_rational(1,10); let expected_output = hex! {"00000000000000000000000000000000 0000000000000000016345785d8a0000"}.to_vec(); - let res = HomaPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HomaPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output); }); diff --git a/runtime/common/src/precompile/honzon.rs b/runtime/common/src/precompile/honzon.rs index 381d35ca6e..b00c4e5399 100644 --- a/runtime/common/src/precompile/honzon.rs +++ b/runtime/common/src/precompile/honzon.rs @@ -16,16 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputPricer, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use frame_support::traits::Get; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_honzon::WeightInfo; use module_support::HonzonManager; @@ -64,22 +61,14 @@ where Runtime: module_evm::Config + module_honzon::Config + module_prices::Config, module_honzon::Pallet: HonzonManager, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -104,15 +93,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Honzon AdjustLoan failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } )?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::CloseLoanByDex => { @@ -135,15 +121,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Honzon CloseLoanByDex failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } )?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::GetPosition => { @@ -159,9 +142,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint_tuple(vec![collateral, debit]), - logs: Default::default(), }) } Action::GetCollateralParameters => { @@ -175,9 +156,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint_array(params), - logs: Default::default(), }) } Action::GetCurrentCollateralRatio => { @@ -193,9 +172,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(ratio.into_inner()), - logs: Default::default(), }) } Action::GetDebitExchangeRate => { @@ -209,9 +186,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(exchange_rate.into_inner()), - logs: Default::default(), }) } } @@ -226,9 +201,10 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); let action = input.action()?; let cost: u64 = match action { @@ -311,6 +287,7 @@ mod tests { }; use frame_support::assert_ok; use hex_literal::hex; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context}; use module_support::{Rate, Ratio}; use orml_traits::Change; use sp_runtime::FixedPointNumber; @@ -354,7 +331,7 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000001000 "}; - let res = HonzonPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HonzonPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(Loans::positions(DOT, alice()).collateral, 268435456); assert_eq!(Loans::positions(DOT, alice()).debit, 4096) @@ -432,7 +409,7 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000100000000 "}; - let res = HonzonPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HonzonPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(Loans::positions(DOT, alice()).debit, 0); @@ -485,7 +462,7 @@ mod tests { 00000000000000000000000000000000 0000000000000000000000174876e800 00000000000000000000000000000000 000000000000000000000000000f4240 "}; - let res = HonzonPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HonzonPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); }); @@ -533,7 +510,7 @@ mod tests { 00000000000000000000000000000000 000000000000000018fae27693b40000 "}; - let res = HonzonPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HonzonPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); }); @@ -582,7 +559,7 @@ mod tests { let expected_output = hex! {" 00000000000000000000000000000000 000000000000152d02c7e14af6800000 "}; - let res = HonzonPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HonzonPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); }); @@ -617,7 +594,7 @@ mod tests { let expected_output = hex! {" 00000000000000000000000000000000 00000000000000000de0b6b3a7640000 "}; - let res = HonzonPrecompile::execute(&input, None, &context, false).unwrap(); + let res = HonzonPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); }) diff --git a/runtime/common/src/precompile/incentives.rs b/runtime/common/src/precompile/incentives.rs index 89d68caead..e9ef10f336 100644 --- a/runtime/common/src/precompile/incentives.rs +++ b/runtime/common/src/precompile/incentives.rs @@ -16,16 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputPricer, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use frame_support::traits::Get; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_incentives::WeightInfo; use module_support::{IncentivesManager, PoolId}; @@ -65,22 +62,14 @@ where Runtime: module_evm::Config + module_incentives::Config + module_prices::Config, module_incentives::Pallet: IncentivesManager, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -88,7 +77,7 @@ where let pool = input.u32_at(1)?; let pool_currency_id = input.currency_id_at(2)?; let reward_currency_id = input.currency_id_at(3)?; - let pool_id = init_pool_id(pool, pool_currency_id, target_gas)?; + let pool_id = init_pool_id(pool, pool_currency_id)?; let value = as IncentivesManager< Runtime::AccountId, @@ -99,9 +88,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(value), - logs: Default::default(), }) } Action::DepositDexShare => { @@ -118,14 +105,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Incentives DepositDexShare failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::WithdrawDexShare => { @@ -142,21 +126,18 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Incentives WithdrawDexShare failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::ClaimRewards => { let who = input.account_id_at(1)?; let pool = input.u32_at(2)?; let pool_currency_id = input.currency_id_at(3)?; - let pool_id = init_pool_id(pool, pool_currency_id, target_gas)?; + let pool_id = init_pool_id(pool, pool_currency_id)?; as IncentivesManager< Runtime::AccountId, @@ -167,20 +148,17 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Incentives ClaimRewards failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::GetClaimRewardDeductionRate => { let pool = input.u32_at(1)?; let pool_currency_id = input.currency_id_at(2)?; - let pool_id = init_pool_id(pool, pool_currency_id, target_gas)?; + let pool_id = init_pool_id(pool, pool_currency_id)?; let value = as IncentivesManager< Runtime::AccountId, @@ -191,16 +169,14 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(value.into_inner()), - logs: Default::default(), }) } Action::GetPendingRewards => { // solidity abi encode array will add an offset at input[1] let pool = input.u32_at(2)?; let pool_currency_id = input.currency_id_at(3)?; - let pool_id = init_pool_id(pool, pool_currency_id, target_gas)?; + let pool_id = init_pool_id(pool, pool_currency_id)?; let who = input.account_id_at(4)?; let reward_currency_ids_len = input.u32_at(5)?; let mut reward_currency_ids = vec![]; @@ -217,9 +193,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint_array(value), - logs: Default::default(), }) } } @@ -234,9 +208,10 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); let action = input.action()?; let cost: u64 = match action { @@ -322,11 +297,7 @@ where } } -fn init_pool_id( - pool_id_number: u32, - pool_currency_id: CurrencyId, - target_gas: Option, -) -> Result { +fn init_pool_id(pool_id_number: u32, pool_currency_id: CurrencyId) -> Result { match pool_id_number { 0 => Ok(PoolId::Loans(pool_currency_id)), 1 => Ok(PoolId::Dex(pool_currency_id)), @@ -334,7 +305,6 @@ fn init_pool_id( _ => Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Incentives: Invalid enum value".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), }), } } @@ -348,6 +318,7 @@ mod tests { }; use frame_support::assert_ok; use hex_literal::hex; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context}; use module_support::Rate; use orml_rewards::PoolInfo; use orml_traits::MultiCurrency; @@ -385,7 +356,8 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000064 "}; - let res = IncentivesPrecompile::execute(&input, None, &context, false).unwrap(); + let res = + IncentivesPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); }); @@ -413,7 +385,8 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000100000 "}; - let res = IncentivesPrecompile::execute(&input, None, &context, false).unwrap(); + let res = + IncentivesPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!( @@ -457,7 +430,8 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000100 "}; - let res = IncentivesPrecompile::execute(&input, None, &context, false).unwrap(); + let res = + IncentivesPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!( @@ -524,7 +498,8 @@ mod tests { 000000000000000000000000 0000000000000000000100000000000000000000 "}; - let res = IncentivesPrecompile::execute(&input, None, &context, false).unwrap(); + let res = + IncentivesPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!( @@ -569,7 +544,8 @@ mod tests { 00000000000000000000000000000000 0000000000000000016345785d8a0000 "}; - let res = IncentivesPrecompile::execute(&input, None, &context, false).unwrap(); + let res = + IncentivesPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); }); @@ -644,7 +620,8 @@ mod tests { 00000000000000000000000000000000 000000000000000000000000000001f4 "}; - let res = IncentivesPrecompile::execute(&input, None, &context, false).unwrap(); + let res = + IncentivesPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); }) diff --git a/runtime/common/src/precompile/input.rs b/runtime/common/src/precompile/input.rs index a5307b9650..711a484e0a 100644 --- a/runtime/common/src/precompile/input.rs +++ b/runtime/common/src/precompile/input.rs @@ -61,16 +61,14 @@ pub trait InputT { pub struct Input<'a, Action, AccountId, AddressMapping, Erc20InfoMapping> { content: &'a [u8], - target_gas: Option, _marker: PhantomData<(Action, AccountId, AddressMapping, Erc20InfoMapping)>, } impl<'a, Action, AccountId, AddressMapping, Erc20InfoMapping> Input<'a, Action, AccountId, AddressMapping, Erc20InfoMapping> { - pub fn new(content: &'a [u8], target_gas: Option) -> Self { + pub fn new(content: &'a [u8]) -> Self { Self { content, - target_gas, _marker: PhantomData, } } @@ -104,7 +102,6 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid input".into(), - cost: self.target_gas.unwrap_or_default(), } ); @@ -116,13 +113,11 @@ where let action = u32::from_be_bytes(param.try_into().map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid action".into(), - cost: self.target_gas.unwrap_or_default(), })?); action.try_into().map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid action".into(), - cost: self.target_gas.unwrap_or_default(), }) } @@ -150,7 +145,6 @@ where Erc20InfoMapping::decode_evm_address(address).ok_or_else(|| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid currency id".into(), - cost: self.target_gas.unwrap_or_default(), }) } @@ -159,7 +153,6 @@ where decode_i128(param).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to decode i128".into(), - cost: self.target_gas.unwrap_or_default(), }) } @@ -173,7 +166,6 @@ where param.try_into().map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to convert uint256 into Balance".into(), - cost: self.target_gas.unwrap_or_default(), }) } @@ -182,7 +174,6 @@ where param.try_into().map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to convert uint256 into u64".into(), - cost: self.target_gas.unwrap_or_default(), }) } @@ -191,7 +182,6 @@ where param.try_into().map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to convert uint256 into u32".into(), - cost: self.target_gas.unwrap_or_default(), }) } @@ -222,7 +212,6 @@ where Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to decode bool".into(), - cost: self.target_gas.unwrap_or_default(), }) } } @@ -368,7 +357,7 @@ mod tests { 00000000 ffffffffffffffffffffffffffffffff00000000000000000000000000000001 "}; - let input = TestInput::new(&data[..], Some(10)); + let input = TestInput::new(&data[..]); assert_ok!( input.nth_param(1, None), &hex!("ffffffffffffffffffffffffffffffff00000000000000000000000000000001")[..] @@ -378,29 +367,27 @@ mod tests { PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid input".into(), - cost: 10, } ); } #[test] fn action_works() { - let input = TestInput::new(&hex!("00000000")[..], None); + let input = TestInput::new(&hex!("00000000")[..]); assert_ok!(input.action(), Action::QueryBalance); - let input = TestInput::new(&hex!("00000001")[..], None); + let input = TestInput::new(&hex!("00000001")[..]); assert_ok!(input.action(), Action::Transfer); - let input = TestInput::new(&hex!("00000002")[..], None); + let input = TestInput::new(&hex!("00000002")[..]); assert_ok!(input.action(), Action::Unknown); - let input = TestInput::new(&hex!("00000003")[..], Some(10)); + let input = TestInput::new(&hex!("00000003")[..]); assert_eq!( input.action(), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid action".into(), - cost: 10, }) ); } @@ -415,7 +402,7 @@ mod tests { ffffffffffffffffffffffff ff00000000000000000000000000000000000003 "}; - let input = TestInput::new(&data[..], None); + let input = TestInput::new(&data[..]); assert_ok!( input.account_id_at(1), MockAddressMapping::get_account_id(&H160::from_str("ff00000000000000000000000000000000000001").unwrap()) @@ -439,7 +426,7 @@ mod tests { ffffffffffffffffffffffff 0000000000000000000000000000000000000002 ffffffffffffffffffffffff ff00000000000000000000000000000000000003 "}; - let input = TestInput::new(&data[..], None); + let input = TestInput::new(&data[..]); assert_ok!( input.evm_address_at(1), H160::from_str("ff00000000000000000000000000000000000001").unwrap() @@ -456,13 +443,12 @@ mod tests { #[test] fn currency_id_works() { - let input = TestInput::new(&[0u8; 100][..], Some(10)); + let input = TestInput::new(&[0u8; 100][..]); assert_err!( input.currency_id_at(1), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid currency id".into(), - cost: 10, } ); @@ -474,7 +460,7 @@ mod tests { ffffffffffffffffffffffff 0000000000000000000100000000000000000002 "}; - let input = TestInput::new(&data[..], None); + let input = TestInput::new(&data[..]); assert_ok!(input.currency_id_at(1), CurrencyId::Token(TokenSymbol::ACA)); assert_ok!(input.currency_id_at(2), CurrencyId::Token(TokenSymbol::AUSD)); assert_ok!(input.currency_id_at(3), CurrencyId::Token(TokenSymbol::DOT)); @@ -488,7 +474,7 @@ mod tests { 00000000000000000000000000000000ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff "}; - let input = TestInput::new(&data[..], None); + let input = TestInput::new(&data[..]); assert_ok!(input.u256_at(1), U256::from(127u128)); assert_ok!(input.u256_at(2), U256::from(u128::MAX)); assert_ok!(input.u256_at(3), U256::MAX); @@ -502,7 +488,7 @@ mod tests { 00000000000000000000000000000000 ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffff ffffffffffffffffffffffffffffffff "}; - let input = TestInput::new(&data[..], Some(10)); + let input = TestInput::new(&data[..]); assert_ok!(input.balance_at(1), 127u128); assert_ok!(input.balance_at(2), u128::MAX); assert_eq!( @@ -510,7 +496,6 @@ mod tests { Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to convert uint256 into Balance".into(), - cost: 10, }) ); } @@ -523,7 +508,7 @@ mod tests { 000000000000000000000000000000000000000000000000 ffffffffffffffff 000000000000000000000000000000000000000000000001 ffffffffffffffff "}; - let input = TestInput::new(&data[..], Some(10)); + let input = TestInput::new(&data[..]); assert_ok!(input.u64_at(1), 127u64); assert_ok!(input.u64_at(2), u64::MAX); assert_eq!( @@ -531,7 +516,6 @@ mod tests { Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to convert uint256 into u64".into(), - cost: 10, }) ); } @@ -544,7 +528,7 @@ mod tests { 00000000000000000000000000000000000000000000000000000000 ffffffff 00000000000000000000000000000000000000000000000000000001 ffffffff "}; - let input = TestInput::new(&data[..], Some(10)); + let input = TestInput::new(&data[..]); assert_ok!(input.u32_at(1), 127u32); assert_ok!(input.u32_at(2), u32::MAX); assert_eq!( @@ -552,7 +536,6 @@ mod tests { Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to convert uint256 into u32".into(), - cost: 10, }) ); } @@ -568,14 +551,13 @@ mod tests { ff000000000000000000000000000000 ffffffffffffffffffffffffffffffff 00000000000000000000000000000000 00000000000000000000000000000000 "}; - let input = TestInput::new(&data[..], Some(10)); + let input = TestInput::new(&data[..]); assert_ok!(input.i128_at(1), 127_i128); assert_eq!( input.i128_at(2), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to decode i128".into(), - cost: 10, }) ); assert_ok!(input.i128_at(3), -1_i128); @@ -585,7 +567,6 @@ mod tests { Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to decode i128".into(), - cost: 10, }) ); assert_ok!(input.i128_at(6), 0); @@ -599,7 +580,7 @@ mod tests { 0000000000000000000000000000000000000000000000000000000000000001 0000000000000000000000000000000000000000000000000000000000000002 "}; - let input = TestInput::new(&data[..], Some(10)); + let input = TestInput::new(&data[..]); assert_ok!(input.bool_at(1), false); assert_ok!(input.bool_at(2), true); assert_eq!( @@ -607,7 +588,6 @@ mod tests { Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "failed to decode bool".into(), - cost: 10, }) ); } diff --git a/runtime/common/src/precompile/liquid_crowdloan.rs b/runtime/common/src/precompile/liquid_crowdloan.rs index c701fcd041..ced1c09264 100644 --- a/runtime/common/src/precompile/liquid_crowdloan.rs +++ b/runtime/common/src/precompile/liquid_crowdloan.rs @@ -16,15 +16,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputPricer, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_liquid_crowdloan::WeightInfo; use module_support::Erc20InfoMapping as _; @@ -48,22 +45,14 @@ impl Precompile for LiquidCrowdloanPrecompile where Runtime: module_evm::Config + module_prices::Config + module_liquid_crowdloan::Config, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -76,16 +65,13 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("LiquidCrowdloan redeem failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; log::debug!(target: "evm", "liuqid_crowdloan: Redeem who: {:?}, amount: {:?}, output: {:?}", who, amount, redeem_amount); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(redeem_amount), - logs: Default::default(), }) } Action::GetRedeemCurrency => { @@ -96,9 +82,7 @@ where log::debug!(target: "evm", "liuqid_crowdloan: GetRedeemCurrency output: {:?}", address); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_address(address), - logs: Default::default(), }) } } @@ -113,9 +97,10 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); let action = input.action()?; let cost = match action { @@ -143,6 +128,7 @@ mod tests { }; use frame_support::assert_ok; use hex_literal::hex; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context}; use orml_traits::MultiCurrency; use sp_runtime::traits::AccountIdConversion; @@ -185,7 +171,8 @@ mod tests { 00000000000000000000000000000000 0000000000000000000000003b9aca00 "}; - let res = LiquidCrowdloanPrecompile::execute(&input, None, &context, false).unwrap(); + let res = LiquidCrowdloanPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); @@ -233,7 +220,8 @@ mod tests { 00000000000000000000000000000000 0000000000000000000000028fa6ae00 "}; - let res = LiquidCrowdloanPrecompile::execute(&input, None, &context, false).unwrap(); + let res = LiquidCrowdloanPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); @@ -259,7 +247,8 @@ mod tests { 000000000000000000000000 0000000000000000000100000000000000000002 "}; - let res = LiquidCrowdloanPrecompile::execute(&input, None, &context, false).unwrap(); + let res = LiquidCrowdloanPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); @@ -270,7 +259,8 @@ mod tests { 000000000000000000000000 0000000000000000000100000000000000000003 "}; - let res = LiquidCrowdloanPrecompile::execute(&input, None, &context, false).unwrap(); + let res = LiquidCrowdloanPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(res.exit_status, ExitSucceed::Returned); assert_eq!(res.output, expected_output.to_vec()); }); diff --git a/runtime/common/src/precompile/mod.rs b/runtime/common/src/precompile/mod.rs index 7c0c510919..75fad712d5 100644 --- a/runtime/common/src/precompile/mod.rs +++ b/runtime/common/src/precompile/mod.rs @@ -31,8 +31,8 @@ use module_evm::{ Blake2F, Bn128Add, Bn128Mul, Bn128Pairing, ECRecover, ECRecoverPublicKey, Identity, IstanbulModexp, Modexp, Precompile, Ripemd160, Sha256, Sha3FIPS256, Sha3FIPS512, }, - runner::state::{PrecompileFailure, PrecompileResult, PrecompileSet}, - Context, ExitRevert, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileResult, PrecompileSet}, + ExitRevert, }; use module_support::{PrecompileCallerFilter, PrecompilePauseFilter}; use sp_core::H160; @@ -98,10 +98,6 @@ pub const INCENTIVES: H160 = H160(hex!("000000000000000000000000000000000000040a pub const XTOKENS: H160 = H160(hex!("000000000000000000000000000000000000040b")); pub const LIQUID_CROWDLOAN: H160 = H160(hex!("000000000000000000000000000000000000040c")); -pub fn target_gas_limit(target_gas: Option) -> Option { - target_gas.map(|x| x.saturating_div(10).saturating_mul(9)) // 90% -} - pub struct AllPrecompiles { set: BTreeSet, _marker: PhantomData<(R, F, E)>, @@ -236,14 +232,9 @@ where IncentivesPrecompile: Precompile, XtokensPrecompile: Precompile, { - fn execute( - &self, - address: H160, - input: &[u8], - target_gas: Option, - context: &Context, - is_static: bool, - ) -> Option { + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { + let context = handle.context(); + let address = handle.code_address(); if !self.is_precompile(address) { return None; } @@ -254,7 +245,6 @@ where return Some(Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "precompile is paused".into(), - cost: target_gas.unwrap_or_default(), })); } @@ -263,43 +253,42 @@ where return Some(Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "cannot be called with DELEGATECALL or CALLCODE".into(), - cost: target_gas.unwrap_or_default(), })); } - log::trace!(target: "evm", "Precompile begin, address: {:?}, input: {:?}, target_gas: {:?}, context: {:?}", address, input, target_gas, context); + log::trace!(target: "evm", "Precompile begin, address: {:?}, input: {:?}, context: {:?}", address, handle.input(), context); // https://github.com/ethereum/go-ethereum/blob/9357280fce5c5d57111d690a336cca5f89e34da6/core/vm/contracts.go#L83 let result = if address == ECRECOVER { - Some(ECRecover::execute(input, target_gas, context, is_static)) + Some(ECRecover::execute(handle)) } else if address == SHA256 { - Some(Sha256::execute(input, target_gas, context, is_static)) + Some(Sha256::execute(handle)) } else if address == RIPEMD { - Some(Ripemd160::execute(input, target_gas, context, is_static)) + Some(Ripemd160::execute(handle)) } else if address == IDENTITY { - Some(Identity::execute(input, target_gas, context, is_static)) + Some(Identity::execute(handle)) } else if address == MODEXP { if R::config().increase_state_access_gas { - Some(Modexp::execute(input, target_gas, context, is_static)) + Some(Modexp::execute(handle)) } else { - Some(IstanbulModexp::execute(input, target_gas, context, is_static)) + Some(IstanbulModexp::execute(handle)) } } else if address == BN_ADD { - Some(Bn128Add::execute(input, target_gas, context, is_static)) + Some(Bn128Add::execute(handle)) } else if address == BN_MUL { - Some(Bn128Mul::execute(input, target_gas, context, is_static)) + Some(Bn128Mul::execute(handle)) } else if address == BN_PAIRING { - Some(Bn128Pairing::execute(input, target_gas, context, is_static)) + Some(Bn128Pairing::execute(handle)) } else if address == BLAKE2F { - Some(Blake2F::execute(input, target_gas, context, is_static)) + Some(Blake2F::execute(handle)) } // Non-standard precompile starts with 128 else if address == ECRECOVER_PUBLICKEY { - Some(ECRecoverPublicKey::execute(input, target_gas, context, is_static)) + Some(ECRecoverPublicKey::execute(handle)) } else if address == SHA3_256 { - Some(Sha3FIPS256::execute(input, target_gas, context, is_static)) + Some(Sha3FIPS256::execute(handle)) } else if address == SHA3_512 { - Some(Sha3FIPS512::execute(input, target_gas, context, is_static)) + Some(Sha3FIPS512::execute(handle)) } // Acala precompile else { @@ -308,7 +297,6 @@ where return Some(Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "NoPermission".into(), - cost: target_gas.unwrap_or_default(), })); } @@ -317,48 +305,39 @@ where return Some(Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Caller is not a system contract".into(), - cost: target_gas.unwrap_or_default(), })); } if address == MULTI_CURRENCY { - Some(MultiCurrencyPrecompile::::execute( - input, target_gas, context, is_static, - )) + Some(MultiCurrencyPrecompile::::execute(handle)) } else if address == NFT { - Some(NFTPrecompile::::execute(input, target_gas, context, is_static)) + Some(NFTPrecompile::::execute(handle)) } else if address == EVM { - Some(EVMPrecompile::::execute(input, target_gas, context, is_static)) + Some(EVMPrecompile::::execute(handle)) } else if address == ORACLE { - Some(OraclePrecompile::::execute(input, target_gas, context, is_static)) + Some(OraclePrecompile::::execute(handle)) } else if address == SCHEDULER { - Some(SchedulePrecompile::::execute(input, target_gas, context, is_static)) + Some(SchedulePrecompile::::execute(handle)) } else if address == DEX { - Some(DEXPrecompile::::execute(input, target_gas, context, is_static)) + Some(DEXPrecompile::::execute(handle)) } else if address == STABLE_ASSET { - Some(StableAssetPrecompile::::execute( - input, target_gas, context, is_static, - )) + Some(StableAssetPrecompile::::execute(handle)) } else if address == HOMA { - Some(HomaPrecompile::::execute(input, target_gas, context, is_static)) + Some(HomaPrecompile::::execute(handle)) } else if address == EVM_ACCOUNTS { - Some(EVMAccountsPrecompile::::execute( - input, target_gas, context, is_static, - )) + Some(EVMAccountsPrecompile::::execute(handle)) } else if address == HONZON { - Some(HonzonPrecompile::::execute(input, target_gas, context, is_static)) + Some(HonzonPrecompile::::execute(handle)) } else if address == INCENTIVES { - Some(IncentivesPrecompile::::execute( - input, target_gas, context, is_static, - )) + Some(IncentivesPrecompile::::execute(handle)) } else if address == XTOKENS { - Some(XtokensPrecompile::::execute(input, target_gas, context, is_static)) + Some(XtokensPrecompile::::execute(handle)) } else { - E::execute(&Default::default(), address, input, target_gas, context, is_static) + E::execute(&Default::default(), handle) } }; - log::trace!(target: "evm", "Precompile end, address: {:?}, input: {:?}, target_gas: {:?}, context: {:?}, result: {:?}", address, input, target_gas, context, result); + log::trace!(target: "evm", "Precompile end, address: {:?}, input: {:?}, context: {:?}, result: {:?}", address, handle.input(), handle.context(), result); if let Some(Err(PrecompileFailure::Revert { ref output, .. })) = result { log::debug!(target: "evm", "Precompile failed: {:?}", core::str::from_utf8(output)); }; @@ -382,16 +361,10 @@ impl PrecompileSet for AcalaPrecompiles where LiquidCrowdloanPrecompile: Precompile, { - fn execute( - &self, - address: H160, - input: &[u8], - gas_limit: Option, - context: &Context, - is_static: bool, - ) -> Option { + fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { + let address = handle.code_address(); if address == LIQUID_CROWDLOAN { - Some(LiquidCrowdloanPrecompile::execute(input, gas_limit, context, is_static)) + Some(LiquidCrowdloanPrecompile::execute(handle)) } else { None } diff --git a/runtime/common/src/precompile/multicurrency.rs b/runtime/common/src/precompile/multicurrency.rs index bfad58e0cc..1855c829bf 100644 --- a/runtime/common/src/precompile/multicurrency.rs +++ b/runtime/common/src/precompile/multicurrency.rs @@ -16,10 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputPricer, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use frame_support::{ pallet_prelude::IsType, @@ -28,8 +25,8 @@ use frame_support::{ use module_currencies::WeightInfo; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_support::Erc20InfoMapping as Erc20InfoMappingT; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -69,30 +66,23 @@ where Runtime::AccountId: IsType, module_currencies::Pallet: MultiCurrencyT, { - fn execute(input: &[u8], target_gas: Option, context: &Context, _is_static: bool) -> PrecompileResult { - let input = Input::< - Action, - Runtime::AccountId, - ::AddressMapping, - Runtime::Erc20InfoMapping, - >::new(input, target_gas_limit(target_gas)); - + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let context = handle.context(); let currency_id = Runtime::Erc20InfoMapping::decode_evm_address(context.caller).ok_or_else(|| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid currency id".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; - let gas_cost = Pricer::::cost(&input, currency_id)?; + let gas_cost = Pricer::::cost(handle, currency_id)?; + handle.record_cost(gas_cost)?; - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } + let input = Input::< + Action, + Runtime::AccountId, + ::AddressMapping, + Runtime::Erc20InfoMapping, + >::new(handle.input()); let action = input.action()?; @@ -103,15 +93,12 @@ where let name = Runtime::Erc20InfoMapping::name(currency_id).ok_or_else(|| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Get name failed".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!(target: "evm", "multicurrency: name: {:?}", name); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bytes(&name), - logs: Default::default(), }) } Action::QuerySymbol => { @@ -119,15 +106,12 @@ where Runtime::Erc20InfoMapping::symbol(currency_id).ok_or_else(|| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Get symbol failed".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!(target: "evm", "multicurrency: symbol: {:?}", symbol); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bytes(&symbol), - logs: Default::default(), }) } Action::QueryDecimals => { @@ -135,15 +119,12 @@ where Runtime::Erc20InfoMapping::decimals(currency_id).ok_or_else(|| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Get decimals failed".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!(target: "evm", "multicurrency: decimals: {:?}", decimals); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(decimals), - logs: Default::default(), }) } Action::QueryTotalIssuance => { @@ -153,9 +134,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(total_issuance), - logs: Default::default(), }) } Action::QueryBalance => { @@ -170,9 +149,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(balance), - logs: Default::default(), }) } Action::Transfer => { @@ -190,14 +167,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Multicurrency Transfer failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } Action::TransferToAccountId => { @@ -219,14 +193,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Multicurrency TransferToAccountId failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: vec![], - logs: Default::default(), }) } } @@ -242,15 +213,14 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input< + fn cost(handle: &mut impl PrecompileHandle, currency_id: CurrencyId) -> Result { + let input = Input::< Action, Runtime::AccountId, ::AddressMapping, Runtime::Erc20InfoMapping, - >, - currency_id: CurrencyId, - ) -> Result { + >::new(handle.input()); + let action = input.action()?; // Decode CurrencyId from EvmAddress @@ -317,6 +287,7 @@ mod tests { }; use frame_support::assert_noop; use hex_literal::hex; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context}; type MultiCurrencyPrecompile = crate::MultiCurrencyPrecompile; @@ -336,11 +307,10 @@ mod tests { "}; assert_noop!( - MultiCurrencyPrecompile::execute(&input, Some(10_000), &context, false), + MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(10_000), &context, false)), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid currency id".into(), - cost: target_gas_limit(Some(10_000)).unwrap(), } ); }); @@ -369,7 +339,8 @@ mod tests { 4163616c61000000000000000000000000000000000000000000000000000000 "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -382,7 +353,8 @@ mod tests { 4c50204163616c61202d204163616c6120446f6c6c6172000000000000000000 "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -411,7 +383,8 @@ mod tests { 4143410000000000000000000000000000000000000000000000000000000000 "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -424,7 +397,8 @@ mod tests { 4c505f4143415f41555344000000000000000000000000000000000000000000 "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -451,14 +425,16 @@ mod tests { 00000000000000000000000000000000 0000000000000000000000000000000c "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); // DexShare context.caller = lp_aca_ausd_evm_address(); - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -486,7 +462,8 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000077359400 "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -497,7 +474,8 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000000 "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -527,7 +505,8 @@ mod tests { 00000000000000000000000000000000 0000000000000000000000e8d4a51000 "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -538,7 +517,8 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000000 "}; - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }) @@ -570,7 +550,8 @@ mod tests { // Token context.caller = aca_evm_address(); - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, [0u8; 0].to_vec()); @@ -580,11 +561,15 @@ mod tests { // DexShare context.caller = lp_aca_ausd_evm_address(); assert_noop!( - MultiCurrencyPrecompile::execute(&input, Some(100_000), &context, false), + MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &context, + false + )), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Multicurrency Transfer failed: BalanceTooLow".into(), - cost: target_gas_limit(Some(100_000)).unwrap(), } ); }) @@ -616,7 +601,8 @@ mod tests { // Token context.caller = aca_evm_address(); - let resp = MultiCurrencyPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)) + .unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, [0u8; 0].to_vec()); @@ -626,11 +612,15 @@ mod tests { // DexShare context.caller = lp_aca_ausd_evm_address(); assert_noop!( - MultiCurrencyPrecompile::execute(&input, Some(100_000), &context, false), + MultiCurrencyPrecompile::execute(&mut MockPrecompileHandle::new( + &input, + Some(100_000), + &context, + false + )), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Multicurrency TransferToAccountId failed: BalanceTooLow".into(), - cost: target_gas_limit(Some(100_000)).unwrap(), } ); }) diff --git a/runtime/common/src/precompile/nft.rs b/runtime/common/src/precompile/nft.rs index 9b157c7d7a..297557b0a0 100644 --- a/runtime/common/src/precompile/nft.rs +++ b/runtime/common/src/precompile/nft.rs @@ -16,15 +16,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputT, Output}; use frame_support::traits::tokens::nonfungibles::{Inspect, Transfer}; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_support::AddressMapping; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -60,22 +57,14 @@ where + Inspect + Transfer, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -88,9 +77,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 0, output: Output::encode_uint(balance), - logs: Default::default(), }) } Action::QueryOwner => { @@ -108,9 +95,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 0, output: Output::encode_address(owner), - logs: Default::default(), }) } Action::Transfer => { @@ -126,14 +111,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("NFT Transfer failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 0, output: vec![], - logs: Default::default(), }) } } @@ -148,9 +130,10 @@ where { pub const BASE_COST: u64 = 200; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); let _action = input.action()?; // TODO: gas cost Ok(Self::BASE_COST) diff --git a/runtime/common/src/precompile/oracle.rs b/runtime/common/src/precompile/oracle.rs index 51d810f2a3..076ce6b7a1 100644 --- a/runtime/common/src/precompile/oracle.rs +++ b/runtime/common/src/precompile/oracle.rs @@ -18,14 +18,13 @@ use super::{ input::{Input, InputPricer, InputT, Output}, - target_gas_limit, weights::PrecompileWeights, }; use crate::{Weight, WeightToGas}; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitSucceed, }; use module_support::{Erc20InfoMapping as Erc20InfoMappingT, PriceProvider as PriceProviderT}; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -52,22 +51,14 @@ impl Precompile for OraclePrecompile where Runtime: module_evm::Config + module_prices::Config, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -103,9 +94,7 @@ where log::debug!(target: "evm", "oracle: getPrice currency_id: {:?}, price: {:?}, adjustment_multiplier: {:?}, output: {:?}", currency_id, price, adjustment_multiplier, output); Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(output), - logs: Default::default(), }) } } @@ -120,9 +109,11 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); + let action = input.action()?; let cost = match action { @@ -144,7 +135,7 @@ mod tests { use crate::precompile::mock::{alice_evm_addr, new_test_ext, Oracle, Price, Test, ALICE, DOT}; use frame_support::{assert_noop, assert_ok}; use hex_literal::hex; - use module_evm::ExitRevert; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context, ExitRevert}; use orml_traits::DataFeeder; type OraclePrecompile = crate::OraclePrecompile; @@ -172,7 +163,8 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000000 "}; - let resp = OraclePrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + OraclePrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); @@ -190,7 +182,8 @@ mod tests { 00000000000000000000000000000000 000000000000065a4da25d3016c00000 "}; - let resp = OraclePrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + OraclePrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output.to_vec()); }); @@ -200,7 +193,7 @@ mod tests { fn oracle_precompile_should_handle_invalid_input() { new_test_ext().execute_with(|| { assert_noop!( - OraclePrecompile::execute( + OraclePrecompile::execute(&mut MockPrecompileHandle::new( &[0u8; 0], Some(1000), &Context { @@ -209,16 +202,15 @@ mod tests { apparent_value: Default::default() }, false - ), + )), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid input".into(), - cost: target_gas_limit(Some(1000)).unwrap(), } ); assert_noop!( - OraclePrecompile::execute( + OraclePrecompile::execute(&mut MockPrecompileHandle::new( &[0u8; 3], Some(1000), &Context { @@ -227,16 +219,15 @@ mod tests { apparent_value: Default::default() }, false - ), + )), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid input".into(), - cost: target_gas_limit(Some(1000)).unwrap(), } ); assert_noop!( - OraclePrecompile::execute( + OraclePrecompile::execute(&mut MockPrecompileHandle::new( &[1u8; 32], Some(1000), &Context { @@ -245,11 +236,10 @@ mod tests { apparent_value: Default::default() }, false - ), + )), PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid action".into(), - cost: target_gas_limit(Some(1000)).unwrap(), } ); }); diff --git a/runtime/common/src/precompile/schedule.rs b/runtime/common/src/precompile/schedule.rs index a9d1ab2dc0..7cd9fff57e 100644 --- a/runtime/common/src/precompile/schedule.rs +++ b/runtime/common/src/precompile/schedule.rs @@ -19,10 +19,7 @@ // Disable the following lints #![allow(clippy::type_complexity)] -use super::{ - input::{Input, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputT, Output}; use frame_support::{ ensure, parameter_types, traits::{ @@ -32,8 +29,8 @@ use frame_support::{ }; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_support::{AddressMapping, TransactionPayment}; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -105,22 +102,14 @@ where Address = TaskAddress, >, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -166,7 +155,6 @@ where output: "Scheduler charge failed".into(), // TODO: upgrade schedule::v3::Named // output: Output::encode_error_msg("Scheduler charge failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; } @@ -185,7 +173,6 @@ where let next_id = current_id.checked_add(1).ok_or_else(|| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Scheduler next id overflow".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; EvmSchedulerNextID::set(&next_id); @@ -222,14 +209,11 @@ where output: "Scheduler schedule failed".into(), // TODO: upgrade schedule::v3::Named // output: Output::encode_error_msg("Scheduler schedule failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 0, output: Output::encode_bytes(&task_id), - logs: Default::default(), }) } Action::Cancel => { @@ -246,14 +230,12 @@ where let task_info = TaskInfo::decode(&mut &task_id[..]).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Decode task_id failed".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; ensure!( task_info.sender == from, PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "NoPermission".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), } ); @@ -267,7 +249,6 @@ where output: "Scheduler cancel failed".into(), // TODO: upgrade schedule::v3::Named // output: Output::encode_error_msg("Scheduler cancel failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; #[cfg(not(feature = "with-ethereum-compatibility"))] @@ -283,9 +264,7 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 0, output: vec![], - logs: Default::default(), }) } Action::Reschedule => { @@ -304,14 +283,12 @@ where let task_info = TaskInfo::decode(&mut &task_id[..]).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Decode task_id failed".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; ensure!( task_info.sender == from, PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "NoPermission".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), } ); @@ -323,14 +300,11 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Scheduler reschedule failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: 0, output: vec![], - logs: Default::default(), }) } } @@ -345,9 +319,11 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); + let _action = input.action()?; // TODO: gas cost Ok(Self::BASE_COST) @@ -362,6 +338,7 @@ mod tests { alice_evm_addr, bob_evm_addr, new_test_ext, run_to_block, Balances, RuntimeEvent as TestEvent, System, Test, }; use hex_literal::hex; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context}; use sp_core::H160; type SchedulePrecompile = crate::SchedulePrecompile; @@ -403,7 +380,7 @@ mod tests { 00000000000000000000000000000000000000000000000000000000 "}; - let resp = SchedulePrecompile::execute(&input, None, &context, false).unwrap(); + let resp = SchedulePrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(sp_core::bytes::to_hex(&resp.output[..], false), "0x\ 0000000000000000000000000000000000000000000000000000000000000020\ @@ -428,16 +405,14 @@ mod tests { 0000000001824f12000000000000000000000000000000000000000000000000 "}; - let resp = SchedulePrecompile::execute(&cancel_input, None, &context, false).unwrap(); + let resp = SchedulePrecompile::execute(&mut MockPrecompileHandle::new(&cancel_input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); - assert_eq!(resp.cost, 0); let event = TestEvent::Scheduler(pallet_scheduler::Event::::Canceled { when: 3, index: 0 }); assert!(System::events().iter().any(|record| record.event == event)); // schedule call again - let resp = SchedulePrecompile::execute(&input, None, &context, false).unwrap(); + let resp = SchedulePrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); - assert_eq!(resp.cost, 0); assert_eq!(sp_core::bytes::to_hex(&resp.output[..], false), "0x\ 0000000000000000000000000000000000000000000000000000000000000020\ 0000000000000000000000000000000000000000000000000000000000000029\ @@ -462,9 +437,8 @@ mod tests { 0000000001824f12000000000000000000000000000000000000000000000000 "}; - let resp = SchedulePrecompile::execute(&reschedule_input, None, &context, false).unwrap(); + let resp = SchedulePrecompile::execute(&mut MockPrecompileHandle::new(&reschedule_input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); - assert_eq!(resp.cost, 0); assert_eq!(resp.output, [0u8; 0].to_vec()); let event = TestEvent::Scheduler(pallet_scheduler::Event::::Scheduled { when: 5, index: 0 }); @@ -534,9 +508,8 @@ mod tests { 1200000000000000000000000000000000000000000000000000000000000000 "}; - let resp = SchedulePrecompile::execute(&input, None, &context, false).unwrap(); + let resp = SchedulePrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); - assert_eq!(resp.cost, 0); assert_eq!(sp_core::bytes::to_hex(&resp.output[..], false), "0x\ 0000000000000000000000000000000000000000000000000000000000000020\ 0000000000000000000000000000000000000000000000000000000000000029\ @@ -572,11 +545,10 @@ mod tests { 0000000001824f12000000000000000000000000000000000000000000000000 "}; assert_eq!( - SchedulePrecompile::execute(&cancel_input, Some(10_000), &context, false), + SchedulePrecompile::execute(&mut MockPrecompileHandle::new(&cancel_input, Some(10_000), &context, false)), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "NoPermission".into(), - cost: target_gas_limit(Some(10_000)).unwrap() }) ); diff --git a/runtime/common/src/precompile/stable_asset.rs b/runtime/common/src/precompile/stable_asset.rs index 70fcb1400e..4afb4f8f8b 100644 --- a/runtime/common/src/precompile/stable_asset.rs +++ b/runtime/common/src/precompile/stable_asset.rs @@ -16,17 +16,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputT, Output}, - target_gas_limit, -}; +use super::input::{Input, InputT, Output}; use crate::{precompile::input::InputPricer, WeightToGas}; use frame_support::traits::Get; use frame_system::pallet_prelude::*; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use module_support::Erc20InfoMapping; use num_enum::{IntoPrimitive, TryFromPrimitive}; @@ -67,22 +64,14 @@ where BlockNumber = BlockNumberFor, >, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let mut gas_cost = Pricer::::cost(&input)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -92,21 +81,12 @@ where if let Some(pool_info) = as StableAsset>::pool(pool_id) { // dynamic gas cost calculation // cost of reading asset currencies - gas_cost = gas_cost.saturating_add( - pool_info - .assets - .iter() - .map(|x| InputPricer::::read_currency(*x)) - .sum::(), - ); - // make sure there's enough gas - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } + let cost = pool_info + .assets + .iter() + .map(|x| InputPricer::::read_currency(*x)) + .sum::(); + handle.record_cost(cost)?; let assets: Vec = pool_info .assets @@ -116,16 +96,12 @@ where Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_address_array(assets), - logs: Default::default(), }) } else { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } } @@ -135,16 +111,12 @@ where if let Some(pool_info) = as StableAsset>::pool(pool_id) { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(pool_info.total_supply), - logs: Default::default(), }) } else { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } } @@ -154,16 +126,12 @@ where if let Some(pool_info) = as StableAsset>::pool(pool_id) { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(pool_info.precision), - logs: Default::default(), }) } else { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } } @@ -173,16 +141,12 @@ where if let Some(pool_info) = as StableAsset>::pool(pool_id) { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(pool_info.mint_fee), - logs: Default::default(), }) } else { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } } @@ -192,16 +156,12 @@ where if let Some(pool_info) = as StableAsset>::pool(pool_id) { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(pool_info.swap_fee), - logs: Default::default(), }) } else { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } } @@ -211,16 +171,12 @@ where if let Some(pool_info) = as StableAsset>::pool(pool_id) { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint(pool_info.redeem_fee), - logs: Default::default(), }) } else { Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } } @@ -245,13 +201,10 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("StableAsset StableAssetSwap failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_uint_tuple(vec![input, output]), - logs: Default::default(), }) } Action::StableAssetMint => { @@ -274,13 +227,10 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("StableAsset StableAssetMint failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } Action::StableAssetRedeem => { @@ -303,13 +253,10 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("StableAsset StableAssetRedeem failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } Action::StableAssetRedeemSingle => { @@ -331,13 +278,10 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("StableAsset StableAssetRedeemSingle failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } Action::StableAssetRedeemMulti => { @@ -360,13 +304,10 @@ where .map_err(|e| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("StableAsset StableAssetRedeemMulti failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Default::default(), - logs: Default::default(), }) } } @@ -381,14 +322,11 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input< - Action, - Runtime::AccountId, - Runtime::AddressMapping, - ::Erc20InfoMapping, - >, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); + let action = input.action()?; let cost: u64 = match action { @@ -458,6 +396,7 @@ mod tests { use crate::precompile::mock::{alice_evm_addr, new_test_ext, RuntimeOrigin, StableAsset, Test, ALICE, AUSD, DOT}; use frame_support::assert_ok; use hex_literal::hex; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context}; type StableAssetPrecompile = crate::StableAssetPrecompile; @@ -488,7 +427,8 @@ mod tests { fb0f0f34 00000000000000000000000000000000000000000000000000000000 00000000 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); let expected_output = hex! {" 00000000000000000000000000000000 00000000000000000000000000000020 00000000000000000000000000000000 00000000000000000000000000000002 @@ -506,7 +446,8 @@ mod tests { fb0f0f34 00000000000000000000000000000000000000000000000000000000 00000001 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert!(resp.output.is_empty()); }); @@ -545,7 +486,8 @@ mod tests { 7172c6aa 00000000000000000000000000000000000000000000000000000000 00000000 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); let expected_output = hex! {" 00000000000000000000000000000000 000000000000000000000000001e8480 "}; @@ -560,7 +502,8 @@ mod tests { 7172c6aa 00000000000000000000000000000000000000000000000000000000 00000001 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert!(resp.output.is_empty()); }); @@ -593,7 +536,8 @@ mod tests { 9ccdcf91 00000000000000000000000000000000000000000000000000000000 00000000 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); let expected_output = hex! {" 00000000000000000000000000000000 00000000000000000000000000000001 "}; @@ -608,7 +552,8 @@ mod tests { 9ccdcf91 00000000000000000000000000000000000000000000000000000000 00000001 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert!(resp.output.is_empty()); }); @@ -641,7 +586,8 @@ mod tests { 62ff9875 00000000000000000000000000000000000000000000000000000000 00000000 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); let expected_output = hex! {" 00000000000000000000000000000000 00000000000000000000000000000002 "}; @@ -656,7 +602,8 @@ mod tests { 62ff9875 00000000000000000000000000000000000000000000000000000000 00000001 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert!(resp.output.is_empty()); }); @@ -689,7 +636,8 @@ mod tests { 68410f61 00000000000000000000000000000000000000000000000000000000 00000000 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); let expected_output = hex! {" 00000000000000000000000000000000 00000000000000000000000000000003 "}; @@ -704,7 +652,8 @@ mod tests { 68410f61 00000000000000000000000000000000000000000000000000000000 00000001 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert!(resp.output.is_empty()); }); @@ -737,7 +686,8 @@ mod tests { 7f2f11ca 00000000000000000000000000000000000000000000000000000000 00000000 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); let expected_output = hex! {" 00000000000000000000000000000000 00000000000000000000000000000004 "}; @@ -752,7 +702,8 @@ mod tests { 7f2f11ca 00000000000000000000000000000000000000000000000000000000 00000001 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert!(resp.output.is_empty()); }); @@ -797,7 +748,9 @@ mod tests { 00000000000000000000000000000000 000000000000000000000000000f4240 00000000000000000000000000000000 000000000000000000000000000f4240 "}; - let mint_resp = StableAssetPrecompile::execute(&mint_input, None, &context, false).unwrap(); + let mint_resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&mint_input, None, &context, false)) + .unwrap(); assert_eq!(mint_resp.exit_status, ExitSucceed::Returned); assert!(mint_resp.output.is_empty()); @@ -819,7 +772,9 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000001 00000000000000000000000000000000 00000000000000000000000000000002 "}; - let redeem_resp = StableAssetPrecompile::execute(&redeem_input, None, &context, false).unwrap(); + let redeem_resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&redeem_input, None, &context, false)) + .unwrap(); assert_eq!(redeem_resp.exit_status, ExitSucceed::Returned); assert!(redeem_resp.output.is_empty()); @@ -839,8 +794,13 @@ mod tests { 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000002 "}; - let redeem_single_resp = - StableAssetPrecompile::execute(&redeem_single_input, None, &context, false).unwrap(); + let redeem_single_resp = StableAssetPrecompile::execute(&mut MockPrecompileHandle::new( + &redeem_single_input, + None, + &context, + false, + )) + .unwrap(); assert_eq!(redeem_single_resp.exit_status, ExitSucceed::Returned); assert!(redeem_single_resp.output.is_empty()); @@ -859,7 +819,13 @@ mod tests { 000000000000000000000000000000000000000000000000000000000000c350 000000000000000000000000000000000000000000000000000000000000c350 "}; - let redeem_multi_resp = StableAssetPrecompile::execute(&redeem_multi_input, None, &context, false).unwrap(); + let redeem_multi_resp = StableAssetPrecompile::execute(&mut MockPrecompileHandle::new( + &redeem_multi_input, + None, + &context, + false, + )) + .unwrap(); assert_eq!(redeem_multi_resp.exit_status, ExitSucceed::Returned); assert!(redeem_multi_resp.output.is_empty()); }); @@ -917,7 +883,8 @@ mod tests { 00000000000000000000000000000000 0000000000000000000000000007a120 00000000000000000000000000000000 00000000000000000000000000079ab3 "}; - let resp = StableAssetPrecompile::execute(&input, None, &context, false).unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, None, &context, false)).unwrap(); assert_eq!(resp.exit_status, ExitSucceed::Returned); assert_eq!(resp.output, expected_output); @@ -941,15 +908,15 @@ mod tests { 00000000000000000000000000000000 00000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000 00000002 "}; - let resp = StableAssetPrecompile::execute(&input, Some(200_000), &context, false) - .err() - .unwrap(); + let resp = + StableAssetPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(200_000), &context, false)) + .err() + .unwrap(); assert_eq!( resp, PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "StableAsset StableAssetSwap failed: PoolNotFound".into(), - cost: target_gas_limit(Some(200_000)).unwrap_or_default() } ); }); diff --git a/runtime/common/src/precompile/tests.rs b/runtime/common/src/precompile/tests.rs index eb8bb1f5d2..e5ee23be68 100644 --- a/runtime/common/src/precompile/tests.rs +++ b/runtime/common/src/precompile/tests.rs @@ -20,6 +20,7 @@ #![cfg(test)] use super::*; use crate::precompile::mock::{new_test_ext, PrecompilesValue}; +use module_evm::precompiles::tests::MockPrecompileHandle; use module_evm::{Context, ExitRevert}; use primitives::evm::{PRECOMPILE_ADDRESS_START, PREDEPLOY_ADDRESS_START}; @@ -36,12 +37,19 @@ fn precompile_filter_works_on_acala_precompiles() { caller: non_system.into(), apparent_value: 0.into(), }; + let mut handle = MockPrecompileHandle { + input: &[0u8; 1], + code_address: precompile, + gas_limit: Some(10), + gas_used: 0, + context: &non_system_caller_context, + is_static: false, + }; assert_eq!( - PrecompilesValue::get().execute(precompile, &[0u8; 1], Some(10), &non_system_caller_context, false), + PrecompilesValue::get().execute(&mut handle), Some(Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "NoPermission".into(), - cost: 10, })), ); }); @@ -60,9 +68,15 @@ fn precompile_filter_does_not_work_on_system_contracts() { caller: non_system.into(), apparent_value: 0.into(), }; - assert!(PrecompilesValue::get() - .execute(non_system.into(), &[0u8; 1], None, &non_system_caller_context, false) - .is_none()); + let mut handle = MockPrecompileHandle { + input: &[0u8; 1], + code_address: non_system.into(), + gas_limit: None, + gas_used: 0, + context: &non_system_caller_context, + is_static: false, + }; + assert!(PrecompilesValue::get().execute(&mut handle).is_none()); }); } @@ -79,8 +93,14 @@ fn precompile_filter_does_not_work_on_non_system_contracts() { caller: another_non_system.into(), apparent_value: 0.into(), }; - assert!(PrecompilesValue::get() - .execute(non_system.into(), &[0u8; 1], None, &non_system_caller_context, false) - .is_none()); + let mut handle = MockPrecompileHandle { + input: &[0u8; 1], + code_address: non_system.into(), + gas_limit: None, + gas_used: 0, + context: &non_system_caller_context, + is_static: false, + }; + assert!(PrecompilesValue::get().execute(&mut handle).is_none()); }); } diff --git a/runtime/common/src/precompile/xtokens.rs b/runtime/common/src/precompile/xtokens.rs index a7cdcf245e..c3fe8b773f 100644 --- a/runtime/common/src/precompile/xtokens.rs +++ b/runtime/common/src/precompile/xtokens.rs @@ -16,16 +16,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use super::{ - input::{Input, InputPricer, InputT, Output, PER_PARAM_BYTES}, - target_gas_limit, -}; +use super::input::{Input, InputPricer, InputT, Output, PER_PARAM_BYTES}; use crate::WeightToGas; use frame_support::pallet_prelude::{Decode, Encode, IsType}; use module_evm::{ precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileOutput, PrecompileResult}, - Context, ExitError, ExitRevert, ExitSucceed, + runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, + ExitRevert, ExitSucceed, }; use num_enum::{IntoPrimitive, TryFromPrimitive}; use orml_traits::{XcmTransfer, XtokensWeightInfo}; @@ -73,22 +70,14 @@ where ::CurrencyId: IsType, ::Balance: IsType, { - fn execute(input: &[u8], target_gas: Option, _context: &Context, _is_static: bool) -> PrecompileResult { + fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult { + let gas_cost = Pricer::::cost(handle)?; + handle.record_cost(gas_cost)?; + let input = Input::::new( - input, - target_gas_limit(target_gas), + handle.input(), ); - let gas_cost = Pricer::::cost(&input, target_gas)?; - - if let Some(gas_limit) = target_gas { - if gas_limit < gas_cost { - return Err(PrecompileFailure::Error { - exit_status: ExitError::OutOfGas, - }); - } - } - let action = input.action()?; match action { @@ -101,14 +90,12 @@ where let dest: MultiLocation = decode_multi_location(dest_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let mut weight_bytes: &[u8] = &input.bytes_at(5)?[..]; let weight = WeightLimit::decode(&mut weight_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid weight".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!( @@ -131,15 +118,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Xtoken Transfer failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bytes_tuple(vec![&transferred.assets.encode(), &transferred.fee.encode()]), - logs: Default::default(), }) } Action::TransferMultiAsset => { @@ -149,21 +133,18 @@ where let asset: MultiAsset = decode_multi_asset(asset_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid multi asset".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let dest_bytes: &[u8] = &input.bytes_at(3)?[..]; let dest: MultiLocation = decode_multi_location(dest_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let mut weight_bytes: &[u8] = &input.bytes_at(4)?[..]; let weight = WeightLimit::decode(&mut weight_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid weight".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!( @@ -186,15 +167,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Xtoken TransferMultiAsset failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bytes_tuple(vec![&transferred.assets.encode(), &transferred.fee.encode()]), - logs: Default::default(), }) } Action::TransferWithFee => { @@ -207,14 +185,12 @@ where let dest: MultiLocation = decode_multi_location(dest_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let mut weight_bytes: &[u8] = &input.bytes_at(6)?[..]; let weight = WeightLimit::decode(&mut weight_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid weight".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!( @@ -237,15 +213,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Xtoken TransferWithFee failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bytes_tuple(vec![&transferred.assets.encode(), &transferred.fee.encode()]), - logs: Default::default(), }) } Action::TransferMultiAssetWithFee => { @@ -255,28 +228,24 @@ where let asset: MultiAsset = decode_multi_asset(asset_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid multi asset".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let fee_bytes: &[u8] = &input.bytes_at(3)?[..]; let fee: MultiAsset = decode_multi_asset(fee_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid fee asset".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let dest_bytes: &[u8] = &input.bytes_at(4)?[..]; let dest: MultiLocation = decode_multi_location(dest_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let mut weight_bytes: &[u8] = &input.bytes_at(5)?[..]; let weight = WeightLimit::decode(&mut weight_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid weight".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!( @@ -299,15 +268,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Xtoken TransferMultiAssetWithFee failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bytes_tuple(vec![&transferred.assets.encode(), &transferred.fee.encode()]), - logs: Default::default(), }) } Action::TransferMultiCurrencies => { @@ -322,7 +288,6 @@ where return Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid currencies size".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), }); } @@ -341,14 +306,12 @@ where let dest: MultiLocation = decode_multi_location(dest_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let mut weight_bytes: &[u8] = &input.bytes_at(5)?[..]; let weight = WeightLimit::decode(&mut weight_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid weight".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!( @@ -371,15 +334,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Xtoken TransferMultiCurrencies failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bytes_tuple(vec![&transferred.assets.encode(), &transferred.fee.encode()]), - logs: Default::default(), }) } Action::TransferMultiAssets => { @@ -389,28 +349,24 @@ where let assets: MultiAssets = decode_multi_assets(assets_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid multi assets".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let fee_item = input.u32_at(3)?; let fee: &MultiAsset = assets.get(fee_item as usize).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid fee index".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let dest_bytes: &[u8] = &input.bytes_at(4)?[..]; let dest: MultiLocation = decode_multi_location(dest_bytes).ok_or(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let mut weight_bytes: &[u8] = &input.bytes_at(5)?[..]; let weight = WeightLimit::decode(&mut weight_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid weight".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; log::debug!( @@ -433,15 +389,12 @@ where PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: Output::encode_error_msg("Xtoken TransferMultiAssets failed", e), - cost: target_gas_limit(target_gas).unwrap_or_default(), } })?; Ok(PrecompileOutput { exit_status: ExitSucceed::Returned, - cost: gas_cost, output: Output::encode_bytes_tuple(vec![&transferred.assets.encode(), &transferred.fee.encode()]), - logs: Default::default(), }) } } @@ -470,10 +423,11 @@ where { const BASE_COST: u64 = 200; - fn cost( - input: &Input, - target_gas: Option, - ) -> Result { + fn cost(handle: &mut impl PrecompileHandle) -> Result { + let input = Input::::new( + handle.input(), + ); + let action = input.action()?; let cost: u64 = match action { @@ -487,7 +441,6 @@ where let dest = VersionedMultiLocation::decode(&mut dest_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let weight = XtokensWeight::::weight_of_transfer(currency_id.into(), amount.into(), &dest); @@ -501,14 +454,12 @@ where let asset = VersionedMultiAsset::decode(&mut asset_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid multi asset".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let mut dest_bytes: &[u8] = &input.bytes_at(3)?[..]; let dest = VersionedMultiLocation::decode(&mut dest_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let weight = XtokensWeight::::weight_of_transfer_multiasset(&asset, &dest); @@ -525,7 +476,6 @@ where let dest = VersionedMultiLocation::decode(&mut dest_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let weight = XtokensWeight::::weight_of_transfer(currency_id.into(), amount.into(), &dest); @@ -539,14 +489,12 @@ where let asset = VersionedMultiAsset::decode(&mut asset_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid multi asset".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let mut dest_bytes: &[u8] = &input.bytes_at(4)?[..]; let dest = VersionedMultiLocation::decode(&mut dest_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let weight = XtokensWeight::::weight_of_transfer_multiasset(&asset, &dest); @@ -564,7 +512,6 @@ where return Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid currencies size".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), }); } @@ -586,7 +533,6 @@ where let dest = VersionedMultiLocation::decode(&mut dest_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let weight = @@ -602,7 +548,6 @@ where VersionedMultiAssets::decode(&mut assets_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid multi asset".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let fee_item = input.u32_at(3)?; @@ -611,7 +556,6 @@ where let dest = VersionedMultiLocation::decode(&mut dest_bytes).map_err(|_| PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "invalid dest".into(), - cost: target_gas_limit(target_gas).unwrap_or_default(), })?; let weight = XtokensWeight::::weight_of_transfer_multiassets(&assets, &fee_item, &dest); @@ -630,7 +574,8 @@ mod tests { use crate::precompile::mock::{alice_evm_addr, new_test_ext, Test, BOB}; use frame_support::weights::Weight; use hex_literal::hex; - use module_evm::ExitRevert; + use module_evm::{precompiles::tests::MockPrecompileHandle, Context, ExitRevert}; + use orml_utilities::with_transaction_result; type XtokensPrecompile = crate::precompile::XtokensPrecompile; @@ -690,11 +635,10 @@ mod tests { let _ = with_transaction_result(|| { assert_eq!( - XtokensPrecompile::execute(&input, Some(10_000), &context, false), + XtokensPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(10_000), &context, false)), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Xtoken Transfer failed: NotCrossChainTransferableCurrency".into(), - cost: 9000, }) ); Ok(()) @@ -756,11 +700,10 @@ mod tests { let _ = with_transaction_result(|| { assert_eq!( - XtokensPrecompile::execute(&input, Some(10_000), &context, false), + XtokensPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(10_000), &context, false)), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Xtoken TransferMultiAsset failed: InvalidDest".into(), - cost: 9000, }) ); Ok(()) @@ -819,11 +762,10 @@ mod tests { let _ = with_transaction_result(|| { assert_eq!( - XtokensPrecompile::execute(&input, Some(10_000), &context, false), + XtokensPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(10_000), &context, false)), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Xtoken TransferWithFee failed: NotCrossChainTransferableCurrency".into(), - cost: 9000, }) ); Ok(()) @@ -894,11 +836,10 @@ mod tests { let _ = with_transaction_result(|| { assert_eq!( - XtokensPrecompile::execute(&input, Some(10_000), &context, false), + XtokensPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(10_000), &context, false)), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Xtoken TransferMultiAssetWithFee failed: InvalidDest".into(), - cost: 9000, }) ); Ok(()) @@ -968,11 +909,10 @@ mod tests { let _ = with_transaction_result(|| { assert_eq!( - XtokensPrecompile::execute(&input, Some(10_000), &context, false), + XtokensPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(10_000), &context, false)), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Xtoken TransferMultiCurrencies failed: NotCrossChainTransferableCurrency".into(), - cost: 9000, }) ); Ok(()) @@ -1037,11 +977,10 @@ mod tests { let _ = with_transaction_result(|| { assert_eq!( - XtokensPrecompile::execute(&input, Some(10_000), &context, false), + XtokensPrecompile::execute(&mut MockPrecompileHandle::new(&input, Some(10_000), &context, false)), Err(PrecompileFailure::Revert { exit_status: ExitRevert::Reverted, output: "Xtoken TransferMultiAssets failed: InvalidDest".into(), - cost: 9000, }) ); Ok(()) From 5655b15ada95525ab6d3cd1e8e29dd54ba1fedc7 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 11 Jan 2024 20:38:55 +0800 Subject: [PATCH 02/22] update fee calculation ref: https://github.com/rust-ethereum/evm/pull/132 --- modules/evm/src/runner/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 1dd9de2b06..b9ca93a305 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -738,7 +738,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu /// Get fee needed for the current executor, given the price. pub fn fee(&self, price: U256) -> U256 { let used_gas = self.used_gas(); - U256::from(used_gas) * price + U256::from(used_gas).saturating_mul(price) } /// Get account nonce. From 2e362fc27e5096334bb05d639d0dc67859892719 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Fri, 12 Jan 2024 14:54:50 +0800 Subject: [PATCH 03/22] add code_size/code_hash fn in StackState trait ref: https://github.com/rust-ethereum/evm/pull/140 --- modules/evm/src/runner/stack.rs | 12 +++++------- modules/evm/src/runner/state.rs | 27 +++++++++++++++++++-------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/modules/evm/src/runner/stack.rs b/modules/evm/src/runner/stack.rs index e0970d5b8e..9bd9051ec0 100644 --- a/modules/evm/src/runner/stack.rs +++ b/modules/evm/src/runner/stack.rs @@ -21,7 +21,7 @@ use crate::{ runner::{ - state::{Accessed, CustomStackState, StackExecutor, StackState as StackStateT, StackSubstateMetadata}, + state::{Accessed, StackExecutor, StackState as StackStateT, StackSubstateMetadata}, Runner as RunnerT, RunnerExtended, }, AccountStorages, BalanceOf, CallInfo, Config, CreateInfo, Error, ExecutionInfo, Pallet, STORAGE_SIZE, @@ -911,14 +911,12 @@ impl<'vicinity, 'config, T: Config> StackStateT<'config> for SubstrateStackState self.substate .recursive_is_cold(&|a: &Accessed| a.accessed_storage.contains(&(address, key))) } -} -impl<'vicinity, 'config, T: Config> CustomStackState for SubstrateStackState<'vicinity, 'config, T> { - fn code_hash_at_address(&self, address: H160) -> H256 { - Pallet::::code_hash_at_address(&address) + fn code_size(&self, address: H160) -> U256 { + Pallet::::code_size_at_address(&address) } - fn code_size_at_address(&self, address: H160) -> U256 { - Pallet::::code_size_at_address(&address) + fn code_hash(&self, address: H160) -> H256 { + Pallet::::code_hash_at_address(&address) } } diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index b9ca93a305..08c013e04f 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -308,12 +308,7 @@ impl<'config> StackSubstateMetadata<'config> { } } -pub trait CustomStackState { - fn code_hash_at_address(&self, address: H160) -> H256; - fn code_size_at_address(&self, address: H160) -> U256; -} - -pub trait StackState<'config>: Backend + CustomStackState { +pub trait StackState<'config>: Backend { fn metadata(&self) -> &StackSubstateMetadata<'config>; fn metadata_mut(&mut self) -> &mut StackSubstateMetadata<'config>; @@ -336,6 +331,22 @@ pub trait StackState<'config>: Backend + CustomStackState { fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError>; fn reset_balance(&mut self, address: H160); fn touch(&mut self, address: H160); + + /// Fetch the code size of an address. + /// Provide a default implementation by fetching the code, but + /// can be customized to use a more performant approach that don't need to + /// fetch the code. + fn code_size(&self, address: H160) -> U256 { + U256::from(self.code(address).len()) + } + + /// Fetch the code hash of an address. + /// Provide a default implementation by fetching the code, but + /// can be customized to use a more performant approach that don't need to + /// fetch the code. + fn code_hash(&self, address: H160) -> H256 { + H256::from_slice(Keccak256::digest(self.code(address)).as_slice()) + } } /// Data returned by a precompile on success. @@ -1136,7 +1147,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler } fn code_size(&self, address: H160) -> U256 { - self.state.code_size_at_address(address) + self.state.code_size(address) } fn code_hash(&self, address: H160) -> H256 { @@ -1144,7 +1155,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler return H256::default(); } - self.state.code_hash_at_address(address) + self.state.code_hash(address) } fn code(&self, address: H160) -> Vec { From 37e4925e2b25b2cd37f1e0784a931a2c5ff716e0 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Sat, 13 Jan 2024 18:03:03 +0800 Subject: [PATCH 04/22] update evm call stack ref: https://github.com/rust-ethereum/evm/pull/136 --- modules/evm/src/runner/mod.rs | 1 + modules/evm/src/runner/state.rs | 302 ++++++++++++++++------- modules/evm/src/runner/tagged_runtime.rs | 33 +++ 3 files changed, 246 insertions(+), 90 deletions(-) create mode 100644 modules/evm/src/runner/tagged_runtime.rs diff --git a/modules/evm/src/runner/mod.rs b/modules/evm/src/runner/mod.rs index 20a22082e6..aa37d2c2e1 100644 --- a/modules/evm/src/runner/mod.rs +++ b/modules/evm/src/runner/mod.rs @@ -19,6 +19,7 @@ pub mod stack; pub mod state; pub mod storage_meter; +pub mod tagged_runtime; use crate::{BalanceOf, CallInfo, Config, CreateInfo}; use module_evm_utility::evm; diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 08c013e04f..d193cbfa48 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -18,12 +18,16 @@ // Synchronize with https://github.com/rust-blockchain/evm/blob/6534c1dd/src/executor/stack/executor.rs -use crate::{encode_revert_message, StorageMeter}; +use crate::{ + encode_revert_message, + runner::tagged_runtime::{RuntimeKind, TaggedRuntime}, + StorageMeter, +}; use core::{cmp::min, convert::Infallible}; use module_evm_utility::{ evm::{ - backend::Backend, Capture, Config, Context, CreateScheme, ExitError, ExitFatal, ExitReason, ExitRevert, - ExitSucceed, Opcode, Runtime, Stack, Transfer, + backend::Backend, maybe_borrowed::MaybeBorrowed, Capture, Config, Context, CreateScheme, ExitError, ExitFatal, + ExitReason, ExitRevert, ExitSucceed, Opcode, Resolve, Runtime, Stack, Transfer, }, evm_gasometer::{self as gasometer, Gasometer, StorageTarget}, evm_runtime::Handler, @@ -98,6 +102,8 @@ macro_rules! emit_exit { }}; } +const DEFAULT_CALL_STACK_CAPACITY: usize = 4; + pub enum StackExitKind { Succeeded, Reverted, @@ -531,10 +537,84 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } /// Execute the runtime until it returns. - pub fn execute(&mut self, runtime: &mut Runtime) -> ExitReason { - match runtime.run(self) { - Capture::Exit(s) => s, - Capture::Trap(_) => unreachable!("Trap is Infallible"), + pub fn execute(&mut self, runtime: &mut Runtime<'config>) -> ExitReason { + let mut call_stack = Vec::with_capacity(DEFAULT_CALL_STACK_CAPACITY); + call_stack.push(TaggedRuntime { + kind: RuntimeKind::Execute, + inner: MaybeBorrowed::Borrowed(runtime), + }); + let (reason, _, _) = self.execute_with_call_stack(&mut call_stack); + reason + } + + /// Execute using Runtimes on the call_stack until it returns. + fn execute_with_call_stack<'borrow>( + &mut self, + call_stack: &mut Vec>, + ) -> (ExitReason, Option, Vec) { + // This `interrupt_runtime` is used to pass the runtime obtained from the + // `Capture::Trap` branch in the match below back to the top of the call stack. + // The reason we can't simply `push` the runtime directly onto the stack in the + // `Capture::Trap` branch is because the borrow-checker complains that the stack + // is already borrowed as long as we hold a pointer on the last element + // (i.e. the currently executing runtime). + let mut interrupt_runtime = None; + loop { + if let Some(rt) = interrupt_runtime.take() { + call_stack.push(rt); + } + let runtime = match call_stack.last_mut() { + Some(runtime) => runtime, + None => { + return (ExitReason::Fatal(ExitFatal::UnhandledInterrupt), None, Vec::new()); + } + }; + let reason = { + let inner_runtime = &mut runtime.inner; + match inner_runtime.run(self) { + Capture::Exit(reason) => reason, + Capture::Trap(Resolve::Call(rt, _)) => { + interrupt_runtime = Some(rt.0); + continue; + } + Capture::Trap(Resolve::Create(rt, _)) => { + interrupt_runtime = Some(rt.0); + continue; + } + } + }; + let runtime_kind = runtime.kind; + let (reason, maybe_address, return_data) = match runtime_kind { + RuntimeKind::Create(created_address) => { + let (reason, maybe_address, return_data) = + self.cleanup_for_create(created_address, reason, runtime.inner.machine().return_value()); + (reason, maybe_address, return_data) + } + RuntimeKind::Call(code_address) => { + let return_data = + self.cleanup_for_call(code_address, &reason, runtime.inner.machine().return_value()); + (reason, None, return_data) + } + RuntimeKind::Execute => (reason, None, runtime.inner.machine().return_value()), + }; + // We're done with that runtime now, so can pop it off the call stack + call_stack.pop(); + // Now pass the results from that runtime on to the next one in the stack + let runtime = match call_stack.last_mut() { + Some(r) => r, + None => return (reason, None, return_data), + }; + emit_exit!(&reason, &return_data); + let inner_runtime = &mut runtime.inner; + let maybe_error = match runtime_kind { + RuntimeKind::Create(_) => inner_runtime.finish_create(reason, maybe_address, return_data), + RuntimeKind::Call(_) => inner_runtime.finish_call(reason, return_data), + RuntimeKind::Execute => inner_runtime.finish_call(reason, return_data), + }; + // Early exit if passing on the result caused an error + if let Err(e) = maybe_error { + return (e, None, Vec::new()); + } } } @@ -584,7 +664,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu false, ) { Capture::Exit((s, _, v)) => emit_exit!(s, v), - Capture::Trap(_) => unreachable!(), + Capture::Trap(rt) => { + let mut cs = Vec::with_capacity(DEFAULT_CALL_STACK_CAPACITY); + cs.push(rt.0); + let (s, _, v) = self.execute_with_call_stack(&mut cs); + emit_exit!(s, v) + } } } @@ -630,7 +715,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu false, ) { Capture::Exit((s, _, v)) => emit_exit!(s, v), - Capture::Trap(_) => unreachable!(), + Capture::Trap(rt) => { + let mut cs = Vec::with_capacity(DEFAULT_CALL_STACK_CAPACITY); + cs.push(rt.0); + let (s, _, v) = self.execute_with_call_stack(&mut cs); + emit_exit!(s, v) + } } } @@ -666,7 +756,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu false, ) { Capture::Exit((s, _, v)) => emit_exit!(s, v), - Capture::Trap(_) => unreachable!(), + Capture::Trap(rt) => { + let mut cs = Vec::with_capacity(DEFAULT_CALL_STACK_CAPACITY); + cs.push(rt.0); + let (s, _, v) = self.execute_with_call_stack(&mut cs); + emit_exit!(s, v) + } } } @@ -733,7 +828,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu context, ) { Capture::Exit((s, v)) => emit_exit!(s, v), - Capture::Trap(_) => unreachable!(), + Capture::Trap(rt) => { + let mut cs = Vec::with_capacity(DEFAULT_CALL_STACK_CAPACITY); + cs.push(rt.0); + let (s, _, v) = self.execute_with_call_stack(&mut cs); + emit_exit!(s, v) + } } } @@ -812,7 +912,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu init_code: Vec, target_gas: Option, take_l64: bool, - ) -> Capture<(ExitReason, Option, Vec), Infallible> { + ) -> Capture<(ExitReason, Option, Vec), StackExecutorCreateInterrupt<'config>> { macro_rules! try_or_fail { ( $e:expr ) => { match $e { @@ -822,13 +922,6 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu }; } - fn check_first_byte(config: &Config, code: &[u8]) -> Result<(), ExitError> { - if config.disallow_executable_format && Some(&Opcode::EOFMAGIC.as_u8()) == code.first() { - return Err(ExitError::InvalidCode(Opcode::EOFMAGIC)); - } - Ok(()) - } - fn l64(gas: u64) -> u64 { gas - gas / 64 } @@ -925,58 +1018,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu self.state.inc_nonce(address); } - let mut runtime = Runtime::new(Rc::new(init_code), Rc::new(Vec::new()), context, self.config); - - let reason = self.execute(&mut runtime); - log::debug!(target: "evm", "Create execution using address {}: {:?}", address, reason); - - match reason { - ExitReason::Succeed(s) => { - let out = runtime.machine().return_value(); + let runtime = Runtime::new(Rc::new(init_code), Rc::new(Vec::new()), context, self.config); - // As of EIP-3541 code starting with 0xef cannot be deployed - if let Err(e) = check_first_byte(self.config, &out) { - self.state.metadata_mut().gasometer.fail(); - let _ = self.exit_substate(StackExitKind::Failed); - return Capture::Exit((e.into(), None, Vec::new())); - } - - if let Some(limit) = self.config.create_contract_limit { - if out.len() > limit { - self.state.metadata_mut().gasometer.fail(); - let _ = self.exit_substate(StackExitKind::Failed); - return Capture::Exit((ExitError::CreateContractLimit.into(), None, Vec::new())); - } - } - - match self.state.metadata_mut().gasometer.record_deposit(out.len()) { - Ok(()) => { - self.state.set_code(address, out); - let e = self.exit_substate(StackExitKind::Succeeded); - try_or_fail!(e); - Capture::Exit((ExitReason::Succeed(s), Some(address), Vec::new())) - } - Err(e) => { - let _ = self.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Error(e), None, Vec::new())) - } - } - } - ExitReason::Error(e) => { - self.state.metadata_mut().gasometer.fail(); - let _ = self.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Error(e), None, Vec::new())) - } - ExitReason::Revert(e) => { - let _ = self.exit_substate(StackExitKind::Reverted); - Capture::Exit((ExitReason::Revert(e), None, runtime.machine().return_value())) - } - ExitReason::Fatal(e) => { - self.state.metadata_mut().gasometer.fail(); - let _ = self.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Fatal(e), None, Vec::new())) - } - } + Capture::Trap(StackExecutorCreateInterrupt(TaggedRuntime { + kind: RuntimeKind::Create(address), + inner: MaybeBorrowed::Owned(runtime), + })) } #[allow(clippy::too_many_arguments)] @@ -990,7 +1037,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu take_l64: bool, take_stipend: bool, context: Context, - ) -> Capture<(ExitReason, Vec), Infallible> { + ) -> Capture<(ExitReason, Vec), StackExecutorCallInterrupt<'config>> { macro_rules! try_or_fail { ( $e:expr ) => { match $e { @@ -1098,48 +1145,113 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu }; } - let mut runtime = Runtime::new(Rc::new(code), Rc::new(input), context, self.config); + let runtime = Runtime::new(Rc::new(code), Rc::new(input), context, self.config); - #[cfg(not(feature = "tracing"))] - let reason = self.execute(&mut runtime); - #[cfg(feature = "tracing")] - //let reason = module_evm_utility::evm::tracing::using(&mut Tracer, || self.execute(&mut runtime)); - let reason = module_evm_utility::evm_runtime::tracing::using(&mut Tracer, || self.execute(&mut runtime)); - //let reason = module_evm_utility::evm_gasometer::tracing::using(&mut Tracer, || self.execute(&mut - // runtime)); + Capture::Trap(StackExecutorCallInterrupt(TaggedRuntime { + kind: RuntimeKind::Call(code_address), + inner: MaybeBorrowed::Owned(runtime), + })) + } - log::debug!(target: "evm", "Call execution using address {}: {:?}", code_address, reason); + fn cleanup_for_create( + &mut self, + created_address: H160, + reason: ExitReason, + return_data: Vec, + ) -> (ExitReason, Option, Vec) { + fn check_first_byte(config: &Config, code: &[u8]) -> Result<(), ExitError> { + if config.disallow_executable_format && Some(&Opcode::EOFMAGIC.as_u8()) == code.first() { + return Err(ExitError::InvalidCode(Opcode::EOFMAGIC)); + } + Ok(()) + } + + log::debug!(target: "evm", "Create execution using address {}: {:?}", created_address, reason); match reason { ExitReason::Succeed(s) => { - // let _ = self.exit_substate(StackExitKind::Succeeded); - let e = self.exit_substate(StackExitKind::Succeeded); - try_or_fail!(e); - Capture::Exit((ExitReason::Succeed(s), runtime.machine().return_value())) + let out = return_data; + let address = created_address; + // As of EIP-3541 code starting with 0xef cannot be deployed + if let Err(e) = check_first_byte(self.config, &out) { + self.state.metadata_mut().gasometer.fail(); + let _ = self.exit_substate(StackExitKind::Failed); + return (e.into(), None, Vec::new()); + } + + if let Some(limit) = self.config.create_contract_limit { + if out.len() > limit { + self.state.metadata_mut().gasometer.fail(); + let _ = self.exit_substate(StackExitKind::Failed); + return (ExitError::CreateContractLimit.into(), None, Vec::new()); + } + } + + match self.state.metadata_mut().gasometer.record_deposit(out.len()) { + Ok(()) => { + self.state.set_code(address, out); + let exit_result = self.exit_substate(StackExitKind::Succeeded); + if let Err(e) = exit_result { + return (e.into(), None, Vec::new()); + } + (ExitReason::Succeed(s), Some(address), Vec::new()) + } + Err(e) => { + let _ = self.exit_substate(StackExitKind::Failed); + (ExitReason::Error(e), None, Vec::new()) + } + } } ExitReason::Error(e) => { + self.state.metadata_mut().gasometer.fail(); let _ = self.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Error(e), Vec::new())) + (ExitReason::Error(e), None, Vec::new()) } ExitReason::Revert(e) => { let _ = self.exit_substate(StackExitKind::Reverted); - Capture::Exit((ExitReason::Revert(e), runtime.machine().return_value())) + (ExitReason::Revert(e), None, return_data) } ExitReason::Fatal(e) => { self.state.metadata_mut().gasometer.fail(); let _ = self.exit_substate(StackExitKind::Failed); - Capture::Exit((ExitReason::Fatal(e), Vec::new())) + (ExitReason::Fatal(e), None, Vec::new()) + } + } + } + + fn cleanup_for_call(&mut self, code_address: H160, reason: &ExitReason, return_data: Vec) -> Vec { + log::debug!(target: "evm", "Call execution using address {}: {:?}", code_address, reason); + match reason { + ExitReason::Succeed(_) => { + let _ = self.exit_substate(StackExitKind::Succeeded); + return_data + } + ExitReason::Error(_) => { + let _ = self.exit_substate(StackExitKind::Failed); + Vec::new() + } + ExitReason::Revert(_) => { + let _ = self.exit_substate(StackExitKind::Reverted); + return_data + } + ExitReason::Fatal(_) => { + self.state.metadata_mut().gasometer.fail(); + let _ = self.exit_substate(StackExitKind::Failed); + Vec::new() } } } } +pub struct StackExecutorCallInterrupt<'config>(TaggedRuntime<'config, 'config>); +pub struct StackExecutorCreateInterrupt<'config>(TaggedRuntime<'config, 'config>); + impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler for StackExecutor<'config, 'precompiles, S, P> { - type CreateInterrupt = Infallible; + type CreateInterrupt = StackExecutorCreateInterrupt<'config>; type CreateFeedback = Infallible; - type CallInterrupt = Infallible; + type CallInterrupt = StackExecutorCallInterrupt<'config>; type CallFeedback = Infallible; fn balance(&self, address: H160) -> U256 { @@ -1437,7 +1549,17 @@ impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Pr context.clone(), ) { Capture::Exit((s, v)) => (s, v), - Capture::Trap(_) => unreachable!("Trap is infaillible since StackExecutor is sync"), + Capture::Trap(rt) => { + // Ideally this would pass the interrupt back to the executor so it could be + // handled like any other call, however the type signature of this function does + // not allow it. For now we'll make a recursive call instead of making a breaking + // change to the precompile API. But this means a custom precompile could still + // potentially cause a stack overflow if you're not careful. + let mut call_stack = Vec::with_capacity(DEFAULT_CALL_STACK_CAPACITY); + call_stack.push(rt.0); + let (reason, _, return_data) = self.executor.execute_with_call_stack(&mut call_stack); + emit_exit!(reason, return_data) + } } } diff --git a/modules/evm/src/runner/tagged_runtime.rs b/modules/evm/src/runner/tagged_runtime.rs new file mode 100644 index 0000000000..16da6ad9e4 --- /dev/null +++ b/modules/evm/src/runner/tagged_runtime.rs @@ -0,0 +1,33 @@ +// This file is part of Acala. + +// Copyright (C) 2020-2023 Acala Foundation. +// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +use module_evm_utility::evm::{maybe_borrowed::MaybeBorrowed, Runtime}; +use sp_core::H160; + +pub struct TaggedRuntime<'config, 'borrow> { + pub kind: RuntimeKind, + pub inner: MaybeBorrowed<'borrow, Runtime<'config>>, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RuntimeKind { + Create(H160), + Call(H160), + /// Special variant used only in `StackExecutor::execute` + Execute, +} From d8729c0f5a787bdd340cb5c042fe5115b161e940 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Sun, 14 Jan 2024 16:33:02 +0800 Subject: [PATCH 05/22] update evm call stack ref: https://github.com/rust-ethereum/evm/pull/155 --- Cargo.lock | 8 +- modules/evm-utility/Cargo.toml | 6 +- modules/evm/src/lib.rs | 8 +- modules/evm/src/precompiles/blake2/mod.rs | 2 +- modules/evm/src/precompiles/bn128.rs | 2 +- modules/evm/src/precompiles/ecrecover.rs | 2 +- .../src/precompiles/ecrecover_publickey.rs | 2 +- modules/evm/src/precompiles/identity.rs | 2 +- modules/evm/src/precompiles/mod.rs | 4 +- modules/evm/src/precompiles/modexp.rs | 2 +- modules/evm/src/precompiles/ripemd.rs | 2 +- modules/evm/src/precompiles/sha256.rs | 2 +- modules/evm/src/precompiles/sha3fips.rs | 2 +- modules/evm/src/runner/state.rs | 135 +----------------- runtime/common/src/precompile/dex.rs | 5 +- runtime/common/src/precompile/evm.rs | 5 +- runtime/common/src/precompile/evm_accounts.rs | 5 +- runtime/common/src/precompile/homa.rs | 5 +- runtime/common/src/precompile/honzon.rs | 5 +- runtime/common/src/precompile/incentives.rs | 5 +- runtime/common/src/precompile/input.rs | 2 +- .../common/src/precompile/liquid_crowdloan.rs | 5 +- runtime/common/src/precompile/mod.rs | 3 +- .../common/src/precompile/multicurrency.rs | 5 +- runtime/common/src/precompile/nft.rs | 5 +- runtime/common/src/precompile/oracle.rs | 4 +- runtime/common/src/precompile/schedule.rs | 5 +- runtime/common/src/precompile/stable_asset.rs | 5 +- runtime/common/src/precompile/xtokens.rs | 5 +- 29 files changed, 54 insertions(+), 194 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5e613b8445..0008eaf65d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" +source = "git+https://github.com/rust-blockchain/evm?rev=8ac19080a8523136e9212c749891f845d7ab0d0f#8ac19080a8523136e9212c749891f845d7ab0d0f" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" +source = "git+https://github.com/rust-blockchain/evm?rev=8ac19080a8523136e9212c749891f845d7ab0d0f#8ac19080a8523136e9212c749891f845d7ab0d0f" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" +source = "git+https://github.com/rust-blockchain/evm?rev=8ac19080a8523136e9212c749891f845d7ab0d0f#8ac19080a8523136e9212c749891f845d7ab0d0f" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=842e03d068ddb6a3195a2dedc4a9b63caadb3355#842e03d068ddb6a3195a2dedc4a9b63caadb3355" +source = "git+https://github.com/rust-blockchain/evm?rev=8ac19080a8523136e9212c749891f845d7ab0d0f#8ac19080a8523136e9212c749891f845d7ab0d0f" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 76208f221c..ac66a804a7 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "842e03d068ddb6a3195a2dedc4a9b63caadb3355", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "8ac19080a8523136e9212c749891f845d7ab0d0f", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "8ac19080a8523136e9212c749891f845d7ab0d0f", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "8ac19080a8523136e9212c749891f845d7ab0d0f", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index 0bd72a44fd..03860e799a 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -24,7 +24,7 @@ pub use crate::runner::{ stack::SubstrateStackState, - state::{PrecompileSet, StackExecutor, StackSubstateMetadata}, + state::{PrecompileResult, StackExecutor, StackSubstateMetadata}, storage_meter::StorageMeter, Runner, }; @@ -46,7 +46,11 @@ use frame_system::{ensure_root, ensure_signed, pallet_prelude::*, EnsureRoot, En use hex_literal::hex; pub use module_evm_utility::{ ethereum::{AccessListItem, Log, TransactionAction}, - evm::{self, Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed}, + evm::{ + self, + executor::stack::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet}, + Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, + }, Account, }; pub use module_support::{ diff --git a/modules/evm/src/precompiles/blake2/mod.rs b/modules/evm/src/precompiles/blake2/mod.rs index befebe5e4b..af60df4ac1 100644 --- a/modules/evm/src/precompiles/blake2/mod.rs +++ b/modules/evm/src/precompiles/blake2/mod.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::Precompile; -use crate::runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; +use crate::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; use module_evm_utility::evm::{ExitError, ExitSucceed}; mod eip_152; diff --git a/modules/evm/src/precompiles/bn128.rs b/modules/evm/src/precompiles/bn128.rs index 9ccd3bcdf1..d1f3ef7564 100644 --- a/modules/evm/src/precompiles/bn128.rs +++ b/modules/evm/src/precompiles/bn128.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::Precompile; -use crate::runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; +use crate::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; use module_evm_utility::evm::{ExitError, ExitSucceed}; use sp_core::U256; use sp_std::vec::Vec; diff --git a/modules/evm/src/precompiles/ecrecover.rs b/modules/evm/src/precompiles/ecrecover.rs index 41415cd33d..c33f5ea34d 100644 --- a/modules/evm/src/precompiles/ecrecover.rs +++ b/modules/evm/src/precompiles/ecrecover.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::LinearCostPrecompile; -use crate::runner::state::PrecompileFailure; +use crate::PrecompileFailure; use module_evm_utility::evm::ExitSucceed; use sp_std::{cmp::min, vec::Vec}; diff --git a/modules/evm/src/precompiles/ecrecover_publickey.rs b/modules/evm/src/precompiles/ecrecover_publickey.rs index d800ab2998..008d456a6c 100644 --- a/modules/evm/src/precompiles/ecrecover_publickey.rs +++ b/modules/evm/src/precompiles/ecrecover_publickey.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::LinearCostPrecompile; -use crate::runner::state::PrecompileFailure; +use crate::PrecompileFailure; use module_evm_utility::evm::{ExitError, ExitSucceed}; use sp_std::{cmp::min, vec::Vec}; diff --git a/modules/evm/src/precompiles/identity.rs b/modules/evm/src/precompiles/identity.rs index 2f5a4c2899..fcb560a771 100644 --- a/modules/evm/src/precompiles/identity.rs +++ b/modules/evm/src/precompiles/identity.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::LinearCostPrecompile; -use crate::runner::state::PrecompileFailure; +use crate::PrecompileFailure; use module_evm_utility::evm::ExitSucceed; use sp_std::vec::Vec; diff --git a/modules/evm/src/precompiles/mod.rs b/modules/evm/src/precompiles/mod.rs index 788a381dbd..7d90a0a6cd 100644 --- a/modules/evm/src/precompiles/mod.rs +++ b/modules/evm/src/precompiles/mod.rs @@ -18,7 +18,7 @@ //! Builtin precompiles. -use crate::runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; +use crate::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; use module_evm_utility::evm::{ExitError, ExitSucceed}; use sp_std::vec::Vec; @@ -93,7 +93,7 @@ fn ensure_linear_cost(target_gas: Option, len: u64, base: u64, word: u64) - } pub mod tests { - use crate::{runner::state::PrecompileHandle, ExitError, ExitReason}; + use crate::{ExitError, ExitReason, PrecompileHandle}; use module_evm_utility::evm::{Context, Transfer}; use sp_core::{H160, H256}; use sp_std::vec::Vec; diff --git a/modules/evm/src/precompiles/modexp.rs b/modules/evm/src/precompiles/modexp.rs index 772e092d67..a0d8100445 100644 --- a/modules/evm/src/precompiles/modexp.rs +++ b/modules/evm/src/precompiles/modexp.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::Precompile; -use crate::runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; +use crate::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}; use module_evm_utility::evm::{ExitError, ExitSucceed}; use num::{BigUint, One, Zero}; use sp_core::U256; diff --git a/modules/evm/src/precompiles/ripemd.rs b/modules/evm/src/precompiles/ripemd.rs index f677997689..b94dd0e696 100644 --- a/modules/evm/src/precompiles/ripemd.rs +++ b/modules/evm/src/precompiles/ripemd.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::LinearCostPrecompile; -use crate::runner::state::PrecompileFailure; +use crate::PrecompileFailure; use module_evm_utility::evm::ExitSucceed; use sha3::Digest; use sp_std::vec::Vec; diff --git a/modules/evm/src/precompiles/sha256.rs b/modules/evm/src/precompiles/sha256.rs index 4d2e404ec7..d352a748e2 100644 --- a/modules/evm/src/precompiles/sha256.rs +++ b/modules/evm/src/precompiles/sha256.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::LinearCostPrecompile; -use crate::runner::state::PrecompileFailure; +use crate::PrecompileFailure; use module_evm_utility::evm::ExitSucceed; use sp_std::vec::Vec; diff --git a/modules/evm/src/precompiles/sha3fips.rs b/modules/evm/src/precompiles/sha3fips.rs index eaf40ef5d5..3448caf699 100644 --- a/modules/evm/src/precompiles/sha3fips.rs +++ b/modules/evm/src/precompiles/sha3fips.rs @@ -17,7 +17,7 @@ // along with this program. If not, see . use super::LinearCostPrecompile; -use crate::runner::state::PrecompileFailure; +use crate::PrecompileFailure; use module_evm_utility::evm::ExitSucceed; use sp_std::vec::Vec; use tiny_keccak::Hasher; diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index d193cbfa48..1d045b6d3d 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -21,13 +21,13 @@ use crate::{ encode_revert_message, runner::tagged_runtime::{RuntimeKind, TaggedRuntime}, - StorageMeter, + PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet, StorageMeter, }; use core::{cmp::min, convert::Infallible}; use module_evm_utility::{ evm::{ backend::Backend, maybe_borrowed::MaybeBorrowed, Capture, Config, Context, CreateScheme, ExitError, ExitFatal, - ExitReason, ExitRevert, ExitSucceed, Opcode, Resolve, Runtime, Stack, Transfer, + ExitReason, Opcode, Resolve, Runtime, Stack, Transfer, }, evm_gasometer::{self as gasometer, Gasometer, StorageTarget}, evm_runtime::Handler, @@ -43,11 +43,7 @@ pub use primitives::{ use sha3::{Digest, Keccak256}; use sp_core::{H160, H256, U256}; use sp_runtime::traits::Zero; -use sp_std::{ - collections::{btree_map::BTreeMap, btree_set::BTreeSet}, - rc::Rc, - vec::Vec, -}; +use sp_std::{collections::btree_set::BTreeSet, rc::Rc, vec::Vec}; macro_rules! event { ($x:expr) => {}; @@ -355,134 +351,9 @@ pub trait StackState<'config>: Backend { } } -/// Data returned by a precompile on success. -#[derive(Debug, Eq, PartialEq, Clone)] -pub struct PrecompileOutput { - pub exit_status: ExitSucceed, - pub output: Vec, -} - -/// Data returned by a precompile in case of failure. -#[derive(Debug, Eq, PartialEq, Clone)] -pub enum PrecompileFailure { - /// Reverts the state changes and consume all the gas. - Error { exit_status: ExitError }, - /// Reverts the state changes. - /// Returns the provided error message. - Revert { exit_status: ExitRevert, output: Vec }, - /// Mark this failure as fatal, and all EVM execution stacks must be exited. - Fatal { exit_status: ExitFatal }, -} - -impl From for PrecompileFailure { - fn from(error: ExitError) -> PrecompileFailure { - PrecompileFailure::Error { exit_status: error } - } -} - -/// Handle provided to a precompile to interact with the EVM. -pub trait PrecompileHandle { - /// Perform subcall in provided context. - /// Precompile specifies in which context the subcall is executed. - fn call( - &mut self, - to: H160, - transfer: Option, - input: Vec, - gas_limit: Option, - is_static: bool, - context: &Context, - ) -> (ExitReason, Vec); - - /// Record cost to the Runtime gasometer. - fn record_cost(&mut self, cost: u64) -> Result<(), ExitError>; - - /// Retreive the remaining gas. - fn remaining_gas(&self) -> u64; - - /// Record a log. - fn log(&mut self, address: H160, topics: Vec, data: Vec) -> Result<(), ExitError>; - - /// Retreive the code address (what is the address of the precompile being called). - fn code_address(&self) -> H160; - - /// Retreive the input data the precompile is called with. - fn input(&self) -> &[u8]; - - /// Retreive the context in which the precompile is executed. - fn context(&self) -> &Context; - - /// Is the precompile call is done statically. - fn is_static(&self) -> bool; - - /// Retreive the gas limit of this call. - fn gas_limit(&self) -> Option; -} - /// A precompile result. pub type PrecompileResult = Result; -/// A set of precompiles. -/// Checks of the provided address being in the precompile set should be -/// as cheap as possible since it may be called often. -pub trait PrecompileSet { - /// Tries to execute a precompile in the precompile set. - /// If the provided address is not a precompile, returns None. - fn execute(&self, handle: &mut impl PrecompileHandle) -> Option; - - /// Check if the given address is a precompile. Should only be called to - /// perform the check while not executing the precompile afterward, since - /// `execute` already performs a check internally. - fn is_precompile(&self, address: H160) -> bool; -} - -impl PrecompileSet for () { - fn execute(&self, _: &mut impl PrecompileHandle) -> Option { - None - } - - fn is_precompile(&self, _: H160) -> bool { - false - } -} - -/// Precompiles function signature. Expected input arguments are: -/// * Input -/// * Gas limit -/// * Context -/// * Is static -/// -/// In case of success returns the output and the cost. -pub type PrecompileFn = fn(&[u8], Option, &Context, bool) -> Result<(PrecompileOutput, u64), PrecompileFailure>; - -impl PrecompileSet for BTreeMap { - fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { - let address = handle.code_address(); - - self.get(&address).map(|precompile| { - let input = handle.input(); - let gas_limit = handle.gas_limit(); - let context = handle.context(); - let is_static = handle.is_static(); - - match (*precompile)(input, gas_limit, context, is_static) { - Ok((output, cost)) => { - handle.record_cost(cost)?; - Ok(output) - } - Err(err) => Err(err), - } - }) - } - - /// Check if the given address is a precompile. Should only be called to - /// perform the check while not executing the precompile afterward, since - /// `execute` already performs a check internally. - fn is_precompile(&self, address: H160) -> bool { - self.contains_key(&address) - } -} - /// Stack-based executor. pub struct StackExecutor<'config, 'precompiles, S, P> { config: &'config Config, diff --git a/runtime/common/src/precompile/dex.rs b/runtime/common/src/precompile/dex.rs index c868802b04..e74e4e8134 100644 --- a/runtime/common/src/precompile/dex.rs +++ b/runtime/common/src/precompile/dex.rs @@ -21,9 +21,8 @@ use crate::WeightToGas; use frame_support::traits::Get; use module_dex::WeightInfo; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_support::{DEXManager, SwapLimit}; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/runtime/common/src/precompile/evm.rs b/runtime/common/src/precompile/evm.rs index a2daba7aa9..84fba4e1dc 100644 --- a/runtime/common/src/precompile/evm.rs +++ b/runtime/common/src/precompile/evm.rs @@ -22,9 +22,8 @@ use super::{ }; use crate::WeightToGas; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, WeightInfo, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, WeightInfo, }; use module_support::EVMManager; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/runtime/common/src/precompile/evm_accounts.rs b/runtime/common/src/precompile/evm_accounts.rs index 14e6ffaa18..2c3aa36103 100644 --- a/runtime/common/src/precompile/evm_accounts.rs +++ b/runtime/common/src/precompile/evm_accounts.rs @@ -20,9 +20,8 @@ use super::input::{Input, InputT, Output}; use crate::WeightToGas; use frame_support::{pallet_prelude::IsType, traits::Get}; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_evm_accounts::WeightInfo; use module_support::EVMAccountsManager; diff --git a/runtime/common/src/precompile/homa.rs b/runtime/common/src/precompile/homa.rs index 62eb56ce30..b94494349f 100644 --- a/runtime/common/src/precompile/homa.rs +++ b/runtime/common/src/precompile/homa.rs @@ -20,9 +20,8 @@ use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use frame_support::traits::Get; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_support::HomaManager; diff --git a/runtime/common/src/precompile/honzon.rs b/runtime/common/src/precompile/honzon.rs index b00c4e5399..d9405629da 100644 --- a/runtime/common/src/precompile/honzon.rs +++ b/runtime/common/src/precompile/honzon.rs @@ -20,9 +20,8 @@ use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use frame_support::traits::Get; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_honzon::WeightInfo; use module_support::HonzonManager; diff --git a/runtime/common/src/precompile/incentives.rs b/runtime/common/src/precompile/incentives.rs index e9ef10f336..be063906ec 100644 --- a/runtime/common/src/precompile/incentives.rs +++ b/runtime/common/src/precompile/incentives.rs @@ -20,9 +20,8 @@ use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use frame_support::traits::Get; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_incentives::WeightInfo; use module_support::{IncentivesManager, PoolId}; diff --git a/runtime/common/src/precompile/input.rs b/runtime/common/src/precompile/input.rs index 711a484e0a..2fc873c1e8 100644 --- a/runtime/common/src/precompile/input.rs +++ b/runtime/common/src/precompile/input.rs @@ -22,7 +22,7 @@ use sp_std::{marker::PhantomData, result::Result, vec::Vec}; use crate::WeightToGas; use ethabi::Token; use frame_support::traits::Get; -use module_evm::{runner::state::PrecompileFailure, ExitRevert}; +use module_evm::{ExitRevert, PrecompileFailure}; use module_support::{AddressMapping as AddressMappingT, Erc20InfoMapping as Erc20InfoMappingT}; use primitives::{Balance, CurrencyId, DexShare}; use sp_core::{H160, U256}; diff --git a/runtime/common/src/precompile/liquid_crowdloan.rs b/runtime/common/src/precompile/liquid_crowdloan.rs index ced1c09264..52168812c2 100644 --- a/runtime/common/src/precompile/liquid_crowdloan.rs +++ b/runtime/common/src/precompile/liquid_crowdloan.rs @@ -19,9 +19,8 @@ use super::input::{Input, InputPricer, InputT, Output}; use crate::WeightToGas; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_liquid_crowdloan::WeightInfo; use module_support::Erc20InfoMapping as _; diff --git a/runtime/common/src/precompile/mod.rs b/runtime/common/src/precompile/mod.rs index 75fad712d5..bee189140d 100644 --- a/runtime/common/src/precompile/mod.rs +++ b/runtime/common/src/precompile/mod.rs @@ -31,8 +31,7 @@ use module_evm::{ Blake2F, Bn128Add, Bn128Mul, Bn128Pairing, ECRecover, ECRecoverPublicKey, Identity, IstanbulModexp, Modexp, Precompile, Ripemd160, Sha256, Sha3FIPS256, Sha3FIPS512, }, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileResult, PrecompileSet}, - ExitRevert, + ExitRevert, PrecompileFailure, PrecompileHandle, PrecompileResult, PrecompileSet, }; use module_support::{PrecompileCallerFilter, PrecompilePauseFilter}; use sp_core::H160; diff --git a/runtime/common/src/precompile/multicurrency.rs b/runtime/common/src/precompile/multicurrency.rs index 1855c829bf..69256981ab 100644 --- a/runtime/common/src/precompile/multicurrency.rs +++ b/runtime/common/src/precompile/multicurrency.rs @@ -24,9 +24,8 @@ use frame_support::{ }; use module_currencies::WeightInfo; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_support::Erc20InfoMapping as Erc20InfoMappingT; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/runtime/common/src/precompile/nft.rs b/runtime/common/src/precompile/nft.rs index 297557b0a0..6046bc626f 100644 --- a/runtime/common/src/precompile/nft.rs +++ b/runtime/common/src/precompile/nft.rs @@ -19,9 +19,8 @@ use super::input::{Input, InputT, Output}; use frame_support::traits::tokens::nonfungibles::{Inspect, Transfer}; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_support::AddressMapping; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/runtime/common/src/precompile/oracle.rs b/runtime/common/src/precompile/oracle.rs index 076ce6b7a1..2f2053aeb5 100644 --- a/runtime/common/src/precompile/oracle.rs +++ b/runtime/common/src/precompile/oracle.rs @@ -22,9 +22,7 @@ use super::{ }; use crate::{Weight, WeightToGas}; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitSucceed, + precompiles::Precompile, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult, }; use module_support::{Erc20InfoMapping as Erc20InfoMappingT, PriceProvider as PriceProviderT}; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/runtime/common/src/precompile/schedule.rs b/runtime/common/src/precompile/schedule.rs index 7cd9fff57e..9a83738cec 100644 --- a/runtime/common/src/precompile/schedule.rs +++ b/runtime/common/src/precompile/schedule.rs @@ -28,9 +28,8 @@ use frame_support::{ }, }; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_support::{AddressMapping, TransactionPayment}; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/runtime/common/src/precompile/stable_asset.rs b/runtime/common/src/precompile/stable_asset.rs index 4afb4f8f8b..27fd20c384 100644 --- a/runtime/common/src/precompile/stable_asset.rs +++ b/runtime/common/src/precompile/stable_asset.rs @@ -21,9 +21,8 @@ use crate::{precompile::input::InputPricer, WeightToGas}; use frame_support::traits::Get; use frame_system::pallet_prelude::*; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use module_support::Erc20InfoMapping; use num_enum::{IntoPrimitive, TryFromPrimitive}; diff --git a/runtime/common/src/precompile/xtokens.rs b/runtime/common/src/precompile/xtokens.rs index c3fe8b773f..393846feef 100644 --- a/runtime/common/src/precompile/xtokens.rs +++ b/runtime/common/src/precompile/xtokens.rs @@ -20,9 +20,8 @@ use super::input::{Input, InputPricer, InputT, Output, PER_PARAM_BYTES}; use crate::WeightToGas; use frame_support::pallet_prelude::{Decode, Encode, IsType}; use module_evm::{ - precompiles::Precompile, - runner::state::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult}, - ExitRevert, ExitSucceed, + precompiles::Precompile, ExitRevert, ExitSucceed, PrecompileFailure, PrecompileHandle, PrecompileOutput, + PrecompileResult, }; use num_enum::{IntoPrimitive, TryFromPrimitive}; use orml_traits::{XcmTransfer, XtokensWeightInfo}; From e5e853f366a91a0b3895ba4a5137be62fb4e3b26 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Mon, 15 Jan 2024 19:49:25 +0800 Subject: [PATCH 06/22] add shanghai eips 3651, 3855, 3860 ref: https://github.com/rust-ethereum/evm/pull/152 --- Cargo.lock | 8 ++-- modules/evm-utility/Cargo.toml | 6 +-- modules/evm/src/runner/state.rs | 65 ++++++++++++++++++++++++++++++++- 3 files changed, 70 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0008eaf65d..a9e2a6c982 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=8ac19080a8523136e9212c749891f845d7ab0d0f#8ac19080a8523136e9212c749891f845d7ab0d0f" +source = "git+https://github.com/rust-blockchain/evm?rev=2e9c3b71f7b9ff241735f15145517d0627c469e6#2e9c3b71f7b9ff241735f15145517d0627c469e6" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=8ac19080a8523136e9212c749891f845d7ab0d0f#8ac19080a8523136e9212c749891f845d7ab0d0f" +source = "git+https://github.com/rust-blockchain/evm?rev=2e9c3b71f7b9ff241735f15145517d0627c469e6#2e9c3b71f7b9ff241735f15145517d0627c469e6" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=8ac19080a8523136e9212c749891f845d7ab0d0f#8ac19080a8523136e9212c749891f845d7ab0d0f" +source = "git+https://github.com/rust-blockchain/evm?rev=2e9c3b71f7b9ff241735f15145517d0627c469e6#2e9c3b71f7b9ff241735f15145517d0627c469e6" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=8ac19080a8523136e9212c749891f845d7ab0d0f#8ac19080a8523136e9212c749891f845d7ab0d0f" +source = "git+https://github.com/rust-blockchain/evm?rev=2e9c3b71f7b9ff241735f15145517d0627c469e6#2e9c3b71f7b9ff241735f15145517d0627c469e6" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index ac66a804a7..587f549099 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "8ac19080a8523136e9212c749891f845d7ab0d0f", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "8ac19080a8523136e9212c749891f845d7ab0d0f", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "8ac19080a8523136e9212c749891f845d7ab0d0f", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "2e9c3b71f7b9ff241735f15145517d0627c469e6", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "2e9c3b71f7b9ff241735f15145517d0627c469e6", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "2e9c3b71f7b9ff241735f15145517d0627c469e6", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 1d045b6d3d..9c7c1ce5d8 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -504,6 +504,23 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu gasometer.record_transaction(transaction_cost) } + fn maybe_record_init_code_cost(&mut self, init_code: &[u8]) -> Result<(), ExitError> { + if let Some(limit) = self.config.max_initcode_size { + // EIP-3860 + if init_code.len() > limit { + self.state.metadata_mut().gasometer.fail(); + let _ = self.exit_substate(StackExitKind::Failed); + return Err(ExitError::OutOfGas); + } + return self + .state + .metadata_mut() + .gasometer + .record_cost(gasometer::init_code_cost(init_code)); + } + Ok(()) + } + /// Execute a `CREATE` transaction. pub fn transact_create( &mut self, @@ -521,6 +538,14 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu address: self.create_address(CreateScheme::Legacy { caller }), }); + if let Some(limit) = self.config.max_initcode_size { + if init_code.len() > limit { + self.state.metadata_mut().gasometer.fail(); + let _ = self.exit_substate(StackExitKind::Failed); + return emit_exit!(ExitError::InitCodeLimit.into(), Vec::new()); + } + } + if let Err(e) = self.record_create_transaction_cost(&init_code, &access_list) { return emit_exit!(e.into(), Vec::new()); } @@ -554,6 +579,14 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu gas_limit: u64, access_list: Vec<(H160, Vec)>, // See EIP-2930 ) -> (ExitReason, Vec) { + if let Some(limit) = self.config.max_initcode_size { + if init_code.len() > limit { + self.state.metadata_mut().gasometer.fail(); + let _ = self.exit_substate(StackExitKind::Failed); + return emit_exit!(ExitError::InitCodeLimit.into(), Vec::new()); + } + } + let code_hash = H256::from_slice(Keccak256::digest(&init_code).as_slice()); event!(TransactCreate2 { caller, @@ -605,6 +638,14 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu gas_limit: u64, access_list: Vec<(H160, Vec)>, ) -> (ExitReason, Vec) { + if let Some(limit) = self.config.max_initcode_size { + if init_code.len() > limit { + self.state.metadata_mut().gasometer.fail(); + let _ = self.exit_substate(StackExitKind::Failed); + return emit_exit!(ExitError::InitCodeLimit.into(), Vec::new()); + } + } + event!(TransactCreate { caller, value, @@ -672,8 +713,16 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu // Initialize initial addresses for EIP-2929 if self.config.increase_state_access_gas { - let addresses = core::iter::once(caller).chain(core::iter::once(address)); - self.state.metadata_mut().access_addresses(addresses); + if self.config.warm_coinbase_address { + // Warm coinbase address for EIP-3651 + let addresses = core::iter::once(caller) + .chain(core::iter::once(address)) + .chain(core::iter::once(self.block_coinbase())); + self.state.metadata_mut().access_addresses(addresses); + } else { + let addresses = core::iter::once(caller).chain(core::iter::once(address)); + self.state.metadata_mut().access_addresses(addresses); + } self.initialize_with_access_list(access_list); } @@ -1254,6 +1303,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler init_code: Vec, target_gas: Option, ) -> Capture<(ExitReason, Option, Vec), Self::CreateInterrupt> { + if let Err(e) = self.maybe_record_init_code_cost(&init_code) { + let reason: ExitReason = e.into(); + emit_exit!(reason.clone()); + return Capture::Exit((reason, None, Vec::new())); + } + self.create_inner(caller, scheme, value, init_code, target_gas, true) } @@ -1266,6 +1321,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler init_code: Vec, target_gas: Option, ) -> Capture<(ExitReason, Option, Vec), Self::CreateInterrupt> { + if let Err(e) = self.maybe_record_init_code_cost(&init_code) { + let reason: ExitReason = e.into(); + emit_exit!(reason.clone()); + return Capture::Exit((reason, None, Vec::new())); + } + let capture = self.create_inner(caller, scheme, value, init_code, target_gas, true); if let Capture::Exit((ref reason, _, ref return_value)) = capture { From 26ae671b8131983b75420ba5187a0c93b8665785 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Tue, 16 Jan 2024 21:29:39 +0800 Subject: [PATCH 07/22] update is_precompile ref: https://github.com/rust-ethereum/evm/pull/157 --- Cargo.lock | 8 ++--- modules/evm-utility/Cargo.toml | 6 ++-- modules/evm/src/lib.rs | 2 +- modules/evm/src/runner/state.rs | 50 +++++++++++++++++++++------- runtime/common/src/precompile/mod.rs | 31 +++++++++++++---- 5 files changed, 71 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9e2a6c982..2e5ae0a00e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=2e9c3b71f7b9ff241735f15145517d0627c469e6#2e9c3b71f7b9ff241735f15145517d0627c469e6" +source = "git+https://github.com/rust-blockchain/evm?rev=5fb8a4957c642134782e184c47f7d7b5a29f3629#5fb8a4957c642134782e184c47f7d7b5a29f3629" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=2e9c3b71f7b9ff241735f15145517d0627c469e6#2e9c3b71f7b9ff241735f15145517d0627c469e6" +source = "git+https://github.com/rust-blockchain/evm?rev=5fb8a4957c642134782e184c47f7d7b5a29f3629#5fb8a4957c642134782e184c47f7d7b5a29f3629" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=2e9c3b71f7b9ff241735f15145517d0627c469e6#2e9c3b71f7b9ff241735f15145517d0627c469e6" +source = "git+https://github.com/rust-blockchain/evm?rev=5fb8a4957c642134782e184c47f7d7b5a29f3629#5fb8a4957c642134782e184c47f7d7b5a29f3629" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=2e9c3b71f7b9ff241735f15145517d0627c469e6#2e9c3b71f7b9ff241735f15145517d0627c469e6" +source = "git+https://github.com/rust-blockchain/evm?rev=5fb8a4957c642134782e184c47f7d7b5a29f3629#5fb8a4957c642134782e184c47f7d7b5a29f3629" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 587f549099..55b828260d 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "2e9c3b71f7b9ff241735f15145517d0627c469e6", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "2e9c3b71f7b9ff241735f15145517d0627c469e6", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "2e9c3b71f7b9ff241735f15145517d0627c469e6", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "5fb8a4957c642134782e184c47f7d7b5a29f3629", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "5fb8a4957c642134782e184c47f7d7b5a29f3629", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "5fb8a4957c642134782e184c47f7d7b5a29f3629", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index 03860e799a..1c224109fc 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -48,7 +48,7 @@ pub use module_evm_utility::{ ethereum::{AccessListItem, Log, TransactionAction}, evm::{ self, - executor::stack::{PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet}, + executor::stack::{IsPrecompileResult, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet}, Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, }, Account, diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 9c7c1ce5d8..25adb1aa30 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -21,7 +21,7 @@ use crate::{ encode_revert_message, runner::tagged_runtime::{RuntimeKind, TaggedRuntime}, - PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet, StorageMeter, + IsPrecompileResult, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet, StorageMeter, }; use core::{cmp::min, convert::Infallible}; use module_evm_utility::{ @@ -1192,12 +1192,17 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler fn code(&self, address: H160) -> Vec { let code = self.state.code(address); - if code.len().is_zero() && !self.precompile_set.is_precompile(address) { - log::debug!( - target: "evm", - "contract does not exist, address: {:?}", - address - ); + if code.len().is_zero() { + if let IsPrecompileResult::Answer { + is_precompile: false, .. + } = self.precompile_set.is_precompile(address, u64::zero()) + { + log::debug!( + target: "evm", + "contract does not exist, address: {:?}", + address + ); + } } code } @@ -1218,11 +1223,27 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler } } - fn is_cold(&self, address: H160, maybe_index: Option) -> bool { - match maybe_index { - None => !self.precompile_set.is_precompile(address) && self.state.is_cold(address), + fn is_cold(&mut self, address: H160, maybe_index: Option) -> Result { + Ok(match maybe_index { + None => { + let is_precompile = match self + .precompile_set + .is_precompile(address, self.state.metadata().gasometer.gas()) + { + IsPrecompileResult::Answer { + is_precompile, + extra_cost, + } => { + self.state.metadata_mut().gasometer.record_cost(extra_cost)?; + is_precompile + } + IsPrecompileResult::OutOfGas => return Err(ExitError::OutOfGas), + }; + + !is_precompile && self.state.is_cold(address) + } Some(index) => self.state.is_storage_cold(address, index), - } + }) } fn gas_left(&self) -> U256 { @@ -1438,10 +1459,15 @@ impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Pr // Since we don't go through opcodes we need manually record the call // cost. Not doing so will make the code panic as recording the call stipend // will do an underflow. + let target_is_cold = match self.executor.is_cold(code_address, None) { + Ok(x) => x, + Err(err) => return (ExitReason::Error(err), Vec::new()), + }; + let gas_cost = gasometer::GasCost::Call { value: transfer.clone().map(|x| x.value).unwrap_or_else(U256::zero), gas: U256::from(gas_limit.unwrap_or(u64::MAX)), - target_is_cold: self.executor.is_cold(code_address, None), + target_is_cold, target_exists: self.executor.exists(code_address), }; diff --git a/runtime/common/src/precompile/mod.rs b/runtime/common/src/precompile/mod.rs index bee189140d..23a1a5a3d3 100644 --- a/runtime/common/src/precompile/mod.rs +++ b/runtime/common/src/precompile/mod.rs @@ -31,10 +31,11 @@ use module_evm::{ Blake2F, Bn128Add, Bn128Mul, Bn128Pairing, ECRecover, ECRecoverPublicKey, Identity, IstanbulModexp, Modexp, Precompile, Ripemd160, Sha256, Sha3FIPS256, Sha3FIPS512, }, - ExitRevert, PrecompileFailure, PrecompileHandle, PrecompileResult, PrecompileSet, + ExitRevert, IsPrecompileResult, PrecompileFailure, PrecompileHandle, PrecompileResult, PrecompileSet, }; use module_support::{PrecompileCallerFilter, PrecompilePauseFilter}; use sp_core::H160; +use sp_runtime::traits::Zero; use sp_std::{collections::btree_set::BTreeSet, marker::PhantomData}; pub mod dex; @@ -234,7 +235,11 @@ where fn execute(&self, handle: &mut impl PrecompileHandle) -> Option { let context = handle.context(); let address = handle.code_address(); - if !self.is_precompile(address) { + + if let IsPrecompileResult::Answer { + is_precompile: false, .. + } = self.is_precompile(address, u64::zero()) + { return None; } @@ -343,8 +348,19 @@ where result } - fn is_precompile(&self, address: H160) -> bool { - self.set.contains(&address) || E::is_precompile(&Default::default(), address) + fn is_precompile(&self, address: H160, _remaining_gas: u64) -> IsPrecompileResult { + let is_precompile = { + self.set.contains(&address) + || match E::is_precompile(&Default::default(), address, u64::zero()) { + IsPrecompileResult::Answer { is_precompile, .. } => is_precompile, + _ => false, + } + }; + + IsPrecompileResult::Answer { + is_precompile, + extra_cost: 0, + } } } @@ -369,8 +385,11 @@ where } } - fn is_precompile(&self, address: H160) -> bool { - address == LIQUID_CROWDLOAN + fn is_precompile(&self, address: H160, _remaining_gas: u64) -> IsPrecompileResult { + IsPrecompileResult::Answer { + is_precompile: address == LIQUID_CROWDLOAN, + extra_cost: 0, + } } } From 25f55c11b425db29f2dc2d62812f566c3654f2ec Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Tue, 16 Jan 2024 21:33:40 +0800 Subject: [PATCH 08/22] fix eip-3860 ref: https://github.com/rust-ethereum/evm/pull/160 --- Cargo.lock | 8 ++++---- modules/evm-utility/Cargo.toml | 6 +++--- modules/evm/src/runner/state.rs | 9 ++++----- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2e5ae0a00e..0d498e758f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=5fb8a4957c642134782e184c47f7d7b5a29f3629#5fb8a4957c642134782e184c47f7d7b5a29f3629" +source = "git+https://github.com/rust-blockchain/evm?rev=b436a7f4b34a1bc63857938f09a32ecd397537c9#b436a7f4b34a1bc63857938f09a32ecd397537c9" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=5fb8a4957c642134782e184c47f7d7b5a29f3629#5fb8a4957c642134782e184c47f7d7b5a29f3629" +source = "git+https://github.com/rust-blockchain/evm?rev=b436a7f4b34a1bc63857938f09a32ecd397537c9#b436a7f4b34a1bc63857938f09a32ecd397537c9" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=5fb8a4957c642134782e184c47f7d7b5a29f3629#5fb8a4957c642134782e184c47f7d7b5a29f3629" +source = "git+https://github.com/rust-blockchain/evm?rev=b436a7f4b34a1bc63857938f09a32ecd397537c9#b436a7f4b34a1bc63857938f09a32ecd397537c9" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=5fb8a4957c642134782e184c47f7d7b5a29f3629#5fb8a4957c642134782e184c47f7d7b5a29f3629" +source = "git+https://github.com/rust-blockchain/evm?rev=b436a7f4b34a1bc63857938f09a32ecd397537c9#b436a7f4b34a1bc63857938f09a32ecd397537c9" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 55b828260d..9bc41b84c7 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "5fb8a4957c642134782e184c47f7d7b5a29f3629", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "5fb8a4957c642134782e184c47f7d7b5a29f3629", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "5fb8a4957c642134782e184c47f7d7b5a29f3629", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "b436a7f4b34a1bc63857938f09a32ecd397537c9", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "b436a7f4b34a1bc63857938f09a32ecd397537c9", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "b436a7f4b34a1bc63857938f09a32ecd397537c9", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 25adb1aa30..456d8f9c10 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -509,8 +509,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu // EIP-3860 if init_code.len() > limit { self.state.metadata_mut().gasometer.fail(); - let _ = self.exit_substate(StackExitKind::Failed); - return Err(ExitError::OutOfGas); + return Err(ExitError::CreateContractLimit); } return self .state @@ -542,7 +541,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu if init_code.len() > limit { self.state.metadata_mut().gasometer.fail(); let _ = self.exit_substate(StackExitKind::Failed); - return emit_exit!(ExitError::InitCodeLimit.into(), Vec::new()); + return emit_exit!(ExitError::CreateContractLimit.into(), Vec::new()); } } @@ -583,7 +582,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu if init_code.len() > limit { self.state.metadata_mut().gasometer.fail(); let _ = self.exit_substate(StackExitKind::Failed); - return emit_exit!(ExitError::InitCodeLimit.into(), Vec::new()); + return emit_exit!(ExitError::CreateContractLimit.into(), Vec::new()); } } @@ -642,7 +641,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu if init_code.len() > limit { self.state.metadata_mut().gasometer.fail(); let _ = self.exit_substate(StackExitKind::Failed); - return emit_exit!(ExitError::InitCodeLimit.into(), Vec::new()); + return emit_exit!(ExitError::CreateContractLimit.into(), Vec::new()); } } From 5a41d40ba1515f0e912da8255597343625de2539 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 17 Jan 2024 14:44:57 +0800 Subject: [PATCH 09/22] update runtime config ref: https://github.com/rust-ethereum/evm/pull/161 --- Cargo.lock | 8 +++--- modules/evm-utility/Cargo.toml | 6 ++-- modules/evm/src/lib.rs | 9 ++++-- modules/evm/src/runner/state.rs | 35 +++++++++++++++--------- modules/evm/src/runner/tagged_runtime.rs | 4 +-- 5 files changed, 38 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d498e758f..e7b2c97b00 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=b436a7f4b34a1bc63857938f09a32ecd397537c9#b436a7f4b34a1bc63857938f09a32ecd397537c9" +source = "git+https://github.com/rust-blockchain/evm?rev=e7138f7234b117d29d4e653da4967d76e51c5eaf#e7138f7234b117d29d4e653da4967d76e51c5eaf" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=b436a7f4b34a1bc63857938f09a32ecd397537c9#b436a7f4b34a1bc63857938f09a32ecd397537c9" +source = "git+https://github.com/rust-blockchain/evm?rev=e7138f7234b117d29d4e653da4967d76e51c5eaf#e7138f7234b117d29d4e653da4967d76e51c5eaf" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=b436a7f4b34a1bc63857938f09a32ecd397537c9#b436a7f4b34a1bc63857938f09a32ecd397537c9" +source = "git+https://github.com/rust-blockchain/evm?rev=e7138f7234b117d29d4e653da4967d76e51c5eaf#e7138f7234b117d29d4e653da4967d76e51c5eaf" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=b436a7f4b34a1bc63857938f09a32ecd397537c9#b436a7f4b34a1bc63857938f09a32ecd397537c9" +source = "git+https://github.com/rust-blockchain/evm?rev=e7138f7234b117d29d4e653da4967d76e51c5eaf#e7138f7234b117d29d4e653da4967d76e51c5eaf" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 9bc41b84c7..fb5636132a 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "b436a7f4b34a1bc63857938f09a32ecd397537c9", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "b436a7f4b34a1bc63857938f09a32ecd397537c9", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "b436a7f4b34a1bc63857938f09a32ecd397537c9", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "e7138f7234b117d29d4e653da4967d76e51c5eaf", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "e7138f7234b117d29d4e653da4967d76e51c5eaf", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "e7138f7234b117d29d4e653da4967d76e51c5eaf", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index 1c224109fc..99c21838ae 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -414,8 +414,13 @@ pub mod module { let state = SubstrateStackState::::new(&vicinity, metadata); let mut executor = StackExecutor::new_with_precompiles(state, T::config(), &()); - let mut runtime = - evm::Runtime::new(Rc::new(account.code.clone()), Rc::new(Vec::new()), context, T::config()); + let mut runtime = evm::Runtime::new( + Rc::new(account.code.clone()), + Rc::new(Vec::new()), + context, + T::config().stack_limit, + T::config().memory_limit, + ); let reason = executor.execute(&mut runtime); assert!( diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 456d8f9c10..ecaea81a4f 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -408,7 +408,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } /// Execute the runtime until it returns. - pub fn execute(&mut self, runtime: &mut Runtime<'config>) -> ExitReason { + pub fn execute(&mut self, runtime: &mut Runtime) -> ExitReason { let mut call_stack = Vec::with_capacity(DEFAULT_CALL_STACK_CAPACITY); call_stack.push(TaggedRuntime { kind: RuntimeKind::Execute, @@ -419,10 +419,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } /// Execute using Runtimes on the call_stack until it returns. - fn execute_with_call_stack<'borrow>( - &mut self, - call_stack: &mut Vec>, - ) -> (ExitReason, Option, Vec) { + fn execute_with_call_stack(&mut self, call_stack: &mut Vec) -> (ExitReason, Option, Vec) { // This `interrupt_runtime` is used to pass the runtime obtained from the // `Capture::Trap` branch in the match below back to the top of the call stack. // The reason we can't simply `push` the runtime directly onto the stack in the @@ -831,7 +828,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu init_code: Vec, target_gas: Option, take_l64: bool, - ) -> Capture<(ExitReason, Option, Vec), StackExecutorCreateInterrupt<'config>> { + ) -> Capture<(ExitReason, Option, Vec), StackExecutorCreateInterrupt<'static>> { macro_rules! try_or_fail { ( $e:expr ) => { match $e { @@ -937,7 +934,13 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu self.state.inc_nonce(address); } - let runtime = Runtime::new(Rc::new(init_code), Rc::new(Vec::new()), context, self.config); + let runtime = Runtime::new( + Rc::new(init_code), + Rc::new(Vec::new()), + context, + self.config.stack_limit, + self.config.memory_limit, + ); Capture::Trap(StackExecutorCreateInterrupt(TaggedRuntime { kind: RuntimeKind::Create(address), @@ -956,7 +959,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu take_l64: bool, take_stipend: bool, context: Context, - ) -> Capture<(ExitReason, Vec), StackExecutorCallInterrupt<'config>> { + ) -> Capture<(ExitReason, Vec), StackExecutorCallInterrupt<'static>> { macro_rules! try_or_fail { ( $e:expr ) => { match $e { @@ -1064,7 +1067,13 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu }; } - let runtime = Runtime::new(Rc::new(code), Rc::new(input), context, self.config); + let runtime = Runtime::new( + Rc::new(code), + Rc::new(input), + context, + self.config.stack_limit, + self.config.memory_limit, + ); Capture::Trap(StackExecutorCallInterrupt(TaggedRuntime { kind: RuntimeKind::Call(code_address), @@ -1162,15 +1171,15 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } } -pub struct StackExecutorCallInterrupt<'config>(TaggedRuntime<'config, 'config>); -pub struct StackExecutorCreateInterrupt<'config>(TaggedRuntime<'config, 'config>); +pub struct StackExecutorCallInterrupt<'borrow>(TaggedRuntime<'borrow>); +pub struct StackExecutorCreateInterrupt<'borrow>(TaggedRuntime<'borrow>); impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler for StackExecutor<'config, 'precompiles, S, P> { - type CreateInterrupt = StackExecutorCreateInterrupt<'config>; + type CreateInterrupt = StackExecutorCreateInterrupt<'static>; type CreateFeedback = Infallible; - type CallInterrupt = StackExecutorCallInterrupt<'config>; + type CallInterrupt = StackExecutorCallInterrupt<'static>; type CallFeedback = Infallible; fn balance(&self, address: H160) -> U256 { diff --git a/modules/evm/src/runner/tagged_runtime.rs b/modules/evm/src/runner/tagged_runtime.rs index 16da6ad9e4..88ad8275a4 100644 --- a/modules/evm/src/runner/tagged_runtime.rs +++ b/modules/evm/src/runner/tagged_runtime.rs @@ -19,9 +19,9 @@ use module_evm_utility::evm::{maybe_borrowed::MaybeBorrowed, Runtime}; use sp_core::H160; -pub struct TaggedRuntime<'config, 'borrow> { +pub struct TaggedRuntime<'borrow> { pub kind: RuntimeKind, - pub inner: MaybeBorrowed<'borrow, Runtime<'config>>, + pub inner: MaybeBorrowed<'borrow, Runtime>, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] From 05f64182e9dc374e4fce4ca33284e9caaadfa292 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 17 Jan 2024 14:52:56 +0800 Subject: [PATCH 10/22] add eip-4399 ref: https://github.com/rust-ethereum/evm/pull/162 --- Cargo.lock | 8 ++++---- modules/evm-utility/Cargo.toml | 6 +++--- modules/evm/src/runner/stack.rs | 4 ++++ modules/evm/src/runner/state.rs | 8 +++++++- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7b2c97b00..015be8b56f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=e7138f7234b117d29d4e653da4967d76e51c5eaf#e7138f7234b117d29d4e653da4967d76e51c5eaf" +source = "git+https://github.com/rust-blockchain/evm?rev=21972c2392af3381bbfcd2139664ba3fff0ee287#21972c2392af3381bbfcd2139664ba3fff0ee287" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=e7138f7234b117d29d4e653da4967d76e51c5eaf#e7138f7234b117d29d4e653da4967d76e51c5eaf" +source = "git+https://github.com/rust-blockchain/evm?rev=21972c2392af3381bbfcd2139664ba3fff0ee287#21972c2392af3381bbfcd2139664ba3fff0ee287" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=e7138f7234b117d29d4e653da4967d76e51c5eaf#e7138f7234b117d29d4e653da4967d76e51c5eaf" +source = "git+https://github.com/rust-blockchain/evm?rev=21972c2392af3381bbfcd2139664ba3fff0ee287#21972c2392af3381bbfcd2139664ba3fff0ee287" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=e7138f7234b117d29d4e653da4967d76e51c5eaf#e7138f7234b117d29d4e653da4967d76e51c5eaf" +source = "git+https://github.com/rust-blockchain/evm?rev=21972c2392af3381bbfcd2139664ba3fff0ee287#21972c2392af3381bbfcd2139664ba3fff0ee287" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index fb5636132a..4227554bf8 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "e7138f7234b117d29d4e653da4967d76e51c5eaf", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "e7138f7234b117d29d4e653da4967d76e51c5eaf", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "e7138f7234b117d29d4e653da4967d76e51c5eaf", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "21972c2392af3381bbfcd2139664ba3fff0ee287", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "21972c2392af3381bbfcd2139664ba3fff0ee287", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "21972c2392af3381bbfcd2139664ba3fff0ee287", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/runner/stack.rs b/modules/evm/src/runner/stack.rs index 9bd9051ec0..69574c9e92 100644 --- a/modules/evm/src/runner/stack.rs +++ b/modules/evm/src/runner/stack.rs @@ -621,6 +621,10 @@ impl<'vicinity, 'config, T: Config> BackendT for SubstrateStackState<'vicinity, self.vicinity.origin } + fn block_randomness(&self) -> Option { + None + } + fn block_hash(&self, number: U256) -> H256 { if number > U256::from(u32::MAX) { H256::default() diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index ecaea81a4f..34ae037891 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -419,7 +419,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } /// Execute using Runtimes on the call_stack until it returns. - fn execute_with_call_stack(&mut self, call_stack: &mut Vec) -> (ExitReason, Option, Vec) { + fn execute_with_call_stack( + &mut self, + call_stack: &mut Vec>, + ) -> (ExitReason, Option, Vec) { // This `interrupt_runtime` is used to pass the runtime obtained from the // `Capture::Trap` branch in the match below back to the top of the call stack. // The reason we can't simply `push` the runtime directly onto the stack in the @@ -1279,6 +1282,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler fn block_difficulty(&self) -> U256 { self.state.block_difficulty() } + fn block_randomness(&self) -> Option { + self.state.block_randomness() + } fn block_gas_limit(&self) -> U256 { self.state.block_gas_limit() } From 47cb26fd37bce3b0fbc7d2cad94d0bad37d48fcb Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 17 Jan 2024 15:05:24 +0800 Subject: [PATCH 11/22] fix eip-2618 ref: https://github.com/rust-ethereum/evm/pull/163 --- Cargo.lock | 8 ++++---- modules/evm-utility/Cargo.toml | 6 +++--- modules/evm/src/lib.rs | 2 +- modules/evm/src/runner/stack.rs | 3 ++- modules/evm/src/runner/state.rs | 18 ++++++++++++------ 5 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 015be8b56f..e878deace4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=21972c2392af3381bbfcd2139664ba3fff0ee287#21972c2392af3381bbfcd2139664ba3fff0ee287" +source = "git+https://github.com/rust-blockchain/evm?rev=0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e#0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=21972c2392af3381bbfcd2139664ba3fff0ee287#21972c2392af3381bbfcd2139664ba3fff0ee287" +source = "git+https://github.com/rust-blockchain/evm?rev=0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e#0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=21972c2392af3381bbfcd2139664ba3fff0ee287#21972c2392af3381bbfcd2139664ba3fff0ee287" +source = "git+https://github.com/rust-blockchain/evm?rev=0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e#0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=21972c2392af3381bbfcd2139664ba3fff0ee287#21972c2392af3381bbfcd2139664ba3fff0ee287" +source = "git+https://github.com/rust-blockchain/evm?rev=0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e#0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 4227554bf8..05d471400c 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "21972c2392af3381bbfcd2139664ba3fff0ee287", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "21972c2392af3381bbfcd2139664ba3fff0ee287", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "21972c2392af3381bbfcd2139664ba3fff0ee287", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index 99c21838ae..559a861c99 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -1519,7 +1519,7 @@ impl Pallet { let balance = T::Currency::free_balance(&account_id); Account { - nonce: U256::from(UniqueSaturatedInto::::unique_saturated_into(nonce)), + nonce: UniqueSaturatedInto::::unique_saturated_into(nonce), balance: U256::from(UniqueSaturatedInto::::unique_saturated_into( convert_decimals_to_evm(balance), )), diff --git a/modules/evm/src/runner/stack.rs b/modules/evm/src/runner/stack.rs index 69574c9e92..bc30562238 100644 --- a/modules/evm/src/runner/stack.rs +++ b/modules/evm/src/runner/stack.rs @@ -733,8 +733,9 @@ impl<'vicinity, 'config, T: Config> StackStateT<'config> for SubstrateStackState self.substate.deleted(address) } - fn inc_nonce(&mut self, address: H160) { + fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError> { Pallet::::inc_nonce(&address); + Ok(()) } fn set_storage(&mut self, address: H160, index: H256, value: H256) { diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 34ae037891..ae4a8d7dc2 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -324,7 +324,7 @@ pub trait StackState<'config>: Backend { fn is_cold(&self, address: H160) -> bool; fn is_storage_cold(&self, address: H160, key: H256) -> bool; - fn inc_nonce(&mut self, address: H160); + fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError>; fn set_storage(&mut self, address: H160, key: H256, value: H256); fn reset_storage(&mut self, address: H160); fn log(&mut self, address: H160, topics: Vec, data: Vec); @@ -691,7 +691,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu gas_limit: u64, access_list: Vec<(H160, Vec)>, ) -> (ExitReason, Vec) { - self.state.inc_nonce(caller); + if let Err(e) = self.state.inc_nonce(caller) { + return (e.into(), Vec::new()); + } event!(TransactCall { caller, @@ -772,7 +774,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } /// Get account nonce. - pub fn nonce(&self, address: H160) -> U256 { + pub fn nonce(&self, address: H160) -> u64 { self.state.basic(address).nonce } @@ -877,7 +879,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu return Capture::Exit((ExitError::OutOfFund.into(), None, Vec::new())); } - self.state.inc_nonce(caller); + if let Err(e) = self.state.inc_nonce(caller) { + return Capture::Exit((e.into(), None, Vec::new())); + } let after_gas = if take_l64 && self.config.call_l64_after_gas { if self.config.estimate { @@ -906,7 +910,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } // We will keep the nonce until the storages are cleared. - if self.nonce(address) > U256::zero() { + if self.nonce(address) > 0 { let _ = self.exit_substate(StackExitKind::Failed); return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new())); } @@ -934,7 +938,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } if self.config.create_increase_nonce { - self.state.inc_nonce(address); + if let Err(e) = self.state.inc_nonce(address) { + return Capture::Exit((e.into(), None, Vec::new())); + } } let runtime = Runtime::new( From 8d17aa8b86fa5a90e9a67205e28fe66cf6ebfeb0 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 17 Jan 2024 15:14:19 +0800 Subject: [PATCH 12/22] fix nonce back to U256 ref: https://github.com/rust-ethereum/evm/pull/166 --- Cargo.lock | 16 ++++++++-------- modules/evm-utility/Cargo.toml | 6 +++--- modules/evm/src/lib.rs | 2 +- modules/evm/src/runner/state.rs | 4 ++-- modules/evm/src/tests.rs | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e878deace4..c8b672f522 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3605,8 +3605,8 @@ dependencies = [ [[package]] name = "evm" -version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e#0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e" +version = "0.38.0" +source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" dependencies = [ "auto_impl", "environmental", @@ -3625,8 +3625,8 @@ dependencies = [ [[package]] name = "evm-core" -version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e#0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e" +version = "0.38.0" +source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3636,8 +3636,8 @@ dependencies = [ [[package]] name = "evm-gasometer" -version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e#0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e" +version = "0.38.0" +source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" dependencies = [ "environmental", "evm-core", @@ -3683,8 +3683,8 @@ dependencies = [ [[package]] name = "evm-runtime" -version = "0.37.0" -source = "git+https://github.com/rust-blockchain/evm?rev=0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e#0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e" +version = "0.38.0" +source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 05d471400c..86644538ce 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "0e035609b0ac5f54cf77b6bb7a1cbc17e2ad6e2e", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index 559a861c99..99c21838ae 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -1519,7 +1519,7 @@ impl Pallet { let balance = T::Currency::free_balance(&account_id); Account { - nonce: UniqueSaturatedInto::::unique_saturated_into(nonce), + nonce: U256::from(UniqueSaturatedInto::::unique_saturated_into(nonce)), balance: U256::from(UniqueSaturatedInto::::unique_saturated_into( convert_decimals_to_evm(balance), )), diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index ae4a8d7dc2..2b01057095 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -774,7 +774,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } /// Get account nonce. - pub fn nonce(&self, address: H160) -> u64 { + pub fn nonce(&self, address: H160) -> U256 { self.state.basic(address).nonce } @@ -910,7 +910,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } // We will keep the nonce until the storages are cleared. - if self.nonce(address) > 0 { + if self.nonce(address) > U256::zero() { let _ = self.exit_substate(StackExitKind::Failed); return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new())); } diff --git a/modules/evm/src/tests.rs b/modules/evm/src/tests.rs index f06005c65f..af9bd22a25 100644 --- a/modules/evm/src/tests.rs +++ b/modules/evm/src/tests.rs @@ -115,13 +115,13 @@ fn should_calculate_contract_address() { Ok(H160::from_str("d654cB21c05cb14895baae28159b1107e9DbD6E4").unwrap()) ); - executor.state_mut().inc_nonce(addr); + assert_ok!(executor.state_mut().inc_nonce(addr)); assert_eq!( executor.create_address(evm::CreateScheme::Legacy { caller: addr }), Ok(H160::from_str("97784910F057B07bFE317b0552AE23eF34644Aed").unwrap()) ); - executor.state_mut().inc_nonce(addr); + assert_ok!(executor.state_mut().inc_nonce(addr)); assert_eq!( executor.create_address(evm::CreateScheme::Legacy { caller: addr }), Ok(H160::from_str("82155a21E0Ccaee9D4239a582EB2fDAC1D9237c5").unwrap()) From 298a3007617f7178930e0f6a1345852097ce0f29 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 17 Jan 2024 22:26:40 +0800 Subject: [PATCH 13/22] remove exit_substate in create functions ref: https://github.com/rust-ethereum/evm/pull/168 --- modules/evm/src/runner/state.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 2b01057095..4d291ba9ab 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -540,7 +540,6 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu if let Some(limit) = self.config.max_initcode_size { if init_code.len() > limit { self.state.metadata_mut().gasometer.fail(); - let _ = self.exit_substate(StackExitKind::Failed); return emit_exit!(ExitError::CreateContractLimit.into(), Vec::new()); } } @@ -581,7 +580,6 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu if let Some(limit) = self.config.max_initcode_size { if init_code.len() > limit { self.state.metadata_mut().gasometer.fail(); - let _ = self.exit_substate(StackExitKind::Failed); return emit_exit!(ExitError::CreateContractLimit.into(), Vec::new()); } } @@ -640,7 +638,6 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu if let Some(limit) = self.config.max_initcode_size { if init_code.len() > limit { self.state.metadata_mut().gasometer.fail(); - let _ = self.exit_substate(StackExitKind::Failed); return emit_exit!(ExitError::CreateContractLimit.into(), Vec::new()); } } From 8a5dbb9005512a1d8597efad3d532c6cad68f4b7 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 18 Jan 2024 18:28:36 +0800 Subject: [PATCH 14/22] record external cost ref: https://github.com/rust-ethereum/evm/pull/170 --- Cargo.lock | 16 +++---- modules/evm-utility/Cargo.toml | 6 +-- modules/evm/src/lib.rs | 2 +- modules/evm/src/precompiles/mod.rs | 8 ++++ modules/evm/src/runner/state.rs | 71 ++++++++++++++++++++++++++++-- 5 files changed, 87 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c8b672f522..b97fdc9e12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3605,8 +3605,8 @@ dependencies = [ [[package]] name = "evm" -version = "0.38.0" -source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" +version = "0.39.1" +source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" dependencies = [ "auto_impl", "environmental", @@ -3625,8 +3625,8 @@ dependencies = [ [[package]] name = "evm-core" -version = "0.38.0" -source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" +version = "0.39.0" +source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3636,8 +3636,8 @@ dependencies = [ [[package]] name = "evm-gasometer" -version = "0.38.0" -source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" +version = "0.39.0" +source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" dependencies = [ "environmental", "evm-core", @@ -3683,8 +3683,8 @@ dependencies = [ [[package]] name = "evm-runtime" -version = "0.38.0" -source = "git+https://github.com/rust-blockchain/evm?rev=adfa174ca6e021e9b0f530bd87e20989eaab31ca#adfa174ca6e021e9b0f530bd87e20989eaab31ca" +version = "0.39.0" +source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 86644538ce..7e3fb82086 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "adfa174ca6e021e9b0f530bd87e20989eaab31ca", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index 99c21838ae..c801fc43c8 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -49,7 +49,7 @@ pub use module_evm_utility::{ evm::{ self, executor::stack::{IsPrecompileResult, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileSet}, - Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, + Config as EvmConfig, Context, ExitError, ExitFatal, ExitReason, ExitRevert, ExitSucceed, ExternalOperation, }, Account, }; diff --git a/modules/evm/src/precompiles/mod.rs b/modules/evm/src/precompiles/mod.rs index 7d90a0a6cd..32de1f73e2 100644 --- a/modules/evm/src/precompiles/mod.rs +++ b/modules/evm/src/precompiles/mod.rs @@ -147,6 +147,14 @@ pub mod tests { } } + fn record_external_cost(&mut self, _ref_time: Option, _proof_size: Option) -> Result<(), ExitError> { + unimplemented!() + } + + fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) { + unimplemented!() + } + fn remaining_gas(&self) -> u64 { unimplemented!() } diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 4d291ba9ab..690ef9f2a7 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -349,6 +349,21 @@ pub trait StackState<'config>: Backend { fn code_hash(&self, address: H160) -> H256 { H256::from_slice(Keccak256::digest(self.code(address)).as_slice()) } + + fn record_external_dynamic_opcode_cost( + &mut self, + _opcode: Opcode, + _gas_cost: gasometer::GasCost, + _target: StorageTarget, + ) -> Result<(), ExitError> { + Ok(()) + } + + fn record_external_cost(&mut self, _ref_time: Option, _proof_size: Option) -> Result<(), ExitError> { + Ok(()) + } + + fn refund_external_cost(&mut self, _ref_time: Option, _proof_size: Option) {} } /// A precompile result. @@ -725,6 +740,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu self.initialize_with_access_list(access_list); } + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AccountBasicRead) { + return (e.into(), Vec::new()); + } + let context = Context { caller, address, @@ -876,6 +895,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu return Capture::Exit((ExitError::OutOfFund.into(), None, Vec::new())); } + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AccountBasicRead) { + return Capture::Exit((ExitReason::Error(e), None, Vec::new())); + } + if let Err(e) = self.state.inc_nonce(caller) { return Capture::Exit((e.into(), None, Vec::new())); } @@ -901,7 +924,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu self.enter_substate(gas_limit, false); { - if self.code_size(address) != U256::zero() { + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AddressCodeRead(address)) { + let _ = self.exit_substate(StackExitKind::Failed); + return Capture::Exit((ExitReason::Error(e), None, Vec::new())); + } + let code_size = self.code_size(address); + if code_size != U256::zero() { let _ = self.exit_substate(StackExitKind::Failed); return Capture::Exit((ExitError::CreateCollision.into(), None, Vec::new())); } @@ -935,6 +963,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } if self.config.create_increase_nonce { + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AccountBasicRead) { + let _ = self.exit_substate(StackExitKind::Failed); + return Capture::Exit((ExitReason::Error(e), None, Vec::new())); + } if let Err(e) = self.state.inc_nonce(address) { return Capture::Exit((e.into(), None, Vec::new())); } @@ -1015,11 +1047,15 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } } - let code = self.code(code_address); - self.enter_substate(gas_limit, is_static); self.state.touch(context.address); + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AddressCodeRead(code_address)) { + let _ = self.exit_substate(StackExitKind::Failed); + return Capture::Exit((ExitReason::Error(e), Vec::new())); + } + let code = self.code(code_address); + if let Some(depth) = self.state.metadata().depth { if depth > self.config.call_stack_limit { let _ = self.exit_substate(StackExitKind::Reverted); @@ -1028,6 +1064,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu } if let Some(transfer) = transfer { + if let Err(e) = self.record_external_operation(crate::ExternalOperation::AccountBasicRead) { + let _ = self.exit_substate(StackExitKind::Failed); + return Capture::Exit((ExitReason::Error(e), Vec::new())); + } match self.state.transfer(transfer) { Ok(()) => (), Err(e) => { @@ -1125,6 +1165,9 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu Ok(()) => { self.state.set_code(address, out); let exit_result = self.exit_substate(StackExitKind::Succeeded); + if let Err(e) = self.record_external_operation(crate::ExternalOperation::Write) { + return (e.into(), None, Vec::new()); + } if let Err(e) = exit_result { return (e.into(), None, Vec::new()); } @@ -1438,6 +1481,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler let gasometer = &mut self.state.metadata_mut().gasometer; gasometer.record_dynamic_cost(gas_cost, memory_cost)?; + + self.state + .record_external_dynamic_opcode_cost(opcode, gas_cost, target)?; + match target { StorageTarget::Address(address) => self.state.metadata_mut().access_address(address), StorageTarget::Slot(address, key) => self.state.metadata_mut().access_storage(address, key), @@ -1447,6 +1494,10 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler Ok(()) } + + fn record_external_operation(&mut self, op: crate::ExternalOperation) -> Result<(), ExitError> { + self.state.record_external_operation(op) + } } struct StackExecutorHandle<'inner, 'config, 'precompiles, S, P> { @@ -1481,11 +1532,13 @@ impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Pr Err(err) => return (ExitReason::Error(err), Vec::new()), }; + let target_exists = self.executor.exists(code_address); + let gas_cost = gasometer::GasCost::Call { value: transfer.clone().map(|x| x.value).unwrap_or_else(U256::zero), gas: U256::from(gas_limit.unwrap_or(u64::MAX)), target_is_cold, - target_exists: self.executor.exists(code_address), + target_exists, }; // We record the length of the input. @@ -1543,6 +1596,16 @@ impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Pr self.executor.state.metadata_mut().gasometer.record_cost(cost) } + /// Record Substrate specific cost. + fn record_external_cost(&mut self, ref_time: Option, proof_size: Option) -> Result<(), ExitError> { + self.executor.state.record_external_cost(ref_time, proof_size) + } + + /// Refund Substrate specific cost. + fn refund_external_cost(&mut self, ref_time: Option, proof_size: Option) { + self.executor.state.refund_external_cost(ref_time, proof_size); + } + /// Retreive the remaining gas. fn remaining_gas(&self) -> u64 { self.executor.state.metadata().gasometer.gas() From 322eca3adc5f104e767b2892c80220a5a546e9e8 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 18 Jan 2024 19:29:30 +0800 Subject: [PATCH 15/22] add record_external_operation ref: https://github.com/rust-ethereum/evm/pull/171 --- Cargo.lock | 8 ++++---- modules/evm-utility/Cargo.toml | 6 +++--- modules/evm/src/runner/state.rs | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b97fdc9e12..6744f00791 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.39.1" -source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" +source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" +source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" +source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=e85c34f96e3237c09955193b41154030b78119c5#e85c34f96e3237c09955193b41154030b78119c5" +source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index 7e3fb82086..f7a7a5992e 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "e85c34f96e3237c09955193b41154030b78119c5", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 690ef9f2a7..3f9e671a95 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -350,6 +350,10 @@ pub trait StackState<'config>: Backend { H256::from_slice(Keccak256::digest(self.code(address)).as_slice()) } + fn record_external_operation(&mut self, _op: crate::ExternalOperation) -> Result<(), ExitError> { + Ok(()) + } + fn record_external_dynamic_opcode_cost( &mut self, _opcode: Opcode, From f46585edd38ad299fec529e939d23fc1d320455a Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Sat, 20 Jan 2024 10:30:14 +0800 Subject: [PATCH 16/22] add storage_growth ref: https://github.com/rust-ethereum/evm/pull/173 --- Cargo.lock | 8 ++++---- modules/evm-utility/Cargo.toml | 6 +++--- modules/evm/src/precompiles/mod.rs | 7 ++++++- modules/evm/src/runner/state.rs | 23 +++++++++++++++++++---- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6744f00791..213faf1a05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3606,7 +3606,7 @@ dependencies = [ [[package]] name = "evm" version = "0.39.1" -source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65" +source = "git+https://github.com/rust-blockchain/evm?rev=44bb77c27be9ee615eaa576ad914fbb461537276#44bb77c27be9ee615eaa576ad914fbb461537276" dependencies = [ "auto_impl", "environmental", @@ -3626,7 +3626,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65" +source = "git+https://github.com/rust-blockchain/evm?rev=44bb77c27be9ee615eaa576ad914fbb461537276#44bb77c27be9ee615eaa576ad914fbb461537276" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3637,7 +3637,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65" +source = "git+https://github.com/rust-blockchain/evm?rev=44bb77c27be9ee615eaa576ad914fbb461537276#44bb77c27be9ee615eaa576ad914fbb461537276" dependencies = [ "environmental", "evm-core", @@ -3684,7 +3684,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=b7b82c7e1fc57b7449d6dfa6826600de37cc1e65#b7b82c7e1fc57b7449d6dfa6826600de37cc1e65" +source = "git+https://github.com/rust-blockchain/evm?rev=44bb77c27be9ee615eaa576ad914fbb461537276#44bb77c27be9ee615eaa576ad914fbb461537276" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index f7a7a5992e..e40fa49f38 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,9 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "b7b82c7e1fc57b7449d6dfa6826600de37cc1e65", default-features = false } +evm = { git = "https://github.com/rust-blockchain/evm", rev = "44bb77c27be9ee615eaa576ad914fbb461537276", default-features = false, features = ["with-codec"] } +evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "44bb77c27be9ee615eaa576ad914fbb461537276", default-features = false } +evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "44bb77c27be9ee615eaa576ad914fbb461537276", default-features = false } #evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } #evm-gasometer = { version = "0.41.0", default-features = false } #evm-runtime = { version = "0.41.0", default-features = false } diff --git a/modules/evm/src/precompiles/mod.rs b/modules/evm/src/precompiles/mod.rs index 32de1f73e2..ef415cfaf8 100644 --- a/modules/evm/src/precompiles/mod.rs +++ b/modules/evm/src/precompiles/mod.rs @@ -147,7 +147,12 @@ pub mod tests { } } - fn record_external_cost(&mut self, _ref_time: Option, _proof_size: Option) -> Result<(), ExitError> { + fn record_external_cost( + &mut self, + _ref_time: Option, + _proof_size: Option, + _storage_growth: Option, + ) -> Result<(), ExitError> { unimplemented!() } diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 3f9e671a95..17a14d18cd 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -363,7 +363,12 @@ pub trait StackState<'config>: Backend { Ok(()) } - fn record_external_cost(&mut self, _ref_time: Option, _proof_size: Option) -> Result<(), ExitError> { + fn record_external_cost( + &mut self, + _ref_time: Option, + _proof_size: Option, + _storage_growth: Option, + ) -> Result<(), ExitError> { Ok(()) } @@ -1167,9 +1172,12 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> StackExecu match self.state.metadata_mut().gasometer.record_deposit(out.len()) { Ok(()) => { + let code_len = out.len(); self.state.set_code(address, out); let exit_result = self.exit_substate(StackExitKind::Succeeded); - if let Err(e) = self.record_external_operation(crate::ExternalOperation::Write) { + if let Err(e) = + self.record_external_operation(crate::ExternalOperation::Write(U256::from(code_len))) + { return (e.into(), None, Vec::new()); } if let Err(e) = exit_result { @@ -1601,8 +1609,15 @@ impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Pr } /// Record Substrate specific cost. - fn record_external_cost(&mut self, ref_time: Option, proof_size: Option) -> Result<(), ExitError> { - self.executor.state.record_external_cost(ref_time, proof_size) + fn record_external_cost( + &mut self, + ref_time: Option, + proof_size: Option, + storage_growth: Option, + ) -> Result<(), ExitError> { + self.executor + .state + .record_external_cost(ref_time, proof_size, storage_growth) } /// Refund Substrate specific cost. From ba375e9829aabf2874aeed1f2cffa50c4a8c78e6 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Sat, 20 Jan 2024 19:32:24 +0800 Subject: [PATCH 17/22] update evm --- Cargo.lock | 22 +++++++++++++--------- modules/evm-utility/Cargo.toml | 9 +++------ 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 213faf1a05..7683b618eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3605,12 +3605,13 @@ dependencies = [ [[package]] name = "evm" -version = "0.39.1" -source = "git+https://github.com/rust-blockchain/evm?rev=44bb77c27be9ee615eaa576ad914fbb461537276#44bb77c27be9ee615eaa576ad914fbb461537276" +version = "0.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "767f43e9630cc36cf8ff2777cbb0121b055f0d1fd6eaaa13b46a1808f0d0e7e9" dependencies = [ "auto_impl", "environmental", - "ethereum 0.14.0", + "ethereum 0.15.0", "evm-core", "evm-gasometer", "evm-runtime", @@ -3625,8 +3626,9 @@ dependencies = [ [[package]] name = "evm-core" -version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=44bb77c27be9ee615eaa576ad914fbb461537276#44bb77c27be9ee615eaa576ad914fbb461537276" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da6cedc5cedb4208e59467106db0d1f50db01b920920589f8e672c02fdc04f" dependencies = [ "parity-scale-codec", "primitive-types", @@ -3636,8 +3638,9 @@ dependencies = [ [[package]] name = "evm-gasometer" -version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=44bb77c27be9ee615eaa576ad914fbb461537276#44bb77c27be9ee615eaa576ad914fbb461537276" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dc0eb591abc5cd7b05bef6a036c2bb6c66ab6c5e0c5ce94bfe377ab670b1fd7" dependencies = [ "environmental", "evm-core", @@ -3683,8 +3686,9 @@ dependencies = [ [[package]] name = "evm-runtime" -version = "0.39.0" -source = "git+https://github.com/rust-blockchain/evm?rev=44bb77c27be9ee615eaa576ad914fbb461537276#44bb77c27be9ee615eaa576ad914fbb461537276" +version = "0.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84bbe09b64ae13a29514048c1bb6fda6374ac0b4f6a1f15a443348ab88ef42cd" dependencies = [ "auto_impl", "environmental", diff --git a/modules/evm-utility/Cargo.toml b/modules/evm-utility/Cargo.toml index e40fa49f38..6cd409a0ae 100644 --- a/modules/evm-utility/Cargo.toml +++ b/modules/evm-utility/Cargo.toml @@ -9,12 +9,9 @@ sha3 = { workspace = true } sp-std = { workspace = true } -evm = { git = "https://github.com/rust-blockchain/evm", rev = "44bb77c27be9ee615eaa576ad914fbb461537276", default-features = false, features = ["with-codec"] } -evm-gasometer = { git = "https://github.com/rust-blockchain/evm", rev = "44bb77c27be9ee615eaa576ad914fbb461537276", default-features = false } -evm-runtime = { git = "https://github.com/rust-blockchain/evm", rev = "44bb77c27be9ee615eaa576ad914fbb461537276", default-features = false } -#evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } -#evm-gasometer = { version = "0.41.0", default-features = false } -#evm-runtime = { version = "0.41.0", default-features = false } +evm = { version = "0.41.1", default-features = false, features = ["with-codec"] } +evm-gasometer = { version = "0.41.0", default-features = false } +evm-runtime = { version = "0.41.0", default-features = false } ethereum = { version = "0.15.0", default-features = false, features = ["with-codec"] } [features] From 407678313fd9a34da8cf5141c32e63fc89dde60c Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Mon, 22 Jan 2024 10:18:08 +0800 Subject: [PATCH 18/22] switch to shanghai hardfork --- modules/asset-registry/src/mock.rs | 4 ++-- modules/currencies/src/mock.rs | 2 +- modules/evm-bridge/src/mock.rs | 6 +++--- modules/evm/src/bench/mod.rs | 8 +++++++- modules/evm/src/lib.rs | 6 +++--- modules/evm/src/runner/state.rs | 2 +- modules/evm/src/tests.rs | 22 +++++++++++----------- modules/honzon-bridge/src/mock.rs | 2 +- runtime/common/src/bench/mod.rs | 19 +++++++++++-------- runtime/integration-tests/src/evm.rs | 8 ++++---- runtime/integration-tests/src/honzon.rs | 4 ++-- runtime/mandala/src/benchmarking/evm.rs | 4 ++-- 12 files changed, 48 insertions(+), 39 deletions(-) diff --git a/modules/asset-registry/src/mock.rs b/modules/asset-registry/src/mock.rs index 56b11f8259..7bfdb36217 100644 --- a/modules/asset-registry/src/mock.rs +++ b/modules/asset-registry/src/mock.rs @@ -201,7 +201,7 @@ pub fn deploy_contracts() { H256::from_slice(&buf).as_bytes().to_vec() }, }], - used_gas: 1235081, + used_gas: 1235455, used_storage: 5131, })); @@ -242,7 +242,7 @@ pub fn deploy_contracts_same_prefix() { H256::from_slice(&buf).as_bytes().to_vec() }, }], - used_gas: 1235081, + used_gas: 1235455, used_storage: 5131, })); diff --git a/modules/currencies/src/mock.rs b/modules/currencies/src/mock.rs index 40798af73e..e2ea6743fd 100644 --- a/modules/currencies/src/mock.rs +++ b/modules/currencies/src/mock.rs @@ -303,7 +303,7 @@ pub fn deploy_contracts() { H256::from_slice(&buf).as_bytes().to_vec() }, }], - used_gas: 1235081, + used_gas: 1235455, used_storage: 5131, })); diff --git a/modules/evm-bridge/src/mock.rs b/modules/evm-bridge/src/mock.rs index 4db15241e7..2c2f56c545 100644 --- a/modules/evm-bridge/src/mock.rs +++ b/modules/evm-bridge/src/mock.rs @@ -203,7 +203,7 @@ pub fn deploy_contracts() { H256::from_slice(&buf).as_bytes().to_vec() }, }], - used_gas: 1235081, + used_gas: 1235455, used_storage: 5131, })); @@ -230,7 +230,7 @@ pub fn deploy_liquidation_ok_contracts() { from: alice_evm_addr(), contract: erc20_address(), logs: vec![], - used_gas: 235274, + used_gas: 235330, used_storage: 844, })); @@ -257,7 +257,7 @@ pub fn deploy_liquidation_err_contracts() { from: alice_evm_addr(), contract: erc20_address(), logs: vec![], - used_gas: 228284, + used_gas: 228338, used_storage: 818, })); diff --git a/modules/evm/src/bench/mod.rs b/modules/evm/src/bench/mod.rs index d195b631e3..7376000572 100644 --- a/modules/evm/src/bench/mod.rs +++ b/modules/evm/src/bench/mod.rs @@ -80,7 +80,13 @@ fn whitelist_keys(b: &mut Bencher, from: H160, code: Vec) -> H160 { let state = SubstrateStackState::::new(&vicinity, metadata); let mut executor = StackExecutor::new_with_precompiles(state, config, &()); - let mut runtime = EVMRuntime::new(Rc::new(code.clone()), Rc::new(Vec::new()), context, config); + let mut runtime = EVMRuntime::new( + Rc::new(code.clone()), + Rc::new(Vec::new()), + context, + config.stack_limit, + config.memory_limit, + ); let reason = executor.execute(&mut runtime); assert!(reason.is_succeed(), "{:?}", reason); diff --git a/modules/evm/src/lib.rs b/modules/evm/src/lib.rs index c801fc43c8..7027744072 100644 --- a/modules/evm/src/lib.rs +++ b/modules/evm/src/lib.rs @@ -104,17 +104,17 @@ pub type NegativeImbalanceOf = pub const RESERVE_ID_STORAGE_DEPOSIT: ReserveIdentifier = ReserveIdentifier::EvmStorageDeposit; pub const RESERVE_ID_DEVELOPER_DEPOSIT: ReserveIdentifier = ReserveIdentifier::EvmDeveloperDeposit; -// Initially based on London hard fork configuration. +// Initially based on shanghai hard fork configuration. static ACALA_CONFIG: EvmConfig = EvmConfig { refund_sstore_clears: 0, // no gas refund sstore_gas_metering: false, // no gas refund sstore_revert_under_stipend: false, // ignored create_contract_limit: Some(MaxCodeSize::get() as usize), - ..module_evm_utility::evm::Config::london() + ..module_evm_utility::evm::Config::shanghai() }; /// Create an empty contract `contract Empty { }`. -pub const BASE_CREATE_GAS: u64 = 67_066; +pub const BASE_CREATE_GAS: u64 = 67_072; /// Call function that just set a storage `function store(uint256 num) public { number = num; }`. pub const BASE_CALL_GAS: u64 = 43_702; diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index 17a14d18cd..a1c9ffa09a 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -16,7 +16,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -// Synchronize with https://github.com/rust-blockchain/evm/blob/6534c1dd/src/executor/stack/executor.rs +// Synchronize with https://github.com/rust-blockchain/evm/blob/d543f10/src/executor/stack/executor.rs use crate::{ encode_revert_message, diff --git a/modules/evm/src/tests.rs b/modules/evm/src/tests.rs index af9bd22a25..6fafc33618 100644 --- a/modules/evm/src/tests.rs +++ b/modules/evm/src/tests.rs @@ -777,7 +777,7 @@ fn publish_factory() { ) .unwrap(); assert_eq!(result.exit_reason, ExitReason::Succeed(ExitSucceed::Returned)); - assert_eq!(result.used_gas.as_u64(), 155_879u64); + assert_eq!(result.used_gas.as_u64(), 155925); assert_eq!(result.used_storage, 461); assert_eq!( balance(alice()), @@ -818,7 +818,7 @@ fn create_nft_contract_works() { from: NetworkContractSource::get(), contract: MIRRORED_TOKENS_ADDRESS_START | H160::from_low_u64_be(MIRRORED_NFT_ADDRESS_START), logs: vec![], - used_gas: 93183, + used_gas: 93197, used_storage: 284, })); assert_eq!(EVM::network_contract_index(), MIRRORED_NFT_ADDRESS_START + 1); @@ -888,7 +888,7 @@ fn create_predeploy_contract_works() { from: NetworkContractSource::get(), contract: addr, logs: vec![], - used_gas: 93183, + used_gas: 93197, used_storage: 284, })); @@ -1877,7 +1877,7 @@ fn evm_execute_mode_should_work() { CallInfo { exit_reason: ExitReason::Succeed(ExitSucceed::Stopped), value: vec![], - used_gas: U256::from(142_445), + used_gas: U256::from(142451), used_storage: expected_used_storage, logs: vec![] } @@ -1904,7 +1904,7 @@ fn evm_execute_mode_should_work() { CallInfo { exit_reason: ExitReason::Succeed(ExitSucceed::Stopped), value: vec![], - used_gas: U256::from(259_561), + used_gas: U256::from(259573), used_storage: expected_used_storage, logs: vec![] } @@ -1964,7 +1964,7 @@ fn evm_execute_mode_should_work() { CallInfo { exit_reason: ExitReason::Succeed(ExitSucceed::Stopped), value: vec![], - used_gas: U256::from(110_469), + used_gas: U256::from(110475), used_storage: expected_used_storage, logs: vec![] } @@ -2007,7 +2007,7 @@ fn evm_execute_mode_should_work() { CallInfo { exit_reason: ExitReason::Succeed(ExitSucceed::Stopped), value: vec![], - used_gas: U256::from(93_369), + used_gas: U256::from(93375), used_storage: expected_used_storage, logs: vec![] } @@ -2293,7 +2293,7 @@ fn auto_publish_works() { from: alice(), contract: factory, logs: vec![], - used_gas: 593209, + used_gas: 593369, used_storage: 2609, })); @@ -2328,7 +2328,7 @@ fn auto_publish_works() { data: vec![], }, ], - used_gas: 387664, + used_gas: 387768, used_storage: 1530, })); @@ -2398,7 +2398,7 @@ fn auto_publish_works() { data: vec![], }, ], - used_gas: 370564, + used_gas: 370668, used_storage: 1466, })); @@ -2455,7 +2455,7 @@ fn auto_publish_works() { ], data: vec![], }], - used_gas: 147214, + used_gas: 147228, used_storage: 407, })); diff --git a/modules/honzon-bridge/src/mock.rs b/modules/honzon-bridge/src/mock.rs index a3a19cf7cf..cadcae46a5 100644 --- a/modules/honzon-bridge/src/mock.rs +++ b/modules/honzon-bridge/src/mock.rs @@ -262,7 +262,7 @@ pub fn deploy_contracts() { H256::from_slice(&buf).as_bytes().to_vec() }, }], - used_gas: 1235081, + used_gas: 1235455, used_storage: 5131, })); diff --git a/runtime/common/src/bench/mod.rs b/runtime/common/src/bench/mod.rs index 513e12fdc7..73d4796de5 100644 --- a/runtime/common/src/bench/mod.rs +++ b/runtime/common/src/bench/mod.rs @@ -22,7 +22,10 @@ pub use crate::{precompile::mock::*, DEXPrecompile, EVMPrecompile, OraclePrecompile}; use frame_support::assert_ok; use hex_literal::hex; -use module_evm::{precompiles::Precompile, Context}; +use module_evm::{ + precompiles::{tests::MockPrecompileHandle, Precompile}, + Context, +}; use module_support::AddressMapping; use orml_traits::DataFeeder; use primitives::currency::{AssetMetadata, TokenInfo}; @@ -121,7 +124,7 @@ fn oracle_get_price(b: &mut Bencher) { "}; let resp = b - .bench(|| OraclePrecompile::::execute(&input, None, &context, false)) + .bench(|| OraclePrecompile::::execute(&mut MockPrecompileHandle::new(&input, None, &context, false))) .unwrap(); assert_eq!(resp.output, expected_output); @@ -148,7 +151,7 @@ fn evm_query_new_contract_extra_bytes(b: &mut Bencher) { "}; let resp = b - .bench(|| EVMPrecompile::::execute(&input, None, &context, false)) + .bench(|| EVMPrecompile::::execute(&mut MockPrecompileHandle::new(&input, None, &context, false))) .unwrap(); assert_eq!(resp.output, expected_output); @@ -175,7 +178,7 @@ fn evm_query_storage_deposit_per_byte(b: &mut Bencher) { "}; let resp = b - .bench(|| EVMPrecompile::::execute(&input, None, &context, false)) + .bench(|| EVMPrecompile::::execute(&mut MockPrecompileHandle::new(&input, None, &context, false))) .unwrap(); assert_eq!(resp.output, expected_output); @@ -216,7 +219,7 @@ fn evm_query_maintainer(b: &mut Bencher) { "}; let resp = b - .bench(|| EVMPrecompile::::execute(&input, None, &context, false)) + .bench(|| EVMPrecompile::::execute(&mut MockPrecompileHandle::new(&input, None, &context, false))) .unwrap(); assert_eq!(resp.output, expected_output); @@ -243,7 +246,7 @@ fn evm_query_developer_deposit(b: &mut Bencher) { "}; let resp = b - .bench(|| EVMPrecompile::::execute(&input, None, &context, false)) + .bench(|| EVMPrecompile::::execute(&mut MockPrecompileHandle::new(&input, None, &context, false))) .unwrap(); assert_eq!(resp.output, expected_output); } @@ -269,7 +272,7 @@ fn evm_query_publication_fee(b: &mut Bencher) { "}; let resp = b - .bench(|| EVMPrecompile::::execute(&input, None, &context, false)) + .bench(|| EVMPrecompile::::execute(&mut MockPrecompileHandle::new(&input, None, &context, false))) .unwrap(); assert_eq!(resp.output, expected_output); } @@ -297,7 +300,7 @@ fn evm_query_developer_status(b: &mut Bencher) { "}; let resp = b - .bench(|| EVMPrecompile::::execute(&input, None, &context, false)) + .bench(|| EVMPrecompile::::execute(&mut MockPrecompileHandle::new(&input, None, &context, false))) .unwrap(); assert_eq!(resp.output, expected_output); } diff --git a/runtime/integration-tests/src/evm.rs b/runtime/integration-tests/src/evm.rs index b76b95326c..3c6676f2b6 100644 --- a/runtime/integration-tests/src/evm.rs +++ b/runtime/integration-tests/src/evm.rs @@ -107,7 +107,7 @@ pub fn deploy_erc20_contracts() { H256::from_slice(&buf).as_bytes().to_vec() }, }], - used_gas: 1235081, + used_gas: 1235455, used_storage: 15130, })); @@ -143,7 +143,7 @@ pub fn deploy_erc20_contracts() { H256::from_slice(&buf).as_bytes().to_vec() }, }], - used_gas: 1235081, + used_gas: 1235455, used_storage: 15130, })); @@ -349,7 +349,7 @@ fn test_evm_module() { from: alice_address, contract, logs: vec![], - used_gas: 132199, + used_gas: 132225, used_storage: 10367, })); @@ -1136,7 +1136,7 @@ fn create_contract_use_none_native_token_to_charge_storage() { from: EvmAddress::from_str("0x414d1f1c39e8357acfa07e8aac63cc5da8f9ca4d").unwrap(), contract: EvmAddress::from_str("0xa764c25fe7641aeb21ac08118fa343093b9cb30d").unwrap(), logs: vec![], - used_gas: 132199, + used_gas: 132225, used_storage: 10367, })); } diff --git a/runtime/integration-tests/src/honzon.rs b/runtime/integration-tests/src/honzon.rs index 8eb73a0b95..d781f24e3b 100644 --- a/runtime/integration-tests/src/honzon.rs +++ b/runtime/integration-tests/src/honzon.rs @@ -98,7 +98,7 @@ pub fn deploy_liquidation_contracts() { from: repayment_evm_addr(), contract: mock_liquidation_address_0(), logs: vec![], - used_gas: 473252, + used_gas: 473376, used_storage: 11949, })); @@ -117,7 +117,7 @@ pub fn deploy_liquidation_contracts() { from: repayment_evm_addr(), contract: mock_liquidation_address_1(), logs: vec![], - used_gas: 473252, + used_gas: 473376, used_storage: 11949, })); diff --git a/runtime/mandala/src/benchmarking/evm.rs b/runtime/mandala/src/benchmarking/evm.rs index 8682788155..14ea2ec22c 100644 --- a/runtime/mandala/src/benchmarking/evm.rs +++ b/runtime/mandala/src/benchmarking/evm.rs @@ -56,8 +56,8 @@ fn deploy_contract(caller: AccountId) -> Result { from: module_evm_accounts::EvmAddressMapping::::get_evm_address(&caller).unwrap(), contract: contract_addr(), logs: vec![], - used_gas: 132_199, - used_storage: 10_367, + used_gas: 132225, + used_storage: 10367, })); Ok(contract_addr()) } From d7ca9ffda818480b822dfd047899c42f4df04272 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Mon, 22 Jan 2024 10:46:55 +0800 Subject: [PATCH 19/22] fix tests --- evm-bench | 2 +- ts-tests/tests/test-gas.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/evm-bench b/evm-bench index 134b8c8476..0c0fa3380a 160000 --- a/evm-bench +++ b/evm-bench @@ -1 +1 @@ -Subproject commit 134b8c8476f1b04256c4a011bd69bd36477409f5 +Subproject commit 0c0fa3380a3fa8d2bf70216f9ce2eddaf9f1b17e diff --git a/ts-tests/tests/test-gas.ts b/ts-tests/tests/test-gas.ts index 37a55c64f0..e3281b84f6 100644 --- a/ts-tests/tests/test-gas.ts +++ b/ts-tests/tests/test-gas.ts @@ -27,7 +27,7 @@ describeWithAcala("Acala RPC (Gas)", (context) => { data: "0x" + Block.bytecode, }); - expect(data.usedGas.toNumber()).to.be.eq(251726); + expect(data.usedGas.toNumber()).to.be.eq(251786); expect(data.gasLimit.toNumber()).closeTo(302071, 1000); expect(data.usedStorage.toNumber()).to.be.eq(10921); }); From 2c7f562868472f3d30050b99219c96278c933047 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Wed, 24 Jan 2024 20:39:28 +0800 Subject: [PATCH 20/22] fix tests --- modules/evm/src/runner/state.rs | 4 +++- modules/evm/src/runner/tagged_runtime.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/evm/src/runner/state.rs b/modules/evm/src/runner/state.rs index e0518613e4..1caba41197 100644 --- a/modules/evm/src/runner/state.rs +++ b/modules/evm/src/runner/state.rs @@ -98,6 +98,8 @@ macro_rules! emit_exit { }}; } +// Default call stack capacity that can be used to +// execute the stack without reallocating. const DEFAULT_CALL_STACK_CAPACITY: usize = 4; pub enum StackExitKind { @@ -1512,7 +1514,7 @@ impl<'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Handler } } -struct StackExecutorHandle<'inner, 'config, 'precompiles, S, P> { +pub struct StackExecutorHandle<'inner, 'config, 'precompiles, S, P> { executor: &'inner mut StackExecutor<'config, 'precompiles, S, P>, code_address: H160, input: &'inner [u8], diff --git a/modules/evm/src/runner/tagged_runtime.rs b/modules/evm/src/runner/tagged_runtime.rs index 88ad8275a4..aa0c58fe79 100644 --- a/modules/evm/src/runner/tagged_runtime.rs +++ b/modules/evm/src/runner/tagged_runtime.rs @@ -1,6 +1,6 @@ // This file is part of Acala. -// Copyright (C) 2020-2023 Acala Foundation. +// Copyright (C) 2020-2024 Acala Foundation. // SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0 // This program is free software: you can redistribute it and/or modify From f0013a417561130a334a034e40723b7280caab1a Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 25 Jan 2024 00:51:52 +0800 Subject: [PATCH 21/22] fix evm-tests --- Cargo.lock | 60 +++++------------------ evm-tests | 2 +- modules/evm/src/precompiles/blake2/mod.rs | 13 +++++ modules/evm/src/precompiles/bn128.rs | 39 +++++++++++++++ modules/evm/src/precompiles/mod.rs | 20 ++++++++ modules/evm/src/precompiles/modexp.rs | 26 ++++++++++ modules/evm/src/runner/stack.rs | 2 +- primitives/src/evm.rs | 2 + runtime/mandala/src/lib.rs | 4 +- 9 files changed, 117 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2a2f4603cc..b48b8e657b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1149,7 +1149,7 @@ version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a399848a68a5196a04c19db5bfc4dca3cd0989a3165150f06c1ad1bc8882aa34" dependencies = [ - "hash-db 0.16.0", + "hash-db", "log", ] @@ -3512,24 +3512,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "ethereum" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a89fb87a9e103f71b903b80b670200b54cc67a07578f070681f1fffb7396fb7" -dependencies = [ - "bytes", - "ethereum-types", - "hash-db 0.15.2", - "hash256-std-hasher", - "parity-scale-codec", - "rlp", - "scale-info", - "serde", - "sha3", - "triehash", -] - [[package]] name = "ethereum" version = "0.15.0" @@ -3538,7 +3520,7 @@ checksum = "2e04d24d20b8ff2235cffbf242d5092de3aa45f77c5270ddbfadd2778ca13fea" dependencies = [ "bytes", "ethereum-types", - "hash-db 0.16.0", + "hash-db", "hash256-std-hasher", "parity-scale-codec", "rlp", @@ -3610,7 +3592,7 @@ checksum = "767f43e9630cc36cf8ff2777cbb0121b055f0d1fd6eaaa13b46a1808f0d0e7e9" dependencies = [ "auto_impl", "environmental", - "ethereum 0.15.0", + "ethereum", "evm-core", "evm-gasometer", "evm-runtime", @@ -3653,7 +3635,7 @@ version = "0.13.1" dependencies = [ "acala-primitives", "env_logger", - "ethereum 0.14.0", + "ethereum", "ethjson", "frame-support", "frame-system", @@ -4566,12 +4548,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "hash-db" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d23bd4e7b5eda0d0f3a307e8b381fdc8ba9000f26fbe912250c0a4cc3956364a" - [[package]] name = "hash-db" version = "0.16.0" @@ -6464,7 +6440,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808b50db46293432a45e63bc15ea51e0ab4c0a1647b8eb114e31a3e698dd6fbe" dependencies = [ - "hash-db 0.16.0", + "hash-db", ] [[package]] @@ -6983,7 +6959,7 @@ dependencies = [ name = "module-evm-utility" version = "2.23.0" dependencies = [ - "ethereum 0.15.0", + "ethereum", "evm", "evm-gasometer", "evm-runtime", @@ -12318,7 +12294,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4ced79f609a44782874d856cf39d256838957195ef34f4fb8ced90bf4b725d0" dependencies = [ - "hash-db 0.16.0", + "hash-db", "kvdb", "kvdb-memorydb", "kvdb-rocksdb", @@ -13958,7 +13934,7 @@ version = "23.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f582f92ce47c86e4ffffe81fdd5120fea7c850dc0800653a7fa203bcc1532335" dependencies = [ - "hash-db 0.16.0", + "hash-db", "log", "parity-scale-codec", "scale-info", @@ -14183,7 +14159,7 @@ dependencies = [ "dyn-clonable", "ed25519-zebra 3.1.0", "futures", - "hash-db 0.16.0", + "hash-db", "hash256-std-hasher", "impl-serde", "lazy_static", @@ -14545,7 +14521,7 @@ version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96e087fa4430befd2047b61d912c9d6fa4eaed408c4b58b46c6e9acd7965f2d3" dependencies = [ - "hash-db 0.16.0", + "hash-db", "log", "parity-scale-codec", "parking_lot 0.12.1", @@ -14666,7 +14642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e359b358263cc322c3f678c272a3a519621d9853dcfa1374dfcbdb5f54c6f85" dependencies = [ "ahash 0.8.6", - "hash-db 0.16.0", + "hash-db", "hashbrown 0.13.2", "lazy_static", "memory-db", @@ -15688,7 +15664,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff28e0f815c2fea41ebddf148e008b077d2faddb026c9555b29696114d602642" dependencies = [ - "hash-db 0.16.0", + "hash-db", "hashbrown 0.13.2", "log", "rustc-hex", @@ -15701,17 +15677,7 @@ version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4ed310ef5ab98f5fa467900ed906cb9232dd5376597e00fd4cba2a449d06c0b" dependencies = [ - "hash-db 0.16.0", -] - -[[package]] -name = "triehash" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1631b201eb031b563d2e85ca18ec8092508e262a3196ce9bd10a67ec87b9f5c" -dependencies = [ - "hash-db 0.15.2", - "rlp", + "hash-db", ] [[package]] diff --git a/evm-tests b/evm-tests index 767a1f025d..a214e67035 160000 --- a/evm-tests +++ b/evm-tests @@ -1 +1 @@ -Subproject commit 767a1f025d74e383108ba5e0c778b65350e88a1a +Subproject commit a214e6703549208c9168a26b1e107ff8519ec4a6 diff --git a/modules/evm/src/precompiles/blake2/mod.rs b/modules/evm/src/precompiles/blake2/mod.rs index 28640540f4..05cd18f352 100644 --- a/modules/evm/src/precompiles/blake2/mod.rs +++ b/modules/evm/src/precompiles/blake2/mod.rs @@ -106,6 +106,19 @@ impl Precompile for Blake2F { output: output_buf.to_vec(), }) } + + #[cfg(feature = "evm-tests")] + fn execute_ext( + input: &[u8], + target_gas: Option, + context: &crate::Context, + is_static: bool, + ) -> Result<(PrecompileOutput, u64), PrecompileFailure> { + let mut handle = crate::precompiles::tests::MockPrecompileHandle::new(&input, target_gas, context, is_static); + let output = Self::execute(&mut handle)?; + + Ok((output, handle.gas_used)) + } } #[cfg(test)] diff --git a/modules/evm/src/precompiles/bn128.rs b/modules/evm/src/precompiles/bn128.rs index 14a0c0781c..c73983899c 100644 --- a/modules/evm/src/precompiles/bn128.rs +++ b/modules/evm/src/precompiles/bn128.rs @@ -97,6 +97,19 @@ impl Precompile for Bn128Add { output: buf.to_vec(), }) } + + #[cfg(feature = "evm-tests")] + fn execute_ext( + input: &[u8], + target_gas: Option, + context: &crate::Context, + is_static: bool, + ) -> Result<(PrecompileOutput, u64), PrecompileFailure> { + let mut handle = crate::precompiles::tests::MockPrecompileHandle::new(&input, target_gas, context, is_static); + let output = Self::execute(&mut handle)?; + + Ok((output, handle.gas_used)) + } } /// The Bn128Mul builtin @@ -137,6 +150,19 @@ impl Precompile for Bn128Mul { output: buf.to_vec(), }) } + + #[cfg(feature = "evm-tests")] + fn execute_ext( + input: &[u8], + target_gas: Option, + context: &crate::Context, + is_static: bool, + ) -> Result<(PrecompileOutput, u64), PrecompileFailure> { + let mut handle = crate::precompiles::tests::MockPrecompileHandle::new(&input, target_gas, context, is_static); + let output = Self::execute(&mut handle)?; + + Ok((output, handle.gas_used)) + } } /// The Bn128Pairing builtin @@ -236,6 +262,19 @@ impl Precompile for Bn128Pairing { output: buf.to_vec(), }) } + + #[cfg(feature = "evm-tests")] + fn execute_ext( + input: &[u8], + target_gas: Option, + context: &crate::Context, + is_static: bool, + ) -> Result<(PrecompileOutput, u64), PrecompileFailure> { + let mut handle = crate::precompiles::tests::MockPrecompileHandle::new(&input, target_gas, context, is_static); + let output = Self::execute(&mut handle)?; + + Ok((output, handle.gas_used)) + } } #[cfg(test)] diff --git a/modules/evm/src/precompiles/mod.rs b/modules/evm/src/precompiles/mod.rs index ca55c57bd0..c616b2639e 100644 --- a/modules/evm/src/precompiles/mod.rs +++ b/modules/evm/src/precompiles/mod.rs @@ -48,6 +48,14 @@ pub trait Precompile { /// `target_gas`. Return `Ok(status, output, gas_used)` if the execution is /// successful. Otherwise return `Err(_)`. fn execute(handle: &mut impl PrecompileHandle) -> PrecompileResult; + + #[cfg(feature = "evm-tests")] + fn execute_ext( + input: &[u8], + target_gas: Option, + context: &crate::Context, + is_static: bool, + ) -> Result<(PrecompileOutput, u64), PrecompileFailure>; } pub trait LinearCostPrecompile { @@ -66,6 +74,18 @@ impl Precompile for T { let (exit_status, output) = T::execute(handle.input(), cost)?; Ok(PrecompileOutput { exit_status, output }) } + + #[cfg(feature = "evm-tests")] + fn execute_ext( + input: &[u8], + target_gas: Option, + context: &crate::Context, + is_static: bool, + ) -> Result<(PrecompileOutput, u64), PrecompileFailure> { + let cost = ensure_linear_cost(target_gas, input.len() as u64, T::BASE, T::WORD)?; + let (exit_status, output) = T::execute(input, cost)?; + Ok((PrecompileOutput { exit_status, output }, cost)) + } } /// Linear gas cost diff --git a/modules/evm/src/precompiles/modexp.rs b/modules/evm/src/precompiles/modexp.rs index 6f15b2ddd2..586c82b23f 100644 --- a/modules/evm/src/precompiles/modexp.rs +++ b/modules/evm/src/precompiles/modexp.rs @@ -295,6 +295,19 @@ impl Precompile for IstanbulModexp { output, }) } + + #[cfg(feature = "evm-tests")] + fn execute_ext( + input: &[u8], + target_gas: Option, + context: &crate::Context, + is_static: bool, + ) -> Result<(PrecompileOutput, u64), PrecompileFailure> { + let mut handle = crate::precompiles::tests::MockPrecompileHandle::new(&input, target_gas, context, is_static); + let output = Self::execute(&mut handle)?; + + Ok((output, handle.gas_used)) + } } impl Precompile for Modexp { @@ -335,6 +348,19 @@ impl Precompile for Modexp { output, }) } + + #[cfg(feature = "evm-tests")] + fn execute_ext( + input: &[u8], + target_gas: Option, + context: &crate::Context, + is_static: bool, + ) -> Result<(PrecompileOutput, u64), PrecompileFailure> { + let mut handle = crate::precompiles::tests::MockPrecompileHandle::new(&input, target_gas, context, is_static); + let output = Self::execute(&mut handle)?; + + Ok((output, handle.gas_used)) + } } #[cfg(test)] diff --git a/modules/evm/src/runner/stack.rs b/modules/evm/src/runner/stack.rs index af2079f8d6..7d812ac43d 100644 --- a/modules/evm/src/runner/stack.rs +++ b/modules/evm/src/runner/stack.rs @@ -622,7 +622,7 @@ impl<'vicinity, 'config, T: Config> BackendT for SubstrateStackState<'vicinity, } fn block_randomness(&self) -> Option { - None + self.vicinity.block_randomness } fn block_hash(&self, number: U256) -> H256 { diff --git a/primitives/src/evm.rs b/primitives/src/evm.rs index 9eb096969e..3df77f3e3c 100644 --- a/primitives/src/evm.rs +++ b/primitives/src/evm.rs @@ -73,6 +73,8 @@ pub struct Vicinity { pub block_difficulty: Option, /// Environmental base fee per gas. pub block_base_fee_per_gas: Option, + /// Environmental randomness. + pub block_randomness: Option, } #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug, TypeInfo)] diff --git a/runtime/mandala/src/lib.rs b/runtime/mandala/src/lib.rs index 34c0d193cf..f4621f2767 100644 --- a/runtime/mandala/src/lib.rs +++ b/runtime/mandala/src/lib.rs @@ -1644,7 +1644,7 @@ impl> frame_support::traits::Get for TxFeePerGasV2 { } #[cfg(feature = "with-ethereum-compatibility")] -static LONDON_CONFIG: module_evm_utility::evm::Config = module_evm_utility::evm::Config::london(); +static SHANGHAI_CONFIG: module_evm_utility::evm::Config = module_evm_utility::evm::Config::shanghai(); impl module_evm::Config for Runtime { type AddressMapping = EvmAddressMapping; @@ -1673,7 +1673,7 @@ impl module_evm::Config for Runtime { #[cfg(feature = "with-ethereum-compatibility")] fn config() -> &'static module_evm_utility::evm::Config { - &LONDON_CONFIG + &SHANGHAI_CONFIG } } From 4027f4daf50fe21bbfcb3d1f989cb293d6d29b56 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Sun, 28 Jan 2024 20:14:39 +0800 Subject: [PATCH 22/22] update ecrecover ref: https://github.com/polkadot-evm/frontier/pull/964 (#2696) --- modules/evm/src/precompiles/blake2/mod.rs | 2 ++ modules/evm/src/precompiles/ecrecover.rs | 18 +++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/modules/evm/src/precompiles/blake2/mod.rs b/modules/evm/src/precompiles/blake2/mod.rs index 05cd18f352..52ba4e47b8 100644 --- a/modules/evm/src/precompiles/blake2/mod.rs +++ b/modules/evm/src/precompiles/blake2/mod.rs @@ -36,6 +36,7 @@ impl Precompile for Blake2F { const BLAKE2_F_ARG_LEN: usize = 213; let input = handle.input(); + if input.len() != BLAKE2_F_ARG_LEN { return Err(PrecompileFailure::Error { exit_status: ExitError::Other( @@ -50,6 +51,7 @@ impl Precompile for Blake2F { let gas_cost: u64 = (rounds as u64) * Blake2F::GAS_COST_PER_ROUND; handle.record_cost(gas_cost)?; + let input = handle.input(); // we use from_le_bytes below to effectively swap byte order to LE if architecture is BE diff --git a/modules/evm/src/precompiles/ecrecover.rs b/modules/evm/src/precompiles/ecrecover.rs index 49d96babef..794a63007e 100644 --- a/modules/evm/src/precompiles/ecrecover.rs +++ b/modules/evm/src/precompiles/ecrecover.rs @@ -36,15 +36,15 @@ impl LinearCostPrecompile for ECRecover { let mut sig = [0u8; 65]; msg[0..32].copy_from_slice(&input[0..32]); - sig[0..32].copy_from_slice(&input[64..96]); - sig[32..64].copy_from_slice(&input[96..128]); - - sig[64] = match input[63] { - v if v > 26 && input[32..63] == [0; 31] => v - 27, - _ => { - return Ok((ExitSucceed::Returned, [0u8; 0].to_vec())); - } - }; + sig[0..32].copy_from_slice(&input[64..96]); // r + sig[32..64].copy_from_slice(&input[96..128]); // s + sig[64] = input[63]; // v + + // v can only be 27 or 28 on the full 32 bytes value. + // https://github.com/ethereum/go-ethereum/blob/a907d7e81aaeea15d80b2d3209ad8e08e3bf49e0/core/vm/contracts.go#L177 + if input[32..63] != [0u8; 31] || ![27, 28].contains(&input[63]) { + return Ok((ExitSucceed::Returned, [0u8; 0].to_vec())); + } let result = match sp_io::crypto::secp256k1_ecdsa_recover(&sig, &msg) { Ok(pubkey) => {