@@ -17,6 +17,7 @@ import (
17
17
"github.com/ipfs/go-cid"
18
18
"github.com/jedib0t/go-pretty/v6/table"
19
19
"github.com/urfave/cli/v2"
20
+ "gopkg.in/cheggaaa/pb.v1"
20
21
21
22
"github.com/filecoin-project/lily/chain/actors"
22
23
init_ "github.com/filecoin-project/lily/chain/actors/builtin/init"
@@ -42,6 +43,9 @@ var ChainCmd = &cli.Command{
42
43
ChainListCmd ,
43
44
ChainSetHeadCmd ,
44
45
ChainActorCodesCmd ,
46
+ ChainStateInspect ,
47
+ ChainStateCompute ,
48
+ ChainStateComputeRange ,
45
49
},
46
50
}
47
51
@@ -74,24 +78,188 @@ var ChainActorCodesCmd = &cli.Command{
74
78
},
75
79
}
76
80
77
- func printSortedActorVersions (av map [actors.Version ]cid.Cid ) error {
78
- t := table .NewWriter ()
79
- t .AppendHeader (table.Row {"Version" , "Name" , "Family" , "Code" })
80
- var versions []int
81
- for v := range av {
82
- versions = append (versions , int (v ))
81
+ func marshalReport (reports []* lily.StateReport , verbose bool ) ([]byte , error ) {
82
+ type stateHeights struct {
83
+ Newest int64 `json:"newest"`
84
+ Oldest int64 `json:"oldest"`
83
85
}
84
- sort .Ints (versions )
85
- for _ , v := range versions {
86
- name , family , err := util .ActorNameAndFamilyFromCode (av [actors .Version (v )])
86
+ type summarizedHeights struct {
87
+ Messages stateHeights `json:"messages"`
88
+ StateRoots stateHeights `json:"stateroots"`
89
+ }
90
+ type hasState struct {
91
+ Messages bool `json:"messages"`
92
+ Receipts bool `json:"receipts"`
93
+ StateRoot bool `json:"stateroot"`
94
+ }
95
+ type stateReport struct {
96
+ Summary summarizedHeights `json:"summary"`
97
+ Detail map [int64 ]hasState `json:"details,omitempty"`
98
+ }
99
+
100
+ var (
101
+ details = make (map [int64 ]hasState )
102
+ headSet bool
103
+ head = reports [0 ]
104
+ oldestMessage = & lily.StateReport {}
105
+ oldestStateRoot = & lily.StateReport {}
106
+ )
107
+
108
+ for _ , r := range reports {
109
+ if verbose {
110
+ details [r .Height ] = hasState {
111
+ Messages : r .HasMessages ,
112
+ Receipts : r .HasReceipts ,
113
+ StateRoot : r .HasState ,
114
+ }
115
+ }
116
+ if ! headSet && (r .HasState && r .HasMessages && r .HasReceipts ) {
117
+ head = r
118
+ headSet = true
119
+ }
120
+ if r .HasState {
121
+ oldestStateRoot = r
122
+ }
123
+ if r .HasMessages {
124
+ oldestMessage = r
125
+ }
126
+ }
127
+
128
+ compiledReport := stateReport {
129
+ Detail : details ,
130
+ Summary : summarizedHeights {
131
+ Messages : stateHeights {Newest : head .Height , Oldest : oldestMessage .Height },
132
+ StateRoots : stateHeights {Newest : head .Height , Oldest : oldestStateRoot .Height },
133
+ },
134
+ }
135
+
136
+ reportOut , err := json .Marshal (compiledReport )
137
+ if err != nil {
138
+ return nil , err
139
+ }
140
+
141
+ return reportOut , nil
142
+ }
143
+
144
+ var ChainStateInspect = & cli.Command {
145
+ Name : "state-inspect" ,
146
+ Usage : "Returns details about each epoch's state in the local datastore" ,
147
+ Flags : []cli.Flag {
148
+ & cli.Uint64Flag {
149
+ Name : "limit" ,
150
+ Aliases : []string {"l" },
151
+ Value : 100 ,
152
+ Usage : "Limit traversal of statetree when searching for oldest state by `N` heights starting from most recent" ,
153
+ },
154
+ & cli.BoolFlag {
155
+ Name : "verbose" ,
156
+ Aliases : []string {"v" },
157
+ Usage : "Include detailed information about the completeness of state for all traversed height(s) starting from most recent" ,
158
+ },
159
+ },
160
+ Action : func (cctx * cli.Context ) error {
161
+ ctx := lotuscli .ReqContext (cctx )
162
+ lapi , closer , err := GetAPI (ctx )
87
163
if err != nil {
88
164
return err
89
165
}
90
- t .AppendRow (table.Row {v , name , family , av [actors .Version (v )]})
91
- t .AppendSeparator ()
92
- }
93
- fmt .Println (t .Render ())
94
- return nil
166
+ defer closer ()
167
+
168
+ report , err := lapi .FindOldestState (ctx , cctx .Int64 ("limit" ))
169
+ if err != nil {
170
+ return err
171
+ }
172
+ sort .Slice (report , func (i , j int ) bool {
173
+ return report [i ].Height > report [j ].Height
174
+ })
175
+
176
+ out , err := marshalReport (report , cctx .Bool ("verbose" ))
177
+ if err != nil {
178
+ return err
179
+ }
180
+ fmt .Println (string (out ))
181
+ return nil
182
+ },
183
+ }
184
+
185
+ var ChainStateComputeRange = & cli.Command {
186
+ Name : "state-compute" ,
187
+ Usage : "Generates the state at epoch `N`" ,
188
+ Flags : []cli.Flag {
189
+ & cli.Uint64Flag {
190
+ Name : "epoch" ,
191
+ Aliases : []string {"e" },
192
+ Required : true ,
193
+ },
194
+ },
195
+ Action : func (cctx * cli.Context ) error {
196
+ ctx := lotuscli .ReqContext (cctx )
197
+ lapi , closer , err := GetAPI (ctx )
198
+ if err != nil {
199
+ return err
200
+ }
201
+ defer closer ()
202
+
203
+ head , err := lapi .ChainHead (ctx )
204
+ if err != nil {
205
+ return err
206
+ }
207
+ ts , err := lapi .ChainGetTipSetByHeight (ctx , abi .ChainEpoch (cctx .Uint64 ("epoch" )), head .Key ())
208
+ if err != nil {
209
+ return err
210
+ }
211
+
212
+ _ , err = lapi .StateCompute (ctx , ts .Key ())
213
+ return err
214
+
215
+ },
216
+ }
217
+
218
+ var ChainStateCompute = & cli.Command {
219
+ Name : "state-compute-range" ,
220
+ Usage : "Generates the state from epoch `FROM` to epoch `TO`" ,
221
+ Flags : []cli.Flag {
222
+ & cli.Uint64Flag {
223
+ Name : "from" ,
224
+ Required : true ,
225
+ },
226
+ & cli.Uint64Flag {
227
+ Name : "to" ,
228
+ Required : true ,
229
+ },
230
+ },
231
+ Action : func (cctx * cli.Context ) error {
232
+ ctx := lotuscli .ReqContext (cctx )
233
+ lapi , closer , err := GetAPI (ctx )
234
+ if err != nil {
235
+ return err
236
+ }
237
+ defer closer ()
238
+
239
+ head , err := lapi .ChainHead (ctx )
240
+ if err != nil {
241
+ return err
242
+ }
243
+ bar := pb .StartNew (int (cctx .Uint64 ("to" ) - cctx .Uint64 ("from" )))
244
+ bar .ShowTimeLeft = true
245
+ bar .ShowPercent = true
246
+ bar .Units = pb .U_NO
247
+ for i := cctx .Int64 ("from" ); i <= cctx .Int64 ("to" ); i ++ {
248
+ ts , err := lapi .ChainGetTipSetByHeight (ctx , abi .ChainEpoch (i ), head .Key ())
249
+ if err != nil {
250
+ return err
251
+ }
252
+
253
+ _ , err = lapi .StateCompute (ctx , ts .Key ())
254
+ if err != nil {
255
+ return err
256
+ }
257
+ bar .Add (1 )
258
+ }
259
+ bar .Finish ()
260
+ return nil
261
+
262
+ },
95
263
}
96
264
97
265
var ChainHeadCmd = & cli.Command {
@@ -547,3 +715,23 @@ func parseTipSet(ctx context.Context, api lily.LilyAPI, vals []string) (*types.T
547
715
548
716
return types .NewTipSet (headers )
549
717
}
718
+
719
+ func printSortedActorVersions (av map [actors.Version ]cid.Cid ) error {
720
+ t := table .NewWriter ()
721
+ t .AppendHeader (table.Row {"Version" , "Name" , "Family" , "Code" })
722
+ var versions []int
723
+ for v := range av {
724
+ versions = append (versions , int (v ))
725
+ }
726
+ sort .Ints (versions )
727
+ for _ , v := range versions {
728
+ name , family , err := util .ActorNameAndFamilyFromCode (av [actors .Version (v )])
729
+ if err != nil {
730
+ return err
731
+ }
732
+ t .AppendRow (table.Row {v , name , family , av [actors .Version (v )]})
733
+ t .AppendSeparator ()
734
+ }
735
+ fmt .Println (t .Render ())
736
+ return nil
737
+ }
0 commit comments