Skip to content

Commit

Permalink
automatically set rollup parameters when possible
Browse files Browse the repository at this point in the history
* Restore deployment.json support until `test-node` is updated to output config files
* use chain id reported by `--l1.url` to determine chain parameters
* add support for providing multiple json config files
  • Loading branch information
joshuacolvin0 committed Apr 15, 2022
1 parent 75312e8 commit 4766324
Show file tree
Hide file tree
Showing 9 changed files with 346 additions and 132 deletions.
39 changes: 26 additions & 13 deletions arbnode/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ type RollupAddresses struct {
}

type RollupAddressesConfig struct {
Bridge string `koanf:"bridge"`
Inbox string `koanf:"inbox"`
SequencerInbox string `koanf:"sequencer-inbox"`
Rollup string `koanf:"rollup"`
ValidatorUtils string `koanf:"validator-utils"`
ValidatorWalletCreator string `koanf:"validator-wallet-creator"`
DeployedAt uint64 `koanf:"deployed-at"`
Bridge string `koanf:"bridge" json:"bridge"`
Inbox string `koanf:"inbox" json:"inbox"`
SequencerInbox string `koanf:"sequencer-inbox" json:"sequencer-inbox"`
Rollup string `koanf:"rollup" json:"rollup"`
ValidatorUtils string `koanf:"validator-utils" json:"validator-utils"`
ValidatorWalletCreator string `koanf:"validator-wallet-creator" json:"validator-wallet-creator"`
DeployedAt uint64 `koanf:"deployed-at" json:"deployed-at"`
}

var RollupAddressesConfigDefault = RollupAddressesConfig{}
Expand Down Expand Up @@ -96,15 +96,28 @@ func (c *RollupAddressesConfig) ParseAddresses() (RollupAddresses, error) {
&a.ValidatorUtils,
&a.ValidatorWalletCreator,
}
names := []string{
"Bridge",
"Inbox",
"SequencerInbox",
"Rollup",
"ValidatorUtils",
"ValidatorWalletCreator",
}
if len(strs) != len(addrs) {
return RollupAddresses{}, fmt.Errorf("internal error: attempting to parse %v strings into %v addresses", len(strs), len(addrs))
}
complete := true
for i, s := range strs {
if !common.IsHexAddress(s) {
return RollupAddresses{}, fmt.Errorf("invalid address: %v", s)
log.Error("invalid address", "name", names[i], "value", s)
complete = false
}
*addrs[i] = common.HexToAddress(s)
}
if !complete {
return RollupAddresses{}, fmt.Errorf("invalid addresses")
}
return a, nil
}

Expand Down Expand Up @@ -714,23 +727,23 @@ func (l arbNodeLifecycle) Stop() error {
}

func CreateNode(stack *node.Node, chainDb ethdb.Database, config *Config, l2BlockChain *core.BlockChain, l1client arbutil.L1Interface, deployInfo *RollupAddresses, txOpts *bind.TransactOpts) (newNode *Node, err error) {
node, err := createNodeImpl(stack, chainDb, config, l2BlockChain, l1client, deployInfo, txOpts)
currentNode, err := createNodeImpl(stack, chainDb, config, l2BlockChain, l1client, deployInfo, txOpts)
if err != nil {
return nil, err
}
var apis []rpc.API
if node.BlockValidator != nil {
if currentNode.BlockValidator != nil {
apis = append(apis, rpc.API{
Namespace: "arb",
Version: "1.0",
Service: &BlockValidatorAPI{val: node.BlockValidator, blockchain: l2BlockChain},
Service: &BlockValidatorAPI{val: currentNode.BlockValidator, blockchain: l2BlockChain},
Public: false,
})
}
stack.RegisterAPIs(apis)

stack.RegisterLifecycle(arbNodeLifecycle{node})
return node, nil
stack.RegisterLifecycle(arbNodeLifecycle{currentNode})
return currentNode, nil
}

func (n *Node) Start(ctx context.Context) error {
Expand Down
107 changes: 87 additions & 20 deletions cmd/conf/config.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package conf

import (
"errors"
"os"
"path"
"path/filepath"

"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/params"
"github.com/offchainlabs/nitro/arbnode"
"github.com/pkg/errors"
flag "github.com/spf13/pflag"
)

Expand All @@ -15,23 +17,23 @@ const PASSWORD_NOT_SET = "PASSWORD_NOT_SET"
type ConfConfig struct {
Dump bool `koanf:"dump"`
EnvPrefix string `koanf:"env-prefix"`
File string `koanf:"file"`
File []string `koanf:"file"`
S3 S3Config `koanf:"s3"`
String string `koanf:"string"`
}

func ConfConfigAddOptions(prefix string, f *flag.FlagSet) {
f.Bool(prefix+".dump", ConfConfigDefault.Dump, "print out currently active configuration file")
f.String(prefix+".env-prefix", ConfConfigDefault.EnvPrefix, "environment variables with given prefix will be loaded as configuration values")
f.String(prefix+".file", ConfConfigDefault.File, "name of configuration file")
f.StringSlice(prefix+".file", ConfConfigDefault.File, "name of configuration file")
S3ConfigAddOptions(prefix+".s3", f)
f.String(prefix+".string", ConfConfigDefault.String, "configuration as JSON string")
}

var ConfConfigDefault = ConfConfig{
Dump: false,
EnvPrefix: "",
File: "",
File: []string{""},
S3: DefaultS3Config,
String: "",
}
Expand Down Expand Up @@ -62,41 +64,53 @@ var DefaultS3Config = S3Config{

type L1Config struct {
ChainID uint64 `koanf:"chain-id"`
Deployment string `koanf:"deployment"`
Rollup arbnode.RollupAddressesConfig `koanf:"rollup"`
URL string `koanf:"url"`
ConnectionAttempts int `koanf:"connection-attempts"`
Wallet WalletConfig `koanf:"wallet"`
}

var L1ConfigDefault = L1Config{
ChainID: 1337,
Rollup: arbnode.RollupAddressesConfig{},
ChainID: 0,
Deployment: "",
Rollup: arbnode.RollupAddressesConfigDefault,
URL: "",
ConnectionAttempts: 15,
Wallet: WalletConfigDefault,
}

func L1ConfigAddOptions(prefix string, f *flag.FlagSet) {
f.Uint64(prefix+".chain-id", L1ConfigDefault.ChainID, "if set other than 0, will be used to validate database and L1 connection")
f.String(prefix+".deployment", L1ConfigDefault.Deployment, "json file including the existing deployment information")
f.String(prefix+".url", L1ConfigDefault.URL, "layer 1 ethereum node RPC URL")
arbnode.RollupAddressesConfigAddOptions(prefix+".rollup", f)
f.Int(prefix+".connection-attempts", L1ConfigDefault.ConnectionAttempts, "layer 1 RPC connection attempts (spaced out at least 1 second per attempt, 0 to retry infinitely)")
WalletConfigAddOptions(prefix+".wallet", f)
WalletConfigAddOptions(prefix+".wallet", f, "wallet")
}

func (c *L1Config) ResolveDirectoryNames(chain string) {
c.Wallet.ResolveDirectoryNames(chain)
}

type L2Config struct {
ChainID uint64 `koanf:"chain-id"`
Wallet WalletConfig `koanf:"wallet"`
ChainID uint64 `koanf:"chain-id"`
DevWallet WalletConfig `koanf:"dev-wallet"`
}

var L2ConfigDefault = L2Config{
ChainID: params.ArbitrumTestnetChainConfig().ChainID.Uint64(),
Wallet: WalletConfigDefault,
ChainID: 0,
DevWallet: WalletConfigDefault,
}

func L2ConfigAddOptions(prefix string, f *flag.FlagSet) {
f.Uint64(prefix+".chain-id", L2ConfigDefault.ChainID, "L2 chain ID (determines Arbitrum network)")
WalletConfigAddOptions(prefix+".wallet", f)
// Dev wallet does not exist unless specified
WalletConfigAddOptions(prefix+".dev-wallet", f, "")
}

func (c *L2Config) ResolveDirectoryNames(chain string) {
c.DevWallet.ResolveDirectoryNames(chain)
}

type WalletConfig struct {
Expand All @@ -106,7 +120,7 @@ type WalletConfig struct {
Account string `koanf:"account"`
}

func (w WalletConfig) Password() *string {
func (w *WalletConfig) Password() *string {
if w.PasswordImpl == PASSWORD_NOT_SET {
return nil
}
Expand All @@ -120,29 +134,75 @@ var WalletConfigDefault = WalletConfig{
Account: "",
}

func WalletConfigAddOptions(prefix string, f *flag.FlagSet) {
f.String(prefix+".pathname", WalletConfigDefault.Pathname, "pathname for wallet")
func WalletConfigAddOptions(prefix string, f *flag.FlagSet, defaultPathname string) {
f.String(prefix+".pathname", defaultPathname, "pathname for wallet")
f.String(prefix+".password", WalletConfigDefault.PasswordImpl, "wallet passphrase")
f.String(prefix+".private-key", WalletConfigDefault.PasswordImpl, "private key for wallet")
f.String(prefix+".account", WalletConfigDefault.Account, "account to use (default is first account in keystore)")
}

func (w *WalletConfig) ResolveDirectoryNames(chain string) {
// Make wallet directories relative to chain directory if specified and not already absolute
if len(w.Pathname) != 0 && !filepath.IsAbs(w.Pathname) {
w.Pathname = path.Join(chain, w.Pathname)
}
}

type PersistentConfig struct {
GlobalConfig string `koanf:"global-config"`
Chain string `koanf:"chain"`
Data string `koanf:"data"`
ChainData string `koanf:"data"`
}

var PersistentConfigDefault = PersistentConfig{
GlobalConfig: "",
GlobalConfig: ".arbitrum",
Chain: "",
Data: "",
ChainData: "chaindata",
}

func PersistentConfigAddOptions(prefix string, f *flag.FlagSet) {
f.String(prefix+".global-config", PersistentConfigDefault.GlobalConfig, "directory to store global config")
f.String(prefix+".chain", PersistentConfigDefault.Chain, "directory to store chain state")
f.String(prefix+".data", PersistentConfigDefault.Data, "directory for data storage requirements")
f.String(prefix+".data", PersistentConfigDefault.ChainData, "directory for data storage requirements")
}

func (c *PersistentConfig) ResolveDirectoryNames() error {
homeDir, err := os.UserHomeDir()
if err != nil {
return errors.Wrap(err, "Unable to read users home directory")
}

// Make persistent storage directory relative to home directory if not already absolute
if !filepath.IsAbs(c.GlobalConfig) {
c.GlobalConfig = path.Join(homeDir, c.GlobalConfig)
}
err = os.MkdirAll(c.GlobalConfig, os.ModePerm)
if err != nil {
return errors.Wrap(err, "Unable to create global configuration directory")
}

// Make chain directory relative to persistent storage directory if not already absolute
if !filepath.IsAbs(c.Chain) {
c.Chain = path.Join(c.GlobalConfig, c.Chain)
}
err = os.MkdirAll(c.Chain, os.ModePerm)
if err != nil {
return errors.Wrap(err, "Unable to create chain directory")
}
if DatabaseInDirectory(c.Chain) {
return errors.Errorf("Database in --persistent.chain (%s) directory, try specifying parent directory", c.Chain)
}

// Make data directory relative to chain directory if not already absolute
if !filepath.IsAbs(c.ChainData) {
c.ChainData = path.Join(c.Chain, c.ChainData)
}
err = os.MkdirAll(c.ChainData, os.ModePerm)
if err != nil {
return errors.Wrap(err, "Unable to create chain data directory")
}

return nil
}

type HTTPConfig struct {
Expand Down Expand Up @@ -222,3 +282,10 @@ func MetricsServerAddOptions(prefix string, f *flag.FlagSet) {
f.String(prefix+".addr", MetricsServerConfigDefault.Addr, "metrics server address")
f.Int(prefix+".port", MetricsServerConfigDefault.Port, "metrics server port")
}

func DatabaseInDirectory(path string) bool {
// Consider database present if file `CURRENT` in directory
_, err := os.Stat(path + "/CURRENT")

return err == nil
}
12 changes: 6 additions & 6 deletions cmd/node/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ import (
)

func TestSeqConfig(t *testing.T) {
args := strings.Split("--persistent.data /data --dev-init --l1.url ws://geth:8546 --l1.wallet.pathname /l1keystore --l1.wallet.password passphrase --l1.rollup.rollup 0x59dd5F1dBD0abDF7Cb31F8F69e7549Fc6B49aa34 --http.addr 0.0.0.0 --ws.addr 0.0.0.0 --node.sequencer.enable --node.feed.output.enable --node.feed.output.port 9642", " ")
_, _, _, err := ParseNode(context.Background(), args)
args := strings.Split("--persistent.data /data --dev-init --l1.url ws://geth:8546 --l1.wallet.pathname /l1keystore --l1.wallet.password passphrase --l1.deployment /deploydata/deployment.json --http.addr 0.0.0.0 --ws.addr 0.0.0.0 --node.sequencer.enable --node.feed.output.enable --node.feed.output.port 9642", " ")
_, _, _, _, _, err := ParseNode(context.Background(), args)
testhelpers.RequireImpl(t, err)
}

func TestUnsafeStakerConfig(t *testing.T) {
args := strings.Split("--persistent.data /data --dev-init --l1.url ws://geth:8546 --l1.wallet.pathname /l1keystore --l1.wallet.password passphrase --l1.rollup.rollup 0x59dd5F1dBD0abDF7Cb31F8F69e7549Fc6B49aa34 --http.addr 0.0.0.0 --ws.addr 0.0.0.0 --node.validator.enable --node.validator.strategy MakeNodes --node.validator.staker-interval 10s --node.forwarding-target null --node.validator.dangerous.without-block-validator", " ")
_, _, _, err := ParseNode(context.Background(), args)
args := strings.Split("--persistent.data /data --dev-init --l1.url ws://geth:8546 --l1.wallet.pathname /l1keystore --l1.wallet.password passphrase --l1.deployment /deploydata/deployment.json --http.addr 0.0.0.0 --ws.addr 0.0.0.0 --node.validator.enable --node.validator.strategy MakeNodes --node.validator.staker-interval 10s --node.forwarding-target null --node.validator.dangerous.without-block-validator", " ")
_, _, _, _, _, err := ParseNode(context.Background(), args)
testhelpers.RequireImpl(t, err)
}

func TestValidatorConfig(t *testing.T) {
args := strings.Split("--persistent.data /data --dev-init --l1.url ws://geth:8546 --l1.wallet.pathname /l1keystore --l1.wallet.password passphrase --l1.rollup.rollup 0x59dd5F1dBD0abDF7Cb31F8F69e7549Fc6B49aa34 --http.addr 0.0.0.0 --ws.addr 0.0.0.0 --node.validator.enable --node.validator.strategy MakeNodes --node.validator.staker-interval 10s --node.forwarding-target null", " ")
_, _, _, err := ParseNode(context.Background(), args)
args := strings.Split("--persistent.data /data --dev-init --l1.url ws://geth:8546 --l1.wallet.pathname /l1keystore --l1.wallet.password passphrase --l1.deployment /deploydata/deployment.json --http.addr 0.0.0.0 --ws.addr 0.0.0.0 --node.validator.enable --node.validator.strategy MakeNodes --node.validator.staker-interval 10s --node.forwarding-target null", " ")
_, _, _, _, _, err := ParseNode(context.Background(), args)
testhelpers.RequireImpl(t, err)
}
Loading

0 comments on commit 4766324

Please sign in to comment.