diff --git a/CHANGES.md b/CHANGES.md index 5eb3e76de..f12ec0c81 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.8.1] 2022-12-07 + +### Changes + +- Performance improvement (approximately 5% reduction in NEAR gas usage) by [@birchmd]. ([#645]) + +### Fixes + +- Tracing bug fix by [@birchmd]. ([#646]) + +[#645]: https://github.com/aurora-is-near/aurora-engine/pull/645 +[#646]: https://github.com/aurora-is-near/aurora-engine/pull/646 + ## [2.8.0] 2022-11-15 ### Added @@ -321,7 +334,8 @@ struct SubmitResult { ## [1.0.0] - 2021-05-12 -[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.8.0...develop +[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.8.1...develop +[2.8.1]: https://github.com/aurora-is-near/aurora-engine/compare/2.8.0...2.8.1 [2.8.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.7.0...2.8.0 [2.7.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.6.1...2.7.0 [2.6.1]: https://github.com/aurora-is-near/aurora-engine/compare/2.6.0...2.6.1 diff --git a/Cargo.lock b/Cargo.lock index 1261e44f9..d321c1287 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -127,7 +127,7 @@ dependencies = [ [[package]] name = "aurora-engine" -version = "2.8.0" +version = "2.8.1" dependencies = [ "aurora-engine-precompiles", "aurora-engine-sdk", @@ -1318,7 +1318,7 @@ dependencies = [ [[package]] name = "evm" version = "0.37.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.1-aurora#12a268120c0f6d4b3c3f35043e7f9482e7a6fd43" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.3-aurora#ad17d1c242356e25692573a5eea4b50ee80f6de3" dependencies = [ "auto_impl", "environmental", @@ -1338,7 +1338,7 @@ dependencies = [ [[package]] name = "evm-core" version = "0.37.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.1-aurora#12a268120c0f6d4b3c3f35043e7f9482e7a6fd43" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.3-aurora#ad17d1c242356e25692573a5eea4b50ee80f6de3" dependencies = [ "parity-scale-codec", "primitive-types 0.12.1", @@ -1349,7 +1349,7 @@ dependencies = [ [[package]] name = "evm-gasometer" version = "0.37.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.1-aurora#12a268120c0f6d4b3c3f35043e7f9482e7a6fd43" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.3-aurora#ad17d1c242356e25692573a5eea4b50ee80f6de3" dependencies = [ "environmental", "evm-core", @@ -1360,7 +1360,7 @@ dependencies = [ [[package]] name = "evm-runtime" version = "0.37.0" -source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.1-aurora#12a268120c0f6d4b3c3f35043e7f9482e7a6fd43" +source = "git+https://github.com/aurora-is-near/sputnikvm.git?tag=v0.37.3-aurora#ad17d1c242356e25692573a5eea4b50ee80f6de3" dependencies = [ "auto_impl", "environmental", diff --git a/VERSION b/VERSION index 834f26295..dbe590065 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.8.0 +2.8.1 diff --git a/engine-precompiles/Cargo.toml b/engine-precompiles/Cargo.toml index 4e392d9ce..b5b57b9a5 100644 --- a/engine-precompiles/Cargo.toml +++ b/engine-precompiles/Cargo.toml @@ -17,7 +17,7 @@ aurora-engine-types = { path = "../engine-types", default-features = false } aurora-engine-sdk = { path = "../engine-sdk", default-features = false } borsh = { version = "0.9.3", default-features = false } bn = { version = "0.5.11", package = "zeropool-bn", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false } libsecp256k1 = { version = "0.7.0", default-features = false, features = ["static-context", "hmac"] } num = { version = "0.4.0", default-features = false, features = ["alloc"] } ripemd = { version = "0.1.1", default-features = false } diff --git a/engine-standalone-storage/Cargo.toml b/engine-standalone-storage/Cargo.toml index 866a62579..889e14d9f 100644 --- a/engine-standalone-storage/Cargo.toml +++ b/engine-standalone-storage/Cargo.toml @@ -20,7 +20,7 @@ aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features aurora-engine-transactions = { path = "../engine-transactions", default-features = false, features = ["std"] } aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false, features = ["std"] } borsh = { version = "0.9.3" } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false } +evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false } hex = "0.4.3" rocksdb = { version = "0.19.0", default-features = false } postgres = "0.19.2" diff --git a/engine-standalone-tracing/Cargo.toml b/engine-standalone-tracing/Cargo.toml index b7bfb8aa3..615da9d6e 100644 --- a/engine-standalone-tracing/Cargo.toml +++ b/engine-standalone-tracing/Cargo.toml @@ -15,10 +15,10 @@ crate-type = ["lib"] [dependencies] aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } -evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std"] } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } -evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } -evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std"] } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } +evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } +evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } hex = { version = "0.4", default-features = false, features = ["std"] } serde = { version = "1", features = ["derive"], optional = true } diff --git a/engine-standalone-tracing/src/types/call_tracer.rs b/engine-standalone-tracing/src/types/call_tracer.rs index 33a695525..e54ca22a1 100644 --- a/engine-standalone-tracing/src/types/call_tracer.rs +++ b/engine-standalone-tracing/src/types/call_tracer.rs @@ -5,21 +5,21 @@ use aurora_engine_types::{types::Address, U256}; #[derive(Debug, Clone, PartialEq, Eq)] pub struct CallFrame { - call_type: CallType, - from: Address, - to: Option
, - value: U256, - gas: u64, - gas_used: u64, - input: Vec, - output: Vec, - error: Option, - calls: Vec, + pub call_type: CallType, + pub from: Address, + pub to: Option
, + pub value: U256, + pub gas: u64, + pub gas_used: u64, + pub input: Vec, + pub output: Vec, + pub error: Option, + pub calls: Vec, } #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct CallTracer { - call_stack: Vec, + pub call_stack: Vec, } impl CallTracer { @@ -163,10 +163,10 @@ impl evm::tracing::EventListener for CallTracer { } => { let call_type = if is_static { CallType::StaticCall - } else if transfer.is_none() { - CallType::DelegateCall } else if code_address == context.address { CallType::Call + } else if transfer.is_none() { + CallType::DelegateCall } else { CallType::CallCode }; diff --git a/engine-test-doubles/Cargo.toml b/engine-test-doubles/Cargo.toml index 54de5edd7..10e29048a 100644 --- a/engine-test-doubles/Cargo.toml +++ b/engine-test-doubles/Cargo.toml @@ -15,8 +15,8 @@ autobenches = false [dependencies] aurora-engine-types = { path = "../engine-types", default-features = false, features = ["std"] } aurora-engine-sdk = { path = "../engine-sdk" } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } -evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } -evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } +evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } +evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } [dev-dependencies] diff --git a/engine-tests/Cargo.toml b/engine-tests/Cargo.toml index 4a551162e..43da94dd9 100644 --- a/engine-tests/Cargo.toml +++ b/engine-tests/Cargo.toml @@ -22,12 +22,12 @@ aurora-engine-sdk = { path = "../engine-sdk", default-features = false, features aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false, features = ["std"] } aurora-engine-transactions = { path = "../engine-transactions", default-features = false, features = ["std"] } engine-standalone-storage = { path = "../engine-standalone-storage" } -engine-standalone-tracing = { path = "../engine-standalone-tracing" } +engine-standalone-tracing = { path = "../engine-standalone-tracing", default-features = false, features = ["impl-serde"] } borsh = { version = "0.9.3", default-features = false } sha3 = { version = "0.10.2", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } -evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } -evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false, features = ["std", "tracing"] } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } +evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } +evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false, features = ["std", "tracing"] } rlp = { version = "0.5.0", default-features = false } base64 = "0.13.0" bstr = "1.0.1" diff --git a/engine-tests/src/test_utils/standalone/mod.rs b/engine-tests/src/test_utils/standalone/mod.rs index 43e30b2ea..927e2d624 100644 --- a/engine-tests/src/test_utils/standalone/mod.rs +++ b/engine-tests/src/test_utils/standalone/mod.rs @@ -317,7 +317,7 @@ impl StandaloneRunner { self.storage_dir.close().unwrap(); } - fn template_tx_msg( + pub(crate) fn template_tx_msg( storage: &mut Storage, env: &env::Fixed, transaction_position: u16, diff --git a/engine-tests/src/tests/mod.rs b/engine-tests/src/tests/mod.rs index 30f18d30e..741e56ae8 100644 --- a/engine-tests/src/tests/mod.rs +++ b/engine-tests/src/tests/mod.rs @@ -22,4 +22,4 @@ mod standalone; mod standard_precompiles; mod state_migration; pub(crate) mod uniswap; -mod xcc; +pub(crate) mod xcc; diff --git a/engine-tests/src/tests/one_inch.rs b/engine-tests/src/tests/one_inch.rs index 63581b3c7..b1f4d388f 100644 --- a/engine-tests/src/tests/one_inch.rs +++ b/engine-tests/src/tests/one_inch.rs @@ -58,7 +58,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 302_000); // more than 302k EVM gas used - assert_gas_bound(profile.all_gas(), 24); + assert_gas_bound(profile.all_gas(), 23); // Same here helper.runner.context.block_timestamp += 10_000_000 * 1_000_000_000; @@ -73,7 +73,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 210_000); // more than 210k EVM gas used - assert_gas_bound(profile.all_gas(), 25); + assert_gas_bound(profile.all_gas(), 24); let (result, profile) = helper.pool_withdraw( &pool, @@ -84,7 +84,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 150_000); // more than 150k EVM gas used - assert_gas_bound(profile.all_gas(), 21); + assert_gas_bound(profile.all_gas(), 20); } #[test] diff --git a/engine-tests/src/tests/repro.rs b/engine-tests/src/tests/repro.rs index fc4be898f..1370a7cf9 100644 --- a/engine-tests/src/tests/repro.rs +++ b/engine-tests/src/tests/repro.rs @@ -27,7 +27,7 @@ fn repro_GdASJ3KESs() { block_timestamp: 1645717564644206730, input_path: "src/tests/res/input_GdASJ3KESs.hex", evm_gas_used: 706713, - near_gas_used: 131, + near_gas_used: 122, }); } @@ -52,7 +52,7 @@ fn repro_8ru7VEA() { block_timestamp: 1648829935343349589, input_path: "src/tests/res/input_8ru7VEA.hex", evm_gas_used: 1732181, - near_gas_used: 239, + near_gas_used: 223, }); } @@ -72,7 +72,7 @@ fn repro_FRcorNv() { block_timestamp: 1650960438774745116, input_path: "src/tests/res/input_FRcorNv.hex", evm_gas_used: 1239721, - near_gas_used: 194, + near_gas_used: 181, }); } @@ -89,7 +89,7 @@ fn repro_5bEgfRQ() { block_timestamp: 1651073772931594646, input_path: "src/tests/res/input_5bEgfRQ.hex", evm_gas_used: 6_414_105, - near_gas_used: 701, + near_gas_used: 657, }); } @@ -107,7 +107,7 @@ fn repro_D98vwmi() { block_timestamp: 1651753443421003245, input_path: "src/tests/res/input_D98vwmi.hex", evm_gas_used: 1_035_348, - near_gas_used: 195, + near_gas_used: 182, }); } @@ -126,7 +126,7 @@ fn repro_Emufid2() { block_timestamp: 1662118048636713538, input_path: "src/tests/res/input_Emufid2.hex", evm_gas_used: 1_156_364, - near_gas_used: 330, + near_gas_used: 306, }); } diff --git a/engine-tests/src/tests/sanity.rs b/engine-tests/src/tests/sanity.rs index eae9b9a00..fb51786bd 100644 --- a/engine-tests/src/tests/sanity.rs +++ b/engine-tests/src/tests/sanity.rs @@ -453,6 +453,34 @@ fn test_call_too_deep_error() { } } +#[test] +fn test_create_out_of_gas() { + let (mut runner, mut signer, _) = initialize_transfer(); + let constructor_code = { + // This EVM bytecode caused an integer overflow in the SputnikVM gas calculation prior to + // https://github.com/aurora-is-near/sputnikvm/pull/17 + let code = "60e041184138410745413205374848484848484848484848484848484848484848484541384107456969697835ffff004545453a4747f06262483b646464645454543030303030303030303030303030303030303030303136383432353936337a5a5a8154543838929260545454545454545454315555555555555555555a5a5a5a5a5a5a5a3d5a615a5a5a5a5a455858580153455858585801825858828282545360305858586158f05858f05830303030303030303136383431353936337a5a5a8154543838929260545454545454545454315555555d55555555555a5a5a5a5a5a5a5a5a5a5a5a5a5a5a4558585801534558585858018258588282825453601558583158183d60253d60013a58f08258853480f07e82823aabac9fcdcea7a758583d6015315858585858f058585860253d60013a3d381a3d3361333030305858586158f05858f0583af00133303030828258588282825453601531585858583d60253d60013a58f08258853580f03a82827eab3d4343468546464646464646464646836500838311111111111111111111837676767676765a5a1515fb41151514742393f0555555555555555555555555555555555555555555555555555555555555555a5a5a5a5a5a455858580153455858585801827676765a5a1515fb41151514742393f055555555555555555555554558585801534558585858018258588282825453601531585858183d60253d60013a5858853580f03a82827eab3d9fcdcea7a75858fe3d60153f484848c40200000000000034483b325885858585858585853d60013a58f08261333030305858853580f03a82827eab30ac9fcdcea7a758583d6085853d60013a58f08261333060253d5e013a3d381a3d3361333030305858586158f05858f0583af001333030308282585882828254535a1531585858583d60253d60013a58f08258853580f03a82827eab3d9fcdcea7a758583d60153f484848483b323a4545314545353a4545450945317432454545304545304545303a4545314545353a45454509453174324545453045453a3a4545453a4545303a454530453a4545303a4545324545353a454545094531743a4546464646303a4545314545353a45454509453174324545453045453a3a4545453a4545303a454530453a4545303a4545314545353a4545450945317432454545304545304545303a4545314545353a45454509453174324545453045453a3a4545453a4545303a454530453a4545303a4545324545353a454545094531743a4546464619464646464646464646464646464646464646468258588282825453601531585858183d60253d60013a58f08258853580f03a828255555555555555555555555555555555555555555555555555556b6b6b6b3a5a3a4447474747f045456464ae646464646464646c6464325858435858013658584337585843015836585858384358585858f15858f158585885854085855858f15858f158580136585843375858430158f1585836585843385843385858013658584337585843015836585843585843385843385858013658584337585843015836585843385858585858f15858f158585858f15858f15858385858585858f15858f1585858f158585858f1585836585843385843385858365858015858433758f15858385858585858f15858f1585858f158585858f158583658584338584338585801365858489292605454545454545454543030303030303030303030303030303030303030303136383431353936337a5a5a8154543838929260545454545454545454315555555555555555555a5a5a5a5a5a5a5a5a5a5a5a413205374848484848484848484848484848484848485a6128a756455f07ef93f31ef468d3bc0d17e020b320616161616161616161616161616161616161616161616161515151515151070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070707070751515151484848485151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151518d616161616141364107454132053748484848484848489060604145614138415a07614541325a5a4558585801534558585858018258588282825453601531585858183d60253d60013a58f08258853480f07e82823aabac9fcdcea7a758583d6015315858585858f058585860253d60013a3d381a3d3361333030305858586158f05858f05830303030303030303136383431353936337a5a5a815454383892926054545454827676765a5a1515fb41151514742393f05555555555555555555555555555555555555555453a4747f04545646464646464646464646c6464643a474745343a4747f045454545453a4747f06262483b646464646464646464646c64646464646464646445646464646464646464646c6464646464646464f0305830303030343a36321a34347a36311a34347d34343a30282828282828282828282828282828282828282828282828282828282828a2a230340b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b050b0b0b3030303030303030303030303030303031353038323036333333333333333333333333333333333345304545304545303a4545314545353a45454509453174324545453045453a3a454506060606060606060606060606065050505050505050505050505050505050505050503361333030305858586158f05858f0581af00133303030828258588282825453601531585858583d60253d60013a58f28258853580f03a82827eab3d9fcdcea7a7464646464646464646464646462946464646464646464646464631707432454545304545353a4545453a4545303a4545304545353a453b32588585858585853a000000000000000000583f48383838486158f05858f0583af00133303030828258588282825453601531585858583d60253d60013a58f08258853580f03a82827eab3d9fcdcea7a758583d60153f484848483b32583f48d93838483b32586e858585858585585858f058585860253d5e013a3d381a3d33613330303058584358585858f15858f158585885854085855858f15858f158580136585843375858430158f1585836585843385843385858013658584337585843015836585843585843385843385858013658584337585843015836585843385858585858f15858f158585858f15858f15858385858585858f15858f1585858f158585858f1585836585843385843385858365858015858433758586158f05858f0583af00133305858586025603d013a3d381a5d3d3361050000003b325885b0bd02f6a392af548bdf1cfaee5dfa0eefcc8eab82827eabac9fcdcea7a758583dfeffffffffffffff6015000000000000000000000000ffffff303d389a3d603dff7effffffffffffff0600f15858385858585858f15858f1585858f158585858f158583658584338584338585801365858489292605454545454545454543030303030303030303030303030303030303030303136383431353936337a5a5a8154543838929260545454545454545454315555555555555555555a5a5a5a5a5affffffffffffffffffffffffffffffffffffffffffffffffffff5a5a5a5a5a5a5a5a5a4558585801534558585858018258588282825453601531585858183d60253d60013a58f08258853480f07e82823aabac9fcdcea7a758583d6015315858580000f70000000037201616355858f058585860253d60013a3d381a3d336133303030585851586158f05858f05830303030303030303136383431353936337a5a5a8154543838929260545454545454545454315555555555555555555a5a5a325a5a5a5a5a5a5a5a5a5a5a5a4558585801534558585858018258588282825453601558583158183d60253d60013a58f08258853480f07e82823aabac000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009fcdcea7a758583d6015315858585858f058585860253d60013a3d381a3d3361333030305858586158f05858f0583af0013330303082825858828282545360153155555555555555555555555a5a5a5a5a5a4558585843468546464646464646464646838383111111111111111111ffff11837676767676765a5a1515fb41151514742393f0555555555555555555555555555555555555555555555555555555555555555a5a5a5a5a5a455858580153455858585801827676765a5a1515fb41151516742393f055555555555555555555555562483b45454545ff3a4747f06262483b4545454545453a47474745343a4747f045454555555555555555555555555555553d3d838311111111111111111111837676767676765a5a1515fb41151514742393f055483f3f453f484848483b32583f48383838483b3258858561616161616161616161616161616161615555555555555555555555555555555555555555555555556155555555618255555a82"; + hex::decode(code).unwrap() + }; + let result = runner + .submit_with_signer(&mut signer, |nonce| { + aurora_engine_transactions::legacy::TransactionLegacy { + nonce, + gas_price: U256::zero(), + gas_limit: u64::MAX.into(), + to: None, + value: Wei::zero(), + data: constructor_code, + } + }) + .unwrap(); + assert!( + matches!(result.status, TransactionStatus::OutOfGas), + "Unexpected status: {:?}", + result.status + ); +} + #[test] fn test_timestamp() { let (mut runner, mut signer, _) = initialize_transfer(); diff --git a/engine-tests/src/tests/standalone/call_tracer.rs b/engine-tests/src/tests/standalone/call_tracer.rs new file mode 100644 index 000000000..64669f08f --- /dev/null +++ b/engine-tests/src/tests/standalone/call_tracer.rs @@ -0,0 +1,350 @@ +use crate::test_utils::{self, standalone}; +use aurora_engine_types::{ + parameters::{CrossContractCallArgs, PromiseArgs, PromiseCreateArgs}, + storage, + types::{Address, NearGas, Wei, Yocto}, + U256, +}; +use borsh::BorshSerialize; +use engine_standalone_storage::sync; +use engine_standalone_tracing::{ + sputnik, + types::call_tracer::{self, CallTracer}, +}; + +#[test] +fn test_trace_precompile_direct_call() { + let mut runner = standalone::StandaloneRunner::default(); + let mut signer = test_utils::Signer::random(); + + runner.init_evm(); + + let tx = aurora_engine_transactions::legacy::TransactionLegacy { + nonce: signer.use_nonce().into(), + gas_price: U256::zero(), + gas_limit: u64::MAX.into(), + to: Some(aurora_engine_precompiles::random::RandomSeed::ADDRESS), + value: Wei::zero(), + data: Vec::new(), + }; + + let mut listener = CallTracer::default(); + let standalone_result = sputnik::traced_call(&mut listener, || { + runner.submit_transaction(&signer.secret_key, tx).unwrap() + }); + assert!(standalone_result.status.is_ok()); + assert_eq!(listener.call_stack.len(), 1); + + let trace = listener.call_stack.pop().unwrap(); + + let expected_trace = call_tracer::CallFrame { + call_type: call_tracer::CallType::Call, + from: test_utils::address_from_secret_key(&signer.secret_key), + to: Some(aurora_engine_precompiles::random::RandomSeed::ADDRESS), + value: U256::zero(), + gas: u64::MAX, + gas_used: 21000_u64, + input: Vec::new(), + output: [0u8; 32].to_vec(), + error: None, + calls: Vec::new(), + }; + + assert_eq!(trace, expected_trace); + + runner.close(); +} + +#[test] +fn test_trace_contract_single_call() { + let mut runner = standalone::StandaloneRunner::default(); + let mut signer = test_utils::Signer::random(); + let signer_address = test_utils::address_from_secret_key(&signer.secret_key); + + runner.init_evm(); + + let constructor = test_utils::erc20::ERC20Constructor::load(); + let deploy_tx = constructor.deploy("Test", "TST", signer.use_nonce().into()); + let deploy_result = runner + .submit_transaction(&signer.secret_key, deploy_tx) + .unwrap(); + let contract_address = { + let bytes = test_utils::unwrap_success_slice(&deploy_result); + Address::try_from_slice(bytes).unwrap() + }; + let contract = test_utils::erc20::ERC20(constructor.0.deployed_at(contract_address)); + + let tx = contract.balance_of(signer_address, signer.use_nonce().into()); + let mut listener = CallTracer::default(); + let standalone_result = sputnik::traced_call(&mut listener, || { + runner + .submit_transaction(&signer.secret_key, tx.clone()) + .unwrap() + }); + assert!(standalone_result.status.is_ok()); + assert_eq!(listener.call_stack.len(), 1); + + let trace = listener.call_stack.pop().unwrap(); + + let expected_trace = call_tracer::CallFrame { + call_type: call_tracer::CallType::Call, + from: signer_address, + to: Some(contract_address), + value: U256::zero(), + gas: u64::MAX, + gas_used: trace.gas_used, + input: tx.data, + output: [0u8; 32].to_vec(), + error: None, + calls: Vec::new(), + }; + + assert_eq!(trace, expected_trace); + + runner.close(); +} + +#[test] +fn test_trace_contract_with_sub_call() { + use crate::tests::uniswap::UniswapTestContext; + const MINT_AMOUNT: u64 = 1_000_000_000_000; + const LIQUIDITY_AMOUNT: u64 = MINT_AMOUNT / 5; + const OUTPUT_AMOUNT: u64 = LIQUIDITY_AMOUNT / 100; + + let mut context = UniswapTestContext::new("uniswap"); + let (token_a, token_b) = context.create_token_pair(MINT_AMOUNT.into()); + let pool = context.create_pool(&token_a, &token_b); + + let (_result, _profile) = + context.add_equal_liquidity(LIQUIDITY_AMOUNT.into(), &token_a, &token_b); + + context.approve_erc20(&token_a, context.swap_router.0.address, U256::MAX); + context.approve_erc20(&token_b, context.swap_router.0.address, U256::MAX); + let params = context.exact_output_single_params(OUTPUT_AMOUNT.into(), &token_a, &token_b); + + let mut listener = CallTracer::default(); + let (_amount_in, _profile) = sputnik::traced_call(&mut listener, || { + context + .runner + .submit_with_signer_profiled(&mut context.signer, |nonce| { + context.swap_router.exact_output_single(params, nonce) + }) + .unwrap() + }); + + assert_eq!(listener.call_stack.len(), 1); + + let user_address = test_utils::address_from_secret_key(&context.signer.secret_key); + let router_address = context.swap_router.0.address; + let pool_address = pool.0.address; + let b_address = token_b.0.address; + let a_address = token_a.0.address; + + // Call flow: + // User -> Router.exactOutputSingle -> Pool.swap -> B.transfer + // -> A.balanceOf + // -> Router.uniswapV3SwapCallback -> A.transferFrom + // -> A.balanceOf + let root_call = listener.call_stack.first().unwrap(); + assert_eq!(root_call.from, user_address); + assert_eq!(root_call.to.unwrap(), router_address); + + let call = subcall_lense(root_call, &[0]); + assert_eq!(call.from, router_address); + assert_eq!(call.to.unwrap(), pool_address); + + let call = subcall_lense(root_call, &[0, 0]); + assert_eq!(call.from, pool_address); + assert_eq!(call.to.unwrap(), b_address); + + let call = subcall_lense(root_call, &[0, 1]); + assert_eq!(call.from, pool_address); + assert_eq!(call.to.unwrap(), a_address); + + let call = subcall_lense(root_call, &[0, 2]); + assert_eq!(call.from, pool_address); + assert_eq!(call.to.unwrap(), router_address); + + let call = subcall_lense(root_call, &[0, 2, 0]); + assert_eq!(call.from, router_address); + assert_eq!(call.to.unwrap(), a_address); + + let call = subcall_lense(root_call, &[0, 3]); + assert_eq!(call.from, pool_address); + assert_eq!(call.to.unwrap(), a_address); +} + +#[test] +fn test_trace_contract_with_precompile_sub_call() { + let mut runner = standalone::StandaloneRunner::default(); + let mut signer = test_utils::Signer::random(); + + runner.init_evm(); + + let constructor = test_utils::standard_precompiles::PrecompilesConstructor::load(); + let deploy_tx = constructor.deploy(signer.use_nonce().into()); + let deploy_result = runner + .submit_transaction(&signer.secret_key, deploy_tx) + .unwrap(); + let contract_address = { + let bytes = test_utils::unwrap_success_slice(&deploy_result); + Address::try_from_slice(bytes).unwrap() + }; + let contract = test_utils::standard_precompiles::PrecompilesContract( + constructor.0.deployed_at(contract_address), + ); + + // This transaction calls the standard precompiles (`ecrecover`, `sha256`, etc) one aft the other. + // So the trace is one top-level call with multiple sub-calls (and the sub-calls contain no further sub-calls). + let tx = contract.call_method("test_all", signer.use_nonce().into()); + let mut listener = CallTracer::default(); + let standalone_result = sputnik::traced_call(&mut listener, || { + runner + .submit_transaction(&signer.secret_key, tx.clone()) + .unwrap() + }); + assert!(standalone_result.status.is_ok()); + assert_eq!(listener.call_stack.len(), 1); + + let trace = listener.call_stack.pop().unwrap(); + assert_eq!(trace.calls.len(), 8); + for call in trace.calls { + assert!(call.calls.is_empty()); + } + + runner.close(); +} + +#[test] +fn test_trace_precompiles_with_subcalls() { + // The XCC precompile does internal sub-calls. We will trace an XCC call. + + let mut runner = standalone::StandaloneRunner::default(); + let mut signer = test_utils::Signer::random(); + let signer_address = test_utils::address_from_secret_key(&signer.secret_key); + let xcc_address = aurora_engine_precompiles::xcc::cross_contract_call::ADDRESS; + + runner.init_evm(); + + // Deploy an ERC-20 contract to act as wNEAR. It doesn't actually need to be bridged for + // this test because we are not executing any scheduled promises. + let constructor = test_utils::erc20::ERC20Constructor::load(); + let deploy_tx = constructor.deploy("wNEAR", "WNEAR", signer.use_nonce().into()); + let deploy_result = runner + .submit_transaction(&signer.secret_key, deploy_tx) + .unwrap(); + let wnear_address = { + let bytes = test_utils::unwrap_success_slice(&deploy_result); + Address::try_from_slice(bytes).unwrap() + }; + let wnear = test_utils::erc20::ERC20(constructor.0.deployed_at(wnear_address)); + let mint_tx = wnear.mint(signer_address, u128::MAX.into(), signer.use_nonce().into()); + runner + .submit_transaction(&signer.secret_key, mint_tx) + .unwrap(); + let approve_tx = wnear.approve(xcc_address, U256::MAX, signer.use_nonce().into()); + runner + .submit_transaction(&signer.secret_key, approve_tx) + .unwrap(); + // Ensure the above ERC-20 token is registered as if it were a bridged token + { + runner.env.block_height += 1; + let storage = &mut runner.storage; + let env = &runner.env; + + let mut tx = + standalone::StandaloneRunner::template_tx_msg(storage, env, 0, Default::default(), &[]); + tx.transaction = sync::types::TransactionKind::DeployErc20( + aurora_engine::parameters::DeployErc20TokenArgs { + nep141: "wrap.near".parse().unwrap(), + }, + ); + let mut outcome = sync::execute_transaction_message(storage, tx).unwrap(); + let key = storage::bytes_to_key(storage::KeyPrefix::Nep141Erc20Map, b"wrap.near"); + outcome.diff.modify(key, wnear_address.as_bytes().to_vec()); + let key = + storage::bytes_to_key(storage::KeyPrefix::Erc20Nep141Map, wnear_address.as_bytes()); + outcome.diff.modify(key, b"wrap.near".to_vec()); + test_utils::standalone::storage::commit(storage, &outcome); + } + + // Setup xcc precompile in standalone runner + let xcc_router_bytes = crate::tests::xcc::contract_bytes(); + let factory_update = { + runner.env.block_height += 1; + runner.env.predecessor_account_id = "aurora".parse().unwrap(); + runner.env.signer_account_id = "aurora".parse().unwrap(); + let storage = &mut runner.storage; + let env = &runner.env; + + let mut tx = + standalone::StandaloneRunner::template_tx_msg(storage, env, 0, Default::default(), &[]); + tx.transaction = sync::types::TransactionKind::FactoryUpdate(xcc_router_bytes); + tx + }; + let outcome = sync::execute_transaction_message(&runner.storage, factory_update).unwrap(); + test_utils::standalone::storage::commit(&mut runner.storage, &outcome); + let set_wnear_address = { + runner.env.block_height += 1; + let storage = &mut runner.storage; + let env = &runner.env; + + let mut tx = + standalone::StandaloneRunner::template_tx_msg(storage, env, 0, Default::default(), &[]); + tx.transaction = sync::types::TransactionKind::FactorySetWNearAddress(wnear_address); + tx + }; + let outcome = sync::execute_transaction_message(&runner.storage, set_wnear_address).unwrap(); + test_utils::standalone::storage::commit(&mut runner.storage, &outcome); + + // User calls XCC precompile + let promise = PromiseCreateArgs { + target_account_id: "some_account.near".parse().unwrap(), + method: "whatever".into(), + args: Vec::new(), + attached_balance: Yocto::new(1), + attached_gas: NearGas::new(100_000_000_000_000), + }; + let xcc_args = CrossContractCallArgs::Delayed(PromiseArgs::Create(promise)); + let tx = aurora_engine_transactions::legacy::TransactionLegacy { + nonce: signer.use_nonce().into(), + gas_price: U256::zero(), + gas_limit: u64::MAX.into(), + to: Some(xcc_address), + value: Wei::zero(), + data: xcc_args.try_to_vec().unwrap(), + }; + let mut listener = CallTracer::default(); + let standalone_result = sputnik::traced_call(&mut listener, || { + runner + .submit_transaction(&signer.secret_key, tx.clone()) + .unwrap() + }); + assert!(standalone_result.status.is_ok()); + assert_eq!(listener.call_stack.len(), 1); + + let trace = listener.call_stack.pop().unwrap(); + assert_eq!(trace.calls.len(), 1); + let subcall = trace.calls.first().unwrap(); + assert_eq!(subcall.call_type, call_tracer::CallType::Call); + assert_eq!(subcall.from, xcc_address); + assert_eq!(subcall.to.unwrap(), wnear_address); + assert_eq!(U256::from_big_endian(&subcall.output), U256::one()); + + runner.close(); +} + +/// A convenience function for pulling out a sub-call from a trace. +/// The `path` gives the index to pull out of each `calls` array. +/// For example `path == []` simply returns the given `root`, while +/// `path == [2, 0]` will return `root.calls[2].calls[0]`. +fn subcall_lense<'a, 'b>( + root: &'a call_tracer::CallFrame, + path: &'b [usize], +) -> &'a call_tracer::CallFrame { + let mut result = root; + for index in path { + result = result.calls.get(*index).unwrap(); + } + result +} diff --git a/engine-tests/src/tests/standalone/mod.rs b/engine-tests/src/tests/standalone/mod.rs index 6e3c6d728..17b037976 100644 --- a/engine-tests/src/tests/standalone/mod.rs +++ b/engine-tests/src/tests/standalone/mod.rs @@ -1,3 +1,4 @@ +mod call_tracer; mod json_snapshot; mod sanity; mod storage; diff --git a/engine-tests/src/tests/uniswap.rs b/engine-tests/src/tests/uniswap.rs index c200b416c..7712f9ec5 100644 --- a/engine-tests/src/tests/uniswap.rs +++ b/engine-tests/src/tests/uniswap.rs @@ -38,7 +38,7 @@ fn test_uniswap_input_multihop() { let (_amount_out, _evm_gas, profile) = context.exact_input(&tokens, INPUT_AMOUNT.into()); - assert_eq!(122, profile.all_gas() / 1_000_000_000_000); + assert_eq!(113, profile.all_gas() / 1_000_000_000_000); } #[test] @@ -49,7 +49,7 @@ fn test_uniswap_exact_output() { let (_result, profile) = context.add_equal_liquidity(LIQUIDITY_AMOUNT.into(), &token_a, &token_b); - test_utils::assert_gas_bound(profile.all_gas(), 33); + test_utils::assert_gas_bound(profile.all_gas(), 32); let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); assert!( (40..=50).contains(&wasm_fraction), @@ -59,7 +59,7 @@ fn test_uniswap_exact_output() { let (_amount_in, profile) = context.exact_output_single(&token_a, &token_b, OUTPUT_AMOUNT.into()); - test_utils::assert_gas_bound(profile.all_gas(), 18); + test_utils::assert_gas_bound(profile.all_gas(), 17); let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); assert!( (45..=55).contains(&wasm_fraction), diff --git a/engine-tests/src/tests/xcc.rs b/engine-tests/src/tests/xcc.rs index ed05df32a..814986a23 100644 --- a/engine-tests/src/tests/xcc.rs +++ b/engine-tests/src/tests/xcc.rs @@ -816,7 +816,7 @@ fn approve_erc20( assert!(approve_result.status.is_ok()); } -fn contract_bytes() -> Vec { +pub(crate) fn contract_bytes() -> Vec { let base_path = Path::new("../etc").join("xcc-router"); let output_path = base_path.join("target/wasm32-unknown-unknown/release/xcc_router.wasm"); test_utils::rust::compile(base_path); diff --git a/engine-transactions/Cargo.toml b/engine-transactions/Cargo.toml index cfc821832..9a57b6d19 100644 --- a/engine-transactions/Cargo.toml +++ b/engine-transactions/Cargo.toml @@ -16,7 +16,7 @@ autobenches = false aurora-engine-types = { path = "../engine-types", default-features = false } aurora-engine-sdk = { path = "../engine-sdk", default-features = false } aurora-engine-precompiles = { path = "../engine-precompiles", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false } rlp = { version = "0.5.0", default-features = false } serde = { version = "1", features = ["derive"], optional = true } diff --git a/engine/Cargo.toml b/engine/Cargo.toml index 06b9d7cf6..15c8922fd 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aurora-engine" -version = "2.8.0" +version = "2.8.1" authors = ["Aurora Labs "] edition = "2021" description = "" @@ -25,7 +25,7 @@ bitflags = { version = "1.3", default-features = false } borsh = { version = "0.9.3", default-features = false } byte-slice-cast = { version = "1.0", default-features = false } ethabi = { version = "18.0", default-features = false } -evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.1-aurora", default-features = false } +evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.37.3-aurora", default-features = false } hex = { version = "0.4", default-features = false, features = ["alloc"] } rjson = { git = "https://github.com/aurora-is-near/rjson", rev = "cc3da949", default-features = false, features = ["integer"] } rlp = { version = "0.5.0", default-features = false }