diff --git a/client/rpc/src/eth/cache/mod.rs b/client/rpc/src/eth/cache/mod.rs index 8b237eed9f..40756a8ffd 100644 --- a/client/rpc/src/eth/cache/mod.rs +++ b/client/rpc/src/eth/cache/mod.rs @@ -467,7 +467,7 @@ where let base_fee = if let Some(base_fee) = handler.base_fee(&id) { base_fee } else { - client.runtime_api().gas_price(&id).unwrap_or(U256::zero()) + client.runtime_api().gas_price(&id).unwrap_or_else(|_|U256::zero()) }; let receipts = handler.current_receipts(&id); let mut result = FeeHistoryCacheItem { diff --git a/frame/base-fee/src/lib.rs b/frame/base-fee/src/lib.rs index 0b3292681f..0b08e4e092 100644 --- a/frame/base-fee/src/lib.rs +++ b/frame/base-fee/src/lib.rs @@ -178,7 +178,7 @@ pub mod pallet { // Normalize to GWEI. let increase = scaled_basefee .checked_div(U256::from(1_000_000)) - .unwrap_or(U256::zero()); + .unwrap_or_else(U256::zero); *bf = bf.saturating_add(increase); } else { Self::deposit_event(Event::BaseFeeOverflow); @@ -196,7 +196,7 @@ pub mod pallet { // Normalize to GWEI. let decrease = scaled_basefee .checked_div(U256::from(1_000_000)) - .unwrap_or(U256::zero()); + .unwrap_or_else(U256::zero); *bf = bf.saturating_sub(decrease); } else { Self::deposit_event(Event::BaseFeeOverflow); diff --git a/frame/ethereum/src/lib.rs b/frame/ethereum/src/lib.rs index ccef120ddc..a3ccf831d4 100644 --- a/frame/ethereum/src/lib.rs +++ b/frame/ethereum/src/lib.rs @@ -41,14 +41,14 @@ use frame_support::{ dispatch::DispatchResultWithPostInfo, scale_info::TypeInfo, traits::{EnsureOrigin, Get, PalletInfoAccess}, - weights::{Pays, PostDispatchInfo, Weight}, + weights::{DispatchInfo, Pays, PostDispatchInfo, Weight}, }; -use frame_system::{pallet_prelude::OriginFor, WeightInfo}; +use frame_system::{pallet_prelude::OriginFor, CheckWeight, WeightInfo}; use pallet_evm::{BlockHashMapping, FeeCalculator, GasWeightMapping, Runner}; use sha3::{Digest, Keccak256}; use sp_runtime::{ generic::DigestItem, - traits::{One, Saturating, UniqueSaturatedInto, Zero}, + traits::{DispatchInfoOf, Dispatchable, One, Saturating, UniqueSaturatedInto, Zero}, transaction_validity::{ InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransactionBuilder, }, @@ -108,9 +108,11 @@ impl> + From> EnsureOrigin } } -impl Call +impl Call where OriginFor: Into>>, + T: Send + Sync + Config, + T::Call: Dispatchable, { pub fn is_self_contained(&self) -> bool { matches!(self, Call::transact { .. }) @@ -146,8 +148,17 @@ where } } - pub fn validate_self_contained(&self, origin: &H160) -> Option { + pub fn validate_self_contained( + &self, + origin: &H160, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { if let Call::transact { transaction } = self { + if let Err(e) = CheckWeight::::do_validate(dispatch_info, len) { + return Some(Err(e)); + } + Some(Pallet::::validate_transaction_in_pool( *origin, transaction, diff --git a/frame/ethereum/src/mock.rs b/frame/ethereum/src/mock.rs index b25fd6001b..bb1ddcbc62 100644 --- a/frame/ethereum/src/mock.rs +++ b/frame/ethereum/src/mock.rs @@ -192,9 +192,14 @@ impl fp_self_contained::SelfContainedCall for Call { } } - fn validate_self_contained(&self, info: &Self::SignedInfo) -> Option { + fn validate_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { match self { - Call::Ethereum(call) => call.validate_self_contained(info), + Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), _ => None, } } diff --git a/frame/ethereum/src/tests/eip1559.rs b/frame/ethereum/src/tests/eip1559.rs index 8699f1247f..474c5a4c70 100644 --- a/frame/ethereum/src/tests/eip1559.rs +++ b/frame/ethereum/src/tests/eip1559.rs @@ -61,9 +61,14 @@ fn transaction_without_enough_gas_should_not_work() { let call = crate::Call::::transact { transaction }; let source = call.check_self_contained().unwrap().unwrap(); - + let extrinsic = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call.clone()), + }; + let dispatch_info = extrinsic.get_dispatch_info(); assert_err!( - call.validate_self_contained(&source).unwrap(), + call.validate_self_contained(&source, &dispatch_info, 0) + .unwrap(), InvalidTransaction::Payment ); }); @@ -83,9 +88,15 @@ fn transaction_with_to_low_nonce_should_not_work() { transaction: signed, }; let source = call.check_self_contained().unwrap().unwrap(); + let extrinsic = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call.clone()), + }; + let dispatch_info = extrinsic.get_dispatch_info(); assert_eq!( - call.validate_self_contained(&source).unwrap(), + call.validate_self_contained(&source, &dispatch_info, 0) + .unwrap(), ValidTransactionBuilder::default() .and_provides((alice.address, U256::from(1))) .priority(0u64) @@ -97,7 +108,6 @@ fn transaction_with_to_low_nonce_should_not_work() { // nonce is 1 assert_ok!(Ethereum::execute(alice.address, &t, None,)); - transaction.nonce = U256::from(0); let signed2 = transaction.sign(&alice.private_key, None); @@ -105,9 +115,15 @@ fn transaction_with_to_low_nonce_should_not_work() { transaction: signed2, }; let source2 = call2.check_self_contained().unwrap().unwrap(); + let extrinsic2 = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call2.clone()), + }; assert_err!( - call2.validate_self_contained(&source2).unwrap(), + call2 + .validate_self_contained(&source2, &extrinsic2.get_dispatch_info(), 0) + .unwrap(), InvalidTransaction::Stale ); }); @@ -127,11 +143,10 @@ fn transaction_with_to_hight_nonce_should_fail_in_block() { transaction: signed, }; let source = call.check_self_contained().unwrap().unwrap(); - let extrinsic = fp_self_contained::CheckedExtrinsic::<_, _, SignedExtra, _> { + let extrinsic = CheckedExtrinsic::<_, _, SignedExtra, _> { signed: fp_self_contained::CheckedSignature::SelfContained(source), function: Call::Ethereum(call), }; - use frame_support::weights::GetDispatchInfo as _; let dispatch_info = extrinsic.get_dispatch_info(); assert_err!( extrinsic.apply::(&dispatch_info, 0), @@ -151,11 +166,10 @@ fn transaction_with_invalid_chain_id_should_fail_in_block() { let call = crate::Call::::transact { transaction }; let source = call.check_self_contained().unwrap().unwrap(); - let extrinsic = fp_self_contained::CheckedExtrinsic::<_, _, SignedExtra, _> { + let extrinsic = CheckedExtrinsic::<_, _, SignedExtra, _> { signed: fp_self_contained::CheckedSignature::SelfContained(source), function: Call::Ethereum(call), }; - use frame_support::weights::GetDispatchInfo as _; let dispatch_info = extrinsic.get_dispatch_info(); assert_err!( extrinsic.apply::(&dispatch_info, 0), diff --git a/frame/ethereum/src/tests/eip2930.rs b/frame/ethereum/src/tests/eip2930.rs index 4f78d07ca5..f4524b0b72 100644 --- a/frame/ethereum/src/tests/eip2930.rs +++ b/frame/ethereum/src/tests/eip2930.rs @@ -60,9 +60,15 @@ fn transaction_without_enough_gas_should_not_work() { let call = crate::Call::::transact { transaction }; let source = call.check_self_contained().unwrap().unwrap(); + let extrinsic = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call.clone()), + }; + let dispatch_info = extrinsic.get_dispatch_info(); assert_err!( - call.validate_self_contained(&source).unwrap(), + call.validate_self_contained(&source, &dispatch_info, 0) + .unwrap(), InvalidTransaction::Payment ); }); @@ -83,9 +89,15 @@ fn transaction_with_to_low_nonce_should_not_work() { transaction: signed, }; let source = call.check_self_contained().unwrap().unwrap(); + let extrinsic = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call.clone()), + }; + let dispatch_info = extrinsic.get_dispatch_info(); assert_eq!( - call.validate_self_contained(&source).unwrap(), + call.validate_self_contained(&source, &dispatch_info, 0) + .unwrap(), ValidTransactionBuilder::default() .and_provides((alice.address, U256::from(1))) .priority(0u64) @@ -105,9 +117,15 @@ fn transaction_with_to_low_nonce_should_not_work() { transaction: signed2, }; let source2 = call2.check_self_contained().unwrap().unwrap(); + let extrinsic2 = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call2.clone()), + }; assert_err!( - call2.validate_self_contained(&source2).unwrap(), + call2 + .validate_self_contained(&source2, &extrinsic2.get_dispatch_info(), 0) + .unwrap(), InvalidTransaction::Stale ); }); diff --git a/frame/ethereum/src/tests/legacy.rs b/frame/ethereum/src/tests/legacy.rs index b95ed412d5..0ce6adca47 100644 --- a/frame/ethereum/src/tests/legacy.rs +++ b/frame/ethereum/src/tests/legacy.rs @@ -60,9 +60,15 @@ fn transaction_without_enough_gas_should_not_work() { let call = crate::Call::::transact { transaction }; let source = call.check_self_contained().unwrap().unwrap(); + let extrinsic = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call.clone()), + }; + let dispatch_info = extrinsic.get_dispatch_info(); assert_err!( - call.validate_self_contained(&source).unwrap(), + call.validate_self_contained(&source, &dispatch_info, 0) + .unwrap(), InvalidTransaction::Payment ); }); @@ -83,9 +89,15 @@ fn transaction_with_to_low_nonce_should_not_work() { transaction: signed, }; let source = call.check_self_contained().unwrap().unwrap(); + let extrinsic = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call.clone()), + }; + let dispatch_info = extrinsic.get_dispatch_info(); assert_eq!( - call.validate_self_contained(&source).unwrap(), + call.validate_self_contained(&source, &dispatch_info, 0) + .unwrap(), ValidTransactionBuilder::default() .and_provides((alice.address, U256::from(1))) .priority(0u64) @@ -105,9 +117,15 @@ fn transaction_with_to_low_nonce_should_not_work() { transaction: signed2, }; let source2 = call2.check_self_contained().unwrap().unwrap(); + let extrinsic2 = CheckedExtrinsic:: { + signed: fp_self_contained::CheckedSignature::SelfContained(source), + function: Call::Ethereum(call2.clone()), + }; assert_err!( - call2.validate_self_contained(&source2).unwrap(), + call2 + .validate_self_contained(&source2, &extrinsic2.get_dispatch_info(), 0) + .unwrap(), InvalidTransaction::Stale ); }); diff --git a/frame/ethereum/src/tests/mod.rs b/frame/ethereum/src/tests/mod.rs index 3e3c62e017..bd40176949 100644 --- a/frame/ethereum/src/tests/mod.rs +++ b/frame/ethereum/src/tests/mod.rs @@ -15,7 +15,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use frame_support::{assert_err, assert_ok, unsigned::TransactionValidityError}; +use frame_support::{ + assert_err, assert_ok, unsigned::TransactionValidityError, weights::GetDispatchInfo, +}; use rustc_hex::{FromHex, ToHex}; use sp_runtime::{ traits::Applyable, @@ -26,6 +28,7 @@ use std::str::FromStr; use crate::{ mock::*, CallOrCreateInfo, RawOrigin, Transaction, TransactionAction, H160, H256, U256, }; +use fp_self_contained::CheckedExtrinsic; mod eip1559; mod eip2930; diff --git a/primitives/self-contained/src/checked_extrinsic.rs b/primitives/self-contained/src/checked_extrinsic.rs index f7376c82ec..d5f1bb42cf 100644 --- a/primitives/self-contained/src/checked_extrinsic.rs +++ b/primitives/self-contained/src/checked_extrinsic.rs @@ -87,11 +87,12 @@ where let unsigned_validation = U::validate_unsigned(source, &self.function)?; Ok(valid.combine_with(unsigned_validation)) } - CheckedSignature::SelfContained(signed_info) => { - self.function.validate_self_contained(signed_info).ok_or( - TransactionValidityError::Invalid(InvalidTransaction::BadProof), - )? - } + CheckedSignature::SelfContained(signed_info) => self + .function + .validate_self_contained(signed_info, info, len) + .ok_or(TransactionValidityError::Invalid( + InvalidTransaction::BadProof, + ))?, } } diff --git a/primitives/self-contained/src/lib.rs b/primitives/self-contained/src/lib.rs index 92d9154c9c..01dc8997ca 100644 --- a/primitives/self-contained/src/lib.rs +++ b/primitives/self-contained/src/lib.rs @@ -26,7 +26,7 @@ pub use crate::{ }; use sp_runtime::{ - traits::{Dispatchable, PostDispatchInfoOf}, + traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf}, transaction_validity::{TransactionValidity, TransactionValidityError}, }; @@ -43,7 +43,12 @@ pub trait SelfContainedCall: Dispatchable { fn check_self_contained(&self) -> Option>; /// Validate a self-contained function. Returns `None` if the /// function is not a self-contained. - fn validate_self_contained(&self, info: &Self::SignedInfo) -> Option; + fn validate_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option; /// Do any pre-flight stuff for a self-contained call. /// /// Note this function by default delegates to `validate_self_contained`, so that diff --git a/template/examples/contract-erc20/create-erc20-rpc.ts b/template/examples/contract-erc20/create-erc20-rpc.ts index 92d18747f2..8a383a5fe5 100755 --- a/template/examples/contract-erc20/create-erc20-rpc.ts +++ b/template/examples/contract-erc20/create-erc20-rpc.ts @@ -1,7 +1,7 @@ import Web3 from "web3"; import * as web3Utils from 'web3-utils'; -const web3 = new Web3("http://localhost:9933"); +const web3 = new Web3("http://127.0.0.1:9933"); const ERC20_BYTECODE = require("./truffle/contracts/MyToken.json").bytecode; const STORAGE_SLOT = "0"; diff --git a/template/examples/contract-erc20/create-erc20.ts b/template/examples/contract-erc20/create-erc20.ts index 577a9b0cc4..1f79e3d697 100644 --- a/template/examples/contract-erc20/create-erc20.ts +++ b/template/examples/contract-erc20/create-erc20.ts @@ -4,8 +4,8 @@ import { U8aFixed } from '@polkadot/types/codec'; import * as web3Utils from 'web3-utils'; import * as crypto from '@polkadot/util-crypto'; -// Provider is set to localhost for development -const wsProvider = new WsProvider("ws://localhost:9944"); +// Provider is set to 127.0.0.1 for development +const wsProvider = new WsProvider("ws://127.0.0.1:9944"); // Keyring needed to sign using Alice account const keyring = new Keyring({ type: 'sr25519' }); diff --git a/template/examples/contract-hello/index.js b/template/examples/contract-hello/index.js index d0e75b39bf..4983f7d274 100644 --- a/template/examples/contract-hello/index.js +++ b/template/examples/contract-hello/index.js @@ -1,5 +1,5 @@ const Web3 = require('web3'); -const web3 = new Web3('http://localhost:8545'); +const web3 = new Web3('http://127.0.0.1:8545'); const ABI = [{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"Said","type":"event"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]; const BYTECODE = "0x608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055507fc68045c3c562488255b55aa2c4c7849de001859ff0d8a36a75c2d5ed80100fb660405180806020018281038252600d8152602001807f48656c6c6f2c20776f726c64210000000000000000000000000000000000000081525060200191505060405180910390a160cf806100c76000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80638da5cb5b14602d575b600080fd5b60336075565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff168156fea265627a7a72315820fae816ad954005c42bea7bc7cb5b19f7fd5d3a250715ca2023275c9ca7ce644064736f6c634300050f0032"; diff --git a/template/runtime/src/lib.rs b/template/runtime/src/lib.rs index 940dad5566..4413854ccc 100644 --- a/template/runtime/src/lib.rs +++ b/template/runtime/src/lib.rs @@ -23,8 +23,8 @@ use sp_core::{ use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{ - AccountIdLookup, BlakeTwo256, Block as BlockT, Dispatchable, IdentifyAccount, NumberFor, - PostDispatchInfoOf, Verify, + AccountIdLookup, BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, + IdentifyAccount, NumberFor, PostDispatchInfoOf, Verify, }, transaction_validity::{TransactionSource, TransactionValidity, TransactionValidityError}, ApplyExtrinsicResult, MultiSignature, @@ -53,7 +53,9 @@ use frame_support::weights::constants::RocksDbWeight as RuntimeDbWeight; pub use pallet_balances::Call as BalancesCall; use pallet_ethereum::{Call::transact, Transaction as EthereumTransaction}; -use pallet_evm::{Account as EVMAccount, EnsureAddressTruncated, HashedAddressMapping, Runner}; +use pallet_evm::{ + Account as EVMAccount, EnsureAddressTruncated, GasWeightMapping, HashedAddressMapping, Runner, +}; pub use pallet_timestamp::Call as TimestampCall; use pallet_transaction_payment::CurrencyAdapter; #[cfg(any(feature = "std", test))] @@ -143,13 +145,15 @@ pub fn native_version() -> NativeVersion { } const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75); +/// We allow for 2 seconds of compute with a 6 second average block time. +pub const MAXIMUM_BLOCK_WEIGHT: Weight = 2 * WEIGHT_PER_SECOND; +const WEIGHT_PER_GAS: u64 = 20_000; parameter_types! { pub const Version: RuntimeVersion = VERSION; pub const BlockHashCount: BlockNumber = 256; - /// We allow for 2 seconds of compute with a 6 second average block time. pub BlockWeights: frame_system::limits::BlockWeights = frame_system::limits::BlockWeights - ::with_sensible_defaults(2 * WEIGHT_PER_SECOND, NORMAL_DISPATCH_RATIO); + ::with_sensible_defaults(MAXIMUM_BLOCK_WEIGHT, NORMAL_DISPATCH_RATIO); pub BlockLength: frame_system::limits::BlockLength = frame_system::limits::BlockLength ::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO); pub const SS58Prefix: u8 = 42; @@ -306,15 +310,25 @@ impl> FindAuthor for FindAuthorTruncated { } } +pub struct FixedGasWeightMapping; +impl GasWeightMapping for FixedGasWeightMapping { + fn gas_to_weight(gas: u64) -> Weight { + gas.saturating_mul(WEIGHT_PER_GAS) + } + fn weight_to_gas(weight: Weight) -> u64 { + weight.wrapping_div(WEIGHT_PER_GAS) + } +} + parameter_types! { pub const ChainId: u64 = 42; - pub BlockGasLimit: U256 = U256::from(u32::max_value()); + pub BlockGasLimit: U256 = U256::from(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT / WEIGHT_PER_GAS); pub PrecompilesValue: FrontierPrecompiles = FrontierPrecompiles::<_>::new(); } impl pallet_evm::Config for Runtime { type FeeCalculator = BaseFee; - type GasWeightMapping = (); + type GasWeightMapping = FixedGasWeightMapping; type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping; type CallOrigin = EnsureAddressTruncated; type WithdrawOrigin = EnsureAddressTruncated; @@ -470,9 +484,14 @@ impl fp_self_contained::SelfContainedCall for Call { } } - fn validate_self_contained(&self, info: &Self::SignedInfo) -> Option { + fn validate_self_contained( + &self, + info: &Self::SignedInfo, + dispatch_info: &DispatchInfoOf, + len: usize, + ) -> Option { match self { - Call::Ethereum(call) => call.validate_self_contained(info), + Call::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len), _ => None, } } diff --git a/ts-tests/tests/test-block.ts b/ts-tests/tests/test-block.ts index 5e1c5bbf76..71028e18d4 100644 --- a/ts-tests/tests/test-block.ts +++ b/ts-tests/tests/test-block.ts @@ -21,7 +21,7 @@ describeWithFrontier("Frontier RPC (Block)", (context) => { author: "0x0000000000000000000000000000000000000000", difficulty: "0", extraData: "0x", - gasLimit: 4294967295, + gasLimit: 75000000, gasUsed: 0, logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -76,7 +76,7 @@ describeWithFrontier("Frontier RPC (Block)", (context) => { author: "0x0000000000000000000000000000000000000000", difficulty: "0", extraData: "0x", - gasLimit: 4294967295, + gasLimit: 75000000, gasUsed: 0, logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", @@ -105,7 +105,7 @@ describeWithFrontier("Frontier RPC (Block)", (context) => { author: "0x0000000000000000000000000000000000000000", difficulty: "0", extraData: "0x", - gasLimit: 4294967295, + gasLimit: 75000000, gasUsed: 0, //hash: "0x14fe6f7c93597f79b901f8b5d7a84277a90915b8d355959b587e18de34f1dc17", logsBloom: diff --git a/ts-tests/tests/test-contract-methods.ts b/ts-tests/tests/test-contract-methods.ts index 861a3ee875..a867f0b878 100644 --- a/ts-tests/tests/test-contract-methods.ts +++ b/ts-tests/tests/test-contract-methods.ts @@ -84,7 +84,7 @@ describeWithFrontier("Frontier RPC (Contract Methods)", (context) => { gasPrice: "0x3B9ACA00", }); // Max u32 - expect(await contract.methods.gasLimit().call()).to.eq('4294967295'); + expect(await contract.methods.gasLimit().call()).to.eq('75000000'); }); // Requires error handling diff --git a/ts-tests/tests/test-gas.ts b/ts-tests/tests/test-gas.ts index d5b2e90b67..f2400acbc9 100644 --- a/ts-tests/tests/test-gas.ts +++ b/ts-tests/tests/test-gas.ts @@ -35,11 +35,15 @@ function estimation_variance(binary_search_estimation, one_off_estimation) { describeWithFrontier("Frontier RPC (Gas)", (context) => { const GENESIS_ACCOUNT = "0x6be02d1d3665660d22ff9624b7be0551ee1ac91b"; + const GENESIS_ACCOUNT_PRIVATE_KEY = "0x99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342"; const TEST_CONTRACT_BYTECODE = Test.bytecode; const TEST_CONTRACT_ABI = Test.abi as AbiItem[]; const FIRST_CONTRACT_ADDRESS = "0xc2bf5f29a4384b1ab0c063e1c666f02121b6084a"; // Those test are ordered. In general this should be avoided, but due to the time it takes // to spin up a frontier node, it saves a lot of time. + // EXTRINSIC_GAS_LIMIT = [BLOCK_GAS_LIMIT - BLOCK_GAS_LIMIT * (NORMAL_DISPATCH_RATIO - AVERAGE_ON_INITIALIZE_RATIO) - EXTRINSIC_BASE_Weight] / WEIGHT_PER_GAS = (1_000_000_000_000 * 2 * (0.75-0.1) - 125_000_000) / 20000 + const EXTRINSIC_GAS_LIMIT = 64993750; + it("eth_estimateGas for contract creation", async function () { // The value returned as an estimation by the evm with estimate mode ON. let one_off_estimation = 196657; @@ -141,4 +145,52 @@ describeWithFrontier("Frontier RPC (Gas)", (context) => { })); expect(result).to.equal(197690); }); + + it("tx gas limit below EXTRINSIC_GAS_LIMIT", async function () { + const tx = await context.web3.eth.accounts.signTransaction( + { + from: GENESIS_ACCOUNT, + data: Test.bytecode, + gas: EXTRINSIC_GAS_LIMIT - 1, + gasPrice: "0x3B9ACA00", + }, + GENESIS_ACCOUNT_PRIVATE_KEY + ); + const createReceipt = await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]); + await createAndFinalizeBlock(context.web3); + expect((createReceipt as any).transactionHash).to.be.not.null; + expect((createReceipt as any).blockHash).to.be.not.null; + + }); + it("tx gas limit equal EXTRINSIC_GAS_LIMIT", async function () { + const tx = await context.web3.eth.accounts.signTransaction( + { + from: GENESIS_ACCOUNT, + data: Test.bytecode, + gas: EXTRINSIC_GAS_LIMIT, + gasPrice: "0x3B9ACA00", + }, + GENESIS_ACCOUNT_PRIVATE_KEY + ); + const createReceipt = await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]); + await createAndFinalizeBlock(context.web3); + expect((createReceipt as any).transactionHash).to.be.not.null; + expect((createReceipt as any).blockHash).to.be.not.null; + }); + it("tx gas limit larger EXTRINSIC_GAS_LIMIT", async function () { + const tx = await context.web3.eth.accounts.signTransaction( + { + from: GENESIS_ACCOUNT, + data: Test.bytecode, + gas: EXTRINSIC_GAS_LIMIT + 1, + gasPrice: "0x3B9ACA00", + }, + GENESIS_ACCOUNT_PRIVATE_KEY + ); + const createReceipt = await customRequest(context.web3, "eth_sendRawTransaction", [tx.rawTransaction]); + await createAndFinalizeBlock(context.web3); + expect((createReceipt as any).error.message).to.equal( + "submit transaction to pool failed: Pool(InvalidTransaction(InvalidTransaction::ExhaustsResources))" + ); + }); }); diff --git a/ts-tests/tests/util.ts b/ts-tests/tests/util.ts index 6ebcd85163..821b92eb81 100644 --- a/ts-tests/tests/util.ts +++ b/ts-tests/tests/util.ts @@ -59,7 +59,7 @@ export async function createAndFinalizeBlockNowait(web3: Web3) { export async function startFrontierNode(provider?: string): Promise<{ web3: Web3; binary: ChildProcess, ethersjs: ethers.providers.JsonRpcProvider }> { var web3; if (!provider || provider == 'http') { - web3 = new Web3(`http://localhost:${RPC_PORT}`); + web3 = new Web3(`http://127.0.0.1:${RPC_PORT}`); } const cmd = BINARY_PATH; @@ -126,10 +126,10 @@ export async function startFrontierNode(provider?: string): Promise<{ web3: Web3 }); if (provider == 'ws') { - web3 = new Web3(`ws://localhost:${WS_PORT}`); + web3 = new Web3(`ws://127.0.0.1:${WS_PORT}`); } - let ethersjs = new ethers.providers.StaticJsonRpcProvider(`http://localhost:${RPC_PORT}`, { + let ethersjs = new ethers.providers.StaticJsonRpcProvider(`http://127.0.0.1:${RPC_PORT}`, { chainId: 42, name: "frontier-dev", });