diff --git a/devnet/query-server.yaml b/devnet/query-server.yaml index b82461a21..1bf0b21a5 100644 --- a/devnet/query-server.yaml +++ b/devnet/query-server.yaml @@ -52,6 +52,8 @@ spec: - http://eth-devnet:8545 - --ethContract - "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" + - --network + - /wormhole/dev # Hardcoded devnet bootstrap (generated from deterministic key in guardiand) - --bootstrap - /dns4/guardian-0.guardian/udp/8996/quic/p2p/12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw diff --git a/devnet/spy.yaml b/devnet/spy.yaml index 17c75173c..94cae5fe0 100644 --- a/devnet/spy.yaml +++ b/devnet/spy.yaml @@ -43,6 +43,8 @@ spec: - /tmp/node.key - --spyRPC - "[::]:7072" + - --network + - /wormhole/dev # Hardcoded devnet bootstrap (generated from deterministic key in guardiand) - --bootstrap - /dns4/guardian-0.guardian/udp/8999/quic/p2p/12D3KooWL3XJ9EMCyZvmmGXL2LMiVBtrVa2BuESsJiXkSj7333Jw diff --git a/docs/operations.md b/docs/operations.md index 6473ffdc3..3e8832385 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -53,6 +53,7 @@ If you use the same RPC node for Wormhole v1, you also need the following additi `getProgramAccount` queries: + ``` [... see above for other required parameters ...] @@ -60,6 +61,7 @@ If you use the same RPC node for Wormhole v1, you also need the following additi --account-index-include-key WormT3McKhFJ2RkiGpdw9GKvNCrB2aB54gb2uV9MfQC # for mainnet --account-index-include-key 5gQf5AUhAgWYgUCt9ouShm9H7dzzXUsLdssYwe5krKhg # for testnet ``` + Alternatively, if you want to run a general-purpose RPC node with indexes for all programs instead of only Wormhole, @@ -72,10 +74,12 @@ leave out the filtering: On mainnet, we strongly recommend blacklisting KIN and the token program to speed up catchup: + ``` --account-index-exclude-key kinXdEcpDQeHPEuQnqmUgtYykqKGVFq6CeVX5iAHJq6 # Mainnet only --account-index-exclude-key TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA # Mainnet only ``` + Note that these indexes require extra disk space and may slow down catchup. The first startup after @@ -261,27 +265,12 @@ may include support for remote signing. ## Bootstrap Peers -The following bootstrap peers are available in each environment. +The list of supported bootstrap peers is defined in `node/pkg/p2p/network_consts.go`. That file also provides golang functions +for obtaining the network parameters (network ID and bootstrap peers) based on the environment (mainnet or testnet). -### Mainnet - - -```bash ---bootstrap "/dns4/wormhole-v2-mainnet-bootstrap.xlabs.xyz/udp/8999/quic/p2p/12D3KooWNQ9tVrcb64tw6bNs2CaNrUGPM7yRrKvBBheQ5yCyPHKC,/dns4/wormhole.mcf.rocks/udp/8999/quic/p2p/12D3KooWDZVv7BhZ8yFLkarNdaSWaB43D6UbQwExJ8nnGAEmfHcU,/dns4/wormhole-v2-mainnet-bootstrap.staking.fund/udp/8999/quic/p2p/12D3KooWG8obDX9DNi1KUwZNu9xkGwfKqTp2GFwuuHpWZ3nQruS1" - ---ccqP2pBootstrap "/dns4/wormhole-v2-mainnet-bootstrap.xlabs.xyz/udp/8996/quic/p2p/12D3KooWNQ9tVrcb64tw6bNs2CaNrUGPM7yRrKvBBheQ5yCyPHKC,/dns4/wormhole.mcf.rocks/udp/8996/quic/p2p/12D3KooWDZVv7BhZ8yFLkarNdaSWaB43D6UbQwExJ8nnGAEmfHcU,/dns4/wormhole-v2-mainnet-bootstrap.staking.fund/udp/8996/quic/p2p/12D3KooWG8obDX9DNi1KUwZNu9xkGwfKqTp2GFwuuHpWZ3nQruS1" -``` - - -### Testnet - - -```bash ---bootstrap "/dns4/t-guardian-01.nodes.stable.io/udp/8999/quic/p2p/12D3KooWCW3LGUtkCVkHZmVSZHzL3C4WRKWfqAiJPz1NR7dT9Bxh,/dns4/t-guardian-02.nodes.stable.io/udp/8999/quic/p2p/12D3KooWJXA6goBCiWM8ucjzc4jVUBSqL9Rri6UpjHbkMPErz5zK,/dns4/p2p-guardian-testnet-1.solana.p2p.org/udp/8999/quic/p2p/12D3KooWE4dmZwxhfjCKHLUqSaww96Cf7kmq1ZuKmzPz3MrJgZxp" - ---ccqP2pBootstrap "/dns4/t-guardian-01.nodes.stable.io/udp/8996/quic/p2p/12D3KooWCW3LGUtkCVkHZmVSZHzL3C4WRKWfqAiJPz1NR7dT9Bxh,/dns4/t-guardian-02.nodes.stable.io/udp/8996/quic/p2p/12D3KooWJXA6goBCiWM8ucjzc4jVUBSqL9Rri6UpjHbkMPErz5zK,/dns4/p2p-guardian-testnet-1.solana.p2p.org/udp/8996/quic/p2p/12D3KooWE4dmZwxhfjCKHLUqSaww96Cf7kmq1ZuKmzPz3MrJgZxp" -``` - +The common Wormhole applications (guardiand, spy and query proxy server) use those functions, so it is not necessary to specify +the actual bootstrap parameters in their configs. Developers of any new applications are strongly urged to do the same, and not +proliferate lists of bootstrap peers which might change over time. ## Run the Guardian Spy @@ -290,27 +279,31 @@ The spy connects to the wormhole guardian peer to peer network and listens for n Start the spy against the testnet wormhole guardian: + ```bash docker run \ --platform=linux/amd64 \ -p 7073:7073 \ --entrypoint /guardiand \ ghcr.io/wormhole-foundation/guardiand:latest \ -spy --nodeKey /node.key --spyRPC "[::]:7073" --network /wormhole/testnet/2/1 --bootstrap "/dns4/t-guardian-01.nodes.stable.io/udp/8999/quic/p2p/12D3KooWCW3LGUtkCVkHZmVSZHzL3C4WRKWfqAiJPz1NR7dT9Bxh,/dns4/t-guardian-02.nodes.stable.io/udp/8999/quic/p2p/12D3KooWJXA6goBCiWM8ucjzc4jVUBSqL9Rri6UpjHbkMPErz5zK,/dns4/p2p-guardian-testnet-1.solana.p2p.org/udp/8999/quic/p2p/12D3KooWE4dmZwxhfjCKHLUqSaww96Cf7kmq1ZuKmzPz3MrJgZxp" + spy --nodeKey /node.key --spyRPC "[::]:7073" --env testnet ``` + To run the spy against mainnet: + ```bash docker run \ --platform=linux/amd64 \ -p 7073:7073 \ --entrypoint /guardiand \ ghcr.io/wormhole-foundation/guardiand:latest \ -spy --nodeKey /node.key --spyRPC "[::]:7073" --network /wormhole/mainnet/2 --bootstrap /dns4/wormhole-v2-mainnet-bootstrap.xlabs.xyz/udp/8999/quic/p2p/12D3KooWNQ9tVrcb64tw6bNs2CaNrUGPM7yRrKvBBheQ5yCyPHKC,/dns4/wormhole.mcf.rocks/udp/8999/quic/p2p/12D3KooWDZVv7BhZ8yFLkarNdaSWaB43D6UbQwExJ8nnGAEmfHcU,/dns4/wormhole-v2-mainnet-bootstrap.staking.fund/udp/8999/quic/p2p/12D3KooWG8obDX9DNi1KUwZNu9xkGwfKqTp2GFwuuHpWZ3nQruS1 + spy --nodeKey /node.key --spyRPC "[::]:7073" --env mainnet ``` + ## Guardian Configurations @@ -326,12 +319,14 @@ Configuration files, environment variables and flags are all supported. **Example**: + ```yaml ethRPC: "ws://eth-devnet:8545" ethContract: "0xC89Ce4735882C9F0f0FE26686c53074E09B0D550" solanaRPC: "http://solana-devnet:8899" solanaContract: "Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o" ``` + ### Environment Variables diff --git a/node/cmd/ccq/query_server.go b/node/cmd/ccq/query_server.go index 4148eee48..bd7518d86 100644 --- a/node/cmd/ccq/query_server.go +++ b/node/cmd/ccq/query_server.go @@ -14,6 +14,7 @@ import ( "time" "github.com/certusone/wormhole/node/pkg/common" + "github.com/certusone/wormhole/node/pkg/p2p" "github.com/certusone/wormhole/node/pkg/telemetry" promremotew "github.com/certusone/wormhole/node/pkg/telemetry/prom_remote_write" "github.com/certusone/wormhole/node/pkg/version" @@ -50,10 +51,10 @@ var ( const DEV_NETWORK_ID = "/wormhole/dev" func init() { - envStr = QueryServerCmd.Flags().String("env", "", "environment (dev, test, prod)") - p2pNetworkID = QueryServerCmd.Flags().String("network", DEV_NETWORK_ID, "P2P network identifier") + envStr = QueryServerCmd.Flags().String("env", "", "environment (devnet, testnet, mainnet)") + p2pNetworkID = QueryServerCmd.Flags().String("network", "", "P2P network identifier (optional, overrides default for environment)") p2pPort = QueryServerCmd.Flags().Uint("port", 8995, "P2P UDP listener port") - p2pBootstrap = QueryServerCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (comma-separated)") + p2pBootstrap = QueryServerCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (optional for testnet or mainnet, overrides default, required for devnet)") nodeKeyPath = QueryServerCmd.Flags().String("nodeKey", "", "Path to node key (will be generated if it doesn't exist)") signerKeyPath = QueryServerCmd.Flags().String("signerKey", "", "Path to key used to sign unsigned queries") listenAddr = QueryServerCmd.Flags().String("listenAddr", "[::]:6069", "Listen address for query server (disabled if blank)") @@ -82,7 +83,6 @@ var QueryServerCmd = &cobra.Command{ func runQueryServer(cmd *cobra.Command, args []string) { common.SetRestrictiveUmask() - networkID := *p2pNetworkID + "/ccq" // Setup logging lvl, err := ipfslog.LevelFromString(*logLevel) @@ -94,6 +94,35 @@ func runQueryServer(cmd *cobra.Command, args []string) { logger := ipfslog.Logger("query-server").Desugar() ipfslog.SetAllLoggers(lvl) + env, err := common.ParseEnvironment(*envStr) + if err != nil || (env != common.UnsafeDevNet && env != common.TestNet && env != common.MainNet) { + if *envStr == "" { + logger.Fatal("Please specify --env") + } + logger.Fatal("Invalid value for --env, should be devnet, testnet or mainnet", zap.String("val", *envStr)) + } + + if *p2pNetworkID == "" { + *p2pNetworkID = p2p.GetNetworkId(env) + } else if env != common.UnsafeDevNet { + logger.Warn("overriding default p2p network ID", zap.String("p2pNetworkID", *p2pNetworkID)) + } + + if *p2pNetworkID == DEV_NETWORK_ID && env != common.UnsafeDevNet { + logger.Fatal("May not set --network to dev unless --env is also dev", zap.String("network", *p2pNetworkID), zap.String("env", *envStr)) + } + + networkID := *p2pNetworkID + "/ccq" + + if *p2pBootstrap == "" { + *p2pBootstrap, err = p2p.GetCcqBootstrapPeers(env) + if err != nil { + logger.Fatal("failed to determine the bootstrap peers from the environment", zap.String("env", string(env)), zap.Error(err)) + } + } else if env != common.UnsafeDevNet { + logger.Warn("overriding default p2p bootstrap peers", zap.String("p2pBootstrap", *p2pBootstrap)) + } + if *telemetryLokiURL != "" { logger.Info("Using Loki telemetry logger") if *telemetryNodeName == "" { @@ -114,18 +143,6 @@ func runQueryServer(cmd *cobra.Command, args []string) { logger = tm.WrapLogger(logger) // Wrap logger with telemetry logger } - env, err := common.ParseEnvironment(*envStr) - if err != nil || (env != common.UnsafeDevNet && env != common.TestNet && env != common.MainNet) { - if *envStr == "" { - logger.Fatal("Please specify --env") - } - logger.Fatal("Invalid value for --env, must be dev, test or prod", zap.String("val", *envStr)) - } - - if *p2pNetworkID == DEV_NETWORK_ID && env != common.UnsafeDevNet { - logger.Fatal("May not set --network to dev unless --env is also dev", zap.String("network", *p2pNetworkID), zap.String("env", *envStr)) - } - // Verify flags if *nodeKeyPath == "" { logger.Fatal("Please specify --nodeKey") diff --git a/node/cmd/guardiand/node.go b/node/cmd/guardiand/node.go index ec0a3aa3d..9cb8ae65d 100644 --- a/node/cmd/guardiand/node.go +++ b/node/cmd/guardiand/node.go @@ -233,9 +233,9 @@ var ( ) func init() { - p2pNetworkID = NodeCmd.Flags().String("network", "/wormhole/dev", "P2P network identifier") + p2pNetworkID = NodeCmd.Flags().String("network", "", "P2P network identifier (optional, overrides default for environment)") p2pPort = NodeCmd.Flags().Uint("port", p2p.DefaultPort, "P2P UDP listener port") - p2pBootstrap = NodeCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (comma-separated)") + p2pBootstrap = NodeCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (optional for mainnet or testnet, overrides default, required for unsafeDevMode)") statusAddr = NodeCmd.Flags().String("statusAddr", "[::]:6060", "Listen address for status server (disabled if blank)") @@ -407,7 +407,7 @@ func init() { ccqEnabled = NodeCmd.Flags().Bool("ccqEnabled", false, "Enable cross chain query support") ccqAllowedRequesters = NodeCmd.Flags().String("ccqAllowedRequesters", "", "Comma separated list of signers allowed to submit cross chain queries") ccqP2pPort = NodeCmd.Flags().Uint("ccqP2pPort", 8996, "CCQ P2P UDP listener port") - ccqP2pBootstrap = NodeCmd.Flags().String("ccqP2pBootstrap", "", "CCQ P2P bootstrap peers (comma-separated)") + ccqP2pBootstrap = NodeCmd.Flags().String("ccqP2pBootstrap", "", "CCQ P2P bootstrap peers (optional for mainnet or testnet, overrides default, required for unsafeDevMode)") ccqAllowedPeers = NodeCmd.Flags().String("ccqAllowedPeers", "", "CCQ allowed P2P peers (comma-separated)") ccqBackfillCache = NodeCmd.Flags().Bool("ccqBackfillCache", true, "Should EVM chains backfill CCQ timestamp cache on startup") @@ -469,6 +469,16 @@ func runNode(cmd *cobra.Command, args []string) { os.Exit(1) } + // Determine execution mode + var env common.Environment + if *unsafeDevMode { + env = common.UnsafeDevNet + } else if *testnetMode { + env = common.TestNet + } else { + env = common.MainNet + } + if *unsafeDevMode { fmt.Print(devwarning) } @@ -514,6 +524,10 @@ func runNode(cmd *cobra.Command, args []string) { logger = logger.Named(*nodeName) } + if *unsafeDevMode && *testnetMode { + logger.Fatal("Cannot be in unsafeDevMode and testnetMode at the same time.") + } + // Override the default go-log config, which uses a magic environment variable. ipfslog.SetAllLoggers(lvl) @@ -525,8 +539,15 @@ func runNode(cmd *cobra.Command, args []string) { } // Use the first guardian node as bootstrap - *p2pBootstrap = fmt.Sprintf("/dns4/guardian-0.guardian/udp/%d/quic/p2p/%s", *p2pPort, g0key.String()) - *ccqP2pBootstrap = fmt.Sprintf("/dns4/guardian-0.guardian/udp/%d/quic/p2p/%s", *ccqP2pPort, g0key.String()) + if *p2pBootstrap == "" { + *p2pBootstrap = fmt.Sprintf("/dns4/guardian-0.guardian/udp/%d/quic/p2p/%s", *p2pPort, g0key.String()) + } + if *ccqP2pBootstrap == "" { + *ccqP2pBootstrap = fmt.Sprintf("/dns4/guardian-0.guardian/udp/%d/quic/p2p/%s", *ccqP2pPort, g0key.String()) + } + if *p2pNetworkID == "" { + *p2pNetworkID = p2p.GetNetworkId(env) + } // Deterministic ganache ETH devnet address. *ethContract = unsafeDevModeEvmContractAddress(*ethContract) @@ -552,6 +573,30 @@ func runNode(cmd *cobra.Command, args []string) { *baseSepoliaContract = unsafeDevModeEvmContractAddress(*baseSepoliaContract) *optimismSepoliaContract = unsafeDevModeEvmContractAddress(*optimismSepoliaContract) *polygonSepoliaContract = unsafeDevModeEvmContractAddress(*polygonSepoliaContract) + } else { // Mainnet or Testnet. + // If the network parameters are not specified, use the defaults. Log a warning if they are specified since we want to discourage this. + // Note that we don't want to prevent it, to allow for network upgrade testing. + if *p2pNetworkID == "" { + *p2pNetworkID = p2p.GetNetworkId(env) + } else { + logger.Warn("overriding default p2p network ID", zap.String("p2pNetworkID", *p2pNetworkID)) + } + if *p2pBootstrap == "" { + *p2pBootstrap, err = p2p.GetBootstrapPeers(env) + if err != nil { + logger.Fatal("failed to determine p2p bootstrap peers", zap.String("env", string(env)), zap.Error(err)) + } + } else { + logger.Warn("overriding default p2p bootstrap peers", zap.String("p2pBootstrap", *p2pBootstrap)) + } + if *ccqP2pBootstrap == "" { + *ccqP2pBootstrap, err = p2p.GetCcqBootstrapPeers(env) + if err != nil { + logger.Fatal("failed to determine ccq bootstrap peers", zap.String("env", string(env)), zap.Error(err)) + } + } else { + logger.Warn("overriding default ccq bootstrap peers", zap.String("ccqP2pBootstrap", *ccqP2pBootstrap)) + } } // Verify flags @@ -831,21 +876,6 @@ func runNode(cmd *cobra.Command, args []string) { } } - // Determine execution mode - // TODO: refactor usage of these variables elsewhere. *unsafeDevMode and *testnetMode should not be accessed directly. - var env common.Environment - if *unsafeDevMode { - env = common.UnsafeDevNet - } else if *testnetMode { - env = common.TestNet - } else { - env = common.MainNet - } - - if *unsafeDevMode && *testnetMode { - logger.Fatal("Cannot be in unsafeDevMode and testnetMode at the same time.") - } - // Complain about Infura on mainnet. // // As it turns out, Infura has a bug where it would sometimes incorrectly round diff --git a/node/cmd/spy/spy.go b/node/cmd/spy/spy.go index 49f4c09cb..d5724a65a 100644 --- a/node/cmd/spy/spy.go +++ b/node/cmd/spy/spy.go @@ -33,6 +33,8 @@ var ( ) var ( + envStr *string + p2pNetworkID *string p2pPort *uint p2pBootstrap *string @@ -49,9 +51,10 @@ var ( ) func init() { - p2pNetworkID = SpyCmd.Flags().String("network", "/wormhole/dev", "P2P network identifier") + envStr = SpyCmd.Flags().String("env", "", `environment (may be "testnet" or "mainnet", required unless "--bootstrap" is specified)`) + p2pNetworkID = SpyCmd.Flags().String("network", "", "P2P network identifier (optional for testnet or mainnet, overrides default, required for devnet)") p2pPort = SpyCmd.Flags().Uint("port", 8999, "P2P UDP listener port") - p2pBootstrap = SpyCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (comma-separated)") + p2pBootstrap = SpyCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (optional for testnet or mainnet, overrides default, required for devnet)") statusAddr = SpyCmd.Flags().String("statusAddr", "[::]:6060", "Listen address for status server (disabled if blank)") @@ -237,6 +240,30 @@ func runSpy(cmd *cobra.Command, args []string) { ipfslog.SetAllLoggers(lvl) + if *envStr != "" { + // If they specify --env then use the defaults for the network parameters and don't allow them to override them. + if *p2pNetworkID != "" || *p2pBootstrap != "" { + logger.Fatal(`If "--env" is specified, "--network" and "--bootstrap" may not be specified`) + } + env, err := common.ParseEnvironment(*envStr) + if err != nil || (env != common.MainNet && env != common.TestNet) { + logger.Fatal(`Invalid value for "--env", should be "mainnet" or "testnet"`) + } + *p2pNetworkID = p2p.GetNetworkId(env) + *p2pBootstrap, err = p2p.GetBootstrapPeers(env) + if err != nil { + logger.Fatal("failed to determine p2p bootstrap peers", zap.String("env", string(env)), zap.Error(err)) + } + } else { + // If they don't specify --env, then --network and --bootstrap are required. + if *p2pNetworkID == "" { + logger.Fatal(`If "--env" is not specified, "--network" must be specified`) + } + if *p2pBootstrap == "" { + logger.Fatal(`If "--env" is not specified, "--bootstrap" must be specified`) + } + } + // Status server if *statusAddr != "" { router := mux.NewRouter() diff --git a/node/hack/query/ccqlistener/ccqlistener.go b/node/hack/query/ccqlistener/ccqlistener.go index 88fe89dba..ae59a9ffe 100644 --- a/node/hack/query/ccqlistener/ccqlistener.go +++ b/node/hack/query/ccqlistener/ccqlistener.go @@ -1,10 +1,10 @@ // This tool can be used to verify that a guardian is properly receiving CCQ queries and publishing responses. // This tool can be used to passively listen for query responses from any guardian: -// go run ccqlistener.go --listenOnly +// go run ccqlistener.go --env mainnet --listenOnly // // Or it can be used to passively listen for query responses from a particular guardian: -// go run ccqlistener.go --listenOnly --targetPeerId +// go run ccqlistener.go --env mainnet --listenOnly --targetPeerId // // This should work both in mainnet and testnet because there are routine monitoring queries running every few minutes. // Note that you may need to wait 15 minutes or more to see something. Look for message saying "query response received". @@ -32,7 +32,7 @@ // // To run the tool as a docker image, you can do something like this: // - wormhole$ docker build --target build -f node/hack/query/ccqlistener/Dockerfile -t ccqlistener . -// - wormhole$ docker run -v /ccqlistener/cfg:/app/cfg ccqlistener /ccqlistener --configDir /app/cfg +// - wormhole$ docker run -v /ccqlistener/cfg:/app/cfg ccqlistener /ccqlistener --env mainnet --configDir /app/cfg // Where /ccqlistener is a directory containing these files: // - ccqlistener.nodeKey // - ccqlistener.signerKey @@ -68,11 +68,10 @@ import ( ) var ( - p2pNetworkID = flag.String("network", "/wormhole/mainnet/2", "P2P network identifier") - p2pPort = flag.Int("port", 8998, "P2P UDP listener port") - p2pBootstrap = flag.String("bootstrap", - "/dns4/wormhole-mainnet-v2-bootstrap.certus.one/udp/8996/quic/p2p/12D3KooWQp644DK27fd3d4Km3jr7gHiuJJ5ZGmy8hH4py7fP4FP7,/dns4/wormhole-v2-mainnet-bootstrap.xlabs.xyz/udp/8996/quic/p2p/12D3KooWNQ9tVrcb64tw6bNs2CaNrUGPM7yRrKvBBheQ5yCyPHKC,/dns4/wormhole.mcf.rocks/udp/8996/quic/p2p/12D3KooWDZVv7BhZ8yFLkarNdaSWaB43D6UbQwExJ8nnGAEmfHcU,/dns4/wormhole-v2-mainnet-bootstrap.staking.fund/udp/8996/quic/p2p/12D3KooWG8obDX9DNi1KUwZNu9xkGwfKqTp2GFwuuHpWZ3nQruS1", - "P2P bootstrap peers (comma-separated)") + envStr = flag.String("env", "", `environment (may be "testnet" or "mainnet", required unless "--bootstrap" is specified)`) + p2pNetworkID = flag.String("network", "", "P2P network identifier (optional, overrides default, required for devnet)") + p2pPort = flag.Int("port", 8998, "P2P UDP listener port") + p2pBootstrap = flag.String("bootstrap", "", "P2P bootstrap peers (optional, overrides default)") nodeKeyPath = flag.String("nodeKey", "ccqlistener.nodeKey", "Path to node key (will be generated if it doesn't exist)") signerKeyPath = flag.String("signerKey", "ccqlistener.signerKey", "Path to key used to sign unsigned queries") configDir = flag.String("configDir", ".", "Directory where nodeKey and signerKey are loaded from (default is .)") @@ -92,6 +91,30 @@ func main() { defer cancel() logger, _ := zap.NewDevelopment() + if *envStr != "" { + // If they specify --env then use the defaults for the network parameters and don't allow them to override them. + if *p2pNetworkID != "" || *p2pBootstrap != "" { + logger.Fatal(`If "--env" is specified, "--network" and "--bootstrap" may not be specified`) + } + env, err := common.ParseEnvironment(*envStr) + if err != nil || (env != common.MainNet && env != common.TestNet) { + logger.Fatal(`Invalid value for "--env", should be "mainnet" or "testnet"`) + } + *p2pNetworkID = p2p.GetNetworkId(env) + *p2pBootstrap, err = p2p.GetCcqBootstrapPeers(env) + if err != nil { + logger.Fatal("failed to determine p2p bootstrap peers", zap.String("env", string(env)), zap.Error(err)) + } + } else { + // If they don't specify --env, then --network and --bootstrap are required. + if *p2pNetworkID == "" { + logger.Fatal(`If "--env" is not specified, "--network" must be specified`) + } + if *p2pBootstrap == "" { + logger.Fatal(`If "--env" is not specified, "--bootstrap" must be specified`) + } + } + nodeKey := *configDir + "/" + *nodeKeyPath var err error diff --git a/node/pkg/p2p/network_consts.go b/node/pkg/p2p/network_consts.go new file mode 100644 index 000000000..63696b00d --- /dev/null +++ b/node/pkg/p2p/network_consts.go @@ -0,0 +1,52 @@ +package p2p + +import ( + "fmt" + + "github.com/certusone/wormhole/node/pkg/common" +) + +// This is the definitive source for the default network parameters. Please reference these (or use the methods below), but avoid copying them! +const MainnetNetworkId = "/wormhole/mainnet/2" +const MainnetBootstrapPeers = "/dns4/wormhole-v2-mainnet-bootstrap.xlabs.xyz/udp/8999/quic/p2p/12D3KooWNQ9tVrcb64tw6bNs2CaNrUGPM7yRrKvBBheQ5yCyPHKC,/dns4/wormhole.mcf.rocks/udp/8999/quic/p2p/12D3KooWDZVv7BhZ8yFLkarNdaSWaB43D6UbQwExJ8nnGAEmfHcU,/dns4/wormhole-v2-mainnet-bootstrap.staking.fund/udp/8999/quic/p2p/12D3KooWG8obDX9DNi1KUwZNu9xkGwfKqTp2GFwuuHpWZ3nQruS1" +const MainnetCcqBootstrapPeers = "/dns4/wormhole-v2-mainnet-bootstrap.xlabs.xyz/udp/8996/quic/p2p/12D3KooWNQ9tVrcb64tw6bNs2CaNrUGPM7yRrKvBBheQ5yCyPHKC,/dns4/wormhole.mcf.rocks/udp/8996/quic/p2p/12D3KooWDZVv7BhZ8yFLkarNdaSWaB43D6UbQwExJ8nnGAEmfHcU,/dns4/wormhole-v2-mainnet-bootstrap.staking.fund/udp/8996/quic/p2p/12D3KooWG8obDX9DNi1KUwZNu9xkGwfKqTp2GFwuuHpWZ3nQruS1" + +const TestnetNetworkId = "/wormhole/testnet/2/1" +const TestnetBootstrapPeers = "/dns4/t-guardian-01.nodes.stable.io/udp/8999/quic/p2p/12D3KooWCW3LGUtkCVkHZmVSZHzL3C4WRKWfqAiJPz1NR7dT9Bxh,/dns4/t-guardian-02.nodes.stable.io/udp/8999/quic/p2p/12D3KooWJXA6goBCiWM8ucjzc4jVUBSqL9Rri6UpjHbkMPErz5zK,/dns4/p2p-guardian-testnet-1.solana.p2p.org/udp/8999/quic/p2p/12D3KooWE4dmZwxhfjCKHLUqSaww96Cf7kmq1ZuKmzPz3MrJgZxp" +const TestnetCcqBootstrapPeers = "/dns4/t-guardian-01.nodes.stable.io/udp/8996/quic/p2p/12D3KooWCW3LGUtkCVkHZmVSZHzL3C4WRKWfqAiJPz1NR7dT9Bxh,/dns4/t-guardian-02.nodes.stable.io/udp/8996/quic/p2p/12D3KooWJXA6goBCiWM8ucjzc4jVUBSqL9Rri6UpjHbkMPErz5zK,/dns4/p2p-guardian-testnet-1.solana.p2p.org/udp/8996/quic/p2p/12D3KooWE4dmZwxhfjCKHLUqSaww96Cf7kmq1ZuKmzPz3MrJgZxp" + +// The Devnet bootstrap peers are derived from the guardian key so we can't include them here. +const DevnetNetworkId = "/wormhole/dev" + +// GetNetworkId returns the default network ID. +func GetNetworkId(env common.Environment) string { + if env == common.MainNet { + return MainnetNetworkId + } + if env == common.TestNet { + return TestnetNetworkId + } + return DevnetNetworkId +} + +// GetBootstrapPeers returns the default p2p bootstrap peers for mainnet and testnet. For any other environment, it returns an error. +func GetBootstrapPeers(env common.Environment) (string, error) { + if env == common.MainNet { + return MainnetBootstrapPeers, nil + } + if env == common.TestNet { + return TestnetBootstrapPeers, nil + } + return "", fmt.Errorf("unsupported environment") +} + +// GetCcqBootstrapPeers returns the default ccq bootstrap peers for mainnet and testnet. For any other environment, it returns an error. +func GetCcqBootstrapPeers(env common.Environment) (string, error) { + if env == common.MainNet { + return MainnetCcqBootstrapPeers, nil + } + if env == common.TestNet { + return TestnetCcqBootstrapPeers, nil + } + return "", fmt.Errorf("unsupported environment") +} diff --git a/node/pkg/p2p/network_consts_test.go b/node/pkg/p2p/network_consts_test.go new file mode 100644 index 000000000..374c24359 --- /dev/null +++ b/node/pkg/p2p/network_consts_test.go @@ -0,0 +1,82 @@ +package p2p + +import ( + "testing" + + "github.com/certusone/wormhole/node/pkg/common" + "go.uber.org/zap" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidateMainnetNetworkId(t *testing.T) { + networkId := GetNetworkId(common.MainNet) + require.Equal(t, MainnetNetworkId, networkId) +} + +func TestValidateTestnetNetworkId(t *testing.T) { + networkId := GetNetworkId(common.TestNet) + require.Equal(t, TestnetNetworkId, networkId) +} + +func TestValidateDevnetNetworkId(t *testing.T) { + networkId := GetNetworkId(common.UnsafeDevNet) + require.Equal(t, DevnetNetworkId, networkId) +} + +func TestValidateMainnetBootstrapPeers(t *testing.T) { + bootstrapPeers, err := GetBootstrapPeers(common.MainNet) + require.NoError(t, err) + require.NotEqual(t, "", bootstrapPeers) + + // Make sure we can parse the result. + logger := zap.NewNop() + bootStrappers, _ := BootstrapAddrs(logger, bootstrapPeers, "somePeerID") + assert.Equal(t, 3, len(bootStrappers)) +} + +func TestValidateMainnetCcqBootstrapPeers(t *testing.T) { + bootstrapPeers, err := GetCcqBootstrapPeers(common.MainNet) + require.NoError(t, err) + require.NotEqual(t, "", bootstrapPeers) + + // Make sure we can parse the result. + logger := zap.NewNop() + bootStrappers, _ := BootstrapAddrs(logger, bootstrapPeers, "somePeerID") + assert.Equal(t, 3, len(bootStrappers)) +} + +func TestValidateTestnetBootstrapPeers(t *testing.T) { + bootstrapPeers, err := GetBootstrapPeers(common.TestNet) + require.NoError(t, err) + require.NotEqual(t, "", bootstrapPeers) + + // Make sure we can parse the result. + logger := zap.NewNop() + bootStrappers, _ := BootstrapAddrs(logger, bootstrapPeers, "somePeerID") + assert.Equal(t, 3, len(bootStrappers)) +} + +func TestValidateTestnetCcqBootstrapPeers(t *testing.T) { + bootstrapPeers, err := GetCcqBootstrapPeers(common.TestNet) + require.NoError(t, err) + require.NotEqual(t, "", bootstrapPeers) + + // Make sure we can parse the result. + logger := zap.NewNop() + bootStrappers, _ := BootstrapAddrs(logger, bootstrapPeers, "somePeerID") + assert.Equal(t, 3, len(bootStrappers)) +} + +func TestGetBootstrapPeersFailsForUnsupportedEnvironment(t *testing.T) { + bootstrapPeers, err := GetBootstrapPeers(common.UnsafeDevNet) + require.ErrorContains(t, err, "unsupported environment") + require.Equal(t, "", bootstrapPeers) +} + +func TestGetCcqBootstrapPeersFailsForUnsupportedEnvironment(t *testing.T) { + bootstrapPeers, err := GetCcqBootstrapPeers(common.UnsafeDevNet) + require.ErrorContains(t, err, "unsupported environment") + require.Equal(t, "", bootstrapPeers) +}