1
1
package main
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"database/sql"
6
7
"encoding/json"
7
8
"errors"
8
9
"fmt"
9
10
"os"
11
+ "runtime"
12
+ "sync"
10
13
"time"
11
14
12
15
"github.com/samber/lo"
16
+ "github.com/snadrus/must"
13
17
"github.com/urfave/cli/v2"
14
18
"github.com/yugabyte/pgx/v5"
15
19
"golang.org/x/xerrors"
16
20
21
+ ffi "github.com/filecoin-project/filecoin-ffi"
17
22
"github.com/filecoin-project/go-address"
23
+ "github.com/filecoin-project/go-state-types/abi"
24
+ "github.com/filecoin-project/go-state-types/builtin"
25
+ "github.com/filecoin-project/go-state-types/crypto"
18
26
"github.com/filecoin-project/go-state-types/dline"
27
+ "github.com/filecoin-project/go-state-types/proof"
19
28
20
29
"github.com/filecoin-project/curio/cmd/curio/internal/translations"
21
30
"github.com/filecoin-project/curio/cmd/curio/tasks"
22
31
"github.com/filecoin-project/curio/deps"
23
32
"github.com/filecoin-project/curio/harmony/harmonydb"
33
+ cuproof "github.com/filecoin-project/curio/lib/proof"
34
+ "github.com/filecoin-project/curio/lib/storiface"
24
35
)
25
36
26
37
var testCmd = & cli.Command {
@@ -43,6 +54,7 @@ var wdPostCmd = &cli.Command{
43
54
Subcommands : []* cli.Command {
44
55
wdPostHereCmd ,
45
56
wdPostTaskCmd ,
57
+ wdPostVanillaCmd ,
46
58
},
47
59
}
48
60
@@ -216,6 +228,10 @@ It will not send any messages to the chain. Since it can compute any deadline, o
216
228
Usage : translations .T ("partition to compute WindowPoSt for" ),
217
229
Value : 0 ,
218
230
},
231
+ & cli.StringFlag {
232
+ Name : "addr" ,
233
+ Usage : translations .T ("SP ID to compute WindowPoSt for" ),
234
+ },
219
235
},
220
236
Action : func (cctx * cli.Context ) error {
221
237
@@ -225,6 +241,14 @@ It will not send any messages to the chain. Since it can compute any deadline, o
225
241
return err
226
242
}
227
243
244
+ var spAddr address.Address
245
+ if cctx .IsSet ("addr" ) {
246
+ spAddr , err = address .NewFromString (cctx .String ("addr" ))
247
+ if err != nil {
248
+ return xerrors .Errorf ("invalid sp address: %w" , err )
249
+ }
250
+ }
251
+
228
252
wdPostTask , wdPoStSubmitTask , derlareRecoverTask , err := tasks .WindowPostScheduler (
229
253
ctx , deps .Cfg .Fees , deps .Cfg .Proving , deps .Chain , deps .Verif , nil , nil , nil ,
230
254
deps .As , deps .Maddrs , deps .DB , deps .Stor , deps .Si , deps .Cfg .Subsystems .WindowPostMaxTasks )
@@ -244,6 +268,10 @@ It will not send any messages to the chain. Since it can compute any deadline, o
244
268
di := dline .NewInfo (head .Height (), cctx .Uint64 ("deadline" ), 0 , 0 , 0 , 10 /*challenge window*/ , 0 , 0 )
245
269
246
270
for maddr := range deps .Maddrs {
271
+ if spAddr != address .Undef && address .Address (maddr ) != spAddr {
272
+ continue
273
+ }
274
+
247
275
out , err := wdPostTask .DoPartition (ctx , head , address .Address (maddr ), di , cctx .Uint64 ("partition" ), true )
248
276
if err != nil {
249
277
fmt .Println ("Error computing WindowPoSt for miner" , maddr , err )
@@ -260,3 +288,223 @@ It will not send any messages to the chain. Since it can compute any deadline, o
260
288
return nil
261
289
},
262
290
}
291
+
292
+ var wdPostVanillaCmd = & cli.Command {
293
+ Name : "vanilla" ,
294
+ Usage : translations .T ("Compute WindowPoSt vanilla proofs and verify them." ),
295
+ Flags : []cli.Flag {
296
+ & cli.Uint64Flag {
297
+ Name : "deadline" ,
298
+ Usage : translations .T ("deadline to compute WindowPoSt for " ),
299
+ Value : 0 ,
300
+ },
301
+ & cli.StringSliceFlag {
302
+ Name : "layers" ,
303
+ Usage : translations .T ("list of layers to be interpreted (atop defaults). Default: base" ),
304
+ },
305
+ & cli.Uint64Flag {
306
+ Name : "partition" ,
307
+ Usage : translations .T ("partition to compute WindowPoSt for" ),
308
+ Value : 0 ,
309
+ },
310
+ & cli.StringFlag {
311
+ Name : "addr" ,
312
+ Usage : translations .T ("SP ID to compute WindowPoSt for" ),
313
+ },
314
+ },
315
+ Action : func (cctx * cli.Context ) error {
316
+ start := time .Now ()
317
+
318
+ ctx := context .Background ()
319
+ deps , err := deps .GetDeps (ctx , cctx )
320
+ if err != nil {
321
+ return err
322
+ }
323
+
324
+ var spAddr address.Address
325
+ if cctx .IsSet ("addr" ) {
326
+ spAddr , err = address .NewFromString (cctx .String ("addr" ))
327
+ if err != nil {
328
+ return xerrors .Errorf ("invalid sp address: %w" , err )
329
+ }
330
+ }
331
+
332
+ wdPostTask , wdPoStSubmitTask , derlareRecoverTask , err := tasks .WindowPostScheduler (
333
+ ctx , deps .Cfg .Fees , deps .Cfg .Proving , deps .Chain , deps .Verif , nil , nil , nil ,
334
+ deps .As , deps .Maddrs , deps .DB , deps .Stor , deps .Si , deps .Cfg .Subsystems .WindowPostMaxTasks )
335
+ if err != nil {
336
+ return err
337
+ }
338
+ _ , _ = wdPoStSubmitTask , derlareRecoverTask
339
+
340
+ if len (deps .Maddrs ) == 0 {
341
+ return errors .New ("no miners to compute WindowPoSt for" )
342
+ }
343
+ head , err := deps .Chain .ChainHead (ctx )
344
+ if err != nil {
345
+ return xerrors .Errorf ("failed to get chain head: %w" , err )
346
+ }
347
+
348
+ di := dline .NewInfo (head .Height (), cctx .Uint64 ("deadline" ), 0 , 0 , 0 , 10 /*challenge window*/ , 0 , 0 )
349
+
350
+ for maddr := range deps .Maddrs {
351
+ if spAddr != address .Undef && address .Address (maddr ) != spAddr {
352
+ continue
353
+ }
354
+
355
+ maddr := address .Address (maddr )
356
+ mid , err := address .IDFromAddress (maddr )
357
+ if err != nil {
358
+ return xerrors .Errorf ("failed to get miner id: %w" , err )
359
+ }
360
+
361
+ buf := new (bytes.Buffer )
362
+ if err := maddr .MarshalCBOR (buf ); err != nil {
363
+ return xerrors .Errorf ("failed to marshal address to cbor: %w" , err )
364
+ }
365
+
366
+ headTs , err := deps .Chain .ChainHead (ctx )
367
+ if err != nil {
368
+ return xerrors .Errorf ("getting current head: %w" , err )
369
+ }
370
+
371
+ rand , err := deps .Chain .StateGetRandomnessFromBeacon (ctx , crypto .DomainSeparationTag_WindowedPoStChallengeSeed , di .Challenge , buf .Bytes (), headTs .Key ())
372
+ if err != nil {
373
+ return xerrors .Errorf ("failed to get chain randomness from beacon for window post (ts=%d; deadline=%d): %w" , headTs .Height (), di , err )
374
+ }
375
+ rand [31 ] &= 0x3f
376
+
377
+ parts , err := deps .Chain .StateMinerPartitions (ctx , maddr , di .Index , headTs .Key ())
378
+ if err != nil {
379
+ return xerrors .Errorf ("getting partitions: %w" , err )
380
+ }
381
+
382
+ if cctx .Uint64 ("partition" ) >= uint64 (len (parts )) {
383
+ return xerrors .Errorf ("invalid partition: %d" , cctx .Uint64 ("partition" ))
384
+ }
385
+
386
+ partition := parts [cctx .Uint64 ("partition" )]
387
+
388
+ log .Infow ("Getting sectors for proof" , "partition" , cctx .Uint64 ("partition" ), "liveSectors" , must .One (partition .LiveSectors .Count ()), "allSectors" , must .One (partition .AllSectors .Count ()))
389
+
390
+ xsinfos , err := wdPostTask .SectorsForProof (ctx , maddr , partition .LiveSectors , partition .AllSectors , headTs )
391
+ if err != nil {
392
+ return xerrors .Errorf ("getting sectors for proof: %w" , err )
393
+ }
394
+
395
+ if len (xsinfos ) == 0 {
396
+ return xerrors .Errorf ("no sectors to prove" )
397
+ }
398
+
399
+ nv , err := deps .Chain .StateNetworkVersion (ctx , headTs .Key ())
400
+ if err != nil {
401
+ return xerrors .Errorf ("getting network version: %w" , err )
402
+ }
403
+
404
+ ppt , err := xsinfos [0 ].SealProof .RegisteredWindowPoStProofByNetworkVersion (nv )
405
+ if err != nil {
406
+ return xerrors .Errorf ("failed to get window post type: %w" , err )
407
+ }
408
+
409
+ sectorNums := make ([]abi.SectorNumber , len (xsinfos ))
410
+ sectorMap := make (map [abi.SectorNumber ]proof.ExtendedSectorInfo )
411
+ for i , s := range xsinfos {
412
+ sectorNums [i ] = s .SectorNumber
413
+ sectorMap [s .SectorNumber ] = s
414
+ }
415
+
416
+ postChallenges , err := ffi .GeneratePoStFallbackSectorChallenges (ppt , abi .ActorID (mid ), abi .PoStRandomness (rand ), sectorNums )
417
+ if err != nil {
418
+ return xerrors .Errorf ("generating fallback challenges: %w" , err )
419
+ }
420
+
421
+ maxPartitionSize , err := builtin .PoStProofWindowPoStPartitionSectors (ppt )
422
+ if err != nil {
423
+ return xerrors .Errorf ("get sectors count of partition failed:%+v" , err )
424
+ }
425
+
426
+ sectors := make ([]storiface.PostSectorChallenge , 0 )
427
+ for i := range postChallenges .Sectors {
428
+ snum := postChallenges .Sectors [i ]
429
+ sinfo := sectorMap [snum ]
430
+
431
+ sectors = append (sectors , storiface.PostSectorChallenge {
432
+ SealProof : sinfo .SealProof ,
433
+ SectorNumber : snum ,
434
+ SealedCID : sinfo .SealedCID ,
435
+ Challenge : postChallenges .Challenges [snum ],
436
+ Update : sinfo .SectorKey != nil ,
437
+ })
438
+ }
439
+ elapsed := time .Since (start )
440
+ log .Infow ("Generated fallback challenges" , "error" , err , "elapsed" , elapsed , "sectors" , len (sectors ), "maxPartitionSize" , maxPartitionSize , "postChallenges" , len (postChallenges .Challenges ))
441
+
442
+ var outLk sync.Mutex
443
+
444
+ wg := sync.WaitGroup {}
445
+ wg .Add (len (sectors ))
446
+ throttle := make (chan struct {}, runtime .NumCPU ())
447
+
448
+ for i , s := range sectors {
449
+ go func (i int , s storiface.PostSectorChallenge ) {
450
+
451
+ throttle <- struct {}{}
452
+ defer func () {
453
+ <- throttle
454
+ }()
455
+ defer wg .Done ()
456
+
457
+ start := time .Now ()
458
+ vanilla , err := deps .Stor .GenerateSingleVanillaProof (ctx , abi .ActorID (mid ), s , ppt )
459
+ elapsed := time .Since (start )
460
+
461
+ if err != nil || vanilla == nil {
462
+ outLk .Lock ()
463
+ log .Errorw ("Generated vanilla proof for sector" , "sector" , s .SectorNumber , "of" , fmt .Sprintf ("%d/%d" , i + 1 , len (sectors )), "error" , err , "elapsed" , elapsed )
464
+ log .Errorw ("reading PoSt challenge for sector" , "sector" , s .SectorNumber , "vlen" , len (vanilla ), "error" , err )
465
+ outLk .Unlock ()
466
+ return
467
+ }
468
+
469
+ // verify vproofs
470
+ pvi := proof.WindowPoStVerifyInfo {
471
+ Randomness : abi .PoStRandomness (rand ),
472
+ Proofs : []proof.PoStProof {},
473
+ ChallengedSectors : []proof.SectorInfo {},
474
+ }
475
+ pvi .Proofs = append (pvi .Proofs , proof.PoStProof {
476
+ PoStProof : ppt ,
477
+ ProofBytes : vanilla ,
478
+ })
479
+ for _ , s := range sectors {
480
+ pvi .ChallengedSectors = append (pvi .ChallengedSectors , proof.SectorInfo {
481
+ SealProof : s .SealProof ,
482
+ SectorNumber : s .SectorNumber ,
483
+ SealedCID : s .SealedCID ,
484
+ })
485
+ }
486
+
487
+ verifyStart := time .Now ()
488
+ ok , err := cuproof .VerifyWindowPoStVanilla (pvi )
489
+ verifyElapsed := time .Since (verifyStart )
490
+
491
+ outLk .Lock ()
492
+ if elapsed .Seconds () > 2 {
493
+ log .Warnw ("Generated vanilla proof for sector (slow)" , "sector" , s .SectorNumber , "of" , fmt .Sprintf ("%d/%d" , i + 1 , len (sectors )), "elapsed" , elapsed )
494
+ } else {
495
+ log .Debugw ("Generated vanilla proof for sector" , "sector" , s .SectorNumber , "of" , fmt .Sprintf ("%d/%d" , i + 1 , len (sectors )), "elapsed" , elapsed )
496
+ }
497
+ if err != nil || ! ok {
498
+ log .Errorw ("Verified window post vanilla proofs" , "error" , err , "elapsed" , verifyElapsed , "ok" , ok )
499
+ } else {
500
+ log .Debugw ("Verified window post vanilla proofs" , "elapsed" , verifyElapsed , "ok" , ok )
501
+ }
502
+ outLk .Unlock ()
503
+ }(i , s )
504
+ }
505
+ wg .Wait ()
506
+ }
507
+
508
+ return nil
509
+ },
510
+ }
0 commit comments