@@ -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,7 +78,7 @@ 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 ) {
@@ -89,37 +92,23 @@ func (ec *ecWrapper) GetTipset(ctx context.Context, tsk gpbft.TipSetKey) (ec.Tip
89
92
return nil , xerrors .Errorf ("getting tipset by key: %w" , err )
90
93
}
91
94
92
- return wrapTS ( ts ) , nil
95
+ return & f3TipSet { TipSet : ts } , nil
93
96
}
94
97
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
97
100
}
98
101
99
102
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
117
106
}
118
107
parentTs , err := ec .ChainStore .GetTipSetFromKey (ctx , ts .Parents ())
119
108
if err != nil {
120
109
return nil , xerrors .Errorf ("getting parent tipset: %w" , err )
121
110
}
122
- return wrapTS ( parentTs ) , nil
111
+ return & f3TipSet { TipSet : parentTs } , nil
123
112
}
124
113
125
114
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
208
197
if waddr .Protocol () != address .BLS {
209
198
return xerrors .Errorf ("wrong type of worker address" )
210
199
}
211
- pe .PubKey = gpbft . PubKey ( waddr .Payload () )
200
+ pe .PubKey = waddr .Payload ()
212
201
powerEntries = append (powerEntries , pe )
213
202
return nil
214
203
})
@@ -219,3 +208,29 @@ func (ec *ecWrapper) getPowerTableLotusTSK(ctx context.Context, tsk types.TipSet
219
208
sort .Sort (powerEntries )
220
209
return powerEntries , nil
221
210
}
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
+ }
0 commit comments