diff --git a/CHANGES.md b/CHANGES.md index 03718b00e..8798d8b86 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,14 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -### [1.3.0] - 2021-06-17 +## [1.4.0] - 2021-06-18 -### [1.2.0] - 2021-06-05 +## [1.3.0] - 2021-06-17 -### [1.1.0] - 2021-05-28 +## [1.2.0] - 2021-06-05 -### [1.0.0] - 2021-05-12 +## [1.1.0] - 2021-05-28 +## [1.0.0] - 2021-05-12 + +[1.4.0]: https://github.com/aurora-is-near/aurora-engine/compare/1.3.0...1.4.0 [1.3.0]: https://github.com/aurora-is-near/aurora-engine/compare/1.2.0...1.3.0 [1.2.0]: https://github.com/aurora-is-near/aurora-engine/compare/1.1.0...1.2.0 [1.1.0]: https://github.com/aurora-is-near/aurora-engine/compare/1.0.0...1.1.0 diff --git a/Cargo.toml b/Cargo.toml index 762f4e9fb..11cca8ea8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -78,10 +78,12 @@ base64 = "0.13.0" [features] default = ["sha2", "std"] std = ["borsh/std", "evm/std", "primitive-types/std", "rlp/std", "sha3/std", "ethabi/std", "logos/std", "bn/std"] -testnet = [] engine = [] contract = ["engine"] evm_bully = [] log = [] -exit-precompiles = ["contract"] +meta-call = ["contract"] integration-test = ["log"] +mainnet = ["contract", "log"] +testnet = ["contract", "log"] +betanet = ["contract", "log", "meta-call"] diff --git a/Makefile b/Makefile index 2abb80bcb..37dca0da8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CARGO = cargo NEAR = near -FEATURES = contract,log,exit-precompiles +FEATURES = mainnet ifeq ($(evm-bully),yes) FEATURES := $(FEATURES),evm_bully @@ -8,6 +8,15 @@ endif all: release +mainnet: FEATURES=mainnet +mainnet: release + +testnet: FEATURES=testnet +testnet: release + +betanet: FEATURES=betanet +betanet: release + release: release.wasm release.wasm: target/wasm32-unknown-unknown/release/aurora_engine.wasm @@ -25,18 +34,18 @@ etc/eth-contracts/artifacts/contracts/test/StateTest.sol/StateTest.json: $(shell debug: debug.wasm -debug.wasm: target/wasm32-unknown-unknown/debug/aurora_engine.wasm +debug.wasm: target/wasm32-unknown-unknown/debug/aurora_engine.wasm etc/eth-contracts/res/EvmErc20.bin ln -sf $< $@ target/wasm32-unknown-unknown/debug/aurora_engine.wasm: Cargo.toml Cargo.lock $(wildcard src/*.rs) $(CARGO) build --target wasm32-unknown-unknown --no-default-features --features=$(FEATURES) -Z avoid-dev-deps test-build: etc/eth-contracts/artifacts/contracts/test/StateTest.sol/StateTest.json etc/eth-contracts/res/EvmErc20.bin - RUSTFLAGS='-C link-arg=-s' $(CARGO) build --target wasm32-unknown-unknown --release --no-default-features --features=contract,integration-test,exit-precompiles -Z avoid-dev-deps + RUSTFLAGS='-C link-arg=-s' $(CARGO) build --target wasm32-unknown-unknown --release --no-default-features --features=contract,integration-test,meta-call -Z avoid-dev-deps ln -sf target/wasm32-unknown-unknown/release/aurora_engine.wasm release.wasm ls -l target/wasm32-unknown-unknown/release/aurora_engine.wasm -.PHONY: all release debug eth-contracts +.PHONY: all release debug eth-contracts mainnet testnet betanet deploy: release.wasm $(NEAR) deploy --account-id=$(or $(NEAR_EVM_ACCOUNT),aurora.test.near) --wasm-file=$< diff --git a/README.md b/README.md index 7026afa19..9754482f7 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,9 @@ rustup target add wasm32-unknown-unknown --toolchain nightly-2021-03-25 ### Building the EVM binary ```sh +make -B mainnet # produces Mainnet build +make -B testnet # produces Testnet build +make -B betanet # produces Betanet build make release # produces release.wasm (300+ KiB) make debug # produces debug.wasm (1+ MiB), which includes symbols ``` diff --git a/etc/eth-contracts/contracts/EvmErc20.sol b/etc/eth-contracts/contracts/EvmErc20.sol index ecd7a78fa..c9759c4e3 100644 --- a/etc/eth-contracts/contracts/EvmErc20.sol +++ b/etc/eth-contracts/contracts/EvmErc20.sol @@ -36,7 +36,7 @@ contract EvmErc20 is Context, ERC20, AdminControlled, IExit { uint input_size = 1 + 32 + recipient.length; assembly { - let res := staticcall(gas(), 0xe9217bc70b7ed1f598ddd3199e80b093fa71124f, add(input, 32), input_size, 0, 32) + let res := call(gas(), 0xe9217bc70b7ed1f598ddd3199e80b093fa71124f, 0, add(input, 32), input_size, 0, 32) } } @@ -49,7 +49,7 @@ contract EvmErc20 is Context, ERC20, AdminControlled, IExit { uint input_size = 1 + 32 + 20; assembly { - let res := staticcall(gas(), 0xb0bd02f6a392af548bdf1cfaee5dfa0eefcc8eab, add(input, 32), input_size, 0, 32) + let res := call(gas(), 0xb0bd02f6a392af548bdf1cfaee5dfa0eefcc8eab, 0, add(input, 32), input_size, 0, 32) } } } diff --git a/etc/eth-contracts/yarn.lock b/etc/eth-contracts/yarn.lock index 1bd09b027..3874e3463 100644 --- a/etc/eth-contracts/yarn.lock +++ b/etc/eth-contracts/yarn.lock @@ -5522,9 +5522,9 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== normalize-url@^4.1.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129" - integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ== + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== npm-run-path@^2.0.0: version "2.0.2" diff --git a/src/connector.rs b/src/connector.rs index 244f728cc..7a247da0c 100644 --- a/src/connector.rs +++ b/src/connector.rs @@ -545,7 +545,6 @@ impl EthConnectorContract { } /// ft_on_transfer callback function - #[allow(clippy::unnecessary_unwrap)] pub fn ft_on_transfer(&mut self, engine: &Engine, args: &NEP141FtOnTransferArgs) { crate::log!("Call ft_on_transfer"); // Parse message with specific rules @@ -555,12 +554,12 @@ impl EthConnectorContract { let fee = message_data.fee.as_u128(); // Mint fee to relayer let relayer = engine.get_relayer(message_data.relayer.as_bytes()); - if fee > 0 && relayer.is_some() { - self.mint_eth_on_aurora(message_data.recipient, args.amount - fee); - let evm_relayer_address: EthAddress = relayer.unwrap().0; - self.mint_eth_on_aurora(evm_relayer_address, fee); - } else { - self.mint_eth_on_aurora(message_data.recipient, args.amount); + match (fee, relayer) { + (fee, Some(crate::prelude::H160(evm_relayer_address))) if fee > 0 => { + self.mint_eth_on_aurora(message_data.recipient, args.amount - fee); + self.mint_eth_on_aurora(evm_relayer_address, fee); + } + _ => self.mint_eth_on_aurora(message_data.recipient, args.amount), } self.save_ft_contract(); sdk::return_output(0.to_string().as_bytes()); diff --git a/src/deposit_event.rs b/src/deposit_event.rs index a4f99a630..0cfbf5887 100644 --- a/src/deposit_event.rs +++ b/src/deposit_event.rs @@ -1,6 +1,6 @@ -use crate::prelude::{vec, String, ToString}; #[cfg(not(feature = "contract"))] -use crate::prelude::{TryInto, Vec}; +use crate::prelude::Vec; +use crate::prelude::{vec, String, ToString}; use crate::types::*; use ethabi::{EventParam, ParamType}; @@ -45,7 +45,8 @@ impl DepositedEvent { ] } - /// Parse raw log Etherium proof entry data. + /// Parses raw Ethereum logs proof's entry data + #[cfg(feature = "engine")] pub fn from_log_entry_data(data: &[u8]) -> Self { let event = EthEvent::fetch_log_entry_data(DEPOSITED_EVENT, Self::event_params(), data); let sender = event.log.params[0].value.clone().into_address().unwrap().0; @@ -65,15 +66,15 @@ impl DepositedEvent { #[cfg(not(feature = "contract"))] #[allow(dead_code)] pub fn to_log_entry_data(&self) -> Vec { - EthEvent::to_log_entry_data( + EthEvent::params_to_log_entry_data( DEPOSITED_EVENT, DepositedEvent::event_params(), self.eth_custodian_address, vec![self.sender.to_vec()], vec![ ethabi::Token::String(self.recipient.clone()), - ethabi::Token::Uint(self.amount.into()), - ethabi::Token::Uint(self.fee.clone()), + ethabi::Token::Uint(self.amount), + ethabi::Token::Uint(self.fee), ], ) } diff --git a/src/fungible_token.rs b/src/fungible_token.rs index a384579ca..4b18fd471 100644 --- a/src/fungible_token.rs +++ b/src/fungible_token.rs @@ -1,14 +1,16 @@ -#[cfg(feature = "engine")] -use crate::parameters::*; #[cfg(feature = "log")] use crate::prelude::format; -use crate::prelude::TryInto; -#[cfg(feature = "engine")] -use crate::prelude::{self, Ordering, String, ToString, Vec, U256}; use crate::types::*; -#[cfg(feature = "engine")] -use crate::{connector, engine, sdk, storage}; use borsh::{BorshDeserialize, BorshSerialize}; +#[cfg(feature = "engine")] +use { + crate::connector, + crate::engine, + crate::parameters::*, + crate::prelude::{self, Ordering, String, ToString, TryInto, Vec, U256}, + crate::sdk, + crate::storage, +}; #[cfg(feature = "engine")] const GAS_FOR_RESOLVE_TRANSFER: Gas = 5_000_000_000_000; @@ -142,6 +144,10 @@ impl FungibleToken { "Sender and receiver should be different" ); assert!(amount > 0, "The amount should be a positive number"); + if !self.accounts_contains_key(receiver_id) { + // TODO: how does this interact with the storage deposit concept? + self.internal_register_account(receiver_id) + } self.internal_withdraw_eth_from_near(sender_id, amount); self.internal_deposit_eth_to_near(receiver_id, amount); crate::log!(&format!( diff --git a/src/lib.rs b/src/lib.rs index e964eee99..8ae87177a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ use crate::parameters::PromiseCreateArgs; #[cfg(feature = "engine")] mod map; +#[cfg(feature = "meta-call")] pub mod meta_parsing; pub mod parameters; pub mod prelude; @@ -279,6 +280,7 @@ mod contract { .sdk_process(); } + #[cfg(feature = "meta-call")] #[no_mangle] pub extern "C" fn meta_call() { let input = sdk::read_input(); diff --git a/src/parameters.rs b/src/parameters.rs index 6b0ee82e6..f70ab06ea 100644 --- a/src/parameters.rs +++ b/src/parameters.rs @@ -1,15 +1,15 @@ use borsh::{BorshDeserialize, BorshSerialize}; -#[cfg(feature = "engine")] -use crate::admin_controlled::PausedMask; -#[cfg(feature = "engine")] -use crate::json; -use crate::prelude::{is_valid_account_id, String, ToString, TryFrom, Vec}; -#[cfg(feature = "engine")] -use crate::sdk; -use crate::types::{AccountId, Balance, Proof, RawAddress, RawH256, RawU256}; -#[cfg(feature = "engine")] -use crate::types::{EthAddress, SdkUnwrap}; +use crate::prelude::{String, Vec}; +use crate::types::{AccountId, Balance, RawAddress, RawH256, RawU256}; +#[cfg(feature = "engine")] +use crate::{ + admin_controlled::PausedMask, + json, + prelude::{is_valid_account_id, ToString, TryFrom}, + sdk, + types::{EthAddress, Proof, SdkUnwrap}, +}; use evm::backend::Log; /// Borsh-encoded parameters for the `new` function. diff --git a/src/precompiles/blake2.rs b/src/precompiles/blake2.rs index f78b82fa2..6511cc80d 100644 --- a/src/precompiles/blake2.rs +++ b/src/precompiles/blake2.rs @@ -18,6 +18,7 @@ mod consts { pub(super) struct Blake2F(PhantomData); impl Blake2F { + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const ADDRESS: [u8; 20] = super::make_address(0, 9); } diff --git a/src/precompiles/bn128.rs b/src/precompiles/bn128.rs index 73b46f57e..3d352f127 100644 --- a/src/precompiles/bn128.rs +++ b/src/precompiles/bn128.rs @@ -48,8 +48,11 @@ mod consts { pub(super) mod addresses { use crate::precompiles; + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub const ADD: [u8; 20] = precompiles::make_address(0, 6); + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub const MUL: [u8; 20] = precompiles::make_address(0, 7); + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub const PAIR: [u8; 20] = precompiles::make_address(0, 8); } diff --git a/src/precompiles/hash.rs b/src/precompiles/hash.rs index 51ae03632..c0f437545 100644 --- a/src/precompiles/hash.rs +++ b/src/precompiles/hash.rs @@ -24,6 +24,7 @@ mod consts { pub struct SHA256(PhantomData); impl SHA256 { + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const ADDRESS: [u8; 20] = super::make_address(0, 2); } @@ -89,6 +90,7 @@ impl Precompile for SHA256 { pub struct RIPEMD160(PhantomData); impl RIPEMD160 { + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const ADDRESS: [u8; 20] = super::make_address(0, 3); } diff --git a/src/precompiles/identity.rs b/src/precompiles/identity.rs index 4053fe652..36515505b 100644 --- a/src/precompiles/identity.rs +++ b/src/precompiles/identity.rs @@ -21,6 +21,7 @@ mod consts { pub struct Identity(PhantomData); impl Identity { + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const ADDRESS: [u8; 20] = super::make_address(0, 4); } diff --git a/src/precompiles/mod.rs b/src/precompiles/mod.rs index a28f31959..4660303aa 100644 --- a/src/precompiles/mod.rs +++ b/src/precompiles/mod.rs @@ -3,24 +3,25 @@ mod bn128; mod hash; mod identity; mod modexp; -#[cfg(feature = "exit-precompiles")] mod native; mod secp256k1; use evm::{Context, ExitError}; -use crate::precompiles::blake2::Blake2F; -use crate::precompiles::bn128::{BN128Add, BN128Mul, BN128Pair}; -use crate::precompiles::hash::{RIPEMD160, SHA256}; -use crate::precompiles::identity::Identity; -use crate::precompiles::modexp::ModExp; -#[cfg(feature = "exit-precompiles")] -use crate::precompiles::native::{ExitToEthereum, ExitToNear}; pub(crate) use crate::precompiles::secp256k1::ecrecover; -use crate::precompiles::secp256k1::ECRecover; -use crate::prelude::{Address, Vec}; -#[cfg(feature = "engine")] -use crate::state::AuroraStackState; +use crate::prelude::Vec; use crate::AuroraState; +#[cfg(feature = "engine")] +use crate::{ + precompiles::blake2::Blake2F, + precompiles::bn128::{BN128Add, BN128Mul, BN128Pair}, + precompiles::hash::{RIPEMD160, SHA256}, + precompiles::identity::Identity, + precompiles::modexp::ModExp, + precompiles::native::{ExitToEthereum, ExitToNear}, + precompiles::secp256k1::ECRecover, + prelude::Address, + state::AuroraStackState, +}; use evm::backend::Log; use evm::ExitSucceed; @@ -65,6 +66,7 @@ impl From for evm::executor::PrecompileOutput { /// A precompile operation result. type PrecompileResult = Result; +#[cfg(feature = "engine")] type EvmPrecompileResult = Result; /// A precompiled function for use in the EVM. @@ -145,11 +147,9 @@ pub fn homestead_precompiles( RIPEMD160::::ADDRESS => Some(RIPEMD160::::run( input, target_gas, context, state, is_static, )), - #[cfg(feature = "exit-precompiles")] ExitToNear::::ADDRESS => Some(ExitToNear::::run( input, target_gas, context, state, is_static, )), - #[cfg(feature = "exit-precompiles")] ExitToEthereum::::ADDRESS => Some( ExitToEthereum::::run(input, target_gas, context, state, is_static), ), @@ -199,11 +199,9 @@ pub fn byzantium_precompiles( bn128::addresses::PAIR => Some(BN128Pair::::run( input, target_gas, context, state, is_static, )), - #[cfg(feature = "exit-precompiles")] ExitToNear::::ADDRESS => Some(ExitToNear::::run( input, target_gas, context, state, is_static, )), - #[cfg(feature = "exit-precompiles")] ExitToEthereum::::ADDRESS => Some( ExitToEthereum::::run(input, target_gas, context, state, is_static), ), @@ -256,11 +254,9 @@ pub fn istanbul_precompiles( Blake2F::::ADDRESS => Some(Blake2F::::run( input, target_gas, context, state, is_static, )), - #[cfg(feature = "exit-precompiles")] ExitToNear::::ADDRESS => Some(ExitToNear::::run( input, target_gas, context, state, is_static, )), - #[cfg(feature = "exit-precompiles")] ExitToEthereum::::ADDRESS => Some( ExitToEthereum::::run(input, target_gas, context, state, is_static), ), @@ -313,11 +309,9 @@ pub fn berlin_precompiles( Blake2F::::ADDRESS => Some(Blake2F::::run( input, target_gas, context, state, is_static, )), - #[cfg(feature = "exit-precompiles")] ExitToNear::::ADDRESS => Some(ExitToNear::::run( input, target_gas, context, state, is_static, )), - #[cfg(feature = "exit-precompiles")] ExitToEthereum::::ADDRESS => Some( ExitToEthereum::::run(input, target_gas, context, state, is_static), ), @@ -329,6 +323,7 @@ pub fn berlin_precompiles( /// const fn for making an address by concatenating the bytes from two given numbers, /// Note that 32 + 128 = 160 = 20 bytes (the length of an address). This function is used /// as a convenience for specifying the addresses of the various precompiles. +#[cfg_attr(not(feature = "engine"), allow(dead_code))] const fn make_address(x: u32, y: u128) -> [u8; 20] { let x_bytes = x.to_be_bytes(); let y_bytes = y.to_be_bytes(); diff --git a/src/precompiles/modexp.rs b/src/precompiles/modexp.rs index 26fcdaff4..26410f054 100644 --- a/src/precompiles/modexp.rs +++ b/src/precompiles/modexp.rs @@ -4,72 +4,102 @@ use crate::precompiles::{ use crate::prelude::{PhantomData, Vec, U256}; use crate::AuroraState; use evm::{Context, ExitError}; -use num::BigUint; +use num::{BigUint, Integer}; +#[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const ADDRESS: [u8; 20] = super::make_address(0, 5); pub(super) struct ModExp(PhantomData, PhantomData); -impl ModExp { - fn adj_exp_len(exp_len: U256, base_len: U256, bytes: &[u8]) -> U256 { - let mut exp32_bytes = Vec::with_capacity(32); - for i in 0..32 { - if U256::from(96) + base_len + U256::from(1) >= U256::from(bytes.len()) { - exp32_bytes.push(0u8); - } else { - let base_len_i = base_len.as_usize(); - let bytes_i = 96 + base_len_i + i; - if let Some(byte) = bytes.get(bytes_i) { - exp32_bytes.push(*byte); - } else { - // Pad out the data if the byte is empty. - exp32_bytes.push(0u8); - } - } - } - let exp32 = U256::from(exp32_bytes.as_slice()); +impl ModExp { + // Note: the output of this function is bounded by 2^67 + fn calc_iter_count(exp_len: u64, base_len: u64, bytes: &[u8]) -> U256 { + #[allow(clippy::redundant_closure)] + let exp = parse_bytes( + bytes, + (base_len as usize).saturating_add(96), + core::cmp::min(32, exp_len as usize), + // I don't understand why I need a closure here, but doesn't compile without one + |x| U256::from(x), + ); - if exp_len <= U256::from(32) && exp32 == U256::zero() { + if exp_len <= 32 && exp.is_zero() { U256::zero() - } else if exp_len <= U256::from(32) { - U256::from(exp32.bits()) + } else if exp_len <= 32 { + U256::from(exp.bits()) - U256::from(1) } else { // else > 32 - U256::from(8) * (exp_len - U256::from(32)) + U256::from(exp32.bits()) + U256::from(8) * U256::from(exp_len - 32) + U256::from(exp.bits()) - U256::from(1) } } - fn mult_complexity(x: U256) -> Result { - if x <= U256::from(64) { - Ok(x * x) - } else if x <= U256::from(1_024) { - Ok(x * x / U256::from(4) + U256::from(96) * x - U256::from(3_072)) - } else { - let (sqroot, overflow) = x.overflowing_mul(x); - if overflow { - Err(ExitError::OutOfGas) + fn run_inner(input: &[u8]) -> Result, ExitError> { + let (base_len, exp_len, mod_len) = parse_lengths(input); + let base_len = base_len as usize; + let exp_len = exp_len as usize; + let mod_len = mod_len as usize; + + let base_start = 96; + let base_end = base_len.saturating_add(base_start); + + let exp_start = base_end; + let exp_end = exp_len.saturating_add(exp_start); + + let mod_start = exp_end; + + let base = parse_bytes(input, base_start, base_len, BigUint::from_bytes_be); + let exponent = parse_bytes(input, exp_start, exp_len, BigUint::from_bytes_be); + let modulus = parse_bytes(input, mod_start, mod_len, BigUint::from_bytes_be); + + let output = { + let computed_result = if modulus == BigUint::from(0u32) { + Vec::new() } else { - Ok(sqroot / U256::from(16) + U256::from(480) * x - U256::from(199_680)) + base.modpow(&exponent, &modulus).to_bytes_be() + }; + // The result must be the same length as the input modulus. + // To ensure this we pad on the left with zeros. + if mod_len > computed_result.len() { + let diff = mod_len - computed_result.len(); + let mut padded_result = Vec::with_capacity(mod_len); + padded_result.extend(core::iter::repeat(0).take(diff)); + padded_result.extend_from_slice(&computed_result); + padded_result + } else { + computed_result } + }; + + Ok(output) + } +} + +impl ModExp { + // ouput of this function is bounded by 2^128 + fn mul_complexity(x: u64) -> U256 { + if x <= 64 { + U256::from(x * x) + } else if x <= 1_024 { + U256::from(x * x / 4 + 96 * x - 3_072) + } else { + // up-cast to avoid overflow + let x = U256::from(x); + let x_sq = x * x; // x < 2^64 => x*x < 2^128 < 2^256 (no overflow) + x_sq / U256::from(16) + U256::from(480) * x - U256::from(199_680) } } } impl Precompile for ModExp { fn required_gas(input: &[u8]) -> Result { - let base_len = U256::from(&input[0..32]); - let exp_len = U256::from(&input[32..64]); - let mod_len = U256::from(&input[64..96]); - - let mul = Self::mult_complexity(core::cmp::max(mod_len, base_len))?; - let adj = core::cmp::max(Self::adj_exp_len(exp_len, base_len, input), U256::from(1)) - / U256::from(20); - let (gas_val, overflow) = mul.overflowing_mul(adj); - if overflow { - Err(ExitError::OutOfGas) - } else { - Ok(gas_val.as_u64()) - } + let (base_len, exp_len, mod_len) = parse_lengths(input); + + let mul = Self::mul_complexity(core::cmp::max(mod_len, base_len)); + let iter_count = Self::calc_iter_count(exp_len, base_len, &input); + // mul * iter_count bounded by 2^195 < 2^256 (no overflow) + let gas = mul * core::cmp::max(iter_count, U256::one()) / U256::from(20); + + Ok(saturating_round(gas)) } /// See: https://eips.ethereum.org/EIPS/eip-198 @@ -83,200 +113,330 @@ impl Precompile for ModExp { ) -> PrecompileResult { let cost = Self::required_gas(input)?; if cost > target_gas { - return Err(ExitError::OutOfGas); - } - - let base_len = U256::from(&input[0..32]); - let exp_len = U256::from(&input[32..64]); - let mod_len = U256::from(&input[64..96]); - - let base_len = base_len.as_usize(); - let mut base_bytes = Vec::with_capacity(32); - for i in 0..base_len { - if 96 + i >= input.len() { - base_bytes.push(0u8); - } else { - base_bytes.push(input[96 + i]); - } - } - - let exp_len = exp_len.as_usize(); - let mut exp_bytes = Vec::with_capacity(32); - for i in 0..exp_len { - if 96 + base_len + i >= input.len() { - exp_bytes.push(0u8); - } else { - exp_bytes.push(input[96 + base_len + i]); - } - } - - let mod_len = mod_len.as_usize(); - let mut mod_bytes = Vec::with_capacity(32); - for i in 0..mod_len { - if 96 + base_len + exp_len + i >= input.len() { - mod_bytes.push(0u8); - } else { - mod_bytes.push(input[96 + base_len + exp_len + i]); - } + Err(ExitError::OutOfGas) + } else { + let output = Self::run_inner(input)?; + Ok(PrecompileOutput::without_logs(cost, output)) } + } +} - let base = BigUint::from_bytes_be(&base_bytes); - let exponent = BigUint::from_bytes_be(&exp_bytes); - let modulus = BigUint::from_bytes_be(&mod_bytes); - - let output = { - let computed_result = base.modpow(&exponent, &modulus).to_bytes_be(); - // The result must be the same length as the input modulus. - // To ensure this we pad on the left with zeros. - if mod_len > computed_result.len() { - let diff = mod_len - computed_result.len(); - let mut padded_result = Vec::with_capacity(mod_len); - padded_result.extend(core::iter::repeat(0).take(diff)); - padded_result.extend_from_slice(&computed_result); - padded_result - } else { - computed_result - } - }; - - Ok(PrecompileOutput::without_logs(cost, output)) +impl ModExp { + // output bounded by 2^122 + fn mul_complexity(base_len: u64, mod_len: u64) -> U256 { + let max_len = core::cmp::max(mod_len, base_len); + let words = U256::from(max_len.div_ceil(&8)); + words * words } } impl Precompile for ModExp { - fn required_gas(_input: &[u8]) -> Result { - todo!() + fn required_gas(input: &[u8]) -> Result { + let (base_len, exp_len, mod_len) = parse_lengths(input); + + let mul = Self::mul_complexity(base_len, mod_len); + let iter_count = Self::calc_iter_count(exp_len, base_len, &input); + // mul * iter_count bounded by 2^189 (so no overflow) + let gas = mul * iter_count / U256::from(3); + + Ok(core::cmp::max(200, saturating_round(gas))) } fn run( - _input: &[u8], - _target_gas: u64, + input: &[u8], + target_gas: u64, _context: &Context, _state: &mut S, _is_static: bool, ) -> PrecompileResult { - todo!() + let cost = Self::required_gas(input)?; + if cost > target_gas { + Err(ExitError::OutOfGas) + } else { + let output = Self::run_inner(input)?; + Ok(PrecompileOutput::without_logs(cost, output)) + } } } +fn parse_bytes T>(input: &[u8], start: usize, size: usize, f: F) -> T { + let len = input.len(); + if start >= len { + return f(&[]); + } + let end = start + size; + if end > len { + f(&input[start..len]) + } else { + f(&input[start..end]) + } +} + +fn saturating_round(x: U256) -> u64 { + if x.bits() > 64 { + u64::MAX + } else { + x.as_u64() + } +} + +fn parse_lengths(input: &[u8]) -> (u64, u64, u64) { + let parse = |start: usize| -> u64 { + // I don't understand why I need a closure here, but doesn't compile without one + #[allow(clippy::redundant_closure)] + saturating_round(parse_bytes(input, start, 32, |x| U256::from(x))) + }; + let base_len = parse(0); + let exp_len = parse(32); + let mod_len = parse(64); + + (base_len, exp_len, mod_len) +} + #[cfg(test)] mod tests { - use crate::test_utils::{new_context, new_state}; + use crate::test_utils::{new_context, new_state, MockState}; use super::*; - #[test] - fn test_modexp() { - let test_input1 = hex::decode( - "\ + // Byzantium tests: https://github.com/holiman/go-ethereum/blob/master/core/vm/testdata/precompiles/modexp.json + // Berlin tests:https://github.com/holiman/go-ethereum/blob/master/core/vm/testdata/precompiles/modexp_eip2565.json + + struct Test { + input: &'static str, + expected: &'static str, + name: &'static str, + } + + const TESTS: [Test; 17] = [ + Test { + input: "\ 0000000000000000000000000000000000000000000000000000000000000001\ 0000000000000000000000000000000000000000000000000000000000000020\ 0000000000000000000000000000000000000000000000000000000000000020\ 03\ fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e\ fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - ) - .unwrap(); - let modexp_res = ModExp::::run( - &test_input1, - 12_288, - &new_context(), - &mut new_state(), - false, - ) - .unwrap() - .output; - let res = U256::from_big_endian(&modexp_res); - - assert_eq!(res, U256::from(1)); - - let test_input2 = hex::decode( - "0000000000000000000000000000000000000000000000000000000000000000\ + expected: "0000000000000000000000000000000000000000000000000000000000000001", + name: "eip198_example_1", + }, + Test { + input: "\ + 0000000000000000000000000000000000000000000000000000000000000000\ 0000000000000000000000000000000000000000000000000000000000000020\ 0000000000000000000000000000000000000000000000000000000000000020\ fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2e\ fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - ) - .unwrap(); - let modexp_res = ModExp::::run( - &test_input2, - 12_288, - &new_context(), - &mut new_state(), - false, - ) - .unwrap() - .output; - let res = U256::from_big_endian(&modexp_res); - - assert_eq!(res, U256::from(0)); - - let test_input3 = hex::decode( - "0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000020\ - ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\ - fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe\ - fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd", - ) - .unwrap(); - assert!(ModExp::::run( - &test_input3, - 0, - &new_context(), - &mut new_state(), - false - ) - .is_err()); - - let test_input4 = hex::decode( - "0000000000000000000000000000000000000000000000000000000000000001\ - 0000000000000000000000000000000000000000000000000000000000000002\ - 0000000000000000000000000000000000000000000000000000000000000020\ - 03\ - ffff\ - 8000000000000000000000000000000000000000000000000000000000000000\ - 07", - ) - .unwrap(); - let expected = U256::from_big_endian( - &hex::decode("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab") - .unwrap(), - ); - let modexp_res = ModExp::::run( - &test_input4, - 12_288, - &new_context(), - &mut new_state(), - false, - ) - .unwrap() - .output; - let res = U256::from_big_endian(&modexp_res); - assert_eq!(res, expected); - - let test_input5 = hex::decode( - "0000000000000000000000000000000000000000000000000000000000000001\ - 0000000000000000000000000000000000000000000000000000000000000002\ - 0000000000000000000000000000000000000000000000000000000000000020\ - 03\ - ffff\ - 80", - ) - .unwrap(); - let expected = U256::from_big_endian( - &hex::decode("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab") - .unwrap(), - ); - let modexp_res = ModExp::::run( - &test_input5, - 12_288, - &new_context(), - &mut new_state(), - false, - ) - .unwrap() - .output; - let res = U256::from_big_endian(&modexp_res); - assert_eq!(res, expected); + expected: "0000000000000000000000000000000000000000000000000000000000000000", + name: "eip198_example_2", + }, + Test { + input: "\ + 0000000000000000000000000000000000000000000000000000000000000040\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000040\ + e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb003\ + 3ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5\ + 02fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac\ + 2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c\ + 6b", + expected: "60008f1614cc01dcfb6bfb09c625cf90b47d4468db81b5f8b7a39d42f332eab9b2da8f2d95311648a8f243f4bb13cfb3d8f7f2a3c014122ebb3ed41b02783adc", + name: "nagydani_1_square", + }, + Test { + input: "\ + 0000000000000000000000000000000000000000000000000000000000000040\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000040\ + e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb003\ + 3ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5\ + 03fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd6095ac\ + 2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a248c\ + 6b", + expected: "4834a46ba565db27903b1c720c9d593e84e4cbd6ad2e64b31885d944f68cd801f92225a8961c952ddf2797fa4701b330c85c4b363798100b921a1a22a46a7fec", + name: "nagydani_1_qube" + }, + Test { + input: "\ + 0000000000000000000000000000000000000000000000000000000000000040\ + 0000000000000000000000000000000000000000000000000000000000000003\ + 0000000000000000000000000000000000000000000000000000000000000040\ + e09ad9675465c53a109fac66a445c91b292d2bb2c5268addb30cd82f80fcb003\ + 3ff97c80a5fc6f39193ae969c6ede6710a6b7ac27078a06d90ef1c72e5c85fb5\ + 010001fc9e1f6beb81516545975218075ec2af118cd8798df6e08a147c60fd60\ + 95ac2bb02c2908cf4dd7c81f11c289e4bce98f3553768f392a80ce22bf5c4f4a\ + 248c6b", + expected: "c36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2", + name: "nagydani_1_pow0x10001", + }, + Test { + input: "\ + 0000000000000000000000000000000000000000000000000000000000000080\ + 0000000000000000000000000000000000000000000000000000000000000001\ + 0000000000000000000000000000000000000000000000000000000000000080\ + cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be\ + 0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81\ + dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dc\ + b9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51\ + 02e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3\ + ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b2\ + 8c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be\ + 9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c2870\ + 87", + expected: "981dd99c3b113fae3e3eaa9435c0dc96779a23c12a53d1084b4f67b0b053a27560f627b873e3f16ad78f28c94f14b6392def26e4d8896c5e3c984e50fa0b3aa44f1da78b913187c6128baa9340b1e9c9a0fd02cb78885e72576da4a8f7e5a113e173a7a2889fde9d407bd9f06eb05bc8fc7b4229377a32941a02bf4edcc06d70", + name: "nagydani_2_square", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf5103e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + expected: "d89ceb68c32da4f6364978d62aaa40d7b09b59ec61eb3c0159c87ec3a91037f7dc6967594e530a69d049b64adfa39c8fa208ea970cfe4b7bcd359d345744405afe1cbf761647e32b3184c7fbe87cee8c6c7ff3b378faba6c68b83b6889cb40f1603ee68c56b4c03d48c595c826c041112dc941878f8c5be828154afd4a16311f", + name: "nagydani_2_qube", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000080cad7d991a00047dd54d3399b6b0b937c718abddef7917c75b6681f40cc15e2be0003657d8d4c34167b2f0bbbca0ccaa407c2a6a07d50f1517a8f22979ce12a81dcaf707cc0cebfc0ce2ee84ee7f77c38b9281b9822a8d3de62784c089c9b18dcb9a2a5eecbede90ea788a862a9ddd9d609c2c52972d63e289e28f6a590ffbf51010001e6d893b80aeed5e6e9ce9afa8a5d5675c93a32ac05554cb20e9951b2c140e3ef4e433068cf0fb73bc9f33af1853f64aa27a0028cbf570d7ac9048eae5dc7b28c87c31e5810f1e7fa2cda6adf9f1076dbc1ec1238560071e7efc4e9565c49be9e7656951985860a558a754594115830bcdb421f741408346dd5997bb01c287087", + expected: "ad85e8ef13fd1dd46eae44af8b91ad1ccae5b7a1c92944f92a19f21b0b658139e0cabe9c1f679507c2de354bf2c91ebd965d1e633978a830d517d2f6f8dd5fd58065d58559de7e2334a878f8ec6992d9b9e77430d4764e863d77c0f87beede8f2f7f2ab2e7222f85cc9d98b8467f4bb72e87ef2882423ebdb6daf02dddac6db2", + name: "nagydani_2_pow0x10001", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb02d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + expected: "affc7507ea6d84751ec6b3f0d7b99dbcc263f33330e450d1b3ff0bc3d0874320bf4edd57debd587306988157958cb3cfd369cc0c9c198706f635c9e0f15d047df5cb44d03e2727f26b083c4ad8485080e1293f171c1ed52aef5993a5815c35108e848c951cf1e334490b4a539a139e57b68f44fee583306f5b85ffa57206b3ee5660458858534e5386b9584af3c7f67806e84c189d695e5eb96e1272d06ec2df5dc5fabc6e94b793718c60c36be0a4d031fc84cd658aa72294b2e16fc240aef70cb9e591248e38bd49c5a554d1afa01f38dab72733092f7555334bbef6c8c430119840492380aa95fa025dcf699f0a39669d812b0c6946b6091e6e235337b6f8", + name: "nagydani_3_square", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb03d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + expected: "1b280ecd6a6bf906b806d527c2a831e23b238f89da48449003a88ac3ac7150d6a5e9e6b3be4054c7da11dd1e470ec29a606f5115801b5bf53bc1900271d7c3ff3cd5ed790d1c219a9800437a689f2388ba1a11d68f6a8e5b74e9a3b1fac6ee85fc6afbac599f93c391f5dc82a759e3c6c0ab45ce3f5d25d9b0c1bf94cf701ea6466fc9a478dacc5754e593172b5111eeba88557048bceae401337cd4c1182ad9f700852bc8c99933a193f0b94cf1aedbefc48be3bc93ef5cb276d7c2d5462ac8bb0c8fe8923a1db2afe1c6b90d59c534994a6a633f0ead1d638fdc293486bb634ff2c8ec9e7297c04241a61c37e3ae95b11d53343d4ba2b4cc33d2cfa7eb705e", + name: "nagydani_3_qube", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000100c9130579f243e12451760976261416413742bd7c91d39ae087f46794062b8c239f2a74abf3918605a0e046a7890e049475ba7fbb78f5de6490bd22a710cc04d30088179a919d86c2da62cf37f59d8f258d2310d94c24891be2d7eeafaa32a8cb4b0cfe5f475ed778f45907dc8916a73f03635f233f7a77a00a3ec9ca6761a5bbd558a2318ecd0caa1c5016691523e7e1fa267dd35e70c66e84380bdcf7c0582f540174e572c41f81e93da0b757dff0b0fe23eb03aa19af0bdec3afb474216febaacb8d0381e631802683182b0fe72c28392539850650b70509f54980241dc175191a35d967288b532a7a8223ce2440d010615f70df269501944d4ec16fe4a3cb010001d7a85909174757835187cb52e71934e6c07ef43b4c46fc30bbcd0bc72913068267c54a4aabebb493922492820babdeb7dc9b1558fcf7bd82c37c82d3147e455b623ab0efa752fe0b3a67ca6e4d126639e645a0bf417568adbb2a6a4eef62fa1fa29b2a5a43bebea1f82193a7dd98eb483d09bb595af1fa9c97c7f41f5649d976aee3e5e59e2329b43b13bea228d4a93f16ba139ccb511de521ffe747aa2eca664f7c9e33da59075cc335afcd2bf3ae09765f01ab5a7c3e3938ec168b74724b5074247d200d9970382f683d6059b94dbc336603d1dfee714e4b447ac2fa1d99ecb4961da2854e03795ed758220312d101e1e3d87d5313a6d052aebde75110363d", + expected: "37843d7c67920b5f177372fa56e2a09117df585f81df8b300fba245b1175f488c99476019857198ed459ed8d9799c377330e49f4180c4bf8e8f66240c64f65ede93d601f957b95b83efdee1e1bfde74169ff77002eaf078c71815a9220c80b2e3b3ff22c2f358111d816ebf83c2999026b6de50bfc711ff68705d2f40b753424aefc9f70f08d908b5a20276ad613b4ab4309a3ea72f0c17ea9df6b3367d44fb3acab11c333909e02e81ea2ed404a712d3ea96bba87461720e2d98723e7acd0520ac1a5212dbedcd8dc0c1abf61d4719e319ff4758a774790b8d463cdfe131d1b2dcfee52d002694e98e720cb6ae7ccea353bc503269ba35f0f63bf8d7b672a76", + name: "nagydani_3_pow0x10001", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8102df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + expected: "8a5aea5f50dcc03dc7a7a272b5aeebc040554dbc1ffe36753c4fc75f7ed5f6c2cc0de3a922bf96c78bf0643a73025ad21f45a4a5cadd717612c511ab2bff1190fe5f1ae05ba9f8fe3624de1de2a817da6072ddcdb933b50216811dbe6a9ca79d3a3c6b3a476b079fd0d05f04fb154e2dd3e5cb83b148a006f2bcbf0042efb2ae7b916ea81b27aac25c3bf9a8b6d35440062ad8eae34a83f3ffa2cc7b40346b62174a4422584f72f95316f6b2bee9ff232ba9739301c97c99a9ded26c45d72676eb856ad6ecc81d36a6de36d7f9dafafee11baa43a4b0d5e4ecffa7b9b7dcefd58c397dd373e6db4acd2b2c02717712e6289bed7c813b670c4a0c6735aa7f3b0f1ce556eae9fcc94b501b2c8781ba50a8c6220e8246371c3c7359fe4ef9da786ca7d98256754ca4e496be0a9174bedbecb384bdf470779186d6a833f068d2838a88d90ef3ad48ff963b67c39cc5a3ee123baf7bf3125f64e77af7f30e105d72c4b9b5b237ed251e4c122c6d8c1405e736299c3afd6db16a28c6a9cfa68241e53de4cd388271fe534a6a9b0dbea6171d170db1b89858468885d08fecbd54c8e471c3e25d48e97ba450b96d0d87e00ac732aaa0d3ce4309c1064bd8a4c0808a97e0143e43a24cfa847635125cd41c13e0574487963e9d725c01375db99c31da67b4cf65eff555f0c0ac416c727ff8d438ad7c42030551d68c2e7adda0abb1ca7c10", + name: "nagydani_4_square", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b8103df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + expected: "5a2664252aba2d6e19d9600da582cdd1f09d7a890ac48e6b8da15ae7c6ff1856fc67a841ac2314d283ffa3ca81a0ecf7c27d89ef91a5a893297928f5da0245c99645676b481b7e20a566ee6a4f2481942bee191deec5544600bb2441fd0fb19e2ee7d801ad8911c6b7750affec367a4b29a22942c0f5f4744a4e77a8b654da2a82571037099e9c6d930794efe5cdca73c7b6c0844e386bdca8ea01b3d7807146bb81365e2cdc6475f8c23e0ff84463126189dc9789f72bbce2e3d2d114d728a272f1345122de23df54c922ec7a16e5c2a8f84da8871482bd258c20a7c09bbcd64c7a96a51029bbfe848736a6ba7bf9d931a9b7de0bcaf3635034d4958b20ae9ab3a95a147b0421dd5f7ebff46c971010ebfc4adbbe0ad94d5498c853e7142c450d8c71de4b2f84edbf8acd2e16d00c8115b150b1c30e553dbb82635e781379fe2a56360420ff7e9f70cc64c00aba7e26ed13c7c19622865ae07248daced36416080f35f8cc157a857ed70ea4f347f17d1bee80fa038abd6e39b1ba06b97264388b21364f7c56e192d4b62d9b161405f32ab1e2594e86243e56fcf2cb30d21adef15b9940f91af681da24328c883d892670c6aa47940867a81830a82b82716895db810df1b834640abefb7db2092dd92912cb9a735175bc447be40a503cf22dfe565b4ed7a3293ca0dfd63a507430b323ee248ec82e843b673c97ad730728cebc", + name: "nagydani_4_qube", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000200db34d0e438249c0ed685c949cc28776a05094e1c48691dc3f2dca5fc3356d2a0663bd376e4712839917eb9a19c670407e2c377a2de385a3ff3b52104f7f1f4e0c7bf7717fb913896693dc5edbb65b760ef1b00e42e9d8f9af17352385e1cd742c9b006c0f669995cb0bb21d28c0aced2892267637b6470d8cee0ab27fc5d42658f6e88240c31d6774aa60a7ebd25cd48b56d0da11209f1928e61005c6eb709f3e8e0aaf8d9b10f7d7e296d772264dc76897ccdddadc91efa91c1903b7232a9e4c3b941917b99a3bc0c26497dedc897c25750af60237aa67934a26a2bc491db3dcc677491944bc1f51d3e5d76b8d846a62db03dedd61ff508f91a56d71028125035c3a44cbb041497c83bf3e4ae2a9613a401cc721c547a2afa3b16a2969933d3626ed6d8a7428648f74122fd3f2a02a20758f7f693892c8fd798b39abac01d18506c45e71432639e9f9505719ee822f62ccbf47f6850f096ff77b5afaf4be7d772025791717dbe5abf9b3f40cff7d7aab6f67e38f62faf510747276e20a42127e7500c444f9ed92baf65ade9e836845e39c4316d9dce5f8e2c8083e2c0acbb95296e05e51aab13b6b8f53f06c9c4276e12b0671133218cc3ea907da3bd9a367096d9202128d14846cc2e20d56fc8473ecb07cecbfb8086919f3971926e7045b853d85a69d026195c70f9f7a823536e2a8f4b3e12e94d9b53a934353451094b81010001df3143a0057457d75e8c708b6337a6f5a4fd1a06727acf9fb93e2993c62f3378b37d56c85e7b1e00f0145ebf8e4095bd723166293c60b6ac1252291ef65823c9e040ddad14969b3b340a4ef714db093a587c37766d68b8d6b5016e741587e7e6bf7e763b44f0247e64bae30f994d248bfd20541a333e5b225ef6a61199e301738b1e688f70ec1d7fb892c183c95dc543c3e12adf8a5e8b9ca9d04f9445cced3ab256f29e998e69efaa633a7b60e1db5a867924ccab0a171d9d6e1098dfa15acde9553de599eaa56490c8f411e4985111f3d40bddfc5e301edb01547b01a886550a61158f7e2033c59707789bf7c854181d0c2e2a42a93cf09209747d7082e147eb8544de25c3eb14f2e35559ea0c0f5877f2f3fc92132c0ae9da4e45b2f6c866a224ea6d1f28c05320e287750fbc647368d41116e528014cc1852e5531d53e4af938374daba6cee4baa821ed07117253bb3601ddd00d59a3d7fb2ef1f5a2fbba7c429f0cf9a5b3462410fd833a69118f8be9c559b1000cc608fd877fb43f8e65c2d1302622b944462579056874b387208d90623fcdaf93920ca7a9e4ba64ea208758222ad868501cc2c345e2d3a5ea2a17e5069248138c8a79c0251185d29ee73e5afab5354769142d2bf0cb6712727aa6bf84a6245fcdae66e4938d84d1b9dd09a884818622080ff5f98942fb20acd7e0c916c2d5ea7ce6f7e173315384518f", + expected: "bed8b970c4a34849fc6926b08e40e20b21c15ed68d18f228904878d4370b56322d0da5789da0318768a374758e6375bfe4641fca5285ec7171828922160f48f5ca7efbfee4d5148612c38ad683ae4e3c3a053d2b7c098cf2b34f2cb19146eadd53c86b2d7ccf3d83b2c370bfb840913ee3879b1057a6b4e07e110b6bcd5e958bc71a14798c91d518cc70abee264b0d25a4110962a764b364ac0b0dd1ee8abc8426d775ec0f22b7e47b32576afaf1b5a48f64573ed1c5c29f50ab412188d9685307323d990802b81dacc06c6e05a1e901830ba9fcc67688dc29c5e27bde0a6e845ca925f5454b6fb3747edfaa2a5820838fb759eadf57f7cb5cec57fc213ddd8a4298fa079c3c0f472b07fb15aa6a7f0a3780bd296ff6a62e58ef443870b02260bd4fd2bbc98255674b8e1f1f9f8d33c7170b0ebbea4523b695911abbf26e41885344823bd0587115fdd83b721a4e8457a31c9a84b3d3520a07e0e35df7f48e5a9d534d0ec7feef1ff74de6a11e7f93eab95175b6ce22c68d78a642ad642837897ec11349205d8593ac19300207572c38d29ca5dfa03bc14cdbc32153c80e5cc3e739403d34c75915e49beb43094cc6dcafb3665b305ddec9286934ae66ec6b777ca528728c851318eb0f207b39f1caaf96db6eeead6b55ed08f451939314577d42bcc9f97c0b52d0234f88fd07e4c1d7780fdebc025cfffcb572cb27a8c33963", + name: "nagydani_4_pow0x10001", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf02e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + expected: "d61fe4e3f32ac260915b5b03b78a86d11bfc41d973fce5b0cc59035cf8289a8a2e3878ea15fa46565b0d806e2f85b53873ea20ed653869b688adf83f3ef444535bf91598ff7e80f334fb782539b92f39f55310cc4b35349ab7b278346eda9bc37c0d8acd3557fae38197f412f8d9e57ce6a76b7205c23564cab06e5615be7c6f05c3d05ec690cba91da5e89d55b152ff8dd2157dc5458190025cf94b1ad98f7cbe64e9482faba95e6b33844afc640892872b44a9932096508f4a782a4805323808f23e54b6ff9b841dbfa87db3505ae4f687972c18ea0f0d0af89d36c1c2a5b14560c153c3fee406f5cf15cfd1c0bb45d767426d465f2f14c158495069d0c5955a00150707862ecaae30624ebacdd8ac33e4e6aab3ff90b6ba445a84689386b9e945d01823a65874444316e83767290fcff630d2477f49d5d8ffdd200e08ee1274270f86ed14c687895f6caf5ce528bd970c20d2408a9ba66216324c6a011ac4999098362dbd98a038129a2d40c8da6ab88318aa3046cb660327cc44236d9e5d2163bd0959062195c51ed93d0088b6f92051fc99050ece2538749165976233697ab4b610385366e5ce0b02ad6b61c168ecfbedcdf74278a38de340fd7a5fead8e588e294795f9b011e2e60377a89e25c90e145397cdeabc60fd32444a6b7642a611a83c464d8b8976666351b4865c37b02e6dc21dbcdf5f930341707b618cc0f03c3122646b3385c9df9f2ec730eec9d49e7dfc9153b6e6289da8c4f0ebea9ccc1b751948e3bb7171c9e4d57423b0eeeb79095c030cb52677b3f7e0b45c30f645391f3f9c957afa549c4e0b2465b03c67993cd200b1af01035962edbc4c9e89b31c82ac121987d6529dafdeef67a132dc04b6dc68e77f22862040b75e2ceb9ff16da0fca534e6db7bd12fa7b7f51b6c08c1e23dfcdb7acbd2da0b51c87ffbced065a612e9b1c8bba9b7e2d8d7a2f04fcc4aaf355b60d764879a76b5e16762d5f2f55d585d0c8e82df6940960cddfb72c91dfa71f6b4e1c6ca25dfc39a878e998a663c04fe29d5e83b9586d047b4d7ff70a9f0d44f127e7d741685ca75f11629128d916a0ffef4be586a30c4b70389cc746e84ebf177c01ee8a4511cfbb9d1ecf7f7b33c7dd8177896e10bbc82f838dcd6db7ac67de62bf46b6a640fb580c5d1d2708f3862e3d2b645d0d18e49ef088053e3a220adc0e033c2afcfe61c90e32151152eb3caaf746c5e377d541cafc6cbb0cc0fa48b5caf1728f2e1957f5addfc234f1a9d89e40d49356c9172d0561a695fce6dab1d412321bbf407f63766ffd7b6b3d79bcfa07991c5a9709849c1008689e3b47c50d613980bec239fb64185249d055b30375ccb4354d71fe4d05648fbf6c80634dfc3575f2f24abb714c1e4c95e8896763bf4316e954c7ad19e5780ab7a040ca6fb9271f90a8b22ae738daf6cb", + name: "nagydani_5_square", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf03e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + expected: "5f9c70ec884926a89461056ad20ac4c30155e817f807e4d3f5bb743d789c83386762435c3627773fa77da5144451f2a8aad8adba88e0b669f5377c5e9bad70e45c86fe952b613f015a9953b8a5de5eaee4566acf98d41e327d93a35bd5cef4607d025e58951167957df4ff9b1627649d3943805472e5e293d3efb687cfd1e503faafeb2840a3e3b3f85d016051a58e1c9498aab72e63b748d834b31eb05d85dcde65e27834e266b85c75cc4ec0135135e0601cb93eeeb6e0010c8ceb65c4c319623c5e573a2c8c9fbbf7df68a930beb412d3f4dfd146175484f45d7afaa0d2e60684af9b34730f7c8438465ad3e1d0c3237336722f2aa51095bd5759f4b8ab4dda111b684aa3dac62a761722e7ae43495b7709933512c81c4e3c9133a51f7ce9f2b51fcec064f65779666960b4e45df3900f54311f5613e8012dd1b8efd359eda31a778264c72aa8bb419d862734d769076bce2810011989a45374e5c5d8729fec21427f0bf397eacbb4220f603cf463a4b0c94efd858ffd9768cd60d6ce68d755e0fbad007ce5c2223d70c7018345a102e4ab3c60a13a9e7794303156d4c2063e919f2153c13961fb324c80b240742f47773a7a8e25b3e3fb19b00ce839346c6eb3c732fbc6b888df0b1fe0a3d07b053a2e9402c267b2d62f794d8a2840526e3ade15ce2264496ccd7519571dfde47f7a4bb16292241c20b2be59f3f8fb4f6383f232d838c5a22d8c95b6834d9d2ca493f5a505ebe8899503b0e8f9b19e6e2dd81c1628b80016d02097e0134de51054c4e7674824d4d758760fc52377d2cad145e259aa2ffaf54139e1a66b1e0c1c191e32ac59474c6b526f5b3ba07d3e5ec286eddf531fcd5292869be58c9f22ef91026159f7cf9d05ef66b4299f4da48cc1635bf2243051d342d378a22c83390553e873713c0454ce5f3234397111ac3fe3207b86f0ed9fc025c81903e1748103692074f83824fda6341be4f95ff00b0a9a208c267e12fa01825054cc0513629bf3dbb56dc5b90d4316f87654a8be18227978ea0a8a522760cad620d0d14fd38920fb7321314062914275a5f99f677145a6979b156bd82ecd36f23f8e1273cc2759ecc0b2c69d94dad5211d1bed939dd87ed9e07b91d49713a6e16ade0a98aea789f04994e318e4ff2c8a188cd8d43aeb52c6daa3bc29b4af50ea82a247c5cd67b573b34cbadcc0a376d3bbd530d50367b42705d870f2e27a8197ef46070528bfe408360faa2ebb8bf76e9f388572842bcb119f4d84ee34ae31f5cc594f23705a49197b181fb78ed1ec99499c690f843a4d0cf2e226d118e9372271054fbabdcc5c92ae9fefaef0589cd0e722eaf30c1703ec4289c7fd81beaa8a455ccee5298e31e2080c10c366a6fcf56f7d13582ad0bcad037c612b710fc595b70fbefaaca23623b60c6c39b11beb8e5843b6b3dac60f", + name: "nagydani_5_qube", + }, + Test { + input: "000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000400c5a1611f8be90071a43db23cc2fe01871cc4c0e8ab5743f6378e4fef77f7f6db0095c0727e20225beb665645403453e325ad5f9aeb9ba99bf3c148f63f9c07cf4fe8847ad5242d6b7d4499f93bd47056ddab8f7dee878fc2314f344dbee2a7c41a5d3db91eff372c730c2fdd3a141a4b61999e36d549b9870cf2f4e632c4d5df5f024f81c028000073a0ed8847cfb0593d36a47142f578f05ccbe28c0c06aeb1b1da027794c48db880278f79ba78ae64eedfea3c07d10e0562668d839749dc95f40467d15cf65b9cfc52c7c4bcef1cda3596dd52631aac942f146c7cebd46065131699ce8385b0db1874336747ee020a5698a3d1a1082665721e769567f579830f9d259cec1a836845109c21cf6b25da572512bf3c42fd4b96e43895589042ab60dd41f497db96aec102087fe784165bb45f942859268fd2ff6c012d9d00c02ba83eace047cc5f7b2c392c2955c58a49f0338d6fc58749c9db2155522ac17914ec216ad87f12e0ee95574613942fa615898c4d9e8a3be68cd6afa4e7a003dedbdf8edfee31162b174f965b20ae752ad89c967b3068b6f722c16b354456ba8e280f987c08e0a52d40a2e8f3a59b94d590aeef01879eb7a90b3ee7d772c839c85519cbeaddc0c193ec4874a463b53fcaea3271d80ebfb39b33489365fc039ae549a17a9ff898eea2f4cb27b8dbee4c17b998438575b2b8d107e4a0d66ba7fca85b41a58a8d51f191a35c856dfbe8aef2b00048a694bbccff832d23c8ca7a7ff0b6c0b3011d00b97c86c0628444d267c951d9e4fb8f83e154b8f74fb51aa16535e498235c5597dac9606ed0be3173a3836baa4e7d756ffe1e2879b415d3846bccd538c05b847785699aefde3e305decb600cd8fb0e7d8de5efc26971a6ad4e6d7a2d91474f1023a0ac4b78dc937da0ce607a45974d2cac1c33a2631ff7fe6144a3b2e5cf98b531a9627dea92c1dc82204d09db0439b6a11dd64b484e1263aa45fd9539b6020b55e3baece3986a8bffc1003406348f5c61265099ed43a766ee4f93f5f9c5abbc32a0fd3ac2b35b87f9ec26037d88275bd7dd0a54474995ee34ed3727f3f97c48db544b1980193a4b76a8a3ddab3591ce527f16d91882e67f0103b5cda53f7da54d489fc4ac08b6ab358a5a04aa9daa16219d50bd672a7cb804ed769d218807544e5993f1c27427104b349906a0b654df0bf69328afd3013fbe430155339c39f236df5557bf92f1ded7ff609a8502f49064ec3d1dbfb6c15d3a4c11a4f8acd12278cbf68acd5709463d12e3338a6eddb8c112f199645e23154a8e60879d2a654e3ed9296aa28f134168619691cd2c6b9e2eba4438381676173fc63c2588a3c5910dc149cf3760f0aa9fa9c3f5faa9162b0bf1aac9dd32b706a60ef53cbdb394b6b40222b5bc80eea82ba8958386672564cae3794f977871ab62337cf010001e30049201ec12937e7ce79d0f55d9c810e20acf52212aca1d3888949e0e4830aad88d804161230eb89d4d329cc83570fe257217d2119134048dd2ed167646975fc7d77136919a049ea74cf08ddd2b896890bb24a0ba18094a22baa351bf29ad96c66bbb1a598f2ca391749620e62d61c3561a7d3653ccc8892c7b99baaf76bf836e2991cb06d6bc0514568ff0d1ec8bb4b3d6984f5eaefb17d3ea2893722375d3ddb8e389a8eef7d7d198f8e687d6a513983df906099f9a2d23f4f9dec6f8ef2f11fc0a21fac45353b94e00486f5e17d386af42502d09db33cf0cf28310e049c07e88682aeeb00cb833c5174266e62407a57583f1f88b304b7c6e0c84bbe1c0fd423072d37a5bd0aacf764229e5c7cd02473460ba3645cd8e8ae144065bf02d0dd238593d8e230354f67e0b2f23012c23274f80e3ee31e35e2606a4a3f31d94ab755e6d163cff52cbb36b6d0cc67ffc512aeed1dce4d7a0d70ce82f2baba12e8d514dc92a056f994adfb17b5b9712bd5186f27a2fda1f7039c5df2c8587fdc62f5627580c13234b55be4df3056050e2d1ef3218f0dd66cb05265fe1acfb0989d8213f2c19d1735a7cf3fa65d88dad5af52dc2bba22b7abf46c3bc77b5091baab9e8f0ddc4d5e581037de91a9f8dcbc69309be29cc815cf19a20a7585b8b3073edf51fc9baeb3e509b97fa4ecfd621e0fd57bd61cac1b895c03248ff12bdbc57509250df3517e8a3fe1d776836b34ab352b973d932ef708b14f7418f9eceb1d87667e61e3e758649cb083f01b133d37ab2f5afa96d6c84bcacf4efc3851ad308c1e7d9113624fce29fab460ab9d2a48d92cdb281103a5250ad44cb2ff6e67ac670c02fdafb3e0f1353953d6d7d5646ca1568dea55275a050ec501b7c6250444f7219f1ba7521ba3b93d089727ca5f3bbe0d6c1300b423377004954c5628fdb65770b18ced5c9b23a4a5a6d6ef25fe01b4ce278de0bcc4ed86e28a0a68818ffa40970128cf2c38740e80037984428c1bd5113f40ff47512ee6f4e4d8f9b8e8e1b3040d2928d003bd1c1329dc885302fbce9fa81c23b4dc49c7c82d29b52957847898676c89aa5d32b5b0e1c0d5a2b79a19d67562f407f19425687971a957375879d90c5f57c857136c17106c9ab1b99d80e69c8c954ed386493368884b55c939b8d64d26f643e800c56f90c01079d7c534e3b2b7ae352cefd3016da55f6a85eb803b85e2304915fd2001f77c74e28746293c46e4f5f0fd49cf988aafd0026b8e7a3bab2da5cdce1ea26c2e29ec03f4807fac432662b2d6c060be1c7be0e5489de69d0a6e03a4b9117f9244b34a0f1ecba89884f781c6320412413a00c4980287409a2a78c2cd7e65cecebbe4ec1c28cac4dd95f6998e78fc6f1392384331c9436aa10e10e2bf8ad2c4eafbcf276aa7bae64b74428911b3269c749338b0fc5075ad", + expected: "5a0eb2bdf0ac1cae8e586689fa16cd4b07dfdedaec8a110ea1fdb059dd5253231b6132987598dfc6e11f86780428982d50cf68f67ae452622c3b336b537ef3298ca645e8f89ee39a26758206a5a3f6409afc709582f95274b57b71fae5c6b74619ae6f089a5393c5b79235d9caf699d23d88fb873f78379690ad8405e34c19f5257d596580c7a6a7206a3712825afe630c76b31cdb4a23e7f0632e10f14f4e282c81a66451a26f8df2a352b5b9f607a7198449d1b926e27036810368e691a74b91c61afa73d9d3b99453e7c8b50fd4f09c039a2f2feb5c419206694c31b92df1d9586140cb3417b38d0c503c7b508cc2ed12e813a1c795e9829eb39ee78eeaf360a169b491a1d4e419574e712402de9d48d54c1ae5e03739b7156615e8267e1fb0a897f067afd11fb33f6e24182d7aaaaa18fe5bc1982f20d6b871e5a398f0f6f718181d31ec225cfa9a0a70124ed9a70031bdf0c1c7829f708b6e17d50419ef361cf77d99c85f44607186c8d683106b8bd38a49b5d0fb503b397a83388c5678dcfcc737499d84512690701ed621a6f0172aecf037184ddf0f2453e4053024018e5ab2e30d6d5363b56e8b41509317c99042f517247474ab3abc848e00a07f69c254f46f2a05cf6ed84e5cc906a518fdcfdf2c61ce731f24c5264f1a25fc04934dc28aec112134dd523f70115074ca34e3807aa4cb925147f3a0ce152d323bd8c675ace446d0fd1ae30c4b57f0eb2c23884bc18f0964c0114796c5b6d080c3d89175665fbf63a6381a6a9da39ad070b645c8bb1779506da14439a9f5b5d481954764ea114fac688930bc68534d403cff4210673b6a6ff7ae416b7cd41404c3d3f282fcd193b86d0f54d0006c2a503b40d5c3930da980565b8f9630e9493a79d1c03e74e5f93ac8e4dc1a901ec5e3b3e57049124c7b72ea345aa359e782285d9e6a5c144a378111dd02c40855ff9c2be9b48425cb0b2fd62dc8678fd151121cf26a65e917d65d8e0dacfae108eb5508b601fb8ffa370be1f9a8b749a2d12eeab81f41079de87e2d777994fa4d28188c579ad327f9957fb7bdecec5c680844dd43cb57cf87aeb763c003e65011f73f8c63442df39a92b946a6bd968a1c1e4d5fa7d88476a68bd8e20e5b70a99259c7d3f85fb1b65cd2e93972e6264e74ebf289b8b6979b9b68a85cd5b360c1987f87235c3c845d62489e33acf85d53fa3561fe3a3aee18924588d9c6eba4edb7a4d106b31173e42929f6f0c48c80ce6a72d54eca7c0fe870068b7a7c89c63cdda593f5b32d3cb4ea8a32c39f00ab449155757172d66763ed9527019d6de6c9f2416aa6203f4d11c9ebee1e1d3845099e55504446448027212616167eb36035726daa7698b075286f5379cd3e93cb3e0cf4f9cb8d017facbb5550ed32d5ec5400ae57e47e2bf78d1eaeff9480cc765ceff39db500", + name: "nagydani_5_pow0x10001", + } + ]; + + const BYZANTIUM_GAS: [u64; 17] = [ + 13_056, 13_056, 204, 204, 3_276, 665, 665, 10_649, 1_894, 1_894, 30_310, 5_580, 5_580, + 89_292, 17_868, 17_868, 285_900, + ]; + + const BERLIN_GAS: [u64; 17] = [ + 1_360, 1_360, 200, 200, 341, 200, 200, 1_365, 341, 341, 5_461, 1_365, 1_365, 21_845, 5_461, + 5_461, 87_381, + ]; + + #[test] + fn test_modexp() { + for (test, test_gas) in TESTS.iter().zip(BYZANTIUM_GAS.iter()) { + let input = hex::decode(&test.input).unwrap(); + let mut state = new_state(); + + let res = ModExp::::run( + &input, + *test_gas, + &new_context(), + &mut state, + false, + ) + .unwrap() + .output; + let expected = hex::decode(&test.expected).unwrap(); + assert_eq!(res, expected, "{}", test.name); + } + } + + #[test] + fn test_byzantium_modexp_gas() { + for (test, test_gas) in TESTS.iter().zip(BYZANTIUM_GAS.iter()) { + let input = hex::decode(&test.input).unwrap(); + + let gas = ModExp::::required_gas(&input).unwrap(); + assert_eq!(gas, *test_gas, "{} gas", test.name); + } + } + + #[test] + fn test_berlin_modexp_gas() { + for (test, test_gas) in TESTS.iter().zip(BERLIN_GAS.iter()) { + let input = hex::decode(&test.input).unwrap(); + + let gas = ModExp::::required_gas(&input).unwrap(); + assert_eq!(gas, *test_gas, "{} gas", test.name); + } + } + + #[test] + fn test_berlin_modexp_big_input() { + let base_len = U256::from(4); + let exp_len = U256::from(u64::MAX); + let mod_len = U256::from(4); + let base: u32 = 1; + let exp = U256::MAX; + + let mut input: Vec = Vec::new(); + input.extend_from_slice(&crate::types::u256_to_arr(&base_len)); + input.extend_from_slice(&crate::types::u256_to_arr(&exp_len)); + input.extend_from_slice(&crate::types::u256_to_arr(&mod_len)); + input.extend_from_slice(&base.to_be_bytes()); + input.extend_from_slice(&crate::types::u256_to_arr(&exp)); + + // completes without any overflow + ModExp::::required_gas(&input).unwrap(); + } + + #[test] + fn test_berlin_modexp_bigger_input() { + let base_len = U256::MAX; + let exp_len = U256::MAX; + let mod_len = U256::MAX; + let base: u32 = 1; + let exp = U256::MAX; + + let mut input: Vec = Vec::new(); + input.extend_from_slice(&crate::types::u256_to_arr(&base_len)); + input.extend_from_slice(&crate::types::u256_to_arr(&exp_len)); + input.extend_from_slice(&crate::types::u256_to_arr(&mod_len)); + input.extend_from_slice(&base.to_be_bytes()); + input.extend_from_slice(&crate::types::u256_to_arr(&exp)); + + // completes without any overflow + ModExp::::required_gas(&input).unwrap(); + } + + #[test] + fn test_berlin_modexp_empty_input() { + let mut state = new_state(); + let res = ModExp::::run(&[], 100_000, &new_context(), &mut state, false) + .unwrap(); + let expected: Vec = Vec::new(); + assert_eq!(res.output, expected) } } diff --git a/src/precompiles/native.rs b/src/precompiles/native.rs index c5b0bfe54..9b3382eae 100644 --- a/src/precompiles/native.rs +++ b/src/precompiles/native.rs @@ -1,14 +1,22 @@ use evm::{Context, ExitError}; -use crate::parameters::{PromiseCreateArgs, WithdrawCallArgs}; -use crate::prelude::{is_valid_account_id, Cow, PhantomData, String, ToString, TryInto, U256}; -use crate::storage::{bytes_to_key, KeyPrefix}; -use crate::types::AccountId; +use crate::prelude::PhantomData; +#[cfg(not(feature = "contract"))] +use crate::prelude::Vec; use crate::AuroraState; -use borsh::BorshSerialize; +#[cfg(feature = "engine")] +use { + crate::parameters::PromiseCreateArgs, + crate::parameters::WithdrawCallArgs, + crate::prelude::{is_valid_account_id, Cow, String, ToString, TryInto, U256}, + crate::storage::{bytes_to_key, KeyPrefix}, + crate::types::AccountId, + borsh::BorshSerialize, +}; use super::{Precompile, PrecompileResult}; +#[cfg_attr(not(feature = "engine"), allow(dead_code))] const ERR_TARGET_TOKEN_NOT_FOUND: &str = "Target token not found"; use crate::precompiles::PrecompileOutput; @@ -23,9 +31,11 @@ mod costs { pub(super) const EXIT_TO_ETHEREUM_GAS: Gas = 0; // TODO(#51): Determine the correct amount of gas + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const FT_TRANSFER_GAS: Gas = 100_000_000_000_000; // TODO(#51): Determine the correct amount of gas + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const WITHDRAWAL_GAS: Gas = 100_000_000_000_000; } @@ -36,10 +46,12 @@ impl ExitToNear { /// /// Address: `0xe9217bc70b7ed1f598ddd3199e80b093fa71124f` /// This address is computed as: `&keccak("exitToNear")[12..]` + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const ADDRESS: [u8; 20] = super::make_address(0xe9217bc7, 0x0b7ed1f598ddd3199e80b093fa71124f); } +#[cfg(feature = "contract")] fn get_nep141_from_erc20(erc20_token: &[u8]) -> AccountId { AccountId::from_utf8( crate::sdk::read_storage(bytes_to_key(KeyPrefix::Erc20Nep141Map, erc20_token).as_slice()) @@ -53,11 +65,11 @@ impl Precompile for ExitToNear { Ok(costs::EXIT_TO_NEAR_GAS) } - #[cfg(not(feature = "exit-precompiles"))] + #[cfg(not(feature = "contract"))] fn run( input: &[u8], target_gas: u64, - context: &Context, + _context: &Context, _state: &mut S, _is_static: bool, ) -> PrecompileResult { @@ -66,33 +78,28 @@ impl Precompile for ExitToNear { } Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, output: Vec::new(), cost: 0, logs: Vec::new(), }) } - #[cfg(feature = "exit-precompiles")] + #[cfg(feature = "contract")] fn run( input: &[u8], target_gas: u64, context: &Context, state: &mut S, - _is_static: bool, + is_static: bool, ) -> PrecompileResult { if Self::required_gas(input)? > target_gas { return Err(ExitError::OutOfGas); } - // TODO(MarX): After calling directly function withdraw in Tester.sol - // This function is called with is_static = true - // Figure out if this needs to be fixed in EVM, or the way - // that is being used to determine if a function is called in static - // mode is incorrect. - // if is_static { - // return Err(ExitError::Other(Cow::from("ERR_INVALID_IN_STATIC"))); - // } + // It's not allowed to call exit precompiles in static mode + if is_static { + return Err(ExitError::Other(Cow::from("ERR_INVALID_IN_STATIC"))); + } // First byte of the input is a flag, selecting the behavior to be triggered: // 0x0 -> Eth transfer @@ -187,6 +194,7 @@ impl ExitToEthereum { /// /// Address: `0xb0bd02f6a392af548bdf1cfaee5dfa0eefcc8eab` /// This address is computed as: `&keccak("exitToEthereum")[12..]` + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const ADDRESS: [u8; 20] = super::make_address(0xb0bd02f6, 0xa392af548bdf1cfaee5dfa0eefcc8eab); } @@ -196,11 +204,11 @@ impl Precompile for ExitToEthereum { Ok(costs::EXIT_TO_ETHEREUM_GAS) } - #[cfg(not(feature = "exit-precompiles"))] + #[cfg(not(feature = "contract"))] fn run( input: &[u8], target_gas: u64, - context: &Context, + _context: &Context, _state: &mut S, _is_static: bool, ) -> PrecompileResult { @@ -209,33 +217,28 @@ impl Precompile for ExitToEthereum { } Ok(PrecompileOutput { - exit_status: ExitSucceed::Returned, output: Vec::new(), cost: 0, logs: Vec::new(), }) } - #[cfg(feature = "exit-precompiles")] + #[cfg(feature = "contract")] fn run( input: &[u8], target_gas: u64, context: &Context, state: &mut S, - _is_static: bool, + is_static: bool, ) -> PrecompileResult { if Self::required_gas(input)? > target_gas { return Err(ExitError::OutOfGas); } - // TODO(MarX): After calling directly function withdraw in Tester.sol - // This function is called with is_static = true - // Figure out if this needs to be fixed in EVM, or the way - // that is being used to determine if a function is called in static - // mode is incorrect. - // if is_static { - // return Err(ExitError::Other(Cow::from("ERR_INVALID_IN_STATIC"))); - // } + // It's not allowed to call exit precompiles in static mode + if is_static { + return Err(ExitError::Other(Cow::from("ERR_INVALID_IN_STATIC"))); + } // First byte of the input is a flag, selecting the behavior to be triggered: // 0x0 -> Eth transfer @@ -326,7 +329,7 @@ impl Precompile for ExitToEthereum { } } -#[cfg(test)] +#[cfg(all(feature = "contract", test))] mod tests { use super::{ExitToEthereum, ExitToNear}; use crate::types::near_account_to_evm_address; diff --git a/src/precompiles/secp256k1.rs b/src/precompiles/secp256k1.rs index f82f545ae..15b764883 100644 --- a/src/precompiles/secp256k1.rs +++ b/src/precompiles/secp256k1.rs @@ -44,6 +44,7 @@ pub fn ecrecover(hash: H256, signature: &[u8]) -> Result { pub(super) struct ECRecover(PhantomData); impl ECRecover { + #[cfg_attr(not(feature = "engine"), allow(dead_code))] pub(super) const ADDRESS: [u8; 20] = super::make_address(0, 1); } diff --git a/src/test_utils/exit_precompile.rs b/src/test_utils/exit_precompile.rs index 740c54b34..3892cefef 100644 --- a/src/test_utils/exit_precompile.rs +++ b/src/test_utils/exit_precompile.rs @@ -1,9 +1,9 @@ -use crate::parameters::{FunctionCallArgs, SubmitResult}; +use crate::parameters::SubmitResult; use crate::prelude::{Address, U256}; use crate::test_utils::{solidity, AuroraRunner, Signer}; use crate::transaction::EthTransaction; -use borsh::BorshSerialize; -use std::convert::TryInto; +#[cfg(feature = "engine")] +use {crate::parameters::FunctionCallArgs, borsh::BorshSerialize, std::convert::TryInto}; pub(crate) struct TesterConstructor(pub solidity::ContractConstructor); diff --git a/src/tests/contract_call.rs b/src/tests/contract_call.rs index 5e5515c55..02e8da91f 100644 --- a/src/tests/contract_call.rs +++ b/src/tests/contract_call.rs @@ -1,13 +1,16 @@ use crate::test_utils::{origin, AuroraRunner, Signer}; -use crate::prelude::U256; use crate::test_utils; use crate::test_utils::exit_precompile::{Tester, TesterConstructor}; -use crate::test_utils::solidity; -use crate::transaction::EthTransaction; -use ethabi::Address; -use near_crypto::SecretKey; -use std::path::{Path, PathBuf}; +#[cfg(feature = "engine")] +use { + crate::prelude::U256, + crate::test_utils::solidity, + crate::transaction::EthTransaction, + ethabi::Address, + near_crypto::SecretKey, + std::path::{Path, PathBuf}, +}; fn setup_test() -> (AuroraRunner, Signer, [u8; 20], Tester) { let mut runner = AuroraRunner::new(); @@ -37,7 +40,7 @@ fn setup_test() -> (AuroraRunner, Signer, [u8; 20], Tester) { #[test] fn hello_world_solidity() { - let (mut runner, mut signer, token, tester) = setup_test(); + let (mut runner, mut signer, _token, tester) = setup_test(); let name = "AuroraG".to_string(); let expected = format!("Hello {}!", name); @@ -48,7 +51,7 @@ fn hello_world_solidity() { #[test] fn withdraw() { - let (mut runner, mut signer, token, tester) = setup_test(); + let (mut runner, mut signer, _token, tester) = setup_test(); let test_data = vec![ (true, "Call contract: tt.testnet.ft_transfer"), @@ -64,7 +67,7 @@ fn withdraw() { #[test] fn withdraw_and_fail() { - let (mut runner, mut signer, token, tester) = setup_test(); + let (mut runner, mut signer, _token, tester) = setup_test(); let test_data = vec![ (true, "Call contract: tt.testnet.ft_transfer"), @@ -83,7 +86,7 @@ fn withdraw_and_fail() { #[test] fn try_withdraw_and_avoid_fail() { - let (mut runner, mut signer, token, tester) = setup_test(); + let (mut runner, mut signer, _token, tester) = setup_test(); let test_data = vec![ (true, "Call contract: tt.testnet.ft_transfer"), @@ -102,7 +105,7 @@ fn try_withdraw_and_avoid_fail() { #[test] fn try_withdraw_and_avoid_fail_and_succeed() { - let (mut runner, mut signer, token, tester) = setup_test(); + let (mut runner, mut signer, _token, tester) = setup_test(); let test_data = vec![ (true, "Call contract: tt.testnet.ft_transfer"), diff --git a/src/tests/erc20_connector.rs b/src/tests/erc20_connector.rs index 79e1c2d39..fbd89857e 100644 --- a/src/tests/erc20_connector.rs +++ b/src/tests/erc20_connector.rs @@ -1,9 +1,9 @@ -use crate::parameters::{FunctionCallArgs, NEP141FtOnTransferArgs, SubmitResult}; +use crate::parameters::{FunctionCallArgs, SubmitResult}; use crate::prelude::*; use crate::test_utils; use crate::test_utils::{create_eth_transaction, origin, AuroraRunner}; use crate::transaction::EthSignedTransaction; -use crate::types::{near_account_to_evm_address, AccountId, Balance, RawAddress, Wei}; +use crate::types::{AccountId, Balance, RawAddress, Wei}; use borsh::{BorshDeserialize, BorshSerialize}; use ethabi::Token; use near_vm_logic::VMOutcome; @@ -157,6 +157,7 @@ impl test_utils::AuroraRunner { result } + #[allow(dead_code)] pub fn admin(&mut self, token: RawAddress, origin: AccountId) -> CallResult { let input = build_input("admin()", &[]); let result = self.evm_call(token, input, origin); @@ -239,7 +240,7 @@ fn test_mint() { let balance = runner.balance_of(token, address, origin()); assert_eq!(balance, U256::from(0)); let amount = 10; - let result = runner.mint(token, address, amount, origin()); + let _result = runner.mint(token, address, amount, origin()); let balance = runner.balance_of(token, address, origin()); assert_eq!(balance, U256::from(amount)); } diff --git a/src/tests/sanity.rs b/src/tests/sanity.rs index 21de73a25..d376da3fe 100644 --- a/src/tests/sanity.rs +++ b/src/tests/sanity.rs @@ -188,13 +188,13 @@ fn initialize_transfer() -> (test_utils::AuroraRunner, SecretKey, Address) { (runner, source_account, dest_address) } -use sha3::{Digest, Keccak256}; +use sha3::Digest; #[test] fn check_selector() { - /// Selector to call mint function in ERC 20 contract - /// - /// keccak("mint(address,uint256)".as_bytes())[..4]; + // Selector to call mint function in ERC 20 contract + // + // keccak("mint(address,uint256)".as_bytes())[..4]; let mut hasher = sha3::Keccak256::default(); hasher.update(b"mint(address,uint256)"); assert_eq!(hasher.finalize()[..4].to_vec(), ERC20_MINT_SELECTOR); diff --git a/src/types.rs b/src/types.rs index addb2640b..bf165650b 100644 --- a/src/types.rs +++ b/src/types.rs @@ -33,6 +33,7 @@ pub type StorageUsage = u64; /// Selector to call mint function in ERC 20 contract /// /// keccak("mint(address,uint256)".as_bytes())[..4]; +#[allow(dead_code)] pub(crate) const ERC20_MINT_SELECTOR: &[u8] = &[64, 193, 15, 25]; pub type EventParams = Vec; @@ -71,7 +72,7 @@ impl EthEvent { /// Build log_entry_data from ethereum event #[cfg(not(feature = "contract"))] #[allow(dead_code)] - pub fn to_log_entry_data( + pub fn params_to_log_entry_data( name: &str, params: EventParams, locker_address: EthAddress, diff --git a/tests/test_meta_parsing.rs b/tests/test_meta_parsing.rs index 0552badc3..19f315ca8 100644 --- a/tests/test_meta_parsing.rs +++ b/tests/test_meta_parsing.rs @@ -1,12 +1,19 @@ -use borsh::BorshSerialize; +#[cfg(feature = "meta-call")] +use { + aurora_engine::meta_parsing::{near_erc712_domain, parse_meta_call, prepare_meta_call_args}, + aurora_engine::parameters::MetaCallArgs, + aurora_engine::prelude::U256, + aurora_engine::types::{u256_to_arr, InternalMetaCallArgs, Wei}, + borsh::BorshSerialize, + near_crypto::{InMemorySigner, KeyType, Signature, Signer}, +}; -use near_crypto::{InMemorySigner, KeyType, PublicKey, Signature, Signer}; +use near_crypto::PublicKey; -use aurora_engine::meta_parsing::{near_erc712_domain, parse_meta_call, prepare_meta_call_args}; -use aurora_engine::parameters::MetaCallArgs; -use aurora_engine::prelude::{Address, U256}; -use aurora_engine::types::{keccak, u256_to_arr, InternalMetaCallArgs, Wei}; +use aurora_engine::prelude::Address; +use aurora_engine::types::keccak; +#[cfg(feature = "meta-call")] pub fn encode_meta_call_function_args( signer: &dyn Signer, chain_id: u64, @@ -73,7 +80,7 @@ pub fn public_key_to_address(public_key: PublicKey) -> Address { } } -#[test] +#[cfg(all(feature = "meta-call", test))] fn test_meta_parsing() { let chain_id = 1313161555; let signer = InMemorySigner::from_seed("doesnt", KeyType::SECP256K1, "a");