Skip to content

Includes frontier PRs polkadot-evm/frontier#1820 and polkadot-evm/frontier#1824#3677

Merged
librelois merged 7 commits intomasterfrom
elois/frontier-pin
Feb 20, 2026
Merged

Includes frontier PRs polkadot-evm/frontier#1820 and polkadot-evm/frontier#1824#3677
librelois merged 7 commits intomasterfrom
elois/frontier-pin

Conversation

@librelois
Copy link
Collaborator

@librelois librelois commented Feb 20, 2026

What does it do?

Includes frontier PRs polkadot-evm/frontier#1824 and polkadot-evm/frontier#1820

What important points should reviewers know?

The new Frontier pin also includes polkadot-evm/frontier#1815, which adds a new configuration option, AllowUnprotectedTxs.
Setting this option to false breaks many tests and requires changes in Moonwall to always provide a chainId, even for legacy transactions. This work will be addressed in a future PR.
For now, this PR sets AllowUnprotectedTxs to true.

Is there something left for follow-up PRs?

What alternative implementations were considered?

Are there relevant PRs or issues in other repositories (Substrate, Polkadot, Frontier, Cumulus)?

What value does it bring to the blockchain users?

@librelois librelois added B5-clientnoteworthy Changes should be mentioned in any downstream projects' release notes D2-notlive PR doesn't change runtime code (so can't be audited) not-breaking Does not need to be mentioned in breaking changes labels Feb 20, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new AllowUnprotectedTxs runtime/test configuration (bool) across multiple crates, wires it into pallet_ethereum::Config, passes allow_unprotected_txs: false into CheckEvmTransactionConfig in pallets/ethereum-xcm, and inserts an extra boolean argument into an Eth RPC constructor call. Tests updated to use createBlock return metadata and explicit block-number lookups.

Changes

Cohort / File(s) Summary
Ethereum XCM pallet
pallets/ethereum-xcm/src/lib.rs
Adds allow_unprotected_txs: false to CheckEvmTransactionConfig passed during EVM transaction validation.
Pallet test mocks
pallets/ethereum-xcm/src/mock.rs, pallets/moonbeam-foreign-assets/src/mock.rs
Adds pub const AllowUnprotectedTxs: bool = true and wires type AllowUnprotectedTxs = AllowUnprotectedTxs; into pallet_ethereum::Config for tests.
Runtimes — moonbase / moonbeam / moonriver
runtime/moonbase/src/lib.rs, runtime/moonbase/tests/xcm_mock/parachain.rs, runtime/moonbeam/src/lib.rs, runtime/moonbeam/tests/xcm_mock/parachain.rs, runtime/moonriver/src/lib.rs, runtime/moonriver/tests/xcm_mock/parachain.rs
Adds AllowUnprotectedTxs parameter (pub const AllowUnprotectedTxs: bool = true) and binds it as type AllowUnprotectedTxs = AllowUnprotectedTxs; in each runtime's pallet_ethereum::Config.
Node RPC service
node/service/src/rpc.rs
Inserts an extra boolean argument into Eth::<..., MoonbeamEthConfig<_, _>>::new(...) call (shifts subsequent params).
Tests — createBlock / block fetch / receipts / feeHistory
test/suites/.../moonbase/**, test/suites/tracing-tests/**
Many tests updated to use createBlock return shape ({ result }) and result.hash or receipt.blockHash to locate txs/blocks; several tests fetch blocks by explicit next block number instead of "latest"; eth_feeHistory tests call RPC directly and adjust timeouts/nonce source.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested labels

agent-review

Suggested reviewers

  • arturgontijo
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly indicates the main change: integrating two specific Frontier PRs (#1820 and #1824) into the codebase.
Description check ✅ Passed Description is well-related to the changeset, explaining the Frontier PRs being integrated, the AllowUnprotectedTxs configuration changes, and deferring Moonwall updates to a future PR.
Linked Issues check ✅ Passed Code changes align with objectives: AllowUnprotectedTxs configuration is added across all runtime/test files [#1815], and the test updates reflect the re-org handling fixes from Frontier PRs #1820 and #1824 [#3667].
Out of Scope Changes check ✅ Passed All changes are in-scope: AllowUnprotectedTxs configuration additions align with Frontier #1815, and test updates reflect API/behavior changes from the upstream Frontier pin.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch elois/frontier-pin

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 20, 2026
manuelmauro
manuelmauro previously approved these changes Feb 20, 2026
@manuelmauro manuelmauro self-requested a review February 20, 2026 14:05
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pallets/ethereum-xcm/src/lib.rs (1)

357-369: ⚠️ Potential issue | 🟠 Major

Use the runtime's AllowUnprotectedTxs configuration in XCM transaction validation.

Line 368 hardcodes allow_unprotected_txs: false, which bypasses the runtime-configurable AllowUnprotectedTxs setting from pallet_ethereum::Config. If a runtime enables unprotected transactions, XCM validation will still reject them while the Ethereum RPC path allows them, creating an inconsistency.

Add pallet_ethereum::Config to the trait bounds and source the setting:

Proposed changes
pub trait Config:
	frame_system::Config<RuntimeEvent: From<Event<Self>>>
	+ pallet_evm::Config
+	+ pallet_ethereum::Config
{
-	allow_unprotected_txs: false,
+	allow_unprotected_txs: <T as pallet_ethereum::Config>::AllowUnprotectedTxs::get(),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pallets/ethereum-xcm/src/lib.rs` around lines 357 - 369, The XCM EVM
validation hardcodes allow_unprotected_txs: false in the
CheckEvmTransactionConfig (created by
CheckEvmTransaction::<T::InvalidEvmTransactionError>::new) which ignores the
runtime's AllowUnprotectedTxs setting; update the pallet trait bounds to require
pallet_ethereum::Config and replace the hardcoded value by reading
pallet_ethereum::Config::AllowUnprotectedTxs (or the associated constant/type
from the pallet_ethereum::Config) so allow_unprotected_txs is sourced from the
runtime configuration when constructing CheckEvmTransactionConfig (alongside the
existing evm_config: T::config(), block_gas_limit, base_fee, chain_id,
is_transactional fields).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@pallets/ethereum-xcm/src/lib.rs`:
- Around line 357-369: The XCM EVM validation hardcodes allow_unprotected_txs:
false in the CheckEvmTransactionConfig (created by
CheckEvmTransaction::<T::InvalidEvmTransactionError>::new) which ignores the
runtime's AllowUnprotectedTxs setting; update the pallet trait bounds to require
pallet_ethereum::Config and replace the hardcoded value by reading
pallet_ethereum::Config::AllowUnprotectedTxs (or the associated constant/type
from the pallet_ethereum::Config) so allow_unprotected_txs is sourced from the
runtime configuration when constructing CheckEvmTransactionConfig (alongside the
existing evm_config: T::config(), block_gas_limit, base_fee, chain_id,
is_transactional fields).

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 20, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
node/service/src/rpc.rs (1)

287-287: Redundant double Arc::clone — prefer Arc::clone(&client).

Arc::clone(&client.clone()) clones the Arc twice (one temporary clone immediately dropped). All other Arc::clone calls in this block use the direct form; this one should too.

♻️ Proposed fix
-        Arc::clone(&client.clone()),
+        Arc::clone(&client),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@node/service/src/rpc.rs` at line 287, The call uses a redundant double clone:
replace the expression Arc::clone(&client.clone()) with the direct form
Arc::clone(&client) to avoid creating and dropping a temporary Arc; locate the
occurrence where Arc::clone is invoked with client (the variable named client in
the rpc module) and change it to Arc::clone(&client) so it matches the other
clones in this block.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@node/service/src/rpc.rs`:
- Line 287: The call uses a redundant double clone: replace the expression
Arc::clone(&client.clone()) with the direct form Arc::clone(&client) to avoid
creating and dropping a temporary Arc; locate the occurrence where Arc::clone is
invoked with client (the variable named client in the rpc module) and change it
to Arc::clone(&client) so it matches the other clones in this block.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 20, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 20, 2026

Coverage Report

@@                  Coverage Diff                  @@
##           master   elois/frontier-pin     +/-   ##
=====================================================
  Coverage   77.10%               77.10%   0.00%     
  Files         389                  389             
+ Lines       76941                76943      +2     
=====================================================
+ Hits        59321                59323      +2     
  Misses      17620                17620             
Files Changed Coverage
/node/service/src/rpc.rs 83.52% (+0.06%) 🔼
/pallets/ethereum-xcm/src/lib.rs 90.67% (+0.07%) 🔼

Coverage generated Fri Feb 20 20:40:35 UTC 2026

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
runtime/moonbeam/src/lib.rs (1)

692-702: Consider using ConstBool<true> instead of pub const AllowUnprotectedTxs: bool = true for consistency with similar bool configs.

The parameter_types! block at line 694 defines AllowUnprotectedTxs as a constant bool that's then assigned to pallet_ethereum::Config::type AllowUnprotectedTxs at line 701. ConstBool<true> is already imported (line 54) and used elsewhere in this runtime (e.g., type AllowMultipleBlocksPerSlot = ConstBool<true> at line 901), making it a more concise and idiomatic alternative.

The pallet_ethereum_xcm pallet hardcodes allow_unprotected_txs: false independently—it does not reference the runtime config value—so changing this parameter will only affect the direct pallet_ethereum path, not XCM transactions.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@runtime/moonbeam/src/lib.rs` around lines 692 - 702, Replace the bool-style
parameter declaration with the generic ConstBool version: in the
parameter_types! block swap the current "pub const AllowUnprotectedTxs: bool =
true" to use ConstBool<true> so the runtime-level constant matches the other
bool configs; then keep "type AllowUnprotectedTxs = AllowUnprotectedTxs;" in the
pallet_ethereum::Config impl (no other changes needed to
pallet_ethereum::Config), ensuring symbols referenced are AllowUnprotectedTxs,
parameter_types!, and pallet_ethereum::Config.
node/service/src/rpc.rs (1)

299-301: Add a comment on the bare true argument to clarify it maps to allow_unprotected_txs.

The unlabeled true at line 300 is the new allow_unprotected_txs parameter added to fc_rpc::Eth::new by the upstream frontier change. Unlike the surrounding named-variable arguments, it reads as magic. A brief inline comment prevents ambiguity for future readers, especially since the value must stay in sync with the runtime's AllowUnprotectedTxs = true.

♻️ Proposed fix
-            10,
-            true,
+            10,
+            true, // allow_unprotected_txs — must match pallet_ethereum::Config::AllowUnprotectedTxs
             forced_parent_hashes,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@node/service/src/rpc.rs` around lines 299 - 301, The bare literal `true` in
the call to fc_rpc::Eth::new (the argument list containing 10, true,
forced_parent_hashes) corresponds to the new allow_unprotected_txs parameter and
should be annotated with an inline comment to make intent explicit; update the
call site in rpc.rs (the fc_rpc::Eth::new invocation) to add a short comment
like /* allow_unprotected_txs: true */ next to the literal and include a note
reminding maintainers to keep this value in sync with the runtime's
AllowUnprotectedTxs = true.
runtime/moonriver/src/lib.rs (1)

695-706: Consider using ConstBool<true> directly instead of the parameter_types wrapper for AllowUnprotectedTxs.

Other boolean config items in this runtime (e.g., pallet_async_backing::Config::AllowMultipleBlocksPerSlot at line 901) use ConstBool<true> directly in the impl block. This would be more concise and consistent:

♻️ Optional: simplify boolean config
 parameter_types! {
     pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes;
-    pub const AllowUnprotectedTxs: bool = true;
 }

 impl pallet_ethereum::Config for Runtime {
     type StateRoot =
         pallet_ethereum::IntermediateStateRoot<<Runtime as frame_system::Config>::Version>;
     type PostLogContent = PostBlockAndTxnHashes;
     type ExtraDataLength = ConstU32<30>;
-    type AllowUnprotectedTxs = AllowUnprotectedTxs;
+    type AllowUnprotectedTxs = ConstBool<true>;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@runtime/moonriver/src/lib.rs` around lines 695 - 706, The AllowUnprotectedTxs
parameter_types wrapper is unnecessary—remove the AllowUnprotectedTxs
parameter_types declaration and use ConstBool<true> directly in the
pallet_ethereum::Config impl: set type AllowUnprotectedTxs = ConstBool<true>;
(leave PostBlockAndTxnHashes and other parameter_types intact); this matches the
pattern used by pallet_async_backing::Config::AllowMultipleBlocksPerSlot and
simplifies the code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@node/service/src/rpc.rs`:
- Around line 299-301: The bare literal `true` in the call to fc_rpc::Eth::new
(the argument list containing 10, true, forced_parent_hashes) corresponds to the
new allow_unprotected_txs parameter and should be annotated with an inline
comment to make intent explicit; update the call site in rpc.rs (the
fc_rpc::Eth::new invocation) to add a short comment like /*
allow_unprotected_txs: true */ next to the literal and include a note reminding
maintainers to keep this value in sync with the runtime's AllowUnprotectedTxs =
true.

In `@runtime/moonbeam/src/lib.rs`:
- Around line 692-702: Replace the bool-style parameter declaration with the
generic ConstBool version: in the parameter_types! block swap the current "pub
const AllowUnprotectedTxs: bool = true" to use ConstBool<true> so the
runtime-level constant matches the other bool configs; then keep "type
AllowUnprotectedTxs = AllowUnprotectedTxs;" in the pallet_ethereum::Config impl
(no other changes needed to pallet_ethereum::Config), ensuring symbols
referenced are AllowUnprotectedTxs, parameter_types!, and
pallet_ethereum::Config.

In `@runtime/moonriver/src/lib.rs`:
- Around line 695-706: The AllowUnprotectedTxs parameter_types wrapper is
unnecessary—remove the AllowUnprotectedTxs parameter_types declaration and use
ConstBool<true> directly in the pallet_ethereum::Config impl: set type
AllowUnprotectedTxs = ConstBool<true>; (leave PostBlockAndTxnHashes and other
parameter_types intact); this matches the pattern used by
pallet_async_backing::Config::AllowMultipleBlocksPerSlot and simplifies the
code.

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 20, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/suites/dev/moonbase/test-eth-fee/test-eth-fee-history.ts (1)

92-92: ⚠️ Potential issue | 🟡 Minor

T01 timeout not bumped consistently with T03.

T01 (timeout: 40_000) and T03 (timeout: 120_000) both call createBlocks(2, [1,2,3], ...) — identical workloads. Only T03 received the bump; T01 is more likely to flake under load.

🛠️ Proposed fix
-      timeout: 40_000,
+      timeout: 120_000,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-eth-fee/test-eth-fee-history.ts` at line 92,
Test T01 uses a shorter timeout (timeout: 40_000) but runs the same heavy
workload as T03 (both call createBlocks(2, [1,2,3], ...)), so update T01’s
timeout to match T03 (120_000) to prevent flakiness; locate the T01 test block
in test-eth-fee-history.ts and change the timeout value from 40_000 to 120_000
where the timeout is set for that test.
🧹 Nitpick comments (7)
test/suites/dev/moonbase/test-contract/test-contract-methods.ts (1)

29-31: LGTM — robust improvement over positional block lookup.

Fetching the transaction first to resolve its blockHash and then asserting toContain (instead of an index-based equality) is strictly more correct: it handles blocks with pre-existing transactions and no longer relies on ordering assumptions.

One minor note: tx.blockHash! suppresses the TypeScript null type for pending transactions. In this dev chain context deployContract awaits finalization before beforeAll resolves, so it is safe in practice. Adding an explicit assertion before line 30 would turn a potential silent-null failure into a clear message if the invariant ever breaks:

🛡️ Optional: guard with an explicit assertion
  const tx = await context.viem().getTransaction({ hash: deployHash });
+ expect(tx.blockHash, "Transaction should be mined before block lookup").not.toBeNull();
  const block = await context.viem().getBlock({ blockHash: tx.blockHash! });
  expect(block.transactions).toContain(deployHash);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-contract/test-contract-methods.ts` around lines
29 - 31, Add an explicit assertion that tx.blockHash is non-null before using
it: after calling context.viem().getTransaction({ hash: deployHash }) and
assigning to tx, assert that tx.blockHash is defined (e.g., throw or use expect
with a clear message) so the subsequent call to context.viem().getBlock({
blockHash: tx.blockHash }) cannot silently pass a null; reference the variables
tx, deployHash and the calls to context.viem().getTransaction / getBlock when
locating the spot to insert this guard.
test/suites/dev/moonbase/test-xcm-v3/test-mock-hrmp-transact-ethereum-10.ts (1)

153-161: LGTM — fetching by pre-computed block number correctly fixes the "latest" flakiness.

Pre-computing blockNumber before injectHrmpMessageAndSeal and then fetching by that specific number is the right fix for the intermittent-null issue described in #3667. Because getBlockNumber() is awaited fresh at the start of every loop iteration, both the V1 and V2 passes compute the correct target block independently.

One optional hardening: Viem's getBlock return type includes null when the block isn't found. Accessing .transactions directly on a potential null would produce an opaque TypeError rather than a meaningful test failure. A lightweight guard makes the failure message clearer if this ever trips:

🛡️ Optional null guard
-          const ethBlock = await context.viem().getBlock({ blockNumber });
-          // Input size is valid - on the limit -, expect block to include a transaction.
-          // That means the pallet-ethereum-xcm decoded the provided input to a BoundedVec.
-          expect(ethBlock.transactions.length).to.be.eq(1);
+          const ethBlock = await context.viem().getBlock({ blockNumber });
+          // Input size is valid - on the limit -, expect block to include a transaction.
+          // That means the pallet-ethereum-xcm decoded the provided input to a BoundedVec.
+          expect(ethBlock, `block ${blockNumber} not found`).to.not.be.null;
+          expect(ethBlock!.transactions.length).to.be.eq(1);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-xcm-v3/test-mock-hrmp-transact-ethereum-10.ts`
around lines 153 - 161, The test fetches ethBlock via
context.viem().getBlock(...) and then accesses ethBlock.transactions without
guarding against getBlock returning null; update the test around
injectHrmpMessageAndSeal / the ethBlock retrieval so you assert ethBlock is not
null (or throw a clear assertion) before checking ethBlock.transactions.length
to produce an explicit, informative test failure instead of a TypeError when the
block is missing.
test/suites/dev/moonbase/test-contract/test-contract-loop-cost.ts (1)

43-43: Consider guarding result before the non-null assertion for a clearer failure message.

result!.hash suppresses the TypeScript error but will still throw a runtime TypeError: Cannot read properties of null (reading 'hash') if createBlock returns { result: null } (e.g., on an unexpected tx rejection). An explicit expect(result).toBeDefined() up front gives a descriptive failure rather than a confusing NPE.

The underlying change — verifying receipt.gasUsed instead of block.gasUsed — is correct and semantically more precise for per-transaction gas assertions. receipt.gasUsed (bigint from viem) aligns with the bigint gas literals in TestParameters, so the .toBe() comparison is type-safe.

🛡️ Proposed defensive guard
-            const { result } = await context.createBlock(rawSigned);
+            const { result } = await context.createBlock(rawSigned);
+            expect(result, "block creation result should not be null").toBeDefined();

             expect(
               await context.readContract!({

Also applies to: 52-55

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-contract/test-contract-loop-cost.ts` at line
43, The test currently uses result!.hash which can throw a runtime NPE if
context.createBlock(rawSigned) returns { result: null }; add an explicit guard
before dereferencing by asserting the result is defined (e.g.,
expect(result).toBeDefined()) immediately after const { result } = await
context.createBlock(rawSigned) and similarly for the other occurrences (lines
covering the second createBlock call), then continue using result.hash; also
ensure the test uses receipt.gasUsed for per-transaction gas assertions
(receipt.gasUsed is a bigint matching TestParameters gas literals) rather than
block.gasUsed.
test/suites/dev/moonbase/test-storage-growth/test-block-storage-growth.ts (1)

35-37: LGTM — correctly eliminates reliance on the "latest" block tag.

Snapshotting currentBlock + 1n before createBlock() and then querying by that specific block number is the right fix for the flakiness described in issue #3667. The +1n BigInt arithmetic is correct, and the assumption that no extra block is produced between lines 35 and 36 holds because foundationMethods: "dev" disables automatic block production.

One minor pre-existing inconsistency: the test title (line 18) still reads "should fill a block with 61 tx at most" while the assertion now checks for 264 transactions. Since line 37 is being touched in this PR, it's a good moment to align the title.

📝 Suggested title update
-      title: "should fill a block with 61 tx at most",
+      title: "should fill a block with 264 tx at most",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-storage-growth/test-block-storage-growth.ts`
around lines 35 - 37, Update the test title string in
test/suites/dev/moonbase/test-storage-growth/test-block-storage-growth.ts to
match the assertion change: replace the existing "should fill a block with 61 tx
at most" with a title that reflects the new expectation (e.g., "should fill a
block with 264 tx at most") so the it/test description and the assertion for 264
transactions are consistent; locate the test by its current title string in the
file and update that literal accordingly.
test/suites/dev/moonbase/test-moon/test-moon-rpc.ts (1)

92-102: LGTM — using result.hash directly is more robust here.

Sourcing the transaction hash from result.hash rather than block.transactions[n] is the right call given the re-org fix in Frontier #1820: the old approach could race with a block being replaced under the test, producing a stale or null hash. The non-null assertion result! is safe since all three tests pass a real transaction to createBlock.

One minor note: if you ever want earlier failure diagnostics, swapping result!.hash for a guarded assertion like:

-        const resp = await api.rpc.moon.isTxFinalized(result!.hash as `0x${string}`);
+        expect(result, "createBlock should return a transaction result").toBeDefined();
+        const resp = await api.rpc.moon.isTxFinalized(result!.hash as `0x${string}`);

…would produce a more descriptive error if createBlock ever fails to include the transaction, instead of a bare TypeError: Cannot read properties of null.

Also applies to: 111-121, 140-150

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-moon/test-moon-rpc.ts` around lines 92 - 102,
The test should source the transaction hash from the createBlock result instead
of reading block.transactions[...] to avoid races; update the calls that use
block.transactions[n] to use the hash returned by context.createBlock (the
result object from createViemTransaction) — e.g., use result.hash (from the
result returned by context.createBlock/createViemTransaction) and optionally add
a guarded assertion that result and result.hash are present before calling
api.rpc.moon.isTxFinalized to get a clearer failure message; apply the same
change to the other occurrences mentioned (the blocks around where result is
used at the other ranges).
test/suites/dev/moonbase/test-eth-tx/test-eth-tx-access-list.ts (1)

56-59: Consider guarding result!.hash for better test failure diagnostics.

Both T01 and T02 run 100 iterations. If any block creation silently produces a null result (e.g., transaction not included), TypeScript's non-null assertion (!) produces a bare Cannot read properties of null (reading 'hash') with no context about which iteration failed. A lightweight guard surfaces a clearer message:

♻️ Suggested guard (same pattern applies to T02 at lines 119–122)
- const { result } = await context.createBlock(txWithAL);
+ const { result } = await context.createBlock(txWithAL);
+ expect(result?.hash, `Block creation returned no hash for n=${n}`).toBeDefined();
  const receipt = await context
    .viem()
-   .getTransactionReceipt({ hash: result!.hash as `0x${string}` });
+   .getTransactionReceipt({ hash: result!.hash as `0x${string}` });

Also applies to: 119-122

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-eth-tx/test-eth-tx-access-list.ts` around lines
56 - 59, The test currently uses a non-null assertion on result from
context.createBlock which yields an unhelpful runtime error if createBlock
returns null; replace the assertion with an explicit guard: after const { result
} = await context.createBlock(txWithAL); add an if (!result) throw new
Error(...) that includes identifying context such as the transaction payload
(txWithAL), the current iteration/index if available, and any returned metadata
to make failures diagnosable; apply the same explicit-null-check pattern to the
other occurrence in T02 (the receipt lookup that uses result!.hash).
test/suites/dev/moonbase/test-subscription/test-subscription-logs.ts (1)

32-32: tx.blockHash! non-null assertion — optional defensive guard for clearer error messages

In viem, Transaction.blockHash is typed 0x${string} | null (null for pending transactions). The non-null assertion here is justified because the transaction is guaranteed to be mined before logs[0] is populated—log events only fire for confirmed transactions. However, adding an explicit guard makes this assumption visible and ensures a meaningful error message if the timing assumption ever changes.

If desired, add a defensive check:

🛡️ Optional defensive guard
+        expect(tx.blockHash, "tx should be mined before log event fires").toBeTruthy();
         const block = await context.viem().getBlock({ blockHash: tx.blockHash! });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-subscription/test-subscription-logs.ts` at line
32, Replace the non-null assertion on tx.blockHash used in the call to
context.viem().getBlock with an explicit defensive check: verify tx.blockHash is
not null before calling getBlock (e.g., if null throw or fail the test with a
clear message), so the code in the block lookup path (the getBlock call and any
logic around logs[0]) fails with a meaningful error rather than using the `!`
operator; update references to tx.blockHash in this test to use that guard and a
descriptive error mentioning the unexpected pending transaction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/suites/dev/moonbase/test-eth-fee/test-eth-fee-history.ts`:
- Around line 100-105: matchExpectations contains a dead assertion because the
filter callback in the reward-length check (the `feeResults.reward.filter((item)
=> { item.length !== reward_percentiles.length; });` call) does not return a
boolean, so `failures` is always empty; fix it by making the callback return the
comparison (e.g. change to a concise arrow that returns `item.length !==
reward_percentiles.length` or add an explicit `return`), or alternatively
replace the filter with a proper loop that collects mismatches before the
`expect(failures.length).toBe(0)` assertion; refer to the `matchExpectations`
function and the `failures`/`feeResults.reward.filter` expression to locate the
change.

---

Outside diff comments:
In `@test/suites/dev/moonbase/test-eth-fee/test-eth-fee-history.ts`:
- Line 92: Test T01 uses a shorter timeout (timeout: 40_000) but runs the same
heavy workload as T03 (both call createBlocks(2, [1,2,3], ...)), so update T01’s
timeout to match T03 (120_000) to prevent flakiness; locate the T01 test block
in test-eth-fee-history.ts and change the timeout value from 40_000 to 120_000
where the timeout is set for that test.

---

Nitpick comments:
In `@test/suites/dev/moonbase/test-contract/test-contract-loop-cost.ts`:
- Line 43: The test currently uses result!.hash which can throw a runtime NPE if
context.createBlock(rawSigned) returns { result: null }; add an explicit guard
before dereferencing by asserting the result is defined (e.g.,
expect(result).toBeDefined()) immediately after const { result } = await
context.createBlock(rawSigned) and similarly for the other occurrences (lines
covering the second createBlock call), then continue using result.hash; also
ensure the test uses receipt.gasUsed for per-transaction gas assertions
(receipt.gasUsed is a bigint matching TestParameters gas literals) rather than
block.gasUsed.

In `@test/suites/dev/moonbase/test-contract/test-contract-methods.ts`:
- Around line 29-31: Add an explicit assertion that tx.blockHash is non-null
before using it: after calling context.viem().getTransaction({ hash: deployHash
}) and assigning to tx, assert that tx.blockHash is defined (e.g., throw or use
expect with a clear message) so the subsequent call to context.viem().getBlock({
blockHash: tx.blockHash }) cannot silently pass a null; reference the variables
tx, deployHash and the calls to context.viem().getTransaction / getBlock when
locating the spot to insert this guard.

In `@test/suites/dev/moonbase/test-eth-tx/test-eth-tx-access-list.ts`:
- Around line 56-59: The test currently uses a non-null assertion on result from
context.createBlock which yields an unhelpful runtime error if createBlock
returns null; replace the assertion with an explicit guard: after const { result
} = await context.createBlock(txWithAL); add an if (!result) throw new
Error(...) that includes identifying context such as the transaction payload
(txWithAL), the current iteration/index if available, and any returned metadata
to make failures diagnosable; apply the same explicit-null-check pattern to the
other occurrence in T02 (the receipt lookup that uses result!.hash).

In `@test/suites/dev/moonbase/test-moon/test-moon-rpc.ts`:
- Around line 92-102: The test should source the transaction hash from the
createBlock result instead of reading block.transactions[...] to avoid races;
update the calls that use block.transactions[n] to use the hash returned by
context.createBlock (the result object from createViemTransaction) — e.g., use
result.hash (from the result returned by
context.createBlock/createViemTransaction) and optionally add a guarded
assertion that result and result.hash are present before calling
api.rpc.moon.isTxFinalized to get a clearer failure message; apply the same
change to the other occurrences mentioned (the blocks around where result is
used at the other ranges).

In `@test/suites/dev/moonbase/test-storage-growth/test-block-storage-growth.ts`:
- Around line 35-37: Update the test title string in
test/suites/dev/moonbase/test-storage-growth/test-block-storage-growth.ts to
match the assertion change: replace the existing "should fill a block with 61 tx
at most" with a title that reflects the new expectation (e.g., "should fill a
block with 264 tx at most") so the it/test description and the assertion for 264
transactions are consistent; locate the test by its current title string in the
file and update that literal accordingly.

In `@test/suites/dev/moonbase/test-subscription/test-subscription-logs.ts`:
- Line 32: Replace the non-null assertion on tx.blockHash used in the call to
context.viem().getBlock with an explicit defensive check: verify tx.blockHash is
not null before calling getBlock (e.g., if null throw or fail the test with a
clear message), so the code in the block lookup path (the getBlock call and any
logic around logs[0]) fails with a meaningful error rather than using the `!`
operator; update references to tx.blockHash in this test to use that guard and a
descriptive error mentioning the unexpected pending transaction.

In `@test/suites/dev/moonbase/test-xcm-v3/test-mock-hrmp-transact-ethereum-10.ts`:
- Around line 153-161: The test fetches ethBlock via
context.viem().getBlock(...) and then accesses ethBlock.transactions without
guarding against getBlock returning null; update the test around
injectHrmpMessageAndSeal / the ethBlock retrieval so you assert ethBlock is not
null (or throw a clear assertion) before checking ethBlock.transactions.length
to produce an explicit, informative test failure instead of a TypeError when the
block is missing.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
test/suites/dev/moonbase/test-eth-fee/test-eth-fee-history.ts (1)

153-166: T03 timeout appears over-provisioned.

T03 creates 2 blocks × 3 transactions = 6 total transactions — far less work than T02's 11 × 10 = 110 — yet both timeouts were set to 120 000 ms. Looks like a copy-paste from T02. Consider reverting T03 to a tighter bound (e.g. the original 40 000 ms or a modest 60 000 ms) to catch genuine hangs sooner.

⏱️ Proposed timeout adjustment for T03
-      timeout: 120_000,
+      timeout: 60_000,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/dev/moonbase/test-eth-fee/test-eth-fee-history.ts` around lines
153 - 166, The test's timeout is over-provisioned: in the test function that
sets block_count = 2 and creates 6 transactions (variables block_count,
reward_percentiles, priority_fees and the test async function invoking
createBlocks and customDevRpcRequest), reduce the timeout from 120_000 to a
tighter bound (e.g., 40_000 or 60_000 ms) in the test configuration so the test
fails faster on hangs while still allowing normal completion.
test/suites/tracing-tests/test-trace-erc20-xcm.ts (1)

120-127: Unguarded transactions[0] access (same as test-trace-ethereum-xcm-1.ts).

transactions[0] is accessed without confirming the array is non-empty. If the XCM transaction doesn't land as expected, transactionHash becomes undefined and the failure propagates to T01/T02 with a cryptic error.

🛡️ Proposed guard
+      expect(
+        (await context.viem().getBlock({ blockNumber: successfulXcmBlockNumber })).transactions.length
+      ).toBeGreaterThan(0);
       transactionHash = (await context.viem().getBlock({ blockNumber: successfulXcmBlockNumber }))
         .transactions[0];

Or cache the block to avoid the double fetch:

-      transactionHash = (await context.viem().getBlock({ blockNumber: successfulXcmBlockNumber }))
-        .transactions[0];
+      const successfulBlock = await context.viem().getBlock({ blockNumber: successfulXcmBlockNumber });
+      expect(successfulBlock.transactions.length).toBeGreaterThan(0);
+      transactionHash = successfulBlock.transactions[0];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/tracing-tests/test-trace-erc20-xcm.ts` around lines 120 - 127,
The code reads transactions[0] without checking the block's transactions array
which can yield undefined; change the logic to first fetch and cache the block
(const block = await context.viem().getBlock({ blockNumber:
successfulXcmBlockNumber })), then verify block.transactions &&
block.transactions.length > 0 and throw or fail with a clear error if empty,
otherwise set transactionHash = block.transactions[0]; reference the
variables/functions successfulXcmBlockNumber, transactionHash,
context.viem().getBlock and injectHrmpMessageAndSeal when locating the change.
test/suites/tracing-tests/test-trace-ethereum-xcm-1.ts (1)

113-123: Unguarded transactions[0] access.

processedBlock.transactions[0] is accessed without a length check. If the XCM transaction is absent from the block, undefined is pushed into transactionHashes silently, and the failure only surfaces later in T01 with an opaque error. The parallel file test-trace-ethereum-xcm-3.ts uses expect(txHashes.length).toBe(...) before indexing — this file should do the same.

🛡️ Proposed guard
+        expect(processedBlock.transactions.length).toBeGreaterThan(0);
         transactionHashes.push(processedBlock.transactions[0]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/suites/tracing-tests/test-trace-ethereum-xcm-1.ts` around lines 113 -
123, The test unguardedly indexes processedBlock.transactions[0] which can be
undefined; modify the block retrieval section (around processedBlockNumber,
processedBlock, and transactionHashes) to assert the block contains at least one
transaction before pushing: after calling context.viem().getBlock({ blockNumber:
processedBlockNumber }) check processedBlock &&
Array.isArray(processedBlock.transactions) && processedBlock.transactions.length
> 0 (or use an expect like
expect(processedBlock.transactions.length).toBeGreaterThan(0)) and only then
push processedBlock.transactions[0]; keep the surrounding flow that sends the
XCM via injectHrmpMessageAndSeal and uses xcmMessage unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/suites/dev/moonbase/test-eth-fee/test-eth-fee-history.ts`:
- Around line 153-166: The test's timeout is over-provisioned: in the test
function that sets block_count = 2 and creates 6 transactions (variables
block_count, reward_percentiles, priority_fees and the test async function
invoking createBlocks and customDevRpcRequest), reduce the timeout from 120_000
to a tighter bound (e.g., 40_000 or 60_000 ms) in the test configuration so the
test fails faster on hangs while still allowing normal completion.

In `@test/suites/tracing-tests/test-trace-erc20-xcm.ts`:
- Around line 120-127: The code reads transactions[0] without checking the
block's transactions array which can yield undefined; change the logic to first
fetch and cache the block (const block = await context.viem().getBlock({
blockNumber: successfulXcmBlockNumber })), then verify block.transactions &&
block.transactions.length > 0 and throw or fail with a clear error if empty,
otherwise set transactionHash = block.transactions[0]; reference the
variables/functions successfulXcmBlockNumber, transactionHash,
context.viem().getBlock and injectHrmpMessageAndSeal when locating the change.

In `@test/suites/tracing-tests/test-trace-ethereum-xcm-1.ts`:
- Around line 113-123: The test unguardedly indexes
processedBlock.transactions[0] which can be undefined; modify the block
retrieval section (around processedBlockNumber, processedBlock, and
transactionHashes) to assert the block contains at least one transaction before
pushing: after calling context.viem().getBlock({ blockNumber:
processedBlockNumber }) check processedBlock &&
Array.isArray(processedBlock.transactions) && processedBlock.transactions.length
> 0 (or use an expect like
expect(processedBlock.transactions.length).toBeGreaterThan(0)) and only then
push processedBlock.transactions[0]; keep the surrounding flow that sends the
XCM via injectHrmpMessageAndSeal and uses xcmMessage unchanged.

@librelois librelois merged commit 04a9072 into master Feb 20, 2026
40 of 41 checks passed
@librelois librelois deleted the elois/frontier-pin branch February 20, 2026 20:56
@coderabbitai coderabbitai bot mentioned this pull request Feb 21, 2026
@arturgontijo arturgontijo mentioned this pull request Feb 23, 2026
13 tasks
arturgontijo pushed a commit that referenced this pull request Feb 23, 2026
…ntier#1824 (#3677)

* update frontier pin

* Configure AllowUnprotectedTxs to false

* Fix compile error

* Temporary allow unprotected txs to not break tests

* fix dev tests

* fix tracing tests

* fix coderabbit suggestion
@arturgontijo arturgontijo mentioned this pull request Feb 24, 2026
13 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B5-clientnoteworthy Changes should be mentioned in any downstream projects' release notes D2-notlive PR doesn't change runtime code (so can't be audited) not-breaking Does not need to be mentioned in breaking changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v0.50.0 frequent null response to eth_getBlockByNumber method with "latest" params when repeat requests are sent to the node

2 participants