diff --git a/CHANGELOG.md b/CHANGELOG.md index 22583bd6e86..13f75670c84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - `lotus send` now supports `--csv` option for sending multiple transactions. ([filecoin-project/lotus#12892](https://github.com/filecoin-project/lotus/pull/12892)) - chore: upgrade to the latest go-f3 and allow F3 chain exchange topics ([filecoin-project/lotus#12893](https://github.com/filecoin-project/lotus/pull/12893) - chore: upgrade to a minimum Golang version of `1.23.6` ([filecoin-project/lotus#12910](https://github.com/filecoin-project/lotus/pull/12910) +- feat: add a `LOTUS_DISABLE_F3_ACTIVATION` enviroment variable allowing disabling F3 activation for a specific contract address or epoch ([filecoin-project/lotus#12920](https://github.com/filecoin-project/lotus/pull/12920)). The `LOTUS_DISABLE_F3` env-var has been renamed to `LOTUS_DISABLE_F3_SUBSYSTEM` to distinguish it from the other F3-related environment variables: `LOTUS_DISABLE_F3_PASSIVE_TESTING` and `LOTUS_DISABLE_F3_ACTIVATION`. - feat: add `GenesisTimestamp` field to `StateGetNetworkParams` response ([filecoin-project/lotus#12925](https://github.com/filecoin-project/lotus/pull/12925)) # UNRELEASED v.1.32.0 diff --git a/build/params_shared_funcs.go b/build/params_shared_funcs.go index 8fe0ee07e36..2c4615033b4 100644 --- a/build/params_shared_funcs.go +++ b/build/params_shared_funcs.go @@ -2,6 +2,7 @@ package build import ( "os" + "strconv" "strings" "github.com/libp2p/go-libp2p/core/protocol" @@ -25,7 +26,7 @@ var SetAddressNetwork = buildconstants.SetAddressNetwork var MustParseAddress = buildconstants.MustParseAddress func IsF3Enabled() bool { - const F3DisableEnvKey = "LOTUS_DISABLE_F3" + const F3DisableEnvKey = "LOTUS_DISABLE_F3_SUBSYSTEM" if !buildconstants.F3Enabled { // Build constant takes precedence over environment variable. return false @@ -65,3 +66,63 @@ func IsF3PassiveTestingEnabled() bool { return false } } + +func parseF3DisableActivationEnv() (contractAddrs []string, epochs []int64) { + const F3DisableActivation = "LOTUS_DISABLE_F3_ACTIVATION" + + v, envVarSet := os.LookupEnv(F3DisableActivation) + if !envVarSet || strings.TrimSpace(v) == "" { + // Environment variable is not set or empty, activation is not disabled + return + } + + // Parse the variable which can be in format "contract:addrs" or "epoch:epochnumber" or both + parts := strings.Split(v, ",") + for _, part := range parts { + kv := strings.SplitN(part, ":", 2) + if len(kv) != 2 { + continue + } + + key := strings.TrimSpace(strings.ToLower(kv[0])) + value := strings.TrimSpace(kv[1]) + + switch key { + case "contract": + // If contract address matches, disable activation + contractAddrs = append(contractAddrs, value) + case "epoch": + parsedEpoch, err := strconv.ParseInt(value, 10, 64) + if err == nil { + epochs = append(epochs, parsedEpoch) + } else { + log.Warnf("error parsing %s env variable, cannot parse epoch", F3DisableActivation) + } + } + } + return contractAddrs, epochs +} + +// IsF3EpochActivationDisabled checks if F3 activation is disabled for the given +// epoch number based on environment variable configuration. +func IsF3EpochActivationDisabled(epoch int64) bool { + _, epochs := parseF3DisableActivationEnv() + for _, e := range epochs { + if e == epoch { + return true + } + } + return false +} + +// IsF3ContractActivationDisabled checks if F3 activation is disabled for the given contract address +// based on environment variable configuration. +func IsF3ContractActivationDisabled(contract string) bool { + contracts, _ := parseF3DisableActivationEnv() + for _, c := range contracts { + if c == contract { + return true + } + } + return false +} diff --git a/chain/lf3/manifest.go b/chain/lf3/manifest.go index 06154604249..ac1f2b8bb41 100644 --- a/chain/lf3/manifest.go +++ b/chain/lf3/manifest.go @@ -51,13 +51,29 @@ 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 - if config.StaticManifest != nil { - log.Infof("using static maniest as primary") + + // 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 != "" { - log.Infow("using contract maniest as primary", "address", config.ContractAddress) + } 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) }