Repository: moonbeam-foundation/moonbeam
Pull request #3279: Use pallet_ethereum to calculate proof_size_base_cost
Author: login: TarekkMA
Labels: name: B7-runtimenoteworthy
description: Changes should be noted in any runtime-upgrade release notes
name: D5-nicetohaveaudit⚠️
description: PR contains trivial changes to logic that should be properly reviewed.
name: not-breaking
description: Does not need to be mentioned in breaking changes
Created: 2025-05-06T09:27:13Z | Merged: 2025-05-13T09:50:49Z

Use `pallet_ethereum`'s `TransactionData` struct and `transaction_weight(...)` function to calculate `proof_size_base_cost` instead of using hardcoded numbers. 

- Update tests to reflect slight change in gas cost


Diff:
diff --git a/Cargo.lock b/Cargo.lock
index c53107f4883..36c25dfaa6c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -6936,6 +6936,7 @@ dependencies = [
  "pallet-collective",
  "pallet-conviction-voting",
  "pallet-crowdloan-rewards",
+ "pallet-ethereum",
  "pallet-ethereum-xcm",
  "pallet-evm",
  "pallet-evm-chain-id",
diff --git a/runtime/common/Cargo.toml b/runtime/common/Cargo.toml
index d3c3027be3a..f8b5da2ab11 100644
--- a/runtime/common/Cargo.toml
+++ b/runtime/common/Cargo.toml
@@ -19,6 +19,7 @@ pallet-asset-manager = { workspace = true }
 pallet-author-mapping = { workspace = true }
 pallet-conviction-voting = { workspace = true }
 pallet-ethereum-xcm = { workspace = true }
+pallet-ethereum = { workspace = true, features = ["forbid-evm-reentrancy"] }
 pallet-migrations = { workspace = true }
 pallet-moonbeam-foreign-assets = { workspace = true }
 pallet-moonbeam-lazy-migrations = { workspace = true }
@@ -105,6 +106,7 @@ std = [
 	"pallet-author-inherent/std",
 	"pallet-author-mapping/std",
 	"pallet-ethereum-xcm/std",
+	"pallet-ethereum/std",
 	"pallet-evm/std",
 	"pallet-migrations/std",
 	"pallet-parachain-staking/std",
@@ -147,6 +149,7 @@ runtime-benchmarks = [
 	"pallet-conviction-voting/runtime-benchmarks",
 	"pallet-crowdloan-rewards/runtime-benchmarks",
 	"pallet-ethereum-xcm/runtime-benchmarks",
+	"pallet-ethereum/runtime-benchmarks",
 	"pallet-evm/runtime-benchmarks",
 	"pallet-identity/runtime-benchmarks",
 	"pallet-moonbeam-orbiters/runtime-benchmarks",
diff --git a/runtime/common/src/apis.rs b/runtime/common/src/apis.rs
index fc8c8636896..2208cc81f97 100644
--- a/runtime/common/src/apis.rs
+++ b/runtime/common/src/apis.rs
@@ -337,43 +337,23 @@ macro_rules! impl_runtime_apis_plus_common {
 						EvmTracer::new().trace(|| {
 							let is_transactional = false;
 							let validate = true;
-							let without_base_extrinsic_weight = true;
-
-
-							// Estimated encoded transaction size must be based on the heaviest transaction
-							// type (EIP1559Transaction) to be compatible with all transaction types.
-							// TODO: remove, since we will get rid of base_cost
-							let mut estimated_transaction_len = data.len() +
-								// pallet ethereum index: 1
-								// transact call index: 1
-								// Transaction enum variant: 1
-								// chain_id 8 bytes
-								// nonce: 32
-								// max_priority_fee_per_gas: 32
-								// max_fee_per_gas: 32
-								// gas_limit: 32
-								// action: 21 (enum varianrt + call address)
-								// value: 32
-								// access_list: 1 (empty vec size)
-								// 65 bytes signature
-								258;
-
-							if access_list.is_some() {
-								estimated_transaction_len += access_list.encoded_size();
-							}
+
+							let transaction_data = pallet_ethereum::TransactionData::new(
+								pallet_ethereum::TransactionAction::Call(to),
+								data.clone(),
+								nonce.unwrap_or_default(),
+								gas_limit,
+								None,
+								max_fee_per_gas.or(Some(U256::default())),
+								max_priority_fee_per_gas.or(Some(U256::default())),
+								value,
+								Some(<Runtime as pallet_evm::Config>::ChainId::get()),
+								access_list.clone().unwrap_or_default(),
+							);
 
 							let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
 
-							let (weight_limit, proof_size_base_cost) =
-								match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
-									gas_limit,
-									without_base_extrinsic_weight
-								) {
-									weight_limit if weight_limit.proof_size() > 0 => {
-										(Some(weight_limit), Some(estimated_transaction_len as u64))
-									}
-									_ => (None, None),
-								};
+							let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
 
 							let _ = <Runtime as pallet_evm::Config>::Runner::call(
 								from,
@@ -476,41 +456,22 @@ macro_rules! impl_runtime_apis_plus_common {
 					let is_transactional = false;
 					let validate = true;
 
-							// Estimated encoded transaction size must be based on the heaviest transaction
-							// type (EIP1559Transaction) to be compatible with all transaction types.
-					// TODO: remove, since we will get rid of base_cost
-					let mut estimated_transaction_len = data.len() +
-						// pallet ethereum index: 1
-						// transact call index: 1
-						// Transaction enum variant: 1
-						// chain_id 8 bytes
-						// nonce: 32
-						// max_priority_fee_per_gas: 32
-						// max_fee_per_gas: 32
-						// gas_limit: 32
-						// action: 21 (enum varianrt + call address)
-						// value: 32
-						// access_list: 1 (empty vec size)
-						// 65 bytes signature
-						258;
-
-					if access_list.is_some() {
-						estimated_transaction_len += access_list.encoded_size();
-					}
+					let transaction_data = pallet_ethereum::TransactionData::new(
+						pallet_ethereum::TransactionAction::Call(to),
+						data.clone(),
+						nonce.unwrap_or_default(),
+						gas_limit,
+						None,
+						max_fee_per_gas.or(Some(U256::default())),
+						max_priority_fee_per_gas.or(Some(U256::default())),
+						value,
+						Some(<Runtime as pallet_evm::Config>::ChainId::get()),
+						access_list.clone().unwrap_or_default(),
+					);
 
 					let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
-					let without_base_extrinsic_weight = true;
 
-					let (weight_limit, proof_size_base_cost) =
-						match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
-							gas_limit,
-							without_base_extrinsic_weight
-						) {
-							weight_limit if weight_limit.proof_size() > 0 => {
-								(Some(weight_limit), Some(estimated_transaction_len as u64))
-							}
-							_ => (None, None),
-						};
+					let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
 
 					<Runtime as pallet_evm::Config>::Runner::call(
 						from,
@@ -551,43 +512,22 @@ macro_rules! impl_runtime_apis_plus_common {
 					let is_transactional = false;
 					let validate = true;
 
-					let mut estimated_transaction_len = data.len() +
-						// from: 20
-						// value: 32
-						// gas_limit: 32
-						// nonce: 32
-						// 1 byte transaction action variant
-						// chain id 8 bytes
-						// 65 bytes signature
-						190;
-
-					if max_fee_per_gas.is_some() {
-						estimated_transaction_len += 32;
-					}
-					if max_priority_fee_per_gas.is_some() {
-						estimated_transaction_len += 32;
-					}
-					if access_list.is_some() {
-						estimated_transaction_len += access_list.encoded_size();
-					}
+					let transaction_data = pallet_ethereum::TransactionData::new(
+						pallet_ethereum::TransactionAction::Create,
+						data.clone(),
+						nonce.unwrap_or_default(),
+						gas_limit,
+						None,
+						max_fee_per_gas.or(Some(U256::default())),
+						max_priority_fee_per_gas.or(Some(U256::default())),
+						value,
+						Some(<Runtime as pallet_evm::Config>::ChainId::get()),
+						access_list.clone().unwrap_or_default(),
+					);
 
-					let gas_limit = if gas_limit > U256::from(u64::MAX) {
-						u64::MAX
-					} else {
-						gas_limit.low_u64()
-					};
-					let without_base_extrinsic_weight = true;
+					let gas_limit = gas_limit.min(u64::MAX.into()).low_u64();
 
-					let (weight_limit, proof_size_base_cost) =
-						match <Runtime as pallet_evm::Config>::GasWeightMapping::gas_to_weight(
-							gas_limit,
-							without_base_extrinsic_weight
-						) {
-							weight_limit if weight_limit.proof_size() > 0 => {
-								(Some(weight_limit), Some(estimated_transaction_len as u64))
-							}
-							_ => (None, None),
-						};
+					let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
 
 					#[allow(clippy::or_fun_call)] // suggestion not helpful here
 					<Runtime as pallet_evm::Config>::Runner::create(
diff --git a/test/suites/dev/moonbase/test-randomness/test-randomness-babe-lottery2.ts b/test/suites/dev/moonbase/test-randomness/test-randomness-babe-lottery2.ts
index ee959a2129f..9f252c9b515 100644
--- a/test/suites/dev/moonbase/test-randomness/test-randomness-babe-lottery2.ts
+++ b/test/suites/dev/moonbase/test-randomness/test-randomness-babe-lottery2.ts
@@ -47,7 +47,7 @@ describeSuite({
         args: [0],
         account: BALTATHAR_ADDRESS,
       });
-      expect(estimatedGas).toMatchInlineSnapshot(`153999n`);
+      expect(estimatedGas).toMatchInlineSnapshot(`151298n`);
 
       const rawTxn = await context.writePrecompile!({
         precompileName: "Randomness",
diff --git a/test/suites/dev/moonbase/test-randomness/test-randomness-babe-lottery3.ts b/test/suites/dev/moonbase/test-randomness/test-randomness-babe-lottery3.ts
index b075a17d939..845d72e7cd3 100644
--- a/test/suites/dev/moonbase/test-randomness/test-randomness-babe-lottery3.ts
+++ b/test/suites/dev/moonbase/test-randomness/test-randomness-babe-lottery3.ts
@@ -49,7 +49,7 @@ describeSuite({
       id: "T01",
       title: "should fail to fulfill before the delay",
       test: async function () {
-        expect(estimatedGasBefore).toMatchInlineSnapshot(`112408n`);
+        expect(estimatedGasBefore).toMatchInlineSnapshot(`112402n`);
 
         expect(
           await context.readPrecompile!({
@@ -86,7 +86,7 @@ describeSuite({
       id: "T02",
       title: "should succeed to fulfill after the delay",
       test: async function () {
-        expect(estimatedGasBefore).toMatchInlineSnapshot(`112408n`);
+        expect(estimatedGasBefore).toMatchInlineSnapshot(`112402n`);
 
         await context.createBlock([
           // Faking relay epoch + 2 in randomness storage
@@ -109,7 +109,7 @@ describeSuite({
           account: BALTATHAR_ADDRESS,
         });
         log("Estimated Gas for startLottery", estimatedGas);
-        expect(estimatedGas).toMatchInlineSnapshot(`155374n`);
+        expect(estimatedGas).toMatchInlineSnapshot(`152726n`);
 
         const rawTxn = await context.writePrecompile!({
           precompileName: "Randomness",
diff --git a/test/suites/dev/moonbase/test-randomness/test-randomness-vrf-lottery4.ts b/test/suites/dev/moonbase/test-randomness/test-randomness-vrf-lottery4.ts
index 55f50aaef45..6690f6f5af9 100644
--- a/test/suites/dev/moonbase/test-randomness/test-randomness-vrf-lottery4.ts
+++ b/test/suites/dev/moonbase/test-randomness/test-randomness-vrf-lottery4.ts
@@ -20,7 +20,7 @@ describeSuite({
         value: 1n * GLMR,
       });
       log("Estimated Gas for startLottery", estimatedGas);
-      expect(estimatedGas).toMatchInlineSnapshot(`112408n`);
+      expect(estimatedGas).toMatchInlineSnapshot(`111529n`);
 
       await context.writeContract!({
         contractAddress: lotteryContract,
@@ -47,7 +47,7 @@ describeSuite({
           args: [0],
         });
         log("Estimated Gas for startLottery", estimatedGas);
-        expect(estimatedGas).toMatchInlineSnapshot(`150735n`);
+        expect(estimatedGas).toMatchInlineSnapshot(`150829n`);
 
         const rawTxn = await context.writePrecompile!({
           precompileName: "Randomness",
diff --git a/test/suites/dev/moonbase/test-randomness/test-randomness-vrf-lottery5.ts b/test/suites/dev/moonbase/test-randomness/test-randomness-vrf-lottery5.ts
index 0eca674862a..fd5a14472ce 100644
--- a/test/suites/dev/moonbase/test-randomness/test-randomness-vrf-lottery5.ts
+++ b/test/suites/dev/moonbase/test-randomness/test-randomness-vrf-lottery5.ts
@@ -48,7 +48,7 @@ describeSuite({
         args: [0],
       });
 
-      expect(estimatedGas).toMatchInlineSnapshot(`150735n`);
+      expect(estimatedGas).toMatchInlineSnapshot(`150829n`);
 
       const rawTxn = await context.writePrecompile!({
         precompileName: "Randomness",
diff --git a/test/suites/dev/moonbase/test-storage-growth/test-precompile-storage-growth.ts b/test/suites/dev/moonbase/test-storage-growth/test-precompile-storage-growth.ts
index 3b30cd37c8c..909e616faf8 100644
--- a/test/suites/dev/moonbase/test-storage-growth/test-precompile-storage-growth.ts
+++ b/test/suites/dev/moonbase/test-storage-growth/test-precompile-storage-growth.ts
@@ -1,14 +1,11 @@
-import { describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
+import { beforeAll, describeSuite, expect, fetchCompiledContract } from "@moonwall/cli";
 import {
   BALTATHAR_ADDRESS,
-  BALTATHAR_PRIVATE_KEY,
   CONTRACT_PROXY_TYPE_ANY,
   FAITH_ADDRESS,
   FAITH_PRIVATE_KEY,
-  PRECOMPILE_NATIVE_ERC20_ADDRESS,
   PRECOMPILE_PROXY_ADDRESS,
 } from "@moonwall/util";
-import { parseEther } from "ethers";
 import { expectEVMResult } from "helpers/eth-transactions";
 import { encodeFunctionData } from "viem";
 
@@ -17,6 +14,10 @@ describeSuite({
   title: "Storage growth limit - Precompiles",
   foundationMethods: "dev",
   testCases: ({ context, it, log }) => {
+    beforeAll(async () => {
+      await context.createBlock();
+    });
+
     it({
       id: "T01",
       title: "should fail to addProxy due to insufficient gas required to cover the storage growth",
@@ -34,7 +35,7 @@ describeSuite({
         });
 
         // Snapshot estimated gas
-        expect(estimatedGas).toMatchInlineSnapshot(`51888n`);
+        expect(estimatedGas).toMatchInlineSnapshot(`49656n`);
 
         const rawTxn = await context.writePrecompile!({
           precompileName: "Proxy",
@@ -54,7 +55,6 @@ describeSuite({
       id: "T02",
       title: "should addProxy correctly with the required gas to cover the storage growth",
       test: async () => {
-        const balBefore = await context.viem().getBalance({ address: FAITH_ADDRESS });
         const { abi: proxyAbi } = fetchCompiledContract("Proxy");
 
         const estimatedGas = await context.viem().estimateGas({
@@ -68,7 +68,7 @@ describeSuite({
         });
 
         // Snapshot estimated gas
-        expect(estimatedGas).toMatchInlineSnapshot(`49856n`);
+        expect(estimatedGas).toMatchInlineSnapshot(`51118n`);
 
         const rawTxn = await context.writePrecompile!({
           precompileName: "Proxy",


Reviews:
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR replaces custom transaction weight and proof size calculation logic with the pallet_ethereum implementation and updates the runtime dependencies accordingly.  
- Replaces legacy gas weight mapping with the new pallet_ethereum::Pallet transaction_weight API.  
- Removes redundant estimated transaction length calculations in favor of a unified transaction_data creation.  
- Updates Cargo.toml to include pallet-ethereum in dependencies, std, and runtime benchmarks.

### Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

| File                                 | Description                                                                                |
| ------------------------------------ | ------------------------------------------------------------------------------------------ |
| runtime/common/src/apis.rs           | Replaces custom gas to weight logic with pallet_ethereum’s transaction_weight computation.  |
| runtime/common/Cargo.toml            | Adds pallet-ethereum as a dependency across workspace, std, and runtime benchmarks.         |


<details>
<summary>Comments suppressed due to low confidence (4)</summary>

**runtime/common/src/apis.rs:356**
* [nitpick] Ensure that the new transaction_weight computation is covered by tests, particularly for edge cases involving proof_size_base_cost.
```
let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
```
**runtime/common/src/apis.rs:474**
* [nitpick] Verify that changes replacing the manual computation with transaction_weight are properly validated with unit and integration tests.
```
let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
```
**runtime/common/src/apis.rs:530**
* [nitpick] Ensure that the behavior of the updated transaction weight and proof cost calculations is thoroughly tested to catch any regressions.
```
let (weight_limit, proof_size_base_cost) = pallet_ethereum::Pallet::<Runtime>::transaction_weight(&transaction_data);
```
**runtime/common/Cargo.toml:22**
* [nitpick] Confirm that the addition of pallet-ethereum as a workspace dependency aligns with the project configuration and versioning strategies.
```
pallet-ethereum = { workspace = true }
```
</details>


state: COMMENTED
author_association: NONE
submitted_at: 2025-05-06T09:27:43Z
user: login: copilot-pull-request-reviewer[bot]
body: Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
state: COMMENTED
author_association: NONE
submitted_at: 2025-05-06T09:40:34Z
user: login: copilot-pull-request-reviewer[bot]
body: ## Pull Request Overview

This PR refactors the calculation of proof_size_base_cost by replacing the manual estimation logic and the GasWeightMapping call with the new pallet_ethereum::Pallet transaction_weight API. In addition, it updates the Cargo.toml to include the pallet-ethereum dependency along with required features.
- Replaces manual encoded transaction length estimation with a new TransactionData-based computation.
- Updates GasWeightMapping usage to rely on pallet_ethereum::Pallet::<Runtime>::transaction_weight.
- Introduces the pallet-ethereum dependency with the "forbid-evm-reentrancy" feature in Cargo.toml.

### Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

| File                        | Description                                                           |
| --------------------------- | --------------------------------------------------------------------- |
| runtime/common/src/apis.rs  | Refactored proof_size_base_cost logic to utilize pallet_ethereum API.  |
| runtime/common/Cargo.toml   | Added pallet-ethereum dependency and updated feature/std listings.    |




state: COMMENTED
author_association: NONE
submitted_at: 2025-05-06T09:41:22Z
user: login: RomarQ
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T10:15:05Z
user: login: RomarQ
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T10:19:38Z
user: login: RomarQ
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T10:20:06Z
user: login: TarekkMA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T10:27:41Z
user: login: TarekkMA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T10:27:50Z
user: login: TarekkMA
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T10:28:14Z
user: login: RomarQ
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T10:57:39Z
user: login: RomarQ
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T10:59:23Z
user: login: stiiifff
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T12:29:31Z

Review comments:
diff_hunk: @@ -337,43 +337,23 @@ macro_rules! impl_runtime_apis_plus_common {
 						EvmTracer::new().trace(|| {
 							let is_transactional = false;
 							let validate = true;
-							let without_base_extrinsic_weight = true;
-
-
-							// Estimated encoded transaction size must be based on the heaviest transaction
-							// type (EIP1559Transaction) to be compatible with all transaction types.
-							// TODO: remove, since we will get rid of base_cost
-							let mut estimated_transaction_len = data.len() +
-								// pallet ethereum index: 1
-								// transact call index: 1
-								// Transaction enum variant: 1
-								// chain_id 8 bytes
-								// nonce: 32
-								// max_priority_fee_per_gas: 32
-								// max_fee_per_gas: 32
-								// gas_limit: 32
-								// action: 21 (enum varianrt + call address)
-								// value: 32
-								// access_list: 1 (empty vec size)
-								// 65 bytes signature
-								258;
-
-							if access_list.is_some() {
-								estimated_transaction_len += access_list.encoded_size();
-							}
+
+							let transaction_data = pallet_ethereum::TransactionData::new(
+								pallet_ethereum::TransactionAction::Call(to),
+								data.clone(),
+								nonce.unwrap_or_default(),
+								gas_limit,
+								None,
+								max_fee_per_gas.or(Some(U256::default())),
+								max_priority_fee_per_gas.or(Some(U256::default())),
path: runtime/common/src/apis.rs
user: login: RomarQ
body: ```suggestion
								max_fee_per_gas,
								max_priority_fee_per_gas,
```
created_at: 2025-05-12T10:15:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -476,41 +456,22 @@ macro_rules! impl_runtime_apis_plus_common {
 					let is_transactional = false;
 					let validate = true;
 
-							// Estimated encoded transaction size must be based on the heaviest transaction
-							// type (EIP1559Transaction) to be compatible with all transaction types.
-					// TODO: remove, since we will get rid of base_cost
-					let mut estimated_transaction_len = data.len() +
-						// pallet ethereum index: 1
-						// transact call index: 1
-						// Transaction enum variant: 1
-						// chain_id 8 bytes
-						// nonce: 32
-						// max_priority_fee_per_gas: 32
-						// max_fee_per_gas: 32
-						// gas_limit: 32
-						// action: 21 (enum varianrt + call address)
-						// value: 32
-						// access_list: 1 (empty vec size)
-						// 65 bytes signature
-						258;
-
-					if access_list.is_some() {
-						estimated_transaction_len += access_list.encoded_size();
-					}
+					let transaction_data = pallet_ethereum::TransactionData::new(
+						pallet_ethereum::TransactionAction::Call(to),
+						data.clone(),
+						nonce.unwrap_or_default(),
+						gas_limit,
+						None,
+						max_fee_per_gas.or(Some(U256::default())),
+						max_priority_fee_per_gas.or(Some(U256::default())),
path: runtime/common/src/apis.rs
user: login: RomarQ
body: ```suggestion
						max_fee_per_gas,
						max_priority_fee_per_gas,
```
created_at: 2025-05-12T10:19:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -551,43 +512,22 @@ macro_rules! impl_runtime_apis_plus_common {
 					let is_transactional = false;
 					let validate = true;
 
-					let mut estimated_transaction_len = data.len() +
-						// from: 20
-						// value: 32
-						// gas_limit: 32
-						// nonce: 32
-						// 1 byte transaction action variant
-						// chain id 8 bytes
-						// 65 bytes signature
-						190;
-
-					if max_fee_per_gas.is_some() {
-						estimated_transaction_len += 32;
-					}
-					if max_priority_fee_per_gas.is_some() {
-						estimated_transaction_len += 32;
-					}
-					if access_list.is_some() {
-						estimated_transaction_len += access_list.encoded_size();
-					}
+					let transaction_data = pallet_ethereum::TransactionData::new(
+						pallet_ethereum::TransactionAction::Create,
+						data.clone(),
+						nonce.unwrap_or_default(),
+						gas_limit,
+						None,
+						max_fee_per_gas.or(Some(U256::default())),
+						max_priority_fee_per_gas.or(Some(U256::default())),
path: runtime/common/src/apis.rs
user: login: RomarQ
body: ```suggestion
						max_fee_per_gas,
						max_priority_fee_per_gas,
```
created_at: 2025-05-12T10:20:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -551,43 +512,22 @@ macro_rules! impl_runtime_apis_plus_common {
 					let is_transactional = false;
 					let validate = true;
 
-					let mut estimated_transaction_len = data.len() +
-						// from: 20
-						// value: 32
-						// gas_limit: 32
-						// nonce: 32
-						// 1 byte transaction action variant
-						// chain id 8 bytes
-						// 65 bytes signature
-						190;
-
-					if max_fee_per_gas.is_some() {
-						estimated_transaction_len += 32;
-					}
-					if max_priority_fee_per_gas.is_some() {
-						estimated_transaction_len += 32;
-					}
-					if access_list.is_some() {
-						estimated_transaction_len += access_list.encoded_size();
-					}
+					let transaction_data = pallet_ethereum::TransactionData::new(
+						pallet_ethereum::TransactionAction::Create,
+						data.clone(),
+						nonce.unwrap_or_default(),
+						gas_limit,
+						None,
+						max_fee_per_gas.or(Some(U256::default())),
+						max_priority_fee_per_gas.or(Some(U256::default())),
path: runtime/common/src/apis.rs
user: login: TarekkMA
body: This will cause some issues, `max_fee_per_gas` is being set as `None` in the estimation. But it's being sent as `Some(..)` when sending the actual call.
created_at: 2025-05-12T10:27:41Z
author_association: CONTRIBUTOR
diff_hunk: @@ -476,41 +456,22 @@ macro_rules! impl_runtime_apis_plus_common {
 					let is_transactional = false;
 					let validate = true;
 
-							// Estimated encoded transaction size must be based on the heaviest transaction
-							// type (EIP1559Transaction) to be compatible with all transaction types.
-					// TODO: remove, since we will get rid of base_cost
-					let mut estimated_transaction_len = data.len() +
-						// pallet ethereum index: 1
-						// transact call index: 1
-						// Transaction enum variant: 1
-						// chain_id 8 bytes
-						// nonce: 32
-						// max_priority_fee_per_gas: 32
-						// max_fee_per_gas: 32
-						// gas_limit: 32
-						// action: 21 (enum varianrt + call address)
-						// value: 32
-						// access_list: 1 (empty vec size)
-						// 65 bytes signature
-						258;
-
-					if access_list.is_some() {
-						estimated_transaction_len += access_list.encoded_size();
-					}
+					let transaction_data = pallet_ethereum::TransactionData::new(
+						pallet_ethereum::TransactionAction::Call(to),
+						data.clone(),
+						nonce.unwrap_or_default(),
+						gas_limit,
+						None,
+						max_fee_per_gas.or(Some(U256::default())),
+						max_priority_fee_per_gas.or(Some(U256::default())),
path: runtime/common/src/apis.rs
user: login: TarekkMA
body: Same comment
created_at: 2025-05-12T10:27:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -337,43 +337,23 @@ macro_rules! impl_runtime_apis_plus_common {
 						EvmTracer::new().trace(|| {
 							let is_transactional = false;
 							let validate = true;
-							let without_base_extrinsic_weight = true;
-
-
-							// Estimated encoded transaction size must be based on the heaviest transaction
-							// type (EIP1559Transaction) to be compatible with all transaction types.
-							// TODO: remove, since we will get rid of base_cost
-							let mut estimated_transaction_len = data.len() +
-								// pallet ethereum index: 1
-								// transact call index: 1
-								// Transaction enum variant: 1
-								// chain_id 8 bytes
-								// nonce: 32
-								// max_priority_fee_per_gas: 32
-								// max_fee_per_gas: 32
-								// gas_limit: 32
-								// action: 21 (enum varianrt + call address)
-								// value: 32
-								// access_list: 1 (empty vec size)
-								// 65 bytes signature
-								258;
-
-							if access_list.is_some() {
-								estimated_transaction_len += access_list.encoded_size();
-							}
+
+							let transaction_data = pallet_ethereum::TransactionData::new(
+								pallet_ethereum::TransactionAction::Call(to),
+								data.clone(),
+								nonce.unwrap_or_default(),
+								gas_limit,
+								None,
+								max_fee_per_gas.or(Some(U256::default())),
+								max_priority_fee_per_gas.or(Some(U256::default())),
path: runtime/common/src/apis.rs
user: login: TarekkMA
body: Same comment 
created_at: 2025-05-12T10:28:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -551,43 +512,22 @@ macro_rules! impl_runtime_apis_plus_common {
 					let is_transactional = false;
 					let validate = true;
 
-					let mut estimated_transaction_len = data.len() +
-						// from: 20
-						// value: 32
-						// gas_limit: 32
-						// nonce: 32
-						// 1 byte transaction action variant
-						// chain id 8 bytes
-						// 65 bytes signature
-						190;
-
-					if max_fee_per_gas.is_some() {
-						estimated_transaction_len += 32;
-					}
-					if max_priority_fee_per_gas.is_some() {
-						estimated_transaction_len += 32;
-					}
-					if access_list.is_some() {
-						estimated_transaction_len += access_list.encoded_size();
-					}
+					let transaction_data = pallet_ethereum::TransactionData::new(
+						pallet_ethereum::TransactionAction::Create,
+						data.clone(),
+						nonce.unwrap_or_default(),
+						gas_limit,
+						None,
+						max_fee_per_gas.or(Some(U256::default())),
+						max_priority_fee_per_gas.or(Some(U256::default())),
path: runtime/common/src/apis.rs
user: login: RomarQ
body: That is weird, should not be the case
created_at: 2025-05-12T10:57:39Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-05-06T09:39:00Z
body: ### WASM runtime size check:

#### Compared to target branch

Moonbase runtime: 2428 KB (no changes) 🚨

Moonbeam runtime: 2412 KB (no changes) 🚨

Moonriver runtime: 2408 KB (no changes) 🚨

#### Compared to latest release (runtime-3600)

Moonbase runtime: 2428 KB (+472 KB compared to latest release) 🚨

Moonbeam runtime: 2412 KB (+468 KB compared to latest release) 🚨

Moonriver runtime: 2408 KB (+468 KB compared to latest release) 🚨

author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-06T10:29:32Z
body: ## [Coverage Report](https://d1alxm61l8eb3k.cloudfront.net/pulls/3279/html/index.html)
```diff
@@                         Coverage Diff                         @@
##           master   tarekkma/improve-base-cost-calc      +/-   ##
===================================================================
+ Coverage   74.76%                            74.79%   +0.03%     
  Files         400                               400              
- Lines      101272                            101212      -60     
===================================================================
- Hits        75712                             75696      -16     
- Misses      25560                             25516      -44     
```

| Files Changed | Coverage |  |
| --- | --- | --- |
| [/runtime/common/src/apis.rs](https://d1alxm61l8eb3k.cloudfront.net/pulls/3279/html/runtime/common/src/apis.rs.html) | 29.09% (+0.12%) | 🔼 |

> Coverage generated Thu May 8 14:14:07 UTC 2025

author_association: CONTRIBUTOR
user: login: librelois
created_at: 2025-05-06T11:40:18Z
body: To be honest, I don’t like the design of TransactionData, as it’s less accurate than using the TransactionV2 enum directly. It will overestimate the PoV base cost when you submit a Legacy or EIP‑2930 transaction. Fixing that would require substantial changes upstream in Frontier.

However, it’s fine for new blocks, because nowadays everyone uses the EIP‑1559 transaction type, so we can merge it as is.
author_association: COLLABORATOR