@@ -20,52 +20,55 @@ import (
20
20
"github.com/filecoin-project/lotus/chain/vm"
21
21
)
22
22
23
+ var (
24
+ _ ec.Backend = (* ecWrapper )(nil )
25
+ _ ec.TipSet = (* f3TipSet )(nil )
26
+
27
+ emptyBeacon = make ([]byte , 32 )
28
+ )
29
+
23
30
type ecWrapper struct {
24
31
ChainStore * store.ChainStore
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
- 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
+ }
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,51 +78,32 @@ 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
+ return & f3TipSet { TipSet : ec .ChainStore .GetHeaviestTipSet ()} , nil
97
95
}
98
96
99
97
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
- }
98
+ ts , err := ec .toLotusTipset (ctx , tsF3 )
99
+ if err != nil {
100
+ return nil , err
117
101
}
118
102
parentTs , err := ec .ChainStore .GetTipSetFromKey (ctx , ts .Parents ())
119
103
if err != nil {
120
104
return nil , xerrors .Errorf ("getting parent tipset: %w" , err )
121
105
}
122
- return wrapTS ( parentTs ) , nil
106
+ return & f3TipSet { TipSet : parentTs } , nil
123
107
}
124
108
125
109
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
208
192
if waddr .Protocol () != address .BLS {
209
193
return xerrors .Errorf ("wrong type of worker address" )
210
194
}
211
- pe .PubKey = gpbft . PubKey ( waddr .Payload () )
195
+ pe .PubKey = waddr .Payload ()
212
196
powerEntries = append (powerEntries , pe )
213
197
return nil
214
198
})
@@ -219,3 +203,36 @@ func (ec *ecWrapper) getPowerTableLotusTSK(ctx context.Context, tsk types.TipSet
219
203
sort .Sort (powerEntries )
220
204
return powerEntries , nil
221
205
}
206
+
207
+ func (ec * ecWrapper ) Finalize (ctx context.Context , key gpbft.TipSetKey ) error {
208
+ ts , err := ec .getTipSetFromF3TSK (ctx , key )
209
+ if err != nil {
210
+ return err
211
+ }
212
+ if err = ec .ChainStore .SetCheckpoint (ctx , ts ); err != nil {
213
+ return xerrors .Errorf ("checkpointing finalized tipset: %w" , err )
214
+ }
215
+ return nil
216
+ }
217
+
218
+ func (ec * ecWrapper ) toLotusTipset (ctx context.Context , ts ec.TipSet ) (* types.TipSet , error ) {
219
+ switch tst := ts .(type ) {
220
+ case * f3TipSet :
221
+ return tst .TipSet , nil
222
+ default :
223
+ // Fall back on getting the tipset by key. This path is executed only in testing.
224
+ return ec .getTipSetFromF3TSK (ctx , ts .Key ())
225
+ }
226
+ }
227
+
228
+ func (ec * ecWrapper ) getTipSetFromF3TSK (ctx context.Context , key gpbft.TipSetKey ) (* types.TipSet , error ) {
229
+ tsk , err := types .TipSetKeyFromBytes (key )
230
+ if err != nil {
231
+ return nil , xerrors .Errorf ("decoding tpiset key: %w" , err )
232
+ }
233
+ ts , err := ec .ChainStore .GetTipSetFromKey (ctx , tsk )
234
+ if err != nil {
235
+ return nil , xerrors .Errorf ("getting tipset from key: %w" , err )
236
+ }
237
+ return ts , nil
238
+ }
0 commit comments