-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: lotus-provider: WinningPoSt support #11410
Changes from 16 commits
f27d54b
f4d8671
f30a7db
49c56e4
b9625da
2a4ce7d
d719db3
8b41013
f2ef006
8744312
7efc4e4
339e062
30cf227
aa87f3c
10032a1
63b130a
68cef72
1a9e3cf
98099cc
aed9a6d
c1edae6
9b4a3ba
0d90430
3947327
fceabdb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,9 @@ | |
# type: bool | ||
#EnableWinningPost = false | ||
|
||
# type: int | ||
#WinningPostMaxTasks = 0 | ||
|
||
|
||
[Fees] | ||
# type: types.FIL | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
create table mining_tasks | ||
snadrus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
( | ||
task_id bigint not null | ||
constraint mining_tasks_pk | ||
primary key, | ||
sp_id bigint not null, | ||
epoch bigint not null, | ||
base_compute_time timestamp not null, | ||
|
||
won bool not null default false, | ||
mined_cid text, | ||
mined_header jsonb, | ||
mined_at timestamp, | ||
|
||
submitted_at timestamp, | ||
|
||
constraint mining_tasks_sp_epoch | ||
unique (sp_id, epoch) | ||
); | ||
|
||
create table mining_base_block | ||
( | ||
id bigserial not null | ||
constraint mining_base_block_pk | ||
primary key, | ||
task_id bigint not null | ||
constraint mining_base_block_mining_tasks_task_id_fk | ||
references mining_tasks | ||
on delete cascade, | ||
sp_id bigint, | ||
block_cid text not null, | ||
|
||
no_win bool not null default false, | ||
|
||
constraint mining_base_block_pk2 | ||
unique (sp_id, task_id, block_cid) | ||
); | ||
|
||
CREATE UNIQUE INDEX mining_base_block_cid_k ON mining_base_block (sp_id, block_cid) WHERE no_win = false; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,7 +71,7 @@ func NewMiner(api v1api.FullNode, epp gen.WinningPoStProver, addr address.Addres | |
api: api, | ||
epp: epp, | ||
address: addr, | ||
waitFunc: func(ctx context.Context, baseTime uint64) (func(bool, abi.ChainEpoch, error), abi.ChainEpoch, error) { | ||
propagationWaitFunc: func(ctx context.Context, baseTime uint64) (func(bool, abi.ChainEpoch, error), abi.ChainEpoch, error) { | ||
// wait around for half the block time in case other parents come in | ||
// | ||
// if we're mining a block in the past via catch-up/rush mining, | ||
|
@@ -114,7 +114,7 @@ type Miner struct { | |
stop chan struct{} | ||
stopping chan struct{} | ||
|
||
waitFunc waitFunc | ||
propagationWaitFunc waitFunc | ||
|
||
// lastWork holds the last MiningBase we built upon. | ||
lastWork *MiningBase | ||
|
@@ -205,15 +205,21 @@ func (m *Miner) mine(ctx context.Context) { | |
ctx, span := trace.StartSpan(ctx, "/mine") | ||
defer span.End() | ||
|
||
// Perform the Winning PoSt warmup in a separate goroutine. | ||
go m.doWinPoStWarmup(ctx) | ||
|
||
var lastBase MiningBase | ||
|
||
// Start the main mining loop. | ||
minerLoop: | ||
for { | ||
// Prepare a context for a single node operation. | ||
ctx := cliutil.OnSingleNode(ctx) | ||
|
||
// Handle stop signals. | ||
select { | ||
case <-m.stop: | ||
// If a stop signal is received, clean up and exit the mining loop. | ||
stopping := m.stopping | ||
m.stop = nil | ||
m.stopping = nil | ||
|
@@ -223,10 +229,11 @@ minerLoop: | |
default: | ||
} | ||
|
||
var base *MiningBase | ||
var base *MiningBase // NOTE: This points to m.lastWork; Incrementing nulls here will increment it there. | ||
var onDone func(bool, abi.ChainEpoch, error) | ||
var injectNulls abi.ChainEpoch | ||
|
||
// Look for the best mining candidate. | ||
for { | ||
prebase, err := m.GetBestMiningCandidate(ctx) | ||
if err != nil { | ||
|
@@ -237,6 +244,7 @@ minerLoop: | |
continue | ||
} | ||
|
||
// Check if we have a new base or if the current base is still valid. | ||
if base != nil && base.TipSet.Height() == prebase.TipSet.Height() && base.NullRounds == prebase.NullRounds { | ||
base = prebase | ||
break | ||
|
@@ -253,13 +261,13 @@ minerLoop: | |
// best mining candidate at that time. | ||
|
||
// Wait until propagation delay period after block we plan to mine on | ||
onDone, injectNulls, err = m.waitFunc(ctx, prebase.TipSet.MinTimestamp()) | ||
onDone, injectNulls, err = m.propagationWaitFunc(ctx, prebase.TipSet.MinTimestamp()) | ||
if err != nil { | ||
log.Error(err) | ||
continue | ||
} | ||
|
||
// just wait for the beacon entry to become available before we select our final mining base | ||
// Ensure the beacon entry is available before finalizing the mining base. | ||
_, err = m.api.StateGetBeaconEntry(ctx, prebase.TipSet.Height()+prebase.NullRounds+1) | ||
if err != nil { | ||
log.Errorf("failed getting beacon entry: %s", err) | ||
|
@@ -272,8 +280,9 @@ minerLoop: | |
base = prebase | ||
} | ||
|
||
base.NullRounds += injectNulls // testing | ||
base.NullRounds += injectNulls // Adjust for testing purposes. | ||
|
||
// Check for repeated mining candidates and handle sleep for the next round. | ||
if base.TipSet.Equals(lastBase.TipSet) && lastBase.NullRounds == base.NullRounds { | ||
log.Warnf("BestMiningCandidate from the previous round: %s (nulls:%d)", lastBase.TipSet.Cids(), lastBase.NullRounds) | ||
if !m.niceSleep(time.Duration(build.BlockDelaySecs) * time.Second) { | ||
|
@@ -282,6 +291,7 @@ minerLoop: | |
continue | ||
} | ||
|
||
// Attempt to mine a block. | ||
b, err := m.mineOne(ctx, base) | ||
if err != nil { | ||
log.Errorf("mining block failed: %+v", err) | ||
|
@@ -299,9 +309,12 @@ minerLoop: | |
} | ||
onDone(b != nil, h, nil) | ||
|
||
// Process the mined block. | ||
if b != nil { | ||
// Record the event of mining a block. | ||
m.journal.RecordEvent(m.evtTypes[evtTypeBlockMined], func() interface{} { | ||
return map[string]interface{}{ | ||
// Data about the mined block. | ||
"parents": base.TipSet.Cids(), | ||
"nulls": base.NullRounds, | ||
"epoch": b.Header.Height, | ||
|
@@ -312,19 +325,23 @@ minerLoop: | |
|
||
btime := time.Unix(int64(b.Header.Timestamp), 0) | ||
now := build.Clock.Now() | ||
// Handle timing for broadcasting the block. | ||
switch { | ||
case btime == now: | ||
// block timestamp is perfectly aligned with time. | ||
case btime.After(now): | ||
// Wait until it's time to broadcast the block. | ||
if !m.niceSleep(build.Clock.Until(btime)) { | ||
log.Warnf("received interrupt while waiting to broadcast block, will shutdown after block is sent out") | ||
build.Clock.Sleep(build.Clock.Until(btime)) | ||
} | ||
default: | ||
// Log if the block was mined in the past. | ||
log.Warnw("mined block in the past", | ||
"block-time", btime, "time", build.Clock.Now(), "difference", build.Clock.Since(btime)) | ||
} | ||
|
||
// Check for slash filter conditions. | ||
if os.Getenv("LOTUS_MINER_NO_SLASHFILTER") != "_yes_i_know_i_can_and_probably_will_lose_all_my_fil_and_power_" && !build.IsNearUpgrade(base.TipSet.Height(), build.UpgradeWatermelonFixHeight) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this os.GetEnv() be replaced with a config in the database? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, this is an extremely dangerous only-for-testing flag, doesn’t belong in user config |
||
witness, fault, err := m.sf.MinedBlock(ctx, b.Header, base.TipSet.Height()+base.NullRounds) | ||
if err != nil { | ||
|
@@ -339,25 +356,27 @@ minerLoop: | |
} | ||
} | ||
|
||
// Check for blocks created at the same height. | ||
if _, ok := m.minedBlockHeights.Get(b.Header.Height); ok { | ||
log.Warnw("Created a block at the same height as another block we've created", "height", b.Header.Height, "miner", b.Header.Miner, "parents", b.Header.Parents) | ||
continue | ||
} | ||
|
||
// Add the block height to the mined block heights. | ||
m.minedBlockHeights.Add(b.Header.Height, true) | ||
|
||
// Submit the newly mined block. | ||
if err := m.api.SyncSubmitBlock(ctx, b); err != nil { | ||
log.Errorf("failed to submit newly mined block: %+v", err) | ||
} | ||
} else { | ||
// If no block was mined, increase the null rounds and wait for the next epoch. | ||
base.NullRounds++ | ||
|
||
// Wait until the next epoch, plus the propagation delay, so a new tipset | ||
// has enough time to form. | ||
// | ||
// See: https://github.com/filecoin-project/lotus/issues/1845 | ||
// Calculate the time for the next round. | ||
nextRound := time.Unix(int64(base.TipSet.MinTimestamp()+build.BlockDelaySecs*uint64(base.NullRounds))+int64(build.PropagationDelaySecs), 0) | ||
|
||
// Wait for the next round or stop signal. | ||
select { | ||
case <-build.Clock.After(build.Clock.Until(nextRound)): | ||
case <-m.stop: | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We probably should have the migrator enable:
lpCfg.Subsystems.EnableWinningPost = true
And add a comment about diabling it in lotus-miner