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
expiryfield 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::transportsfield renamed totransport_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 connects
PeerConnected - 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
- We don't have this key stored and therefore return
- T3:
UpdatedAuthorityIdsarrives 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_timeoutto 1h when using--ipfs-serverflag, 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:
- makes some BEEFY keystore methods more generic:
sign()public_keys()
This is done by implementing the specific logic in theBeefyAuthorityId.
- Removes the
BeefyAuthorityId::SignatureHashersince 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.
- The log is causing a lot of noise in our test nets: https://grafana.teleport.parity.io/goto/fjTQ_vzDg?orgId=1
[#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
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-fnfrompallet-staking-async. This crate is no longer needed. - rename
ahm-testtointegration-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_limitfield inTransactionLimits::EthereumGasnon-optional, enforcing bounded execution on all Ethereum-style calls - Updates
dry_run_eth_transactto useevm_max_extrinsic_weight()as the weight limit, preventing unbounded computation during dry-run RPC calls - Simplifies metering code by removing
Optionhandling 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:
- Block A contains transaction TX1 → stored in
transaction_hashes - Server restarts (clearing the in-memory
block_number_to_hashesmap) - Re-org happens, Block B (different hash) now contains the same TX1
- 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:
- Add transaction_index::HostFunctions with NO-OP impl to the cumulus ParachainSystem validate_block for polkadot-prepare/execute-worker
- Add custom inherent provider for pallet-transaction-storage to omni node
- 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_periodto thenew_data_provider - introduces the
TransactionStorageApi::retention_periodruntime 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 tomul_*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 asu32) 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_transactextrinsics. - 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
meteringfolder - Since outside code interacts only with the
ResourceMeter, most functions now don't use a separate gas meter and deposit meter anymore but just aResourceMeter - Similar to the two two kinds of deposits meters (
RootandNested), there are two kind ofResourceMeter: the top-levelTransactionMeterused at the beginning of a transaction and aFrameMeterused once per frame - The limits of a
TransactionMeterare specified through theTransactionLimitstype, which distinguishes between Substrate and Ethereum execution mode. - The limits of a
FrameMeteris specified through the typeCallResources, 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_limithas been renamed tofinalizeas that describes the semantics bettertry_into_deposithas been renamed toexecute_postponed_deposits
- This applied particularly to the methods at the end of the lifecycle:
- 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 isNone, 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_executorandsync_from_executorare a bit simplified and there is no need forengine_fuel_leftanymore.
Other Changes
- The old name
gasfor weights has been consistently replaced byweight eth_callandeth_instantiate_with_codenow take aweight_limit(used to ensure that weight does not exceed the max extrinsic weight) and aneth_gas_limit(the new externally defined limit)- The numeric calculation in
compute_max_integer_quotientandcompute_max_integer_pair_quotient(defined insubstrate/frame/revive/src/evm/frees.rs) are meant to divide a number by the next fee multiplier - The call tracer does not take a
GasMapperanymore as it will now be fed directly with the Ethereum gas values instead of weights - Re-entrancy protection now has three modes: no protection,
Strictprotection andAllowNextAllowNextallows 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
Strictprotection we setallows_reentryof the caller tofalsebefore the creation of the new frame, forAllowNextwe 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_depositin 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_codenow 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
- fixes paritytech/contract-issues#215
- fixes #8362
- fixes https://github.com/paritytech-secops/srlabs_findings/issues/589
- fixes paritytech/contract-issues#197
- fixes paritytech/contract-issues#208
- fixes paritytech/contract-issues#212
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_priceinstead of next fee multiplier- TBD, also see #10148 (review)
- 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 fullprocess_messageimplementation 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:
- Build on rustc >= 1.92 was broken despite #10749. That PR was broken.
- The nested cargo didn't properly inherit the parent toolchain (an older error). Leading to the situation where a
1.88was 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 } } | jqThe response includes additional fields compared to the original Geth debug RPC endpoints:
For the trace:
weight_consumed: same as gas but expressed in Weightbase_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 stringsreturned: 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_logsflag toDebugSettingsto 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.
SELFDESTRUCTshould be allowed inside the constructor. The issuing contract will exist as account without code for the remainder of the transaction.- The
terminatepre-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
SELFDESTRUCTtoTerminate.sol. Need https://github.com/paritytech/devops/issues/4508 but can be tested locally with newestresolc.
[#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_keysandpurge_keyson 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_keysandpurge_keyson behalf of validators. TheProxyType::Stakingfilter on runtime has been updated to include these calls. - Validators are still allowed to call
set_keysandpurge_keysvia 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_rootandreceipts_rootcalculations against real Ethereum data - Organized naming:
block_{block_number}_{network}.jsonandreceipts_{block_number}_{network}.json
🛠️ Tooling
- Test Data Collection Script:
- Added
get_test_data.shfor fetching test data from live Ethereum networks - Simple curl-based script that can be extended with additional blocks
- Added
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
weightCostin as the cost of executing the opcode itself, excluding gas/weight consumed by child calls - Tracks child call consumption via a
PendingStepstack 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:
terminateset_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_timeoutto 1h when using--ipfs-serverflag, 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