Skip to content

Commit 896dde4

Browse files
committed
Merge remote-tracking branch 'origin/main' into hm/snapshot-export
2 parents 740fe1a + 08b78bc commit 896dde4

File tree

6 files changed

+29
-38
lines changed

6 files changed

+29
-38
lines changed

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,9 @@ consensus protocol to finalize tipsets when voted for by more than two-thirds of
2424

2525
## Status
2626

27-
**:test_tube: Under Passive Testing**
27+
**🚀 Live on Mainnet**
2828

29-
The implementation of Go-F3 is complete and is currently undergoing passive testing in nv23. It has also been integrated
30-
into Lotus.
29+
Go-F3 was successfully activated on Filecoin mainnet on April 29, 2025 on epoch 4920480.
3130

3231
## Project Structure
3332

bootstrap_delay_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func TestComputeBootstrapDelay(t *testing.T) {
6464
name: "out of sync - way after bootstrap",
6565
time: genesis.Add(time.Duration(bootstrapEpoch+100)*period + 1*time.Second),
6666
ts: tipset{genesis: genesis, epoch: int64(bootstrapEpoch - 100), period: period},
67-
want: 0 * time.Second,
67+
want: 1 * time.Nanosecond, // we don't start immediately as the tipset we need is not available yet
6868
},
6969
{
7070
name: "out of sync - way before bootstrap",

f3.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,9 @@ func (m *F3) GetPowerTableByInstance(ctx context.Context, instance uint64) (gpbf
136136

137137
// computeBootstrapDelay returns the time at which the F3 instance specified by
138138
// the passed manifest should be started.
139+
// It will return 0 if the manifest bootstrap epoch is greater than the current epoch.
140+
// It will also return 1ns if the manifest bootstrap epoch is equal to the current epoch but by
141+
// the time calculation, we should have already received the bootstrap tipset.
139142
func computeBootstrapDelay(ts ec.TipSet, clock clock.Clock, mfst manifest.Manifest) time.Duration {
140143
currentEpoch := ts.Epoch()
141144
if currentEpoch >= mfst.BootstrapEpoch {
@@ -144,7 +147,9 @@ func computeBootstrapDelay(ts ec.TipSet, clock clock.Clock, mfst manifest.Manife
144147
epochDelay := mfst.BootstrapEpoch - currentEpoch
145148
start := ts.Timestamp().Add(time.Duration(epochDelay) * mfst.EC.Period)
146149
delay := clock.Until(start)
147-
delay = max(delay, 0)
150+
// ensure that we don't start immediately
151+
// to trigger waiting for the bootstrap tipset to exist
152+
delay = max(delay, 1*time.Nanosecond)
148153
return delay
149154
}
150155

@@ -185,6 +190,8 @@ func (m *F3) Start(startCtx context.Context) (_err error) {
185190
delay := computeBootstrapDelay(ts, m.clock, m.mfst)
186191
if delay > 0 {
187192
log.Infow("waiting for bootstrap epoch", "duration", delay.String())
193+
// reduce hot-looping by waiting for at least 20ms
194+
delay = max(delay, 20*time.Millisecond)
188195
startTimer.Reset(delay)
189196
} else {
190197
err = m.startInternal(m.runningCtx)
@@ -201,9 +208,9 @@ func (m *F3) Start(startCtx context.Context) (_err error) {
201208
}
202209

203210
// Stop F3.
204-
func (m *F3) Stop(context.Context) (_err error) {
211+
func (m *F3) Stop(ctx context.Context) (_err error) {
205212
m.cancelCtx()
206-
return nil
213+
return m.stopInternal(ctx)
207214
}
208215

209216
func (s *f3State) stop(ctx context.Context) (err error) {

f3_helpers_test.go

Lines changed: 0 additions & 16 deletions
This file was deleted.

f3_test.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ func TestF3WithLookback(t *testing.T) {
9494
env.requireInstanceEventually(5, eventualCheckTimeout, true)
9595
}
9696

97-
func TestF3PauseResumeCatchup(t *testing.T) {
97+
func TestF3StopStartCatchup(t *testing.T) {
9898
// Quiet down the logs since the test asserts a scenario that triggers
9999
// OhShitStore ERROR level logs.
100100
_ = logging.SetLogLevel("f3/ohshitstore", "DPANIC")
@@ -104,8 +104,8 @@ func TestF3PauseResumeCatchup(t *testing.T) {
104104
env.requireEpochFinalizedEventually(env.manifest.BootstrapEpoch, eventualCheckTimeout)
105105

106106
// Pausing two nodes should pause the network.
107-
env.pauseNode(1)
108-
env.pauseNode(2)
107+
env.stopNode(1)
108+
env.stopNode(2)
109109

110110
env.requireF3NotRunningEventually(eventualCheckTimeout, nodeMatchers.byID(1, 2))
111111

@@ -118,22 +118,23 @@ func TestF3PauseResumeCatchup(t *testing.T) {
118118
}, eventualCheckTimeout, eventualCheckInterval)
119119

120120
// Resuming node 1 should continue agreeing on instances.
121-
env.resumeNode(1)
121+
env.startNode(1)
122+
env.connectAll()
122123
env.requireF3RunningEventually(eventualCheckTimeout, nodeMatchers.byID(1))
123124

124125
// Wait until we're far enough that pure GPBFT catchup should be impossible.
125126
targetInstance := env.nodes[1].currentGpbftInstance() + env.manifest.CommitteeLookback + 1
126127
env.requireInstanceEventually(targetInstance, eventualCheckTimeout, false)
127128

128-
env.resumeNode(2)
129+
env.startNode(2)
129130
env.requireF3RunningEventually(eventualCheckTimeout, nodeMatchers.byID(2))
130131

131132
// Everyone should catch up eventually
132133
env.requireInstanceEventually(targetInstance, eventualCheckTimeout, true)
133134

134135
// Pause the "good" node.
135136
node0failInstance := env.nodes[0].currentGpbftInstance()
136-
env.pauseNode(0)
137+
env.stopNode(0)
137138
env.requireF3NotRunningEventually(eventualCheckTimeout, nodeMatchers.byID(0))
138139

139140
// We should be able to make progress with the remaining nodes.
@@ -337,12 +338,12 @@ func (n *testNode) init() *f3.F3 {
337338
return n.f3
338339
}
339340

340-
func (n *testNode) pause() {
341-
require.NoError(n.e.t, n.f3.Pause(n.e.testCtx))
341+
func (n *testNode) stop() {
342+
require.NoError(n.e.t, n.f3.Stop(n.e.testCtx))
342343
}
343344

344-
func (n *testNode) resume() {
345-
require.NoError(n.e.t, n.f3.Resume(n.e.testCtx))
345+
func (n *testNode) start() {
346+
require.NoError(n.e.t, n.f3.Start(n.e.testCtx))
346347
}
347348

348349
type testNodeStatus struct {
@@ -629,12 +630,12 @@ func (e *testEnv) withManifest(m manifest.Manifest) *testEnv {
629630
return e
630631
}
631632

632-
func (e *testEnv) pauseNode(i int) {
633-
e.nodes[i].pause()
633+
func (e *testEnv) stopNode(i int) {
634+
e.nodes[i].stop()
634635
}
635636

636-
func (e *testEnv) resumeNode(i int) {
637-
e.nodes[i].resume()
637+
func (e *testEnv) startNode(i int) {
638+
e.nodes[i].start()
638639
}
639640

640641
func (e *testEnv) injectDatastoreFailures(i int, fn func(op string) error) {

version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "v0.8.6"
2+
"version": "v0.8.7"
33
}

0 commit comments

Comments
 (0)