diff --git a/.golangci.yml b/.golangci.yml index b8ee9849d0e..d95b76d4024 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -10,7 +10,6 @@ linters: - gosec - unconvert - staticcheck - - exportloopref - unused # We don't want to skip builtin/ @@ -51,7 +50,6 @@ issues: exclude-use-default: false exclude-rules: - - path: .*_test.go linters: - gosec diff --git a/CHANGELOG.md b/CHANGELOG.md index 75577486946..573c20eb057 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - feat: expose `/v2` APIs through Lotus Gateway ([filecoin-project/lotus#13075](https://github.com/filecoin-project/lotus/pull/13075)) - chore: upgrade to go-f3 `v0.8.4` ([filecoin-project/lotus#13084](https://github.com/filecoin-project/lotus/pull/13084)) - fix(f3): limit the concurrency of F3 power table calculation ([filecoin-project/lotus#13085](https://github.com/filecoin-project/lotus/pull/13085)) +- feat(f3): remove dynnamic manifest functionality and use static manifest ([filecoin-project/lotus#13074](https://github.com/filecoin-project/lotus/pull/13074)) See https://github.com/filecoin-project/lotus/blob/release/v1.33.0/CHANGELOG.md diff --git a/build/buildconstants/f3manifest_2k.json b/build/buildconstants/f3manifest_2k.json new file mode 100644 index 00000000000..de90dea1cc3 --- /dev/null +++ b/build/buildconstants/f3manifest_2k.json @@ -0,0 +1,61 @@ +{ + "Pause": false, + "ProtocolVersion": 7, + "InitialInstance": 0, + "BootstrapEpoch": 1000, + "NetworkName": "2k", + "ExplicitPower": null, + "IgnoreECPower": false, + "InitialPowerTable": null, + "CommitteeLookback": 10, + "CatchUpAlignment": 15000000000, + "Gpbft": { + "Delta": 6000000000, + "DeltaBackOffExponent": 2, + "QualityDeltaMultiplier": 1, + "MaxLookaheadRounds": 5, + "ChainProposedLength": 100, + "RebroadcastBackoffBase": 6000000000, + "RebroadcastBackoffExponent": 1.3, + "RebroadcastBackoffSpread": 0.1, + "RebroadcastBackoffMax": 60000000000 + }, + "EC": { + "Period": 4000000000, + "Finality": 900, + "DelayMultiplier": 2, + "BaseDecisionBackoffTable": [1.3, 1.69, 2.2, 2.86, 3.71, 4.83, 6.27, 7.5], + "HeadLookback": 4, + "Finalize": true + }, + "CertificateExchange": { + "ClientRequestTimeout": 10000000000, + "ServerRequestTimeout": 60000000000, + "MinimumPollInterval": 30000000000, + "MaximumPollInterval": 120000000000 + }, + "PubSub": { + "CompressionEnabled": true, + "ChainCompressionEnabled": true, + "GMessageSubscriptionBufferSize": 128, + "ValidatedMessageBufferSize": 128 + }, + "ChainExchange": { + "SubscriptionBufferSize": 32, + "MaxChainLength": 100, + "MaxInstanceLookahead": 10, + "MaxDiscoveredChainsPerInstance": 1000, + "MaxWantedChainsPerInstance": 1000, + "RebroadcastInterval": 2000000000, + "MaxTimestampAge": 8000000000 + }, + "PartialMessageManager": { + "PendingDiscoveredChainsBufferSize": 100, + "PendingPartialMessagesBufferSize": 100, + "PendingChainBroadcastsBufferSize": 100, + "PendingInstanceRemovalBufferSize": 10, + "CompletedMessagesBufferSize": 100, + "MaxBufferedMessagesPerInstance": 25000, + "MaxCachedValidatedMessagesPerInstance": 25000 + } +} diff --git a/build/buildconstants/f3manifest_butterfly.json b/build/buildconstants/f3manifest_butterfly.json new file mode 100644 index 00000000000..50c94e0b87d --- /dev/null +++ b/build/buildconstants/f3manifest_butterfly.json @@ -0,0 +1,61 @@ +{ + "Pause": false, + "ProtocolVersion": 7, + "InitialInstance": 0, + "BootstrapEpoch": 1000, + "NetworkName": "butterflynet", + "ExplicitPower": null, + "IgnoreECPower": false, + "InitialPowerTable": null, + "CommitteeLookback": 10, + "CatchUpAlignment": 15000000000, + "Gpbft": { + "Delta": 6000000000, + "DeltaBackOffExponent": 2, + "QualityDeltaMultiplier": 1, + "MaxLookaheadRounds": 5, + "ChainProposedLength": 100, + "RebroadcastBackoffBase": 6000000000, + "RebroadcastBackoffExponent": 1.3, + "RebroadcastBackoffSpread": 0.1, + "RebroadcastBackoffMax": 60000000000 + }, + "EC": { + "Period": 30000000000, + "Finality": 900, + "DelayMultiplier": 2, + "BaseDecisionBackoffTable": [1.3, 1.69, 2.2, 2.86, 3.71, 4.83, 6.27, 7.5], + "HeadLookback": 4, + "Finalize": true + }, + "CertificateExchange": { + "ClientRequestTimeout": 10000000000, + "ServerRequestTimeout": 60000000000, + "MinimumPollInterval": 30000000000, + "MaximumPollInterval": 120000000000 + }, + "PubSub": { + "CompressionEnabled": true, + "ChainCompressionEnabled": true, + "GMessageSubscriptionBufferSize": 128, + "ValidatedMessageBufferSize": 128 + }, + "ChainExchange": { + "SubscriptionBufferSize": 32, + "MaxChainLength": 100, + "MaxInstanceLookahead": 10, + "MaxDiscoveredChainsPerInstance": 1000, + "MaxWantedChainsPerInstance": 1000, + "RebroadcastInterval": 2000000000, + "MaxTimestampAge": 8000000000 + }, + "PartialMessageManager": { + "PendingDiscoveredChainsBufferSize": 100, + "PendingPartialMessagesBufferSize": 100, + "PendingChainBroadcastsBufferSize": 100, + "PendingInstanceRemovalBufferSize": 10, + "CompletedMessagesBufferSize": 100, + "MaxBufferedMessagesPerInstance": 25000, + "MaxCachedValidatedMessagesPerInstance": 25000 + } +} diff --git a/chain/lf3/testdata/contract_manifest_golden.json b/build/buildconstants/f3manifest_calibnet.json similarity index 90% rename from chain/lf3/testdata/contract_manifest_golden.json rename to build/buildconstants/f3manifest_calibnet.json index c9fe811e6db..9ac51fcbf74 100644 --- a/chain/lf3/testdata/contract_manifest_golden.json +++ b/build/buildconstants/f3manifest_calibnet.json @@ -2,11 +2,13 @@ "Pause": false, "ProtocolVersion": 7, "InitialInstance": 0, - "BootstrapEpoch": 5000000, - "NetworkName": "filecoin", + "BootstrapEpoch": 2081674, + "NetworkName": "calibrationnet", "ExplicitPower": null, "IgnoreECPower": false, - "InitialPowerTable": null, + "InitialPowerTable": { + "/": "bafy2bzaceab236vmmb3n4q4tkvua2n4dphcbzzxerxuey3mot4g3cov5j3r2c" + }, "CommitteeLookback": 10, "CatchUpAlignment": 15000000000, "Gpbft": { @@ -34,7 +36,7 @@ 6.27, 7.5 ], - "HeadLookback": 0, + "HeadLookback": 4, "Finalize": true }, "CertificateExchange": { diff --git a/build/buildconstants/f3manifest_interop.json b/build/buildconstants/f3manifest_interop.json new file mode 100644 index 00000000000..72d4d1d1a4b --- /dev/null +++ b/build/buildconstants/f3manifest_interop.json @@ -0,0 +1,61 @@ +{ + "Pause": false, + "ProtocolVersion": 7, + "InitialInstance": 0, + "BootstrapEpoch": 1000, + "NetworkName": "interopnet", + "ExplicitPower": null, + "IgnoreECPower": false, + "InitialPowerTable": null, + "CommitteeLookback": 10, + "CatchUpAlignment": 15000000000, + "Gpbft": { + "Delta": 6000000000, + "DeltaBackOffExponent": 2, + "QualityDeltaMultiplier": 1, + "MaxLookaheadRounds": 5, + "ChainProposedLength": 100, + "RebroadcastBackoffBase": 6000000000, + "RebroadcastBackoffExponent": 1.3, + "RebroadcastBackoffSpread": 0.1, + "RebroadcastBackoffMax": 60000000000 + }, + "EC": { + "Period": 30000000000, + "Finality": 900, + "DelayMultiplier": 2, + "BaseDecisionBackoffTable": [1.3, 1.69, 2.2, 2.86, 3.71, 4.83, 6.27, 7.5], + "HeadLookback": 4, + "Finalize": true + }, + "CertificateExchange": { + "ClientRequestTimeout": 10000000000, + "ServerRequestTimeout": 60000000000, + "MinimumPollInterval": 30000000000, + "MaximumPollInterval": 120000000000 + }, + "PubSub": { + "CompressionEnabled": true, + "ChainCompressionEnabled": true, + "GMessageSubscriptionBufferSize": 128, + "ValidatedMessageBufferSize": 128 + }, + "ChainExchange": { + "SubscriptionBufferSize": 32, + "MaxChainLength": 100, + "MaxInstanceLookahead": 10, + "MaxDiscoveredChainsPerInstance": 1000, + "MaxWantedChainsPerInstance": 1000, + "RebroadcastInterval": 2000000000, + "MaxTimestampAge": 8000000000 + }, + "PartialMessageManager": { + "PendingDiscoveredChainsBufferSize": 100, + "PendingPartialMessagesBufferSize": 100, + "PendingChainBroadcastsBufferSize": 100, + "PendingInstanceRemovalBufferSize": 10, + "CompletedMessagesBufferSize": 100, + "MaxBufferedMessagesPerInstance": 25000, + "MaxCachedValidatedMessagesPerInstance": 25000 + } +} diff --git a/build/buildconstants/f3manifest_mainnet.json b/build/buildconstants/f3manifest_mainnet.json new file mode 100644 index 00000000000..1e776c8ce79 --- /dev/null +++ b/build/buildconstants/f3manifest_mainnet.json @@ -0,0 +1,63 @@ +{ + "Pause": false, + "ProtocolVersion": 7, + "InitialInstance": 0, + "BootstrapEpoch": 4920480, + "NetworkName": "filecoin", + "ExplicitPower": null, + "IgnoreECPower": false, + "InitialPowerTable": { + "/": "bafy2bzacecklgxd2eksmodvhgurqvorkg3wamgqkrunir3al2gchv2cikgmbu" + }, + "CommitteeLookback": 10, + "CatchUpAlignment": 15000000000, + "Gpbft": { + "Delta": 6000000000, + "DeltaBackOffExponent": 2, + "QualityDeltaMultiplier": 8, + "MaxLookaheadRounds": 5, + "ChainProposedLength": 20, + "RebroadcastBackoffBase": 6000000000, + "RebroadcastBackoffExponent": 1.3, + "RebroadcastBackoffSpread": 0.1, + "RebroadcastBackoffMax": 60000000000 + }, + "EC": { + "Period": 30000000000, + "Finality": 900, + "DelayMultiplier": 2, + "BaseDecisionBackoffTable": [1.3, 1.69, 2.2, 2.86, 3.71, 4.83, 6.27, 7.5], + "HeadLookback": 4, + "Finalize": true + }, + "CertificateExchange": { + "ClientRequestTimeout": 10000000000, + "ServerRequestTimeout": 60000000000, + "MinimumPollInterval": 30000000000, + "MaximumPollInterval": 120000000000 + }, + "PubSub": { + "CompressionEnabled": true, + "ChainCompressionEnabled": true, + "GMessageSubscriptionBufferSize": 768, + "ValidatedMessageBufferSize": 1024 + }, + "ChainExchange": { + "SubscriptionBufferSize": 64, + "MaxChainLength": 20, + "MaxInstanceLookahead": 10, + "MaxDiscoveredChainsPerInstance": 1000, + "MaxWantedChainsPerInstance": 1000, + "RebroadcastInterval": 2000000000, + "MaxTimestampAge": 16000000000 + }, + "PartialMessageManager": { + "PendingDiscoveredChainsBufferSize": 100, + "PendingPartialMessagesBufferSize": 100, + "PendingChainBroadcastsBufferSize": 100, + "PendingInstanceRemovalBufferSize": 10, + "CompletedMessagesBufferSize": 100, + "MaxBufferedMessagesPerInstance": 25000, + "MaxCachedValidatedMessagesPerInstance": 25000 + } +} diff --git a/build/buildconstants/params_2k.go b/build/buildconstants/params_2k.go index 20fb5ac2f4b..837c26b8d8b 100644 --- a/build/buildconstants/params_2k.go +++ b/build/buildconstants/params_2k.go @@ -4,6 +4,7 @@ package buildconstants import ( + _ "embed" "os" "strconv" "strings" @@ -180,7 +181,6 @@ func init() { } F3Enabled = getBoolean("LOTUS_F3_ENABLED", F3Enabled) - F3BootstrapEpoch = getUpgradeHeight("LOTUS_F3_BOOTSTRAP_EPOCH", F3BootstrapEpoch) BuildType |= Build2k @@ -211,11 +211,5 @@ var WhitelistedBlock = cid.Undef var F3Enabled = true -var F3ManifestServerID = MustParseID("12D3KooWHcNBkqXEBrsjoveQvj6zDF3vK5S9tAfqyYaQF1LGSJwG") - -// The initial F3 power table CID. -var F3InitialPowerTableCID cid.Cid = cid.Undef - -var F3BootstrapEpoch abi.ChainEpoch = 1000 - -var F3ParamsAddress = "" +//go:embed f3manifest_2k.json +var F3ManifestBytes []byte diff --git a/build/buildconstants/params_butterfly.go b/build/buildconstants/params_butterfly.go index b71690922f5..0b05ac96b03 100644 --- a/build/buildconstants/params_butterfly.go +++ b/build/buildconstants/params_butterfly.go @@ -4,6 +4,8 @@ package buildconstants import ( + _ "embed" + "github.com/ipfs/go-cid" "github.com/filecoin-project/go-address" @@ -109,10 +111,5 @@ var WhitelistedBlock = cid.Undef const F3Enabled = true -var F3ManifestServerID = MustParseID("12D3KooWJr9jy4ngtJNR7JC1xgLFra3DjEtyxskRYWvBK9TC3Yn6") - -// The initial F3 power table CID. -var F3InitialPowerTableCID cid.Cid = cid.Undef - -const F3BootstrapEpoch abi.ChainEpoch = -1 -const F3ParamsAddress = "0x9fd3B2D38EE4C920c9954DA752eDF810887501c1" +//go:embed f3manifest_butterfly.json +var F3ManifestBytes []byte diff --git a/build/buildconstants/params_calibnet.go b/build/buildconstants/params_calibnet.go index aa5d7504a76..fb159933254 100644 --- a/build/buildconstants/params_calibnet.go +++ b/build/buildconstants/params_calibnet.go @@ -4,6 +4,7 @@ package buildconstants import ( + _ "embed" "os" "strconv" @@ -167,12 +168,5 @@ var WhitelistedBlock = cid.Undef const F3Enabled = true -var F3ManifestServerID = MustParseID("12D3KooWS9vD9uwm8u2uPyJV32QBAhKAmPYwmziAgr3Xzk2FU1Mr") - -// The initial F3 power table CID. -var F3InitialPowerTableCID cid.Cid = cid.MustParse("bafy2bzaceab236vmmb3n4q4tkvua2n4dphcbzzxerxuey3mot4g3cov5j3r2c") - -// Calibnet F3 activation epoch is 2024-10-24T13:30:00Z - Epoch 2081674 -const F3BootstrapEpoch abi.ChainEpoch = UpgradeTuktukHeight + 2880 - -var F3ParamsAddress = "" +//go:embed f3manifest_calibnet.json +var F3ManifestBytes []byte diff --git a/build/buildconstants/params_interop.go b/build/buildconstants/params_interop.go index c080ee2e580..80f2733c10e 100644 --- a/build/buildconstants/params_interop.go +++ b/build/buildconstants/params_interop.go @@ -149,11 +149,5 @@ var WhitelistedBlock = cid.Undef const F3Enabled = true -var F3ManifestServerID = MustParseID("12D3KooWQJ2rdVnG4okDUB6yHQhAjNutGNemcM7XzqC9Eo4z9Jce") - -// The initial F3 power table CID. -var F3InitialPowerTableCID cid.Cid = cid.Undef - -const F3BootstrapEpoch abi.ChainEpoch = 1000 - -var F3ParamsAddress = "" +//go:embed f3manifest_interop.json +var F3ManifestBytes []byte diff --git a/build/buildconstants/params_mainnet.go b/build/buildconstants/params_mainnet.go index 428e72723d5..ca760f9b1d4 100644 --- a/build/buildconstants/params_mainnet.go +++ b/build/buildconstants/params_mainnet.go @@ -4,6 +4,7 @@ package buildconstants import ( + _ "embed" "math" "os" "strconv" @@ -190,13 +191,7 @@ const Eip155ChainId = 314 // WhitelistedBlock skips checks on message validity in this block to sidestep the zero-bls signature var WhitelistedBlock = cid.MustParse("bafy2bzaceapyg2uyzk7vueh3xccxkuwbz3nxewjyguoxvhx77malc2lzn2ybi") -// The F3 manifest server ID, if any. -var F3ManifestServerID = MustParseID("12D3KooWENMwUF9YxvQxar7uBWJtZkA6amvK4xWmKXfSiHUo2Qq7") - -// The initial F3 power table CID. -var F3InitialPowerTableCID = cid.MustParse("bafy2bzacecklgxd2eksmodvhgurqvorkg3wamgqkrunir3al2gchv2cikgmbu") - const F3Enabled = true -const F3BootstrapEpoch abi.ChainEpoch = -1 -var F3ParamsAddress = "0xA19080A1Bcb82Bb61bcb9691EC94653Eb5315716" +//go:embed f3manifest_mainnet.json +var F3ManifestBytes []byte diff --git a/build/buildconstants/params_shared_vals.go b/build/buildconstants/params_shared_vals.go index 879ddaba955..e6d1d71afb3 100644 --- a/build/buildconstants/params_shared_vals.go +++ b/build/buildconstants/params_shared_vals.go @@ -6,8 +6,6 @@ package buildconstants import ( "os" - "github.com/ipfs/go-cid" - "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin" @@ -67,16 +65,6 @@ func init() { if os.Getenv("LOTUS_ADDRESS_TYPE") == AddressMainnetEnvVar { SetAddressNetwork(address.Mainnet) } - - if ptCid := os.Getenv("F3_INITIAL_POWERTABLE_CID"); ptCid != "" { - if k, err := cid.Parse(ptCid); err != nil { - log.Errorf("failed to parse F3_INITIAL_POWERTABLE_CID %q: %s", ptCid, err) - } else if F3InitialPowerTableCID.Defined() && k != F3InitialPowerTableCID { - log.Errorf("ignoring F3_INITIAL_POWERTABLE_CID as lotus has a hard-coded initial F3 power table") - } else { - F3InitialPowerTableCID = k - } - } } // Sync diff --git a/build/buildconstants/params_testground.go b/build/buildconstants/params_testground.go index 15ca46cae33..384b99a41af 100644 --- a/build/buildconstants/params_testground.go +++ b/build/buildconstants/params_testground.go @@ -8,10 +8,10 @@ package buildconstants import ( + _ "embed" "math/big" "github.com/ipfs/go-cid" - "github.com/libp2p/go-libp2p/core/peer" "github.com/filecoin-project/go-address" "github.com/filecoin-project/go-state-types/abi" @@ -125,14 +125,12 @@ var ( ZeroAddress = MustParseAddress("f3yaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaby2smx7a") - WhitelistedBlock = cid.Undef - BootstrappersFile = "" - GenesisFile = "" - F3Enabled = false - F3ManifestServerID peer.ID = "" - F3BootstrapEpoch abi.ChainEpoch = -1 - F3InitialPowerTableCID = cid.Undef - F3ParamsAddress = "" + WhitelistedBlock = cid.Undef + BootstrappersFile = "" + GenesisFile = "" + + F3Enabled = false + F3ManifestBytes []byte ) func init() { diff --git a/build/buildconstants/shared_funcs.go b/build/buildconstants/shared_funcs.go index 114452753d6..a2d4ddc71db 100644 --- a/build/buildconstants/shared_funcs.go +++ b/build/buildconstants/shared_funcs.go @@ -1,12 +1,17 @@ package buildconstants import ( + "encoding/json" "math/big" + "os" + "time" + "github.com/ipfs/go-cid" logging "github.com/ipfs/go-log/v2" "github.com/libp2p/go-libp2p/core/peer" "github.com/filecoin-project/go-address" + "github.com/filecoin-project/go-f3/manifest" "github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/lotus/chain/actors/policy" @@ -47,3 +52,36 @@ func wholeFIL(whole uint64) *big.Int { bigWhole := big.NewInt(int64(whole)) return bigWhole.Mul(bigWhole, big.NewInt(int64(FilecoinPrecision))) } + +func F3Manifest() *manifest.Manifest { + if F3ManifestBytes == nil { + return nil + } + var manif manifest.Manifest + + if err := json.Unmarshal(F3ManifestBytes, &manif); err != nil { + log.Panicf("failed to unmarshal F3 manifest: %s", err) + } + if err := manif.Validate(); err != nil { + log.Panicf("invalid F3 manifest: %s", err) + } + + if ptCid := os.Getenv("F3_INITIAL_POWERTABLE_CID"); ptCid != "" { + if k, err := cid.Parse(ptCid); err != nil { + log.Errorf("failed to parse F3_INITIAL_POWERTABLE_CID %q: %s", ptCid, err) + } else if manif.InitialPowerTable.Defined() && k != manif.InitialPowerTable { + log.Errorf("ignoring F3_INITIAL_POWERTABLE_CID as lotus has a hard-coded initial F3 power table") + } else { + manif.InitialPowerTable = k + } + } + if !manif.InitialPowerTable.Defined() { + log.Warn("initial power table is not specified, it will be populated automatically assuming this is testing network") + } + + // EC Period sanity check + if manif.EC.Period != time.Duration(BlockDelaySecs)*time.Second { + log.Panicf("static manifest EC period is %v, expected %v", manif.EC.Period, time.Duration(BlockDelaySecs)*time.Second) + } + return &manif +} diff --git a/chain/lf3/config.go b/chain/lf3/config.go index abf9c082a62..7802a8e0f89 100644 --- a/chain/lf3/config.go +++ b/chain/lf3/config.go @@ -1,18 +1,15 @@ package lf3 import ( - "os" "time" "github.com/ipfs/go-cid" - "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/lotus/build/buildconstants" - "github.com/filecoin-project/lotus/chain/actors/policy" "github.com/filecoin-project/lotus/node/modules/dtypes" ) @@ -24,21 +21,6 @@ type Config struct { // StaticManifest this instance's default manifest absent any dynamic manifests. Also see // PrioritizeStaticManifest. StaticManifest *manifest.Manifest - // DynamicManifestProvider is the peer ID of the peer authorized to send us dynamic manifest - // updates. Dynamic manifest updates can be used for testing but will not be used to affect - // finality. - DynamicManifestProvider peer.ID - // PrioritizeStaticManifest means that, once we get within one finality of the static - // manifest's bootstrap epoch we'll switch to it and ignore any further dynamic manifest - // updates. This exists to enable bootstrapping F3. - PrioritizeStaticManifest bool - // TESTINGAllowDynamicFinalize allow dynamic manifests to finalize tipsets. DO NOT ENABLE - // THIS IN PRODUCTION! - AllowDynamicFinalize bool - - // ContractAddress specifies the address of the contract carring F3 parameters - ContractAddress string - ContractPollInterval time.Duration } // NewManifest constructs a sane F3 manifest based on the passed parameters. This function does not @@ -85,34 +67,10 @@ func NewConfig(nn dtypes.NetworkName) *Config { if nn == "testnetnet" { nn = "filecoin" } - pollInterval := 15 * time.Minute - if envVar := os.Getenv("LOTUS_F3_POLL_INTERVAL"); len(envVar) != 0 { - d, err := time.ParseDuration(envVar) - if err != nil { - log.Errorf("invalid duration in LOTUS_F3_POLL_INTERVAL, defaulting to %v", pollInterval) - } else { - pollInterval = d - } - - } c := &Config{ - BaseNetworkName: gpbft.NetworkName(nn), - PrioritizeStaticManifest: true, - DynamicManifestProvider: buildconstants.F3ManifestServerID, - AllowDynamicFinalize: false, - ContractPollInterval: pollInterval, - } - if buildconstants.F3BootstrapEpoch >= 0 { - c.StaticManifest = NewManifest( - c.BaseNetworkName, - policy.ChainFinality, - buildconstants.F3BootstrapEpoch, - time.Duration(buildconstants.BlockDelaySecs)*time.Second, - buildconstants.F3InitialPowerTableCID, - ) - } - if buildconstants.F3ParamsAddress != "" { - c.ContractAddress = buildconstants.F3ParamsAddress + BaseNetworkName: gpbft.NetworkName(nn), + StaticManifest: buildconstants.F3Manifest(), } + return c } diff --git a/chain/lf3/manifest.go b/chain/lf3/manifest.go index 1da82c8efbc..670ecca67ef 100644 --- a/chain/lf3/manifest.go +++ b/chain/lf3/manifest.go @@ -1,356 +1,25 @@ package lf3 import ( - "bytes" - "compress/flate" - "context" - "encoding/binary" - "encoding/json" - "fmt" - "io" - "math" - "strings" - "time" - - "github.com/ipfs/go-datastore" - "github.com/ipfs/go-datastore/namespace" - pubsub "github.com/libp2p/go-libp2p-pubsub" - "golang.org/x/sync/errgroup" "golang.org/x/xerrors" - "github.com/filecoin-project/go-f3/ec" - "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/api" "github.com/filecoin-project/lotus/build" - "github.com/filecoin-project/lotus/build/buildconstants" - "github.com/filecoin-project/lotus/chain/store" - "github.com/filecoin-project/lotus/chain/types" - "github.com/filecoin-project/lotus/chain/types/ethtypes" - "github.com/filecoin-project/lotus/lib/must" - "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") +func NewManifestProvider(mctx helpers.MetricsCtx, config *Config) (prov manifest.ManifestProvider, err error) { + if config.StaticManifest == nil { + return manifest.NoopManifestProvider{}, nil } - 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(mctx helpers.MetricsCtx, config *Config, cs *store.ChainStore, ps *pubsub.PubSub, mds dtypes.MetadataDS, stateCaller StateCaller) (prov manifest.ManifestProvider, err error) { - var primaryManifest manifest.ManifestProvider - - // Check if static manifest activation is disabled - staticDisabled := false if config.StaticManifest != nil && build.IsF3EpochActivationDisabled(config.StaticManifest.BootstrapEpoch) { log.Warnf("F3 activation disabled by environment configuration for bootstrap epoch %d", config.StaticManifest.BootstrapEpoch) - staticDisabled = true - } - - // Check if contract manifest activation is disabled - contractDisabled := false - if config.ContractAddress != "" && build.IsF3ContractActivationDisabled(config.ContractAddress) { - log.Warnf("F3 activation disabled by environment configuration for contract %s", config.ContractAddress) - contractDisabled = true - } - - if config.StaticManifest != nil && !staticDisabled { - log.Infof("using static manifest as primary") - primaryManifest, err = manifest.NewStaticManifestProvider(config.StaticManifest) - } else if config.ContractAddress != "" && !contractDisabled { - log.Infow("using contract manifest as primary", "address", config.ContractAddress) - primaryManifest, err = NewContractManifestProvider(mctx, config, stateCaller) - } - - if err != nil { - return nil, fmt.Errorf("creating primary manifest: %w", err) - } - - if config.DynamicManifestProvider == "" || !build.IsF3PassiveTestingEnabled() { - if config.StaticManifest == nil && config.ContractAddress == "" { - return manifest.NoopManifestProvider{}, nil - } - return primaryManifest, nil - } - - opts := []manifest.DynamicManifestProviderOption{ - manifest.DynamicManifestProviderWithDatastore( - namespace.Wrap(mds, datastore.NewKey("/f3-dynamic-manifest")), - ), - } - - if config.AllowDynamicFinalize { - log.Error("dynamic F3 manifests are allowed to finalize tipsets, do not enable this in production!") - } - - networkNameBase := config.BaseNetworkName + "/" - filter := func(m *manifest.Manifest) error { - if m.EC.Finalize { - if !config.AllowDynamicFinalize { - return fmt.Errorf("refusing dynamic manifest that finalizes tipsets") - } - log.Error("WARNING: loading a dynamic F3 manifest that will finalize new tipsets") - } - if !strings.HasPrefix(string(m.NetworkName), string(networkNameBase)) { - return fmt.Errorf( - "refusing dynamic manifest with network name %q, must start with %q", - m.NetworkName, - networkNameBase, - ) - } - return nil - } - opts = append(opts, - manifest.DynamicManifestProviderWithFilter(filter), - ) - - prov, err = manifest.NewDynamicManifestProvider(ps, config.DynamicManifestProvider, opts...) - if err != nil { - return nil, err - } - if config.PrioritizeStaticManifest && primaryManifest != nil { - prov, err = manifest.NewFusingManifestProvider(mctx, - (*headGetter)(cs), prov, primaryManifest) - } - return prov, err -} - -type StateCaller interface { - StateCall(ctx context.Context, msg *types.Message, tsk types.TipSetKey) (res *api.InvocResult, err error) -} - -type ContractManifestProvider struct { - address string - networkName gpbft.NetworkName - stateCaller StateCaller - pollInterval time.Duration - - manifestChanges chan *manifest.Manifest - - errgrp *errgroup.Group - runningCtx context.Context - cancel context.CancelFunc -} - -func NewContractManifestProvider(mctx helpers.MetricsCtx, config *Config, stateCaller StateCaller) (*ContractManifestProvider, error) { - ctx, cancel := context.WithCancel(context.WithoutCancel(mctx)) - errgrp, ctx := errgroup.WithContext(ctx) - return &ContractManifestProvider{ - stateCaller: stateCaller, - address: config.ContractAddress, - networkName: config.BaseNetworkName, - pollInterval: config.ContractPollInterval, - - manifestChanges: make(chan *manifest.Manifest, 1), - - errgrp: errgrp, - runningCtx: ctx, - cancel: cancel, - }, nil -} - -func (cmp *ContractManifestProvider) Start(context.Context) error { - // no address, nothing to do - if len(cmp.address) == 0 { - // send nil so fusing knows we have nothing - log.Infof("contract manifest provider, address unknown, exiting") - cmp.manifestChanges <- nil - return nil - } - - var knownManifest *manifest.Manifest - knownManifest, err := cmp.fetchManifest(cmp.runningCtx) - if err != nil { - log.Warnw("got error while fetching manifest from contract", "error", err) + return manifest.NoopManifestProvider{}, nil } - cmp.manifestChanges <- knownManifest - - cmp.errgrp.Go(func() error { - t := time.NewTicker(cmp.pollInterval) - defer t.Stop() - - loop: - for cmp.runningCtx.Err() == nil { - select { - case <-t.C: - m, err := cmp.fetchManifest(cmp.runningCtx) - if err != nil { - log.Warnw("got error while fetching manifest from contract", "error", err) - continue loop - } - - if knownManifest.Equal(m) { - continue loop - } - - c, err := m.Cid() - if err != nil { - log.Errorf("got error while computing manifest CID") - } - - if m != nil { - log.Infow("new manifest from contract", "enabled", true, - "bootstrapEpoch", m.BootstrapEpoch, - "manifestCID", c) - } else { - log.Info("new manifest from contract", "enabled", false) - } - cmp.manifestChanges <- m - knownManifest = m - case <-cmp.runningCtx.Done(): - } - } - - return nil - }) - return nil -} - -func decompressManifest(compressedManifest []byte) (*manifest.Manifest, error) { - reader := io.LimitReader(flate.NewReader(bytes.NewReader(compressedManifest)), 1<<20) - var m manifest.Manifest - err := json.NewDecoder(reader).Decode(&m) + smp, err := manifest.NewStaticManifestProvider(config.StaticManifest) if err != nil { - return nil, err + return nil, xerrors.Errorf("creating static manifest provider: %w", err) } - return &m, nil -} - -func (cmp *ContractManifestProvider) fetchManifest(ctx context.Context) (*manifest.Manifest, error) { - ethReturn, err := cmp.callContract(ctx) - if err != nil { - return nil, fmt.Errorf("calling contract at %s: %w", cmp.address, err) - } - if len(ethReturn) == 0 { - return nil, nil - } - - activationEpoch, compressedManifest, err := parseContractReturn(ethReturn) - if err != nil { - return nil, fmt.Errorf("parsing contract information: %w", err) - } - - if activationEpoch == math.MaxUint64 || len(compressedManifest) == 0 { - return nil, nil - } - - m, err := decompressManifest(compressedManifest) - if err != nil { - return nil, fmt.Errorf("got error while decoding manifest: %w", err) - } - - if m.BootstrapEpoch < 0 || uint64(m.BootstrapEpoch) != activationEpoch { - return nil, fmt.Errorf("bootstrap epoch does not match: %d != %d", m.BootstrapEpoch, activationEpoch) - } - - if !m.InitialPowerTable.Defined() && buildconstants.F3InitialPowerTableCID.Defined() { - m.InitialPowerTable = buildconstants.F3InitialPowerTableCID - } - - if err := m.Validate(); err != nil { - return nil, fmt.Errorf("manifest does not validate: %w", err) - } - - if m.NetworkName != cmp.networkName { - return nil, fmt.Errorf("network name does not match, expected: %s, got: %s", - cmp.networkName, m.NetworkName) - } - - return m, nil -} - -func parseContractReturn(retBytes []byte) (uint64, []byte, error) { - // 3*32 because there should be 3 slots minimum - if len(retBytes) < 3*32 { - return 0, nil, fmt.Errorf("no activation information") - } - - var slot []byte - // split off first slot - slot, retBytes = retBytes[:32], retBytes[32:] - // it is uint64 so we want the last 8 bytes - slot = slot[24:32] - activationEpoch := binary.BigEndian.Uint64(slot) - - // next slot is the offest to variable length bytes - // it is always the same 0x00000...0040 - slot, retBytes = retBytes[:32], retBytes[32:] - for i := 0; i < 31; i++ { - if slot[i] != 0 { - return 0, nil, fmt.Errorf("wrong value for offest (padding): slot[%d] = 0x%x != 0x00", i, slot[i]) - } - } - if slot[31] != 0x40 { - return 0, nil, fmt.Errorf("wrong value for offest : slot[31] = 0x%x != 0x40", slot[31]) - } - - // finally after that there are manifest bytes - // starts with length in a full slot, slot no 3 - slot, retBytes = retBytes[:32], retBytes[32:] - slot = slot[24:32] - pLen := binary.BigEndian.Uint64(slot) - if pLen > 4<<10 { - return 0, nil, fmt.Errorf("too long declared payload: %d > %d", pLen, 4<<10) - } - payloadLength := int(pLen) - - if payloadLength > len(retBytes) { - return 0, nil, fmt.Errorf("not enough remaining bytes: %d > %d", payloadLength, retBytes) - } - - return activationEpoch, retBytes[:payloadLength], nil -} - -func (cmp *ContractManifestProvider) callContract(ctx context.Context) ([]byte, error) { - address, err := ethtypes.ParseEthAddress(cmp.address) - if err != nil { - return nil, fmt.Errorf("trying to parse contract address: %s: %w", cmp.address, err) - } - - ethCall := ethtypes.EthCall{ - To: &address, - Data: must.One(ethtypes.DecodeHexString("0x2587660d")), // method ID of activationInformation() - } - - fMessage, err := ethCall.ToFilecoinMessage() - if err != nil { - return nil, fmt.Errorf("converting to filecoin message: %w", err) - } - - msgRes, err := cmp.stateCaller.StateCall(ctx, fMessage, types.EmptyTSK) - if err != nil { - return nil, fmt.Errorf("state call error: %w", err) - } - if msgRes.MsgRct.ExitCode != 0 { - return nil, fmt.Errorf("message returned exit code %v: %v", msgRes.MsgRct.ExitCode, msgRes.Error) - } - - var ethReturn abi.CborBytes - err = ethReturn.UnmarshalCBOR(bytes.NewReader(msgRes.MsgRct.Return)) - if err != nil { - return nil, fmt.Errorf("could not decode return value: %w", err) - } - return []byte(ethReturn), nil -} - -func (cmp *ContractManifestProvider) Stop(context.Context) error { - cmp.cancel() - return cmp.errgrp.Wait() -} - -func (cmp *ContractManifestProvider) ManifestUpdates() <-chan *manifest.Manifest { - return cmp.manifestChanges + return smp, err } diff --git a/chain/lf3/manifest_test.go b/chain/lf3/manifest_test.go deleted file mode 100644 index 223eb087206..00000000000 --- a/chain/lf3/manifest_test.go +++ /dev/null @@ -1,45 +0,0 @@ -package lf3 - -import ( - _ "embed" - "encoding/hex" - "encoding/json" - "strings" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/filecoin-project/go-f3/manifest" -) - -//go:embed testdata/contract_manifest_golden.json -var manifestJSONBytes []byte - -//go:embed testdata/contract_return.hex -var hexReturn string - -func TestContractManifest_ParseEthData(t *testing.T) { - var manifestGolden manifest.Manifest - err := json.Unmarshal(manifestJSONBytes, &manifestGolden) - require.NoError(t, manifestGolden.Validate(), "golden manifest is not valid") - - require.NoErrorf(t, err, "did manifest format change?") - decodedHex, err := hex.DecodeString(strings.Trim(hexReturn, "\n")) - require.NoError(t, err, "failed to decode hex string") - - activationEpoch, compressedManifest, err := parseContractReturn(decodedHex) - require.NoError(t, err, "parseContractReturn failed") - - require.Equal(t, uint64(5000000), activationEpoch, "activationEpoch mismatch") - - manifest, err := decompressManifest(compressedManifest) - require.NoError(t, err, "decompressManifest failed") - - require.NoError(t, manifest.Validate(), "manifest is not valid") - - manifestJSON, err := json.MarshalIndent(manifest, "", " ") - require.NoError(t, err, "failed to marshal manifest") - - require.JSONEq(t, string(manifestJSONBytes), string(manifestJSON), "manifest JSON mismatch") - -} diff --git a/chain/lf3/testdata/contract_return.hex b/chain/lf3/testdata/contract_return.hex deleted file mode 100644 index 576e86a97e5..00000000000 --- a/chain/lf3/testdata/contract_return.hex +++ /dev/null @@ -1 +0,0 @@ -00000000000000000000000000000000000000000000000000000000004c4b40000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000002a38554c172da3010bde72b18ce190f360d90de82a16966424a214d0f9d1e16790d9ac8922bcb4dd24cfebd2bd9c63698810323ebbd5dbd7dbbd2fb45afd75f429e61ff732f0691e1a5dbd1ca28a6c413ea8c2b49d8d8eddf496e38883b991990ccc60cdcfe542993190de93c556c47db5703f773e0039a17a59f1f20b101fd980b648acbbe03e7afa9e08c9ba57a414db0cc85288eda4aa5711e56402dae14e18047d8086c86852a49b83188f74a3d6f803d13e8173a42306cf723bd117c2b1394c622a5ce4aea6dba89edfe3b7dd0e70c8501fa1cb5581530a5ecdfe2982a50b2481794f0f71c04376f8eb5c885e154a32bc22f090b78b5fa608710ad542ea3cc7a5682e10eb8a40ea42ac3e81ee5d6ec5c11d5e12bdc68051183cc58092a8ea7e0fa7724f398d910eb7bc393b475aa49996dafe79f245111ad430744fc289a1ad61e2e517365530d0787f2be70e97c22f0ba692dbcb54cab5cb555ce90713b91a584aafdbf1ca357d76497a3eb6a1d7841bd9c8caaf5d01bfbd5fa9337d9878ebc605cadc7de955bfd2e457c255f1aa3d52ee59fd562748e7b2742d486c79c81c1f92bdb81dc626d4d48054ab3c23f3966e69127a8725374fac0a835eabfa88f88a323e2824b9ee4c95209baa386a240743a4fadebe0f941472f97f9669d6f1aa25542c391d926cca5b53f2a6b6e4eef39d2ed8240d82265ce98e6a9b12dcde318f5ba30d10f2625f5897c8dc8bea80c39a4d556db838f4d3e79c430a8cd70b11d578da0eaaddbdfd7fd8352e0339e3145ddc1c825c968de1bcfa3dff2fc2790d9e7788d8bd6e84dd0d1423b099421496f5cc1938ee681b64f6569dd0224fdebe6dd941197dbc312da16ef4f2cd9ed9c67c82ee1b4aae70cb9f2638589a2aa0fc897f5fc09ace7e1544ef2a7406a66dbf2e0aa6566086c87d1e1b475c558772f3efe030000000000000000000000000000000000000000000000000000000000 \ No newline at end of file diff --git a/cmd/lotus-shed/f3.go b/cmd/lotus-shed/f3.go index 3f4e340712c..7799505b95b 100644 --- a/cmd/lotus-shed/f3.go +++ b/cmd/lotus-shed/f3.go @@ -25,7 +25,6 @@ import ( "github.com/filecoin-project/go-f3/manifest" "github.com/filecoin-project/go-state-types/abi" - "github.com/filecoin-project/lotus/chain/lf3" "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types/ethtypes" lcli "github.com/filecoin-project/lotus/cli" @@ -40,7 +39,6 @@ var f3Cmd = &cli.Command{ Subcommands: []*cli.Command{ f3ClearStateCmd, f3GenExplicitPower, - f3CheckActivation, f3CheckActivationRaw, }, } @@ -74,54 +72,6 @@ func loadF3IDList(path string) ([]gpbft.ActorID, error) { return ids, nil } -var f3CheckActivation = &cli.Command{ - Name: "check-activation", - Usage: "queries f3 parameters contract using chain module", - - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "contract", - Usage: "address contract to query", - }, - &cli.StringFlag{ - Name: "networkname", - Usage: "name of the network to be used", - Value: "filecoin", - }, - }, - Action: func(cctx *cli.Context) error { - config := lf3.Config{ - BaseNetworkName: gpbft.NetworkName(cctx.String("networkname")), - ContractAddress: cctx.String("contract"), - ContractPollInterval: 15 * time.Second, - } - api, closer, err := cliutil.GetFullNodeAPIV1(cctx) - if err != nil { - return fmt.Errorf("getting api: %w", err) - } - defer closer() - ctx := cliutil.ReqContext(cctx) - prov, err := lf3.NewManifestProvider(ctx, &config, nil, nil, nil, api) - if err != nil { - return fmt.Errorf("creating manifest proivder: %w", err) - } - - err = prov.Start(ctx) - if err != nil { - return fmt.Errorf("starting manifest provider: %w", err) - } - for { - select { - case m := <-prov.ManifestUpdates(): - log.Infof("new manifest: %+v\n", m) - case <-ctx.Done(): - _ = prov.Stop(context.Background()) - return nil - } - } - }, -} - var f3CheckActivationRaw = &cli.Command{ Name: "check-activation-raw", Usage: "queries f3 parameters contract using raw logic", diff --git a/itests/f3_test.go b/itests/f3_test.go index 031216e5819..b91670c1f59 100644 --- a/itests/f3_test.go +++ b/itests/f3_test.go @@ -8,9 +8,6 @@ import ( "time" "github.com/ipfs/go-cid" - "github.com/libp2p/go-libp2p" - pubsub "github.com/libp2p/go-libp2p-pubsub" - "github.com/libp2p/go-libp2p/core/host" "github.com/stretchr/testify/require" "golang.org/x/sync/errgroup" @@ -23,8 +20,8 @@ import ( "github.com/filecoin-project/lotus/api" lotus_api "github.com/filecoin-project/lotus/api" + "github.com/filecoin-project/lotus/build/buildconstants" "github.com/filecoin-project/lotus/chain/lf3" - "github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/node" "github.com/filecoin-project/lotus/node/modules" @@ -37,10 +34,8 @@ const ( ) type testEnv struct { - nodes []*kit.TestFullNode - miners []*kit.TestMiner - // observer currently not use but may come handy to test certificate exchanges - ms *manifest.ManifestSender + nodes []*kit.TestFullNode + miners []*kit.TestMiner m *manifest.Manifest t *testing.T testCtx context.Context @@ -66,6 +61,9 @@ func TestF3_Enabled(t *testing.T) { // 2. Not-yet-ready state (F3 enabled but not yet operational) func TestF3_InactiveModes(t *testing.T) { kit.QuietMiningLogs() + oldMani := buildconstants.F3ManifestBytes + defer func() { buildconstants.F3ManifestBytes = oldMani }() + buildconstants.F3ManifestBytes = nil testCases := []struct { mode string @@ -185,71 +183,6 @@ func TestF3_InactiveModes(t *testing.T) { } } -// TestF3_Rebootstrap tests F3 can be rebootsrapped by changing the manifest -// without disrupting miner participation. -func TestF3_Rebootstrap(t *testing.T) { - kit.QuietMiningLogs() - - const blocktime = 100 * time.Millisecond - e := setup(t, blocktime) - e.waitTillAllMinersParticipate(10 * time.Second) - n := e.nodes[0] - - newInstance := uint64(2) - e.waitTillF3Instance(newInstance, 20*time.Second) - e.requireAllMinersParticipate() - - prevCert, err := n.F3GetCertificate(e.testCtx, newInstance) - require.NoError(t, err) - - cpy := *e.m - cpy.BootstrapEpoch = 25 - cpy.NetworkName = BaseNetworkName + "/2" - e.ms.UpdateManifest(&cpy) - - e.waitTillManifestChange(&cpy, 20*time.Second) - e.waitTillAllMinersParticipate(10 * time.Second) - e.waitTillF3Rebootstrap(20 * time.Second) - e.waitTillF3Instance(prevCert.GPBFTInstance+1, 20*time.Second) - e.requireAllMinersParticipate() -} - -// TestF3_PauseAndRebootstrap tests that F3 pause, then resume, then and -// rebootstrap works as expected, and all miners continue to participate in F3 -// regardless. -func TestF3_PauseAndRebootstrap(t *testing.T) { - kit.QuietMiningLogs() - - const blocktime = 100 * time.Millisecond - e := setup(t, blocktime) - e.waitTillAllMinersParticipate(10 * time.Second) - - newInstance := uint64(2) - e.waitTillF3Instance(newInstance, 20*time.Second) - e.requireAllMinersParticipate() - - origManifest := *e.m - pausedManifest := origManifest - pausedManifest.Pause = true - e.ms.UpdateManifest(&pausedManifest) - e.waitTillF3Pauses(30 * time.Second) - e.requireAllMinersParticipate() // Pause should not affect participation leasing. - - e.ms.UpdateManifest(&origManifest) - e.waitTillF3Runs(30 * time.Second) - e.waitTillAllMinersParticipate(10 * time.Second) - - cpy := *e.m - cpy.NetworkName = BaseNetworkName + "/2" - cpy.BootstrapEpoch = 25 - e.ms.UpdateManifest(&cpy) - - e.waitTillManifestChange(&cpy, 20*time.Second) - e.waitTillAllMinersParticipate(10 * time.Second) - e.waitTillF3Rebootstrap(20 * time.Second) - e.requireAllMinersParticipate() -} - // Tests that pause/resume and rebootstrapping F3 works func TestF3_Bootstrap(t *testing.T) { kit.QuietMiningLogs() @@ -260,29 +193,13 @@ func TestF3_Bootstrap(t *testing.T) { ) staticManif := newTestManifest(BaseNetworkName, bootstrapEpoch, blocktime) - dynamicManif := *staticManif - dynamicManif.BootstrapEpoch = 5 - dynamicManif.EC.Finalize = false - dynamicManif.NetworkName = BaseNetworkName + "/1" e := setupWithStaticManifest(t, staticManif, true) - e.ms.UpdateManifest(&dynamicManif) - e.waitTillManifestChange(&dynamicManif, 20*time.Second) - e.waitTillAllMinersParticipate(10 * time.Second) - e.waitTillF3Instance(2, 20*time.Second) - e.waitTillManifestChange(staticManif, 20*time.Second) e.waitTillAllMinersParticipate(10 * time.Second) e.waitTillF3Instance(2, 20*time.Second) - // Try to switch back, we should ignore the manifest update. - e.ms.UpdateManifest(&dynamicManif) - for _, n := range e.nodes { - m, err := n.F3GetManifest(e.testCtx) - require.NoError(e.t, err) - require.True(t, m.Equal(staticManif)) - } e.requireAllMinersParticipate() } @@ -305,36 +222,6 @@ func TestF3_JsonRPCErrorsPassThrough(t *testing.T) { require.Zero(t, ticket) } -func (e *testEnv) waitTillF3Rebootstrap(timeout time.Duration) { - e.waitFor(func(n *kit.TestFullNode) bool { - // the prev epoch yet, check if we already bootstrapped and from - // the right epoch - cert, err := n.F3GetCertificate(e.testCtx, 0) - if err != nil || cert == nil { - return false - } - m, err := n.F3GetManifest(e.testCtx) - require.NoError(e.t, err) - - // Find the first non-null block at or before the target height, that's the bootstrap block. - targetEpoch := m.BootstrapEpoch - m.EC.Finality - ts, err := n.ChainGetTipSetByHeight(e.testCtx, abi.ChainEpoch(targetEpoch), types.EmptyTSK) - if err != nil { - return false - } - - return cert.ECChain.Base().Epoch == int64(ts.Height()) - }, timeout) -} - -func (e *testEnv) waitTillF3Pauses(timeout time.Duration) { - e.waitFor(func(n *kit.TestFullNode) bool { - r, err := n.F3IsRunning(e.testCtx) - require.NoError(e.t, err) - return !r - }, timeout) -} - func (e *testEnv) waitTillF3Runs(timeout time.Duration) { e.waitFor(func(n *kit.TestFullNode) bool { r, err := n.F3IsRunning(e.testCtx) @@ -440,7 +327,7 @@ func (e *testEnv) waitFor(f func(n *kit.TestFullNode) bool, timeout time.Duratio // and the second full-node is an observer that is not directly connected to // a miner. The last return value is the manifest sender for the network. func setup(t *testing.T, blocktime time.Duration, opts ...kit.NodeOpt) *testEnv { - return setupWithStaticManifest(t, newTestManifest(BaseNetworkName+"/1", DefaultBootstrapEpoch, blocktime), false, opts...) + return setupWithStaticManifest(t, newTestManifest(BaseNetworkName, DefaultBootstrapEpoch, blocktime), false, opts...) } func newTestManifest(networkName gpbft.NetworkName, bootstrapEpoch int64, blocktime time.Duration) *manifest.Manifest { @@ -494,16 +381,9 @@ func setupWithStaticManifest(t *testing.T, manif *manifest.Manifest, testBootstr require.NoError(t, errgrp.Wait()) }) - // create manifest host first to get the manifest ID to setup F3 - manifestServerHost, err := libp2p.New(libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1")) - require.NoError(t, err) - cfg := &lf3.Config{ - BaseNetworkName: BaseNetworkName, - StaticManifest: manif, - DynamicManifestProvider: manifestServerHost.ID(), - PrioritizeStaticManifest: testBootstrap, - AllowDynamicFinalize: !testBootstrap, + BaseNetworkName: BaseNetworkName, + StaticManifest: manif, } nodeOpts := []kit.NodeOpt{kit.WithAllSubsystems(), kit.F3Config(cfg)} @@ -539,27 +419,5 @@ func setupWithStaticManifest(t *testing.T, manif *manifest.Manifest, testBootstr e.nodes = []*kit.TestFullNode{&n1, &n2, &n3} e.miners = []*kit.TestMiner{&m1, &m2, &m3, &m4} - // create manifest sender and connect to full-nodes - e.ms = e.newManifestSender(ctx, t, manifestServerHost, blocktime) - for _, n := range e.nodes { - err = n.NetConnect(ctx, e.ms.PeerInfo()) - require.NoError(t, err) - } - errgrp.Go(func() error { - defer func() { - require.NoError(t, manifestServerHost.Close()) - }() - return e.ms.Run(ctx) - }) - return e } - -func (e *testEnv) newManifestSender(ctx context.Context, t *testing.T, h host.Host, senderTimeout time.Duration) *manifest.ManifestSender { - ps, err := pubsub.NewGossipSub(ctx, h) - require.NoError(t, err) - - ms, err := manifest.NewManifestSender(ctx, h, ps, e.m, senderTimeout) - require.NoError(t, err) - return ms -} diff --git a/itests/kit/node_opts.go b/itests/kit/node_opts.go index 40dc1e809c6..d2b0d984c79 100644 --- a/itests/kit/node_opts.go +++ b/itests/kit/node_opts.go @@ -265,8 +265,6 @@ func F3Backend(backend lf3.F3Backend) NodeOpt { func F3Disabled() NodeOpt { return ConstructorOpts( node.Unset(new(*lf3.Config)), - node.Unset(new(*lf3.ContractManifestProvider)), - node.Unset(new(lf3.StateCaller)), node.Unset(new(manifest.ManifestProvider)), node.Unset(new(lf3.F3Backend)), ) diff --git a/node/builder_chain.go b/node/builder_chain.go index d6f57c12788..8174bf63051 100644 --- a/node/builder_chain.go +++ b/node/builder_chain.go @@ -188,8 +188,6 @@ var ChainNode = Options( If(build.IsF3Enabled(), Override(new(*lf3.Config), lf3.NewConfig), - Override(new(*lf3.ContractManifestProvider), lf3.NewContractManifestProvider), - Override(new(lf3.StateCaller), From(new(full.StateModule))), Override(new(manifest.ManifestProvider), lf3.NewManifestProvider), Override(new(lf3.F3Backend), lf3.New), ), diff --git a/node/modules/lp2p/pubsub.go b/node/modules/lp2p/pubsub.go index b5ff4a90616..f1757531a7d 100644 --- a/node/modules/lp2p/pubsub.go +++ b/node/modules/lp2p/pubsub.go @@ -3,7 +3,6 @@ package lp2p import ( "context" "encoding/json" - "fmt" "net" "time" @@ -368,21 +367,11 @@ func GossipSub(in GossipIn) (service *pubsub.PubSub, err error) { allowTopics = append(allowTopics, drandTopics...) if in.F3Config != nil { - if in.F3Config.StaticManifest != nil || in.F3Config.ContractAddress != "" { + if in.F3Config.StaticManifest != nil { gpbftTopic := manifest.PubSubTopicFromNetworkName(in.F3Config.BaseNetworkName) chainexTopic := manifest.ChainExchangeTopicFromNetworkName(in.F3Config.BaseNetworkName) allowTopics = append(allowTopics, gpbftTopic, chainexTopic) } - if in.F3Config.DynamicManifestProvider != "" { - gpbftTopicPrefix := manifest.PubSubTopicFromNetworkName(in.F3Config.BaseNetworkName) - chainexTopicPrefix := manifest.ChainExchangeTopicFromNetworkName(in.F3Config.BaseNetworkName) - allowTopics = append(allowTopics, manifest.ManifestPubSubTopicName) - for i := range lf3.MaxDynamicManifestChangesAllowed { - gpbftTopic := fmt.Sprintf("%s/%d", gpbftTopicPrefix, i) - chainexTopic := fmt.Sprintf("%s/%d", chainexTopicPrefix, i) - allowTopics = append(allowTopics, gpbftTopic, chainexTopic) - } - } } options = append(options,