Skip to content

Latest commit

 

History

History
55 lines (34 loc) · 8.09 KB

File metadata and controls

55 lines (34 loc) · 8.09 KB

v2.4.4 Release Note

Summary

v2.4.4 is a recommended stability, correctness, and security patch release on top of v2.4.3. It continues the transaction-log integrity work started in v2.4.3: it corrects a SELFDESTRUCT transaction-log amount corruption that could mislead balance-reconstructing systems. It also fixes non-archive nodes silently serving latest state for historical reads (which broke exchange balance reconciliation), hardens two panic paths so untrusted input can no longer crash a node, and closes a debug-tracing DoS vector on API nodes. No hardfork, no genesis change, and no config schema change is required for existing operators; v2.4.4 is Go-only and introduces no new activation heights.

Operator-/integrator-visible behavior change (#4917): on a non-archive node, a historical state read at a block height below the tip (e.g. eth_getBalance / eth_getCode / storage reads at a past block) now returns an explicit ErrNotSupported ("use an archive node") error instead of silently returning latest-tip state. This is a correctness fix — the previous behavior returned wrong-but-plausible data — but any integration that was (knowingly or not) relying on historical queries against a non-archive endpoint will now get an error and should be pointed at an archive node. Archive nodes and latest-height queries are unaffected.

Changes

Security

  • Enforce the debug_trace* execution timeout (was a no-op) (#4886) — The trace execution timeout in parseTracer never fired: the deadline context was cancelled when parseTracer returned (before the EVM trace ran), so the watchdog saw context.Canceled instead of context.DeadlineExceeded and tracer.Stop was never called. A slow/expensive debug_trace* request could run unbounded — a DoS vector on API nodes that expose debug tracing. The watchdog is now armed for the full duration of trace execution, for every tracer type, and traceBlock surfaces a timeout as the RPC error instead of returning partial results. Fast traces are unaffected.
  • Abort EVM execution when the trace timeout fires (#4918) — Stopping the tracer alone only stopped result collection; the EVM kept executing until gas exhaustion, undercutting the timeout above. Now paired with EVM cancellation like upstream geth: a TraceCanceller travels in the trace context, each EVM registers its Cancel with it, and the watchdog aborts execution. A cancelled infinite-loop trace returns in ~100ms instead of burning the full gas budget. The consensus path never carries a canceller.

Fix

  • Correct the SELFDESTRUCT transaction-log amount ([evm]) — generateSelfDestructTransferLog stored the stateDB.lastAddBalanceAmount *big.Int directly into the IN_CONTRACT_TRANSFER transaction log for a SELFDESTRUCT. That pointer is mutated in place by the gas-deposit refund performed right after the EVM returns, so the recorded self-destruct log was retroactively overwritten with the gas-refund amount instead of the amount actually transferred to the beneficiary. Transaction logs are not part of any receipt or state root, so balances, receipts, and block/state roots are unchanged — but systems that reconstruct balances from transaction logs (indexers, wallets, exchanges) could be misled. The fix copies the amount instead of aliasing the mutable pointer, with an e2e regression test reproducing the on-chain MEV pattern (a value-carrying sub-call that reverts, then a self-destruct).
  • Error on historical state read on a non-archive node instead of returning latest (#4917) — A non-archive node keeps no historical state, so a read at a past height silently returned latest-tip state (e.g. eth_getBalance at an old block returned the current balance), which broke exchange reconciliation. WorkingSetAtHeight now returns ErrNotSupported for any explicit height below the tip on a non-archive node. Query path only; block production/validation are untouched. (See the operator note above.)
  • Recover panics while validating a proposed block (#4920) — A proposed block is untrusted input. A panic while processing a block's actions during ValidateBlock is now recovered and surfaced as an error (the block is rejected) instead of taking the validating node down. The working set is discarded by the caller on error, so no partial state leaks; the commit/PutBlock path stays fatal as before. Extends the same resilience added on the mint path in v2.4.2 (#4840).
  • Evict the sender when an action panics during minting (#4921) — If a single pending action panicked while being executed during minting, the panic unwound past the sender-eviction logic and was only caught by the mint goroutine's top-level recover, discarding the whole draft without removing the offending action from the pool — so the same action was retried on every subsequent mint attempt. The panic is now recovered around the single-action call and routed through normal error handling, which evicts the sender before the draft is abandoned. This turns a run of repeated draft failures into a one-time lost draft.
  • Use a fresh tracer per transaction in debug_traceBlock* (#4878) — debug_traceBlockByNumber / debug_traceBlockByHash shared one tracer across every transaction in the block, leaking per-tx state: prestateTracer accumulated touched accounts across txs, and callTracer never reset its callstack, dropping later txs with "incorrect number of top-level calls". A freshly instantiated tracer is now swapped in between transactions (matching geth), so per-tx traces are independent and ordered. Read-only tracing path; state/receipt roots are unaffected.

Tooling

  • txlogpatch: add -correct mode for the self-destruct log fix — The v2.4.3 transaction-log patch runs in strip mode (it removes forged IN_CONTRACT_TRANSFER records produced by the MakeTransfer issue). The self-destruct corruption instead mis-records the amount on a genuine record, so it must be rewritten, not removed. The new -correct mode reads a correct_amount_rau column from the CSV and rewrites only the amount (RAU) of the matched IN_CONTRACT_TRANSFER record, keeping its sender/recipient/type. The default strip mode is unchanged.

Transaction-log patch (mainnet)

v2.4.3 shipped txlog.db.patch for nodes that serve transaction-log queries (GetTransactionLogByActionHash, GetTransactionLogByBlockHeight), correcting the historical forged in-contract-transfer records. The Go fixes in v2.4.4 stop new corrupted records from being written; already-recorded self-destruct amounts on mainnet are corrected the same way, via an updated txlog.db.patch regenerated with txlogpatch -correct.

The v2.4.4 txlog.db.patch supersedes the v2.4.3 one and covers 239 blocks: the 232 self-destruct amount corrections (txlogpatch -correct, heights 3121723749346893) plus the same 7 forged MakeTransfer records stripped in v2.4.3 (4970366949705590, byte-identical to the v2.4.3 patch on those blocks).

sha256  dee9406afc991d5439ab4c27bc85fa658e1fb241ddabe1cc5fef18f27d728986  txlog.db.patch

The patch is optional and consensus-neutral — it only affects the transaction logs served for the patched heights and does not change balances, receipts, or block hashes. To enable it, download the patch (verify the sha256 above) and set chain.patchTransactionLogPath (see README.md and the v2.4.3 release note). Only set patchTransactionLogPath if the file is present — a node configured with a missing patch file will fail to start.

Upgrade Priority

v2.4.4 is recommended for all node types. API/gateway nodes that expose debug_trace*, and any operator serving transaction-log data should upgrade as soon as possible.

Node type Action
Delegate Recommended
Fullnode Recommended
API node Recommended (upgrade ASAP if debug_trace* is exposed)
Archive node Recommended

No genesis or config schema changes are required; v2.4.4 is Go-only and introduces no new activation heights.

Commits

https://github.com/iotexproject/iotex-core/compare/v2.4.3...v2.4.4