Skip to content

Commit f293db5

Browse files
committed
Checkpoint tipsets that are finalized by F3
Once a decision is received from F3, checkpoint it in chain-store. As part of checkpointing, refactor the F3 tipset wrapper to reduce type casting. Note that go-f3 module now uses Go 1.22, which requires Lotus go module to be updated accordingly. Part of filecoin-project/go-f3#603
1 parent 6c63df6 commit f293db5

File tree

5 files changed

+80
-71
lines changed

5 files changed

+80
-71
lines changed

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#####################################
2-
FROM golang:1.21.7-bullseye AS lotus-builder
2+
FROM golang:1.22.7-bullseye AS lotus-builder
33
MAINTAINER Lotus Development Team
44

55
RUN apt-get update && apt-get install -y ca-certificates build-essential clang ocl-icd-opencl-dev ocl-icd-libopencl1 jq libhwloc-dev

build/openrpc/full.json

+4-12
Original file line numberDiff line numberDiff line change
@@ -6485,9 +6485,7 @@
64856485
"type": "string"
64866486
},
64876487
"PowerTable": {
6488-
"media": {
6489-
"binaryEncoding": "base64"
6490-
},
6488+
"title": "Content Identifier",
64916489
"type": "string"
64926490
}
64936491
},
@@ -6548,9 +6546,7 @@
65486546
"type": "array"
65496547
},
65506548
"PowerTable": {
6551-
"media": {
6552-
"binaryEncoding": "base64"
6553-
},
6549+
"title": "Content Identifier",
65546550
"type": "string"
65556551
}
65566552
},
@@ -6822,9 +6818,7 @@
68226818
"type": "string"
68236819
},
68246820
"PowerTable": {
6825-
"media": {
6826-
"binaryEncoding": "base64"
6827-
},
6821+
"title": "Content Identifier",
68286822
"type": "string"
68296823
}
68306824
},
@@ -6885,9 +6879,7 @@
68856879
"type": "array"
68866880
},
68876881
"PowerTable": {
6888-
"media": {
6889-
"binaryEncoding": "base64"
6890-
},
6882+
"title": "Content Identifier",
68916883
"type": "string"
68926884
}
68936885
},

chain/lf3/ec.go

+69-54
Original file line numberDiff line numberDiff line change
@@ -20,52 +20,55 @@ import (
2020
"github.com/filecoin-project/lotus/chain/vm"
2121
)
2222

23+
var (
24+
_ ec.Backend = (*ecWrapper)(nil)
25+
_ ec.TipSet = (*f3TipSet)(nil)
26+
27+
emptyBeacon = make([]byte, 32)
28+
)
29+
2330
type ecWrapper struct {
2431
ChainStore *store.ChainStore
2532
StateManager *stmgr.StateManager
2633
}
2734

28-
var _ ec.TipSet = (*f3TipSet)(nil)
29-
30-
type f3TipSet types.TipSet
31-
32-
func (ts *f3TipSet) cast() *types.TipSet {
33-
return (*types.TipSet)(ts)
35+
type f3TipSet struct {
36+
*types.TipSet
3437
}
3538

36-
func (ts *f3TipSet) String() string {
37-
return ts.cast().String()
38-
}
39+
func (ts *f3TipSet) String() string { return ts.TipSet.String() }
40+
func (ts *f3TipSet) Key() gpbft.TipSetKey { return ts.TipSet.Key().Bytes() }
41+
func (ts *f3TipSet) Epoch() int64 { return int64(ts.TipSet.Height()) }
3942

40-
func (ts *f3TipSet) Key() gpbft.TipSetKey {
41-
return ts.cast().Key().Bytes()
43+
func (ts *f3TipSet) FirstBlockHeader() *types.BlockHeader {
44+
if ts.TipSet == nil || len(ts.TipSet.Blocks()) == 0 {
45+
return nil
46+
}
47+
return ts.TipSet.Blocks()[0]
4248
}
4349

4450
func (ts *f3TipSet) Beacon() []byte {
45-
entries := ts.cast().Blocks()[0].BeaconEntries
46-
if len(entries) == 0 {
47-
// This should never happen in practice, but set beacon to a non-nil
48-
// 32byte slice to force the message builder to generate a
49-
// ticket. Otherwise, messages that require ticket, i.e. CONVERGE will fail
50-
// validation due to the absence of ticket. This is a convoluted way of doing it.
51-
return make([]byte, 32)
52-
}
53-
return entries[len(entries)-1].Data
54-
}
55-
56-
func (ts *f3TipSet) Epoch() int64 {
57-
return int64(ts.cast().Height())
51+
switch header := ts.FirstBlockHeader(); {
52+
case header == nil, len(header.BeaconEntries) == 0:
53+
// This should never happen in practice, but set beacon to a non-nil 32byte slice
54+
// to force the message builder to generate a ticket. Otherwise, messages that
55+
// require ticket, i.e. CONVERGE will fail validation due to the absence of
56+
// ticket. This is a convoluted way of doing it.
57+
58+
// TODO: investigate if this is still necessary, or how message builder can be
59+
// adapted to behave correctly regardless of beacon value, e.g. fail fast
60+
// instead of building CONVERGE with empty beacon.
61+
return emptyBeacon
62+
default:
63+
return header.BeaconEntries[len(header.BeaconEntries)-1].Data
64+
}
5865
}
5966

6067
func (ts *f3TipSet) Timestamp() time.Time {
61-
return time.Unix(int64(ts.cast().Blocks()[0].Timestamp), 0)
62-
}
63-
64-
func wrapTS(ts *types.TipSet) ec.TipSet {
65-
if ts == nil {
66-
return nil
68+
if header := ts.FirstBlockHeader(); header != nil {
69+
return time.Unix(int64(header.Timestamp), 0)
6770
}
68-
return (*f3TipSet)(ts)
71+
return time.Time{}
6972
}
7073

7174
// GetTipsetByEpoch should return a tipset before the one requested if the requested
@@ -75,7 +78,7 @@ func (ec *ecWrapper) GetTipsetByEpoch(ctx context.Context, epoch int64) (ec.TipS
7578
if err != nil {
7679
return nil, xerrors.Errorf("getting tipset by height: %w", err)
7780
}
78-
return wrapTS(ts), nil
81+
return &f3TipSet{TipSet: ts}, nil
7982
}
8083

8184
func (ec *ecWrapper) GetTipset(ctx context.Context, tsk gpbft.TipSetKey) (ec.TipSet, error) {
@@ -89,37 +92,23 @@ func (ec *ecWrapper) GetTipset(ctx context.Context, tsk gpbft.TipSetKey) (ec.Tip
8992
return nil, xerrors.Errorf("getting tipset by key: %w", err)
9093
}
9194

92-
return wrapTS(ts), nil
95+
return &f3TipSet{TipSet: ts}, nil
9396
}
9497

95-
func (ec *ecWrapper) GetHead(_ context.Context) (ec.TipSet, error) {
96-
return wrapTS(ec.ChainStore.GetHeaviestTipSet()), nil
98+
func (ec *ecWrapper) GetHead(context.Context) (ec.TipSet, error) {
99+
return &f3TipSet{TipSet: ec.ChainStore.GetHeaviestTipSet()}, nil
97100
}
98101

99102
func (ec *ecWrapper) GetParent(ctx context.Context, tsF3 ec.TipSet) (ec.TipSet, error) {
100-
var ts *types.TipSet
101-
if tsW, ok := tsF3.(*f3TipSet); ok {
102-
ts = tsW.cast()
103-
} else {
104-
// There are only two implementations of ec.TipSet: f3TipSet, and one in fake EC
105-
// backend.
106-
//
107-
// TODO: Revisit the type check here and remove as needed once testing
108-
// is over and fake EC backend goes away.
109-
tskLotus, err := types.TipSetKeyFromBytes(tsF3.Key())
110-
if err != nil {
111-
return nil, xerrors.Errorf("decoding tsk: %w", err)
112-
}
113-
ts, err = ec.ChainStore.GetTipSetFromKey(ctx, tskLotus)
114-
if err != nil {
115-
return nil, xerrors.Errorf("getting tipset by key for get parent: %w", err)
116-
}
103+
ts, err := ec.toLotusTipset(ctx, tsF3)
104+
if err != nil {
105+
return nil, err
117106
}
118107
parentTs, err := ec.ChainStore.GetTipSetFromKey(ctx, ts.Parents())
119108
if err != nil {
120109
return nil, xerrors.Errorf("getting parent tipset: %w", err)
121110
}
122-
return wrapTS(parentTs), nil
111+
return &f3TipSet{TipSet: parentTs}, nil
123112
}
124113

125114
func (ec *ecWrapper) GetPowerTable(ctx context.Context, tskF3 gpbft.TipSetKey) (gpbft.PowerEntries, error) {
@@ -208,7 +197,7 @@ func (ec *ecWrapper) getPowerTableLotusTSK(ctx context.Context, tsk types.TipSet
208197
if waddr.Protocol() != address.BLS {
209198
return xerrors.Errorf("wrong type of worker address")
210199
}
211-
pe.PubKey = gpbft.PubKey(waddr.Payload())
200+
pe.PubKey = waddr.Payload()
212201
powerEntries = append(powerEntries, pe)
213202
return nil
214203
})
@@ -219,3 +208,29 @@ func (ec *ecWrapper) getPowerTableLotusTSK(ctx context.Context, tsk types.TipSet
219208
sort.Sort(powerEntries)
220209
return powerEntries, nil
221210
}
211+
212+
func (ec *ecWrapper) FinalizeTipset(ctx context.Context, tsF3 ec.TipSet) error {
213+
ts, err := ec.toLotusTipset(ctx, tsF3)
214+
if err != nil {
215+
return err
216+
}
217+
return ec.ChainStore.SetCheckpoint(ctx, ts)
218+
}
219+
220+
func (ec *ecWrapper) toLotusTipset(ctx context.Context, ects ec.TipSet) (*types.TipSet, error) {
221+
switch tst := ects.(type) {
222+
case *f3TipSet:
223+
return tst.TipSet, nil
224+
default:
225+
// Fall back on getting the tipset by key. This path is executed only in testing.
226+
tsk, err := types.TipSetKeyFromBytes(ects.Key())
227+
if err != nil {
228+
return nil, xerrors.Errorf("decoding tpiset key: %w", err)
229+
}
230+
ts, err := ec.ChainStore.GetTipSetFromKey(ctx, tsk)
231+
if err != nil {
232+
return nil, xerrors.Errorf("getting tipset from key: %w", err)
233+
}
234+
return ts, nil
235+
}
236+
}

go.mod

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module github.com/filecoin-project/lotus
22

3-
go 1.21
3+
go 1.22
4+
5+
toolchain go1.22.6
46

57
retract v1.14.0 // Accidentally force-pushed tag, use v1.14.1+ instead.
68

@@ -42,7 +44,7 @@ require (
4244
github.com/filecoin-project/go-cbor-util v0.0.1
4345
github.com/filecoin-project/go-commp-utils/v2 v2.1.0
4446
github.com/filecoin-project/go-crypto v0.1.0
45-
github.com/filecoin-project/go-f3 v0.2.0
47+
github.com/filecoin-project/go-f3 v0.2.1-0.20240913104949-a47f60fb7a51
4648
github.com/filecoin-project/go-fil-commcid v0.2.0
4749
github.com/filecoin-project/go-hamt-ipld/v3 v3.4.0
4850
github.com/filecoin-project/go-jsonrpc v0.6.0

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -268,8 +268,8 @@ github.com/filecoin-project/go-commp-utils/v2 v2.1.0/go.mod h1:NbxJYlhxtWaNhlVCj
268268
github.com/filecoin-project/go-crypto v0.0.0-20191218222705-effae4ea9f03/go.mod h1:+viYnvGtUTgJRdy6oaeF4MTFKAfatX071MPDPBL11EQ=
269269
github.com/filecoin-project/go-crypto v0.1.0 h1:Pob2MphoipMbe/ksxZOMcQvmBHAd3sI/WEqcbpIsGI0=
270270
github.com/filecoin-project/go-crypto v0.1.0/go.mod h1:K9UFXvvoyAVvB+0Le7oGlKiT9mgA5FHOJdYQXEE8IhI=
271-
github.com/filecoin-project/go-f3 v0.2.0 h1:Gis44+hOrDjSUEw3IDmU7CudNILi5e+bb1pgZgp680k=
272-
github.com/filecoin-project/go-f3 v0.2.0/go.mod h1:43fBLX0iX0+Nnw4Z91wSrdfDYAd6YEDexy7GcLnIJtk=
271+
github.com/filecoin-project/go-f3 v0.2.1-0.20240913104949-a47f60fb7a51 h1:x1S+tB2diPXBKxDh6uUERdx/Foy/jU5df9d8Kbb7ICQ=
272+
github.com/filecoin-project/go-f3 v0.2.1-0.20240913104949-a47f60fb7a51/go.mod h1:5Gg9h133OU0GMp+oJwOOnJ84p9MO9RJfMKt4Xrgt070=
273273
github.com/filecoin-project/go-fil-commcid v0.2.0 h1:B+5UX8XGgdg/XsdUpST4pEBviKkFOw+Fvl2bLhSKGpI=
274274
github.com/filecoin-project/go-fil-commcid v0.2.0/go.mod h1:8yigf3JDIil+/WpqR5zoKyP0jBPCOGtEqq/K1CcMy9Q=
275275
github.com/filecoin-project/go-fil-commp-hashhash v0.2.0 h1:HYIUugzjq78YvV3vC6rL95+SfC/aSTVSnZSZiDV5pCk=

0 commit comments

Comments
 (0)