Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 12 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,24 @@

# UNRELEASED

- The minimum supported Golang version is now `1.24.7`
- feat(gateway): expose StateGetRandomnessDigestFromBeacon ([filecoin-project/lotus#13339](https://github.com/filecoin-project/lotus/pull/13339))
- chore(deps): update of quic-go to v0.54.1 and go-libp2p to v0.43.0 ([filecoin-project/lotus#13361](https://github.com/filecoin-project/lotus/pull/13361))
- feat(spcli): add a `deposit-margin-factor` option to `lotus-miner actor new` and `lotus-shed miner create` so the sent deposit still covers the on-chain requirement if it rises between lookup and execution
- feat(cli): lotus evm deploy prints message CID ([filecoin-project/lotus#13378](https://github.com/filecoin-project/lotus/pull/13378))
- chore: update benchmark tests to use testing.B.Loop for improved performance ([filecoin-project/lotus#13385](https://github.com/filecoin-project/lotus/pull/13385)) ([filecoin-project/lotus#13396](https://github.com/filecoin-project/lotus/pull/13396)) ([filecoin-project/lotus#13405](https://github.com/filecoin-project/lotus/pull/13405))
- fix(eth): properly return vm error in all gas estimation methods ([filecoin-project/lotus#13389](https://github.com/filecoin-project/lotus/pull/13389))
- chore: all actor cmd support --actor ([filecoin-project/lotus#13391](https://github.com/filecoin-project/lotus/pull/13391))
- feat(spcli): add a `deposit-margin-factor` option to `lotus-miner init` so the sent deposit still covers the on-chain requirement if it rises between lookup and execution
- feat(consensus): wire tipset gas reservations and reservation-aware mempool pre-pack to activate at network version 28 (UpgradeXxHeight), keeping receipts and gas accounting identical while preventing miner penalties from underfunded intra-tipset messages

## 👌 Improvements
- docs: fix outdated link in documentation ([#13436](https://github.com/filecoin-project/lotus/pull/13436))
- docs: fix dead link in documentation ([#13437](https://github.com/filecoin-project/lotus/pull/13437))

# UNRELEASED v1.34.2

See https://github.com/filecoin-project/lotus/blob/release/v1.34.2/CHANGELOG.md

See https://github.com/filecoin-project/lotus/blob/release/v1.34.2/CHANGELOG.md
# Node and Miner v1.34.1 / 2025-09-15

This is a non-critical patch release that fixes an issue with the Lotus `v1.34.0` release where the incorrect version of filecoin-ffi was included. Lotus `v1.34.0` used filecoin-ffi `v1.34.0-dev` when it should have used `v1.34.0`. This isn’t critical since it’s the same filecoin-ffi version used during the nv27 Calibration network upgrade, but for consistency with other Node implementations like Forest, we are creating this release. This ensures the inclusion of ref-fvm `v4.7.3` update that was missing in v1.34.0. All users of v1.34.0 are encouraged to upgrade to v1.34.1.
Expand Down
118 changes: 78 additions & 40 deletions chain/consensus/compute_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"golang.org/x/xerrors"

amt4 "github.com/filecoin-project/go-amt-ipld/v4"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/big"
Expand Down Expand Up @@ -196,6 +197,10 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
}
}

// Network version at the execution epoch, used for reservations activation
// and gating.
nv := sm.GetNetworkVersion(ctx, epoch)

vmEarlyDuration := partDone()
earlyCronGas := cronGas
cronGas = 0
Expand All @@ -206,50 +211,77 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
return cid.Undef, cid.Undef, xerrors.Errorf("making vm: %w", err)
}

var (
receipts []*types.MessageReceipt
storingEvents = sm.ChainStore().IsStoringEvents()
events [][]types.Event
processedMsgs = make(map[cid.Cid]struct{})
)

var msgGas int64

for _, b := range bms {
penalty := types.NewInt(0)
gasReward := big.Zero()

for _, cm := range append(b.BlsMessages, b.SecpkMessages...) {
m := cm.VMMessage()
if _, found := processedMsgs[m.Cid()]; found {
continue
}
r, err := vmi.ApplyMessage(ctx, cm)
if err != nil {
return cid.Undef, cid.Undef, err
}

msgGas += r.GasUsed

receipts = append(receipts, &r.MessageReceipt)
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)

if storingEvents {
// Appends nil when no events are returned to preserve positional alignment.
events = append(events, r.Events)
}
// Start a tipset reservation session around explicit messages. A deferred
// call ensures the session is closed on all paths, while the explicit call
// before cron keeps the session scope limited to explicit messages.
if err := startReservations(ctx, vmi, bms, nv); err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("starting tipset reservations: %w", err)
}
defer func() {
if err := endReservations(ctx, vmi, nv); err != nil {
log.Warnw("ending tipset reservations failed", "error", err)
}
}()

if em != nil {
if err := em.MessageApplied(ctx, ts, cm.Cid(), m, r, false); err != nil {
var (
receipts []*types.MessageReceipt
storingEvents = sm.ChainStore().IsStoringEvents()
events [][]types.Event
processedMsgs = make(map[cid.Cid]struct{})
seenSenders = make(map[address.Address]struct{}) // Strict Sender Partitioning
)

var msgGas int64

for _, b := range bms {
penalty := types.NewInt(0)
gasReward := big.Zero()
currentBlockSenders := make(map[address.Address]struct{})

for _, cm := range append(b.BlsMessages, b.SecpkMessages...) {
m := cm.VMMessage()
if _, found := processedMsgs[m.Cid()]; found {
continue
}

// Strict Sender Partitioning:
// If this sender was seen in a previous block (higher precedence),
// ignore this message completely.
if _, found := seenSenders[m.From]; found {
continue
}

r, err := vmi.ApplyMessage(ctx, cm)
if err != nil {
return cid.Undef, cid.Undef, err
}

msgGas += r.GasUsed

receipts = append(receipts, &r.MessageReceipt)
gasReward = big.Add(gasReward, r.GasCosts.MinerTip)
penalty = big.Add(penalty, r.GasCosts.MinerPenalty)

if storingEvents {
// Appends nil when no events are returned to preserve positional alignment.
events = append(events, r.Events)
}

if em != nil {
if err := em.MessageApplied(ctx, ts, cm.Cid(), m, r, false); err != nil {
return cid.Undef, cid.Undef, err
}
}
processedMsgs[m.Cid()] = struct{}{}
currentBlockSenders[m.From] = struct{}{}
}
processedMsgs[m.Cid()] = struct{}{}
}

params := &reward.AwardBlockRewardParams{
Miner: b.Miner,

// After processing the block, mark its senders as seen for future blocks.
for s := range currentBlockSenders {
seenSenders[s] = struct{}{}
}

params := &reward.AwardBlockRewardParams{ Miner: b.Miner,
Penalty: penalty,
GasReward: gasReward,
WinCount: b.WinCount,
Expand All @@ -260,6 +292,12 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
}
}

// End the reservation session before running cron so that reservations
// strictly cover explicit messages only.
if err := endReservations(ctx, vmi, nv); err != nil {
return cid.Undef, cid.Undef, xerrors.Errorf("ending tipset reservations: %w", err)
}

vmMsgDuration := partDone()
partDone = metrics.Timer(ctx, metrics.VMApplyCron)

Expand Down
53 changes: 53 additions & 0 deletions chain/consensus/features.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package consensus

import "os"

// ReservationFeatureFlags holds feature toggles for tipset gas reservations.
//
// These flags are evaluated by consensus and the message pool when deciding
// whether to attempt tipset‑scope reservations pre‑activation, and how to
// interpret Begin/End reservation errors.
type ReservationFeatureFlags struct {
// MultiStageReservations enables tipset‑scope gas reservations
// pre‑activation. When false, ReservationsEnabled returns false for
// network versions before ReservationsActivationNetworkVersion and Lotus
// operates in legacy mode (no Begin/End calls).
//
// At or after activation, reservations are always enabled regardless of
// this flag.
MultiStageReservations bool

// MultiStageReservationsStrict controls how pre‑activation reservation
// failures are handled when MultiStageReservations is true:
//
// - When false (non‑strict), non‑NotImplemented Begin/End errors such
// as ErrReservationsInsufficientFunds and ErrReservationsPlanTooLarge
// are treated as best‑effort: Lotus logs and falls back to legacy
// mode for that tipset.
// - When true (strict), those reservation failures invalidate the
// tipset pre‑activation. Node‑error classes (e.g. overflow or
// invariant violations) always surface as errors regardless of this
// flag.
MultiStageReservationsStrict bool
}

// Feature exposes the current reservation feature flags.
//
// Defaults:
// - MultiStageReservations: enabled when LOTUS_ENABLE_TIPSET_RESERVATIONS=1.
// - MultiStageReservationsStrict: enabled when
// LOTUS_ENABLE_TIPSET_RESERVATIONS_STRICT=1.
//
// These defaults preserve the existing environment‑based gating while making
// the flags explicit and testable.
var Feature = ReservationFeatureFlags{
MultiStageReservations: os.Getenv("LOTUS_ENABLE_TIPSET_RESERVATIONS") == "1",
MultiStageReservationsStrict: os.Getenv("LOTUS_ENABLE_TIPSET_RESERVATIONS_STRICT") == "1",
}

// SetFeatures overrides the global reservation feature flags. This is intended
// for wiring from higher‑level configuration and for tests; callers should
// treat it as process‑wide and set it once during initialization.
func SetFeatures(flags ReservationFeatureFlags) {
Feature = flags
}
Loading
Loading