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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@
- chore: update benchmark tests to use testing.B.Loop for improved performance ([filecoin-project/lotus#13385](https://github.com/filecoin-project/lotus/pull/13385))
- 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(api): ChainExport API supports exporting a specified Snapshot version ([filecoin-project/lotus#13395](https://github.com/filecoin-project/lotus/pull/13395))

# 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.

# Node and Miner v1.34.0 / 2025-09-11

This is a **MANDATORY Lotus v1.34.0 release**, which will deliver the Filecoin network version 27, codenamed “Golden Week” 🏮. This release candidate sets the upgrade epoch for the Mainnet network to **Epoch 5348280: 2025-09-24T23:00:00Z**. (See the [local time for other timezones](https://www.worldtimebuddy.com/?qm=1&lid=100,5128581,5368361,1816670&h=100&date=2025-9-24&sln=23-24&hf=1&c=1196).)
This is a **MANDATORY Lotus v1.34.0 release**, which will deliver the Filecoin network version 27, codenamed “Golden Week” 🏮. This release candidate sets the upgrade epoch for the Mainnet network to **Epoch 5348280: 2025-09-24T23:00:00Z**. (See the [local time for other timezones](https://www.worldtimebuddy.com/?qm=1&lid=100,5128581,5368361,1816670&h=100&date=2025-9-24&sln=23-24&hf=1&c=1196).)

## ☢️ Upgrade Warnings ☢️
- All Lotus node and Storage Provider (SP) operators must upgrade to v1.34.x before the specified date for the Mainnet network.
Expand Down
2 changes: 1 addition & 1 deletion api/api_full.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ type FullNode interface {
// back to genesis, the entire genesis state, and the most recent 'nroots'
// state trees.
// If oldmsgskip is set, messages from before the requested roots are also not included.
ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error) //perm:read
ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey, version uint64) (<-chan []byte, error) //perm:read
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is going to be an annoyingly breaking change .. of the type we've kind of agreed to avoid if at all possible in v1

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a change that needs careful consideration, so I'm putting it in a separate PR now.
We will need it eventually, and using lotus-shed to export is not always convenient (need to take the node offline). But I agree that we can discuss it more. I just submitted it first so that you can see the diff


// ChainExportRangeInternal triggers the export of a chain
// CAR-snapshot directly to disk. It is similar to ChainExport,
Expand Down
8 changes: 4 additions & 4 deletions api/mocks/mock_full.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions api/proxy_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions api/v0api/v1_wrapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,4 +213,8 @@ func (w *WrapperV1Full) BeaconGetEntry(ctx context.Context, epoch abi.ChainEpoch
return w.StateGetBeaconEntry(ctx, epoch)
}

func (w *WrapperV1Full) ChainExport(ctx context.Context, nroots abi.ChainEpoch, oldmsgskip bool, tsk types.TipSetKey) (<-chan []byte, error) {
return w.FullNode.ChainExport(ctx, nroots, oldmsgskip, tsk, 2)
}

var _ FullNode = &WrapperV1Full{}
6 changes: 6 additions & 0 deletions chain/lf3/f3.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/filecoin-project/go-f3"
"github.com/filecoin-project/go-f3/blssig"
"github.com/filecoin-project/go-f3/certs"
"github.com/filecoin-project/go-f3/certstore"
"github.com/filecoin-project/go-f3/gpbft"
"github.com/filecoin-project/go-f3/manifest"

Expand All @@ -41,6 +42,7 @@ type F3Backend interface {
Participate(_ context.Context, ticket api.F3ParticipationTicket) (api.F3ParticipationLease, error)
ListParticipants() []api.F3Participant
GetManifest(ctx context.Context) (*manifest.Manifest, error)
GetCertStore() (*certstore.Store, error)
GetCert(ctx context.Context, instance uint64) (*certs.FinalityCertificate, error)
GetLatestCert(ctx context.Context) (*certs.FinalityCertificate, error)
GetPowerTable(ctx context.Context, tsk types.TipSetKey) (gpbft.PowerEntries, error)
Expand Down Expand Up @@ -286,6 +288,10 @@ func (fff *F3) Participate(_ context.Context, ticket api.F3ParticipationTicket)
return fff.leaser.participate(ticket)
}

func (fff *F3) GetCertStore() (*certstore.Store, error) {
return fff.inner.GetCertStore()
}

func (fff *F3) GetCert(ctx context.Context, instance uint64) (*certs.FinalityCertificate, error) {
return fff.inner.GetCert(ctx, instance)
}
Expand Down
13 changes: 11 additions & 2 deletions cli/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1107,9 +1107,13 @@ var ChainExportCmd = &cli.Command{
&cli.BoolFlag{
Name: "skip-old-msgs",
},
&cli.StringFlag{
Name: "version",
Value: "2",
},
},
Action: func(cctx *cli.Context) error {
api, closer, err := GetFullNodeAPI(cctx)
api, closer, err := GetFullNodeAPIV1(cctx)
if err != nil {
return err
}
Expand Down Expand Up @@ -1147,7 +1151,12 @@ var ChainExportCmd = &cli.Command{
return fmt.Errorf("must pass recent stateroots along with skip-old-msgs")
}

stream, err := api.ChainExport(ctx, rsrs, skipold, ts.Key())
version := cctx.Uint64("version")
if version != 1 && version != 2 {
return fmt.Errorf("invalid version %d", version)
}

stream, err := api.ChainExport(ctx, rsrs, skipold, ts.Key(), version)
if err != nil {
return err
}
Expand Down
31 changes: 30 additions & 1 deletion cli/chain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ func TestChainExport(t *testing.T) {

gomock.InOrder(
mockApi.EXPECT().ChainHead(ctx).Return(ts, nil),
mockApi.EXPECT().ChainExport(ctx, abi.ChainEpoch(0), false, ts.Key()).Return(export, nil),
mockApi.EXPECT().ChainExport(ctx, abi.ChainEpoch(0), false, ts.Key(), uint64(2)).Return(export, nil),
)

err := app.Run([]string{"chain", "export", "whatever.car"})
Expand All @@ -504,6 +504,35 @@ func TestChainExport(t *testing.T) {
assert.Equal(t, expBytes, mockFile.Bytes())
}

func TestChainExportVersionFlag(t *testing.T) {
app, mockApi, _, done := NewMockAppWithFullAPI(t, WithCategory("chain", ChainExportCmd))
defer done()

mockFile := mockExportFile{new(bytes.Buffer)}
app.Metadata["export-file"] = mockFile

blk := mock.MkBlock(nil, 0, 0)
ts := mock.TipSet(blk)

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

export := make(chan []byte, 2)
export <- []byte("whatever")
export <- []byte{}
close(export)

gomock.InOrder(
mockApi.EXPECT().ChainHead(ctx).Return(ts, nil),
mockApi.EXPECT().ChainExport(ctx, abi.ChainEpoch(0), false, ts.Key(), uint64(1)).Return(export, nil),
)

err := app.Run([]string{"chain", "export", "--version", "1", "whatever.car"})
assert.NoError(t, err)

assert.Equal(t, "whatever", mockFile.String())
}

func TestChainGasPrice(t *testing.T) {
app, mockApi, buf, done := NewMockAppWithFullAPI(t, WithCategory("chain", ChainGasPriceCmd))
defer done()
Expand Down
1 change: 1 addition & 0 deletions cli/mocks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ func NewMockAppWithFullAPI(t *testing.T, cmd *ucli.Command) (*ucli.App, *mocks.M
mockFullNode := mocks.NewMockFullNode(ctrl)
var fullNode api.FullNode = mockFullNode
app.Metadata["test-full-api"] = fullNode
app.Metadata["testnode-full"] = fullNode

// this will only work if the implementation uses the app.Writer,
// if it uses fmt.*, it has to be refactored
Expand Down
3 changes: 2 additions & 1 deletion documentation/en/api-methods-v1-stable.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions documentation/en/cli-lotus.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions itests/kit/f3.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/filecoin-project/go-f3"
"github.com/filecoin-project/go-f3/certs"
"github.com/filecoin-project/go-f3/certstore"
"github.com/filecoin-project/go-f3/gpbft"
"github.com/filecoin-project/go-f3/manifest"

Expand Down Expand Up @@ -69,6 +70,10 @@ func (t *MockF3Backend) GetManifest(context.Context) (*manifest.Manifest, error)
}, nil
}

func (t *MockF3Backend) GetCertStore() (*certstore.Store, error) {
return nil, nil
}

func (t *MockF3Backend) GetCert(_ context.Context, instance uint64) (*certs.FinalityCertificate, error) {
if !t.Running {
return nil, f3.ErrF3NotRunning
Expand Down
23 changes: 20 additions & 3 deletions node/impl/full/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/filecoin-project/go-address"
amt4 "github.com/filecoin-project/go-amt-ipld/v4"
"github.com/filecoin-project/go-f3/certs"
"github.com/filecoin-project/go-f3/certstore"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/specs-actors/actors/util/adt"

Expand Down Expand Up @@ -62,6 +63,7 @@ type ChainModuleAPI interface {
ChainGetTipSetAfterHeight(ctx context.Context, h abi.ChainEpoch, tsk types.TipSetKey) (*types.TipSet, error)
ChainReadObj(context.Context, cid.Cid) ([]byte, error)
ChainGetPath(ctx context.Context, from, to types.TipSetKey) ([]*api.HeadChange, error)
ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipoldmsgs bool, tsk types.TipSetKey, version uint64) (<-chan []byte, error)
}

var _ ChainModuleAPI = *new(api.FullNode)
Expand Down Expand Up @@ -703,17 +705,32 @@ func (a ChainAPI) ChainExportRangeInternal(ctx context.Context, head, tail types
return nil
}

func (a *ChainAPI) ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipoldmsgs bool, tsk types.TipSetKey) (<-chan []byte, error) {
ts, err := a.Chain.GetTipSetFromKey(ctx, tsk)
func (m *ChainModule) ChainExport(ctx context.Context, nroots abi.ChainEpoch, skipoldmsgs bool, tsk types.TipSetKey, version uint64) (<-chan []byte, error) {
ts, err := m.Chain.GetTipSetFromKey(ctx, tsk)
if err != nil {
return nil, xerrors.Errorf("loading tipset %s: %w", tsk, err)
}

var certstore *certstore.Store
if version == 2 {
certstore, err = m.F3.GetCertStore()
if err != nil {
return nil, xerrors.Errorf("getting certstore: %w", err)
}
}

r, w := io.Pipe()
out := make(chan []byte)
go func() {
bw := bufio.NewWriterSize(w, 1<<20)

err = a.Chain.ExportV1(ctx, ts, nroots, skipoldmsgs, bw)
// export v1 snapshot if not certstore or version is SnapshotVersion1
if certstore == nil || version == 1 {
err = m.Chain.ExportV1(ctx, ts, nroots, skipoldmsgs, bw)
} else {
err = m.Chain.ExportV2(ctx, ts, nroots, skipoldmsgs, certstore, bw)
}

_ = bw.Flush() // it is a write to a pipe
_ = w.CloseWithError(err) // it is a pipe
}()
Expand Down
Loading