Skip to content

Celadon audit - #214

Draft
panos-xyz wants to merge 14 commits into
release/1.3.0from
feat/morphtx-v2-eip7702
Draft

panos-xyz wants to merge 14 commits into
release/1.3.0from
feat/morphtx-v2-eip7702

Conversation

@panos-xyz

Copy link
Copy Markdown
Contributor

Audit diff from the v1.3.0 release to the MorphTx v2 / Celadon upgrade (feat/morphtx-v2-eip7702). Covers #209 (CI), #210 (call-mode fee-token alignment), and #211 (MorphTx v2 + EIP-7702 + Celadon hardfork + alt-token refund rounding).

dependabot Bot and others added 12 commits September 15, 2026 17:32
)

Bumps the actions-weekly group with 1 update: [taiki-e/install-action](https://github.com/taiki-e/install-action).


Updates `taiki-e/install-action` from 2.87.5 to 2.87.11
- [Release notes](https://github.com/taiki-e/install-action/releases)
- [Changelog](https://github.com/taiki-e/install-action/blob/main/CHANGELOG.md)
- [Commits](taiki-e/install-action@v2.87.5...v2.87.11)

---
updated-dependencies:
- dependency-name: taiki-e/install-action
  dependency-version: 2.87.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: actions-weekly
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Add MorphTx version 2 (0x7f || 0x02 || rlp), which carries an EIP-7702
authorization list on top of the v1 fields and is activated by the new
Onyx timestamp fork.

- primitives: encode the authorization list after memo in both the
  payload and the signature hash; an empty list is valid and behaves like
  v1, a non-empty list forbids CREATE, v0/v1 must not carry one; the
  Compact codec stays backward compatible; JSON always emits
  authorizationList for v2 ([] when empty) and never for v0/v1
- chainspec: add the Onyx hardfork (onyxTime), mapped to OSAKA
- consensus/txpool: reject v2 before Onyx; the upstream pool's authority
  and delegation limits apply to v2 through Transaction::authorization_list
- revm: apply v2 authorization lists through the same path and refund
  accounting as 0x04, enforce the static EIP-7702 rules, and size the L1
  data fee of simulated transactions with the list
- rpc: build v2 from requests carrying authorizations and reject invalid
  combinations as parameter errors
- statetest: model MorphTx with authorizations as v2, add the onyx fork
cargo-deny now fails on RUSTSEC-2026-0285: rustls before 0.23.45 accepts
TLS 1.3 handshake messages across encryption level boundaries. rustls
0.23.45 requires aws-lc-rs ^1.18 and rustls-webpki ^0.103.14, so those
are bumped as well.
- primitives: `decode_fields` (behind `rlp_decode_fields`) now requires
  the RLP list to be consumed exactly for every version, matching
  `Decodable::decode`, so surplus elements are rejected instead of left
  unread; add regression tests
- node tests: pin the pre-Onyx v2 rejection to the "not yet active" error
- statetest: document that the presence of `authorizationList` (even an
  empty one) selects v2, the same convention used to select 0x04
Drop the `version` selector from `MorphTransactionRequest` and derive the
version from the content: V1 is the baseline (the request layer no longer
produces V0) and a non-empty `authorizationList` selects V2. An absent,
`null` or empty list are the same thing, and a legacy `version` key is
ignored like any other unknown key.

The rule lives in primitives as `TxMorph::inferred_version` /
`with_inferred_version`, so library users derive the version the same way
the RPC layer does instead of filling it in by hand. The CREATE rejection
now reads "MorphTx with an authorization list cannot create a contract" on
every layer.

The e2e simulation tests select a MorphTx with a memo instead of the removed
key and check that a legacy `version` key leaves the estimate unchanged.

Claude-Session: https://claude.ai/code/session_01WYbNZVUBHa4qCoRK46taTS
The fork that activates MorphTx v2 was carried under the placeholder name
Onyx. It is now named Celadon, so rename it everywhere on this branch:

- `MorphHardfork::Onyx` -> `MorphHardfork::Celadon`, together with
  `is_onyx` / `is_onyx_active_at_timestamp` and the test schedule
  `HardforkSchedule::PreOnyx`
- genesis key `onyxTime` -> `celadonTime` (no alias is kept: the old key
  never shipped in a bundled chainspec, and an unknown key is ignored, so
  a private devnet genesis has to switch to the new key)
- the pre-fork rejection now reads
  `MorphTx version 2 is not yet active (celadon fork not reached)`
- the statetest fork name `Onyx` -> `Celadon` (`osaka` still maps to it)
- test names and comments

No behaviour change besides those names.

Claude-Session: https://claude.ai/code/session_01WYbNZVUBHa4qCoRK46taTS
* fix(revm): align call-mode fee-token execution with go-ethereum

A fee token registered without a `balanceSlot` takes the EVM-call path:
the protocol resolves the payer's balance with `balanceOf` and moves the
fee with an ERC20 `transfer`. morph-reth diverged from morph-geth on that
path in ways that change `gasUsed`, receipts and state roots, so a
follower rejects blocks a geth block producer accepts.

Measured against the golden fixtures added in the next commit, main fails
8 of 12 case templates on both Emerald and Jade:

- The fee `transfer()` frame's SSTORE refund was discarded, so a fee that
  clears the payer's balance slot earned the user no refund (the receipt
  `gasUsed` mismatch reported in #207). go-ethereum runs that call through
  `evm.Call` inside `buyAltTokenGas()` before `StateDB.Prepare`, which does
  not reset the refund counter, so the refund reaches `refundGas()`. The
  net counter is now carried on `MorphEvm` and recorded before the
  EIP-3529 cap, so it can also be cancelled by a negative refund from main
  execution.

- Internal calls ran with a default transaction environment and their own
  storage, so `balanceOf`/`transfer` saw ORIGIN = 0x0 and an effective gas
  price of 0. A guard on either read the wrong value and the payer's
  balance resolved to zero, rejecting an affordable transaction. Internal
  frames now keep the outer transaction's ORIGIN and GASPRICE, run in the
  executing block's environment, and `balanceOf` executes as a genuine
  static frame under the same 200k gas allowance geth uses.

- A successful transfer whose return value or balance delta failed a later
  business check was rolled back with its logs. go-ethereum keeps the
  state and logs and only reports the failure. The frame now owns its
  checkpoint: a VM revert still rolls back, a business failure does not,
  and a database failure stays fatal rather than becoming a verdict about
  the token.

- Zero fees skipped neither `transfer(0)` nor the initial `balanceOf`;
  geth skips both transfer modes but still performs the balance query.
  Nonce and cache updates, and call-mode access-list/transient cleanup,
  still happen.

`TokenFeeInfo::effective_fee_limit` replaces the two hand-rolled
fee-limit clamps the execution and pool paths each carried, so they
cannot drift. `MorphEvm::from_env` gives execution and pool queries one
constructor. The receipt builder now reads registry metadata with
`load_storage_only`, which never builds a temporary EVM to resolve a
balance it does not use.

The pool's single call site is adapted to the new `load_for_caller`
signature while keeping its previous behaviour: admission still evaluates
a call-mode `balanceOf` under the hardfork's defaults. Threading the real
head environment through admission is txpool work and is deliberately not
part of this change.

* test(statetest): add geth-derived golden fixtures for fee-token calls

Twelve cases across Emerald and Jade, with state roots, logs roots and
transaction gas generated by morph-geth 5744b8f66. Every case registers
its token with `balanceSlot = 0`, so all twelve exercise the EVM-call
path: deduction clearing the payer's ERC20 balance slot, the one-unit
balance control, main-frame revert and OOG, a main call that restores the
cleared slot, negative-refund cancellation, ORIGIN and GASPRICE guards,
static-call violations, a successful transfer whose refund returns false,
a refund that reverts, and zero-fee storage warmth. Note that "balance
slot" in these case names is the ERC20's own storage slot that the fee
`transfer()` clears, not the registry's optional `balanceSlot` field; the
storage-slot fee path is not covered by these fixtures.

Replaying them against main (v1.3.0) fails 8 of the 12 templates on both
forks. With the preceding commit all 24 outcomes pass.

* docs(revm): document the transaction-id invariant behind the mid-tx finalize

The call-mode fee path commits its deduction by calling `evm.finalize()`
mid-transaction, then re-marks every account and slot cold to reproduce
the warmth go-ethereum's `StateDB.Prepare` would leave behind. Nothing
explained why the whole journal is discarded there, or which part of that
reset the correctness depends on.

The load-bearing property is that the reset must not advance the
transaction id. Warming a slot runs through
`EvmStorageSlot::mark_warm_with_transaction_id`, which re-baselines the
EIP-2200 `original_value` to the present value whenever the slot's id
differs from the journal's. Had that fired on the slot the deduction just
cleared, the main frame's SSTORE would be a create rather than a
recreate and the `SubRefund` cancelling the deduction's `+4800` would be
lost — measured on `main_restores_cleared_slot`, 23_291 gas becomes
38_391.

It cannot fire here because ids stay equal across execution. revm
advances the id only when a transaction finishes — `commit_tx()` from
`execution_result`, or `discard_tx()` on the error path — both after the
main frame; `ExecuteEvm::finalize` then resets it to ZERO before the next
transaction. `finalize()` at this point is therefore idempotent for the
id, while `commit_tx()` would leave the deduction-warmed slots holding 0
against a journal holding 1. Verified by substitution: swapping
`commit_tx()` in fails `main_restores_cleared_slot` with a state root
mismatch.

* fix(revm): return the fee frames' shared memory to the transaction

The fee-token frames are top-level frames that run in the middle of a
transaction, so neither of revm's truncation points covers them:
`free_child_context` only releases a child frame's region, and
`LocalContext::clear` only runs once the whole transaction is done. The
frames therefore left their bytes on the context's shared buffer and the
main transaction frame started on top of them. Measured on a call-mode
MorphTx: the main frame entered with `MSIZE == 32`, and `MLOAD(0)`
returned 9_000_000, the payer's post-fee token balance left behind by the
internal `balanceOf`. go-ethereum allocates a fresh `Memory` for every
interpreter run (core/vm/interpreter.go), so both read zero there, and
both read zero here on the ETH-fee control. Any contract that reads
memory it never wrote, or branches on MSIZE, produced a different result
on morph-reth than on morph-geth.

Carve each fee frame's memory out above whatever the buffer already
holds, and release it on the way out, including on the error path.

The frames keep writing into the context's buffer rather than one of
their own: a nested call hands its callee a `CallInput::SharedBuffer`
range, and while a contract callee resolves that range against its own
frame memory, a precompile callee resolves it against the context's
buffer (`CallInput::as_bytes`). A private buffer would hand every
precompile called from a fee frame empty calldata —
`fee_token_frames_reach_a_precompile_through_memory` fails with
`InsufficientTokenBalance { available: 0 }` under that variant.

Gas is unaffected, since memory expansion is charged from the per-frame
`Gas` counter, and the leak did not cross transactions, since
`local_mut().clear()` runs at the end of each one. The 24 geth-derived
golden fixtures cannot see any of this: ten of their twelve templates
call a codeless EOA and the other two call bytecode that writes before it
reads.

* docs(revm): correct what the pool's balanceOf query aligns with

The comment justified setting the query's ORIGIN to the queried account by
claiming go-ethereum's pool does the same. It does not: `getBalanceFunc`
builds its EVM on an empty `vm.TxContext{}` (core/tx_pool.go:341), so its
ORIGIN is the zero address — and go-ethereum's own execution layer resolves
the same `balanceOf` with ORIGIN set to the sender, so its pool disagrees
with its own execution.

Setting ORIGIN to the account is still the right call, for the opposite
reason to the one recorded: admission exists to predict what the builder
will be able to include, so it follows this client's execution layer rather
than the other client's pool. Say that, and record the one input the query
still cannot match — GASPRICE, which stays at the `TxEnv` default of zero
because the effective price depends on the next block's base fee.

* test(node): run the e2e fee-token path in EVM-call mode

Every registered fee token on mainnet now has its `balanceSlot` cleared, so
the fee is moved by real `balanceOf` and `transfer` calls into the token
contract. The e2e genesis registered `balanceSlot = 2` instead, which put all
128 integration tests on the direct-storage path: the mode that is scheduled
to be disabled by a hardfork, and the one production does not use. The
node-level behaviour of the mode production does run — receipts, log
ordering, pool admission, the replay RPCs — had no integration coverage at
all, while the 24 statetest golden fixtures cover only its state effects.

Give the test token the ERC20 runtime the gas-regression test already carried
inline, and clear the registry's `balanceSlot`. The runtime keeps `balanceOf`
at slot 1, so `test_token_balance_slot` still derives the same slot
independently and remains a test oracle rather than a second copy of the code
under test.

Both gas regressions hold unchanged at 48_128 and 50_428: the fee frames run
on their own 200k budget, and the deduction books no SSTORE refund while the
payer keeps a balance. What does change is the receipt, which now carries the
fee deduction and the fee reimbursement around the transaction's own
transfer. Assert that ordering — deduction, main, refund — since it is what
go-ethereum produces and what indexers read.

* fix(revm): make the fee path's load-bearing invariants local and true

Six items a review of this branch turned up, each verified against revm 42
and go-ethereum before being acted on.

`reimburse_caller_token_fee`'s slot branch reaches `sload`/`sstore` on the
token directly, which panic rather than error when the account is absent from
`journal.state` (`sload_assume_account_present` -> `ColdLoadSkipped` ->
`unwrap_db_error`). It relied on the deduction having loaded it, but the
deduction skips both transfer modes for a zero fee. The two cannot disagree
today — `eth_to_token_amount` rounds up, so a zero token fee means a zero ETH
fee, which returns before the transfer — but that proof lives in another
function. Load it where it is needed instead; today the load is a no-op.

`evm_call` has the same shape of hidden dependency: its `CallValue::Transfer`
frame runs `Journal::transfer_loaded`, whose zero-value path is
`self.state.get_mut(&to).unwrap()`. An ordinary CALL is safe because the
opcode's `load_acc_and_calc_gas` loaded the account; an internal call has no
opcode, so `internal_call_code` is the only load. Its doc comment described
itself purely as a warmth-preserving code read. Say what it is also for.

`MorphBlockExecutor::hardfork` became write-only when `get_morph_tx_fields`
stopped taking a hardfork, leaving a doc comment claiming it is "reused in
`commit_transaction`". Removing it leaves `spec` dead as well — it existed
only to compute it. Drop both, and the constructor argument with them.

Two comments claimed things that are not true of the pinned revm or of the
code they describe. `load_token_fee_info` blamed a "30M gas limit" on the
previous path, which went through `system_call_one` and so already capped at
go-ethereum's 200k; the divergence was the environment and the sender. And
`ExecutionResult::Revert` does carry a `logs` field in revm 42 — the fee logs
need their side channel because the mid-transaction `finalize()` clears the
journal's logs, not because the variant cannot hold them.

The pool restated the fee-limit clamp by hand under a "Match REVM semantics"
comment, although `TokenFeeInfo::effective_fee_limit` was added to be the one
copy. Use it. Finally, `transfer_erc20_with_evm`'s affordability check built
its error message with `ok_or`, rendering two U256s and allocating a String on
every successful call-mode fee transfer; `ok_or_else` defers it.

* test(statetest): cover uninitialized memory and the direct-slot path

The twelve golden cases all target either a codeless EOA or bytecode that
writes before it reads, and all twelve register the token in EVM-call mode.
Two consensus-relevant behaviours were therefore invisible to them.

`main_reads_uninitialized_memory` commits MSIZE and MLOAD(0) to storage from
the transaction's own frame, before writing either. go-ethereum allocates a
fresh `Memory` for every interpreter run, so both read zero and neither SSTORE
changes state; a client whose fee frames leave their bytes on the
transaction's shared memory writes two non-zero slots and misses the root.
Verified to have teeth: reverting the fee frames to a checkpoint-zero
`SharedMemory` fails it with a state root mismatch.

`slot_deduct_keep` and `slot_deduct_clear` are the first coverage of the
registry's direct-slot path, which has to keep working for replaying blocks
produced before every mainnet token moved to the call path. `slot_deduct_clear`
is byte-for-byte the transaction `deduct_clear` runs and costs 21_000 against
its 16_800: clearing the payer's balance through a real `transfer` books a
`+4800` SSTORE refund that reaches the transaction, while `SetState` books
nothing. That 4_200 is the only way the two modes bill differently, and it is
now pinned from both sides.

Roots and logs hashes come from morph-geth 4012f174b, which reproduces all
twelve existing cases unchanged.

* test(node): assert the fee logs survive a reverting main frame

`receipt.rs` caches the fee `Transfer` events outside the journal because
go-ethereum's `StateDB.logs` is not part of the state snapshot/revert
mechanism: when the main frame reverts, the deduction's log must still be in
the receipt. Nothing asserted that. Every reverting golden case used a token
that emits no logs, so its expected `logs` hash is the empty hash and a client
that dropped `pre_fee_logs` on the floor would produce the same value. The
property decides the receipt's logs and therefore the block's receipts root.

`morph_tx_v0_token_fee_still_charged_on_revert` already reverts the main frame
against the real ERC20 test token and already runs through
`MorphBlockExecutor` and the production receipt builder. Assert the two fee
transfers it must carry, in go-ethereum's order, and that the deduction moved a
non-zero fee. Verified to have teeth: not extending `pre_fee_logs` in
`build_receipt` fails it.

One comment described the code wrongly and is corrected:

- The call-mode deduction comment said re-marking accounts and slots cold
  "reproduces the warmth `Prepare` would have left behind". It does not, and
  must not: the coinbase and access list are re-warmed later by upstream
  `pre_execution::load_accounts`, which runs after this deduction because the
  deduction happens in `validate()`. Say so, and say what breaks if a future
  change reorders those phases.

`load_token_fee_info`'s claim that the old path "capped at
`SYSTEM_CALL_GAS_LIMIT`, which is go-ethereum's 200k" reads wrong, because
revm's `SYSTEM_CALL_GAS_LIMIT` is 30_000_000. It is right, though: this crate
defines its own 200_000 in `exec.rs` and sets it in the `SystemCallEvm` impl,
shadowing revm's. Name that shadowing, since the bare constant reads as a
mistake and invites exactly the wrong "fix".

`expectException` stays presence-only, which reads like an oversight. It is
deliberate: go-ethereum's own statetest harness returns early on
`len(ExpectException) > 0` under a standing "TODO check error string", so
matching the text here would make this runner stricter than the client the
fixtures come from. A comment now records that.

* refactor(revm): keep the fee-token helpers' invariants inside them

Four cleanups from a review of this branch. None of them changes execution.

`transfer_erc20_with_slot` needs the token account in `journal.state`,
because the journal's `sload`/`sstore` panic rather than error when it is
absent, and both callers loaded it themselves with a comment apiece saying
why. The helper now loads and touches the token ahead of its checkpoint.
That is exactly what the deduction did before. The refund's extra touch is a
no-op: a refund only runs after a non-zero deduction, which already touched
the token in the same transaction. The slot-path golden fixtures pass
unchanged, and the unit test that exercises the helper no longer pre-loads
the token.

`reimburse_caller_token_fee` built its missing-cache error with `ok_or`,
allocating the message on every token refund. It now uses `ok_or_else`.

`TokenRegistryEntry`, its `load` and its `load_for_caller` had become `pub`
and re-exported with no user outside this crate, and `load_for_caller` hands
back a `TokenFeeInfo` without going through `ensure_usable`. They are
`pub(crate)` again. The pool keeps using `TokenFeeInfo::load_for_caller`.

The handler and token-fee tests each carried an identical database that
fails storage reads of one token. A single copy now lives in the token-fee
test module, which is `pub(crate)` so the handler tests can use it.

* docs(evm): give the real reason fee logs are kept out of the result

The receipt builder said fee logs are cached apart from the journal because
revm's `ExecutionResult::Revert` carries no logs. In revm 42 it does. The
real reason is that the call-mode deduction runs a mid-transaction
`finalize()` that clears the journal's logs, so the handler moves them out
first, and it drains the refund's logs the same way. `result` then holds only
the main frame's logs, which a revert has already discarded.

The same wrong claim was corrected in `handler.rs` earlier on this branch;
this is the copy that was left behind.

* test(statetest): replay a mainnet slot-mode fee-token transaction

Slot mode is being retired on mainnet, but blocks that already ran it must
keep replaying identically, and only two synthetic golden cases exercised
the registry's direct-slot path.

The new case replays transaction
0x9ebfdac9040d7c2a8739ffdaae8baf5e7aa22fdb48585f80592de4b4cf39ed44 from block
26836567: a V0 MorphTx paying its fee in token 1 through the direct slot,
sent by an EIP-7702-delegated account holding no ETH, whose call transfers
that same token. One transaction covers the deduction, the main frame
writing the payer's already-debited balance slot, and the slot-mode refund.

go-ethereum's state-test runner only signs with `secretKey` and fixes the
chain id to 1, so the sender moves to the harness account, carrying its
nonce, delegation code and re-keyed token balance, and the fee vault's
balance is re-keyed to the harness vault. The prestate tracer reports zero
for the balance slots the fee logic reads straight from state, so those, the
registry entry and the L1 gas price oracle slots are taken from the parent
block. That is exact here because the transaction is alone in its block.

Roots come from morph-geth 4012f174b, which passes the fixture, as does this
runner. The gas used equals the on-chain receipt's 51_257, and the logs root
equals the on-chain logs with the sender topic substituted. Verified to have
teeth: swapping the slot-mode refund's direction fails it with a state root
mismatch.
# Conflicts:
#	crates/txpool/src/morph_tx_validation.rs
Rounding the prepaid alt-token fee up and the unused-gas refund up again
under-collects: the chain gives back part of a token unit the caller never
spent. From Celadon on, the deduction records the numerator its ceiling
overcharged and the refund adds it back before rounding down, so the caller
is charged the ceiling of the *net* fee. Before Celadon both halves keep
rounding up, because that is what mainnet state was built from.

Rounding down can reach zero, which the ceiling never did for a non-zero
refund. go-ethereum's `TransferAltTokenHybrid` returns early on a zero
amount, so the refund now does too: no `Transfer(.., 0)` log on the call
path, no slot writes on the direct-slot path.

This is not gated on the transaction being MorphTx v2 — it applies to every
alt-fee transaction at the fork, so a client without it diverges on the
first token-fee transaction after activation, not on the first v2 one.

Ports go-ethereum#371 `886d7f40b` and `4d71e2b72`.
Nine golden roots from morph-geth 5a0d0d771: three consecutive gas limits on
each of Emerald, Jade and Celadon.

The fee token is registered with `priceRatio = 3` against `scale = 1` and the
transaction carries one non-zero calldata byte, so neither the prepaid fee nor
the transaction's gas cost is a multiple of the ratio. That is the only shape
where rounding both halves up independently disagrees with charging the
ceiling of the net fee: Celadon collects ceil(21_016 / 3) = 7_006 on all three
limits, while Emerald and Jade collect 7_005 on two of them and land on a
second state root.

The 21_016 also pins the gas: morph does not apply the EIP-7623 calldata
floor, which would bill 21_040 and miss every root in the fixture.
`cached_alt_fee_rounding_credit` was the one per-transaction cache the
reset at the top of `validate_against_state_and_deduct_caller` left alone.
That is safe today: the credit is only read next to
`cached_token_fee_info`, and the same deduction writes both. Clearing it
with the rest keeps that true without depending on where the reads happen.

No behaviour change. The new test fails if the reset is removed.

Claude-Session: https://claude.ai/code/session_01WYbNZVUBHa4qCoRK46taTS
…fixture

The fixture ran one calldata length, whose net fee of 21_016 gas leaves a
remainder of 1 modulo the price ratio of 3. For that remainder the prepaid
rounding credit never carries into the refund, so a client that rounds the
refund down but drops the credit lands on all nine roots: the fixture
pinned the fork gate and the rounding direction, not the credit.

Run one, two and three non-zero calldata bytes (21_016, 21_032 and 21_048
gas, remainders 1, 2 and 0) against the same three gas limits. With the
credit dropped, Celadon over-collects a token unit on three of the six new
Celadon cases and misses their roots.

The 27 state and logs roots come from morph-geth 5a0d0d771
(go-ethereum#371) and `evm statetest` reads them back from this file. The
nine roots that were already here are unchanged.

Claude-Session: https://claude.ai/code/session_01WYbNZVUBHa4qCoRK46taTS
@coderabbitai

coderabbitai Bot commented Sep 23, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Warning

Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption.


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

❤️ Share

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

@github-actions

Copy link
Copy Markdown

PR title 不符合 Conventional Commit 规范。

合法格式示例:

  • feat: add new feature
  • fix(consensus): correct gas calculation
  • docs: update README

可用类型:

类型 说明
feat 新功能
fix Bug 修复
chore 日常维护
test 测试相关
bench 基准测试
perf 性能优化
refactor 代码重构
docs 文档更新
ci CI/CD 配置
revert 回滚
deps 依赖更新
style 代码格式化

Breaking Changes 用 ! 标记,如:feat!: changed the API

详见:https://www.conventionalcommits.org/en/v1.0.0/

imbl 7.0.0 depends on imbl-sized-chunks 0.1.3, whose Chunk and
InlineArray removal methods can double-free or use-after-free when an
element's Drop panics (RUSTSEC-2026-0292). imbl 7.0.2 moves to the fixed
imbl-sized-chunks 0.2.0 and drops bitmaps 3.2.1. The dependency comes in
through reth-transaction-pool; only Cargo.lock changes.
CodeQL's rust/hard-coded-cryptographic-value query treats an argument
bound to a parameter named `nonce` as a cryptographic nonce. Every test
that passed a literal account or authorization nonce to these helpers
therefore raised a critical alert, each a false positive that had to be
dismissed by hand, and every new test added more.

Rename the parameters to `tx_nonce` and `auth_nonce`, as the txpool test
helpers already do; the query stopped reporting those after the same
rename. The nonces the helpers put into transactions and authorizations
are unchanged.
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