From 63078745a227176094297fedc5e55e9eaa416b02 Mon Sep 17 00:00:00 2001 From: "Joshua J. Bouw" Date: Fri, 1 Jul 2022 17:04:46 +0700 Subject: [PATCH] Merge: 2.6.1 into `develop` from `master` (#546) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Feat(standalone): Add debug tracing of remaining gas values (#391) * Balance type refactoring (#386) * Remove standalone binary (#403) * Eth Address cleanup (#387) * Fix(dep) Pass std feature on to rjson library (#402) * Feat(benchmarks): update gas bounds after wasm cost reduction (#406) * Feat(tests): Mock touching trie nodes (#408) * Fix: Only allow owner to call deploy_upgrade (#410) * Feat(tests): Uniswap multi-hop swap benchmark (#415) * Fix(engine): Return revert error message during contract deploy (#424) * Move engine transactions module to engine-transactions crate (#418) * Avoid using wasmer directly (#420) * Fix compilation after #418 merge * Use default git attributes for Cargo.lock (#421) * Switch to rebranded blake2 (#422) * Remove unused unused (#423) * Chore: make aurora compatible with latest nightlies (#425) * Chore: upgrade to the recent nightly (#426) * chore: upgrade to the latest nearcore version (#427) * chore: move to 2021 edition (#428) * Benchmark contract performing only pure arithmetic and memory operations (#429) * Fix(engine): Require chain_id (#432) * chore: make sure aurora is using the latest cost config (#435) * Fix(test): make uniswap benchmarks reproducible (#437) * Fix(test): lower gas limit on OOG test; this is needed because the solidity compiler got more efficient, not because of a regression in EVM gas metering correctness * Fix(engine): Cache generation values to avoid repeated state reads (#438) * Fix(engine): Optimize is_account_empty (#439) * Fix(test): update uniswap wasm fraction; this is needed because optimizations from #438 and #439 together lowered the fraction of gas spent on IO * Fix(engine): Upgrade to latest SputnikVM (#445) * Fix(engine): Simple cache to stop consecutive duplicate reads (#446) * Version update and change log Co-authored-by: Aleksey Kladov Co-authored-by: Evgeny Ukhanov Co-authored-by: Michael Birch Release 2.5.0. (#460) * Engine: Upgrade to latest SputnikVM changes (#455) * Engine: further caching optimizations (#456) * Use EthTransactionKind reference to serialize into bytes (#457) * Test: Reproduce GdASJ3KESs8VegpFECTveCwLQp8fxw8yvsauNEmGb6pZ gas failure (#454) * Fix typo: promise_create (#452) * Fix(Engine): Transactions to the zero address are not the same as transactions with empty to field (#458) Co-authored-by: Marcelo Fornet Co-authored-by: Michael Birch Release 2.5.1. (#470) * Feat(Engine): Precompiles for predecessor_account_id and current_account_id (#462) * Implement a NEAR native version of the Solidity pure arithmetic benchmark to compare EVM execution cost with direct wasm cost (#463) * Fix features related to panic_info_message (#466) * Fix(standalone): set predecessor_account_id appropriately when executing promise callbacks (#467) * Fix(engine): fix bug in checking if an address exists (#469) * Version update * Update unreleased link Co-authored-by: Joshua J. Bouw Release 2.5.2. (#475) * Revert "Feat(Engine): Precompiles for predecessor_account_id and current_account_id (#462)" Release 2.5.3. (#527) * Fix(precompile): ExitToNear ExitToEthereum vulnerability patch Fix vulnerability Include exploit contract * Release 2.5.3 notes * Update solidity version Co-authored-by: Michael Birch Release 2.6.0. (#494) * Feat(Engine): Precompiles for predecessor_account_id and current_account_id (#462) * Fix(precompiles): Allow native precompiles to work in the standalone engine (#473) * Standalone engine improvements (#478) * Fix(Engine): Predecessor id precompile works in view calls (#477) * Feat(standalone): Persist transaction data (#481) * Feat(Engine): Add custom precompile for NEAR prepaid_gas (#479) * Test: Reproduce 8ru7VEAEbyfZdbC1W2PYQv2cY3W92rbTToDEN4yTp8aZ gas failure (#485) * Feat(standalone): Function to get latest/earliest block (#482) * Engine optimization: cache all reads from NEAR state (#488) * Feat(standalone): Handle call to new method of Engine contract (#490) * Feat(engine-types): optional serde integration (#468) * Changed near-blake2 dependency (#484) * Feat(standalone): thread-safety and serde (#496) * Refactor repro tests to have less boilerplate (#497) * Add serde for TraceTransaction (#495) * Fix(standalone): include possible execution errors in the TransactionIncludedOutcome result field (#500) * Reproduce transaction FRcorNvFojoxBrdiVMTy9gRD3H8EYXXKau4feevMZmFV (#498) * Reproduce transaction 5bEgfRQ5TSJfN9XCqYkMr9cgBLToM7JmS1bNzKpDXJhT (#499) * Fix(connector): Return an error when storage cannot be read instead of panicking (#501) * Standalone: forward underlying rocksdb crate features (#502) * Feat(tests): Multisender benchmark (#503) * Feat(test): Reproduce D98vwmi44hAYs8KtX5aLne1zEkj3MUss42e5SkG2a4SC (#504) * Standalone engine storage saves the AccountId of the associated engine deployed on chain (#510) * Fix(precompiles): Fix secp256k1 run not returning empty slice on an incorrect V byte (#513) * Self-contained wasm contract for testing 5bEgfRQ (#514) * Update gas estimation code to use new data from NEAR protocol v53 (#517) * Fix: Legacy transactions must be allowed (#520) * Chore(precompiles): Include blake2 compression only (#528) * Build(deps): Upgrade `libsecp256k1` version 0.3.5 => 0.7.0 (#515) * Bump regex from 1.5.4 to 1.5.6 (#526) * Bump regex from 1.5.4 to 1.5.6 in /etc/ft-receiver (#525) * Bump zeroize_derive from 1.1.0 to 1.3.2 (#523) * Bump crossbeam-deque from 0.8.0 to 0.8.1 (#521) * Bump crossbeam-utils from 0.8.4 to 0.8.8 (#524) * Bump cross-fetch from 2.2.3 to 2.2.6 in /etc/eth-contracts (#508) * Bump simple-get from 2.8.1 to 2.8.2 in /etc/eth-contracts (#507) * Bump follow-redirects from 1.14.0 to 1.15.1 in /etc/eth-contracts (#529) * Bump shelljs from 0.8.4 to 0.8.5 in /etc/eth-contracts * Fix(ecrecover): Set malleability flag to `0` for ecrecover. (#474) Co-authored-by: Evgeny Ukhanov Co-authored-by: Marcelo Fornet Co-authored-by: Michael Birch Co-authored-by: Roman Hodulák Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Release 2.6.1. (#537) * Fix: Don't allow fee stealing. * Fix: Don't allow bridge receipt forging. * Fix(engine): Correctly account for changes in total supply of ETH on Aurora (#536) Co-authored-by: Michael Birch Co-authored-by: Michael Birch --- AUTHORS | 15 +- CHANGES.md | 131 ++++++++++++++++-- Cargo.lock | 7 +- README.md | 6 +- TODO.md | 20 --- VERSION | 2 +- engine-precompiles/src/native.rs | 4 + engine-sdk/Cargo.toml | 2 + engine-sdk/src/near_runtime.rs | 16 +++ engine-standalone-tracing/Cargo.toml | 1 - engine-standalone-tracing/src/sputnik.rs | 12 +- engine-standalone-tracing/src/types/mod.rs | 4 +- engine-tests/src/tests/erc20_connector.rs | 66 ++++++++- engine-tests/src/tests/ghsa_3p69_m8gg_fwmf.rs | 48 +++++++ engine-tests/src/tests/mod.rs | 1 + engine-tests/src/tests/res/echo.sol | 17 +++ engine-tests/src/tests/res/exploit.sol | 25 ++++ engine/Cargo.toml | 6 +- engine/src/engine.rs | 12 +- engine/src/lib.rs | 14 +- etc/self-contained-5bEgfRQ/Cargo.lock | 124 ++++++----------- etc/state-migration-test/Cargo.lock | 2 +- 22 files changed, 394 insertions(+), 141 deletions(-) delete mode 100644 TODO.md create mode 100644 engine-tests/src/tests/ghsa_3p69_m8gg_fwmf.rs create mode 100644 engine-tests/src/tests/res/echo.sol create mode 100644 engine-tests/src/tests/res/exploit.sol diff --git a/AUTHORS b/AUTHORS index 065738923..6ca08348c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,3 +1,12 @@ -* Arto Bendiken - -* Illia Polosukhin +Aleksey Kladov +Andrew Bednoff +Arto Bendiken +Evgeny Kuzyakov +Evgeny Ukhanov +Frank Braun +Illia Polosukhin +Joshua J. Bouw +Kirill Abramov +Marcelo Fornet +Michael Birch +Roman Hodulak diff --git a/CHANGES.md b/CHANGES.md index 00b2ecab1..2acbd9809 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,26 +7,127 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.6.1] 2022-06-23 + +### Fixes + +- Fixed an issue with accounting being problematic with the total supply of ETH on Aurora as it could artificially deplete by @[birchmd]. ([#536]) +- Fixed the possibility of forging receipts to allow for withdrawals on the Rainbow Bridge by [@birchmd], [@mfornet], [@sept-en] and [@joshuajbouw]. Written by [@birchmd]. +- Fixed the ability the steal funds from those by setting a fee when receiving NEP-141 as ERC-20 by [@birchmd], [@mfornet], and [@joshuajbouw]. Written by [@joshuajbouw]. + +[#536]: https://github.com/aurora-is-near/aurora-engine/pull/536 + +## [2.6.0] 2022-06-08 + +### Added + +- A precompile at the address `0x536822d27de53629ef1f84c60555689e9488609f` was created to expose the prepaid gas from the NEAR host function by [@birchmd]. ([#479]) + +### Changes + +- A better implementation of caching was added to reduce the overall gas costs of storage reads resulting in roughly a 15% - 18% reduction of gas costs by [@birchmd]. ([#488]) + +### Fixes + +- If the `v` byte of secp256k1 is incorrect, it now returns correctly an empty vector by [@RomanHodulak]. ([#513]) +- Original ETH transactions which do not contain a Chain ID are allowed again to allow for use of [EIP-1820] by [@joshuajbouw]. ([#520]) +- Ecrecover didn't reject `r`, `s` values larger than curve order by [@RomanHodulak]. ([#515]) +- The predecessor account ID was failing in the `view` method by [@birchmd]. ([#477]) +- Ecrecover was incorrectly setting the NEAR ecrecover malleability flag by [@birchmd] and [@joshuajbouw]. ([#474]) + +[EIP-1820]: https://eips.ethereum.org/EIPS/eip-1820 +[#520]: https://github.com/aurora-is-near/aurora-engine/pull/520 +[#515]: https://github.com/aurora-is-near/aurora-engine/pull/515 +[#513]: https://github.com/aurora-is-near/aurora-engine/pull/513 +[#488]: https://github.com/aurora-is-near/aurora-engine/pull/488 +[#479]: https://github.com/aurora-is-near/aurora-engine/pull/479 +[#477]: https://github.com/aurora-is-near/aurora-engine/pull/477 +[#474]: https://github.com/aurora-is-near/aurora-engine/pull/474 + +## [2.5.3] 2022-04-27 + +### Fixes + +- Fixed inflation vulnerability relating to ExitToNear and ExitToEthereum by [@birchmd], [@mfornet], and [@joshuajbouw]. Written by [@birchmd]. + +## [2.5.2] 2022-03-22 + +### Removed + +- New Aurora-only precompiles removed since they do not work in NEAR view calls. This will need to be fixed and they will be re-added to a future release. + +## [2.5.1] - 2022-03-16 + +### Fixes + +- Fix for bug in checking address exists introduced in the v2.5.0 release by [@birchmd]. ([#469]) + +### Added + +- New Aurora-only precompiles for checking the current and predecessor NEAR account IDs by [@birchmd]. ([#462]) + +[#462]: https://github.com/aurora-is-near/aurora-engine/pull/462 +[#469]: https://github.com/aurora-is-near/aurora-engine/pull/469 + +## [2.5.0] - 2022-03-09 + +### Changes + +- Performance improvement by [@birchmd] and [@olonho]: ([#455]) ([#456]) + +### Fixes + +- Bug fix for the behaviour of transactions to the zero address by [@birchmd]. ([#458]) + +[#455]: https://github.com/aurora-is-near/aurora-engine/pull/455 +[#456]: https://github.com/aurora-is-near/aurora-engine/pull/456 +[#458]: https://github.com/aurora-is-near/aurora-engine/pull/458 + +## [2.4.0] - 2022-02-16 + +### Changes + +- Performance improvements by [@birchmd] and [@matklad]; the engine should now consume much less NEAR gas: ([#427]) ([#438]) ([#439]) ([#445]) ([#446]) +- Security improvment: only Engine contract owner can use the `deploy_upgrade` method by [@birchmd]. ([#410]) +- Bug fix: Engine now returns the error message in the case of a revert during an EVM contract deploy, previously it would always return an address (even when the deploy failed) by [@birchmd]. ([#424]) +- Security improvment: Engine will no longer accept EVM transactions without a chain ID as part of their signature by [@birchmd]. This should have no impact on users as all modern Ethereum tooling includes the chain ID. ([#432]) +- Improvements to code quality by [@mrLSD]: ([#386]) ([#387]) +- Improvements and additions to internal tests and benchmarks by [@birchmd]: ([#408]) ([#415]) ([#429]) + +[#386]: https://github.com/aurora-is-near/aurora-engine/pull/386 +[#387]: https://github.com/aurora-is-near/aurora-engine/pull/387 +[#408]: https://github.com/aurora-is-near/aurora-engine/pull/408 +[#410]: https://github.com/aurora-is-near/aurora-engine/pull/410 +[#415]: https://github.com/aurora-is-near/aurora-engine/pull/415 +[#424]: https://github.com/aurora-is-near/aurora-engine/pull/424 +[#427]: https://github.com/aurora-is-near/aurora-engine/pull/427 +[#429]: https://github.com/aurora-is-near/aurora-engine/pull/429 +[#432]: https://github.com/aurora-is-near/aurora-engine/pull/432 +[#438]: https://github.com/aurora-is-near/aurora-engine/pull/438 +[#439]: https://github.com/aurora-is-near/aurora-engine/pull/439 +[#445]: https://github.com/aurora-is-near/aurora-engine/pull/445 +[#446]: https://github.com/aurora-is-near/aurora-engine/pull/446 + ## [2.3.0] - 2021-12-10 ### Added -- A precompile which exposes NEAR's random number generator was added by [@mfornet] as requested by -[@birchmd]. ([#368] [#297]) +- A precompile which exposes NEAR's random number generator was added by [@mfornet] as requested by + [@birchmd]. ([#368] [#297]) - London hard fork support was added by [@birchmd]. ([#244]) ### Changes - The gas limit for `deposit` and `ft_on_transfer` were changed as they were not attaching enough -gas, as changed by [@mrLSD]. ([#389]) + gas, as changed by [@mrLSD]. ([#389]) ### Fixes -- There was an issue with the original storage not actually being stored. Unfortunately, previous -transactions can't be updated with this change. This has been fixed by [@birchmd]. ([#390]) +- There was an issue with the original storage not actually being stored. Unfortunately, previous + transactions can't be updated with this change. This has been fixed by [@birchmd]. ([#390]) - Call arguments were intended to have a value attached to them to make it equivalent to an ETH -call. This was fixed in a backwards compatible manner by [@andrcmdr], as reported by [@birchmd]. -([#351] [#309]) + call. This was fixed in a backwards compatible manner by [@andrcmdr], as reported by [@birchmd]. + ([#351] [#309]) ### Removed @@ -37,10 +138,10 @@ call. This was fixed in a backwards compatible manner by [@andrcmdr], as reporte [#388]: https://github.com/aurora-is-near/aurora-engine/pull/388 [#368]: https://github.com/aurora-is-near/aurora-engine/pull/368 [#351]: https://github.com/aurora-is-near/aurora-engine/pull/351 -[#311]: https://github.com/aurora-is-near/aurora-engine/pull/311 +[#311]: https://github.com/aurora-is-near/aurora-engine/pull/311 [#309]: https://github.com/aurora-is-near/aurora-engine/issues/309 [#297]: https://github.com/aurora-is-near/aurora-engine/issues/297 -[#244]: https://github.com/aurora-is-near/aurora-engine/pull/244 +[#244]: https://github.com/aurora-is-near/aurora-engine/pull/244 ## [2.2.0] - 2021-11-09 @@ -180,7 +281,14 @@ struct SubmitResult { ## [1.0.0] - 2021-05-12 -[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.3.0...master +[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.6.1...develop +[2.6.1]: https://github.com/aurora-is-near/aurora-engine/compare/2.6.0...2.6.1 +[2.6.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.5.3...2.6.0 +[2.5.3]: https://github.com/aurora-is-near/aurora-engine/compare/2.5.2...2.5.3 +[2.5.2]: https://github.com/aurora-is-near/aurora-engine/compare/2.5.1...2.5.2 +[2.5.1]: https://github.com/aurora-is-near/aurora-engine/compare/2.5.0...2.5.1 +[2.5.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.4.0...2.5.0 +[2.4.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.3.0...2.4.0 [2.3.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.2.0...2.3.0 [2.2.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.1.0...2.2.0 [2.1.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.0.2...2.1.0 @@ -208,4 +316,7 @@ struct SubmitResult { [@joshuajbouw]: https://github.com/joshuajbouw [@mfornet]: https://github.com/mfornet [@mrLSD]: https://github.com/mrLSD +[@RomanHodulak]: https://github.com/RomanHodulak [@sept-en]: https://github.com/sept-en +[@matklad]: https://github.com/matklad +[@olonho]: https://github.com/olonho diff --git a/Cargo.lock b/Cargo.lock index 70255cc08..ca50dfebe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,7 +117,7 @@ dependencies = [ [[package]] name = "aurora-engine" -version = "2.1.0" +version = "2.6.1" dependencies = [ "aurora-bn", "aurora-engine-precompiles", @@ -1180,7 +1180,6 @@ dependencies = [ "evm-core", "evm-gasometer", "evm-runtime", - "hex", "serde", ] @@ -2128,9 +2127,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5172b50c23043ff43dd53e51392f36519d9b35a8f3a410d30ece5d1aedd58ae" +checksum = "fe3179b85e1fd8b14447cbebadb75e45a1002f541b925f0bfec366d56a81c56d" dependencies = [ "libc", ] diff --git a/README.md b/README.md index 9ebbc23a4..77f570040 100644 --- a/README.md +++ b/README.md @@ -14,9 +14,9 @@ documentation. Network | Contract ID | Chain ID | Version ------- | ------------------- | ---------- | ------ -Mainnet | [`aurora`][Mainnet] | 1313161554 | 2.2.0 -Testnet | [`aurora`][Testnet] | 1313161555 | 2.3.0 -Local | `aurora.test.near` | 1313161556 | 2.3.0 +Mainnet | [`aurora`][Mainnet] | 1313161554 | 2.6.1 +Testnet | [`aurora`][Testnet] | 1313161555 | 2.6.1 +Local | `aurora.test.near` | 1313161556 | 2.6.1 [Mainnet]: https://explorer.near.org/accounts/aurora [Testnet]: https://explorer.testnet.near.org/accounts/aurora diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 2fa47f251..000000000 --- a/TODO.md +++ /dev/null @@ -1,20 +0,0 @@ -# To-Dos - -## Storage - -- Add version byte prefix to all storage keys? -- Store the account nonce and balance in a struct - -## Ticketed - -- [#1]: Add `begin_chain` function to contract -- [#2]: Add `begin_block` function to contract -- [#3]: Implement `raw_call` function in contract -- [#4]: Implement `meta_call` function in contract -- [#5]: Implement precompiles - -[#1]: https://github.com/aurora-is-near/aurora-engine/issues/1 -[#2]: https://github.com/aurora-is-near/aurora-engine/issues/2 -[#3]: https://github.com/aurora-is-near/aurora-engine/issues/3 -[#4]: https://github.com/aurora-is-near/aurora-engine/issues/4 -[#5]: https://github.com/aurora-is-near/aurora-engine/issues/5 diff --git a/VERSION b/VERSION index 276cbf9e2..6a6a3d8e3 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.3.0 +2.6.1 diff --git a/engine-precompiles/src/native.rs b/engine-precompiles/src/native.rs index 99df0a964..6f1049ad8 100644 --- a/engine-precompiles/src/native.rs +++ b/engine-precompiles/src/native.rs @@ -257,6 +257,8 @@ impl Precompile for ExitToNear { // It's not allowed to call exit precompiles in static mode if is_static { return Err(ExitError::Other(Cow::from("ERR_INVALID_IN_STATIC"))); + } else if context.address != exit_to_near::ADDRESS.raw() { + return Err(ExitError::Other(Cow::from("ERR_INVALID_IN_DELEGATE"))); } // First byte of the input is a flag, selecting the behavior to be triggered: @@ -451,6 +453,8 @@ impl Precompile for ExitToEthereum { // It's not allowed to call exit precompiles in static mode if is_static { return Err(ExitError::Other(Cow::from("ERR_INVALID_IN_STATIC"))); + } else if context.address != exit_to_ethereum::ADDRESS.raw() { + return Err(ExitError::Other(Cow::from("ERR_INVALID_IN_DELEGATE"))); } // First byte of the input is a flag, selecting the behavior to be triggered: diff --git a/engine-sdk/Cargo.toml b/engine-sdk/Cargo.toml index 6db4a2a7e..feb770474 100644 --- a/engine-sdk/Cargo.toml +++ b/engine-sdk/Cargo.toml @@ -22,3 +22,5 @@ sha2 = { version = "0.9.3", default-features = false } std = ["aurora-engine-types/std"] contract = [] log = [] +mainnet = [] +testnet = [] diff --git a/engine-sdk/src/near_runtime.rs b/engine-sdk/src/near_runtime.rs index 66b9f1327..c325d7a7d 100644 --- a/engine-sdk/src/near_runtime.rs +++ b/engine-sdk/src/near_runtime.rs @@ -6,6 +6,18 @@ use aurora_engine_types::parameters::{PromiseAction, PromiseBatchAction, Promise use aurora_engine_types::types::PromiseResult; use aurora_engine_types::H256; +#[cfg(feature = "mainnet")] +/// The mainnet eth_custodian address 0x6BFaD42cFC4EfC96f529D786D643Ff4A8B89FA52 +const CUSTODIAN_ADDRESS: &[u8] = &[ + 107, 250, 212, 44, 252, 78, 252, 150, 245, 41, 215, 134, 214, 67, 255, 74, 139, 137, 250, 82, +]; + +#[cfg(feature = "testnet")] +/// The testnet eth_custodian address 0x84a82Bb39c83989D5Dc07e1310281923D2544dC2 +const CUSTODIAN_ADDRESS: &[u8] = &[ + 132, 168, 43, 179, 156, 131, 152, 157, 93, 192, 126, 19, 16, 40, 25, 35, 210, 84, 77, 194, +]; + /// Wrapper type for indices in NEAR's register API. pub struct RegisterIndex(u64); @@ -113,6 +125,10 @@ impl crate::io::IO for Runtime { fn return_output(&mut self, value: &[u8]) { unsafe { + #[cfg(any(feature = "mainnet", feature = "testnet"))] + if value.len() >= 56 && &value[36..56] == CUSTODIAN_ADDRESS { + panic!("ERR_ILLEGAL_RETURN"); + } exports::value_return(value.len() as u64, value.as_ptr() as u64); } } diff --git a/engine-standalone-tracing/Cargo.toml b/engine-standalone-tracing/Cargo.toml index e2c3d0c32..c75c273c3 100644 --- a/engine-standalone-tracing/Cargo.toml +++ b/engine-standalone-tracing/Cargo.toml @@ -21,7 +21,6 @@ evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "374 evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "37448b6cacd98b06282cff5a559684505c29bd2b", default-features = false, features = ["std", "tracing"] } evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "37448b6cacd98b06282cff5a559684505c29bd2b", default-features = false, features = ["std", "tracing"] } evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", rev = "37448b6cacd98b06282cff5a559684505c29bd2b", default-features = false, features = ["std", "tracing"] } -hex = { version = "0.4" } serde = { version = "1", features = ["derive"], optional = true } [features] diff --git a/engine-standalone-tracing/src/sputnik.rs b/engine-standalone-tracing/src/sputnik.rs index 5f1395373..ba32e55a0 100644 --- a/engine-standalone-tracing/src/sputnik.rs +++ b/engine-standalone-tracing/src/sputnik.rs @@ -48,14 +48,18 @@ impl evm_gasometer::tracing::EventListener for TransactionTraceBuilder { fn event(&mut self, event: evm_gasometer::tracing::Event) { use evm_gasometer::tracing::Event; match event { - Event::RecordCost { cost, snapshot: _ } => { + Event::RecordCost { cost, snapshot } => { self.current.gas_cost = EthGas::new(cost); + if let Some(snapshot) = snapshot { + self.current.gas = + EthGas::new(snapshot.gas_limit - snapshot.used_gas - snapshot.memory_gas); + } } Event::RecordDynamicCost { gas_cost, memory_gas, gas_refund: _, - snapshot: _, + snapshot, } => { // In SputnikVM memory gas is cumulative (ie this event always shows the total) gas // spent on memory up to this point. But geth traces simply show how much gas each step @@ -68,6 +72,10 @@ impl evm_gasometer::tracing::EventListener for TransactionTraceBuilder { }; self.current_memory_gas = memory_gas; self.current.gas_cost = EthGas::new(gas_cost + memory_cost_diff); + if let Some(snapshot) = snapshot { + self.current.gas = + EthGas::new(snapshot.gas_limit - snapshot.used_gas - snapshot.memory_gas); + } } Event::RecordRefund { refund: _, diff --git a/engine-standalone-tracing/src/types/mod.rs b/engine-standalone-tracing/src/types/mod.rs index d6040d9ac..93495b43a 100644 --- a/engine-standalone-tracing/src/types/mod.rs +++ b/engine-standalone-tracing/src/types/mod.rs @@ -163,9 +163,9 @@ pub struct TraceLog { pub depth: Depth, /// Any errors that may have occurred during execution. pub error: Option, - /// Gas used to execute the transaction. + /// Remaining (unused) gas. pub gas: EthGas, - /// Gas cost for the transaction. + /// Gas cost for the opcode at this step. pub gas_cost: EthGas, /// The bounded memory. pub memory: LogMemory, diff --git a/engine-tests/src/tests/erc20_connector.rs b/engine-tests/src/tests/erc20_connector.rs index 44df03fe9..be83cac26 100644 --- a/engine-tests/src/tests/erc20_connector.rs +++ b/engine-tests/src/tests/erc20_connector.rs @@ -297,6 +297,7 @@ fn test_ft_on_transfer_fail() { assert_eq!(res, format!("\"{}\"", amount.to_string())); } +#[ignore] #[test] fn test_relayer_charge_fee() { let mut runner = AuroraRunner::new(); @@ -400,7 +401,7 @@ mod sim_tests { CallArgs, DeployErc20TokenArgs, FunctionCallArgsV2, SubmitResult, }; use aurora_engine_types::types::Address; - use borsh::BorshSerialize; + use borsh::{BorshDeserialize, BorshSerialize}; use near_sdk_sim::UserAccount; use serde_json::json; @@ -412,6 +413,69 @@ mod sim_tests { const INITIAL_ETH_BALANCE: u64 = 777_777_777; const ETH_EXIT_AMOUNT: u64 = 111_111_111; + #[test] + fn test_ghsa_5c82_x4m4_hcj6_exploit() { + let TestExitToNearEthContext { + mut signer, + signer_address, + chain_id, + tester_address: _, + aurora, + } = test_exit_to_near_eth_common(); + + let constructor = test_utils::solidity::ContractConstructor::force_compile( + "src/tests/res", + "target/solidity_build", + "exploit.sol", + "Exploit", + ); + let nonce = signer.use_nonce().into(); + let deploy_tx = constructor.deploy_without_constructor(nonce); + let signed_tx = test_utils::sign_transaction(deploy_tx, Some(chain_id), &signer.secret_key); + let deploy_result = aurora.call("submit", &rlp::encode(&signed_tx)); + let contract_address = match &deploy_result.status() { + near_sdk_sim::transaction::ExecutionStatus::SuccessValue(bytes) => { + let submit_result = SubmitResult::try_from_slice(bytes).unwrap(); + Address::try_from_slice(test_utils::unwrap_success_slice(&submit_result)).unwrap() + } + _ => panic!("Unknown result: {:?}", deploy_result), + }; + let contract = constructor.deployed_at(contract_address); + + let nonce = signer.use_nonce().into(); + let hacker_account = "hacker.near"; + let hacker_account_bytes = hacker_account.as_bytes().to_vec(); + let mut exploit_tx = contract.call_method_with_args( + "exploit", + &[ethabi::Token::Bytes(hacker_account_bytes)], + nonce, + ); + exploit_tx.value = Wei::new_u64(ETH_EXIT_AMOUNT); + let signed_tx = + test_utils::sign_transaction(exploit_tx, Some(chain_id), &signer.secret_key); + aurora + .call("submit", &rlp::encode(&signed_tx)) + .assert_success(); + + // check balances -- Hacker does not steal any funds! + assert_eq!( + nep_141_balance_of( + aurora.contract.account_id.as_str(), + &aurora.contract, + &aurora, + ), + INITIAL_ETH_BALANCE as u128 + ); + assert_eq!( + nep_141_balance_of(hacker_account, &aurora.contract, &aurora), + 0 + ); + assert_eq!( + eth_balance_of(signer_address, &aurora), + Wei::new_u64(INITIAL_ETH_BALANCE) + ); + } + #[test] fn test_exit_to_near() { // Deploy Aurora; deploy NEP-141; bridge NEP-141 to ERC-20 on Aurora diff --git a/engine-tests/src/tests/ghsa_3p69_m8gg_fwmf.rs b/engine-tests/src/tests/ghsa_3p69_m8gg_fwmf.rs new file mode 100644 index 000000000..065af19c6 --- /dev/null +++ b/engine-tests/src/tests/ghsa_3p69_m8gg_fwmf.rs @@ -0,0 +1,48 @@ +use crate::test_utils; +use borsh::BorshSerialize; + +#[test] +fn test_exploit_fix() { + let (mut runner, mut signer, _) = crate::tests::sanity::initialize_transfer(); + + let constructor = test_utils::solidity::ContractConstructor::compile_from_source( + "src/tests/res", + "target/solidity_build", + "echo.sol", + "Echo", + ); + + let nonce = signer.use_nonce(); + let contract = runner.deploy_contract( + &signer.secret_key, + |c| c.deploy_without_constructor(nonce.into()), + constructor, + ); + + let eth_custodian_address = if cfg!(feature = "mainnet-test") { + "6bfad42cfc4efc96f529d786d643ff4a8b89fa52" + } else if cfg!(feature = "testnet-test") { + "84a82bb39c83989d5dc07e1310281923d2544dc2" + } else { + panic!("This test requires mainnet-test or testnet-test feature enabled.") + }; + let target_address = "1111111122222222333333334444444455555555"; + let amount: u64 = 1_000_000; + let amount_bytes = amount.to_le_bytes(); + let payload = hex::decode(format!( + "000000{}{}{}", + hex::encode(amount_bytes), + target_address, + eth_custodian_address + )) + .unwrap(); + + let tx = contract.call_method_with_args("echo", &[ethabi::Token::Bytes(payload)], nonce.into()); + let sender = test_utils::address_from_secret_key(&signer.secret_key); + let view_call_args = test_utils::as_view_call(tx, sender); + let input = view_call_args.try_to_vec().unwrap(); + + let (_outcome, maybe_error) = runner.one_shot().call("view", "viewer", input); + let error_message = format!("{:?}", maybe_error); + assert!(error_message.contains("ERR_ILLEGAL_RETURN")); +} diff --git a/engine-tests/src/tests/mod.rs b/engine-tests/src/tests/mod.rs index f6b4dd0ed..7689f5a0d 100644 --- a/engine-tests/src/tests/mod.rs +++ b/engine-tests/src/tests/mod.rs @@ -6,6 +6,7 @@ mod eip1559; mod erc20; mod erc20_connector; mod eth_connector; +mod ghsa_3p69_m8gg_fwmf; #[cfg(feature = "meta-call")] mod meta_parsing; mod multisender; diff --git a/engine-tests/src/tests/res/echo.sol b/engine-tests/src/tests/res/echo.sol new file mode 100644 index 000000000..6047e16a3 --- /dev/null +++ b/engine-tests/src/tests/res/echo.sol @@ -0,0 +1,17 @@ + // SPDX-License-Identifier: GPL-3.0 + + pragma solidity >=0.7.0 <0.9.0; + + contract Echo { + + function echo(bytes memory payload) public pure { + assembly { + let pos := mload(0x40) + + mstore(pos, mload(add(payload, 0x20))) + mstore(add(pos, 0x20), mload(add(payload, 0x40))) + + return(pos, 51) + } + } + } diff --git a/engine-tests/src/tests/res/exploit.sol b/engine-tests/src/tests/res/exploit.sol new file mode 100644 index 000000000..c3c7fa93f --- /dev/null +++ b/engine-tests/src/tests/res/exploit.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity ^0.8.6; + +contract Exploit { + address payable private owner; + + constructor() { + owner = payable(msg.sender); + } + + function exploit(bytes memory recipient) public payable { + require(msg.sender == owner); + + bytes memory input = abi.encodePacked("\x00", recipient); + uint input_size = 1 + recipient.length; + + assembly { + let res := delegatecall(gas(), 0xe9217bc70b7ed1f598ddd3199e80b093fa71124f, add(input, 32), input_size, 0, 32) + } + + owner.transfer(msg.value); + } +} + diff --git a/engine/Cargo.toml b/engine/Cargo.toml index aa63774d3..b9c77c623 100644 --- a/engine/Cargo.toml +++ b/engine/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aurora-engine" -version = "2.1.0" +version = "2.6.1" authors = ["Aurora Labs "] edition = "2021" description = "" @@ -54,8 +54,8 @@ tracing = ["evm/tracing"] meta-call = [] error_refund = ["aurora-engine-precompiles/error_refund"] integration-test = ["log"] -mainnet = ["contract", "log"] -testnet = ["contract", "log"] +mainnet = ["contract", "log", "aurora-engine-sdk/mainnet"] +testnet = ["contract", "log", "aurora-engine-sdk/testnet"] mainnet-test = ["meta-call"] testnet-test = ["meta-call"] impl-serde = ["aurora-engine-types/impl-serde", "serde", "aurora-engine-transactions/impl-serde", "evm-core/with-serde"] diff --git a/engine/src/engine.rs b/engine/src/engine.rs index cdbd8ac41..d8ea9a0b7 100644 --- a/engine/src/engine.rs +++ b/engine/src/engine.rs @@ -761,7 +761,7 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { // Message format: // Recipient of the transaction - 40 characters (Address in hex) // Fee to be paid in ETH (Optional) - 64 characters (Encoded in big endian / hex) - let mut message = args.msg.as_bytes(); + let message = args.msg.as_bytes(); assert_or_finish!(message.len() >= 40, output_on_fail, self.io); let recipient = Address::new(H160(unwrap_res_or_finish!( @@ -769,16 +769,8 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { output_on_fail, self.io ))); - message = &message[40..]; - let fee = if message.is_empty() { - U256::from(0) - } else { - assert_or_finish!(message.len() == 64, output_on_fail, self.io); - U256::from_big_endian( - unwrap_res_or_finish!(hex::decode(message), output_on_fail, self.io).as_slice(), - ) - }; + let fee = U256::zero(); (recipient, fee) }; diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 0c25428b6..735fd0074 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -518,7 +518,7 @@ mod contract { #[no_mangle] pub extern "C" fn withdraw() { - let mut io = Runtime; + let io = Runtime; io.assert_one_yocto().sdk_unwrap(); let args = io.read_input_borsh().sdk_unwrap(); let current_account_id = io.current_account_id(); @@ -528,7 +528,11 @@ mod contract { .withdraw_eth_from_near(¤t_account_id, &predecessor_account_id, args) .sdk_unwrap(); let result_bytes = result.try_to_vec().sdk_expect("ERR_SERIALIZE"); - io.return_output(&result_bytes); + // We intentionally do not go through the `io` struct here because we must bypass + // the check that prevents output that is accepted by the eth_custodian + unsafe { + exports::value_return(result_bytes.len() as u64, result_bytes.as_ptr() as u64); + } } #[no_mangle] @@ -909,6 +913,12 @@ mod contract { fn predecessor_address(predecessor_account_id: &AccountId) -> Address { near_account_to_evm_address(predecessor_account_id.as_bytes()) } + + mod exports { + extern "C" { + pub(crate) fn value_return(value_len: u64, value_ptr: u64); + } + } } pub trait AuroraState { diff --git a/etc/self-contained-5bEgfRQ/Cargo.lock b/etc/self-contained-5bEgfRQ/Cargo.lock index 6ff1281ca..7b05cad08 100644 --- a/etc/self-contained-5bEgfRQ/Cargo.lock +++ b/etc/self-contained-5bEgfRQ/Cargo.lock @@ -26,6 +26,16 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +[[package]] +name = "aurora-blake2" +version = "0.9.1" +source = "git+https://github.com/aurora-is-near/aurora-blake2.git#05a0b5f7a544c527c0118f8afe2f943b3de4bb03" +dependencies = [ + "crypto-mac", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + [[package]] name = "aurora-bn" version = "0.1.0" @@ -66,6 +76,7 @@ dependencies = [ name = "aurora-engine-precompiles" version = "1.0.0" dependencies = [ + "aurora-blake2", "aurora-bn", "aurora-engine-sdk", "aurora-engine-types", @@ -512,27 +523,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array 0.14.5", - "hmac", -] - [[package]] name = "impl-codec" version = "0.5.1" @@ -591,52 +581,17 @@ checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "libsecp256k1" -version = "0.7.0" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0452aac8bab02242429380e9b2f94ea20cea2b37e2c1777a1358799bbe97f37" +checksum = "1fc1e2c808481a63dc6da2074752fdd4336a3c8fcc68b83db6f1fd5224ae7962" dependencies = [ "arrayref", - "base64", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand", - "serde", - "sha2", - "typenum", -] - -[[package]] -name = "libsecp256k1-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" -dependencies = [ "crunchy", - "digest 0.9.0", + "digest 0.8.1", + "rand", "subtle", ] -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" -dependencies = [ - "libsecp256k1-core", -] - [[package]] name = "log" version = "0.4.17" @@ -788,6 +743,12 @@ dependencies = [ "syn", ] +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + [[package]] name = "primitive-types" version = "0.10.1" @@ -864,18 +825,39 @@ dependencies = [ [[package]] name = "rand" -version = "0.8.5" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ + "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" -version = "0.6.3" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" + +[[package]] +name = "rand_hc" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] [[package]] name = "regex-syntax" @@ -965,20 +947,6 @@ name = "serde" version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] [[package]] name = "sha2" diff --git a/etc/state-migration-test/Cargo.lock b/etc/state-migration-test/Cargo.lock index f65c71a92..d7eb518cb 100644 --- a/etc/state-migration-test/Cargo.lock +++ b/etc/state-migration-test/Cargo.lock @@ -37,7 +37,7 @@ dependencies = [ [[package]] name = "aurora-engine" -version = "2.1.0" +version = "2.6.1" dependencies = [ "aurora-bn", "aurora-engine-precompiles",