Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions f3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ var base = manifest.Manifest{
Gpbft: manifest.GpbftConfig{
Delta: 3 * time.Second,
DeltaBackOffExponent: 1.3,
DeltaBackOffMax: 1 * time.Hour,
QualityDeltaMultiplier: 1.0,
MaxLookaheadRounds: 5,
ChainProposedLength: 30,
Expand Down
6 changes: 1 addition & 5 deletions gpbft/gpbft.go
Original file line number Diff line number Diff line change
Expand Up @@ -964,11 +964,7 @@ func (i *instance) alarmAfterSynchrony() time.Time {
// The delay duration increases with each round.
// Returns the absolute time at which the alarm will fire.
func (i *instance) alarmAfterSynchronyWithMulti(multi float64) time.Time {
delta := time.Duration(float64(i.participant.delta) * multi *
math.Pow(i.participant.deltaBackOffExponent, float64(i.current.Round)))
timeout := i.participant.host.Time().Add(2 * delta)
i.participant.host.SetAlarm(timeout)
return timeout
return i.participant.AlarmAfterSynchronyWithMulti(i.current.Round, multi)
}

// Builds a justification for a value from a quorum result.
Expand Down
17 changes: 17 additions & 0 deletions gpbft/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
const (
defaultDelta = 3 * time.Second
defaultDeltaBackOffExponent = 2.0
defaultDeltaBackOffMax = 1 * time.Hour
defaultMaxCachedInstances = 10
defaultMaxCachedMessagesPerInstance = 25_000
defaultCommitteeLookback = 10
Expand All @@ -22,6 +23,7 @@ type Option func(*options) error
type options struct {
delta time.Duration
deltaBackOffExponent float64
deltaBackOffMax time.Duration

qualityDeltaMulti float64

Expand All @@ -41,6 +43,7 @@ func newOptions(o ...Option) (*options, error) {
opts := &options{
delta: defaultDelta,
deltaBackOffExponent: defaultDeltaBackOffExponent,
deltaBackOffMax: defaultDeltaBackOffMax,
qualityDeltaMulti: 1.0,
committeeLookback: defaultCommitteeLookback,
rebroadcastAfter: defaultRebroadcastAfter,
Expand Down Expand Up @@ -87,6 +90,20 @@ func WithDeltaBackOffExponent(e float64) Option {
}
}

// WithDeltaBackOffMax sets the delta back-off max for each round.
// Defaults to 1h if unspecified. It must be larger than zero.
//
// See: https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0086.md#synchronization-of-participants-in-the-current-instance
func WithDeltaBackOffMax(d time.Duration) Option {
return func(o *options) error {
if d < 0 {
return errors.New("delta duration max cannot be less than zero")
}
o.deltaBackOffMax = d
return nil
}
}

func WithQualityDeltaMultiplier(m float64) Option {
return func(o *options) error {
if m < 0 {
Expand Down
15 changes: 15 additions & 0 deletions gpbft/participant.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
"math"
"sort"
"sync"
"time"
Expand Down Expand Up @@ -315,6 +316,20 @@ func (p *Participant) trace(format string, args ...any) {
}
}

// Sets an alarm to be delivered after a synchrony delay including a multiplier on the duration.
// The delay duration increases with each round.
// Returns the absolute time at which the alarm will fire.
func (p *Participant) AlarmAfterSynchronyWithMulti(round uint64, multi float64) time.Time {
delta := time.Duration(float64(p.delta) * multi *
math.Pow(p.deltaBackOffExponent, float64(round)))
if delta > p.deltaBackOffMax {
delta = p.deltaBackOffMax
}
timeout := p.host.Time().Add(2 * delta)
p.host.SetAlarm(timeout)
return timeout
}

// A collection of messages queued for delivery for a future instance.
// The queue drops equivocations and unjustified messages beyond some round number.
type messageQueue struct {
Expand Down
52 changes: 51 additions & 1 deletion gpbft/participant_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
"math"
"math/rand"
"sync"
"testing"
Expand Down Expand Up @@ -54,6 +55,7 @@ func newParticipantTestSubject(t *testing.T, seed int64, instance uint64) *parti
const (
delta = 2 * time.Second
deltaBackOffExponent = 1.3
deltaBackOffMax = 30 * time.Second
)

rng := rand.New(rand.NewSource(seed))
Expand Down Expand Up @@ -89,7 +91,7 @@ func newParticipantTestSubject(t *testing.T, seed int64, instance uint64) *parti
subject.Participant, err = gpbft.NewParticipant(subject.host,
gpbft.WithTracer(subject),
gpbft.WithDelta(delta),
gpbft.WithDeltaBackOffExponent(deltaBackOffExponent))
gpbft.WithDeltaBackOffExponent(deltaBackOffExponent), gpbft.WithDeltaBackOffMax(deltaBackOffMax))
require.NoError(t, err)
subject.requireNotStarted()
return subject
Expand Down Expand Up @@ -485,6 +487,54 @@ func TestParticipant(t *testing.T) {
})
}

func TestParticipant_alarmAfterSynchronyWithMulti(t *testing.T) {
const (
seed = 894651320
delta = 2 * time.Second
deltaBackOffExponent = 1.2
deltaBackOffMax = 30 * time.Second
)

now := time.Now()

tests := []struct {
name string
round uint64
multi float64
timeout time.Duration
}{
{
name: "uncapped",
round: 3,
multi: 1,
timeout: 2 * time.Duration(float64(delta)*1*
math.Pow(deltaBackOffExponent, float64(3))),
},
{
name: "capped",
round: 30,
multi: 1,
timeout: 2 * deltaBackOffMax,
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
host := gpbft.NewMockHost(t)
host.On("NetworkName").Return(gpbft.NetworkName("testnetnet")).Maybe()
host.On("Time").Return(now)
host.On("SetAlarm", mock.Anything)
p, err := gpbft.NewParticipant(host,
gpbft.WithDelta(delta),
gpbft.WithDeltaBackOffExponent(deltaBackOffExponent), gpbft.WithDeltaBackOffMax(deltaBackOffMax))
require.NoError(t, err)
require.NotNil(t, p)
timeout := p.AlarmAfterSynchronyWithMulti(test.round, test.multi)
require.Equal(t, timeout, now.Add(test.timeout))
})
}
}

func TestParticipant_ValidateMessage(t *testing.T) {
const (
seed = 894651320
Expand Down
6 changes: 6 additions & 0 deletions manifest/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ var (
DefaultGpbftConfig = GpbftConfig{
Delta: 6 * time.Second,
DeltaBackOffExponent: 2.0,
DeltaBackOffMax: 1 * time.Hour,
QualityDeltaMultiplier: 1.0,
MaxLookaheadRounds: 5,
ChainProposedLength: gpbft.ChainDefaultLen,
Expand Down Expand Up @@ -114,6 +115,7 @@ func (c *CxConfig) Validate() error {
type GpbftConfig struct {
Delta time.Duration
DeltaBackOffExponent float64
DeltaBackOffMax time.Duration
QualityDeltaMultiplier float64
MaxLookaheadRounds uint64

Expand All @@ -132,6 +134,9 @@ func (g *GpbftConfig) Validate() error {
if g.DeltaBackOffExponent < 1.0 {
return fmt.Errorf("gpbft backoff exponent must be at least 1.0, was %f", g.DeltaBackOffExponent)
}
if g.DeltaBackOffMax < g.Delta {
return fmt.Errorf("gpbft delta backoff max must be no less than Delta, was %s", g.DeltaBackOffMax)
}

if g.QualityDeltaMultiplier < 0 {
return fmt.Errorf("gpbft quality duration multiplier is negative: %f", g.QualityDeltaMultiplier)
Expand Down Expand Up @@ -161,6 +166,7 @@ func (g *GpbftConfig) ToOptions() []gpbft.Option {
return []gpbft.Option{
gpbft.WithDelta(g.Delta),
gpbft.WithDeltaBackOffExponent(g.DeltaBackOffExponent),
gpbft.WithDeltaBackOffMax(g.DeltaBackOffMax),
gpbft.WithQualityDeltaMultiplier(g.QualityDeltaMultiplier),
gpbft.WithMaxLookaheadRounds(g.MaxLookaheadRounds),
gpbft.WithRebroadcastBackoff(
Expand Down
7 changes: 4 additions & 3 deletions manifest/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ var base = manifest.Manifest{
NetworkName: "test",
CommitteeLookback: 10,
Gpbft: manifest.GpbftConfig{
Delta: 10,
Delta: 10 * time.Second,
DeltaBackOffExponent: 1.2,
DeltaBackOffMax: 1 * time.Hour,
QualityDeltaMultiplier: 1.0,
MaxLookaheadRounds: 5,
ChainProposedLength: gpbft.ChainDefaultLen,
Expand Down Expand Up @@ -113,8 +114,8 @@ func TestManifest_CID(t *testing.T) {
t.Parallel()

const (
wantLocalDevnetCid = "baguqfiheaiqgpujeb5upzhbblchkuc2sxeis2y5upbsefktyspqqmjrcr27fiua"
wantAfterUpdateCid = "baguqfiheaiqaixtgfxvyaqdkdy6nsdybpvwjw7vgtw22enjg24kunho3b5nrduq"
wantLocalDevnetCid = "baguqfiheaiqkwe3ngxsexltkudtgs3ssqdeney2gxugqmw3jskkdmg56laxwzxq"
wantAfterUpdateCid = "baguqfiheaiqpmprgeaqongk4wunqi5rez2jpvsxhg3cebi5pvtjpbyz5gfrfvgq"
)
subject := manifest.LocalDevnetManifest()
// Use a fixed network name for deterministic CID calculation.
Expand Down
Loading