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 explicitErrNotSupported("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 andlatest-height queries are unaffected.
- Enforce the
debug_trace*execution timeout (was a no-op) (#4886) — The trace execution timeout inparseTracernever fired: the deadline context was cancelled whenparseTracerreturned (before the EVM trace ran), so the watchdog sawcontext.Canceledinstead ofcontext.DeadlineExceededandtracer.Stopwas never called. A slow/expensivedebug_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, andtraceBlocksurfaces 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
TraceCancellertravels in the trace context, each EVM registers itsCancelwith 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.
- Correct the SELFDESTRUCT transaction-log amount (
[evm]) —generateSelfDestructTransferLogstored thestateDB.lastAddBalanceAmount*big.Intdirectly into theIN_CONTRACT_TRANSFERtransaction 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_getBalanceat an old block returned the current balance), which broke exchange reconciliation.WorkingSetAtHeightnow returnsErrNotSupportedfor 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
ValidateBlockis 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/PutBlockpath 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_traceBlockByHashshared one tracer across every transaction in the block, leaking per-tx state:prestateTraceraccumulated touched accounts across txs, andcallTracernever 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.
txlogpatch: add-correctmode for the self-destruct log fix — The v2.4.3 transaction-log patch runs in strip mode (it removes forgedIN_CONTRACT_TRANSFERrecords 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-correctmode reads acorrect_amount_raucolumn from the CSV and rewrites only the amount (RAU) of the matchedIN_CONTRACT_TRANSFERrecord, keeping its sender/recipient/type. The default strip mode is unchanged.
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 31217237–49346893) plus the same 7 forged MakeTransfer records stripped in v2.4.3 (49703669–49705590, 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 setpatchTransactionLogPathif the file is present — a node configured with a missing patch file will fail to start.
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.
https://github.com/iotexproject/iotex-core/compare/v2.4.3...v2.4.4