@@ -12,6 +12,7 @@ import (
12
12
"github.com/filecoin-project/go-f3/gpbft"
13
13
"github.com/filecoin-project/go-state-types/abi"
14
14
15
+ "github.com/filecoin-project/lotus/chain"
15
16
"github.com/filecoin-project/lotus/chain/actors/builtin/miner"
16
17
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
17
18
"github.com/filecoin-project/lotus/chain/stmgr"
@@ -20,52 +21,54 @@ import (
20
21
"github.com/filecoin-project/lotus/chain/vm"
21
22
)
22
23
24
+ var (
25
+ _ ec.Backend = (* ecWrapper )(nil )
26
+ _ ec.TipSet = (* f3TipSet )(nil )
27
+ )
28
+
23
29
type ecWrapper struct {
24
30
ChainStore * store.ChainStore
31
+ Syncer * chain.Syncer
25
32
StateManager * stmgr.StateManager
26
33
}
27
34
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
34
37
}
35
38
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 ()) }
39
42
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 ]
42
48
}
43
49
44
50
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
+ 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.
51
61
return make ([]byte , 32 )
62
+ default :
63
+ return header .BeaconEntries [len (header .BeaconEntries )- 1 ].Data
52
64
}
53
- return entries [len (entries )- 1 ].Data
54
- }
55
-
56
- func (ts * f3TipSet ) Epoch () int64 {
57
- return int64 (ts .cast ().Height ())
58
65
}
59
66
60
67
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 )
67
70
}
68
- return ( * f3TipSet )( ts )
71
+ return time. Time {}
69
72
}
70
73
71
74
// GetTipsetByEpoch should return a tipset before the one requested if the requested
@@ -75,57 +78,42 @@ func (ec *ecWrapper) GetTipsetByEpoch(ctx context.Context, epoch int64) (ec.TipS
75
78
if err != nil {
76
79
return nil , xerrors .Errorf ("getting tipset by height: %w" , err )
77
80
}
78
- return wrapTS ( ts ) , nil
81
+ return & f3TipSet { TipSet : ts } , nil
79
82
}
80
83
81
84
func (ec * ecWrapper ) GetTipset (ctx context.Context , tsk gpbft.TipSetKey ) (ec.TipSet , error ) {
82
- tskLotus , err := types .TipSetKeyFromBytes (tsk )
83
- if err != nil {
84
- return nil , xerrors .Errorf ("decoding tsk: %w" , err )
85
- }
86
-
87
- ts , err := ec .ChainStore .GetTipSetFromKey (ctx , tskLotus )
85
+ ts , err := ec .getTipSetFromF3TSK (ctx , tsk )
88
86
if err != nil {
89
87
return nil , xerrors .Errorf ("getting tipset by key: %w" , err )
90
88
}
91
89
92
- return wrapTS ( ts ) , nil
90
+ return & f3TipSet { TipSet : ts } , nil
93
91
}
94
92
95
- func (ec * ecWrapper ) GetHead (_ context.Context ) (ec.TipSet , error ) {
96
- return wrapTS (ec .ChainStore .GetHeaviestTipSet ()), nil
93
+ func (ec * ecWrapper ) GetHead (context.Context ) (ec.TipSet , error ) {
94
+ head := ec .ChainStore .GetHeaviestTipSet ()
95
+ if head == nil {
96
+ return nil , xerrors .New ("no heaviest tipset" )
97
+ }
98
+ return & f3TipSet {TipSet : head }, nil
97
99
}
98
100
99
101
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
- }
102
+ ts , err := ec .toLotusTipSet (ctx , tsF3 )
103
+ if err != nil {
104
+ return nil , err
117
105
}
118
106
parentTs , err := ec .ChainStore .GetTipSetFromKey (ctx , ts .Parents ())
119
107
if err != nil {
120
108
return nil , xerrors .Errorf ("getting parent tipset: %w" , err )
121
109
}
122
- return wrapTS ( parentTs ) , nil
110
+ return & f3TipSet { TipSet : parentTs } , nil
123
111
}
124
112
125
113
func (ec * ecWrapper ) GetPowerTable (ctx context.Context , tskF3 gpbft.TipSetKey ) (gpbft.PowerEntries , error ) {
126
- tsk , err := types . TipSetKeyFromBytes (tskF3 )
114
+ tsk , err := toLotusTipSetKey (tskF3 )
127
115
if err != nil {
128
- return nil , xerrors . Errorf ( "decoding tsk: %w" , err )
116
+ return nil , err
129
117
}
130
118
return ec .getPowerTableLotusTSK (ctx , tsk )
131
119
}
@@ -208,7 +196,7 @@ func (ec *ecWrapper) getPowerTableLotusTSK(ctx context.Context, tsk types.TipSet
208
196
if waddr .Protocol () != address .BLS {
209
197
return xerrors .Errorf ("wrong type of worker address" )
210
198
}
211
- pe .PubKey = gpbft . PubKey ( waddr .Payload () )
199
+ pe .PubKey = waddr .Payload ()
212
200
powerEntries = append (powerEntries , pe )
213
201
return nil
214
202
})
@@ -219,3 +207,44 @@ func (ec *ecWrapper) getPowerTableLotusTSK(ctx context.Context, tsk types.TipSet
219
207
sort .Sort (powerEntries )
220
208
return powerEntries , nil
221
209
}
210
+
211
+ func (ec * ecWrapper ) Finalize (ctx context.Context , key gpbft.TipSetKey ) error {
212
+ tsk , err := toLotusTipSetKey (key )
213
+ if err != nil {
214
+ return err
215
+ }
216
+ if err = ec .Syncer .SyncCheckpoint (ctx , tsk ); err != nil {
217
+ return xerrors .Errorf ("checkpointing finalized tipset: %w" , err )
218
+ }
219
+ return nil
220
+ }
221
+
222
+ func (ec * ecWrapper ) toLotusTipSet (ctx context.Context , ts ec.TipSet ) (* types.TipSet , error ) {
223
+ switch tst := ts .(type ) {
224
+ case * f3TipSet :
225
+ return tst .TipSet , nil
226
+ default :
227
+ // Fall back on getting the tipset by key. This path is executed only in testing.
228
+ return ec .getTipSetFromF3TSK (ctx , ts .Key ())
229
+ }
230
+ }
231
+
232
+ func (ec * ecWrapper ) getTipSetFromF3TSK (ctx context.Context , key gpbft.TipSetKey ) (* types.TipSet , error ) {
233
+ tsk , err := toLotusTipSetKey (key )
234
+ if err != nil {
235
+ return nil , err
236
+ }
237
+ ts , err := ec .ChainStore .GetTipSetFromKey (ctx , tsk )
238
+ if err != nil {
239
+ return nil , xerrors .Errorf ("getting tipset from key: %w" , err )
240
+ }
241
+ return ts , nil
242
+ }
243
+
244
+ func toLotusTipSetKey (key gpbft.TipSetKey ) (types.TipSetKey , error ) {
245
+ tsk , err := types .TipSetKeyFromBytes (key )
246
+ if err != nil {
247
+ return types.TipSetKey {}, xerrors .Errorf ("decoding tpiset key: %w" , err )
248
+ }
249
+ return tsk , nil
250
+ }
0 commit comments