Repository navigation
Conversation
eth: fix peerSet lock deadlock in waitSnapExtension
eth: cap NewBlockHashesPacket length
consensus/parlia: add metrics for assembleVoteAttestation outcomes
* params: add Jenner hardfork definition * params: enforce Jenner fork ordering and readiness plumbing * core/vm: support block-context-aware precompile dispatch Add a MilliTimestamp field to vm.BlockContext (filled from Header.MilliTimestamp() in NewEVMBlockContext) and an optional BlockContextPrecompiledContract interface. RunPrecompiledContract takes the block context and dispatches to RunWithBlockContext when a precompile implements the optional interface; all existing precompiles keep the plain Run(input) path unchanged. All call sites (4 production, 5 in tests/fuzzers) updated mechanically. No behavior change. * core/vm: implement BEP-706 milliTimestamp precompile * core/vm: enable milliTimestamp precompile from Jenner fork * core: add Jenner fork transition chain-level test * cmd, eth, core: add --override.jenner flag * internal/ethapi: sync millisecond timestamp for block overrides * core/vm: add fuzz test for milliTimestamp precompile * internal/ethapi: treat prevRandao override as millisecond remainder On BSC the header field behind the prevRandao override (MixDigest) carries the millisecond remainder of the block timestamp (BEP-520) — consensus enforces a value below 1000 and the real chain never exposes it to the EVM as randomness. Follow the same semantics for block overrides on this client: the value is validated (< 1000, rejected otherwise so callers cannot pass arbitrary random values) and assembled into the millisecond timestamp reported by the BEP-706 precompile (time*1000 + prevRandao), while still replacing blockCtx.Random. The eth_simulateV1 block context now derives the millisecond timestamp from the simulated header's MixDigest directly, with the same bound enforced in sanitizeChain. Documented on BlockOverrides.PrevRandao; to be supplemented in BEP-706. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * eth/catalyst: handle Jenner fork in simulated beacon Without a Jenner case, payloadVersion fell through to the post-merge panic once Jenner became the latest fork — reachable on the block production path (sealPayload). Jenner does not change the Engine payload version, so report the underlying fork set's version: V4 when Amsterdam is active beneath it, V3 otherwise (Jenner is always the latest fork, so it can sit on top of either). The slot-number payload attribute check has the same latent issue: it compared LatestFork against Amsterdam by equality, which Jenner-over-Amsterdam would miss, so it now uses IsAmsterdam directly. Covered by a unit test for pre-fork, Jenner-over-V3 and Jenner-over-Amsterdam. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * internal/ethapi: fix lint issues in jenner override tests Drop a redundant Go 1.22+ loop-variable copy (copyloopvar) and an ineffectual first assignment to headRandao (ineffassign) flagged by golangci-lint in CI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * core/vm: keep UBT precompile set above Jenner Jenner sat above UBT in the activePrecompiledContracts switch, so a config with both rules active (only representable on a Parlia+UBT devnet through RPC simulation — consensus never sets both, isMerge is always false on BSC) would swap the active UBT set for a Pasteur-derived one. Restore the pre-existing precedence: UBT keeps shadowing every BSC fork set, Jenner included, matching how it already shadows Pasteur. Regression test asserts every UBT precompile stays available and 0x70 is absent when both rules are active. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * params, core, eth: order Jenner right after Pasteur * core: use a generated key in the Jenner chain test * internal/ethapi, params: address PR review comments --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…e Amsterdam BlockAccessListHash (EIP-7928) and SlotNumber (EIP-7843) are trailing rlp:"optional" header fields that are covered by the block hash but not by the Parlia seal preimage (EncodeSigHeader stops after RequestsHash). Parlia's header verification never validated them, so before Amsterdam an unprivileged peer could append a crafted BlockAccessListHash to any validator-signed block: RLP-valid, seal preimage and signature unchanged, but a different block hash. Every node accepted the mutated block as validly sealed, letting a peer with no stake or key grind the block hash of an honest validator's block (e.g. to bias BLOCKHASH-based consumers or win a same-height lower-hash fork-choice tie). Validate these fields in VerifyUnsealedHeader, which is on the peer-import path (VerifyHeader -> verifyHeader -> VerifyUnsealedHeader, before verifySeal) as well as the bid pre-seal path, mirroring the existing RequestsHash/ParentBeaconRoot handling: require them absent before Amsterdam and present from Amsterdam on. This closes the live pre-Amsterdam malleability; from Amsterdam the fields are legitimately present and their content is bound by state validation and the slot rules. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* miner: persist BidBlock revokes across restarts * miner: journal BidBlock revokes under datadir instead of chaindata * miner: version the BidBlock revoke journal and pin its keys
* internal/ethapi: introduce gRPC endpoint for mev send bidblock request * internal/ethapi: expose MEV protobuf definitions * internal/ethapi: preserve MEV error details over gRPC * eth, miner: configure MEV gRPC by port
…e at Jenner verifyDoubleSignEvidence charges a flat DoubleSignEvidenceVerifyGas regardless of input size, while Run computes SealHash over both RLP-decoded headers whose Extra fields are not size-bounded, so the metered cost does not track the hashing work. Add a Jenner-gated variant (verifyDoubleSignEvidenceJenner) pricing per input byte (DoubleSignEvidenceVerifyPerByteGas = 16), mirroring 0x67's cometBFTLightBlockValidatePasteur. Verification logic inherited unchanged; pre-Jenner tables (including Pasteur) keep the flat-gas contract. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Expose Miner.Config.DelayLeftOver via mev_params so builders can compute BidMustBefore per validator instead of hardcoding 15ms.
…r-nil consensus/parlia: validate BlockAccessListHash and SlotNumber in header verification
core/vm: price the 0x68 double-sign-evidence precompile per input byte at Pasteur
* params: add the Jenner fork and the CAS20 governance constant
Jenner is the fork BEP-702 ships in. IsOnJenner marks the single block that
crosses into it, and it counts block 1 as that block on a chain whose genesis is
already Jenner-active — such a chain has no false-to-true transition to find, and
the fork's state changes have to be applied somewhere or the feature can never be
bootstrapped.
CAS20GovHubAddress duplicates GovHub's fixed system address, which
core/systemcontracts cannot supply because it imports core/vm and so cannot be
imported back. It is the one address a governance proposal can reach the
activation registry through, and it is the same on every network — which is why
the switch can be a constant rather than configuration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: add the stateful-precompile host and the CAS20 token family
Two layers, in one commit because they do not compile apart: the host's AddLog
meters through a charge helper the family defines.
**The host.** A StatefulPrecompiledContract receives a PrecompileContext
carrying the StateDB, the caller, the call-form guards and dynamic gas
accounting, so a precompile can read and write consensus state. RequiredGas
reports nothing, because a stateful cost depends on state not yet read — whether
a slot is cold, whether a write creates or rewrites — so metering happens inside
the handler as the work is performed. Existing precompiles and
RunPrecompiledContract are untouched.
Gas accounting is frame-scoped and sticky. A refused charge marks the frame and
every later charge on it refuses too, so one failure ends the call rather than
letting the rest of a handler run on an exhausted budget; the exit turns that
mark into ErrOutOfGas whatever the handler returned. Charges mirror the
interpreter's own cost functions — EIP-2929 warm/cold, EIP-2200 net metering with
EIP-3529 refunds, the EIP-2200 reentrancy sentry, LOG and KECCAK256 prices — so
nothing a CAS20 call does is cheaper than the same work through bytecode.
**The family.** A factory at a fixed address derives a token's address from
(variant, creator, salt) and plants a one-byte 0xEF sentinel there; the token
holds no executable code, is routed by its address prefix, and keeps its state
under that address in ERC-7201 namespaces. Two variants — Asset, with the
ERC-8056 scaled multiplier and disclosure announcements, and Stablecoin — share
the shared ERC-20 surface, role-based access control, a pause mask, EIP-2612
permit, and transfer policies resolved through a singleton PolicyRegistry. An
ActivationRegistry holds the per-feature switch that gates creation and policy
writes, and never reaches a token that already exists.
Every state write is metered before it happens and refused in a read-only frame
by the metering layer itself, so a handler that forgot its own guard cannot write
during a STATICCALL. Malformed calldata and unknown selectors revert with empty
returndata rather than a selector echo, keeping one client's internal strings out
of consensus.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/systemcontracts: plant the CAS20 registry sentinels at the fork
The two singleton registries hold storage and no code, so EIP-161 would clear
them and their storage with them. They are precompiles rather than upgradeable
contracts, so the sentinels are planted here instead of through an Upgrade
config, and nothing else is written: no feature is opened and there is no admin
to seed, the activation admin being governance's to appoint afterwards.
The sentinels are also what make that appointment possible. GovHub refuses a
proposal target carrying no code and reports the refusal in an event while
leaving the proposal itself successful, so a registry without one could never
receive its first parameter change and the failure would read as a success.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: answer as an equivalent Solidity contract does
Nine places where the precompiles answered differently from the contract they
stand in for. None was reachable from a test the suite had, because the checks
that would have caught them compared our own artifacts against each other.
Argument decoding. A malformed narrow argument is a decode failure, and
Solidity's external decoder reverts with empty returndata for every one of them:
an integer outside an enum's range, a bool that is neither 0 nor 1, a uint8 or
address carrying padding a caller could not have produced, a bytes4 with nonzero
trailing bytes. Measured against solc 0.8.16 and 0.8.19, which agree. Panic(0x21)
comes from an internal uint-to-enum cast and never from argument handling, so
seven sites raising it were reporting a failure Solidity does not report there;
supportsInterface answered false for an encoding it should have refused. The six
Panic(0x11) sites are arithmetic overflow and stay.
PolicyRegistry. The registry's absence error carries no id — the caller named the
policy — and the parameterized form belongs to a token reporting an id it could
not find; two composite paths used the token's. createCompositePolicy checked the
type before the zero-admin guard, where the two simple constructors check the
admin first; all three now agree, and the order is observable through which error
a caller receives. Child validation ran one interleaved pass per child, so a set
naming both an ineligible child and a missing one reported whichever came first;
it now runs existence over the whole set before eligibility over the whole set,
and a set holding both reports the absence. A sentinel was accepted as a child,
though it stores no membership for a composite to consult. And an INTERSECT over
no children answered false, alone among the four types in not taking its own
empty-set semantics: an AND over nothing is vacuously true, which makes a
never-created INTERSECT as permissive as a never-created BLOCKLIST already was.
Binding checks existence, so no token can reference either.
Storage. A string length word in the long form encodes 32 bytes or more; a
shorter one is as non-canonical as an oversized one and now reads as empty. The
word has two readers, and the second feeds setStringAt's release loop, so leaving
it out would have released chunks for a string the reader reports as absent.
Every change is witnessed: reverting any one of them fails a test.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: open the token space at 0xCA52
The reserved prefix is two bytes, but the eight zero bytes that follow it are
part of the layout, so the first five hex digits of every token address are the
marker plus a zero the padding supplies for free. Spending the second byte on
0x52 makes those digits spell the standard's name; 0x50 spelled it without its
number.
Nothing structural moves. The factory keeps 0xCA5F, the registries keep 0x7020,
and the reserved-space audit was made against the whole 0xCA5 namespace rather
than the token prefix alone, so it covers this choice without being redone.
The one vector that names the prefix in full is the padding case, which has to
carry a valid marker to reach the check it is named for. It does, and deleting
the padding check still fails it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: drop comments the identifier already makes
A doc comment that restates its own name costs a reader the time to find that
out. Eleven of them go; what stays is the half a name cannot carry.
Deleted outright where the signature was the whole story: eventTopic, revCAS20,
revCAS20Bytes, the policy precompile type, the core storage root. Trimmed to the
part that is not derivable elsewhere: the delegate-call error keeps why it is
refused rather than what it is, cas20ErrorSel keeps that it registers as well as
computes, and two exported accessors keep their one line and lose the examples of
who calls them.
Left alone: anything naming a consensus rule, a check order, or a distinction the
identifier does not draw — that a policy view is metered where the same type has
an unmetered constructor, which two of the four policy types count as composite,
that an empty metadata value clears rather than writes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: plant the registry sentinels only at the fork
Remove the lazy ensureSentinel path that every registry write ran. On a
conforming chain it was unreachable: the fork transition seeds both
registries before any transaction, and it could not rescue the case it
existed for, since GovHub tests extcodesize before forwarding a
parameter change and would have refused the registry before the write
was ever attempted. What it did cost was a code-hash read per write.
With the admin appointed through governance rather than taken from
configuration, the fork hook is the only path that can plant the byte,
and it now stands alone. The sentinel tests that only exercised the lazy path go
with it; the seeded case gains a negative control showing a bare
account with the same storage is reaped by EIP-161 clearing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: decode announce and batchMint arguments before the state checks
Solidity's dispatcher decodes a function's arguments before any
modifier runs, so calldata that does not decode is reported as such
whoever sent it and whatever the token's state. announce and batchMint
checked the pause, the role and the reentrancy flag first, answering a
business error for a payload that never named a valid call.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: keep only the comments a name cannot carry
Delete a comment when the identifier or the body already says it, or
when a test pins the behaviour; keep, compressed, the why a name cannot
express and no test guards: check order, storage layout, deliberate
dead code, the gas and sentinel invariants. Test files lose the step
comments that restated their own assertion messages.
Dead code met on the way goes too: the unused cas20PendingMulBits, an
activate() call in a test whose result was discarded, updateMembers'
second identical bool check, and finalizeUpdateAdmin's zero-caller
clause already implied by the non-zero pending admin. readU64 now
delegates to u64FromWord instead of repeating its loop.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: bound getStringAt's allocation by paid reads; log a foreign registry code
getStringAt allocated the stored length before any tail read was
charged, so a call forwarding too little gas could still trigger a
large allocation before running out. The buffer now grows only behind
reads that were paid for.
seedCAS20Sentinel finding code on a registry address can only mean an
address collision, so say so in the log instead of returning silently.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* params: write IsOnJenner the way IsOnPasteur is written
Drop the arm that treated block 1 as the fork boundary on a chain born
Jenner-active. CAS20MarkerCode is exported so such a chain carries the
registry sentinels in its genesis allocation, as the other system
accounts do; the boundary predicate then needs no special case and
reads like the other IsOn* helpers. Also restore UBTTime to its place
in the aligned field block.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: answer newUIMultiplier with the current multiplier when nothing is scheduled
It returned the raw pending lane, which is zero for a new token, after an
instant update and after a cancellation. ERC-8056 answers with
the effective multiplier whenever no schedule is live.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm, internal/ethapi: add cas20_getTokenInfo
A wallet reading one CAS20 token today issues a dozen eth_calls against
the same address, and reconstructing a consistent view of the scheduled
multiplier from multiplier, newUIMultiplier and effectiveAt across
separate calls is racy across blocks. cas20_getTokenInfo(address, block)
answers the whole configuration from one state, variant-tagged, with the
effective multiplier already folded and a pending schedule reported only
while it is live; cas20_getTokenInfoBatch does the same over up to twenty
addresses, answering null for one that holds no token.
The facade reads through the unmetered storage accessors and is bounded
against state the precompile could not have written: a string longer than
256 KiB is refused rather than walked. The namespace is not in the default
module list.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* internal/ethapi: serve the CAS20 token info from the eth namespace
eth_getCAS20TokenInfo and eth_getCAS20TokenInfoBatch, beside the other
BSC additions to eth_, so no extra module has to be enabled.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: decode before the static-frame guard in every token method
pause, batchMint and announce refused a static frame before decoding
their arguments, while every other token method decodes first, so the
same malformed calldata under STATICCALL reported StaticCallNotAllowed
from three methods and an empty revert from the rest. The order is
observable and therefore consensus; every token method now shares one
prefix. The factory and the registries keep their guard before decoding.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: refuse a code write in a static frame at the metering layer
chargeStorageWrite and AddLog already mark the frame write-protected, so a
handler missing its own guard fails closed; chargeCodeWrite did not, and
the factory's SetCode was covered only by the entry-point guard. Now every
mutation the family performs is refused at the point of mutation as well.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: name the standard, not another implementation, in comments
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: charge each internal dispatch what the reference contract pays
The bytes[] decoder accepts entries whose offsets alias one another, so an
announce bundle or an initCalls array of size O(N+M) could name N×M
dispatches, and a constant getter reads no state, so each one ran for
nothing: 12.5M dispatches fit in a 15M-gas transaction and took 746 ms.
Every entry now pays a warm CALL plus the copy of its own bytes before it
runs, which is what the reference contract pays to route it through a call
of its own. Aliasing stays accepted; it is no longer free.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/systemcontracts: pin the CAS20 GovHub constant to GovHubContract
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: make the dispatch-charge test run out of gas inside the loop
The negative case's budget could not pay for the announcement itself, so it
never reached the loop it claimed to test. It now pays for the announcement
and exactly 200 dispatches, then for a hundred fewer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/tracing, core/vm, eth/tracers: announce native storage access to tracers
The prestate and access-list tracers discover storage through the SLOAD and
SSTORE opcodes, and a CAS20 operation executes none: a traced transfer
showed no token storage, diffMode missed the balance change, and
eth_createAccessList returned an empty list. A new OnStorageRead hook fires
for every slot a stateful precompile reads or is about to write; the two
tracers consume it and see the same slots bytecode would have shown them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm, internal/ethapi: let a code override reach a CAS20 address
StateOverride.Apply removed an overridden address from the static precompile
map, but a CAS20 address is routed by prefix, so the call still reached
native code and reverted against the replaced marker. An override on such
an address now leaves a DisabledPrecompile marker in the map, which dispatch
reads as "ordinary account"; on-chain routing is untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/tracing, eth/tracers, internal/ethapi: finish the native-access tracing
Three gaps in the previous two commits. An account read had no hook, so a
token appeared in a prestate only once a slot was touched, and createCAS20's
new account was captured after its sentinel was written: the prestate showed
the code as pre-existing and the diff missed its creation. OnAccountRead now
fires before every native account read, from the existence check and the
factory's occupancy check alike. The mux tracer did not forward the new
hooks, so a prestate tracer requested beside a call tracer lost every CAS20
slot again. And eth_createAccessList applied overrides against a nil
precompile map, which a CAS20 code override then wrote to; it now builds the
set, applies the overrides to it and hands it to the EVM it simulates with.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: let a memo transfer declare the format its payload follows
A memo is a 32-byte hash, and a hash says nothing about how the payload
behind it is encoded: an indexer or a receiving institution cannot tell
which message format a transfer claims to follow, or parse the payload it
receives out of band, without a side channel.
transferWithMemoFormat(to, amount, memo, formatId)
transferFromWithMemoFormat(from, to, amount, memo, formatId)
run the ordinary memo transfer of their own entry point — the transferFrom
form is transferFrom whoever calls it, so a holder moving its own balance
spends its self-approval as through transferFromWithMemo — and emit
MemoFormatDeclared(declarer, memo, formatId) right after Memo, so an indexer
ties the declaration to its transfer by log position. The formatId is one
bytes32 naming a format definition maintained off chain: composing several
standards is the definition's business, not the chain's. The chain records
the declaration and nothing more — it never sees the payload, so it never
verifies the claim, and it keeps no registry of formats. A zero formatId is
refused; the plain memo methods are how a transfer declares nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* core/vm: consolidate cas20 abi helpers
* core/tracing, core/vm, eth/tracers: clarify native access hook contracts
* core/vm: simplify gas accounting and compare native access costs
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…BEP-714) (#3822) * consensus/parlia, core/systemcontracts: implement BEP-714 client changes for Jenner
…er, drop dead StateOverride copy (#3826) * core/vm: emit CAS20Created before the admin grant and initCalls CAS20Created is the token's identity record. Emit it as soon as that identity is written, ahead of the initial RoleGranted and whatever the initCalls log, so a creation transaction's logs read in the order the state was built. The event test pins the order. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * core/vm: run the bootstrap window as the factory initCalls are calls the factory makes into the new token, so the token should see the factory as msg.sender, as it would for any contract the factory called. Running them as the creator let the factory act in the creator's name: approve, transfer, burn and the renounce methods inside the window operated on the creator's balances and roles, a power no ordinary caller of the token has. The initial admin's RoleGranted names the factory as sender for the same reason. No test relied on the old caller; the event test now pins the new one. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * internal/ethapi: drop the unused StateOverride copy internal/ethapi/override owns OverrideAccount, StateOverride and Apply, and every RPC path uses that package. The copy left in api.go was reachable only from a test that the override package already carries, and it lacked the DisabledPrecompile handling the live Apply gained, so a future caller pointed at it would silently lose CAS20 override routing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
#3825) * eth/protocols/eth: fix deadlock when re-requesting partial receipts (#35537) When an eth/70 receipts response arrives with LastBlockIncomplete set, requestPartialReceipts re-requested the remainder while holding receiptBufferLock across the dispatch. That dispatch blocks until the dispatcher loop accepts the request. If the loop is concurrently cancelling a request for that peer, its cleanup takes the same receiptBufferLock. The dispatcher then waits for the lock the re-request holds while the re-request waits on a channel only the dispatcher reads. The fix releases the lock before sending and routes the follow-up through the dispatcher as a new resend request. --------- Co-authored-by: Gary Rong <garyrong0905@gmail.com> (cherry picked from commit c57bbe4) * eth/protocols/eth, eth/downloader: reject empty partial receipt responses (#35593) eth/70 can complete a receipts request over multiple round trips. Current implementation has two issues in requester side. 1. A peer could keep a request loop alive with incomplete responses that deliver no receipt. An incomplete response must now add at least one receipt. A trailing empty list after other blocks is still accepted. We already have a grace period and peer-dropping logic covering this, but an additional guard is nice to have. 2. Response.Time is recorded across all rounds, making the peer's roundtrip estimate incorrect. The dispatcher now counts the rounds made under a request id, and the downloader divides the delivered items and elapsed time to one round trip. (cherry picked from commit 596096a) * eth/protocols/eth: add regression tests for partial receipt cancellation and continuation --------- Co-authored-by: 0xSHKWON <kwonsanghyeon3245@naver.com> Co-authored-by: Gary Rong <garyrong0905@gmail.com> Co-authored-by: Bosul Mun <bosul.mun@ethereum.org>
…3847) * params: set bsc testnet jenner hardfork to 2026-10-29 02:30:00 AM UTC * chore: bump 1.8.1 for bsc testnet jenner hf
joey0612
approved these changes
Oct 16, 2026
zlacfzy
approved these changes
Oct 16, 2026
flywukong
approved these changes
Oct 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Merge
developintomasterfor v1.8.1 and the Jenner hardfork on BSC Chapel testnet, scheduled for 2026-10-29 02:30 UTC (1793241000).All Chapel testnet nodes must upgrade before activation. Mainnet activation is not scheduled in this release.
Key Changes
0x70.block.timestampremains in seconds.SendBidBlockaccess on cross-validator bad-block evidence, persists revocations across restarts, and adds bad-block and revocation metrics.Upgrade Notes
8552. Configure[Eth.Miner.Mev] GRPCPortto change the port, or use--mev.grpc.disableto disable it. JSON-RPC remains supported.eth_call,eth_estimateGas,debug_traceCallandeth_simulateV1,blockOverrides.prevRandao, when supplied, must encode a millisecond remainder (0–999) as a 32-byte hex value. This validation applies immediately after upgrading, before Jenner activation.timeremains in seconds.See the v1.8.1 changelog for the full change list and upgrade instructions.