Skip to content

Commit

Permalink
feat(f3): prepare for f3 bootstrap
Browse files Browse the repository at this point in the history
This patch:

1. Bootstraps F3 when we hit the `F3BootstrapEpoch` (when non-negative).
2. Refuses any/all dynamic manifests once we get within one finality of said epoch.
3. Sets the F3 network name for mainnet to "filecoin".
4. Refuses any/all dynamic manifests that don't start with the expected
    network name prefix.
  • Loading branch information
Stebalien committed Oct 3, 2024
1 parent 0e7292a commit a1be71f
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 56 deletions.
83 changes: 57 additions & 26 deletions chain/lf3/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,72 @@ import (

"github.com/filecoin-project/go-f3/gpbft"
"github.com/filecoin-project/go-f3/manifest"
"github.com/filecoin-project/go-state-types/abi"

"github.com/filecoin-project/lotus/build/buildconstants"
"github.com/filecoin-project/lotus/chain/actors/policy"
"github.com/filecoin-project/lotus/node/modules/dtypes"
)

type Config struct {
InitialManifest *manifest.Manifest
DynamicManifestProvider peer.ID
// Base network name. This is usually the name of the network defined by the static manifest
// (if present) and is the base from which dynamic network names are defined.
BaseNetworkName gpbft.NetworkName
StaticManifest *manifest.Manifest
DynamicManifestProvider peer.ID
PrioritizeStaticManifest bool
}

func NewConfig(manifestProvider peer.ID, initialPowerTable cid.Cid) func(dtypes.NetworkName) *Config {
return func(nn dtypes.NetworkName) *Config {
m := manifest.LocalDevnetManifest()
m.NetworkName = gpbft.NetworkName(nn)
m.EC.Period = time.Duration(buildconstants.BlockDelaySecs) * time.Second
m.CatchUpAlignment = time.Duration(buildconstants.BlockDelaySecs) * time.Second / 2
if buildconstants.F3BootstrapEpoch < 0 {
// if unset, set to a sane default so we don't get scary logs and pause.
m.BootstrapEpoch = 2 * int64(policy.ChainFinality)
m.Pause = true
} else {
m.BootstrapEpoch = int64(buildconstants.F3BootstrapEpoch)
}
m.EC.Finality = int64(policy.ChainFinality)
m.CommitteeLookback = 5
m.InitialPowerTable = initialPowerTable
m.EC.Finalize = buildconstants.F3Consensus
func NewManifest(
nn gpbft.NetworkName,
finality, bootstrapEpoch abi.ChainEpoch,
ecPeriod time.Duration,
initialPowerTable cid.Cid,
) *manifest.Manifest {
return &manifest.Manifest{
ProtocolVersion: manifest.VersionCapability,
BootstrapEpoch: int64(bootstrapEpoch),
NetworkName: nn,
InitialPowerTable: initialPowerTable,
CommitteeLookback: manifest.DefaultCommitteeLookback,
CatchUpAlignment: ecPeriod / 2,
Gpbft: manifest.DefaultGpbftConfig,
EC: manifest.EcConfig{
Period: ecPeriod,
Finality: int64(finality),
DelayMultiplier: manifest.DefaultEcConfig.DelayMultiplier,
BaseDecisionBackoffTable: manifest.DefaultEcConfig.BaseDecisionBackoffTable,
HeadLookback: 0,
Finalize: true,
},
CertificateExchange: manifest.CxConfig{
ClientRequestTimeout: manifest.DefaultCxConfig.ClientRequestTimeout,
ServerRequestTimeout: manifest.DefaultCxConfig.ServerRequestTimeout,
MinimumPollInterval: ecPeriod,
MaximumPollInterval: 4 * ecPeriod,
},
}
}

// TODO: We're forcing this to start paused for now. We need to remove this for the final
// mainnet launch.
m.Pause = true
return &Config{
InitialManifest: m,
DynamicManifestProvider: manifestProvider,
}
func NewConfig(nn dtypes.NetworkName) *Config {
// Use "filecoin" as the network name on mainnet, otherwise use the network name. Yes,
// mainnet is called testnetnet in state.
if nn == "testnetnet" {
nn = "filecoin"
}
c := &Config{
BaseNetworkName: gpbft.NetworkName(nn),
PrioritizeStaticManifest: true,
DynamicManifestProvider: buildconstants.F3ManifestServerID,
}
if buildconstants.F3BootstrapEpoch >= 0 {
c.StaticManifest = NewManifest(
c.BaseNetworkName,
policy.ChainFinality,
buildconstants.F3BootstrapEpoch,
time.Duration(buildconstants.BlockDelaySecs)*time.Second,
buildconstants.F3InitialPowerTableCID,
)
}
return c
}
59 changes: 49 additions & 10 deletions chain/lf3/manifest.go
Original file line number Diff line number Diff line change
@@ -1,45 +1,84 @@
package lf3

import (
"context"
"fmt"
"strings"

"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/namespace"
pubsub "github.com/libp2p/go-libp2p-pubsub"
"golang.org/x/xerrors"

"github.com/filecoin-project/go-f3/ec"
"github.com/filecoin-project/go-f3/manifest"

"github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/modules/helpers"
)

type headGetter store.ChainStore

func (hg *headGetter) GetHead(context.Context) (ec.TipSet, error) {
head := (*store.ChainStore)(hg).GetHeaviestTipSet()
if head == nil {
return nil, xerrors.New("no heaviest tipset")
}
return &f3TipSet{TipSet: head}, nil
}

// Determines the max. number of configuration changes
// that are allowed for the dynamic manifest.
// If the manifest changes more than this number, the F3
// message topic will be filtered
var MaxDynamicManifestChangesAllowed = 1000

func NewManifestProvider(config *Config, ps *pubsub.PubSub, mds dtypes.MetadataDS) (manifest.ManifestProvider, error) {
func NewManifestProvider(mctx helpers.MetricsCtx, config *Config, cs *store.ChainStore, ps *pubsub.PubSub, mds dtypes.MetadataDS) (prov manifest.ManifestProvider, err error) {
if config.DynamicManifestProvider == "" {
return manifest.NewStaticManifestProvider(config.InitialManifest)
if config.StaticManifest == nil {
return manifest.NoopManifestProvider{}, nil
}
return manifest.NewStaticManifestProvider(config.StaticManifest)
}

opts := []manifest.DynamicManifestProviderOption{
manifest.DynamicManifestProviderWithDatastore(
namespace.Wrap(mds, datastore.NewKey("/f3-dynamic-manifest")),
),
}

if config.StaticManifest != nil {
opts = append(opts,
manifest.DynamicManifestProviderWithInitialManifest(config.StaticManifest),
)
}

primaryNetworkName := config.InitialManifest.NetworkName
networkNameBase := config.BaseNetworkName + "/"
filter := func(m *manifest.Manifest) error {
if m.EC.Finalize {
return fmt.Errorf("refusing dynamic manifest that finalizes tipsets")
}
if m.NetworkName == primaryNetworkName {
if !strings.HasPrefix(string(m.NetworkName), string(networkNameBase)) {
return fmt.Errorf(
"refusing dynamic manifest with network name %q that clashes with initial manifest",
primaryNetworkName,
"refusing dynamic manifest with network name %q, must start with %q",
m.NetworkName,
networkNameBase,
)
}
return nil
}
ds := namespace.Wrap(mds, datastore.NewKey("/f3-dynamic-manifest"))
return manifest.NewDynamicManifestProvider(ps, config.DynamicManifestProvider,
manifest.DynamicManifestProviderWithInitialManifest(config.InitialManifest),
manifest.DynamicManifestProviderWithDatastore(ds),
opts = append(opts,
manifest.DynamicManifestProviderWithFilter(filter),
)

prov, err = manifest.NewDynamicManifestProvider(ps, config.DynamicManifestProvider, opts...)
if err != nil {
return nil, err
}
if config.PrioritizeStaticManifest && config.StaticManifest != nil {
prov, err = manifest.NewFusingManifestProvider(mctx,
(*headGetter)(cs), prov, config.StaticManifest)
}
return prov, err
}
21 changes: 8 additions & 13 deletions itests/kit/node_opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/libp2p/go-libp2p/core/peer"

"github.com/filecoin-project/go-f3/gpbft"
"github.com/filecoin-project/go-f3/manifest"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/big"
Expand Down Expand Up @@ -218,23 +219,17 @@ func MutateSealingConfig(mut func(sc *config.SealingConfig)) NodeOpt {
func F3Enabled(bootstrapEpoch abi.ChainEpoch, blockDelay time.Duration, finality abi.ChainEpoch, manifestProvider peer.ID) NodeOpt {
return ConstructorOpts(
node.Override(new(*lf3.Config), func(nn dtypes.NetworkName) *lf3.Config {
c := lf3.NewConfig(manifestProvider, cid.Undef)(nn)
c.InitialManifest.Pause = false
c.InitialManifest.EC.Period = blockDelay
c.InitialManifest.Gpbft.Delta = blockDelay / 5
c.InitialManifest.EC.Finality = int64(finality)
c.InitialManifest.BootstrapEpoch = int64(bootstrapEpoch)
c.InitialManifest.EC.HeadLookback = 0
c.InitialManifest.EC.Finalize = true
c.InitialManifest.CatchUpAlignment = blockDelay / 2
c.InitialManifest.CertificateExchange.MinimumPollInterval = 2 * blockDelay
c.InitialManifest.CertificateExchange.MaximumPollInterval = 10 * blockDelay
return c
m := lf3.NewManifest(gpbft.NetworkName(nn), finality, bootstrapEpoch, blockDelay, cid.Undef)
return &lf3.Config{
StaticManifest: m,
DynamicManifestProvider: manifestProvider,
PrioritizeStaticManifest: false,
}
}),
node.Override(new(manifest.ManifestProvider),
func(config *lf3.Config, ps *pubsub.PubSub) (manifest.ManifestProvider, error) {
return manifest.NewDynamicManifestProvider(ps, config.DynamicManifestProvider,
manifest.DynamicManifestProviderWithInitialManifest(config.InitialManifest),
manifest.DynamicManifestProviderWithInitialManifest(config.StaticManifest),
)
}),
node.Override(new(*lf3.F3), lf3.New),
Expand Down
6 changes: 1 addition & 5 deletions node/builder_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (

"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/build/buildconstants"
"github.com/filecoin-project/lotus/chain"
"github.com/filecoin-project/lotus/chain/beacon"
"github.com/filecoin-project/lotus/chain/consensus"
Expand Down Expand Up @@ -165,10 +164,7 @@ var ChainNode = Options(
),

If(build.IsF3Enabled(),
Override(new(*lf3.Config), lf3.NewConfig(
buildconstants.F3ManifestServerID,
buildconstants.F3InitialPowerTableCID,
)),
Override(new(*lf3.Config), lf3.NewConfig),
Override(new(manifest.ManifestProvider), lf3.NewManifestProvider),
Override(new(*lf3.F3), lf3.New),
),
Expand Down
7 changes: 5 additions & 2 deletions node/modules/lp2p/pubsub.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,9 +388,12 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) {
allowTopics = append(allowTopics, drandTopics...)

if in.F3Config != nil {
f3BaseTopicName := manifest.PubSubTopicFromNetworkName(in.F3Config.InitialManifest.NetworkName)
allowTopics = append(allowTopics, f3BaseTopicName)
if in.F3Config.StaticManifest != nil {
f3TopicName := manifest.PubSubTopicFromNetworkName(in.F3Config.StaticManifest.NetworkName)
allowTopics = append(allowTopics, f3TopicName)
}
if in.F3Config.DynamicManifestProvider != "" {
f3BaseTopicName := manifest.PubSubTopicFromNetworkName(in.F3Config.BaseNetworkName)
allowTopics = append(allowTopics, manifest.ManifestPubSubTopicName)
for i := 0; i < lf3.MaxDynamicManifestChangesAllowed; i++ {
allowTopics = append(allowTopics, fmt.Sprintf("%s/%d", f3BaseTopicName, i))
Expand Down

0 comments on commit a1be71f

Please sign in to comment.