diff --git a/cmd/nitro/nitro.go b/cmd/nitro/nitro.go index 8bbceecab7..c7f9d57b08 100644 --- a/cmd/nitro/nitro.go +++ b/cmd/nitro/nitro.go @@ -53,12 +53,14 @@ import ( _ "github.com/offchainlabs/nitro/nodeInterface" "github.com/offchainlabs/nitro/solgen/go/bridgegen" "github.com/offchainlabs/nitro/solgen/go/precompilesgen" + "github.com/offchainlabs/nitro/solgen/go/rollupgen" "github.com/offchainlabs/nitro/staker" "github.com/offchainlabs/nitro/staker/validatorwallet" "github.com/offchainlabs/nitro/util/colors" "github.com/offchainlabs/nitro/util/headerreader" "github.com/offchainlabs/nitro/util/rpcclient" "github.com/offchainlabs/nitro/util/signature" + "github.com/offchainlabs/nitro/validator/server_common" "github.com/offchainlabs/nitro/validator/valnode" ) @@ -420,6 +422,52 @@ func mainImpl() int { } }() + // Check that node is compatible with on-chain WASM module root on startup and before any ArbOS upgrades take effect to prevent divergences + if nodeConfig.Node.ParentChainReader.Enable && nodeConfig.Validation.Wasm.EnableWasmrootsCheck { + // Fetch current on-chain WASM module root + rollupUserLogic, err := rollupgen.NewRollupUserLogic(rollupAddrs.Rollup, l1Client) + if err != nil { + log.Error("failed to create rollupUserLogic", "err", err) + return 1 + } + moduleRoot, err := rollupUserLogic.WasmModuleRoot(&bind.CallOpts{Context: ctx}) + if err != nil { + log.Error("failed to get on-chain WASM module root", "err", err) + return 1 + } + if (moduleRoot == common.Hash{}) { + log.Error("on-chain WASM module root is zero") + return 1 + } + // Check if the on-chain WASM module root belongs to the set of allowed module roots + allowedWasmModuleRoots := nodeConfig.Validation.Wasm.AllowedWasmModuleRoots + if len(allowedWasmModuleRoots) > 0 { + moduleRootMatched := false + for _, root := range allowedWasmModuleRoots { + if common.HexToHash(root) == moduleRoot { + moduleRootMatched = true + break + } + } + if !moduleRootMatched { + log.Error("on-chain WASM module root did not match with any of the allowed WASM module roots") + return 1 + } + } else { + // If no allowed module roots were provided in config, check if we have a validator machine directory for the on-chain WASM module root + locator, err := server_common.NewMachineLocator(nodeConfig.Validation.Wasm.RootPath) + if err != nil { + log.Error("failed to create machine locator", "err", err) + return 1 + } + path := locator.GetMachinePath(moduleRoot) + if _, err := os.Stat(path); err != nil { + log.Error("unable to find validator machine directory for the on-chain WASM module root", "err", err) + return 1 + } + } + } + chainDb, l2BlockChain, err := openInitializeChainDb(ctx, stack, nodeConfig, new(big.Int).SetUint64(nodeConfig.Chain.ID), gethexec.DefaultCacheConfigFor(stack, &nodeConfig.Execution.Caching), l1Client, rollupAddrs) if l2BlockChain != nil { deferFuncs = append(deferFuncs, func() { l2BlockChain.Stop() }) diff --git a/validator/valnode/valnode.go b/validator/valnode/valnode.go index ea9980e547..ca954094ff 100644 --- a/validator/valnode/valnode.go +++ b/validator/valnode/valnode.go @@ -16,15 +16,21 @@ import ( ) type WasmConfig struct { - RootPath string `koanf:"root-path"` + RootPath string `koanf:"root-path"` + EnableWasmrootsCheck bool `koanf:"enable-wasmroots-check"` + AllowedWasmModuleRoots []string `koanf:"allowed-wasm-module-roots"` } func WasmConfigAddOptions(prefix string, f *flag.FlagSet) { f.String(prefix+".root-path", DefaultWasmConfig.RootPath, "path to machine folders, each containing wasm files (machine.wavm.br, replay.wasm)") + f.Bool(prefix+".enable-wasmroots-check", DefaultWasmConfig.EnableWasmrootsCheck, "enable check for compatibility of on-chain WASM module root with node") + f.StringSlice(prefix+".allowed-wasm-module-roots", DefaultWasmConfig.AllowedWasmModuleRoots, "list of WASM module roots to check if the on-chain WASM module root belongs to on node startup") } var DefaultWasmConfig = WasmConfig{ - RootPath: "", + RootPath: "", + EnableWasmrootsCheck: true, + AllowedWasmModuleRoots: []string{}, } type Config struct {