Skip to content

fix(runtime)!: store a stub at every Orbinum precompile so Solidity high-level calls reach them, drop the applied spec 19 migrations (spec 20) - #171

Merged
nol4lej merged 1 commit into
mainfrom
fix/precompile-code-spec-20
Oct 18, 2026
Merged

nol4lej merged 1 commit into
mainfrom
fix/precompile-code-spec-20

Conversation

@nol4lej

@nol4lej nol4lej commented Oct 18, 2026

Copy link
Copy Markdown
Member

Summary

A Solidity high-level call to a function that returns nothing checks the target's code size first. The Orbinum precompiles (0x0400–0x0403, 0x0801, 0x0802) had no code, so such a call reverted before it reached the precompile. Spec 20 gives each of them a stub and prunes the migration set.

Changed

  • Precompile code. PRECOMPILE_CODE = 0x60006000fd (PUSH1 0 PUSH1 0 REVERT), never executed, is stored at every precompile past the Ethereum range (FrontierPrecompiles::addresses_with_code()). 0x01–0x05 keep no code, as on Ethereum.
    • Genesis presets store it.
    • migrations::PrecompileCode stores it on a live chain. It is idempotent: an address that already holds code is left alone. Try-runtime post_upgrade checks every address.
  • Migrations. Migrations holds only PrecompileCode. RelayerFeesToPool, RemoveRelayerPallet and MoveStrandedEvmTips ran on testnet with spec 19 and are removed with their tests, so no later upgrade runs them again.
  • Structure. migrations.rs becomes migrations/{mod.rs, precompile_code.rs}. runtime_tests.rs becomes runtime_tests/, one module per concern (accounts, metadata_hash, weights, host_functions, block_author, precompile_code), each with the helpers it uses.
  • Version. spec_version 19 → 20, transaction_version unchanged (7). RUNTIME_VERSIONS.md: spec 20 covers this PR and the Balances precompile fix (fix(precompile-balances)!: refuse delegated, static and value calls; charge the dispatch weight up front and revert with a reason (0.2.0) #170); spec 19 is dated v0.5.0.

Testing

  • cargo test -p orbinum-runtime (54), clippy -D warnings with and without try-runtime, fmt --check.
  • Upgrade rehearsal on a local chain started from the spec 19 runtime (main) with no precompile code:
    • activity before the upgrade: Substrate and EVM transfers, a contract deploy, Balances precompile, 3 Substrate shields + 1 EVM shield, 2 private transfers, a partial unshield, a fee claim;
    • try-runtime on-runtime-upgrade --checks all: code stored at 6 addresses, idempotent, no weight issues, PoV 3 KiB, full state decodes, try-state passes;
    • sudo(system.setCode): spec 19 → 20, migration log stored code at 6 precompile address(es), block production continues;
    • after the upgrade, the precompile E2E (28 checks) and the same activity round pass.

…igh-level calls reach them, drop the applied spec 19 migrations (spec 20)
@nol4lej
nol4lej merged commit 4ee0db1 into main Oct 18, 2026
5 checks passed
nol4lej added a commit that referenced this pull request Oct 18, 2026
* Forbid transactions without chain ID by default (#1815)

Orbinum: the RPC half (rpc_allow_unprotected_txs) was already in the node, so only
the runtime check lands here. AllowUnprotectedTxs = ConstBool<false> in
template/runtime/src/configs/evm.rs; the EIP-7702 validation tests gain the new field.

(cherry picked from commit 9f94a1538b2f0a7314ffffe959115ea7e50f0e59)

* Add support for EIP-7883 (#1801)

(cherry picked from commit 50ae25ab41285c918fffe14ed069d10c5feab193)

* Add support for EIP-7823 (#1804)

(cherry picked from commit 8e48b1253ba27b99f40856d2bcb538f22ffd080b)

* fix: patch runner to not exit on calculating weight (#1813)

(cherry picked from commit f25b014e7abd19622825086f3d4d0c3f0d57fdf4)

* Explicitly handle MultipleLogs error in pallet-ethereum hooks (#1809)

(cherry picked from commit 87347e1d7c92b97bd31579ba977559659157760f)

* Fix LRU size calc when replacing a key (#1833)

(cherry picked from commit 3e40adcf53d1fb53b12b17245c48745299ab83b0)

* Add support for EIP-7825 (#1799)

Orbinum: the EIP-7825 validation tests gain the allow_unprotected_txs field from #1815.
MAX_TRANSACTION_GAS_LIMIT was already in fp-evm.

(cherry picked from commit f9adbbfa39ee156b2daf0a6f354d0eaacb65440e)

* make tx gas limit cap configurable

Orbinum: TransactionGasLimit = Some(MAX_TRANSACTION_GAS_LIMIT) in
template/runtime/src/configs/evm.rs (2^24 gas; shield costs ~41k, private_transfer ~92k).
The balances and shielded-pool precompile mocks, which implement pallet_evm::Config in
full, take TransactionGasLimit = ().

(cherry picked from commit b2088f29b9b95d190f46e4618825fec09853b579)

* test(ts): the shielded-pool precompile holds the 0x60006000fd stub, not empty code

Since #171 every Orbinum precompile stores PUSH1 0 PUSH1 0 REVERT so Solidity high-level
calls pass their code-size check. eth_getCode(0x0801) returns that stub.

* docs(runtime): record the upstream Frontier EVM changes in spec 20 (chain-id check, EIP-7825 gas cap, modexp EIP-7823/7883, OutOfGas on failed weight conversion, multiple pre-log digests invalid)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant