diff --git a/Dockerfile b/Dockerfile index 51a39ed0395..cc41a084be0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ##################################### -FROM golang:1.21.7-bullseye AS lotus-builder +FROM golang:1.22.7-bullseye AS lotus-builder MAINTAINER Lotus Development Team RUN apt-get update && apt-get install -y ca-certificates build-essential clang ocl-icd-opencl-dev ocl-icd-libopencl1 jq libhwloc-dev diff --git a/build/openrpc/full.json b/build/openrpc/full.json index 862211eb411..cf388f17bbe 100644 --- a/build/openrpc/full.json +++ b/build/openrpc/full.json @@ -6485,9 +6485,7 @@ "type": "string" }, "PowerTable": { - "media": { - "binaryEncoding": "base64" - }, + "title": "Content Identifier", "type": "string" } }, @@ -6548,9 +6546,7 @@ "type": "array" }, "PowerTable": { - "media": { - "binaryEncoding": "base64" - }, + "title": "Content Identifier", "type": "string" } }, @@ -6822,9 +6818,7 @@ "type": "string" }, "PowerTable": { - "media": { - "binaryEncoding": "base64" - }, + "title": "Content Identifier", "type": "string" } }, @@ -6885,9 +6879,7 @@ "type": "array" }, "PowerTable": { - "media": { - "binaryEncoding": "base64" - }, + "title": "Content Identifier", "type": "string" } }, diff --git a/chain/lf3/ec.go b/chain/lf3/ec.go index 69095bab8d3..f157df8c0b7 100644 --- a/chain/lf3/ec.go +++ b/chain/lf3/ec.go @@ -20,52 +20,55 @@ import ( "github.com/filecoin-project/lotus/chain/vm" ) +var ( + _ ec.Backend = (*ecWrapper)(nil) + _ ec.TipSet = (*f3TipSet)(nil) + + emptyBeacon = make([]byte, 32) +) + type ecWrapper struct { ChainStore *store.ChainStore StateManager *stmgr.StateManager } -var _ ec.TipSet = (*f3TipSet)(nil) - -type f3TipSet types.TipSet - -func (ts *f3TipSet) cast() *types.TipSet { - return (*types.TipSet)(ts) +type f3TipSet struct { + *types.TipSet } -func (ts *f3TipSet) String() string { - return ts.cast().String() -} +func (ts *f3TipSet) String() string { return ts.TipSet.String() } +func (ts *f3TipSet) Key() gpbft.TipSetKey { return ts.TipSet.Key().Bytes() } +func (ts *f3TipSet) Epoch() int64 { return int64(ts.TipSet.Height()) } -func (ts *f3TipSet) Key() gpbft.TipSetKey { - return ts.cast().Key().Bytes() +func (ts *f3TipSet) FirstBlockHeader() *types.BlockHeader { + if ts.TipSet == nil || len(ts.TipSet.Blocks()) == 0 { + return nil + } + return ts.TipSet.Blocks()[0] } func (ts *f3TipSet) Beacon() []byte { - entries := ts.cast().Blocks()[0].BeaconEntries - if len(entries) == 0 { - // This should never happen in practice, but set beacon to a non-nil - // 32byte slice to force the message builder to generate a - // ticket. Otherwise, messages that require ticket, i.e. CONVERGE will fail - // validation due to the absence of ticket. This is a convoluted way of doing it. - return make([]byte, 32) - } - return entries[len(entries)-1].Data -} - -func (ts *f3TipSet) Epoch() int64 { - return int64(ts.cast().Height()) + switch header := ts.FirstBlockHeader(); { + case header == nil, len(header.BeaconEntries) == 0: + // This should never happen in practice, but set beacon to a non-nil 32byte slice + // to force the message builder to generate a ticket. Otherwise, messages that + // require ticket, i.e. CONVERGE will fail validation due to the absence of + // ticket. This is a convoluted way of doing it. + + // TODO: investigate if this is still necessary, or how message builder can be + // adapted to behave correctly regardless of beacon value, e.g. fail fast + // instead of building CONVERGE with empty beacon. + return emptyBeacon + default: + return header.BeaconEntries[len(header.BeaconEntries)-1].Data + } } func (ts *f3TipSet) Timestamp() time.Time { - return time.Unix(int64(ts.cast().Blocks()[0].Timestamp), 0) -} - -func wrapTS(ts *types.TipSet) ec.TipSet { - if ts == nil { - return nil + if header := ts.FirstBlockHeader(); header != nil { + return time.Unix(int64(header.Timestamp), 0) } - return (*f3TipSet)(ts) + return time.Time{} } // GetTipsetByEpoch should return a tipset before the one requested if the requested @@ -75,51 +78,32 @@ func (ec *ecWrapper) GetTipsetByEpoch(ctx context.Context, epoch int64) (ec.TipS if err != nil { return nil, xerrors.Errorf("getting tipset by height: %w", err) } - return wrapTS(ts), nil + return &f3TipSet{TipSet: ts}, nil } func (ec *ecWrapper) GetTipset(ctx context.Context, tsk gpbft.TipSetKey) (ec.TipSet, error) { - tskLotus, err := types.TipSetKeyFromBytes(tsk) - if err != nil { - return nil, xerrors.Errorf("decoding tsk: %w", err) - } - - ts, err := ec.ChainStore.GetTipSetFromKey(ctx, tskLotus) + ts, err := ec.getTipSetFromF3TSK(ctx, tsk) if err != nil { return nil, xerrors.Errorf("getting tipset by key: %w", err) } - return wrapTS(ts), nil + return &f3TipSet{TipSet: ts}, nil } -func (ec *ecWrapper) GetHead(_ context.Context) (ec.TipSet, error) { - return wrapTS(ec.ChainStore.GetHeaviestTipSet()), nil +func (ec *ecWrapper) GetHead(context.Context) (ec.TipSet, error) { + return &f3TipSet{TipSet: ec.ChainStore.GetHeaviestTipSet()}, nil } func (ec *ecWrapper) GetParent(ctx context.Context, tsF3 ec.TipSet) (ec.TipSet, error) { - var ts *types.TipSet - if tsW, ok := tsF3.(*f3TipSet); ok { - ts = tsW.cast() - } else { - // There are only two implementations of ec.TipSet: f3TipSet, and one in fake EC - // backend. - // - // TODO: Revisit the type check here and remove as needed once testing - // is over and fake EC backend goes away. - tskLotus, err := types.TipSetKeyFromBytes(tsF3.Key()) - if err != nil { - return nil, xerrors.Errorf("decoding tsk: %w", err) - } - ts, err = ec.ChainStore.GetTipSetFromKey(ctx, tskLotus) - if err != nil { - return nil, xerrors.Errorf("getting tipset by key for get parent: %w", err) - } + ts, err := ec.toLotusTipset(ctx, tsF3) + if err != nil { + return nil, err } parentTs, err := ec.ChainStore.GetTipSetFromKey(ctx, ts.Parents()) if err != nil { return nil, xerrors.Errorf("getting parent tipset: %w", err) } - return wrapTS(parentTs), nil + return &f3TipSet{TipSet: parentTs}, nil } func (ec *ecWrapper) GetPowerTable(ctx context.Context, tskF3 gpbft.TipSetKey) (gpbft.PowerEntries, error) { @@ -208,7 +192,7 @@ func (ec *ecWrapper) getPowerTableLotusTSK(ctx context.Context, tsk types.TipSet if waddr.Protocol() != address.BLS { return xerrors.Errorf("wrong type of worker address") } - pe.PubKey = gpbft.PubKey(waddr.Payload()) + pe.PubKey = waddr.Payload() powerEntries = append(powerEntries, pe) return nil }) @@ -219,3 +203,36 @@ func (ec *ecWrapper) getPowerTableLotusTSK(ctx context.Context, tsk types.TipSet sort.Sort(powerEntries) return powerEntries, nil } + +func (ec *ecWrapper) Finalize(ctx context.Context, key gpbft.TipSetKey) error { + ts, err := ec.getTipSetFromF3TSK(ctx, key) + if err != nil { + return err + } + if err = ec.ChainStore.SetCheckpoint(ctx, ts); err != nil { + return xerrors.Errorf("checkpointing finalized tipset: %w", err) + } + return nil +} + +func (ec *ecWrapper) toLotusTipset(ctx context.Context, ts ec.TipSet) (*types.TipSet, error) { + switch tst := ts.(type) { + case *f3TipSet: + return tst.TipSet, nil + default: + // Fall back on getting the tipset by key. This path is executed only in testing. + return ec.getTipSetFromF3TSK(ctx, ts.Key()) + } +} + +func (ec *ecWrapper) getTipSetFromF3TSK(ctx context.Context, key gpbft.TipSetKey) (*types.TipSet, error) { + tsk, err := types.TipSetKeyFromBytes(key) + if err != nil { + return nil, xerrors.Errorf("decoding tpiset key: %w", err) + } + ts, err := ec.ChainStore.GetTipSetFromKey(ctx, tsk) + if err != nil { + return nil, xerrors.Errorf("getting tipset from key: %w", err) + } + return ts, nil +} diff --git a/go.mod b/go.mod index d21a5e1e502..f77b175b6e1 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/filecoin-project/lotus -go 1.21 +go 1.22 + +toolchain go1.22.6 retract v1.14.0 // Accidentally force-pushed tag, use v1.14.1+ instead. @@ -42,7 +44,7 @@ require ( github.com/filecoin-project/go-cbor-util v0.0.1 github.com/filecoin-project/go-commp-utils/v2 v2.1.0 github.com/filecoin-project/go-crypto v0.1.0 - github.com/filecoin-project/go-f3 v0.2.0 + github.com/filecoin-project/go-f3 v0.2.1-0.20240913140337-3f4036020113 github.com/filecoin-project/go-fil-commcid v0.2.0 github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0 github.com/filecoin-project/go-jsonrpc v0.6.0 diff --git a/go.sum b/go.sum index 9dcc39b5d3a..e712c178aaa 100644 --- a/go.sum +++ b/go.sum @@ -268,8 +268,10 @@ github.com/filecoin-project/go-commp-utils/v2 v2.1.0/go.mod h1:NbxJYlhxtWaNhlVCj github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ= github.com/filecoin-project/go-crypto v0.1.0 h1:Pob2MphoipMbe/ksxZOMcQvmBHAd3sI/WEqcbpIsGI0= github.com/filecoin-project/go-crypto v0.1.0/go.mod h1:K9UFXvvoyAVvB+0Le7oGlKiT9mgA5FHOJdYQXEE8IhI= -github.com/filecoin-project/go-f3 v0.2.0 h1:Gis44+hOrDjSUEw3IDmU7CudNILi5e+bb1pgZgp680k= -github.com/filecoin-project/go-f3 v0.2.0/go.mod h1:43fBLX0iX0+Nnw4Z91wSrdfDYAd6YEDexy7GcLnIJtk= +github.com/filecoin-project/go-f3 v0.2.1-0.20240913104949-a47f60fb7a51 h1:x1S+tB2diPXBKxDh6uUERdx/Foy/jU5df9d8Kbb7ICQ= +github.com/filecoin-project/go-f3 v0.2.1-0.20240913104949-a47f60fb7a51/go.mod h1:5Gg9h133OU0GMp+oJwOOnJ84p9MO9RJfMKt4Xrgt070= +github.com/filecoin-project/go-f3 v0.2.1-0.20240913140337-3f4036020113 h1:Qbb6IhbkjEqf5LbZU3p8z2FbFFQE3TDjamu+xGYMLRw= +github.com/filecoin-project/go-f3 v0.2.1-0.20240913140337-3f4036020113/go.mod h1:5Gg9h133OU0GMp+oJwOOnJ84p9MO9RJfMKt4Xrgt070= github.com/filecoin-project/go-fil-commcid v0.2.0 h1:B+5UX8XGgdg/XsdUpST4pEBviKkFOw+Fvl2bLhSKGpI= github.com/filecoin-project/go-fil-commcid v0.2.0/go.mod h1:8yigf3JDIil+/WpqR5zoKyP0jBPCOGtEqq/K1CcMy9Q= github.com/filecoin-project/go-fil-commp-hashhash v0.2.0 h1:HYIUugzjq78YvV3vC6rL95+SfC/aSTVSnZSZiDV5pCk=