This release contains security fixes. Operators are advised to upgrade promptly. Details will be published in security advisories on besu-eth/besu after operators have had an opportunity to upgrade.
Headline: Amsterdam scheduled on Hoodi
- The Amsterdam hard fork is scheduled on Hoodi at timestamp 1793036568 (Mon, 26 Oct 2026, 17:42:48 UTC). Hoodi node operators must upgrade before then. [#11531]
Action required on upgrade
- Bonsai database auto-upgrade on first start (DB v4 / archive v3): stores jump-dest analysis alongside code. Takes a few minutes on mainnet, and the DB can no longer be opened by an older Besu afterward. A new besu storage revert-code-format subcommand can roll it back if you need to downgrade. [#11327, #11364]
- Default discovery mode is now BOTH (DiscV4 + DiscV5 concurrently). Set --discovery-mode=V4 (or V5) to pin to one. [#11344]
- Chain-pruning retention increased for EIP-4444/EIP-7928 history expiry — defaults/minimums rise from 113056 to 457568 blocks (more disk retained). [#11316]
- Amsterdam rejects transactions with a gas limit above the EIP-8037 cap (2^32-1). [#11414]
Upcoming Breaking Changes
- Plugin API
PluginTransactionSelectorFactory.create(final SelectorsStateManager selectorsStateManager)is deprecated for removalMiningServiceis deprecated for removal and will be removed in a future release, with no replacement. It has no known usageBesuEventsis deprecated and will be removed at the breaking release. Its event families are available onBlockchainService,TransactionPoolServiceandSynchronizationServicethroughsubscribe*methods returning aSubscriptionhandle;TTDReachedListenerhas no replacement, since it never had an add method. #11283- The plugin API is being reorganized into per-feature modules (#10820). Nothing has changed for plugin authors yet:
besu-plugin-apire-exports every module, so existing plugins compile and run unmodified. A future release will apply the breaking changes, batched into a single break with a migration guide:- packages are renamed to match their module, for example
org.hyperledger.besu.plugin.services.storagebecomesorg.hyperledger.besu.plugin.storage, with contracts plugins implement moving under anspisub-package - contracts that serve several unrelated audiences are split apart, and contracts that overlap are merged into one
- types and methods whose names no longer describe what they do are renamed, and a number of signatures change
- contracts and methods that are deprecated, superseded, or have no known usage are removed
- packages are renamed to match their module, for example
- The plugin lifecycle is being redesigned. The phases a plugin goes through, the services available in each of them, and the way a plugin obtains those services are all expected to change, and the changes will not be source compatible.
PluginVersionsProvider,plugin.data.Request,plugin.data.Restriction,plugin.data.UnsignedPrivateMarkerTransactionandplugin.data.Signatureare deprecated for removal, with no replacement. None is reachable through any plugin service or data contract: the three privacy types were orphaned when private transaction support was removed,Requestis implemented internally but never exposed, andPluginVersionsProvideris internal--versionplumbing
--Xbft-legacy-protocol-encodingwill be removed once Besu 25.x is no longer supported. #10499--snapsync-synchronizer-pre-checkpoint-headers-only-enabledis deprecated (since 26.8.1) and will be removed in a future release; the flag is now a silent no-op.--rpc-tx-feecapwill treat a value of 0 as limiting fees to 0. Today it treats 0 as "do not cap fees". To achieve similar behaviour set it to a suitably large value to effectively prevent any fee capping.
Breaking Changes
-
--Xsnapsync-synchronizer-pivot-block-distance-before-cachinghas been removed; it was deprecated as a no-op since 26.6.1. #11499 -
The default discovery mode is now
BOTH: nodes run DiscV4 and DiscV5 concurrently unless--discovery-mode=V4or--discovery-mode=V5selects a single protocol. #11344 -
trace_callandtrace_callManynow select transaction validation aseth_calldoes, including itsstrictflag. Unlessstrictistrue, a call whosegasPrice,maxFeePerGasandmaxPriorityFeePerGasare all zero or omitted runs withGASPRICEandBASEFEE0 and pays no execution gas fees. Previously such a call was rejected as underpriced at a block with a base fee, or, with its fees omitted, was charged at the base fee. Calls thateth_callvalidates and charges are still validated and charged, each call in atrace_callManybundle is priced on its own, and, as ineth_call, a nonce above the sender's is accepted. Atrace_callthat fails validation now returns the reason, such asGas price below current base fee(-32009), instead ofInternal error. #11404 -
Chain data pruning now retains blocks and block access lists for the EIP-4444 history expiry window (
HISTORY_PRUNE_EPOCHS= 14299 epochs) instead of the weak subjectivity period (3533 epochs), as required by EIP-7928. The default and minimum of--Xchain-pruning-blocks-retained,--Xchain-pruning-bals-retainedand--Xchain-pruning-retained-minimumchange from113056to457568blocks. #11316 -
trace_transactionnow returnsnullfor an unknown transaction hash instead of an empty array, matchingtrace_get,eth_getTransactionByHash, Erigon and Reth. An empty array no longer means the transaction is unknown. #11379 -
trace_blockandtrace_replayBlockTransactionsnow return aBlock not founderror (-32000) for a block number that is not on the chain instead of anullresult, astrace_callandtrace_callManyalready do. #11381 -
trace_filternow honoursblockHashand traces exactly that block, aseth_getLogsdoes. Previously the member was parsed and ignored, so{"blockHash": ...}traced the latest block, and withfromBlockortoBlockthe hash was dropped. A non-nullblockHashcombined with a non-nullfromBlockortoBlockis now rejected withInvalid filter params(-32602). An unknown or noncanonical hash returnsBlock not found(-32000), a canonical block without a stored body, as after history pruning, returnsPruned history unavailable(4444), and a block that cannot be traced on its parent state returnsWorld state unavailable(-32000), including withcount: 0. A nullblockHashis still ignored. #11407 -
Bonsai databases storing code by its hash are upgraded on first start to store the jump destination analysis next to the code (Bonsai database version 4, archive version 3); the upgrade takes a few minutes on mainnet, after which the database cannot be opened by an older version of Besu. #11327
Additions and Improvements
- Update
Bouncycastleto 1.85 to address CVEsCVE-2026-8763andCVE-2026-13506. #11336 - Update Jackson to 2.21.6 to address CVE
CVE-2026-68497#11396 - Update Jackson to 2.21.7 to address CVE
CVE-2026-91777#11503 PoaQueryServiceandBftQueryServiceare no longer deprecated. #11376- Add
engine_newPayloadWithWitnessV5whose VALID response also carries the EIP-8025 execution witness #11181 - Reference tests no longer keep a second copy of the execution-spec fixtures under
build/resources, and the new Gradle propertybesu.referenceTests.fixturesDirlets all checkouts and worktrees share one unpacked copy of each fixture version. #11413 - Add
debug_getRawExecutionRequests, which re-executes a block and returns the EIP-7685 execution requests it produced, in the Engine APIexecutionRequestsform (nullbefore Prague). #11481 - Add
--include-balsoption tobesu blocks export, writing a<to>.balssidecar with BALs for each exported block. #11042 callTracernow honours thewithLogtracer option. Each call frame that emitted logs carries alogsarray of{address, topics, data, position, index}, whereindexequals the receiptlogIndexof the same log andpositionis the number of subcalls the frame had made when the log was emitted. Logs of reverted frames are omitted, as specified in execution-apis#855. #11342- Warn at startup when a PoA chain on Amsterdam leaves the EIP-8282 builder deposit or exit request contract address out of the genesis, since blocks are invalid from the fork unless a contract is deployed at the default address. #NNNN
- The jump destination analysis of contract code is computed once, when the code is stored, instead of on every code cache miss. #11327
- EVM v2: add AND, OR, XOR and NOT. #11477
- Schedule the Amsterdam fork on Hoodi at timestamp
1793036568(Mon, 26 Oct 2026, 17:42:48 UTC). #11531 - The EVM no longer calls the operation tracer for every operation when tracing is disabled.
- New
besu storage revert-code-formatsubcommand reverts the contract code storage and the database metadata, so that a database upgraded to store the jump destination analysis can be opened by an older Besu version again; Besu logs how to run it after the upgrade. #11364
Bug fixes
- Receipts received from a peer carrying a transaction type byte that no type defines are now rejected on decode, on both the EIP-2718 and eth/69 paths.
evmtool t8n-serverkeeps serving requests again. Sinceevmtoolbegan exiting with the subcommand's exit code, the server process exited right after printingTransition server listening on, so filling tests with Besu as the transition tool failed. A server that cannot bind its port now exits with a non-zero code instead of 0. #11555- DNS-discovered dual-stack peers now respect
--p2p-ipv6-outbound-enabledwhen choosing the connection address. #11422 - Block propagation no longer repeatedly re-requests an announced block that is already saved as pending while waiting for its parent. The repeated header and body requests could use up the announcing peer's request capacity and starve the parent request, leaving a node that connects well behind the chain head stuck at its starting block. #11517
admin_logsRemoveCachenow returns an error when any log bloom cache segment could not be deleted, instead of reportingCache Removedafter a partial deletion. #11067txparse --corpus-filenow closes the corpus file stream after processing instead of leaking the underlying file descriptor (it previously suppressed theStreamResourceLeakwarning rather than releasing the resource). #11423besu blocks export --include-balsno longer truncates an existing RLP output when the BAL sidecar cannot be opened. #11467eth_simulateV1blocks after Amsterdam now carryslotNumber(the parent's plus one), a block access list that includes the system calls, and a headergasUsedthat follows EIP-8037, as real blocks do. PreviouslyslotNumberwas missing, and the block hash differed from other clients. #11394eth_simulateV1now returns-38014when a call's value exceeds the sender balance. It returned-32603. #11394- Publish the chain head only after sync block bodies and receipts are committed, so readers cannot observe a head absent from storage. #10842
- Transaction objects returned by
eth_getTransactionBy*,eth_getBlockBy*with full transactions,eth_simulateV1and thetxpoolmethods now carry"to": nullfor a contract creation instead of omitting the field, as other clients do and the execution-apis schema describes. #11434 debug_traceCallnow accepts a block hash as its block parameter, as execution-apis specifies. A hash was rejected with-32602 Invalid block param; an unknown hash now returns-32000 Block not found, as an unknown block number does. #11433- A contract created from within a system call now gets its initial nonce and deployed code.
SystemCallProcessorran every frame with the message-call processor, so aCREATEin a system call's code, reachable when a system contract's code is replaced on a custom or test chain, left the new account with nonce 0 and ran its initcode without deploying anything. - Block access lists now record the net change of the withdrawals and the system calls that share the post-execution index, measured from the state at the start of that index, and include writes made in a system call's own frame. When replaced system contract code changed a value across calls, or changed it twice, each call was diffed against the one before it, giving extra or duplicate entries.
trace_callManynow treats each call as a separate transaction for EIP-2200/EIP-3529 SSTORE gas and refunds. A call writing a slot that an earlier call in the bundle had written was priced against the slot's value before the bundle, for example charging 2,800 gas less for a nonzero-to-nonzero write since Berlin. #11365BlobCache.restoreBlobnow reports that a blob transaction cannot be restored instead of throwingNullPointerExceptionwhen any of its blobs is no longer cached.- DiscV5 discovery now throttles to
--Xv5-discovery-interval-seconds(default 30s) once connected peers reach--Xv5-minimum-peer-ratioof--max-peers, instead of stopping peer search entirely. Below that ratio it runs at--Xv5-fast-discovery-interval-seconds(default 1s). #11344 - Backward sync no longer retries a block every few milliseconds when its parent world state is unavailable. The forward sync step swallowed the error meant to stop backward sync, so the same block was fetched, validated and logged in a tight loop. The
Backward sync haltedwarning is now also logged only once per block. #11303 - JSON-RPC response streaming no longer parks a Vert.x worker thread for the full backpressure timeout after the client has gone away, so a client that stops reading a large response can no longer starve the worker pool that also serves the Engine API. #11146
- Every method advertised by
engine_exchangeCapabilitiesis now registered: on networks without Amsterdam the Amsterdam engine methods answer-38005 Unsupported forkwhere a fork check applies, instead of-32604 Method not enabled, andengine_getBlobsV4is served from Osaka on. #11425 - The transaction pool is no longer disabled, leaving built blocks empty and
engine_getBlobsreturning null, when peers on a different chain report a higher head than the one the consensus client is driving. #11424 trace_callManynow answers a bundle with an invalid call with a JSON-RPC error. Previously it returned the complete error response ({"jsonrpc":"2.0","id":1,"error":{...}}) as theresultof a successful response. An unavailable world state now returnsWorld state unavailableinstead of anullresult. #11401txpool_besuPendingTransactions: thegasPricefilter no longer fails on EIP-1559 transactions, and a negativelimitis rejected as an invalid parameter. #11374engine_getPayloadno longer waits up to 500ms before returning an empty block when no block is being built. #11426trace_callandtrace_callManyvalidate unsigned calls as the draft trace spec and the other clients do. Atrace_callManybundle with an invalid call returns that call's validation error, such asGas price below current base fee(-32009), instead ofInternal error. A positivemaxPriorityFeePerGasabove themaxFeePerGasis reported asMax priority fee per gas exceeds max fee per gasbefore a fee cap below the base fee, also ineth_call. A suppliednonceis accepted but neither validated nor used: the call runs at the sender's nonce, which aCREATEaddress derives from. The blob fee is priced on its own, in the simulation path shared witheth_call,eth_estimateGasanddebug_traceCall: unlessstrictistrue, a blob call whosemaxFeePerBlobGasis omitted or 0 runs withBLOBBASEFEE0 and pays no blob fee, a positivemaxFeePerBlobGasis priced at the block's blob base fee instead of 1 and charged, and a blob call priced for gas pays for its gas instead of running unpriced. Calls without blob fields are unchanged. A call that setsgasPricetogether withmaxFeePerGasormaxPriorityFeePerGasis rejected with-32602ineth_call,eth_estimateGas,eth_createAccessList,debug_traceCall,trace_callandtrace_callMany, as in Geth, instead of ignoringgasPrice. AgasPricewith anauthorizationListserves as both fee caps instead of failing withInternal error, andmaxFeePerGasormaxPriorityFeePerGasbefore London are rejected instead of dropped. #11432- GraphQL
sendRawTransactionaccepts typed transactions in their standard encoding (type || rlp(payload)), aseth_sendRawTransactiondoes. It decoded the data as a block body transaction, so an EIP-1559 transaction was rejected with-32602 Invalid params. #11444 debug_traceBlock,debug_traceBlockByHashanddebug_traceBlockByNumberincludereturnDatain struct logs whenenableReturnDatais set, asdebug_traceTransactionand batched requests already do. #11450eth_estimateGasandeth_createAccessListnow accept a block hash as well as a block number or tag. #11380- A failing EIP-4788 beacon roots or EIP-2935 history storage system call no longer invalidates the block. #11415
- Publish the jump destination analysis of a contract safely to other threads #11403
- Retry bootnodes while under-peered to avoid a node on a small network staying at zero peers. #11368
- The Bonsai code cache and the EVM jump destination cache refuse to store empty code under a non-empty code hash. #11420
- When fetching announced transactions from a peer, Besu again requests them in the order they were announced and, after a partial response, asks only for the ones not yet returned. Since 26.6.0 the request order did not follow the announcements and every retry asked for the whole batch again, so a peer that returned the whole batch was asked for it a second time unless the last transaction it sent was also the last one announced. #11465
- Replacing a payload build because the consensus client sent new payload attributes is now logged at debug level, with the inputs that changed, instead of as a warning. #11504
- A block build whose transaction selection timed out no longer closes its world state while a transaction is still executing on it. #11473
- The block creation timing logged for an empty payload now shows when that block was built, instead of the process start time. #11461
- Amsterdam now rejects transactions with a gas limit above the EIP-8037 cap of
2^32-1. #11414 - Receipt sync no longer rejects a partial receipt list from a peer when one of its transactions used more than 45M gas. #11414
- A client closing the connection during a streamed JSON-RPC response is logged as a closed connection instead of an error. #11459
- A transaction whose signature does not recover a public key is rejected as
Invalid signatureinstead of causing an internal error. #11458 - The finalized block is updated once at the end of a backward sync session, instead of once per forkchoice update received during it. #11457
- Backward sync, the Engine API and block import no longer move the head world state concurrently, which could corrupt it and stall the node. #11402
- The layered transaction pool no longer gets corrupted when a sender with priority is promoted from the sparse layer, or when a late block selection result refers to a transaction the pool has since replaced or removed. #11462
- Snap sync now restarts instead of staying idle when one of its world state download pipelines fails. #11515
- Snap sync no longer downloads the storage and code of an account twice when an account range response goes past the end of the range. #11516
- Snap sync no longer stalls when a download completes while the pipeline stage is handing on another result. #11514
36ddd158df8ce15c613f0ae9fa66b628f7a31ec3bc09de02efa09c0ae11f41b1 besu-26.10.0.zip
927429dd887aca3deb09196c42c88f883258b97d3b9269a12e0204f00d8a5d96 besu-26.10.0.tar.gz