github paritytech/polkadot-sdk polkadot-stable2603-rc1
Polkadot stable2603-rc1

pre-release9 hours ago

This release contains the changes from polkadot-stable2512-1 to polkadot-stable2603-rc1.

⚠️ Warning: Pre-release Version

The currently published version is a pre-release and is not yet a final stable version. This release is provided for testing purposes only, and there is no guarantee that everything will work as expected. Errors and unusual behaviours of some features are to be expected.

Please use this version at your own risk and report any issues you encounter. We recommend waiting for the official release if you need a stable version.

Changelog

Changelog for Node Dev

ℹ️ These changes are relevant to: Those who build around the client side code. Alternative client builders, SMOLDOT, those who consume RPCs. These are people who are oblivious to the runtime changes. They only care about the meta-protocol, not the protocol itself.

[#10223]: Removed dependency to sp-consensus-grandpa from sc-network-sync

Refactored warp sync to remove the dependency on GRANDPA consensus primitives from the network sync module.
Instead of directly verifying proofs with GRANDPA-specific parameters, warp sync now uses a more generic
verifier pattern. This makes the warp sync implementation independent of any specific consensus mechanism,
allowing it to work with different consensus algorithms in the future.

[#10690]: statement-store: implement new rpc api

Implements the new simplified RPC API for the statement store as proposed in PR #10452.
The API surface has been reduced to two main functions: submit and subscribe_statement.

Submit changes:

  • Added support for the new expiry field where statements with an expiration timestamp
    lower than the current time are rejected.

Subscribe changes:

  • Implemented a configurable worker pool that manages all subscriptions.
  • New subscriptions are assigned to workers via a round-robin protocol.
  • When a new statement is accepted by the statement-store, all workers are notified and
    evaluate their assigned subscription filters, notifying each subscriber accordingly.
  • Existing statements matching the filter are sent on subscription.

Additional improvements:

  • Added periodical scanning and removal of expired statements.
  • Removed the old API methods (broadcast, posts, networkState, etc.) in favor of the
    simplified submit/subscribe interface.

[#10796]: Fix size limit mismatch in process_initial_sync_burst

Fixes a debug assertion failure in process_initial_sync_burst where the size filter
used MAX_STATEMENT_NOTIFICATION_SIZE while find_sendable_chunk reserved additional
space for Compact<u32> vector length encoding (5 bytes).

This mismatch caused debug_assert_eq!(to_send.len(), sent) to fail when statements
were sized to fit the filter's larger limit but exceeded find_sendable_chunk's
stricter limit.

The fix extracts the size calculation into a shared max_statement_payload_size()
function that both locations now use, ensuring consistent size limits.

[#10770]: Statement-store: Follow-up improvements from PR #10718 review

This follow-up PR addresses review comments from PR #10718:

  • Removed unnecessary Result wrapper from statement_hashes() - method is infallible
  • Added debug assertion to validate sent count matches prepared count

[#10906]: collator-protocol: Remove stale pending collations from the waiting queue

This PR removes the stale pending collations from the waiting queue when the peer that advertised the collation disconnects.

When the peer reconnects, the peer data is freshly created without any prior information about advertised collations.
Then the state-pending collation is picked from the queue. The network request will not be emitted since the fn fetch_collation sees no prior advertisement via peer_data.has_advertised and returns Err(FetchError::NotAdvertised).

To avoid this, remove the stale entries immediately when the peer disconnects.

Part of the stabilization of:

[#10779]: remote-externalities: Support downloading from multiple RPC servers in parallel + major refactoring

Major refactoring of frame-remote-externalities to support downloading state from multiple
RPC servers in parallel. This improves reliability and performance when fetching remote state.

Breaking changes:

  • OnlineConfig::transports field renamed to transport_uris
  • Various internal API changes

[#10891]: collator-protocol: Re-advertise collations when peer authority IDs are updated

The collator protocol contained a race-condition which could manifest as "Collation wasn't advertised".

A given peer ("A") can connect before the new authority keys are received via UpdatedAuthorityIds (nk -- new key).

  • T0: peer A connectsPeerConnected
  • T1: peer A sends its current view PeerViewChange
    • Peer A wants the block N
  • T2: validator_group.should_advertise_to: checks peer A for key nK (the new key)
    • We don't have this key stored and therefore return ShouldAdvertiseTo::NotAuthority
  • T3: UpdatedAuthorityIds arrives with (peer A, [nK])

At this point, we have the collation, peer A wants to collation, we know peer A is an authority but we never send the collation back. Then, the collation will expire with "Collation wasn't advertised".

To close the gap, the UpdatedAuthorityIds events will trigger a re-advertisement of collations

  • note: if the advertisement was already sent, the logic does not resend it (achieved in should_advertise_to).

Part of the stabilization of:

[#10954]: auth-discovery: Ensure DHT published addresses have ports

We have seen instances in production where validators will propagate multiaddresses without ports.
These addresses are effectively unreachable from the networking layer perspective.
They might be discovered via:

  • identify protocol
  • or simply a wrongly configured CLI for public addresses

To close the gap on this issue, this PR checks that the published addresses will always contain a port.

Closes:

Part of:

[#10464]: collator-protocol: Readvertise collations after peer disconnects

There's a possible race case between peer connectivity and collation advertisement:

  • The advertisement was generated
  • peer disconnected before receiving the advertisement

As a result of that, when the peer reconnects, the previous collation (C0) is not sent.
This happens when the collator has produced another collation (C1).
However, from the logs it looks like the collation C1 is advertising, but C0 is skipped.

  • T0: peer disconnects without receiving C0
  • T1: peer reconnects
  • T2: collator advertises C1, but not C0

This PR aims to resubmit collations on PeerConect events to mitigate these cases

Closes #10463

[#10974]: slot_timer: Downgrade spammy log to debug

The log is quite spammy with 12core setup since the last ~2 blocks will be skipped in the last second of block production.

[#10718]: Statement-store: Propagate all statements to newly connected peers

When a new node connects, we now propagate all statements in our store to them. This happens in bursts of ~1MiB messages
over time to not completley use up all resources. If multiple peers are connecting, round robin between them.

[#10513]: Extract parachain types into a dedicated crate

Closes #10512.

Moves the common parachain primitives (accounts, balances, hashes, opaque block types) into a new parachains-common-types crate. The existing parachains-common crate re-exports these definitions, and polkadot-omni-node-lib now depends on the lightweight types crate to avoid pulling runtime pallets into omni-node builds.

[#10662]: Bulletin as parachain missing features

  • Node developers/operators could enable the transaction storage inherent data provider setup by using --enable-tx-storage-idp flag. This is especially useful in the context of bulletin chain.
  • Node developers will set up the network idle_connection_timeout to 1h when using --ipfs-server flag, again, useful in the context of bulletin chain.

[#9880]: ah-westend: Elastic Scaling with 3 cores on AssetHub Westend

This PR enables elastic scaling on AssetHubWestend with 3 bulk cores.

Guideline for enablement: https://paritytech.github.io/polkadot-sdk/master/polkadot_sdk_docs/guides/enable_elastic_scaling/index.html

Next Steps

  • Ensure collators are running with 2509 or newer
  • Double check the changes locally
  • If AH Westend looks good, we'll enable ES to AHPaseo

cc @paritytech/sdk-node @sandreim

[#10882]: statement-store: make encode/hash faster

Optimizes statement encoding and hashing by pre-allocating memory for the encoded buffer.
This reduces allocation overhead and improves performance, particularly when receiving
statements from multiple peers. Benchmarks show ~16% speedup when receiving statements
from 16 peers.

[#10763]: Make some BEEFY keystore logic more generic

This PR:

  1. makes some BEEFY keystore methods more generic:
  • sign()
  • public_keys()
    This is done by implementing the specific logic in the BeefyAuthorityId.
  1. Removes the BeefyAuthorityId::SignatureHasher since for some algorithms it doesn't make sense to have a hasher.

Also since now the BeefyAuthorityId implements both the signing and the verification logic, we should have better consistency.

Related to #8707 (comment)

[#10542]: statement-store: Add latency bench

Adds a latency benchmark for the statement store to measure propagation performance across distributed nodes.

[#10846]: net/metrics: Add metrics for inbound/outbound traffic

This PR adds a new metric for inbound / outbound traffic for individual request-response protocols.

  • the PR is motivated by #10765 which shows a significant number of bytes as downloaded (4-5 MiB/s). This is suspicious for a fully synced validator, 1-2 blocks to the tip of the chain.
  • It suggests a protocol is internally consuming too much bandwidth leading to network inefficiencies, wasted CPU, and in the case of the issue to OOM kills

cc @paritytech/sdk-node

[#10785]: Fix inefficient do_propagate_statements

Fixes an O(n^2) complexity issue in send_statements_in_chunks. The loop in
find_sendable_chunk was inefficient because it was passing to_send[offset..]
after each chunk and then calling chunk.encoded_size() on the entire slice.

The fix uses an incremental approach that adds statements one by one until the
size limit is reached, only computing sizes for statements that will actually
be sent in each chunk.

For 300,000 statements, this reduces the processing time from ~2.5 seconds to ~0.33s.

[#10787]: statement-store: validation without runtime

This removes slow runtime validation from statement-submission hot path.
Validation now happens on the node side via direct signature verification
and storage reads for account quotas.

[#10960]: Warn when dropping an out of view candidate

This changes a debug log to a warning. The other log messages around the candidate state are also partially warnings. A candidate that is directly out of view counts clearly as a warning. Besides that this pull request also increases
the lookahead for Westend + Rococo to 5 to align it with Kusama.

[#10661]: statement-store: Add networking benchmark

Adds a benchmark for the statement store networking to measure performance
of statement propagation and validation under various conditions.

[#10965]: fatxpool: Do not remove listener for finalized view

The transaction pool is now able to handle events for active but finalized views. This improves transaction handling for manual-seal nodes which immediately finalize.

[#10658]: Omninode instant seal: Support relay parent offset

This brings support for relay parent offset to the omni-node instant seal consensus engine. Before instant seal was not working with relay parent offsets bigger than 0.

[#10201]: telemtry: Downgrade spam log to debug

This PR downgrade the telemetry warning log to debug.

[#10421]: statement-store: New RPC result types

Moved submission failures from JSON-RPC errors into structured result types:

  • Internal submission result type changed to hold more information for clients.
  • The "statement_submit" method now returns enum with clear status variants (New, Known, Invalid, Rejected).
  • NetworkPriority removed as we never used it.
  • Updated and simplified the reputation system.
  • Runtime API wasn't changed.

[#10755]: Fix polkadot-omni-node dev mode slot mismatch panic

Fixes a panic when running polkadot-omni-node in dev mode with parachains
that have slot durations different from the relay chain (e.g., 12s vs 6s).
The mock relay chain data now correctly accounts for the slot duration ratio.

[#10847]: net: Spawn network backend as essential task

This PR spawns the network backends as essential (libp2p / litep2p).

When the network future exits, it will bring down the whole process.

  • there's no point in running a node without the core network backend as it will not be able to communicate with peers
  • while at it, have changed some logs from debug to warn
  • the network backend can be brought down unintentionally by the import_notif_stream

Discovered during:

[#9947]: Proposer/BlockBuilder: Accept proof recorder & extensions

This pull request fundamentally changes how Proposer and BlockBuilder are handling the proof recorder and extensions. Before this pull request the proof recorder was initialized by the BlockBuilder and the proposer statically enabled proof recording or disabled it. With this pull request the proof recorder is passed from the the caller down to the block builder. This also moves the responsibility for extracting the final storage proof to the caller and is not part of the block builder logic anymore. The extensions are now also configurable by the caller and are not longer "guessed" by the block builder.

This pull request also remvoes the cumulus-client-proposer crate as it is not really required anymore.

[#10827]: Add more buckets to histogram for bitfields sent

Description

image On Kusama the chart already goes to infinity, so we need to adjust it to the desired value.

Integration

Should not affect downstream projects.

[#10573]: Bump trie-db to 0.31.0

Bumps trie-db to 0.31.0 and trie-bench to 0.42.1.

[#10807]: Omni-node: Move timestamps closer to now

Blocks produced with Omni-nodes dev-mode are now closer to the current time. Previously they were starting at UNIX_EPOCH.

[#10973]: cumulus: Remove max_depth for the parent search

We were just incrementing this number all the time and there is actually no need to have it, as the search is already automatically bounded. For chains with 500ms blocks and relay offset of 1 we easily go above this limit and this then leads to forks.

So, let's remove the value.

[#11020]: Block Response Handler: Take protocol overhead better into account

We now take the protobuf overhead into account.

[#10617]: statement-store: use many workers for network statements processing

Adds --statement-network-workers CLI parameter to enable concurrent statement validation from the network.
Previously, statements were validated sequentially by a single worker. This change allows multiple workers
o process statements in parallel, improving throughput when statement store is enabled

[#10493]: add external transient_storage to pallet_revive::ExecConfig

Description

This PR adds the ability to supply external copy of TransientStorage to pallet_revive::ExecConfig to be used during execution.
This is required by testing in foundry as we only enter pallet_revive during a CALL or CREATE instruction and we need to carryover
the transient storage to other following calls as they happen within an external tx.
For example this is required to support more testing scenarious inside foundry-polkadot because only a subset of execution happens on pallet-revive.
e.g:

fn example_test() { // this entrypoint is executed on the side of `foundry-polkadot`
Example contract = new Example(); // happens on pallet-revive
contract.setTransientStorage(5); // happens on pallet-revive

uint256 result = contract.getTransientStorage(); // happens on pallet-revive and returns `0` aka the default value 
// `result` above is `0` because `transient_storage` is reset after every call to `pallet-revive` and in `foundry-polkadot`
// only `CALL` and `CREATE` within function calls(already executed on foundry's revm) are forwarded to `pallet-revive`,
// so for assertion below to pass we would need to have our external `transient_storage` instance to be manually supplied
// to pallet-revive and be persistent within the wrapping call
assertEq(5, result); // fails without this PR with `5 != 0` 
}

link for the test-file inside foundry-polkadot:

Changelog for Runtime Dev

ℹ️ These changes are relevant to: All of those who rely on the runtime. A parachain team that is using a pallet. A DApp that is using a pallet. These are people who care about the protocol (WASM, not the meta-protocol (client).)

[#10971]: Implement IERC20Metadata for pallet-assets precompiles

Implements the missing ERC20 metadata functions (name, symbol, decimals) for the
pallet-assets precompile to provide full ERC20 compatibility. These functions are essential
for proper EVM wallet and tooling integration.

The precompile implementation reads metadata from pallet-assets storage and returns properly
formatted values with appropriate gas charging using dedicated weight functions. All functions
include proper error handling for missing metadata and invalid UTF-8 encoding.

Benchmarks have been added to measure the weight of metadata reads, and corresponding weight
functions have been implemented in the WeightInfo trait.

The IERC20.sol interface file has been reorganized to clearly separate and document methods
from the base IERC20 interface and the IERC20Metadata extension, with links to the original
OpenZeppelin contracts for better maintainability.

[#10842]: Remove unused code in staking-async

  • remove the reward-fn from pallet-staking-async. This crate is no longer needed.
  • rename ahm-test to integration-tests

[#10739]: build & deploy eth-rpc docker image for stable release

build and deploy eth-rpc docker image for stable branches

[#10843]: Expand multisig pallet tests

Expand the multisig pallet tests to cover more cases. In particular, those concerning out-of-order signatories,
and sender in signatories. Also, reword extrinsic comments.

[#10749]: [pallet-revive] fixtures compilation fix for rust 1.92.0

Fix this error after upgrading to rustc 1.92.0:

  error: panic_immediate_abort is now a real panic strategy! Enable it with `panic = "immediate-abort"` in Cargo.toml, or with the compiler flags `-Zunstable-options -Cpanic=immediate-abort`. In both cases, you still need to build core, e.g. with `-Zbuild-std`
    --> /Users/robert/.rustup/toolchains/1.92.0-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/panicking.rs:36:1

[#10635]: [pallet-revive] remove unstable host function sr25519_verify

fixes part of #8572

[#10902]: [pallet-revive] Enforce weight limit on dry-run RPC calls

Summary

  • Makes the weight_limit field in TransactionLimits::EthereumGas non-optional, enforcing bounded execution on all Ethereum-style calls
  • Updates dry_run_eth_transact to use evm_max_extrinsic_weight() as the weight limit, preventing unbounded computation during dry-run RPC calls
  • Simplifies metering code by removing Option handling for weight limits in Ethereum execution mode

[#10693]: refund deposit_eth_extrinsic_revert_event on the base_weight

When an eth transaction succeed we refund the pre-charged revert_event.
The refund should be done on the base weight and not the weight_consumed, as the latest could be lower than the cost of the revert_event

[#10713]: Fix off-by-one error in child bounty limit validation

Fixes an off-by-one error in pallet-child-bounties where the add_child_bounty
function allowed creating MaxActiveChildBountyCount + 1 child bounties instead of
being capped at MaxActiveChildBountyCount.

The validation check used <= instead of <, allowing the count to exceed the limit
by one. This fix changes the comparison to < and removes an unnecessary type cast.

This is a bug fix that ensures runtime configuration limits are properly enforced.

Fixes #10652

[#10950]: fix(revive): handle transaction hash conflicts during re-org

Summary

Fixes a UNIQUE constraint violation when processing blocks after a re-org:

UNIQUE constraint failed: transaction_hashes.transaction_hash

Problem

When a blockchain re-org occurs:

  1. Block A contains transaction TX1 → stored in transaction_hashes
  2. Server restarts (clearing the in-memory block_number_to_hashes map)
  3. Re-org happens, Block B (different hash) now contains the same TX1
  4. INSERT fails because TX1 already exists with old block_hash

[#10396]: ExecuteBlock split up seal verification and actual execution

ExecuteBlock exposes the execute_block function that is used by validate_block to execute a block. In case auf AuRa the block execution includes the verification of the seal and the removal of the seal. To verify the seal, the block executor needs to load the current authority set. The problem is that when we have storage proof reclaim enabled and the host function is used in on_initialize before pallet_aura_ext::on_initialize (this is where we fetch the authority set to ensure it appears in the proof) is called, it leads to validate_block returning a different size and thus, breaking the block. To solve this issue ExecuteBlock is now split into seal verification and execution of the verified block. In validate_block the seal verification is then run outside of the block execution, not leading to the issues of reporting different proof sizes.

[#10712]: [pallet-revive] remove code related to stable and unstable_hostfn

Part of #8572

Removes the proc macro unstable_hostfn and attribute #[stable] because they are not used anywhere.

[#10387]: pallet-revive: add DebugSetting for bypassing eip-3607 for contracts and precompiles

Adds a new DebugSetting option which, if enabled, allows transactions coming from contract accounts or precompiles.
This is needed so that test nodes like anvil can send transactions from
contract or precompile accounts, a widely-used feature in tests.

[#10804]: Take the header size into account for the total block size

The BlockSize storage item (formerly AllExtrinsicsLen) in frame-system now includes the header overhead (digest size and
empty header size) in addition to the extrinsic lengths. This ensures that block size limits
accurately account for the full block size, not just the extrinsics. Additionally, inherent
digests are now limited to 20% of the maximum block size to prevent oversized headers.

Breaking Change: AllExtrinsicsLen has been renamed to BlockSize to better reflect its purpose.
External code using frame_system::AllExtrinsicsLen must be updated to use frame_system::BlockSize.

The deprecated BlockLength::max and BlockLength::max_with_normal_ratio functions have been
replaced with the new builder pattern across the entire codebase. Use
BlockLength::builder().max_length(value).build() or
BlockLength::builder().max_length(value).modify_max_length_for_class(DispatchClass::Normal, |m| *m = ratio * value).build()
instead.

[#10475]: try state check for pallet authority discovery

This PR introduces the try_state hook to pallet-authority-discovery to verify key storage invariants.

closes part of #239

[#10366]: [pallet-revive] update evm create benchmark

Add a benchmark for the EVM CREATE instruction.

We are currently reusing the seal_instantiate benchmark from PVM instantiation, which is incorrect because instantiating an EVM contract takes different arguments and follows a different code path than creating a PVM contract.

This benchmark performs the following steps:

  • Generates init bytecode of size i, optionally including a balance with dust.
  • Executes the init code that triggers a single benchmark opcode returning a runtime code of the maximum allowed size (qrevm::primitives::eip170::MAX_CODE_SIZE`).

[#10732]: Use the revive-differential-tests reusable action

Description

This PR changes how we run differential tests. The revive-differential-tests repo now ships with a reusable action which we use to run the differential tests.

[#10986]: [Pool] Use active era for withdrawals

Standardising using active era in pools and staking. Current Era should only be used for election logic

[#10554]: [pallet-revive] add EVM gas call syscalls

This PR adds two new syscalls for calls accepting EVM gas instead of Weight and Deposit.

This is an important change for the initial release as it will align PVM contracts closer to EVM (the problem can't be solved in the Solidity compiler).

[#10686]: Weight: Put must_use above some of the functions

Some functions return the modified weight and the user must use this or the changes are lost. This way the compiler informs the user.

[#10393]: Add configuration to set Ethereum gas scale

This PR adds a new configuration parameter (GasScale) to pallet-revive that allows to change the scale of the Ethereum gas and of the Ethereum gas price.

Before this PR, the Ethereum gas price is simply the next fee multiplier of pallet-transaction-payment multiplied by NativeToEthRatio. Thus, on Polkadot this is 100_000_000 when the multiplier has its default value of 1.

The required gas of a transaction is its total cost divided by the gas price, where the total cost is the sum of the transaction fee and the storage deposit.

This leads to a situation where the required gas for a transaction on revive is usually orders of magnitude larger than the required amount of gas on Ethereum. This can lead to issues with tools or systems that interact with revive and hard code expected gas amounts or upper limits of gas amounts.

Setting GasScale has two effects:

  • revive's Ethereum gas price is scaled up by the factor GasScale
  • resulting used/estimated gas amounts get scaled down by the factor GasScale.

Technical Details

Internally, revive uses exactly the same gas price and gas units as before. Only at the interface these amounts and prices get scaled by GasScale.

Recommended

This PR sets GasScale for the dev-node to 50_000.

This is motivated by the fact that storing a value in a contract storage slot costs DepositPerChildTrieItem + DepositPerByte * 32, which is 2_000_000_000 + 10_000_000 * 32 (= 2_320_000_000) plancks. Before this change the gas price was 1_000_000 wei, so that this
equated to 2_320_000_000 gas units. In EVM this operation requires 22_100 gas only.

Thus, GasScale would need to be about 100_000 in order for SSTORE to have similar worst case gas requirements.

Resolved Issues

This PR addresses paritytech/contract-issues#18 but we also need to find an appropriate GasScale for a mainnet installment of pallet-revive.

[#10505]: pallet-aura: Extend try_state to also check CurrentSlot

This ensures that CurrentSlot matches timestamp / slot_duration. Which is especially important to ensure that no one changed the SlotDuration.

[#10866]: Extend remote externalities Client and child storage query unit tests

This PR fixes a test failure in the remote externalities crate concerning optionality of child key loading.
It also adds follow-up tests to #10779 to check Client construction from valid/invalid URIs.

[#10905]: Bump pallet-staking-reward-fn

sp-arithmetic was bumped in a previous PR but not published yet on crates.io.
Both polkadot-runtime-common (already bumped and not released in a previous PR) and pallet-staking-reward-fn depend on it.
Bump pallet-staking-reward-fn so that parity-publish CI job can correctly resolve sp-arithmetic.
Without this fix, we would end up with a dependency graph with two versions of sp-arithmetic with one of the two missing a trait impl needed by polkadot-runtime-common.

[#10662]: Bulletin as parachain missing features

This PR adds the required support and features for running Bulletin as a parachain. It is a top-level PR that merges three partial features:

  1. Add transaction_index::HostFunctions with NO-OP impl to the cumulus ParachainSystem validate_block for polkadot-prepare/execute-worker
  2. Add custom inherent provider for pallet-transaction-storage to omni node
  3. Configurable RetentionPeriod feeded to the inherent provider over runtime API

This PR also refactors pallet-transaction-storage and sp-transaction-storage-proof (the new_data_provider inherent provider), both of which rely on a hard-coded DEFAULT_RETENTION_PERIOD. This PR:

  • adds a new configurable argument retention_period to the new_data_provider
  • introduces the TransactionStorageApi::retention_period runtime API, which the runtime can specify arbitrary
  • provides an example of using new_data_provider, with the node client calling the runtime API when constructing inherent provider data

[#10980]: Add StakingOperator proxy type to Westend AssetHub

Introduces StakingOperator proxy type that allows validator operational tasks (validate, chill, kick) and session key management (set_keys, purge_keys) without access to fund management operations.

This enables pure proxy stashes to delegate validator operations: now that pallet_staking_async_rc_client provides
set_keys/purge_keys on AssetHub, pure proxies can fully utilize StakingOperator.

[#10682]: add must_use attributes

Add must_use attributes on arithmetic fns

[#10830]: Rework EC Hostcalls

Rework all elliptic curve hostcalls: BLS12-381, BLS12-377, BW6-761,
Ed-on-BLS12-377, and Ed-on-BLS12-381-Bandersnatch.

Changes:

  • Use affine representation for point arguments instead of projective.
    mul_projective_* hostcalls renamed to mul_* and now accept/return
    affine points. msm_* hostcalls now return affine points.
  • Eliminate host-side memory allocation. Hostcalls now take an output
    buffer parameter (&mut [u8]) instead of returning allocated memory.
  • Hostcalls now return Result<(), Error> (marshaled as u32) to signal
    success or error conditions.

New pass-by strategy (in sp-runtime-interface):

  • PassFatPointerAndWrite: Passes a mutable buffer pointer to the host.
    The host creates a zero-initialized buffer, the host function writes to it,
    and the result is written back to guest memory.

[#10567]: [Revive] Fix construction of negative zero SignedGas

Closes https://github.com/paritytech-secops/srlabs_findings/issues/603

This fixes an issue where a zero SignedGas value can be constructed that uses the Negative variant. The rest of the code relies on the invariant that zero SignedGas has always the Positive variant and this is also documented in the code.

[#10166]: Implement general gas tracking

This PR implements the general gas tracking spec.

This PR ballooned into something much bigger than I expected. Many of the changes are due to the fact that all tests and a lot of the other logic has some touch points with the resource management logic. Most of the actual changes in logic are just in the folder metering of pallet-revive.

The main changes are that

  • Metering now works differently depending on whether the transaction as a whole defines weight and deposit limits ("Substrate execution mode") or just an Ethereum gas limit ("Ethereum execution mode"). The Ethereum execution mode is used for all eth_transact extrinsics.
  • There is a third resource (in addition to weight and storage deposits): Ethereum gas. In the Ethereum execution mode this is a shared resource (consumable through weight and through storage deposits).

Metering logic

Almost all changes in this PR are confined to the folder metering of pallet-revive. Before this PR there were two meters: a weight meter and a gas meter. They have now been combined into a main meter called ResourceMeter. Outside code only interacts with the ResourceMeter and not individually with the gas or storage meter. The reason is that in Ethereum execution mode gas is a shared resource and interacting with one meter influences the limits of the other meter.

Here are some finer points:

  • The previous code of the gas and deposit meters has been moved to the metering folder
  • Since outside code interacts only with the ResourceMeter, most functions now don't use a separate gas meter and deposit meter anymore but just a ResourceMeter
  • Similar to the two two kinds of deposits meters (Root and Nested), there are two kind of ResourceMeter: the top-level TransactionMeter used at the beginning of a transaction and a FrameMeter used once per frame
  • The limits of a TransactionMeter are specified through the TransactionLimits type, which distinguishes between Substrate and Ethereum execution mode.
  • The limits of a FrameMeter is specified through the type CallResources, which can either be a) no limits (e.g., in the case of contract creation), or b) a weight and deposit, or c) a gas limit.
  • The top level name of functions in the meters has been changed to be a bit more explicit about their purpose.
    • This applied particularly to the methods at the end of the lifecycle:
      • enforce_limit has been renamed to finalize as that describes the semantics better
      • try_into_deposit has been renamed to execute_postponed_deposits
  • For absorbing a frame meter into its parent meter, there are two different absorption functions:
    • absorb_weight_meter_only: when a frame reverts. In this case we ignore all storage deposits from the reverting frame. We still need to absorb the observed maximum deposit so that we determine the correct maximum deposit during dry running.
    • absorb_all_meters: when a frame was successful
  • The weight meter now has an effective_weight_limit, which needs to be recalculated whenever the deposit meter changes and is for optimization purposes.
  • The limits of the gas meter and deposit meters are now an Option<...>. When it is None, then this represents unlimited meters and this is only used for Ethereum style executions (the meters are not really unlimited, there will be a gas limit that effectively limits the resource usages of the weight and deposit meters).
  • In the weight meters, the sync_to_executor and sync_from_executor are a bit simplified and there is no need for engine_fuel_left anymore.

Other Changes

  • The old name gas for weights has been consistently replaced by weight
  • eth_call and eth_instantiate_with_code now take a weight_limit (used to ensure that weight does not exceed the max extrinsic weight) and an eth_gas_limit (the new externally defined limit)
  • The numeric calculation in compute_max_integer_quotient and compute_max_integer_pair_quotient (defined in substrate/frame/revive/src/evm/frees.rs) are meant to divide a number by the next fee multiplier
  • The call tracer does not take a GasMapper anymore as it will now be fed directly with the Ethereum gas values instead of weights
  • Re-entrancy protection now has three modes: no protection, Strict protection and AllowNext
    • AllowNext allows to re-enter the same contract but only for the next frame. This is required to implement reentrancy protection for simple transfers with call stipends
    • For Strict protection we set allows_reentry of the caller to false before the creation of the new frame, for AllowNext we to it after the creation
  • We define the max block gas as u64::MAX (as discussed with @pgherveou)
  • I now calculate the maximal required storage deposits during dry running (called max_storage_deposit in the deposit meter). For example, if a transaction encounters a storage deposit that is later refunded, then the total storage deposit is zero. However, the caller needs to provide enough resources so that temporarily the execution does not run out of gas and terminates the call prematurely.
  • The function try_upload_code now always takes a meter and records the storage deposit charge there
  • In this PR I added logic to correctly handle call stipends (this fixes paritytech/contract-issues#215)

Fixes

This fixes a couple of issues

TODOs

  • Ignore deposit refunds for dry running
  • Properly enforce weight limits
  • Fix gas mapping in the tracer
  • Fix (?) gas mapping in block storage (with_ethereum_context)
  • Check dry running logic again, and create_call, also in ExecConfig
  • Introduce SignedGas
  • use effective_gas_price instead of next fee multiplier
  • ensure that deducted amount is effective_gas_price * used gas
    • this has already been addressed in #10148
  • check logic of ensure_not_overdrawn
  • Optimize calculations
  • Check whether rounding is done correctly
  • add debug logging
  • Scale gas amounts charged in revm
    • this has been addressed in another PR: #10393

Other TODOs

  • fix tests and benchmarks
  • add new tests
  • add code docs
  • resolve merge conflicts
  • run benchmarks
  • add PR description

[#8175]: Snowbridge V2: Generic inbound message processing

Description

This PR adds a new MessageProcessor type to the inbound-queue-v2 pallet's config.

This type allows to make the processing of inbound messages more generic, via the (also new) MessageProcessor trait, which contains the following functions:

  • can_process_message: a custom (light) preliminary check to ensure that the message can be processed without the need of entering the full process_message implementation yet.
  • process_message: actually performs the custom inbound message processing logic.

Motivation

At the moment of inbound message processing, it might be the case that, for instance, there is no need to perform any XCM related logic, as it could happen in solo-chain contexts.
By making use of the functionality included in this PR, projects using Snowbridge can leverage this customization, implementing any kind of processing they need for inbound queue messages in a more flexible way.

Note: XcmPayload's name change

In this PR I also included a small name change for the XcmPayload enum. The proposed name it's just a plain Payload, and it still contains the same fields as before.
The reason for this change is to generalize the concept of "raw" bytes we receive in the first variant. At the moment of processing an inbound message, this bytes could be used not only as XCM but also as other kind of data.
This change doesn't imply further changes on the current Snowbridge smart contract implementations.

[#10780]: Fix pallet-revive-fixtures

Fixing two issues:

  1. Build on rustc >= 1.92 was broken despite #10749. That PR was broken.
  2. The nested cargo didn't properly inherit the parent toolchain (an older error). Leading to the situation where a 1.88 was only applied to the parent toolchain

Replacement for #10778.

[#10451]: Accept custom capacity for block notifier buffer

Add a setter for a custom block notifier

[#10663]: [WIP][pallet-revive] replaced binary erc20 fixtures with solidity fixtures

fixes #8566

[#10831]: Fix fee handling of pay-over-xcm trait(s)

Changed how pay-over-xcm is handling delivery fees. The old behavior was effectively allowing free delivery for any origin, and it was either burning innexistent tokens (noop at the end of the day), or it was minting "protocol fees" into the treasury account out of thin air.

In practice, the traits were always used with waived fees configuration so this bug was never exploitable in production, but it was there nonetheless.

Changed transfer-over-xcm and pay-over-xcm implementations to use the runtime's XCM config, rather than custom Router and FeeHandler. This reduces the opportunity for misconfiguration since it relies on the message delivery and fee handling configurations at consolidated at the runtime configuration level.

Waived locations for some system pallets were also correctly configured to explicitly allow what was previously implicitly allowed by the buggy code.

[#10399]: Limit the authority to adjust nomination pool deposits

Up until this point, when EDs of chains using nomination pools were reduced, the subsequent reward account funds in exces could be claimed by anyone, despite the fact that they had been typically provided at the beginning by the pool owner. We therefore limit access to these funds only to the pool owner and the (optional) root account when EDs get reduced. The restriction does not apply to the increase in EDs, as these imply that funds are transferred into the pool rather than out of it.

[#9722]: [pallet-revive] opcode tracer

This PR introduces a Geth-compatible execution tracer (StructLogger) for pallet-revive

The tracer can be used to capture both EVM opcode and PVM syscall.
It can be used with the same RPC endpoint as Geth StructLogger.

Since it can be quite resource intensive, It can only be queried from the node when the DebugSettings are enabled (This is turned on now by default in the dev-node)

Tested in paritytech/evm-test-suite#138

example:

❯ cast rpc debug_traceTransaction "<TX_HASH>" | jq

# or with options
# See list of options https://geth.ethereum.org/docs/developers/evm-tracing/built-in-tracers#struct-opcode-logger

 ❯ cast rpc debug_traceTransaction "<TX_HASH>", { "tracer": { "enableMemory": true } } | jq

The response includes additional fields compared to the original Geth debug RPC endpoints:

For the trace:

  • weight_consumed: same as gas but expressed in Weight
  • base_call_weight: the base cost of the transaction

For each step:

  • weight_cost: same as gas_cost but expressed in Weight

For an EVM execution, the output will look like this

{
  "gas": 4208049,
  "weight_consumed": { "ref_time": 126241470000, "proof_size": 4208 },
  "base_call_weight": { "ref_time": 9000000000, "proof_size": 3000 },
  "failed": false,
  "returnValue": "0x",
  "structLogs": [
    {
      "gas": 4109533,
      "gasCost": 3,
      "weight_cost": { "ref_time": 90000, "proof_size": 0 },
      "depth": 1,
      "pc": 0,
      "op": "PUSH1",
      "stack": []
    },
    {
      "gas": 4109530,
      "gasCost": 3,
      "weight_cost": { "ref_time": 90000, "proof_size": 0 },
      "depth": 1,
      "pc": 2,
      "op": "PUSH1",
      "stack": [
        "0x80"
      ]
    },
    {
      "gas": 4109527,
      "gasCost": 3,
      "weight_cost": { "ref_time": 90000, "proof_size": 0 },
      "depth": 1,
      "pc": 4,
      "op": "MSTORE",
      "stack": [
        "0x80",
        "0x40"
      ]
    }]
}

For PVM execution, each step includes additional fields not present in Geth:

  • args: Array of syscall arguments (register values a0-a5) as hex strings
  • returned: The syscall return value

These fields are enabled by default. To disable them, use disableSyscallDetails: true.

Example output with syscall details:

{
  "gas": 97108,
  "gasCost": 131,
  "weight_cost": { "ref_time": 3930000, "proof_size": 0 },
  "depth": 1,
  "op": "call_data_load",
  "args": ["0x0", "0x4"],
  "returned": "0x2a"
}

[#10511]: Minor pallet-scheduler documentation/unit test additions

This PR changes the Rust documentation of some extrinsic calls in the scheduler pallet.

It also adds some checks to the Lookup<T> storage item in a unit test to named task cancellation via
the anonymous cancellation call, and a unit test for the rescheduling of a failed named/anonymous task
to a full agenda.

[#10444]: Improve charge_transaction_payment benchmark ergonomics

Adds a setup_benchmark_environment() hook to allow runtimes to configure
required state before running the benchmark (e.g., setting block author for
fee distribution). Also fixes amount_to_endow calculation to use actual
computed fee and ensure it meets the existential deposit.

[#10593]: Align Common Functions between Bulletin and SDK

The PR aligns common functions between Bulletin and SDK.

[#10793]: Snowbridge: Fix fork version slot selection for sync committee signature verification

Fixes fork version selection for sync committee signature verification to use signature_slot - 1 per the Ethereum Altair light-client spec. This prevents valid light client updates from being rejected at fork activation boundaries.

[#10454]: staking: do not remove an invulnerable in case of bad solution

Invulnerables are not automatically removed from the Invulnerables storage when their solution is rejected.
Removal should occur only through governance, not automatically.
An operational or network issue that leads to an incomplete submission is much more likely than a bad faith action from an invulnerable.

[#10958]: Enforce match_arm_blocks = true for consistent formatting

Flips match_arm_blocks from false to true in rustfmt configuration to ensure
all multi-line match arm bodies are wrapped in braces consistently.

This is a formatting-only change with no functional impact. It enforces a single
valid style for match arms, eliminating ambiguity that caused unnecessary diffs
when LLMs generated code with braces.

[#10471]: [Revive] Change default value of eth_getStorageAt

Closes paritytech/contract-issues#230

With this change eth_getStorageAt of the eth rpc always returns a 32 byte array. If the storage slot has never been written before, it returns the 32 byte zero value as the default value. Before that it was the empty array.

[#10385]: Disable polkavm logging in pallet-revive

This PR adds configurable control over PolkaVM logging in pallet-revive to address performance degradation (details: #8760 (comment))

  • Upgrades PolkaVM to v0.30.0 which provides set_imperfect_logger_filtering_workaround()
  • Adds pvm_logs flag to DebugSettings to control PolkaVM interpreter logging
  • Disables PolkaVM logs by default (when pvm_logs=false), enabling them only when explicitly configured
  • Fixes performance issue where excessive PolkaVM logging was impacting block proposal times

The logging can be re-enabled via debug settings when needed for troubleshooting.

Additionally:

  • PolkaVM has been bumped globally across whole codebase.

[#10244]: [pallet-revive] add tracing for selfdestruct

Add tracing for selfdestruct

[#10721]: Integrate asset test utilities for asset hub westend

The PR migrates exchange_asset tests from integration tests to unit tests in the AssetHubWestend runtime and introduces a shared helper to reduce duplication.

[#10634]: Remove uses of sp-debug-derive/force-debug feature

Removes the force-debug feature flag from sp-debug-derive dependencies across the codebase.
This feature has been a no-op since #10582 and can be safely removed without any behavioral change.

[#10510]: [pallet-revive] fix delegate_call_contract in evm-test-suites

evm-test-suite was not correctly executing delegate_call_contract causing pallet-revive to silently reject the delegatecall. After evm-test-suite was fixed we found that the trace for delegate calls is incorrect. This fixes it.

[#10922]: [pallet-revive] small improvements

Small safety and completeness improvements for pallet-revive:

  • Add selfdestruct call tracing: Emit terminate trace after successful SELFDESTRUCT
  • Add debug assertions for unsafe bytecode operations: in relative_jump, absolute_jump, and read_slice
  • Remove transmute in i256 sign detection: Replace unsafe { core::mem::transmute } with explicit conditional logic for determining Sign::Zero vs Sign::Plus

[#10582]: Deprecate RuntimeDebug and replace it with Debug

I compared multiple builds which each other:

Runtime RuntimeDebug .compact.wasm Debug .compact.wasm Δ bytes Δ %
westend-runtime 10,004,155 10,093,902 +89,747 +0.90%
asset-hub-westend-runtime 13,453,435 13,491,827 +38,392 +0.29%
bridge-hub-westend-runtime 6,975,911 7,078,591 +102,680 +1.47%
collectives-westend-runtime 6,660,307 6,725,426 +65,119 +0.98%
people-westend-runtime 5,639,941 5,661,539 +21,598 +0.38%
coretime-westend-runtime 5,667,343 5,689,961 +22,618 +0.40%
glutton-westend-runtime 2,502,303 2,514,727 +12,424 +0.50%
Runtime RuntimeDebug .compact.compressed.wasm Debug .compact.compressed.wasm Δ bytes Δ %
westend-runtime 1,911,531 1,918,414 +6,883 +0.36%
asset-hub-westend-runtime 2,402,348 2,408,262 +5,914 +0.25%
bridge-hub-westend-runtime 1,397,714 1,409,183 +11,469 +0.82%
collectives-westend-runtime 1,265,180 1,268,329 +3,149 +0.25%
people-westend-runtime 1,125,880 1,126,034 +154 +0.01%
coretime-westend-runtime 1,132,311 1,135,300 +2,989 +0.26%
glutton-westend-runtime 543,780 546,127 +2,347 +0.43%

With --features on-chain-release-build:

Runtime RuntimeDebug .compact.wasm Debug .compact.wasm Δ bytes Δ %
westend-runtime 10,088,725 10,088,725 0 0.00%
asset-hub-westend-runtime 13,491,318 13,491,318 0 0.00%
bridge-hub-westend-runtime 7,078,244 7,078,244 0 0.00%
collectives-westend-runtime 6,724,948 6,724,948 0 0.00%
people-westend-runtime 5,640,009 5,661,591 +21,582 +0.38%
coretime-westend-runtime 5,689,735 5,689,735 0 0.00%
glutton-westend-runtime 2,504,593 2,517,004 +12,411 +0.50%
Runtime RuntimeDebug .compact.compressed.wasm Debug .compact.compressed.wasm Δ bytes Δ %
westend-runtime 1,917,250 1,917,250 0 0.00%
asset-hub-westend-runtime 2,408,382 2,408,382 0 0.00%
bridge-hub-westend-runtime 1,409,259 1,409,259 0 0.00%
collectives-westend-runtime 1,267,981 1,267,981 0 0.00%
people-westend-runtime 1,126,034 1,130,613 +4,579 +0.41%
coretime-westend-runtime 1,135,207 1,135,207 0 0.00%
glutton-westend-runtime 545,344 548,753 +3,409 +0.63%

This shows that the size increase is neglectable and not worth the increased hassle when it comes to debuggin inside wasm.

Closes: #3005

[#10448]: wasm-builder: Only overwrite wasm files if they changed

When running two different cargo commands, they may both compile the same wasm files. When the second cargo command produces the same wasm files, we are now not gonna overwrite it. This has the advantage that we can run the first command again without it trying to recompile the project. Right now it would lead to the wasm files always getting recreated, which is wasting a lot of time :)

[#10437]: Remove pallet::getter usage from merkel mountain range pallet

Advances #3326

[#10302]: Fix termination

This PR fixes up termination by changing the behavior to:

  • The free balance (without ed) should be send away right away to the beneficiary and not be delayed like the contract deletion.
  • The ed and storage deposit will be send away only when terminating but to the origin (delayed).
  • The scheduling of the terminate needs to be reverted if the scheduling frame reverts.
  • SELFDESTRUCT should be allowed inside the constructor. The issuing contract will exist as account without code for the remainder of the transaction.
  • The terminate pre-compile should revert if delegate called or its caller was delegate called. This is just my opinion but if we are changing semantics we can might as well add some security. We are increasing the attack surface by allowing the destruction of any contract (not only created in the current tx).

Other fixes

  • Storage refunds should no longer use BestEffort. This is necessary to fail refunds in case some other locks (due to participation in gov for example) prevent sending them away. This is in anticipation of new pre-compiles.
  • Moved pre-compile interfaces to sol files and made them available to fixtures
  • Added some Solidity written tests to exercise error cases

Further tests needed

Those should all be written in Solidity to test both backends at the same time. No more Rust fixtures.

@0xRVE can you take those over as I am ooo.

  • Test that checks that scheduled deletions do properly roll back if a frame fails
  • Test that value send to a contract after scheduling for deletion is send to the beneficiary (different from Eth where this balance is lost)
  • Add tests that use SELFDESTRUCT to Terminate.sol. Need https://github.com/paritytech/devops/issues/4508 but can be tested locally with newest resolc.

[#10863]: parachain-system: Ensure left-over message budget fits into the PoV

Ensure we check the buget against the remaining proof size in the block.

[#10698]: [pallet-revive] added trybuild test for precompile compile-time checks

fixes #8364

This PR adds compile-time tests using try_build to validate invariants enforced on registered precompiles. The tests ensure collision detection and related compile-time checks are correctly triggered and remain enforced.

[#10735]: Genesis Patch Support for Frame Omni-Bencher

This update adds a --genesis-patch CLI option to frame-omni-bencher,
allowing users to apply custom JSON patches to genesis state during
benchmarking. This enables advanced testing scenarios like stress
testing with many accounts without modifying chain specifications.

[#10371]: Try State Hook for Pallet Assets

This PR introduces the try_state hook to pallet-assets to verify key storage invariants.

[#10309]: [pallet-revive] evm remove contract storage slot when writing all zero bytes

fixes paritytech/contract-issues#216

When writing all zero bytes to a storage item, the item shall be deleted and deposit refunded.

[#10947]: benchmarking: fix DB read/write counts

PR #10802 added reset_read_write_count() at the end of commit_db() to prevent warmup operations from appearing in benchmarking results. However, commit_db is called twice: one on on_before_start() closure before benchmark, and one after benchmark execution after benchmark.
This PR whitelists warmup key so that it doesn't appear in the read/write count.
We also regenerate staking-async and pallet-conviction-voting benchmarks (testing both v1 and v2)

[#10540]: Tighten length estimation during dry running

The length of the RLP-encoded Ethereum transaction will have an effect on the transaction cost (as pallet-transaction-payment charges a length fee) and therefore the required Ethereum gas.

During dry running we need to estimate the length of the actual RLP-encoded Ethereum transaction that will submitted later. Some of the parameters that determine the length will usually not be provided at the dry running stage yet: gas, gas_price and max_priority_fee_per_gas.

If we underestimate the actual lengths of these parameters, then the gas estimate might be too low and transaction execution will run out of gas. If we over estimate, then the pre-dispatch weight will be unreasonably large and we risk that a transaction that might still fit into a block, won't be put into the block anymore, which leads to lower block utilization.

Current Approach

The current approach is to just assume that maximal possible length for these fields, which results when they have the maximum possible value, U256::MAX, due to how RLP encoding works. This is a gross over estimation.

New Approach

In practice there won't be gas requirements and gas estimates that are more than u64::MAX and therefore we assume this as the maximal value for gas.

For gas_price and max_priority_fee_per_gas we assume that the caller will use the current base fee and will scale it be some small amount so that the RLP encoding is at most one byte longer than the RLP encoding of the base fee. We achieve that by determining the RLP encoding of the base fee multiplied by 256.

[#10963]: revive-eth-rpc: Use pending block for estimate_gas in dev mode

Use Pending as the default block for eth_estimateGas in dev mode, matching Anvil/EDR behavior. Non-dev mode continues to use Latest (go-ethereum behavior).

Refs paritytech/contract-issues#261

[#10666]: staking-async: allow session keys handling on AssetHub

Added session keys handling on AssetHub for staking-async:

  • Validators can now call set_keys and purge_keys on AssetHub, which forwards the request to the RelayChain via XCM.
  • Session keys and ownership proof are validated on AssetHub before forwarding. Only validated keys are sent to RC (no proof), as RC trusts AH's validation.
  • Staking proxies can call set_keys and purge_keys on behalf of validators. The ProxyType::Staking filter on runtime has been updated to include these calls.
  • Validators are still allowed to call set_keys and purge_keys via relay-chain pallet-session's extrinsics. This option will be deprecated in the future.
  • No key deposit is required on AssetHub.
  • XCM delivery fees are charged from user's liquid balance before sending messages.
  • Workflow change: unlike the current flow for new validators on RC (bond -> set_keys -> validate), users on Asset Hub MUST call bond and validate BEFORE
    calling set_keys. Attempting to set keys before declaring intent to validate will fail with NotValidator.

[#10638]: [pallet-revive] remove unstable host function ecdsa_to_eth_address

fixes part of #8572

[#10324]: Cleanup HRMP channels that were force removed from RC state

Cleanup old LastHrmpMqcHeads entries when the corresponding channel was remove from RC state

[#9461]: Expose migrating keys

This PR introduces the ability for multi-block migrations to declare which storage prefixes they will modify,
enabling external tooling and monitoring systems to identify potentially affected state during migration execution.

Implement migrating_prefixes() in your SteppedMigration to declare modified storage prefixes.
For migration collections, use nth_migrating_prefixes() to retrieve prefixes by index.

[#10558]: pin solc version to 0.8.30 in tests-misc.yml

pin solc version to 0.8.30 in tests-misc.yml

[#10680]: revive: fix revive post_upgrade assert

Fix post_upgrade assertion logic in revive v2 migration

[#9452]: Add comprehensive test data for Ethereum trie root validation

Summary

This PR adds comprehensive test data for validating Ethereum transaction and receipt trie root calculations in the revive crate. It includes real-world Ethereum blocks covering all supported transaction types.


Details

🧪 Test Data

  • Expanded Test Fixtures:
    • Added 3 Ethereum blocks with their receipts (2 from mainnet, 1 from Sepolia testnet)
    • Blocks include all supported transaction types (Legacy, EIP-2930, EIP-1559, EIP-4844)
    • Test data validates transactions_root and receipts_root calculations against real Ethereum data
    • Organized naming: block_{block_number}_{network}.json and receipts_{block_number}_{network}.json

🛠️ Tooling

  • Test Data Collection Script:
    • Added get_test_data.sh for fetching test data from live Ethereum networks
    • Simple curl-based script that can be extended with additional blocks

Builds on top of: #9418

Part of: paritytech/contract-issues#139

[#10383]: Enable force debug in revive dev node

This change ensures that all types that implement RuntimeDebug are fully displayed in log output of the revive dev node, instead of just showing <wasm:stripped>.

Unfortunately, the trait RuntimeDebugNoBound, that we also use frequently in pallet-revive, is not affected and will still output <wasm:stripped> (it does not check for the force-debug feature flag, instead it only fully outputs values when either one of the features std or try_runtime is enabled – this is something we implement as a general change).

[#10771]: Snowbridge: Describe the token location with the length field included to avoid collisions

For GeneralKey, two XCM junctions that differ only in length can currently produce the same description bytes,
and therefore the same TokenId. To avoid such collisions, this PR includes the length field in the describe function.
We do have several PNAs registered that could be affected by this change. However, these tokens are not currently in use,
there have been no transfers and no tokens minted so far. As a result, simply re-registering these tokens should be sufficient,
without requiring a runtime storage migration.

[#10928]: [pallet-revive] Fix gas_cost and weight_cost for nested calls in execution tracer

Description

This PR fixes gasCost and weightCost calculations in execution tracing (structLogs) for opcodes that spawn child calls (CALL, DELEGATECALL, CREATE, etc.). Previously, was and reflected pre-execution state rather than actual consumption for any parent call.

This PR:

  • Computes and weightCost in as the cost of executing the opcode itself, excluding gas/weight consumed by child calls
  • Tracks child call consumption via a PendingStep stack and subtracts it when the parent opcode completes
  • Adds test coverage for nested call gas tracking in both EVM and PVM modes

Difference from Ethereum/Geth

In Geth's opcode tracing, for CALL-like opcodes includes the opcode's intrinsic cost plus all gas forwarded to child calls. In our implementation, gasCost reports only the opcode's intrinsic cost, excluding forwarded gas. The intrinsic cost includes:

  • The *CALL opcode's base cost
  • Post-call costs such as copying return data back to the caller's memory (e.g., CopyToContract)

[#10716]: Migrate pallet-example-offchain-worker to use TransactionExtension API

Migrates pallet-example-offchain-worker from the deprecated ValidateUnsigned trait
to the modern TransactionExtension API using the #[pallet::authorize] attribute.

This change demonstrates how to validate unsigned transactions using the new approach,
which provides better composability and flexibility for transaction validation.

The pallet now uses #[pallet::authorize] on unsigned transaction calls to validate:

  • Block number is within the expected window
  • Price data is valid
  • For signed payloads, signature verification using the authority's public key

This serves as a reference example for other pallets migrating away from ValidateUnsigned.

[#10697]: [frame-support] remove error reporting in remote_transfer_xcm for paid execution

The reason is that it is broken and will result in spamming errors until we fix it properly: #10078.

[#9086]: Make HRMP advancement rule more restrictive

This PR improves check_enough_messages_included() and makes the advancement rule more restrictive for HRMP.

[#10524]: Fix Differential Testing CI Flakiness

Description

This PR updates the commit hash of the revive differential testing framework that we use to fix the flakiness we observed in CI. It was fixed in the framework by caching the chainspec of the node's we spawn so that the chainspec is only generated once and used for all of the nodes.

[#10957]: pallet-dap: mark funds as inactive and expect buffer account to be pre-funded

In pallet-dap, mark funds in the issuance buffer as inactive so they do not participate in governance.
In production, the buffer account must be pre-funded (e.g., via genesis allocation or transfer) before the pallet receives any funds.
Removed the InitBufferAccount migration since the buffer account is now expected to be pre-funded externally.
For delegated staking, redirect slashes to DAP for Westend AssetHub.
Removed DAP dependency from main staking-async crate, keep it only for test runtimes.

[#10907]: Update the resolc and retester versions

Summary

This PR allows us to use nightly versions of the resolc compiler in the differential tests CI which include fixes not yet available in the published version of the compiler. It also bumps the commit hash of differential tests used to a version that allows for gas limits to be specified manually to circumvent the issue observed in paritytech/contract-issues#259

[#10808]: Update retester CI to check expectations

Description

This PR makes a number of changes to the retester CI job that were recommended by @athei and other people at parity.

One of our main objectives with the changes in this PR is to harden the CI and ensure that the job status that we see in Github is representative of whether we got the results that we expect or not.

With this PR, we added two versioned controlled JSON files, one for each platform that we run differential tests on, which describe the status that we expect for each one of the tests that we run.

Part of the retester CI job is to run the differential tests and ensure that the results of running tests match the expectation files we have in the repo for the platform.

In this case:

  • CI is green if the test's execution matches the expectations that we've set in the expectations JSON files.
  • CI is red if the test's execution doesn't match the expectations that we've set in the expectations JSON files.

The CI job for retester no longer posts a comment with the status of all of the tests.

If the expectations do not match, then the new expectations file is uploaded to the CI job you would be required to update the expectation file to match.

[#10380]: pallet-revive benchmark opcode fix

Benchmark opcode was using the invalid opcode instead of defining a new one.

[#9184]: FixedPoint: Support parsing x.y format

This makes it easier to declare a fixed point value. The old format is also still supported.

[#10729]: [FRAME] Bounties return balance and assets on close

Ensures that bounties that got closed with close_bounty will return the maximal possible
amount of Native balance and specific relevant Assets.
This fixes an issue where closed bounties would not refund any balance to the treasury because
assets were blocking the withdrawal through account references.

[#10880]: Remove failing assertion related to VoterList count mismatch

Updated bags-list so that on_insert queues items into PendingRebag instead of failing, and removed the invariant that required VoterList's count to equal the combined number of Nominators and Validators. This is safe while bags-list is locked. After unlocking, on_idle drains PendingRebag, and the counts converge back to consistency over time.

[#10612]: revive eth-rpc Add polkadot_postDispatchWeight rpc methods

Add a new RPC method to return the post-dispatch weight of a transaction

[#10911]: [pallet-revive] Fix EXTCODESIZE and EXTCODEHASH for mocked addresses

Fixes EXTCODESIZE and EXTCODEHASH opcodes for mocked addresses. Previously, these opcodes did not check the mock handler, causing them to return values indicating no code exists at mocked addresses. Fixed by adding mocked_code method to MockHandler trait to provide dummy bytecode.

[#10517]: [pallet-revive] remove disabled host functions terminate and set_code_hash

fixes part of #8570

Removes the following disabled host functions:

  • terminate
  • set_code_hash

[#10397]: Update the commit hash of the revive-differential-tests

Description

This is a PR that updates the commit hash of the revive-differential-tests framework and the compilation caches to a version that includes fixes to certain tests that used hard-coded gas values. The compilation caches required an update since this was a change to the contract's code.

[#10427]: Fix assertion

Description

According to assertion message and comment("at least"), T::MaxDebugBufferLen::get() > MIN_DEBUG_BUF_SIZE should be changed into T::MaxDebugBufferLen::get() >= MIN_DEBUG_BUF_SIZE

// Debug buffer should at least be large enough to accommodate a simple error message
const MIN_DEBUG_BUF_SIZE: u32 = 256;
assert!(
	T::MaxDebugBufferLen::get() > MIN_DEBUG_BUF_SIZE,
	"Debug buffer should have minimum size of {} (current setting is {})",
	MIN_DEBUG_BUF_SIZE,
	T::MaxDebugBufferLen::get(),
);

For this assertion, the assertion message indicates assertion will fail when max_storage_size > storage_size_limit, which means it requires max_storage_size <= storage_size_limit, but assertion predicate is max_storage_size < storage_size_limit. Based on the code semantics, assertion predicate should be changed into max_storage_size <= storage_size_limit.

assert!(
	max_storage_size < storage_size_limit,
	"Maximal storage size {} exceeds the storage limit {}",
	max_storage_size,
	storage_size_limit
);

[#10359]: Remove invulnerables form staking-async

The 'staking-async' pallet has inherited the list of invulnerable validators from the 'staking' pallet, but these are no longer used. We can therefore remove them, together with additional clean-up. This includes removing the 'set_invulnerables(...)' call together with the 'Invulnerables<T: Config>' storage type.

[#10340]: Remove "SolutionImprovementThreshold" logic

The threshold mechanism used by the election-provider-multi-block verifier pallet is no longer relevant. There are no queued solutions to compare during the initial verification. Solutions are subsequently processed in order of decreasing score, with the first verified solution being selected, while any remaining solutions are not verified.

[#9925]: Staking-Async + EPMB: Migrate operations to poll

Migrate staking-async and its election provider pallet to on_poll

[#10580]: Fix eth-rpc publish

Use the update subxt macro to generate the metadata in OUT_DIR;
not doing so generates the following error when we try to publish the package:

error: failed to publish to registry at https://crates.io

Caused by:
  the remote server responded with an error (status 403 Forbidden): this crate exists but you don't seem to be an owner. If you believe this is a mistake, perhaps you need to accept an invitation to be an owner before publishing.

see related subxt changes: paritytech/subxt#2142

[#10460]: Remove pallet::getter usage from sassafras pallet

This PR removes all pallet::getter occurrences from pallet-sassafras.

Changelog for Node Operator

ℹ️ These changes are relevant to: Those who don't write any code and only run code.

[#8541]: collator-protocol-revamp: CollationManager and subsystem impl

This PR adds a new experimental validator-side collator protocol subsystem implementation,
which can be enabled via the --experimental-collator-protocol CLI flag.

The new implementation introduces a reputation-based collator selection mechanism. Collators
are assigned scores based on the outcome of their submitted collations: valid included
candidates increase the score, while invalid collations or failed fetches decrease it.
When multiple collation advertisements are received, validators prioritize fetching from
higher-reputation collators first (with timestamp as a tiebreaker for equal scores).

[#10709]: Introduce a "jemalloc-shim" crate

This crate basically serves as a hack to properly enable jemalloc on Linux and disable it on all other OSes by default.

[#10662]: Bulletin as parachain missing features

  • Node developers/operators could enable the transaction storage inherent data provider setup by using --enable-tx-storage-idp flag. This is especially useful in the context of bulletin chain.
  • Node developers will set up the network idle_connection_timeout to 1h when using --ipfs-server flag, again, useful in the context of bulletin chain.

[#10978]: Omni-node supports polkadot-asset-hub

The polkadot-omni-node binary now supports polkadot-asset-hub. Other system chains where already supported, but PAH uses Ed25519, which makes it a special case.

[#10196]: Improve Warp Sync Logging

This update makes warp sync logs more useful. it shows a clear count of synced eras and removes
unnecessary block details during the proof phase, giving a better view of progress.

[#1739]: Require proof for session key registration

Node operators will now need to provide a proof when registering their SessionKeys on chain.
A new rpc author_rotateKeysWithOwner is provided to generate the SessionKeys plus the proof.
Both values then need to be feed into set_keys as part of the transaction.
author_rotateKeysWithOwner is a replacement for author_rotateKeys.

[#10617]: statement-store: use many workers for network statements processing

Adds --statement-network-workers CLI parameter to enable concurrent statement validation from the network.
Previously, statements were validated sequentially by a single worker. This change allows multiple workers
o process statements in parallel, improving throughput when statement store is enabled

Changelog for Runtime User

ℹ️ These changes are relevant to: Anyone using the runtime. This can be a token holder or a dev writing a front end for a chain.

[#10828]: [pallet-broker] add extrinsic to forcefully remove the potential renewal

Add an extrinsic allowing to forcefully remove the existing potential renewal from chain without the need to directly manipulate the storage.

[#10767]: Fix auto-renew core tracking on immediate renew

Summary

Fix auto-renew tracking when do_enable_auto_renew triggers an immediate renewal. The auto-renew record now follows the new core index returned by do_renew, preventing a stale core from being
renewed in the next sale rotation.

Discovered by the Darwinia Network team while attempting a renew.

Problem

When enabling auto-renew during the renewal window (PotentialRenewals at sale.region_begin), do_enable_auto_renew immediately calls do_renew. That call can allocate a different core
index, but the auto-renew record was stored with the old core. On the next rotation, renew_cores attempts to renew that stale core and emits AutoRenewalFailed, even though the workload has
already moved to the new core.

Fix

Capture the returned core index from do_renew inside do_enable_auto_renew, and store that core in AutoRenewals (and the enable event).

Tests

  • Added enable_auto_renew_immediate_updates_core_and_renews
  • cargo test -p pallet-broker

Closes: #10006

[#10697]: [frame-support] remove error reporting in remote_transfer_xcm for paid execution

The reason is that it is broken and will result in spamming errors until we fix it properly: #10078.

Rust compiler versions

This release was built and tested against the following versions of rustc.
Other versions may work.

  • Rust Stable: 1.88.0

Runtimes

The information about the runtimes included in this release can be found below.
The runtimes have been built using srtool v0.18.3 and rustc 1.88.0 (6b00bc388 2025-06-23).

Westend

🏋️ Runtime Size:          1.87 MB (1962174 bytes)
🔥 Core Version:          westend-1022000 (parity-westend-0.tx27.au2)
🗜 Compressed:            Yes: 81.15%
🎁 Metadata version:      V14
🗳️ system.setCode hash:   0x6641b5268c6f627cde7ea6019047b79a9002e7eb17a054077b294858a20c3865
🗳️ authorizeUpgrade hash: 0x1d433bcf3852ec53da2e141525f2eda1c822a7a4c95c23d9faf46d04b6d4e9ae
🗳️ Blake2-256 hash:       0x936eade31dc2e98472138d2fde4ac02b1aedadd99827ada375557e9ef8b39256
📦 IPFS:                  QmNcopQgx9ivmTM4i78c3Vsc5Nj7ku3WCDifSiD1ASjKyE

Westend Assethub

🏋️ Runtime Size:          2.39 MB (2502662 bytes)
🔥 Core Version:          westmint-1022000 (westmint-0.tx16.au1)
🗜 Compressed:            Yes: 82.25%
🎁 Metadata version:      V14
🗳️ system.setCode hash:   0xa88e0d304d6e53c4ffd0deaa45ad4c772cbe39fc30483d21d98b310fcec6a976
🗳️ authorizeUpgrade hash: 0x8e466470f1e285d5c353444bd00563f3402e803e44e4eba66d912d54244e8f6b
🗳️ Blake2-256 hash:       0x7ba69161266f778d4b78637f426e209a5efe4f933a3109bf5381825b4ce26cec
📦 IPFS:                  QmV7GF5KDLhgvGba9ayL67Ks3u9DHasDJmofTy7AwCfbNf

Westend Bridgehub

🏋️ Runtime Size:          1.36 MB (1426617 bytes)
🔥 Core Version:          bridge-hub-westend-1022000 (bridge-hub-westend-0.tx6.au1)
🗜 Compressed:            Yes: 80.01%
🎁 Metadata version:      V14
🗳️ system.setCode hash:   0xdbacb65e95a3372da00a7c5160139c5be78218367f19b190d676ef40727ace20
🗳️ authorizeUpgrade hash: 0x03e0d6d9689b463e60a2d989a310a89e901375be4c447fb55ae0c75a5fd9ec8e
🗳️ Blake2-256 hash:       0x7335745c862a2a04a3c3e4ce3bbbd077f47da6fe324f59618f6987d087ac2138
📦 IPFS:                  QmeniSJBj9XySzZW2nFsHuaXWPWj9Buw2fmDV9hEcjhpE8

Westend Collectives

🏋️ Runtime Size:          1.23 MB (1289076 bytes)
🔥 Core Version:          collectives-westend-1022000 (collectives-westend-0.tx6.au1)
🗜 Compressed:            Yes: 81.1%
🎁 Metadata version:      V14
🗳️ system.setCode hash:   0x1f3b332f4aa79881136b9ba1298738ee98262e87dd523f4ea9a032fa8ecf313a
🗳️ authorizeUpgrade hash: 0x1505688566cf90af39e078de0fe0fb0d702b5d859c1d0ae0f28de37a0c9fec06
🗳️ Blake2-256 hash:       0x49c11e8d8f1cda04ebf9c68062254b0af0f60f316b12e34e305ffc047a686450
📦 IPFS:                  QmaUeG5a6DZA1xu8D7oU2RVetuFiP1tXTaiEzLyFps5ZbT

Westend Coretime

🏋️ Runtime Size:          1.10 MB (1149499 bytes)
🔥 Core Version:          coretime-westend-1022000 (coretime-westend-0.tx2.au1)
🗜 Compressed:            Yes: 80.1%
🎁 Metadata version:      V14
🗳️ system.setCode hash:   0x508b4c463b7f13acdc9e74ac9b9c3aaa8b57f1c848abce83f4235676b94f7e93
🗳️ authorizeUpgrade hash: 0x7ee87c7978f509645cab0a5150e0410673052cea42197dba318d113236fb14b6
🗳️ Blake2-256 hash:       0x360d64f5e9bc5b93ce3bf09d017770d63a3d20d591891371434023283bf846af
📦 IPFS:                  Qmf9nKZZdsuRFU1VGHFZNqHpBu53pyz3QuNzBgKQvRN55Y

Westend Glutton

🏋️ Runtime Size:          545.58 kB (558672 bytes)
🔥 Core Version:          glutton-westend-1022000 (glutton-westend-0.tx1.au1)
🗜 Compressed:            Yes: 78.14%
🎁 Metadata version:      V14
🗳️ system.setCode hash:   0xe267acc5cb381094ae945e700b3b1cfc3661032fa7eb9729a694a5b2863b7ffe
🗳️ authorizeUpgrade hash: 0xc2376c037053f9799970aad49b53921b3244fcd03804c818f9701c71f244423e
🗳️ Blake2-256 hash:       0x7a19dbabde7f3f77a3e35089bcb645d0425c78a77cd129ac30b578c648ca878b
📦 IPFS:                  QmVb65JAU6YxuxgZJYs6k9APc6QBo6U7LjEbpioBMyEa6d

Westend People

🏋️ Runtime Size:          1.09 MB (1139672 bytes)
🔥 Core Version:          people-westend-1022000 (people-westend-0.tx2.au1)
🗜 Compressed:            Yes: 80.12%
🎁 Metadata version:      V14
🗳️ system.setCode hash:   0xb513513fece374c57e5282ccaf81f2acaa23e9ad693d44650c05b7e950299f37
🗳️ authorizeUpgrade hash: 0xcb1ab6f5380cb4b0bd40c2b309c22e3308bf2a75ebacf7b6c5a6aebe67364959
🗳️ Blake2-256 hash:       0x7e1adff5b1995ba375600e8dd09ba8dfe6e0a39fff759f0a288886c7942d98f7
📦 IPFS:                  QmWPmCayFpHCtEwh3uW3FwncGdLjhxeyGLLHu51C1E4V57

Docker images

The docker images for the polkadot node binary and the polkadot-parachain binary can be found at Docker hub (will be available a few minutes after the release has been published):

You may also pull it with:

docker pull parity/polkadot:stable2603-rc1

or

docker pull parity/polkadot-parachain:stable2603-rc1

Don't miss a new polkadot-sdk release

NewReleases is sending notifications on new releases.