Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
b5747f3
consensus, core, miner, params: source reserved base-fee capacity fro…
kamuikatsurgi Aug 11, 2026
0747234
core/txpool: admit fallback-fee reserved transactions without balance…
kamuikatsurgi Aug 11, 2026
a1595be
merge ws1: reserved capacity header (POS-3669)
kamuikatsurgi Aug 11, 2026
281ab8f
merge ws3: txpool balance waivers (POS-3671)
kamuikatsurgi Aug 11, 2026
7c24a7f
core, core/rawdb, miner, internal/ethapi: zero effective gas price on…
kamuikatsurgi Aug 11, 2026
3ca9655
merge ws2: reserved receipts side table (POS-3670)
kamuikatsurgi Aug 11, 2026
a89f78c
core/vm: make dispatch interrupt tests independent of execution speed
kamuikatsurgi Aug 12, 2026
9e9f638
merge develop into scratch/rbs-integration to test against latest bor
kamuikatsurgi Aug 12, 2026
0fcb9a0
merge reserved-blockspace-block-building (now current with develop) f…
kamuikatsurgi Aug 12, 2026
9ab1760
core/txpool, internal/cli/server: bound aggregate reserved-sender txp…
kamuikatsurgi Aug 14, 2026
ffb80b5
merge reserved-blockspace-block-building (now current with develop) f…
kamuikatsurgi Aug 14, 2026
22a5b1c
merge reserved-blockspace-block-building (now current with develop) f…
kamuikatsurgi Aug 17, 2026
b724146
eth/gasprice, internal/ethapi: exclude reserved transactions from fee…
kamuikatsurgi Aug 18, 2026
5c2dae8
core, consensus/bor/registryreader: emit reserved-region chain metric…
kamuikatsurgi Aug 18, 2026
330ca68
core, tests/bor: add reserved-blockspace execution determinism covera…
kamuikatsurgi Aug 18, 2026
11b9cdc
merge reserved-blockspace-block-building (now current with develop) f…
kamuikatsurgi Aug 18, 2026
54f709e
core/txpool/legacypool: drop unused test config helper
kamuikatsurgi Aug 18, 2026
bc458c8
merge reserved-blockspace-block-building (now current with develop) f…
kamuikatsurgi Aug 25, 2026
da1cdd2
merge reserved-blockspace-block-building (pipelined-import reserved v…
kamuikatsurgi Aug 25, 2026
1c2bfef
tests: deflake reserved pool balance test's cross-node pool assertion
kamuikatsurgi Aug 25, 2026
124087f
consensus/bor/registryreader: keep non-free fee-mode clients out of t…
kamuikatsurgi Aug 25, 2026
cf9f3e8
core/state, consensus/bor: keep isolated system-call reads in produce…
kamuikatsurgi Aug 25, 2026
7f9f819
miner: stop pipeline test workers before mutating their fields
kamuikatsurgi Aug 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 68 additions & 42 deletions consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -1069,26 +1069,29 @@ func (c *Bor) giuglianoExtraFields(header *types.Header, parent *types.Header) (
return &gt, &bfcd
}

// reservedGasUsedPlaceholder returns the zero-valued reserved-gas field for
// post-ReservedBlockspace headers, so the field is present (non-nil) from
// Prepare on and the header passes the verifyReservedFields presence check
// even when there are no reserved transactions. The miner overwrites it with
// the block's real reserved gas total at the end of block building
// (worker.writeReservedGasUsed). Nil pre-fork, keeping the field off the wire.
func (c *Bor) reservedGasUsedPlaceholder(header *types.Header) *uint64 {
// reservedFieldsPlaceholder returns zero-valued reserved-gas and capacity
// fields for post-ReservedBlockspace headers, so both are present (non-nil)
// from Prepare on and the header passes the verifyReservedFields presence
// check even when there are no reserved transactions or the registry carves
// out no capacity yet. The miner overwrites both with the block's real values
// at the end of block building (worker.writeReservedFields). Nil pre-fork,
// keeping the fields off the wire.
func (c *Bor) reservedFieldsPlaceholder(header *types.Header) (gasUsed, capacity *uint64) {
if !c.config.IsReservedBlockspace(header.Number) {
return nil
return nil, nil
}

var zeroGas uint64
var zeroGas, zeroCapacity uint64

return &zeroGas
return &zeroGas, &zeroCapacity
}

// verifyReservedFields checks that post-ReservedBlockspace headers carry the
// reserved-region gas field, plus a header-only bound on its value. Value
// correctness (the sum over the block's reserved transactions, per-client
// quota) is a body-level check that lands with the block-validation slice.
// reserved-region fields, plus a header-only bound on ReservedGasUsed. Value
// correctness for both fields (the sum over the block's reserved transactions
// for gas used, the registry snapshot's effective capacity for capacity) is a
// body-level check that lands with the block-validation slice
// (validateReservedFields).
func (c *Bor) verifyReservedFields(header *types.Header) error {
if !c.config.IsReservedBlockspace(header.Number) {
return nil
Expand All @@ -1097,12 +1100,23 @@ func (c *Bor) verifyReservedFields(header *types.Header) error {
if reservedGasUsed == nil {
return errMissingReservedBlockspaceFields
}
if header.GetReservedCapacity(c.chainConfig) == nil {
return errMissingReservedBlockspaceFields
}
// The reserved region is a subset of the block, so its gas cannot exceed the
// block's gas used. Reject the impossible value rather than letting CalcBaseFee
// silently clamp it (the base fee consumes parent.ReservedGasUsed).
if *reservedGasUsed > header.GasUsed {
return errReservedGasUsedExceedsBlock
}
// No bound here ties ReservedCapacity to GasLimit: governance (setLimits,
// quota updates) has no tie to the block gas limit, which is itself
// operator-tunable per block, so a registry state whose effective
// capacity meets or exceeds GasLimit is a reachable, valid state.
// Rejecting it at the header would leave no valid next block and halt the
// chain; the exact value is enforced against the registry by
// validateReservedFields instead, and CalcBaseFee's reserved-aware target
// falls back deterministically when capacity >= GasLimit.
return nil
}

Expand Down Expand Up @@ -1188,7 +1202,9 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, w

gasTarget, baseFeeChangeDenom := c.giuglianoExtraFields(header, parent)

blockExtraDataBytes, err := types.EncodeBlockExtraData(c.chainConfig, header.Number, tempValidatorBytes, gasTarget, baseFeeChangeDenom, c.reservedGasUsedPlaceholder(header))
reservedGasUsed, reservedCapacity := c.reservedFieldsPlaceholder(header)

blockExtraDataBytes, err := types.EncodeBlockExtraData(c.chainConfig, header.Number, tempValidatorBytes, gasTarget, baseFeeChangeDenom, reservedGasUsed, reservedCapacity)
if err != nil {
log.Error("error while encoding block extra data", "err", err)
return fmt.Errorf("error while encoding block extra data: %v", err)
Expand All @@ -1203,7 +1219,9 @@ func (c *Bor) Prepare(chain consensus.ChainHeaderReader, header *types.Header, w
} else if c.chainConfig.IsCancun(header.Number) {
gasTarget, baseFeeChangeDenom := c.giuglianoExtraFields(header, parent)

blockExtraDataBytes, err := types.EncodeBlockExtraData(c.chainConfig, header.Number, nil, gasTarget, baseFeeChangeDenom, c.reservedGasUsedPlaceholder(header))
reservedGasUsed, reservedCapacity := c.reservedFieldsPlaceholder(header)

blockExtraDataBytes, err := types.EncodeBlockExtraData(c.chainConfig, header.Number, nil, gasTarget, baseFeeChangeDenom, reservedGasUsed, reservedCapacity)
if err != nil {
log.Error("error while encoding block extra data", "err", err)
return fmt.Errorf("error while encoding block extra data: %v", err)
Expand Down Expand Up @@ -1848,31 +1866,51 @@ func (c *Bor) checkAndCommitSpan(
var ctx = context.Background()
headerNumber := header.Number.Uint64()

tempState := state.Inner().Copy()
tempState.ResetPrefetcher()
tempState.StartPrefetcher("bor", state.Witness(), nil)

span, err := c.spanner.GetCurrentSpan(ctx, header.ParentHash, tempState)
span, err := c.readCurrentSpan(ctx, state.Inner(), header.ParentHash)
if err != nil {
return err
}

tempState.IntermediateRoot(false)

// Propagate addresses accessed during GetCurrentSpan back to the original
// state so they appear in the FlatDiff ReadSet. Without this, the pipelined
// SRC goroutine's witness won't capture their trie proof nodes (the copy's
// reads aren't tracked on the original), causing stateless execution to fail
// with missing trie nodes for the validator contract.
tempState.PropagateReadsTo(state.Inner())

if c.needToCommitSpan(span, headerNumber) {
return c.FetchAndCommitSpan(ctx, span.Id+1, state, header, chain)
}

return nil
}

// readCurrentSpan reads the span contract isolated from the live block state,
// while keeping the read's trie nodes in any witness being produced - a
// stateless verifier repeats this read, so the witness must carry them (see
// state.ReadIsolated).
func (c *Bor) readCurrentSpan(ctx context.Context, stateDB *state.StateDB, parentHash common.Hash) (*borTypes.Span, error) {
var span *borTypes.Span
err := stateDB.ReadIsolated(func(tmp *state.StateDB) error {
var err error
span, err = c.spanner.GetCurrentSpan(ctx, parentHash, tmp)
return err
})
if err != nil {
return nil, err
}
return span, nil
}

// readLastStateID reads the state-receiver contract's last state-sync id
// isolated from the live block state, with the same witness guarantees as
// readCurrentSpan.
func (c *Bor) readLastStateID(stateDB *state.StateDB, number uint64, hash common.Hash) (*big.Int, error) {
var id *big.Int
err := stateDB.ReadIsolated(func(tmp *state.StateDB) error {
var err error
id, err = c.GenesisContractsClient.LastStateId(tmp, number, hash)
return err
})
if err != nil {
return nil, err
}
return id, nil
}

func (c *Bor) needToCommitSpan(currentSpan *borTypes.Span, headerNumber uint64) bool {
// If span is nil, return false.
if currentSpan == nil {
Expand Down Expand Up @@ -2000,23 +2038,11 @@ func (c *Bor) CommitStates(

if c.config.IsIndore(header.Number) {
// Fetch the LastStateId from contract via current state instance
tempState := state.Inner().Copy()
tempState.ResetPrefetcher()
tempState.StartPrefetcher("bor", state.Witness(), nil)

lastStateIDBig, err = c.GenesisContractsClient.LastStateId(tempState, number-1, header.ParentHash)
lastStateIDBig, err = c.readLastStateID(state.Inner(), number-1, header.ParentHash)
if err != nil {
return nil, err
}

tempState.IntermediateRoot(false)

// Propagate addresses accessed during LastStateId back to the original
// state so they appear in the FlatDiff ReadSet. Without this, the
// pipelined SRC goroutine's witness won't capture their trie proof
// nodes, causing stateless execution to fail with missing trie nodes.
tempState.PropagateReadsTo(state.Inner())

stateSyncDelay := c.config.CalculateStateSyncDelay(number)
to = time.Unix(int64(header.Time-stateSyncDelay), 0)
} else {
Expand Down
Loading
Loading