2020-10-28 14:41:38 -07:00
package guardiand
2020-08-02 14:12:58 -07:00
import (
"context"
2022-01-09 12:56:59 -08:00
"encoding/base64"
2020-08-02 14:12:58 -07:00
"fmt"
2022-05-23 02:25:24 -07:00
"log"
"net/http"
_ "net/http/pprof" // #nosec G108 we are using a custom router (`router := mux.NewRouter()`) and thus not automatically expose pprof.
"os"
2022-11-28 05:48:27 -08:00
"os/signal"
2022-05-23 02:25:24 -07:00
"path"
"strings"
2022-11-28 05:48:27 -08:00
"syscall"
2022-05-23 02:25:24 -07:00
2022-10-24 09:01:32 -07:00
"github.com/certusone/wormhole/node/pkg/watchers/wormchain"
2022-09-28 06:27:13 -07:00
"github.com/certusone/wormhole/node/pkg/watchers/cosmwasm"
"github.com/certusone/wormhole/node/pkg/watchers/algorand"
2022-10-13 18:22:54 -07:00
"github.com/certusone/wormhole/node/pkg/watchers/aptos"
2022-09-28 06:27:13 -07:00
"github.com/certusone/wormhole/node/pkg/watchers/evm"
"github.com/certusone/wormhole/node/pkg/watchers/near"
"github.com/certusone/wormhole/node/pkg/watchers/solana"
2022-11-18 06:14:22 -08:00
"github.com/certusone/wormhole/node/pkg/watchers/sui"
2023-01-16 04:33:01 -08:00
"github.com/certusone/wormhole/node/pkg/wormconn"
2022-09-28 04:15:57 -07:00
2022-08-24 02:55:33 -07:00
"github.com/benbjohnson/clock"
2021-12-02 16:02:32 -08:00
"github.com/certusone/wormhole/node/pkg/db"
2021-10-05 11:13:07 -07:00
"github.com/certusone/wormhole/node/pkg/notify/discord"
2022-01-09 12:56:59 -08:00
"github.com/certusone/wormhole/node/pkg/telemetry"
"github.com/certusone/wormhole/node/pkg/version"
2021-12-02 16:02:32 -08:00
"github.com/gagliardetto/solana-go/rpc"
2022-01-06 08:58:56 -08:00
"go.uber.org/zap/zapcore"
2021-08-06 21:28:46 -07:00
2021-07-28 06:56:19 -07:00
solana_types "github.com/gagliardetto/solana-go"
2021-02-04 02:26:01 -08:00
"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp"
2023-01-17 05:30:50 -08:00
"github.com/certusone/wormhole/node/pkg/accountant"
2021-08-26 01:35:09 -07:00
"github.com/certusone/wormhole/node/pkg/common"
"github.com/certusone/wormhole/node/pkg/devnet"
2022-07-19 11:08:06 -07:00
"github.com/certusone/wormhole/node/pkg/governor"
2021-08-26 01:35:09 -07:00
"github.com/certusone/wormhole/node/pkg/p2p"
"github.com/certusone/wormhole/node/pkg/processor"
gossipv1 "github.com/certusone/wormhole/node/pkg/proto/gossip/v1"
"github.com/certusone/wormhole/node/pkg/readiness"
"github.com/certusone/wormhole/node/pkg/reporter"
"github.com/certusone/wormhole/node/pkg/supervisor"
2023-01-16 04:33:01 -08:00
cosmoscrypto "github.com/cosmos/cosmos-sdk/crypto/types"
2021-12-02 16:02:32 -08:00
eth_common "github.com/ethereum/go-ethereum/common"
ethcrypto "github.com/ethereum/go-ethereum/crypto"
2022-09-05 20:36:58 -07:00
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
2021-12-02 16:02:32 -08:00
"github.com/spf13/cobra"
2022-08-18 01:52:36 -07:00
"github.com/wormhole-foundation/wormhole/sdk/vaa"
2021-12-02 16:02:32 -08:00
"go.uber.org/zap"
2021-08-26 01:35:09 -07:00
2020-08-02 14:12:58 -07:00
ipfslog "github.com/ipfs/go-log/v2"
)
var (
2020-10-28 14:41:38 -07:00
p2pNetworkID * string
p2pPort * uint
p2pBootstrap * string
2020-08-16 08:05:58 -07:00
2020-10-28 14:41:38 -07:00
nodeKeyPath * string
2020-08-16 08:05:58 -07:00
2022-11-18 07:36:22 -08:00
adminSocketPath * string
publicGRPCSocketPath * string
2020-11-19 03:53:19 -08:00
2021-07-21 11:56:25 -07:00
dataDir * string
2021-01-24 08:20:04 -08:00
statusAddr * string
2021-08-30 07:19:00 -07:00
guardianKeyPath * string
solanaContract * string
2020-11-19 03:53:17 -08:00
2021-07-09 05:56:52 -07:00
ethRPC * string
ethContract * string
2020-08-16 08:05:58 -07:00
2021-07-28 06:32:49 -07:00
bscRPC * string
bscContract * string
2022-11-11 06:12:16 -08:00
polygonRPC * string
polygonContract * string
polygonRootChainRpc * string
polygonRootChainContractAddress * string
2021-10-18 08:53:13 -07:00
2022-03-15 07:41:10 -07:00
auroraRPC * string
auroraContract * string
2022-03-03 13:40:32 -08:00
fantomRPC * string
fantomContract * string
2022-02-02 09:50:10 -08:00
2021-12-09 13:40:55 -08:00
avalancheRPC * string
avalancheContract * string
2021-12-20 11:40:58 -08:00
oasisRPC * string
oasisContract * string
2022-03-03 13:40:32 -08:00
karuraRPC * string
karuraContract * string
acalaRPC * string
acalaContract * string
2022-04-04 15:11:03 -07:00
klaytnRPC * string
klaytnContract * string
2022-04-28 09:20:38 -07:00
celoRPC * string
celoContract * string
2022-05-10 08:23:07 -07:00
moonbeamRPC * string
moonbeamContract * string
2022-06-14 07:22:49 -07:00
neonRPC * string
neonContract * string
2020-11-16 04:28:07 -08:00
terraWS * string
terraLCD * string
terraContract * string
2022-06-16 12:17:43 -07:00
terra2WS * string
terra2LCD * string
terra2Contract * string
2022-07-06 07:19:57 -07:00
injectiveWS * string
injectiveLCD * string
injectiveContract * string
2022-10-05 06:05:31 -07:00
xplaWS * string
xplaLCD * string
xplaContract * string
2022-04-29 12:56:08 -07:00
algorandIndexerRPC * string
algorandIndexerToken * string
2022-05-10 04:41:59 -07:00
algorandAlgodRPC * string
algorandAlgodToken * string
2022-05-10 08:23:07 -07:00
algorandAppID * uint64
2021-12-22 08:22:04 -08:00
2022-08-05 10:49:16 -07:00
nearRPC * string
nearContract * string
2023-01-16 04:33:01 -08:00
wormchainWS * string
wormchainLCD * string
wormchainURL * string
wormchainKeyPath * string
2023-01-17 05:30:50 -08:00
wormchainKeyPassPhrase * string
2023-01-16 04:33:01 -08:00
2023-01-17 05:30:50 -08:00
accountantContract * string
accountantWS * string
accountantCheckEnabled * bool
2022-09-02 01:36:24 -07:00
2022-10-13 18:22:54 -07:00
aptosRPC * string
aptosAccount * string
aptosHandle * string
2022-11-18 06:14:22 -08:00
suiRPC * string
suiWS * string
suiAccount * string
suiPackage * string
2022-09-26 06:56:39 -07:00
solanaRPC * string
2021-01-21 02:31:32 -08:00
2022-07-28 10:30:00 -07:00
pythnetContract * string
pythnetRPC * string
2023-01-18 08:24:55 -08:00
pythnetWS * string
2022-07-28 10:30:00 -07:00
2022-09-28 07:39:58 -07:00
arbitrumRPC * string
arbitrumContract * string
2022-12-02 05:38:45 -08:00
optimismRPC * string
optimismContract * string
optimismCtcRpc * string
optimismCtcContractAddress * string
2022-11-10 05:50:08 -08:00
2020-10-28 14:41:38 -07:00
logLevel * string
2020-08-17 09:20:15 -07:00
2020-10-28 14:41:38 -07:00
unsafeDevMode * bool
2021-11-22 07:49:41 -08:00
testnetMode * bool
2020-10-28 14:41:38 -07:00
devNumGuardians * uint
nodeName * string
2021-05-12 22:57:08 -07:00
2021-08-20 16:52:07 -07:00
publicRPC * string
publicWeb * string
2021-07-07 02:39:48 -07:00
2021-08-20 15:44:37 -07:00
tlsHostname * string
tlsProdEnv * bool
2021-08-05 08:01:36 -07:00
disableHeartbeatVerify * bool
2022-01-09 12:56:59 -08:00
disableTelemetry * bool
telemetryKey * string
2021-08-05 08:01:36 -07:00
2021-10-05 11:13:07 -07:00
discordToken * string
discordChannel * string
2021-07-07 02:39:48 -07:00
bigTablePersistenceEnabled * bool
bigTableGCPProject * string
bigTableInstanceName * string
bigTableTableName * string
2021-11-04 02:00:52 -07:00
bigTableTopicName * string
2021-07-07 02:39:48 -07:00
bigTableKeyPath * string
2022-07-19 11:08:06 -07:00
chainGovernorEnabled * bool
2020-08-02 14:12:58 -07:00
)
2020-10-28 14:41:38 -07:00
func init ( ) {
2021-08-30 07:19:00 -07:00
p2pNetworkID = NodeCmd . Flags ( ) . String ( "network" , "/wormhole/dev" , "P2P network identifier" )
p2pPort = NodeCmd . Flags ( ) . Uint ( "port" , 8999 , "P2P UDP listener port" )
p2pBootstrap = NodeCmd . Flags ( ) . String ( "bootstrap" , "" , "P2P bootstrap peers (comma-separated)" )
2020-10-28 14:41:38 -07:00
2021-08-30 07:19:00 -07:00
statusAddr = NodeCmd . Flags ( ) . String ( "statusAddr" , "[::]:6060" , "Listen address for status server (disabled if blank)" )
2021-01-24 08:20:04 -08:00
2021-08-30 07:19:00 -07:00
nodeKeyPath = NodeCmd . Flags ( ) . String ( "nodeKey" , "" , "Path to node key (will be generated if it doesn't exist)" )
2020-10-28 14:41:38 -07:00
2021-08-30 07:19:00 -07:00
adminSocketPath = NodeCmd . Flags ( ) . String ( "adminSocket" , "" , "Admin gRPC service UNIX domain socket path" )
2022-11-18 07:36:22 -08:00
publicGRPCSocketPath = NodeCmd . Flags ( ) . String ( "publicGRPCSocket" , "" , "Public gRPC service UNIX domain socket path" )
2020-11-19 03:53:19 -08:00
2021-08-30 07:19:00 -07:00
dataDir = NodeCmd . Flags ( ) . String ( "dataDir" , "" , "Data directory" )
2021-07-21 11:56:25 -07:00
2021-08-30 07:19:00 -07:00
guardianKeyPath = NodeCmd . Flags ( ) . String ( "guardianKey" , "" , "Path to guardian key (required)" )
solanaContract = NodeCmd . Flags ( ) . String ( "solanaContract" , "" , "Address of the Solana program (required)" )
2020-11-19 03:53:17 -08:00
2021-08-30 07:19:00 -07:00
ethRPC = NodeCmd . Flags ( ) . String ( "ethRPC" , "" , "Ethereum RPC URL" )
ethContract = NodeCmd . Flags ( ) . String ( "ethContract" , "" , "Ethereum contract address" )
2020-10-28 14:41:38 -07:00
2021-08-30 07:19:00 -07:00
bscRPC = NodeCmd . Flags ( ) . String ( "bscRPC" , "" , "Binance Smart Chain RPC URL" )
bscContract = NodeCmd . Flags ( ) . String ( "bscContract" , "" , "Binance Smart Chain contract address" )
2021-07-28 06:32:49 -07:00
2021-10-18 08:53:13 -07:00
polygonRPC = NodeCmd . Flags ( ) . String ( "polygonRPC" , "" , "Polygon RPC URL" )
polygonContract = NodeCmd . Flags ( ) . String ( "polygonContract" , "" , "Polygon contract address" )
2022-11-11 06:12:16 -08:00
polygonRootChainRpc = NodeCmd . Flags ( ) . String ( "polygonRootChainRpc" , "" , "Polygon root chain RPC" )
polygonRootChainContractAddress = NodeCmd . Flags ( ) . String ( "polygonRootChainContractAddress" , "" , "Polygon root chain contract address" )
2021-10-18 08:53:13 -07:00
2021-12-09 13:40:55 -08:00
avalancheRPC = NodeCmd . Flags ( ) . String ( "avalancheRPC" , "" , "Avalanche RPC URL" )
avalancheContract = NodeCmd . Flags ( ) . String ( "avalancheContract" , "" , "Avalanche contract address" )
2021-12-20 11:40:58 -08:00
oasisRPC = NodeCmd . Flags ( ) . String ( "oasisRPC" , "" , "Oasis RPC URL" )
oasisContract = NodeCmd . Flags ( ) . String ( "oasisContract" , "" , "Oasis contract address" )
2022-03-15 07:41:10 -07:00
auroraRPC = NodeCmd . Flags ( ) . String ( "auroraRPC" , "" , "Aurora Websocket RPC URL" )
auroraContract = NodeCmd . Flags ( ) . String ( "auroraContract" , "" , "Aurora contract address" )
2022-02-02 09:50:10 -08:00
fantomRPC = NodeCmd . Flags ( ) . String ( "fantomRPC" , "" , "Fantom Websocket RPC URL" )
fantomContract = NodeCmd . Flags ( ) . String ( "fantomContract" , "" , "Fantom contract address" )
2022-03-03 13:40:32 -08:00
karuraRPC = NodeCmd . Flags ( ) . String ( "karuraRPC" , "" , "Karura RPC URL" )
karuraContract = NodeCmd . Flags ( ) . String ( "karuraContract" , "" , "Karura contract address" )
acalaRPC = NodeCmd . Flags ( ) . String ( "acalaRPC" , "" , "Acala RPC URL" )
acalaContract = NodeCmd . Flags ( ) . String ( "acalaContract" , "" , "Acala contract address" )
2022-04-04 15:11:03 -07:00
klaytnRPC = NodeCmd . Flags ( ) . String ( "klaytnRPC" , "" , "Klaytn RPC URL" )
klaytnContract = NodeCmd . Flags ( ) . String ( "klaytnContract" , "" , "Klaytn contract address" )
2022-04-28 09:20:38 -07:00
celoRPC = NodeCmd . Flags ( ) . String ( "celoRPC" , "" , "Celo RPC URL" )
celoContract = NodeCmd . Flags ( ) . String ( "celoContract" , "" , "Celo contract address" )
2022-05-10 08:23:07 -07:00
moonbeamRPC = NodeCmd . Flags ( ) . String ( "moonbeamRPC" , "" , "Moonbeam RPC URL" )
moonbeamContract = NodeCmd . Flags ( ) . String ( "moonbeamContract" , "" , "Moonbeam contract address" )
2022-06-14 07:22:49 -07:00
neonRPC = NodeCmd . Flags ( ) . String ( "neonRPC" , "" , "Neon RPC URL" )
neonContract = NodeCmd . Flags ( ) . String ( "neonContract" , "" , "Neon contract address" )
2021-08-30 07:19:00 -07:00
terraWS = NodeCmd . Flags ( ) . String ( "terraWS" , "" , "Path to terrad root for websocket connection" )
terraLCD = NodeCmd . Flags ( ) . String ( "terraLCD" , "" , "Path to LCD service root for http calls" )
terraContract = NodeCmd . Flags ( ) . String ( "terraContract" , "" , "Wormhole contract address on Terra blockchain" )
2020-11-16 04:28:07 -08:00
2022-06-16 12:17:43 -07:00
terra2WS = NodeCmd . Flags ( ) . String ( "terra2WS" , "" , "Path to terrad root for websocket connection" )
terra2LCD = NodeCmd . Flags ( ) . String ( "terra2LCD" , "" , "Path to LCD service root for http calls" )
terra2Contract = NodeCmd . Flags ( ) . String ( "terra2Contract" , "" , "Wormhole contract address on Terra 2 blockchain" )
2022-07-06 07:19:57 -07:00
injectiveWS = NodeCmd . Flags ( ) . String ( "injectiveWS" , "" , "Path to root for Injective websocket connection" )
injectiveLCD = NodeCmd . Flags ( ) . String ( "injectiveLCD" , "" , "Path to LCD service root for Injective http calls" )
injectiveContract = NodeCmd . Flags ( ) . String ( "injectiveContract" , "" , "Wormhole contract address on Injective blockchain" )
2022-10-05 06:05:31 -07:00
xplaWS = NodeCmd . Flags ( ) . String ( "xplaWS" , "" , "Path to root for XPLA websocket connection" )
xplaLCD = NodeCmd . Flags ( ) . String ( "xplaLCD" , "" , "Path to LCD service root for XPLA http calls" )
xplaContract = NodeCmd . Flags ( ) . String ( "xplaContract" , "" , "Wormhole contract address on XPLA blockchain" )
2022-04-29 12:56:08 -07:00
algorandIndexerRPC = NodeCmd . Flags ( ) . String ( "algorandIndexerRPC" , "" , "Algorand Indexer RPC URL" )
algorandIndexerToken = NodeCmd . Flags ( ) . String ( "algorandIndexerToken" , "" , "Algorand Indexer access token" )
2022-05-10 04:41:59 -07:00
algorandAlgodRPC = NodeCmd . Flags ( ) . String ( "algorandAlgodRPC" , "" , "Algorand Algod RPC URL" )
algorandAlgodToken = NodeCmd . Flags ( ) . String ( "algorandAlgodToken" , "" , "Algorand Algod access token" )
2022-04-29 12:56:08 -07:00
algorandAppID = NodeCmd . Flags ( ) . Uint64 ( "algorandAppID" , 0 , "Algorand app id" )
2021-12-22 08:22:04 -08:00
2022-08-05 10:49:16 -07:00
nearRPC = NodeCmd . Flags ( ) . String ( "nearRPC" , "" , "near RPC URL" )
nearContract = NodeCmd . Flags ( ) . String ( "nearContract" , "" , "near contract" )
2022-10-21 13:28:04 -07:00
wormchainWS = NodeCmd . Flags ( ) . String ( "wormchainWS" , "" , "Path to wormchaind root for websocket connection" )
2022-09-02 01:36:24 -07:00
wormchainLCD = NodeCmd . Flags ( ) . String ( "wormchainLCD" , "" , "Path to LCD service root for http calls" )
2023-01-16 04:33:01 -08:00
wormchainURL = NodeCmd . Flags ( ) . String ( "wormchainURL" , "" , "wormhole-chain gRPC URL" )
wormchainKeyPath = NodeCmd . Flags ( ) . String ( "wormchainKeyPath" , "" , "path to wormhole-chain private key for signing transactions" )
wormchainKeyPassPhrase = NodeCmd . Flags ( ) . String ( "wormchainKeyPassPhrase" , "" , "pass phrase used to unarmor the wormchain key file" )
2023-01-17 05:30:50 -08:00
accountantWS = NodeCmd . Flags ( ) . String ( "accountantWS" , "" , "Websocket used to listen to the accountant smart contract on wormchain" )
accountantContract = NodeCmd . Flags ( ) . String ( "accountantContract" , "" , "Address of the accountant smart contract on wormchain" )
accountantCheckEnabled = NodeCmd . Flags ( ) . Bool ( "accountantCheckEnabled" , false , "Should accountant be enforced on transfers" )
2022-09-02 01:36:24 -07:00
2022-10-13 18:22:54 -07:00
aptosRPC = NodeCmd . Flags ( ) . String ( "aptosRPC" , "" , "aptos RPC URL" )
aptosAccount = NodeCmd . Flags ( ) . String ( "aptosAccount" , "" , "aptos account" )
aptosHandle = NodeCmd . Flags ( ) . String ( "aptosHandle" , "" , "aptos handle" )
2022-11-18 06:14:22 -08:00
suiRPC = NodeCmd . Flags ( ) . String ( "suiRPC" , "" , "sui RPC URL" )
suiWS = NodeCmd . Flags ( ) . String ( "suiWS" , "" , "sui WS URL" )
suiAccount = NodeCmd . Flags ( ) . String ( "suiAccount" , "" , "sui account" )
suiPackage = NodeCmd . Flags ( ) . String ( "suiPackage" , "" , "sui package" )
2023-01-18 08:24:55 -08:00
solanaRPC = NodeCmd . Flags ( ) . String ( "solanaRPC" , "" , "Solana RPC URL (required)" )
2021-01-21 02:31:32 -08:00
2022-07-28 10:30:00 -07:00
pythnetContract = NodeCmd . Flags ( ) . String ( "pythnetContract" , "" , "Address of the PythNet program (required)" )
2023-01-18 08:24:55 -08:00
pythnetRPC = NodeCmd . Flags ( ) . String ( "pythnetRPC" , "" , "PythNet RPC URL (required)" )
pythnetWS = NodeCmd . Flags ( ) . String ( "pythnetWS" , "" , "PythNet WS URL" )
2022-07-28 10:30:00 -07:00
2022-09-28 07:39:58 -07:00
arbitrumRPC = NodeCmd . Flags ( ) . String ( "arbitrumRPC" , "" , "Arbitrum RPC URL" )
arbitrumContract = NodeCmd . Flags ( ) . String ( "arbitrumContract" , "" , "Arbitrum contract address" )
2022-11-10 05:50:08 -08:00
optimismRPC = NodeCmd . Flags ( ) . String ( "optimismRPC" , "" , "Optimism RPC URL" )
optimismContract = NodeCmd . Flags ( ) . String ( "optimismContract" , "" , "Optimism contract address" )
2022-12-02 05:38:45 -08:00
optimismCtcRpc = NodeCmd . Flags ( ) . String ( "optimismCtcRpc" , "" , "Optimism CTC RPC" )
optimismCtcContractAddress = NodeCmd . Flags ( ) . String ( "optimismCtcContractAddress" , "" , "Optimism CTC contract address" )
2022-11-10 05:50:08 -08:00
2021-08-30 07:19:00 -07:00
logLevel = NodeCmd . Flags ( ) . String ( "logLevel" , "info" , "Logging level (debug, info, warn, error, dpanic, panic, fatal)" )
2020-10-28 14:41:38 -07:00
2021-08-30 07:19:00 -07:00
unsafeDevMode = NodeCmd . Flags ( ) . Bool ( "unsafeDevMode" , false , "Launch node in unsafe, deterministic devnet mode" )
2022-10-31 07:14:01 -07:00
testnetMode = NodeCmd . Flags ( ) . Bool ( "testnetMode" , false , "Launch node in testnet mode (enables testnet-only features)" )
2021-08-30 07:19:00 -07:00
devNumGuardians = NodeCmd . Flags ( ) . Uint ( "devNumGuardians" , 5 , "Number of devnet guardians to include in guardian set" )
nodeName = NodeCmd . Flags ( ) . String ( "nodeName" , "" , "Node name to announce in gossip heartbeats" )
2021-05-12 22:57:08 -07:00
2021-08-30 07:19:00 -07:00
publicRPC = NodeCmd . Flags ( ) . String ( "publicRPC" , "" , "Listen address for public gRPC interface" )
publicWeb = NodeCmd . Flags ( ) . String ( "publicWeb" , "" , "Listen address for public REST and gRPC Web interface" )
2021-08-20 15:44:37 -07:00
2021-08-30 07:19:00 -07:00
tlsHostname = NodeCmd . Flags ( ) . String ( "tlsHostname" , "" , "If set, serve publicWeb as TLS with this hostname using Let's Encrypt" )
tlsProdEnv = NodeCmd . Flags ( ) . Bool ( "tlsProdEnv" , false ,
2021-08-20 15:44:37 -07:00
"Use the production Let's Encrypt environment instead of staging" )
2021-07-07 02:39:48 -07:00
2021-08-30 07:19:00 -07:00
disableHeartbeatVerify = NodeCmd . Flags ( ) . Bool ( "disableHeartbeatVerify" , false ,
2021-08-05 08:01:36 -07:00
"Disable heartbeat signature verification (useful during network startup)" )
2022-01-09 12:56:59 -08:00
disableTelemetry = NodeCmd . Flags ( ) . Bool ( "disableTelemetry" , false ,
"Disable telemetry" )
telemetryKey = NodeCmd . Flags ( ) . String ( "telemetryKey" , "" ,
"Telemetry write key" )
2021-08-05 08:01:36 -07:00
2021-10-05 11:13:07 -07:00
discordToken = NodeCmd . Flags ( ) . String ( "discordToken" , "" , "Discord bot token (optional)" )
discordChannel = NodeCmd . Flags ( ) . String ( "discordChannel" , "" , "Discord channel name (optional)" )
2021-08-30 07:19:00 -07:00
bigTablePersistenceEnabled = NodeCmd . Flags ( ) . Bool ( "bigTablePersistenceEnabled" , false , "Turn on forwarding events to BigTable" )
bigTableGCPProject = NodeCmd . Flags ( ) . String ( "bigTableGCPProject" , "" , "Google Cloud project ID for storing events" )
bigTableInstanceName = NodeCmd . Flags ( ) . String ( "bigTableInstanceName" , "" , "BigTable instance name for storing events" )
bigTableTableName = NodeCmd . Flags ( ) . String ( "bigTableTableName" , "" , "BigTable table name to store events in" )
2021-11-04 02:00:52 -07:00
bigTableTopicName = NodeCmd . Flags ( ) . String ( "bigTableTopicName" , "" , "GCP topic name to publish to" )
2021-08-30 07:19:00 -07:00
bigTableKeyPath = NodeCmd . Flags ( ) . String ( "bigTableKeyPath" , "" , "Path to json Service Account key" )
2022-07-19 11:08:06 -07:00
chainGovernorEnabled = NodeCmd . Flags ( ) . Bool ( "chainGovernorEnabled" , false , "Run the chain governor" )
2020-10-28 14:41:38 -07:00
}
2020-08-17 05:55:51 -07:00
var (
rootCtx context . Context
rootCtxCancel context . CancelFunc
)
2020-08-19 05:23:00 -07:00
// "Why would anyone do this?" are famous last words.
//
// We already forcibly override RPC URLs and keys in dev mode to prevent security
// risks from operator error, but an extra warning won't hurt.
const devwarning = `
++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +
| NODE IS RUNNING IN INSECURE DEVELOPMENT MODE |
| |
2022-07-06 11:27:49 -07:00
| Do not use -- unsafeDevMode in prod . |
2020-08-19 05:23:00 -07:00
++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +
`
2021-08-30 07:19:00 -07:00
// NodeCmd represents the node command
var NodeCmd = & cobra . Command {
Use : "node" ,
Short : "Run the guardiand node" ,
Run : runNode ,
2020-10-28 14:41:38 -07:00
}
2020-08-02 14:12:58 -07:00
2022-07-06 11:27:49 -07:00
// This variable may be overridden by the -X linker flag to "dev" in which case
// we enforce the --unsafeDevMode flag. Only development binaries/docker images
// are distributed. Production binaries are required to be built from source by
// guardians to reduce risk from a compromised builder.
var Build = "prod"
2022-09-20 07:00:29 -07:00
// observationRequestBufferSize is the buffer size of the per-network reobservation channel
const observationRequestBufferSize = 25
2021-08-30 07:19:00 -07:00
func runNode ( cmd * cobra . Command , args [ ] string ) {
2022-07-06 11:27:49 -07:00
if Build == "dev" && ! * unsafeDevMode {
fmt . Println ( "This is a development build. --unsafeDevMode must be enabled." )
os . Exit ( 1 )
}
2020-08-19 05:23:00 -07:00
if * unsafeDevMode {
fmt . Print ( devwarning )
}
2021-12-02 16:02:32 -08:00
common . LockMemory ( )
common . SetRestrictiveUmask ( )
2020-10-22 07:51:56 -07:00
2021-08-02 04:26:57 -07:00
// Refuse to run as root in production mode.
if ! * unsafeDevMode && os . Geteuid ( ) == 0 {
fmt . Println ( "can't run as uid 0" )
os . Exit ( 1 )
}
2020-08-02 14:12:58 -07:00
// Set up logging. The go-log zap wrapper that libp2p uses is compatible with our
// usage of zap in supervisor, which is nice.
lvl , err := ipfslog . LevelFromString ( * logLevel )
if err != nil {
fmt . Println ( "Invalid log level" )
os . Exit ( 1 )
}
2022-01-25 03:59:18 -08:00
logger := zap . New ( zapcore . NewCore (
consoleEncoder { zapcore . NewConsoleEncoder (
zap . NewDevelopmentEncoderConfig ( ) ) } ,
zapcore . AddSync ( zapcore . Lock ( os . Stderr ) ) ,
zap . NewAtomicLevelAt ( zapcore . Level ( lvl ) ) ) )
2022-01-06 08:58:56 -08:00
if * unsafeDevMode {
// Use the hostname as nodeName. For production, we don't want to do this to
// prevent accidentally leaking sensitive hostnames.
hostname , err := os . Hostname ( )
if err != nil {
panic ( err )
}
* nodeName = hostname
// Put node name into the log for development.
logger = logger . Named ( * nodeName )
}
2020-08-02 14:12:58 -07:00
// Override the default go-log config, which uses a magic environment variable.
ipfslog . SetAllLoggers ( lvl )
2021-01-24 08:20:04 -08:00
if * statusAddr != "" {
// Use a custom routing instead of using http.DefaultServeMux directly to avoid accidentally exposing packages
// that register themselves with it by default (like pprof).
router := mux . NewRouter ( )
// pprof server. NOT necessarily safe to expose publicly - only enable it in dev mode to avoid exposing it by
// accident. There's benefit to having pprof enabled on production nodes, but we would likely want to expose it
// via a dedicated port listening on localhost, or via the admin UNIX socket.
if * unsafeDevMode {
// Pass requests to http.DefaultServeMux, which pprof automatically registers with as an import side-effect.
router . PathPrefix ( "/debug/pprof/" ) . Handler ( http . DefaultServeMux )
}
2020-11-27 15:46:37 -08:00
2021-01-24 08:20:04 -08:00
// Simple endpoint exposing node readiness (safe to expose to untrusted clients)
router . HandleFunc ( "/readyz" , readiness . Handler )
// Prometheus metrics (safe to expose to untrusted clients)
router . Handle ( "/metrics" , promhttp . Handler ( ) )
go func ( ) {
logger . Info ( "status server listening on [::]:6060" )
2022-05-23 02:25:24 -07:00
// SECURITY: If making changes, ensure that we always do `router := mux.NewRouter()` before this to avoid accidentally exposing pprof
2022-11-28 05:48:27 -08:00
logger . Error ( "status server crashed" , zap . Error ( http . ListenAndServe ( * statusAddr , router ) ) ) // #nosec G114 local status server not vulnerable to DoS attack
2020-08-19 05:23:00 -07:00
} ( )
2021-01-24 08:20:04 -08:00
}
2020-08-19 05:23:00 -07:00
2021-01-24 08:20:04 -08:00
// In devnet mode, we automatically set a number of flags that rely on deterministic keys.
if * unsafeDevMode {
2022-10-06 05:57:25 -07:00
g0key , err := peer . IDFromPrivateKey ( devnet . DeterministicP2PPrivKeyByIndex ( 0 ) )
if err != nil {
panic ( err )
2020-08-19 05:23:00 -07:00
}
2022-10-06 05:57:25 -07:00
// Use the first guardian node as bootstrap
* p2pBootstrap = fmt . Sprintf ( "/dns4/guardian-0.guardian/udp/%d/quic/p2p/%s" , * p2pPort , g0key . String ( ) )
2020-08-19 05:23:00 -07:00
// Deterministic ganache ETH devnet address.
2022-11-10 14:27:39 -08:00
* ethContract = unsafeDevModeEvmContractAddress ( * ethContract )
* bscContract = unsafeDevModeEvmContractAddress ( * bscContract )
* polygonContract = unsafeDevModeEvmContractAddress ( * polygonContract )
* avalancheContract = unsafeDevModeEvmContractAddress ( * avalancheContract )
* oasisContract = unsafeDevModeEvmContractAddress ( * oasisContract )
* auroraContract = unsafeDevModeEvmContractAddress ( * auroraContract )
* fantomContract = unsafeDevModeEvmContractAddress ( * fantomContract )
* karuraContract = unsafeDevModeEvmContractAddress ( * karuraContract )
* acalaContract = unsafeDevModeEvmContractAddress ( * acalaContract )
* klaytnContract = unsafeDevModeEvmContractAddress ( * klaytnContract )
* celoContract = unsafeDevModeEvmContractAddress ( * celoContract )
* moonbeamContract = unsafeDevModeEvmContractAddress ( * moonbeamContract )
* neonContract = unsafeDevModeEvmContractAddress ( * neonContract )
* arbitrumContract = unsafeDevModeEvmContractAddress ( * arbitrumContract )
* optimismContract = unsafeDevModeEvmContractAddress ( * optimismContract )
2020-08-19 05:23:00 -07:00
}
2020-08-02 14:12:58 -07:00
2020-08-03 13:33:35 -07:00
// Verify flags
2020-08-19 05:23:00 -07:00
if * nodeKeyPath == "" && ! * unsafeDevMode { // In devnet mode, keys are deterministically generated.
2020-11-20 12:18:29 -08:00
logger . Fatal ( "Please specify --nodeKey" )
2020-08-03 13:33:35 -07:00
}
2021-08-30 07:19:00 -07:00
if * guardianKeyPath == "" {
logger . Fatal ( "Please specify --guardianKey" )
2020-11-19 03:53:17 -08:00
}
2020-11-19 03:53:19 -08:00
if * adminSocketPath == "" {
2020-11-20 12:18:29 -08:00
logger . Fatal ( "Please specify --adminSocket" )
2020-11-19 03:53:19 -08:00
}
2022-11-18 07:36:22 -08:00
if * adminSocketPath == * publicGRPCSocketPath {
logger . Fatal ( "--adminSocket must not equal --publicGRPCSocket" )
}
if ( * publicRPC != "" || * publicWeb != "" ) && * publicGRPCSocketPath == "" {
logger . Fatal ( "If either --publicRPC or --publicWeb is specified, --publicGRPCSocket must also be specified" )
}
2021-07-21 11:56:25 -07:00
if * dataDir == "" {
logger . Fatal ( "Please specify --dataDir" )
}
2020-08-16 08:05:58 -07:00
if * ethRPC == "" {
2020-11-20 12:18:29 -08:00
logger . Fatal ( "Please specify --ethRPC" )
2020-08-16 08:05:58 -07:00
}
2020-08-19 05:23:00 -07:00
if * ethContract == "" {
2020-11-20 12:18:29 -08:00
logger . Fatal ( "Please specify --ethContract" )
2020-08-19 05:23:00 -07:00
}
2021-07-28 06:32:49 -07:00
if * bscRPC == "" {
logger . Fatal ( "Please specify --bscRPC" )
}
if * bscContract == "" {
logger . Fatal ( "Please specify --bscContract" )
}
2021-10-18 08:53:13 -07:00
if * polygonRPC == "" {
logger . Fatal ( "Please specify --polygonRPC" )
}
if * polygonContract == "" {
logger . Fatal ( "Please specify --polygonContract" )
}
2021-12-14 14:27:17 -08:00
if * avalancheRPC == "" {
logger . Fatal ( "Please specify --avalancheRPC" )
}
2021-12-21 12:55:31 -08:00
if * oasisRPC == "" {
logger . Fatal ( "Please specify --oasisRPC" )
}
2022-02-28 13:32:22 -08:00
if * fantomRPC == "" {
logger . Fatal ( "Please specify --fantomRPC" )
}
if * fantomContract == "" && ! * unsafeDevMode {
logger . Fatal ( "Please specify --fantomContract" )
}
2022-04-09 05:06:10 -07:00
if * auroraRPC == "" {
logger . Fatal ( "Please specify --auroraRPC" )
}
if * auroraContract == "" && ! * unsafeDevMode {
logger . Fatal ( "Please specify --auroraContract" )
}
2022-05-02 11:28:17 -07:00
if * karuraRPC == "" {
logger . Fatal ( "Please specify --karuraRPC" )
}
if * karuraContract == "" && ! * unsafeDevMode {
logger . Fatal ( "Please specify --karuraContract" )
}
2022-06-02 09:18:44 -07:00
if * acalaRPC == "" {
logger . Fatal ( "Please specify --acalaRPC" )
}
if * acalaContract == "" && ! * unsafeDevMode {
logger . Fatal ( "Please specify --acalaContract" )
}
2022-05-16 07:06:17 -07:00
if * klaytnRPC == "" {
logger . Fatal ( "Please specify --klaytnRPC" )
}
if * klaytnContract == "" && ! * unsafeDevMode {
logger . Fatal ( "Please specify --klaytnContract" )
}
2022-05-12 09:12:40 -07:00
if * celoRPC == "" {
logger . Fatal ( "Please specify --celoRPC" )
}
if * celoContract == "" && ! * unsafeDevMode {
logger . Fatal ( "Please specify --celoContract" )
}
2022-08-26 09:46:37 -07:00
if * nearRPC != "" {
if * nearContract == "" {
logger . Fatal ( "If --nearRPC is specified, then --nearContract must be specified" )
2022-08-05 10:49:16 -07:00
}
2022-08-26 09:46:37 -07:00
} else if * nearContract != "" {
2022-10-12 13:47:03 -07:00
logger . Fatal ( "If --nearRPC is not specified, then --nearContract must not be specified" )
2022-08-05 10:49:16 -07:00
}
2022-09-12 16:41:39 -07:00
if * moonbeamRPC == "" {
logger . Fatal ( "Please specify --moonbeamRPC" )
}
if * moonbeamContract == "" {
logger . Fatal ( "Please specify --moonbeamContract" )
}
2022-10-27 11:50:01 -07:00
if * arbitrumRPC == "" {
logger . Fatal ( "Please specify --arbitrumRPC" )
}
if * arbitrumContract == "" {
logger . Fatal ( "Please specify --arbitrumContract" )
}
2022-10-12 13:47:03 -07:00
if * xplaWS != "" {
if * xplaLCD == "" || * xplaContract == "" {
logger . Fatal ( "If --xplaWS is specified, then --xplaLCD and --xplaContract must be specified" )
}
} else if * xplaLCD != "" || * xplaContract != "" {
logger . Fatal ( "If --xplaWS is not specified, then --xplaLCD and --xplaContract must not be specified" )
}
2022-10-20 09:43:43 -07:00
if * wormchainWS != "" {
if * wormchainLCD == "" {
logger . Fatal ( "If --wormchainWS is specified, then --wormchainLCD must be specified" )
}
} else if * wormchainLCD != "" {
logger . Fatal ( "If --wormchainWS is not specified, then --wormchainLCD must not be specified" )
}
2022-10-13 18:22:54 -07:00
2022-10-14 08:34:24 -07:00
if * aptosRPC != "" {
if * aptosAccount == "" {
logger . Fatal ( "If --aptosRPC is specified, then --aptosAccount must be specified" )
}
if * aptosHandle == "" {
logger . Fatal ( "If --aptosRPC is specified, then --aptosHandle must be specified" )
2022-10-13 18:22:54 -07:00
}
}
2022-11-18 06:14:22 -08:00
if * suiRPC != "" {
if * suiWS == "" {
logger . Fatal ( "If --suiRPC is specified, then --suiWS must be specified" )
}
if * suiAccount == "" {
logger . Fatal ( "If --suiRPC is specified, then --suiAccount must be specified" )
}
if * suiPackage == "" && ! * unsafeDevMode {
logger . Fatal ( "If --suiRPC is specified, then --suiPackage must be specified" )
}
}
2022-10-13 18:22:54 -07:00
2022-11-10 11:56:38 -08:00
if ( * optimismRPC == "" ) != ( * optimismContract == "" ) {
logger . Fatal ( "Both --optimismContract and --optimismRPC must be set together or both unset" )
}
2021-11-22 07:49:41 -08:00
if * testnetMode {
2022-06-14 07:22:49 -07:00
if * neonRPC == "" {
logger . Fatal ( "Please specify --neonRPC" )
}
if * neonContract == "" {
logger . Fatal ( "Please specify --neonContract" )
}
2021-11-22 07:49:41 -08:00
} else {
2022-06-14 07:22:49 -07:00
if * neonRPC != "" && ! * unsafeDevMode {
logger . Fatal ( "Please do not specify --neonRPC" )
}
if * neonContract != "" && ! * unsafeDevMode {
logger . Fatal ( "Please do not specify --neonContract" )
}
2021-11-22 07:49:41 -08:00
}
2020-08-17 10:22:12 -07:00
if * nodeName == "" {
2020-11-20 12:18:29 -08:00
logger . Fatal ( "Please specify --nodeName" )
2020-08-17 10:22:12 -07:00
}
2021-01-21 02:31:32 -08:00
2022-07-10 17:47:10 -07:00
// Solana, Terra Classic, Terra 2, and Algorand are optional in devnet
if ! * unsafeDevMode {
2021-01-21 02:31:32 -08:00
2022-07-10 17:47:10 -07:00
if * solanaContract == "" {
logger . Fatal ( "Please specify --solanaContract" )
2021-12-22 08:22:04 -08:00
}
2022-07-10 17:47:10 -07:00
if * solanaRPC == "" {
2022-08-26 06:45:47 -07:00
logger . Fatal ( "Please specify --solanaRPC" )
2022-05-10 04:41:59 -07:00
}
2022-07-10 17:47:10 -07:00
if * terraWS == "" {
logger . Fatal ( "Please specify --terraWS" )
}
if * terraLCD == "" {
logger . Fatal ( "Please specify --terraLCD" )
2022-05-10 04:41:59 -07:00
}
2022-07-10 17:47:10 -07:00
if * terraContract == "" {
logger . Fatal ( "Please specify --terraContract" )
2021-12-22 08:22:04 -08:00
}
2022-07-10 17:47:10 -07:00
if * terra2WS == "" {
logger . Fatal ( "Please specify --terra2WS" )
}
if * terra2LCD == "" {
logger . Fatal ( "Please specify --terra2LCD" )
}
if * terra2Contract == "" {
logger . Fatal ( "Please specify --terra2Contract" )
}
2022-08-16 08:14:48 -07:00
if * algorandIndexerRPC == "" {
logger . Fatal ( "Please specify --algorandIndexerRPC" )
}
if * algorandAlgodRPC == "" {
logger . Fatal ( "Please specify --algorandAlgodRPC" )
}
if * algorandAlgodToken == "" {
logger . Fatal ( "Please specify --algorandAlgodToken" )
}
if * algorandAppID == 0 {
logger . Fatal ( "Please specify --algorandAppID" )
}
2022-07-28 10:30:00 -07:00
2022-08-26 06:45:47 -07:00
if * pythnetContract == "" {
logger . Fatal ( "Please specify --pythnetContract" )
}
if * pythnetRPC == "" {
logger . Fatal ( "Please specify --pythnetRPC" )
2022-07-10 17:47:10 -07:00
}
2022-12-07 11:43:44 -08:00
if * injectiveWS == "" {
logger . Fatal ( "Please specify --injectiveWS" )
}
if * injectiveLCD == "" {
logger . Fatal ( "Please specify --injectiveLCD" )
}
if * injectiveContract == "" {
logger . Fatal ( "Please specify --injectiveContract" )
}
2021-12-22 08:22:04 -08:00
}
2022-07-10 17:47:10 -07:00
2021-07-07 02:39:48 -07:00
if * bigTablePersistenceEnabled {
if * bigTableGCPProject == "" {
logger . Fatal ( "Please specify --bigTableGCPProject" )
}
if * bigTableInstanceName == "" {
logger . Fatal ( "Please specify --bigTableInstanceName" )
}
if * bigTableTableName == "" {
logger . Fatal ( "Please specify --bigTableTableName" )
}
2021-11-04 02:00:52 -07:00
if * bigTableTopicName == "" {
logger . Fatal ( "Please specify --bigTableTopicName" )
}
2021-07-07 02:39:48 -07:00
if * bigTableKeyPath == "" {
logger . Fatal ( "Please specify --bigTableKeyPath" )
}
}
2021-10-18 08:23:55 -07:00
// Complain about Infura on mainnet.
//
// As it turns out, Infura has a bug where it would sometimes incorrectly round
// block timestamps, which causes consensus issues - the timestamp is part of
// the VAA and nodes using Infura would sometimes derive an incorrect VAA,
// accidentally attacking the network by signing a conflicting VAA.
//
// Node operators do not usually rely on Infura in the first place - doing
// so is insecure, since nodes blindly trust the connected nodes to verify
// on-chain message proofs. However, node operators sometimes used
// Infura during migrations where their primary node was offline, causing
// the aforementioned consensus oddities which were eventually found to
// be Infura-related. This is generally to the detriment of network security
// and a judgement call made by individual operators. In the case of Infura,
// we know it's actively dangerous so let's make an opinionated argument.
//
// Insert "I'm a sign, not a cop" meme.
//
2021-10-26 16:42:00 -07:00
if strings . Contains ( * ethRPC , "mainnet.infura.io" ) ||
strings . Contains ( * polygonRPC , "polygon-mainnet.infura.io" ) {
2021-10-18 08:23:55 -07:00
logger . Fatal ( "Infura is known to send incorrect blocks - please use your own nodes" )
}
2020-08-16 08:05:58 -07:00
ethContractAddr := eth_common . HexToAddress ( * ethContract )
2021-07-28 06:32:49 -07:00
bscContractAddr := eth_common . HexToAddress ( * bscContract )
2021-10-18 08:53:13 -07:00
polygonContractAddr := eth_common . HexToAddress ( * polygonContract )
2021-12-09 13:40:55 -08:00
avalancheContractAddr := eth_common . HexToAddress ( * avalancheContract )
2021-12-20 11:40:58 -08:00
oasisContractAddr := eth_common . HexToAddress ( * oasisContract )
2022-03-15 07:41:10 -07:00
auroraContractAddr := eth_common . HexToAddress ( * auroraContract )
2022-02-02 09:50:10 -08:00
fantomContractAddr := eth_common . HexToAddress ( * fantomContract )
2022-03-03 13:40:32 -08:00
karuraContractAddr := eth_common . HexToAddress ( * karuraContract )
acalaContractAddr := eth_common . HexToAddress ( * acalaContract )
2022-04-04 15:11:03 -07:00
klaytnContractAddr := eth_common . HexToAddress ( * klaytnContract )
2022-04-28 09:20:38 -07:00
celoContractAddr := eth_common . HexToAddress ( * celoContract )
2022-05-10 08:23:07 -07:00
moonbeamContractAddr := eth_common . HexToAddress ( * moonbeamContract )
2022-06-14 07:22:49 -07:00
neonContractAddr := eth_common . HexToAddress ( * neonContract )
2022-09-28 07:39:58 -07:00
arbitrumContractAddr := eth_common . HexToAddress ( * arbitrumContract )
2022-11-10 05:50:08 -08:00
optimismContractAddr := eth_common . HexToAddress ( * optimismContract )
2021-08-30 07:19:00 -07:00
solAddress , err := solana_types . PublicKeyFromBase58 ( * solanaContract )
2021-01-21 02:31:32 -08:00
if err != nil {
2021-08-30 07:19:00 -07:00
logger . Fatal ( "invalid Solana contract address" , zap . Error ( err ) )
2021-01-21 02:31:32 -08:00
}
2022-07-28 10:30:00 -07:00
var pythnetAddress solana_types . PublicKey
2022-08-26 06:45:47 -07:00
pythnetAddress , err = solana_types . PublicKeyFromBase58 ( * pythnetContract )
if err != nil {
logger . Fatal ( "invalid PythNet contract address" , zap . Error ( err ) )
2022-07-28 10:30:00 -07:00
}
2020-08-03 13:33:35 -07:00
2020-11-19 03:53:17 -08:00
// In devnet mode, we generate a deterministic guardian key and write it to disk.
if * unsafeDevMode {
gk , err := generateDevnetGuardianKey ( )
if err != nil {
logger . Fatal ( "failed to generate devnet guardian key" , zap . Error ( err ) )
}
2021-08-30 07:19:00 -07:00
err = writeGuardianKey ( gk , "auto-generated deterministic devnet key" , * guardianKeyPath , true )
2020-11-19 03:53:17 -08:00
if err != nil {
logger . Fatal ( "failed to write devnet guardian key" , zap . Error ( err ) )
}
}
2021-07-30 13:40:01 -07:00
// Database
dbPath := path . Join ( * dataDir , "db" )
if err := os . MkdirAll ( dbPath , 0700 ) ; err != nil {
logger . Fatal ( "failed to create database directory" , zap . Error ( err ) )
}
db , err := db . Open ( dbPath )
if err != nil {
logger . Fatal ( "failed to open database" , zap . Error ( err ) )
}
defer db . Close ( )
2020-08-17 10:36:17 -07:00
// Guardian key
2021-08-30 07:19:00 -07:00
gk , err := loadGuardianKey ( * guardianKeyPath )
2020-11-19 03:53:17 -08:00
if err != nil {
logger . Fatal ( "failed to load guardian key" , zap . Error ( err ) )
}
2021-02-03 04:01:51 -08:00
guardianAddr := ethcrypto . PubkeyToAddress ( gk . PublicKey ) . String ( )
2020-11-19 03:53:17 -08:00
logger . Info ( "Loaded guardian key" , zap . String (
2021-02-03 04:01:51 -08:00
"address" , guardianAddr ) )
p2p . DefaultRegistry . SetGuardianAddress ( guardianAddr )
2020-08-17 09:20:15 -07:00
2020-08-02 14:12:58 -07:00
// Node's main lifecycle context.
2020-08-17 05:55:51 -07:00
rootCtx , rootCtxCancel = context . WithCancel ( context . Background ( ) )
defer rootCtxCancel ( )
2020-08-02 14:12:58 -07:00
2022-11-28 05:48:27 -08:00
sigterm := make ( chan os . Signal , 1 )
signal . Notify ( sigterm , syscall . SIGTERM )
go func ( ) {
<- sigterm
logger . Info ( "Received sigterm. exiting." )
rootCtxCancel ( )
} ( )
2023-01-20 13:15:13 -08:00
// Setup various channels...
2020-08-19 05:23:00 -07:00
2023-01-20 13:15:13 -08:00
// Outbound gossip message queue (needs to be read/write because p2p needs read/write)
gossipSendC := make ( chan [ ] byte )
2020-08-21 04:00:40 -07:00
// Inbound observations
2020-11-20 13:35:00 -08:00
obsvC := make ( chan * gossipv1 . SignedObservation , 50 )
2020-08-20 12:48:58 -07:00
2023-01-20 13:15:13 -08:00
// Finalized guardian observations aggregated across all chains
msgReadC , msgWriteC := makeChannelPair [ * common . MessagePublication ] ( 0 )
// Ethereum incoming guardian set updates
setReadC , setWriteC := makeChannelPair [ * common . GuardianSet ] ( 0 )
2021-09-13 06:03:26 -07:00
// Inbound signed VAAs
2023-01-20 13:15:13 -08:00
signedInReadC , signedInWriteC := makeChannelPair [ * gossipv1 . SignedVAAWithQuorum ] ( 50 )
2021-09-13 06:03:26 -07:00
2022-02-08 14:16:43 -08:00
// Inbound observation requests from the p2p service (for all chains)
2023-01-20 13:15:13 -08:00
obsvReqReadC , obsvReqWriteC := makeChannelPair [ * gossipv1 . ObservationRequest ] ( common . ObsvReqChannelSize )
2021-12-20 13:23:45 -08:00
// Outbound observation requests
2023-01-20 13:15:13 -08:00
obsvReqSendReadC , obsvReqSendWriteC := makeChannelPair [ * gossipv1 . ObservationRequest ] ( common . ObsvReqChannelSize )
2021-12-20 13:23:45 -08:00
2020-11-19 03:53:19 -08:00
// Injected VAAs (manually generated rather than created via observation)
2023-01-20 13:15:13 -08:00
injectReadC , injectWriteC := makeChannelPair [ * vaa . VAA ] ( 0 )
2020-11-19 03:53:19 -08:00
2021-07-31 09:51:38 -07:00
// Guardian set state managed by processor
2022-09-06 16:36:02 -07:00
gst := common . NewGuardianSetState ( nil )
2021-07-31 09:51:38 -07:00
2022-02-08 14:16:43 -08:00
// Per-chain observation requests
chainObsvReqC := make ( map [ vaa . ChainID ] chan * gossipv1 . ObservationRequest )
2023-01-20 13:15:13 -08:00
// Per-chain msgC
chainMsgC := make ( map [ vaa . ChainID ] chan * common . MessagePublication )
// aggregate per-chain msgC into msgC.
// SECURITY defense-in-depth: This way we enforce that a watcher must set the msg.EmitterChain to its chainId, which makes the code easier to audit
for _ , chainId := range vaa . GetAllNetworkIDs ( ) {
chainMsgC [ chainId ] = make ( chan * common . MessagePublication )
go func ( c <- chan * common . MessagePublication , chainId vaa . ChainID ) {
for {
select {
case <- rootCtx . Done ( ) :
return
case msg := <- c :
if msg . EmitterChain == chainId {
msgWriteC <- msg
} else {
// SECURITY: This should never happen. If it does, a watcher has been compromised.
logger . Fatal ( "SECURITY CRITICAL: Received observation from a chain that was not marked as originating from that chain" ,
zap . Stringer ( "tx" , msg . TxHash ) ,
zap . Stringer ( "emitter_address" , msg . EmitterAddress ) ,
zap . Uint64 ( "sequence" , msg . Sequence ) ,
zap . Stringer ( "msgChainId" , msg . EmitterChain ) ,
zap . Stringer ( "watcherChainId" , chainId ) ,
)
}
}
}
} ( chainMsgC [ chainId ] , chainId )
}
2021-10-05 11:13:07 -07:00
var notifier * discord . DiscordNotifier
if * discordToken != "" {
notifier , err = discord . NewDiscordNotifier ( * discordToken , * discordChannel , logger )
if err != nil {
logger . Error ( "failed to initialize Discord bot" , zap . Error ( err ) )
}
}
2020-10-28 14:41:37 -07:00
// Load p2p private key
var priv crypto . PrivKey
if * unsafeDevMode {
idx , err := devnet . GetDevnetIndex ( )
if err != nil {
logger . Fatal ( "Failed to parse hostname - are we running in devnet?" )
}
priv = devnet . DeterministicP2PPrivKeyByIndex ( int64 ( idx ) )
} else {
2021-12-02 16:02:32 -08:00
priv , err = common . GetOrCreateNodeKey ( logger , * nodeKeyPath )
2020-10-28 14:41:37 -07:00
if err != nil {
logger . Fatal ( "Failed to load node key" , zap . Error ( err ) )
}
}
2022-01-09 12:56:59 -08:00
// Enable unless it is disabled. For devnet, only when --telemetryKey is set.
if ! * disableTelemetry && ( ! * unsafeDevMode || * unsafeDevMode && * telemetryKey != "" ) {
logger . Info ( "Telemetry enabled" )
if * telemetryKey == "" {
logger . Fatal ( "Please specify --telemetryKey" )
}
creds , err := decryptTelemetryServiceAccount ( )
if err != nil {
logger . Fatal ( "Failed to decrypt telemetry service account" , zap . Error ( err ) )
}
// Get libp2p peer ID from private key
pk := priv . GetPublic ( )
peerID , err := peer . IDFromPublicKey ( pk )
if err != nil {
logger . Fatal ( "Failed to get peer ID from private key" , zap . Error ( err ) )
}
tm , err := telemetry . New ( context . Background ( ) , telemetryProject , creds , map [ string ] string {
"node_name" : * nodeName ,
"node_key" : peerID . Pretty ( ) ,
"guardian_addr" : guardianAddr ,
"network" : * p2pNetworkID ,
"version" : version . Version ( ) ,
} )
if err != nil {
logger . Fatal ( "Failed to initialize telemetry" , zap . Error ( err ) )
}
defer tm . Close ( )
logger = tm . WrapLogger ( logger )
} else {
logger . Info ( "Telemetry disabled" )
}
// Redirect ipfs logs to plain zap
ipfslog . SetPrimaryCore ( logger . Core ( ) )
2021-08-09 22:29:21 -07:00
// provides methods for reporting progress toward message attestation, and channels for receiving attestation lifecyclye events.
attestationEvents := reporter . EventListener ( logger )
2023-01-16 04:33:01 -08:00
// If the wormchain sending info is configured, connect to it.
var wormchainKey cosmoscrypto . PrivKey
var wormchainConn * wormconn . ClientConn
if * wormchainURL != "" {
if * wormchainKeyPath == "" {
logger . Fatal ( "if wormchainURL is specified, wormchainKeyPath is required" )
}
if * wormchainKeyPassPhrase == "" {
logger . Fatal ( "if wormchainURL is specified, wormchainKeyPassPhrase is required" )
}
// Load the wormchain key.
wormchainKeyPathName := * wormchainKeyPath
if * unsafeDevMode {
idx , err := devnet . GetDevnetIndex ( )
if err != nil {
logger . Fatal ( "failed to get devnet index" , zap . Error ( err ) )
}
wormchainKeyPathName = fmt . Sprint ( * wormchainKeyPath , idx )
}
logger . Debug ( "acct: loading key file" , zap . String ( "key path" , wormchainKeyPathName ) )
wormchainKey , err = wormconn . LoadWormchainPrivKey ( wormchainKeyPathName , * wormchainKeyPassPhrase )
if err != nil {
logger . Fatal ( "failed to load devnet wormchain private key" , zap . Error ( err ) )
}
// Connect to wormchain.
logger . Info ( "Connecting to wormchain" , zap . String ( "wormchainURL" , * wormchainURL ) , zap . String ( "wormchainKeyPath" , wormchainKeyPathName ) )
wormchainConn , err = wormconn . NewConn ( rootCtx , * wormchainURL , wormchainKey )
if err != nil {
logger . Fatal ( "failed to connect to wormchain" , zap . Error ( err ) )
}
}
2023-01-17 05:30:50 -08:00
// Set up the accountant. If the accountant smart contract is configured, we will instantiate the accountant and VAAs
// will be passed to it for processing. It will forward all token bridge transfers to the accountant contract.
// If accountantCheckEnabled is set to true, token bridge transfers will not be signed and published until they
// are approved by the accountant smart contract.
2023-01-20 13:15:13 -08:00
acctReadC , acctWriteC := makeChannelPair [ * common . MessagePublication ] ( 0 )
2023-01-16 04:33:01 -08:00
2023-01-17 05:30:50 -08:00
var acct * accountant . Accountant
if * accountantContract != "" {
if * accountantWS == "" {
logger . Fatal ( "acct: if accountantContract is specified, accountantWS is required" )
2023-01-16 04:33:01 -08:00
}
if * wormchainLCD == "" {
2023-01-17 05:30:50 -08:00
logger . Fatal ( "acct: if accountantContract is specified, wormchainLCD is required" )
2023-01-16 04:33:01 -08:00
}
if wormchainConn == nil {
2023-01-17 05:30:50 -08:00
logger . Fatal ( "acct: if accountantContract is specified, the wormchain sending connection must be enabled" )
2023-01-16 04:33:01 -08:00
}
2023-01-17 05:30:50 -08:00
if * accountantCheckEnabled {
logger . Info ( "acct: accountant is enabled and will be enforced" )
2023-01-16 04:33:01 -08:00
} else {
2023-01-17 05:30:50 -08:00
logger . Info ( "acct: accountant is enabled but will not be enforced" )
2023-01-16 04:33:01 -08:00
}
2023-01-17 05:30:50 -08:00
env := accountant . MainNetMode
2023-01-16 04:33:01 -08:00
if * testnetMode {
2023-01-17 05:30:50 -08:00
env = accountant . TestNetMode
2023-01-16 04:33:01 -08:00
} else if * unsafeDevMode {
2023-01-17 05:30:50 -08:00
env = accountant . DevNetMode
2023-01-16 04:33:01 -08:00
}
2023-01-17 05:30:50 -08:00
acct = accountant . NewAccountant (
2023-01-16 04:33:01 -08:00
rootCtx ,
logger ,
db ,
2023-01-24 13:03:18 -08:00
obsvReqWriteC ,
2023-01-17 05:30:50 -08:00
* accountantContract ,
* accountantWS ,
2023-01-16 04:33:01 -08:00
wormchainConn ,
2023-01-17 05:30:50 -08:00
* accountantCheckEnabled ,
2023-01-16 04:33:01 -08:00
gk ,
gst ,
acctWriteC ,
env ,
)
} else {
2023-01-17 05:30:50 -08:00
logger . Info ( "acct: accountant is disabled" )
2023-01-16 04:33:01 -08:00
}
2022-07-19 11:08:06 -07:00
var gov * governor . ChainGovernor
if * chainGovernorEnabled {
logger . Info ( "chain governor is enabled" )
env := governor . MainNetMode
if * testnetMode {
env = governor . TestNetMode
} else if * unsafeDevMode {
env = governor . DevNetMode
}
gov = governor . NewChainGovernor ( logger , db , env )
} else {
logger . Info ( "chain governor is disabled" )
}
2020-08-02 14:12:58 -07:00
// Run supervisor.
2020-08-17 09:20:15 -07:00
supervisor . New ( rootCtx , logger , func ( ctx context . Context ) error {
2020-10-28 14:41:37 -07:00
if err := supervisor . Run ( ctx , "p2p" , p2p . Run (
2023-01-20 13:15:13 -08:00
( chan <- * gossipv1 . SignedObservation ) ( obsvC ) , obsvReqWriteC , obsvReqSendReadC , gossipSendC , signedInWriteC , priv , gk , gst , * p2pPort , * p2pNetworkID , * p2pBootstrap , * nodeName , * disableHeartbeatVerify , rootCtxCancel , acct , gov , nil , nil ) ) ; err != nil {
2020-08-02 14:12:58 -07:00
return err
}
2022-10-20 09:43:43 -07:00
// For each chain that wants a watcher, we:
// - create and register a component for readiness checks.
// - create an observation request channel.
// - create the watcher.
//
// NOTE: The "none" is a special indicator to disable a watcher until it is desirable to turn it back on.
2020-08-16 08:05:58 -07:00
2022-10-26 12:20:13 -07:00
var ethWatcher * evm . Watcher
2022-10-20 09:43:43 -07:00
if shouldStart ( ethRPC ) {
logger . Info ( "Starting Ethereum watcher" )
readiness . RegisterComponent ( common . ReadinessEthSyncing )
chainObsvReqC [ vaa . ChainIDEthereum ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2023-01-20 13:15:13 -08:00
ethWatcher = evm . NewEthWatcher ( * ethRPC , ethContractAddr , "eth" , common . ReadinessEthSyncing , vaa . ChainIDEthereum , chainMsgC [ vaa . ChainIDEthereum ] , setWriteC , chainObsvReqC [ vaa . ChainIDEthereum ] , * unsafeDevMode )
2022-10-20 09:43:43 -07:00
if err := supervisor . Run ( ctx , "ethwatch" ,
2023-01-11 11:31:02 -08:00
common . WrapWithScissors ( ethWatcher . Run , "ethwatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2021-07-28 06:32:49 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( bscRPC ) {
logger . Info ( "Starting BSC watcher" )
readiness . RegisterComponent ( common . ReadinessBSCSyncing )
chainObsvReqC [ vaa . ChainIDBSC ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2023-01-20 13:15:13 -08:00
bscWatcher := evm . NewEthWatcher ( * bscRPC , bscContractAddr , "bsc" , common . ReadinessBSCSyncing , vaa . ChainIDBSC , chainMsgC [ vaa . ChainIDBSC ] , nil , chainObsvReqC [ vaa . ChainIDBSC ] , * unsafeDevMode )
2022-11-14 17:38:04 -08:00
bscWatcher . SetWaitForConfirmations ( true )
2023-01-11 11:31:02 -08:00
if err := supervisor . Run ( ctx , "bscwatch" , common . WrapWithScissors ( bscWatcher . Run , "bscwatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2022-06-06 13:17:14 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( polygonRPC ) {
2022-11-14 17:38:04 -08:00
// Checkpointing is required in mainnet, so we don't need to wait for confirmations.
waitForConfirmations := * unsafeDevMode || * testnetMode
if ! waitForConfirmations && * polygonRootChainRpc == "" {
2022-11-11 06:12:16 -08:00
log . Fatal ( "Polygon checkpointing is required in mainnet" )
2022-10-20 09:43:43 -07:00
}
logger . Info ( "Starting Polygon watcher" )
readiness . RegisterComponent ( common . ReadinessPolygonSyncing )
chainObsvReqC [ vaa . ChainIDPolygon ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2023-01-20 13:15:13 -08:00
polygonWatcher := evm . NewEthWatcher ( * polygonRPC , polygonContractAddr , "polygon" , common . ReadinessPolygonSyncing , vaa . ChainIDPolygon , chainMsgC [ vaa . ChainIDPolygon ] , nil , chainObsvReqC [ vaa . ChainIDPolygon ] , * unsafeDevMode )
2022-11-14 17:38:04 -08:00
polygonWatcher . SetWaitForConfirmations ( waitForConfirmations )
2022-11-11 06:12:16 -08:00
if err := polygonWatcher . SetRootChainParams ( * polygonRootChainRpc , * polygonRootChainContractAddress ) ; err != nil {
return err
}
2023-01-11 11:31:02 -08:00
if err := supervisor . Run ( ctx , "polygonwatch" , common . WrapWithScissors ( polygonWatcher . Run , "polygonwatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2022-04-09 05:06:10 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( avalancheRPC ) {
logger . Info ( "Starting Avalanche watcher" )
readiness . RegisterComponent ( common . ReadinessAvalancheSyncing )
chainObsvReqC [ vaa . ChainIDAvalanche ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "avalanchewatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * avalancheRPC , avalancheContractAddr , "avalanche" , common . ReadinessAvalancheSyncing , vaa . ChainIDAvalanche , chainMsgC [ vaa . ChainIDAvalanche ] , nil , chainObsvReqC [ vaa . ChainIDAvalanche ] , * unsafeDevMode ) . Run , "avalanchewatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2022-02-28 13:32:22 -08:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( oasisRPC ) {
logger . Info ( "Starting Oasis watcher" )
chainObsvReqC [ vaa . ChainIDOasis ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "oasiswatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * oasisRPC , oasisContractAddr , "oasis" , common . ReadinessOasisSyncing , vaa . ChainIDOasis , chainMsgC [ vaa . ChainIDOasis ] , nil , chainObsvReqC [ vaa . ChainIDOasis ] , * unsafeDevMode ) . Run , "oasiswatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2022-05-02 11:28:17 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( auroraRPC ) {
logger . Info ( "Starting Aurora watcher" )
readiness . RegisterComponent ( common . ReadinessAuroraSyncing )
chainObsvReqC [ vaa . ChainIDAurora ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "aurorawatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * auroraRPC , auroraContractAddr , "aurora" , common . ReadinessAuroraSyncing , vaa . ChainIDAurora , chainMsgC [ vaa . ChainIDAurora ] , nil , chainObsvReqC [ vaa . ChainIDAurora ] , * unsafeDevMode ) . Run , "aurorawatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2022-06-02 09:18:44 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( fantomRPC ) {
logger . Info ( "Starting Fantom watcher" )
readiness . RegisterComponent ( common . ReadinessFantomSyncing )
chainObsvReqC [ vaa . ChainIDFantom ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "fantomwatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * fantomRPC , fantomContractAddr , "fantom" , common . ReadinessFantomSyncing , vaa . ChainIDFantom , chainMsgC [ vaa . ChainIDFantom ] , nil , chainObsvReqC [ vaa . ChainIDFantom ] , * unsafeDevMode ) . Run , "fantomwatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2022-05-16 07:06:17 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( karuraRPC ) {
logger . Info ( "Starting Karura watcher" )
readiness . RegisterComponent ( common . ReadinessKaruraSyncing )
chainObsvReqC [ vaa . ChainIDKarura ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "karurawatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * karuraRPC , karuraContractAddr , "karura" , common . ReadinessKaruraSyncing , vaa . ChainIDKarura , chainMsgC [ vaa . ChainIDKarura ] , nil , chainObsvReqC [ vaa . ChainIDKarura ] , * unsafeDevMode ) . Run , "karurawatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2022-05-12 09:12:40 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( acalaRPC ) {
logger . Info ( "Starting Acala watcher" )
readiness . RegisterComponent ( common . ReadinessAcalaSyncing )
chainObsvReqC [ vaa . ChainIDAcala ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "acalawatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * acalaRPC , acalaContractAddr , "acala" , common . ReadinessAcalaSyncing , vaa . ChainIDAcala , chainMsgC [ vaa . ChainIDAcala ] , nil , chainObsvReqC [ vaa . ChainIDAcala ] , * unsafeDevMode ) . Run , "acalawatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
2022-09-12 16:41:39 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( klaytnRPC ) {
logger . Info ( "Starting Klaytn watcher" )
readiness . RegisterComponent ( common . ReadinessKlaytnSyncing )
chainObsvReqC [ vaa . ChainIDKlaytn ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "klaytnwatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * klaytnRPC , klaytnContractAddr , "klaytn" , common . ReadinessKlaytnSyncing , vaa . ChainIDKlaytn , chainMsgC [ vaa . ChainIDKlaytn ] , nil , chainObsvReqC [ vaa . ChainIDKlaytn ] , * unsafeDevMode ) . Run , "klaytnwatch" ) ) ; err != nil {
2022-03-03 13:40:32 -08:00
return err
}
2022-10-20 09:43:43 -07:00
}
if shouldStart ( celoRPC ) {
logger . Info ( "Starting Celo watcher" )
readiness . RegisterComponent ( common . ReadinessCeloSyncing )
chainObsvReqC [ vaa . ChainIDCelo ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "celowatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * celoRPC , celoContractAddr , "celo" , common . ReadinessCeloSyncing , vaa . ChainIDCelo , chainMsgC [ vaa . ChainIDCelo ] , nil , chainObsvReqC [ vaa . ChainIDCelo ] , * unsafeDevMode ) . Run , "celowatch" ) ) ; err != nil {
2022-06-14 07:22:49 -07:00
return err
}
2022-10-20 09:43:43 -07:00
}
if shouldStart ( moonbeamRPC ) {
logger . Info ( "Starting Moonbeam watcher" )
readiness . RegisterComponent ( common . ReadinessMoonbeamSyncing )
chainObsvReqC [ vaa . ChainIDMoonbeam ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "moonbeamwatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( evm . NewEthWatcher ( * moonbeamRPC , moonbeamContractAddr , "moonbeam" , common . ReadinessMoonbeamSyncing , vaa . ChainIDMoonbeam , chainMsgC [ vaa . ChainIDMoonbeam ] , nil , chainObsvReqC [ vaa . ChainIDMoonbeam ] , * unsafeDevMode ) . Run , "moonbeamwatch" ) ) ; err != nil {
2022-09-28 07:39:58 -07:00
return err
}
2021-11-22 07:49:41 -08:00
}
2022-10-27 11:50:01 -07:00
if shouldStart ( arbitrumRPC ) {
if ethWatcher == nil {
log . Fatalf ( "if arbitrum is enabled then ethereum must also be enabled." )
}
logger . Info ( "Starting Arbitrum watcher" )
readiness . RegisterComponent ( common . ReadinessArbitrumSyncing )
chainObsvReqC [ vaa . ChainIDArbitrum ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2023-01-20 13:15:13 -08:00
arbitrumWatcher := evm . NewEthWatcher ( * arbitrumRPC , arbitrumContractAddr , "arbitrum" , common . ReadinessArbitrumSyncing , vaa . ChainIDArbitrum , chainMsgC [ vaa . ChainIDArbitrum ] , nil , chainObsvReqC [ vaa . ChainIDArbitrum ] , * unsafeDevMode )
2022-11-14 06:07:45 -08:00
arbitrumWatcher . SetL1Finalizer ( ethWatcher )
2023-01-11 11:31:02 -08:00
if err := supervisor . Run ( ctx , "arbitrumwatch" , common . WrapWithScissors ( arbitrumWatcher . Run , "arbitrumwatch" ) ) ; err != nil {
2022-10-27 11:50:01 -07:00
return err
}
}
2022-11-10 11:56:38 -08:00
if shouldStart ( optimismRPC ) {
if ethWatcher == nil {
log . Fatalf ( "if optimism is enabled then ethereum must also be enabled." )
}
2022-12-02 05:38:45 -08:00
if ! * unsafeDevMode {
if * optimismCtcRpc == "" || * optimismCtcContractAddress == "" {
log . Fatalf ( "--optimismCtcRpc and --optimismCtcContractAddress both need to be set." )
}
}
2022-11-10 11:56:38 -08:00
logger . Info ( "Starting Optimism watcher" )
readiness . RegisterComponent ( common . ReadinessOptimismSyncing )
chainObsvReqC [ vaa . ChainIDOptimism ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2023-01-20 13:15:13 -08:00
optimismWatcher := evm . NewEthWatcher ( * optimismRPC , optimismContractAddr , "optimism" , common . ReadinessOptimismSyncing , vaa . ChainIDOptimism , chainMsgC [ vaa . ChainIDOptimism ] , nil , chainObsvReqC [ vaa . ChainIDOptimism ] , * unsafeDevMode )
2022-11-14 06:07:45 -08:00
optimismWatcher . SetL1Finalizer ( ethWatcher )
2022-12-02 05:38:45 -08:00
if err := optimismWatcher . SetRootChainParams ( * optimismCtcRpc , * optimismCtcContractAddress ) ; err != nil {
return err
}
2023-01-11 11:31:02 -08:00
if err := supervisor . Run ( ctx , "optimismwatch" , common . WrapWithScissors ( optimismWatcher . Run , "optimismwatch" ) ) ; err != nil {
2022-11-10 11:56:38 -08:00
return err
}
}
2021-11-22 07:49:41 -08:00
2022-10-20 09:43:43 -07:00
if shouldStart ( terraWS ) {
2022-07-10 17:47:10 -07:00
logger . Info ( "Starting Terra watcher" )
2022-10-20 09:43:43 -07:00
readiness . RegisterComponent ( common . ReadinessTerraSyncing )
chainObsvReqC [ vaa . ChainIDTerra ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2022-07-10 17:47:10 -07:00
if err := supervisor . Run ( ctx , "terrawatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( cosmwasm . NewWatcher ( * terraWS , * terraLCD , * terraContract , chainMsgC [ vaa . ChainIDTerra ] , chainObsvReqC [ vaa . ChainIDTerra ] , common . ReadinessTerraSyncing , vaa . ChainIDTerra ) . Run , "terrawatch" ) ) ; err != nil {
2022-07-10 17:47:10 -07:00
return err
}
2020-11-16 04:28:07 -08:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( terra2WS ) {
2022-07-10 17:47:10 -07:00
logger . Info ( "Starting Terra 2 watcher" )
2022-10-20 09:43:43 -07:00
readiness . RegisterComponent ( common . ReadinessTerra2Syncing )
chainObsvReqC [ vaa . ChainIDTerra2 ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2022-07-10 17:47:10 -07:00
if err := supervisor . Run ( ctx , "terra2watch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( cosmwasm . NewWatcher ( * terra2WS , * terra2LCD , * terra2Contract , chainMsgC [ vaa . ChainIDTerra2 ] , chainObsvReqC [ vaa . ChainIDTerra2 ] , common . ReadinessTerra2Syncing , vaa . ChainIDTerra2 ) . Run , "terra2watch" ) ) ; err != nil {
2022-07-10 17:47:10 -07:00
return err
}
2022-06-22 07:29:21 -07:00
}
2022-10-20 09:43:43 -07:00
if shouldStart ( xplaWS ) {
2022-10-05 06:05:31 -07:00
logger . Info ( "Starting XPLA watcher" )
2022-10-20 09:43:43 -07:00
readiness . RegisterComponent ( common . ReadinessXplaSyncing )
chainObsvReqC [ vaa . ChainIDXpla ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2022-10-05 06:05:31 -07:00
if err := supervisor . Run ( ctx , "xplawatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( cosmwasm . NewWatcher ( * xplaWS , * xplaLCD , * xplaContract , chainMsgC [ vaa . ChainIDXpla ] , chainObsvReqC [ vaa . ChainIDXpla ] , common . ReadinessXplaSyncing , vaa . ChainIDXpla ) . Run , "xplawatch" ) ) ; err != nil {
2022-07-06 07:19:57 -07:00
return err
}
}
2022-10-20 09:43:43 -07:00
if shouldStart ( algorandIndexerRPC ) {
logger . Info ( "Starting Algorand watcher" )
readiness . RegisterComponent ( common . ReadinessAlgorandSyncing )
chainObsvReqC [ vaa . ChainIDAlgorand ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2021-12-22 08:22:04 -08:00
if err := supervisor . Run ( ctx , "algorandwatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( algorand . NewWatcher ( * algorandIndexerRPC , * algorandIndexerToken , * algorandAlgodRPC , * algorandAlgodToken , * algorandAppID , chainMsgC [ vaa . ChainIDAlgorand ] , chainObsvReqC [ vaa . ChainIDAlgorand ] ) . Run , "algorandwatch" ) ) ; err != nil {
2021-12-22 08:22:04 -08:00
return err
}
}
2022-10-20 09:43:43 -07:00
if shouldStart ( nearRPC ) {
logger . Info ( "Starting Near watcher" )
readiness . RegisterComponent ( common . ReadinessNearSyncing )
chainObsvReqC [ vaa . ChainIDNear ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2022-08-05 10:49:16 -07:00
if err := supervisor . Run ( ctx , "nearwatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( near . NewWatcher ( * nearRPC , * nearContract , chainMsgC [ vaa . ChainIDNear ] , chainObsvReqC [ vaa . ChainIDNear ] , ! ( * unsafeDevMode || * testnetMode ) ) . Run , "nearwatch" ) ) ; err != nil {
2022-08-05 10:49:16 -07:00
return err
}
}
2021-12-22 08:22:04 -08:00
2022-09-02 01:36:24 -07:00
// Start Wormchain watcher only if configured
2022-10-20 09:43:43 -07:00
if shouldStart ( wormchainWS ) {
2022-09-02 01:36:24 -07:00
logger . Info ( "Starting Wormchain watcher" )
2022-10-20 09:43:43 -07:00
readiness . RegisterComponent ( common . ReadinessWormchainSyncing )
chainObsvReqC [ vaa . ChainIDWormchain ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2022-09-02 01:36:24 -07:00
if err := supervisor . Run ( ctx , "wormchainwatch" ,
2023-01-20 13:15:13 -08:00
wormchain . NewWatcher ( * wormchainWS , * wormchainLCD , chainMsgC [ vaa . ChainIDWormchain ] , chainObsvReqC [ vaa . ChainIDWormchain ] ) . Run ) ; err != nil {
2022-09-02 01:36:24 -07:00
return err
}
}
2022-10-20 09:43:43 -07:00
if shouldStart ( aptosRPC ) {
logger . Info ( "Starting Aptos watcher" )
readiness . RegisterComponent ( common . ReadinessAptosSyncing )
chainObsvReqC [ vaa . ChainIDAptos ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2022-10-13 18:22:54 -07:00
if err := supervisor . Run ( ctx , "aptoswatch" ,
2023-01-20 13:15:13 -08:00
aptos . NewWatcher ( * aptosRPC , * aptosAccount , * aptosHandle , chainMsgC [ vaa . ChainIDAptos ] , chainObsvReqC [ vaa . ChainIDAptos ] ) . Run ) ; err != nil {
2022-10-13 18:22:54 -07:00
return err
}
}
2022-09-02 01:36:24 -07:00
2022-11-18 06:14:22 -08:00
if shouldStart ( suiRPC ) {
logger . Info ( "Starting Sui watcher" )
readiness . RegisterComponent ( common . ReadinessSuiSyncing )
chainObsvReqC [ vaa . ChainIDSui ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "suiwatch" ,
2023-01-20 13:15:13 -08:00
sui . NewWatcher ( * suiRPC , * suiWS , * suiAccount , * suiPackage , * unsafeDevMode , chainMsgC [ vaa . ChainIDSui ] , chainObsvReqC [ vaa . ChainIDSui ] ) . Run ) ; err != nil {
2022-11-18 06:14:22 -08:00
return err
}
}
2022-11-14 06:07:45 -08:00
var solanaFinalizedWatcher * solana . SolanaWatcher
2022-10-20 09:43:43 -07:00
if shouldStart ( solanaRPC ) {
logger . Info ( "Starting Solana watcher" )
readiness . RegisterComponent ( common . ReadinessSolanaSyncing )
chainObsvReqC [ vaa . ChainIDSolana ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2022-07-10 17:47:10 -07:00
if err := supervisor . Run ( ctx , "solwatch-confirmed" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( solana . NewSolanaWatcher ( * solanaRPC , nil , solAddress , * solanaContract , chainMsgC [ vaa . ChainIDSolana ] , nil , rpc . CommitmentConfirmed , common . ReadinessSolanaSyncing , vaa . ChainIDSolana ) . Run , "solwatch-confirmed" ) ) ; err != nil {
2022-07-10 17:47:10 -07:00
return err
}
2023-01-20 13:15:13 -08:00
solanaFinalizedWatcher = solana . NewSolanaWatcher ( * solanaRPC , nil , solAddress , * solanaContract , chainMsgC [ vaa . ChainIDSolana ] , chainObsvReqC [ vaa . ChainIDSolana ] , rpc . CommitmentFinalized , common . ReadinessSolanaSyncing , vaa . ChainIDSolana )
2023-01-18 08:24:55 -08:00
if err := supervisor . Run ( ctx , "solwatch-finalized" , common . WrapWithScissors ( solanaFinalizedWatcher . Run , "solwatch-finalized" ) ) ; err != nil {
2022-07-28 10:30:00 -07:00
return err
}
}
2022-10-20 09:43:43 -07:00
if shouldStart ( pythnetRPC ) {
logger . Info ( "Starting Pythnet watcher" )
readiness . RegisterComponent ( common . ReadinessPythNetSyncing )
chainObsvReqC [ vaa . ChainIDPythNet ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2022-07-28 10:30:00 -07:00
if err := supervisor . Run ( ctx , "pythwatch-confirmed" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( solana . NewSolanaWatcher ( * pythnetRPC , pythnetWS , pythnetAddress , * pythnetContract , chainMsgC [ vaa . ChainIDPythNet ] , nil , rpc . CommitmentConfirmed , common . ReadinessPythNetSyncing , vaa . ChainIDPythNet ) . Run , "pythwatch-confirmed" ) ) ; err != nil {
2022-07-10 17:47:10 -07:00
return err
}
2020-08-20 12:48:58 -07:00
}
2022-12-07 11:43:44 -08:00
if shouldStart ( injectiveWS ) {
logger . Info ( "Starting Injective watcher" )
readiness . RegisterComponent ( common . ReadinessInjectiveSyncing )
chainObsvReqC [ vaa . ChainIDInjective ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
if err := supervisor . Run ( ctx , "injectivewatch" ,
2023-01-20 13:15:13 -08:00
common . WrapWithScissors ( cosmwasm . NewWatcher ( * injectiveWS , * injectiveLCD , * injectiveContract , chainMsgC [ vaa . ChainIDInjective ] , chainObsvReqC [ vaa . ChainIDInjective ] , common . ReadinessInjectiveSyncing , vaa . ChainIDInjective ) . Run , "injectivewatch" ) ) ; err != nil {
2022-12-07 11:43:44 -08:00
return err
}
}
2022-10-20 09:43:43 -07:00
if * testnetMode {
if shouldStart ( neonRPC ) {
2022-11-14 06:07:45 -08:00
if solanaFinalizedWatcher == nil {
log . Fatalf ( "if neon is enabled then solana must also be enabled." )
}
2022-10-20 09:43:43 -07:00
logger . Info ( "Starting Neon watcher" )
readiness . RegisterComponent ( common . ReadinessNeonSyncing )
chainObsvReqC [ vaa . ChainIDNeon ] = make ( chan * gossipv1 . ObservationRequest , observationRequestBufferSize )
2023-01-20 13:15:13 -08:00
neonWatcher := evm . NewEthWatcher ( * neonRPC , neonContractAddr , "neon" , common . ReadinessNeonSyncing , vaa . ChainIDNeon , chainMsgC [ vaa . ChainIDNeon ] , nil , chainObsvReqC [ vaa . ChainIDNeon ] , * unsafeDevMode )
2022-11-14 06:07:45 -08:00
neonWatcher . SetL1Finalizer ( solanaFinalizedWatcher )
2023-01-11 11:31:02 -08:00
if err := supervisor . Run ( ctx , "neonwatch" , common . WrapWithScissors ( neonWatcher . Run , "neonwatch" ) ) ; err != nil {
2022-10-20 09:43:43 -07:00
return err
}
}
}
2023-01-20 13:15:13 -08:00
go handleReobservationRequests ( rootCtx , clock . New ( ) , logger , obsvReqReadC , chainObsvReqC )
2022-10-20 09:43:43 -07:00
2023-01-16 04:33:01 -08:00
if acct != nil {
if err := acct . Start ( ctx ) ; err != nil {
2023-01-17 05:30:50 -08:00
logger . Fatal ( "acct: failed to start accountant" , zap . Error ( err ) )
2023-01-16 04:33:01 -08:00
}
}
2022-07-19 11:08:06 -07:00
if gov != nil {
err := gov . Run ( ctx )
if err != nil {
log . Fatal ( "failed to create chain governor" , zap . Error ( err ) )
}
}
2023-01-20 13:15:13 -08:00
if err := supervisor . Run ( ctx , "processor" , processor . NewProcessor ( ctx ,
2021-07-30 13:40:01 -07:00
db ,
2023-01-20 13:15:13 -08:00
msgReadC ,
setReadC ,
gossipSendC ,
2020-11-30 08:13:48 -08:00
obsvC ,
2023-01-20 13:15:13 -08:00
obsvReqSendWriteC ,
injectReadC ,
signedInReadC ,
2020-11-30 08:13:48 -08:00
gk ,
2021-07-31 09:51:38 -07:00
gst ,
2020-11-30 08:13:48 -08:00
* unsafeDevMode ,
* devNumGuardians ,
* ethRPC ,
2022-09-02 01:36:24 -07:00
* wormchainLCD ,
2021-08-09 22:29:21 -07:00
attestationEvents ,
2021-10-05 11:13:07 -07:00
notifier ,
2022-07-19 11:08:06 -07:00
gov ,
2023-01-16 04:33:01 -08:00
acct ,
acctReadC ,
2023-01-20 13:15:13 -08:00
) . Run ) ; err != nil {
2020-08-21 15:21:41 -07:00
return err
}
2023-01-20 13:15:13 -08:00
adminService , err := adminServiceRunnable ( logger , * adminSocketPath , injectWriteC , signedInWriteC , obsvReqSendWriteC , db , gst , gov , gk , ethRPC , ethContract )
if err != nil {
logger . Fatal ( "failed to create admin service socket" , zap . Error ( err ) )
}
2020-11-19 03:53:19 -08:00
if err := supervisor . Run ( ctx , "admin" , adminService ) ; err != nil {
return err
}
2022-11-18 07:36:22 -08:00
if shouldStart ( publicGRPCSocketPath ) {
// local public grpc service socket
publicrpcUnixService , publicrpcServer , err := publicrpcUnixServiceRunnable ( logger , * publicGRPCSocketPath , db , gst , gov )
if err != nil {
logger . Fatal ( "failed to create publicrpc service socket" , zap . Error ( err ) )
2021-05-12 22:57:08 -07:00
}
2022-11-18 07:36:22 -08:00
if err := supervisor . Run ( ctx , "publicrpcsocket" , publicrpcUnixService ) ; err != nil {
2021-07-30 16:18:53 -07:00
return err
}
2022-11-18 07:36:22 -08:00
if shouldStart ( publicRPC ) {
publicrpcService , err := publicrpcTcpServiceRunnable ( logger , * publicRPC , db , gst , gov )
if err != nil {
log . Fatal ( "failed to create publicrpc tcp service" , zap . Error ( err ) )
}
if err := supervisor . Run ( ctx , "publicrpc" , publicrpcService ) ; err != nil {
return err
}
}
if shouldStart ( publicWeb ) {
publicwebService , err := publicwebServiceRunnable ( logger , * publicWeb , * publicGRPCSocketPath , publicrpcServer ,
* tlsHostname , * tlsProdEnv , path . Join ( * dataDir , "autocert" ) )
if err != nil {
log . Fatal ( "failed to create publicrpc web service" , zap . Error ( err ) )
}
if err := supervisor . Run ( ctx , "publicweb" , publicwebService ) ; err != nil {
return err
}
}
2021-07-30 16:18:53 -07:00
}
2020-11-19 03:53:19 -08:00
2021-08-09 22:29:21 -07:00
if * bigTablePersistenceEnabled {
bigTableConnection := & reporter . BigTableConnectionConfig {
GcpProjectID : * bigTableGCPProject ,
GcpInstanceName : * bigTableInstanceName ,
TableName : * bigTableTableName ,
2021-11-04 02:00:52 -07:00
TopicName : * bigTableTopicName ,
2021-08-09 22:29:21 -07:00
GcpKeyFilePath : * bigTableKeyPath ,
}
if err := supervisor . Run ( ctx , "bigtable" , reporter . BigTableWriter ( attestationEvents , bigTableConnection ) ) ; err != nil {
return err
}
}
2020-08-17 05:55:51 -07:00
logger . Info ( "Started internal services" )
2020-08-02 14:12:58 -07:00
2021-08-30 11:40:38 -07:00
<- ctx . Done ( )
return nil
2020-10-22 03:20:11 -07:00
} ,
// It's safer to crash and restart the process in case we encounter a panic,
// rather than attempting to reschedule the runnable.
supervisor . WithPropagatePanic )
2020-08-02 14:12:58 -07:00
2021-08-30 11:40:38 -07:00
<- rootCtx . Done ( )
logger . Info ( "root context cancelled, exiting..." )
// TODO: wait for things to shut down gracefully
2020-08-02 14:12:58 -07:00
}
2022-01-09 12:56:59 -08:00
func decryptTelemetryServiceAccount ( ) ( [ ] byte , error ) {
// Decrypt service account credentials
key , err := base64 . StdEncoding . DecodeString ( * telemetryKey )
if err != nil {
return nil , fmt . Errorf ( "failed to decode: %w" , err )
}
ciphertext , err := base64 . StdEncoding . DecodeString ( telemetryServiceAccount )
if err != nil {
panic ( err )
}
creds , err := common . DecryptAESGCM ( ciphertext , key )
if err != nil {
return nil , fmt . Errorf ( "failed to decrypt: %w" , err )
}
return creds , err
}
2022-10-20 09:43:43 -07:00
func shouldStart ( rpc * string ) bool {
return * rpc != "" && * rpc != "none"
}
2022-11-10 14:27:39 -08:00
func unsafeDevModeEvmContractAddress ( contractAddr string ) string {
if contractAddr != "" {
return contractAddr
}
return devnet . GanacheWormholeContractAddress . Hex ( )
}
2023-01-20 13:15:13 -08:00
func makeChannelPair [ T any ] ( cap int ) ( <- chan T , chan <- T ) {
out := make ( chan T , cap )
return out , out
}