@@ -105,16 +105,22 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don
105
105
Epoch uint64
106
106
BlockCIDs []BlockCID
107
107
CompTime time.Time
108
+ Won bool
108
109
}
109
110
110
111
var details MiningTaskDetails
111
112
112
113
// First query to fetch from mining_tasks
113
- err = t .db .QueryRow (ctx , `SELECT sp_id, epoch, base_compute_time FROM mining_tasks WHERE task_id = $1` , taskID ).Scan (& details .SpID , & details .Epoch , & details .CompTime )
114
+ err = t .db .QueryRow (ctx , `SELECT sp_id, epoch, base_compute_time, won FROM mining_tasks WHERE task_id = $1` , taskID ).Scan (& details .SpID , & details .Epoch , & details .CompTime , & details . Won )
114
115
if err != nil {
115
116
return false , xerrors .Errorf ("query mining base info fail: %w" , err )
116
117
}
117
118
119
+ if details .Won {
120
+ log .Errorw ("WinPostTask.Do() task already won?!" , "taskID" , taskID )
121
+ return true , nil
122
+ }
123
+
118
124
// Second query to fetch from mining_base_block
119
125
rows , err := t .db .Query (ctx , `SELECT block_cid FROM mining_base_block WHERE task_id = $1` , taskID )
120
126
if err != nil {
@@ -415,12 +421,17 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don
415
421
return false , xerrors .Errorf ("failed to marshal block header: %w" , err )
416
422
}
417
423
418
- _ , err = t .db .Exec (ctx , `UPDATE mining_tasks
424
+ n , err : = t .db .Exec (ctx , `UPDATE mining_tasks
419
425
SET won = true, mined_cid = $2, mined_header = $3, mined_at = $4
420
- WHERE task_id = $1` , taskID , blockMsg .Header .Cid (), string (bhjson ), time .Now ().UTC ())
426
+ WHERE task_id = $1 AND won = false ` , taskID , blockMsg .Header .Cid (), string (bhjson ), time .Now ().UTC ())
421
427
if err != nil {
422
428
return false , xerrors .Errorf ("failed to update mining task: %w" , err )
423
429
}
430
+
431
+ if n == 0 {
432
+ log .Warnw ("WinPostTask task already mined?" , "tipset" , types .LogCids (base .TipSet .Cids ()), "miner" , maddr , "round" , round , "block" , blockMsg .Header .Cid ())
433
+ return true , xerrors .Errorf ("block already mined?" )
434
+ }
424
435
}
425
436
426
437
// wait until block timestamp
@@ -429,6 +440,12 @@ func (t *WinPostTask) Do(taskID harmonytask.TaskID, stillOwned func() bool) (don
429
440
time .Sleep (time .Until (time .Unix (int64 (blockMsg .Header .Timestamp ), 0 )))
430
441
}
431
442
443
+ if ! stillOwned () {
444
+ // make sure no one else got their hands on the task
445
+ log .Warnw ("WinPostTask task no longer owned" , "tipset" , types .LogCids (base .TipSet .Cids ()), "miner" , maddr , "round" , round , "block" , blockMsg .Header .Cid ())
446
+ return true , xerrors .Errorf ("task no longer owned" )
447
+ }
448
+
432
449
// submit block!!
433
450
{
434
451
log .Infow ("WinPostTask submitting block" , "tipset" , types .LogCids (base .TipSet .Cids ()), "miner" , maddr , "round" , round , "block" , blockMsg .Header .Cid ())
@@ -522,10 +539,13 @@ func (t *WinPostTask) TypeDetails() harmonytask.TaskTypeDetails {
522
539
}
523
540
524
541
return harmonytask.TaskTypeDetails {
525
- Name : "WinPost" ,
526
- Max : t .max ,
527
- MaxFailures : 3 ,
528
- Follows : nil ,
542
+ Name : "WinPost" ,
543
+ Max : t .max ,
544
+
545
+ // We're not allowing retry to be conservative. Retry in winningPoSt done badly can lead to slashing, and
546
+ // that is generally worse than not mining a block. In general the task code is heavily defensive, and
547
+ // retry should be fine, but not allowing it is just another layer preventing slashing.
548
+ MaxFailures : 1 ,
529
549
Cost : resources.Resources {
530
550
Cpu : 1 ,
531
551
0 commit comments