From e666a3c039f3b3e18d20dedd39163b4e7df22827 Mon Sep 17 00:00:00 2001 From: zjb0807 Date: Thu, 11 Jan 2024 20:33:10 +0800 Subject: [PATCH] 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(())