| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013 |
- package guardiand
- import (
- "context"
- "fmt"
- "net"
- _ "net/http/pprof" // #nosec G108 we are using a custom router (`router := mux.NewRouter()`) and thus not automatically expose pprof.
- "os"
- "os/signal"
- "path"
- "runtime"
- "slices"
- "strings"
- "syscall"
- "time"
- "github.com/certusone/wormhole/node/pkg/guardiansigner"
- "github.com/certusone/wormhole/node/pkg/watchers"
- "github.com/certusone/wormhole/node/pkg/watchers/ibc"
- ethcrypto "github.com/ethereum/go-ethereum/crypto"
- "github.com/certusone/wormhole/node/pkg/watchers/cosmwasm"
- "github.com/certusone/wormhole/node/pkg/watchers/algorand"
- "github.com/certusone/wormhole/node/pkg/watchers/aptos"
- "github.com/certusone/wormhole/node/pkg/watchers/evm"
- "github.com/certusone/wormhole/node/pkg/watchers/near"
- "github.com/certusone/wormhole/node/pkg/watchers/solana"
- "github.com/certusone/wormhole/node/pkg/watchers/sui"
- "github.com/certusone/wormhole/node/pkg/wormconn"
- guardianDB "github.com/certusone/wormhole/node/pkg/db"
- "github.com/certusone/wormhole/node/pkg/telemetry"
- "github.com/certusone/wormhole/node/pkg/version"
- "github.com/gagliardetto/solana-go/rpc"
- "go.uber.org/zap/zapcore"
- "github.com/certusone/wormhole/node/pkg/common"
- "github.com/certusone/wormhole/node/pkg/devnet"
- "github.com/certusone/wormhole/node/pkg/node"
- "github.com/certusone/wormhole/node/pkg/p2p"
- "github.com/certusone/wormhole/node/pkg/supervisor"
- promremotew "github.com/certusone/wormhole/node/pkg/telemetry/prom_remote_write"
- "github.com/certusone/wormhole/node/pkg/txverifier"
- libp2p_crypto "github.com/libp2p/go-libp2p/core/crypto"
- "github.com/libp2p/go-libp2p/core/peer"
- "github.com/spf13/cobra"
- "github.com/spf13/viper"
- "github.com/wormhole-foundation/wormhole/sdk"
- "github.com/wormhole-foundation/wormhole/sdk/vaa"
- "go.uber.org/zap"
- ipfslog "github.com/ipfs/go-log/v2"
- )
- var (
- p2pNetworkID *string
- p2pPort *uint
- p2pBootstrap *string
- protectedPeers []string
- additionalPublishers *[]string
- nodeKeyPath *string
- adminSocketPath *string
- publicGRPCSocketPath *string
- dataDir *string
- statusAddr *string
- guardianKeyPath *string
- guardianSignerUri *string
- ethRPC *string
- ethContract *string
- bscRPC *string
- bscContract *string
- polygonRPC *string
- polygonContract *string
- fantomRPC *string
- fantomContract *string
- avalancheRPC *string
- avalancheContract *string
- klaytnRPC *string
- klaytnContract *string
- celoRPC *string
- celoContract *string
- moonbeamRPC *string
- moonbeamContract *string
- terraWS *string
- terraLCD *string
- terraContract *string
- terra2WS *string
- terra2LCD *string
- terra2Contract *string
- injectiveWS *string
- injectiveLCD *string
- injectiveContract *string
- gatewayWS *string
- gatewayLCD *string
- gatewayContract *string
- algorandIndexerRPC *string
- algorandIndexerToken *string
- algorandAlgodRPC *string
- algorandAlgodToken *string
- algorandAppID *uint64
- nearRPC *string
- nearContract *string
- wormchainURL *string
- ibcWS *string
- ibcLCD *string
- ibcBlockHeightURL *string
- ibcContract *string
- accountantContract *string
- accountantWS *string
- accountantCheckEnabled *bool
- accountantKeyPath *string
- accountantKeyPassPhrase *string
- accountantNttContract *string
- accountantNttKeyPath *string
- accountantNttKeyPassPhrase *string
- aptosRPC *string
- aptosAccount *string
- aptosHandle *string
- movementRPC *string
- movementAccount *string
- movementHandle *string
- suiRPC *string
- suiMoveEventType *string
- solanaRPC *string
- solanaContract *string
- solanaShimContract *string
- fogoRPC *string
- fogoContract *string
- fogoShimContract *string
- pythnetContract *string
- pythnetRPC *string
- pythnetWS *string
- arbitrumRPC *string
- arbitrumContract *string
- optimismRPC *string
- optimismContract *string
- baseRPC *string
- baseContract *string
- scrollRPC *string
- scrollContract *string
- mantleRPC *string
- mantleContract *string
- xlayerRPC *string
- xlayerContract *string
- lineaRPC *string
- lineaContract *string
- berachainRPC *string
- berachainContract *string
- unichainRPC *string
- unichainContract *string
- worldchainRPC *string
- worldchainContract *string
- monadRPC *string
- monadContract *string
- inkRPC *string
- inkContract *string
- hyperEvmRPC *string
- hyperEvmContract *string
- seiEvmRPC *string
- seiEvmContract *string
- mezoRPC *string
- mezoContract *string
- convergeRPC *string
- convergeContract *string
- plumeRPC *string
- plumeContract *string
- xrplEvmRPC *string
- xrplEvmContract *string
- plasmaRPC *string
- plasmaContract *string
- creditCoinRPC *string
- creditCoinContract *string
- mocaRPC *string
- mocaContract *string
- sepoliaRPC *string
- sepoliaContract *string
- holeskyRPC *string
- holeskyContract *string
- arbitrumSepoliaRPC *string
- arbitrumSepoliaContract *string
- baseSepoliaRPC *string
- baseSepoliaContract *string
- optimismSepoliaRPC *string
- optimismSepoliaContract *string
- polygonSepoliaRPC *string
- polygonSepoliaContract *string
- logLevel *string
- publicRpcLogDetailStr *string
- publicRpcLogToTelemetry *bool
- unsafeDevMode *bool
- testnetMode *bool
- nodeName *string
- publicRPC *string
- publicWeb *string
- tlsHostname *string
- tlsProdEnv *bool
- disableHeartbeatVerify *bool
- disableTelemetry *bool
- // Loki cloud logging parameters
- telemetryLokiURL *string
- // Prometheus remote write URL
- promRemoteURL *string
- chainGovernorEnabled *bool
- governorFlowCancelEnabled *bool
- coinGeckoApiKey *string
- ccqEnabled *bool
- ccqAllowedRequesters *string
- ccqP2pPort *uint
- ccqP2pBootstrap *string
- ccqProtectedPeers []string
- ccqAllowedPeers *string
- ccqBackfillCache *bool
- gatewayRelayerContract *string
- gatewayRelayerKeyPath *string
- gatewayRelayerKeyPassPhrase *string
- // This is the externally reachable address advertised over gossip for guardian p2p and ccq p2p.
- gossipAdvertiseAddress *string
- // env is the mode we are running in, Mainnet, Testnet or UnsafeDevnet.
- env common.Environment
- subscribeToVAAs *bool
- // A list of chain IDs that should enable the Transfer Verifier. If empty, Transfer Verifier will not be enabled.
- transferVerifierEnabledChainIDs *[]uint
- // Global variable used to store enabled Chain IDs for Transfer Verification. Contents are parsed from
- // transferVerifierEnabledChainIDs.
- txVerifierChains []vaa.ChainID
- // featureFlags are additional static flags that should be published in P2P heartbeats.
- featureFlags []string
- notaryEnabled *bool
- )
- func init() {
- 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 (optional for mainnet or testnet, overrides default, required for unsafeDevMode)")
- NodeCmd.Flags().StringSliceVarP(&protectedPeers, "protectedPeers", "", []string{}, "")
- additionalPublishers = NodeCmd.Flags().StringArray("additionalPublishEndpoint", []string{}, "defines an alternate publisher as label;url;delay;chains where delay and chains are optional")
- statusAddr = NodeCmd.Flags().String("statusAddr", "[::]:6060", "Listen address for status server (disabled if blank)")
- nodeKeyPath = NodeCmd.Flags().String("nodeKey", "", "Path to node key (will be generated if it doesn't exist)")
- adminSocketPath = NodeCmd.Flags().String("adminSocket", "", "Admin gRPC service UNIX domain socket path")
- publicGRPCSocketPath = NodeCmd.Flags().String("publicGRPCSocket", "", "Public gRPC service UNIX domain socket path")
- dataDir = NodeCmd.Flags().String("dataDir", "", "Data directory")
- guardianKeyPath = NodeCmd.Flags().String("guardianKey", "", "Path to guardian key")
- guardianSignerUri = NodeCmd.Flags().String("guardianSignerUri", "", "Guardian signer URI")
- solanaContract = NodeCmd.Flags().String("solanaContract", "", "Address of the Solana program (required if solanaRpc is specified)")
- solanaShimContract = NodeCmd.Flags().String("solanaShimContract", "", "Address of the Solana shim program")
- fogoContract = NodeCmd.Flags().String("fogoContract", "", "Address of the Fogo program (required if fogoRpc is specified)")
- fogoShimContract = NodeCmd.Flags().String("fogoShimContract", "", "Address of the Fogo shim program")
- ethRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "ethRPC", "Ethereum RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- ethContract = NodeCmd.Flags().String("ethContract", "", "Ethereum contract address")
- bscRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "bscRPC", "Binance Smart Chain RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- bscContract = NodeCmd.Flags().String("bscContract", "", "Binance Smart Chain contract address")
- polygonRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "polygonRPC", "Polygon RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- polygonContract = NodeCmd.Flags().String("polygonContract", "", "Polygon contract address")
- avalancheRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "avalancheRPC", "Avalanche RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- avalancheContract = NodeCmd.Flags().String("avalancheContract", "", "Avalanche contract address")
- fantomRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "fantomRPC", "Fantom Websocket RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- fantomContract = NodeCmd.Flags().String("fantomContract", "", "Fantom contract address")
- klaytnRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "klaytnRPC", "Klaytn RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- klaytnContract = NodeCmd.Flags().String("klaytnContract", "", "Klaytn contract address")
- celoRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "celoRPC", "Celo RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- celoContract = NodeCmd.Flags().String("celoContract", "", "Celo contract address")
- moonbeamRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "moonbeamRPC", "Moonbeam RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- moonbeamContract = NodeCmd.Flags().String("moonbeamContract", "", "Moonbeam contract address")
- terraWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "terraWS", "Path to terrad root for websocket connection", "ws://terra-terrad:26657/websocket", []string{"ws", "wss"})
- terraLCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "terraLCD", "Path to LCD service root for http calls", "http://terra-terrad:1317", []string{"http", "https"})
- terraContract = NodeCmd.Flags().String("terraContract", "", "Wormhole contract address on Terra blockchain")
- terra2WS = node.RegisterFlagWithValidationOrFail(NodeCmd, "terra2WS", "Path to terrad root for websocket connection", "ws://terra2-terrad:26657/websocket", []string{"ws", "wss"})
- terra2LCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "terra2LCD", "Path to LCD service root for http calls", "http://terra2-terrad:1317", []string{"http", "https"})
- terra2Contract = NodeCmd.Flags().String("terra2Contract", "", "Wormhole contract address on Terra 2 blockchain")
- injectiveWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "injectiveWS", "Path to root for Injective websocket connection", "ws://injective:26657/websocket", []string{"ws", "wss"})
- injectiveLCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "injectiveLCD", "Path to LCD service root for Injective http calls", "http://injective:1317", []string{"http", "https"})
- injectiveContract = NodeCmd.Flags().String("injectiveContract", "", "Wormhole contract address on Injective blockchain")
- gatewayWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "gatewayWS", "Path to root for Gateway watcher websocket connection", "ws://wormchain:26657/websocket", []string{"ws", "wss"})
- gatewayLCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "gatewayLCD", "Path to LCD service root for Gateway watcher http calls", "http://wormchain:1317", []string{"http", "https"})
- gatewayContract = NodeCmd.Flags().String("gatewayContract", "", "Wormhole contract address on Gateway blockchain")
- algorandIndexerRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "algorandIndexerRPC", "Algorand Indexer RPC URL", "http://algorand:8980", []string{"http", "https"})
- algorandIndexerToken = NodeCmd.Flags().String("algorandIndexerToken", "", "Algorand Indexer access token")
- algorandAlgodRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "algorandAlgodRPC", "Algorand Algod RPC URL", "http://algorand:4001", []string{"http", "https"})
- algorandAlgodToken = NodeCmd.Flags().String("algorandAlgodToken", "", "Algorand Algod access token")
- algorandAppID = NodeCmd.Flags().Uint64("algorandAppID", 0, "Algorand app id")
- nearRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "nearRPC", "Near RPC URL", "http://near:3030", []string{"http", "https"})
- nearContract = NodeCmd.Flags().String("nearContract", "", "Near contract")
- wormchainURL = node.RegisterFlagWithValidationOrFail(NodeCmd, "wormchainURL", "Wormhole-chain gRPC URL", "wormchain:9090", []string{""})
- ibcWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "ibcWS", "Websocket used to listen to the IBC receiver smart contract on wormchain", "ws://wormchain:26657/websocket", []string{"ws", "wss"})
- ibcLCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "ibcLCD", "Path to LCD service root for http calls", "http://wormchain:1317", []string{"http", "https"})
- ibcBlockHeightURL = node.RegisterFlagWithValidationOrFail(NodeCmd, "ibcBlockHeightURL", "Optional URL to query for the block height (generated from ibcWS if not specified)", "http://wormchain:1317", []string{"http", "https"})
- ibcContract = NodeCmd.Flags().String("ibcContract", "", "Address of the IBC smart contract on wormchain")
- accountantWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "accountantWS", "Websocket used to listen to the accountant smart contract on wormchain", "http://wormchain:26657", []string{"http", "https"})
- accountantContract = NodeCmd.Flags().String("accountantContract", "", "Address of the accountant smart contract on wormchain")
- accountantKeyPath = NodeCmd.Flags().String("accountantKeyPath", "", "path to accountant private key for signing transactions")
- accountantKeyPassPhrase = NodeCmd.Flags().String("accountantKeyPassPhrase", "", "pass phrase used to unarmor the accountant key file")
- accountantCheckEnabled = NodeCmd.Flags().Bool("accountantCheckEnabled", false, "Should accountant be enforced on transfers")
- accountantNttContract = NodeCmd.Flags().String("accountantNttContract", "", "Address of the NTT accountant smart contract on wormchain")
- accountantNttKeyPath = NodeCmd.Flags().String("accountantNttKeyPath", "", "path to NTT accountant private key for signing transactions")
- accountantNttKeyPassPhrase = NodeCmd.Flags().String("accountantNttKeyPassPhrase", "", "pass phrase used to unarmor the NTT accountant key file")
- aptosRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "aptosRPC", "Aptos RPC URL", "http://aptos:8080", []string{"http", "https"})
- aptosAccount = NodeCmd.Flags().String("aptosAccount", "", "aptos account")
- aptosHandle = NodeCmd.Flags().String("aptosHandle", "", "aptos handle")
- movementRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "movementRPC", "Movement RPC URL", "", []string{"http", "https"})
- movementAccount = NodeCmd.Flags().String("movementAccount", "", "movement account")
- movementHandle = NodeCmd.Flags().String("movementHandle", "", "movement handle")
- suiRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "suiRPC", "Sui RPC URL", "http://sui:9000", []string{"http", "https"})
- suiMoveEventType = NodeCmd.Flags().String("suiMoveEventType", "", "Sui move event type for publish_message")
- solanaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "solanaRPC", "Solana RPC URL (required)", "http://solana-devnet:8899", []string{"http", "https"})
- fogoRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "fogoRPC", "Fogo RPC URL (required)", "http://solana-devnet:8899", []string{"http", "https"})
- pythnetContract = NodeCmd.Flags().String("pythnetContract", "", "Address of the PythNet program (required)")
- pythnetRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "pythnetRPC", "PythNet RPC URL (required)", "http://pythnet.rpcpool.com", []string{"http", "https"})
- pythnetWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "pythnetWS", "PythNet WS URL", "wss://pythnet.rpcpool.com", []string{"ws", "wss"})
- arbitrumRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "arbitrumRPC", "Arbitrum RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- arbitrumContract = NodeCmd.Flags().String("arbitrumContract", "", "Arbitrum contract address")
- sepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "sepoliaRPC", "Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- sepoliaContract = NodeCmd.Flags().String("sepoliaContract", "", "Sepolia contract address")
- holeskyRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "holeskyRPC", "Holesky RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- holeskyContract = NodeCmd.Flags().String("holeskyContract", "", "Holesky contract address")
- optimismRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "optimismRPC", "Optimism RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- optimismContract = NodeCmd.Flags().String("optimismContract", "", "Optimism contract address")
- scrollRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "scrollRPC", "Scroll RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- scrollContract = NodeCmd.Flags().String("scrollContract", "", "Scroll contract address")
- mantleRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "mantleRPC", "Mantle RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- mantleContract = NodeCmd.Flags().String("mantleContract", "", "Mantle contract address")
- xlayerRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "xlayerRPC", "XLayer RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- xlayerContract = NodeCmd.Flags().String("xlayerContract", "", "XLayer contract address")
- lineaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "lineaRPC", "Linea RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- lineaContract = NodeCmd.Flags().String("lineaContract", "", "Linea contract address")
- berachainRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "berachainRPC", "Berachain RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- berachainContract = NodeCmd.Flags().String("berachainContract", "", "Berachain contract address")
- unichainRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "unichainRPC", "Unichain RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- unichainContract = NodeCmd.Flags().String("unichainContract", "", "Unichain contract address")
- worldchainRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "worldchainRPC", "Worldchain RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- worldchainContract = NodeCmd.Flags().String("worldchainContract", "", "Worldchain contract address")
- baseRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "baseRPC", "Base RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- baseContract = NodeCmd.Flags().String("baseContract", "", "Base contract address")
- inkRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "inkRPC", "Ink RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- inkContract = NodeCmd.Flags().String("inkContract", "", "Ink contract address")
- hyperEvmRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "hyperEvmRPC", "HyperEVM RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- hyperEvmContract = NodeCmd.Flags().String("hyperEvmContract", "", "HyperEVM contract address")
- monadRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "monadRPC", "Monad RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- monadContract = NodeCmd.Flags().String("monadContract", "", "Monad contract address")
- seiEvmRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "seiEvmRPC", "SeiEVM RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- seiEvmContract = NodeCmd.Flags().String("seiEvmContract", "", "SeiEVM contract address")
- mezoRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "mezoRPC", "Mezo RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- mezoContract = NodeCmd.Flags().String("mezoContract", "", "Mezo contract address")
- convergeRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "convergeRPC", "converge RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- convergeContract = NodeCmd.Flags().String("convergeContract", "", "Converge contract address")
- plumeRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "plumeRPC", "Plume RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- plumeContract = NodeCmd.Flags().String("plumeContract", "", "Plume contract address")
- xrplEvmRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "xrplEvmRPC", "XRPLEVM RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- xrplEvmContract = NodeCmd.Flags().String("xrplEvmContract", "", "XRPLEVM contract address")
- plasmaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "plasmaRPC", "PLASMA RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- plasmaContract = NodeCmd.Flags().String("plasmaContract", "", "Plasma contract address")
- creditCoinRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "creditCoinRPC", "CREDITCOIN RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- creditCoinContract = NodeCmd.Flags().String("creditCoinContract", "", "CreditCoin contract address")
- mocaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "MocaRPC", "Moca RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- mocaContract = NodeCmd.Flags().String("mocaContract", "", "Moca contract address")
- arbitrumSepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "arbitrumSepoliaRPC", "Arbitrum on Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- arbitrumSepoliaContract = NodeCmd.Flags().String("arbitrumSepoliaContract", "", "Arbitrum on Sepolia contract address")
- baseSepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "baseSepoliaRPC", "Base on Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- baseSepoliaContract = NodeCmd.Flags().String("baseSepoliaContract", "", "Base on Sepolia contract address")
- optimismSepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "optimismSepoliaRPC", "Optimism on Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- optimismSepoliaContract = NodeCmd.Flags().String("optimismSepoliaContract", "", "Optimism on Sepolia contract address")
- polygonSepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "polygonSepoliaRPC", "Polygon on Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
- polygonSepoliaContract = NodeCmd.Flags().String("polygonSepoliaContract", "", "Polygon on Sepolia contract address")
- logLevel = NodeCmd.Flags().String("logLevel", "info", "Logging level (debug, info, warn, error, dpanic, panic, fatal)")
- publicRpcLogDetailStr = NodeCmd.Flags().String("publicRpcLogDetail", "full", "The detail with which public RPC requests shall be logged (none=no logging, minimal=only log gRPC methods, full=log gRPC method, payload (up to 200 bytes) and user agent (up to 200 bytes))")
- publicRpcLogToTelemetry = NodeCmd.Flags().Bool("logPublicRpcToTelemetry", true, "whether or not to include publicRpc request logs in telemetry")
- unsafeDevMode = NodeCmd.Flags().Bool("unsafeDevMode", false, "Launch node in unsafe, deterministic devnet mode")
- testnetMode = NodeCmd.Flags().Bool("testnetMode", false, "Launch node in testnet mode (enables testnet-only features)")
- nodeName = NodeCmd.Flags().String("nodeName", "", "Node name to announce in gossip heartbeats")
- 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")
- tlsHostname = NodeCmd.Flags().String("tlsHostname", "", "If set, serve publicWeb as TLS with this hostname using Let's Encrypt")
- tlsProdEnv = NodeCmd.Flags().Bool("tlsProdEnv", false,
- "Use the production Let's Encrypt environment instead of staging")
- disableHeartbeatVerify = NodeCmd.Flags().Bool("disableHeartbeatVerify", false,
- "Disable heartbeat signature verification (useful during network startup)")
- disableTelemetry = NodeCmd.Flags().Bool("disableTelemetry", false,
- "Disable telemetry")
- telemetryLokiURL = NodeCmd.Flags().String("telemetryLokiURL", "", "Loki cloud logging URL")
- promRemoteURL = NodeCmd.Flags().String("promRemoteURL", "", "Prometheus remote write URL (Grafana)")
- chainGovernorEnabled = NodeCmd.Flags().Bool("chainGovernorEnabled", false, "Run the chain governor")
- governorFlowCancelEnabled = NodeCmd.Flags().Bool("governorFlowCancelEnabled", false, "Enable flow cancel on the governor")
- coinGeckoApiKey = NodeCmd.Flags().String("coinGeckoApiKey", "", "CoinGecko Pro API key. If no API key is provided, CoinGecko requests may be throttled or blocked.")
- 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 (optional for mainnet or testnet, overrides default, required for unsafeDevMode)")
- NodeCmd.Flags().StringSliceVarP(&ccqProtectedPeers, "ccqProtectedPeers", "", []string{}, "")
- 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")
- gossipAdvertiseAddress = NodeCmd.Flags().String("gossipAdvertiseAddress", "", "External IP to advertize on Guardian and CCQ p2p (use if behind a NAT or running in k8s)")
- gatewayRelayerContract = NodeCmd.Flags().String("gatewayRelayerContract", "", "Address of the smart contract on wormchain to receive relayed VAAs")
- gatewayRelayerKeyPath = NodeCmd.Flags().String("gatewayRelayerKeyPath", "", "Path to gateway relayer private key for signing transactions")
- gatewayRelayerKeyPassPhrase = NodeCmd.Flags().String("gatewayRelayerKeyPassPhrase", "", "Pass phrase used to unarmor the gateway relayer key file")
- subscribeToVAAs = NodeCmd.Flags().Bool("subscribeToVAAs", false, "Guardiand should subscribe to incoming signed VAAs, set to true if running a public RPC node")
- transferVerifierEnabledChainIDs = NodeCmd.Flags().UintSlice("transferVerifierEnabledChainIDs", make([]uint, 0), "Transfer Verifier will be enabled for these chain IDs (comma-separated)")
- notaryEnabled = NodeCmd.Flags().Bool("notaryEnabled", false, "Run the notary")
- }
- var (
- rootCtx context.Context
- rootCtxCancel context.CancelFunc
- )
- const envPrefix = "GUARDIAND"
- // "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 |
- | |
- | Do not use --unsafeDevMode in prod. |
- +++++++++++++++++++++++++++++++++++++++++++++++++++
- `
- // NodeCmd represents the node command
- var NodeCmd = &cobra.Command{
- Use: "node",
- Short: "Run the guardiand node",
- PersistentPreRunE: initConfig,
- Run: runNode,
- }
- // 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"
- // initConfig initializes the file configuration.
- func initConfig(cmd *cobra.Command, args []string) error {
- return node.InitFileConfig(cmd, node.ConfigOptions{
- FilePath: viper.ConfigFileUsed(),
- EnvPrefix: envPrefix,
- })
- }
- func runNode(cmd *cobra.Command, args []string) {
- if *unsafeDevMode && *testnetMode {
- fmt.Println("Cannot be in unsafeDevMode and testnetMode at the same time.")
- }
- // Determine execution mode
- if *unsafeDevMode {
- env = common.UnsafeDevNet
- } else if *testnetMode {
- env = common.TestNet
- } else {
- env = common.MainNet
- }
- if Build == "dev" && env != common.UnsafeDevNet {
- fmt.Println("This is a development build. --unsafeDevMode must be enabled.")
- os.Exit(1)
- }
- if env == common.UnsafeDevNet {
- fmt.Print(devwarning)
- }
- if env != common.MainNet {
- fmt.Println("Not locking in memory.")
- } else {
- common.LockMemory()
- }
- common.SetRestrictiveUmask()
- // Refuse to run as root in production mode.
- if env != common.UnsafeDevNet && os.Geteuid() == 0 {
- fmt.Println("can't run as uid 0")
- os.Exit(1)
- }
- // 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)
- }
- if !(*chainGovernorEnabled) && *governorFlowCancelEnabled {
- fmt.Println("Flow cancel can only be enabled when the governor is enabled")
- os.Exit(1)
- }
- logger := zap.New(zapcore.NewCore(
- consoleEncoder{zapcore.NewConsoleEncoder(
- zap.NewDevelopmentEncoderConfig())},
- zapcore.AddSync(zapcore.Lock(os.Stderr)),
- zap.NewAtomicLevelAt(zapcore.Level(lvl))))
- if env == common.UnsafeDevNet {
- // 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)
- }
- // Override the default go-log config, which uses a magic environment variable.
- logger.Info("setting level for all loggers", zap.String("level", logger.Level().String()))
- ipfslog.SetAllLoggers(lvl)
- if viper.ConfigFileUsed() != "" {
- logger.Info("loaded config file", zap.String("filePath", viper.ConfigFileUsed()))
- }
- // In devnet mode, we automatically set a number of flags that rely on deterministic keys.
- if env == common.UnsafeDevNet {
- g0key, err := peer.IDFromPrivateKey(devnet.DeterministicP2PPrivKeyByIndex(0))
- if err != nil {
- panic(err)
- }
- // Use the first guardian node as bootstrap
- 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)
- }
- } 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
- if *nodeName == "" && env == common.MainNet {
- logger.Fatal("Please specify --nodeName")
- }
- if *nodeKeyPath == "" && env != common.UnsafeDevNet { // In devnet mode, keys are deterministically generated.
- logger.Fatal("Please specify --nodeKey")
- }
- if *guardianKeyPath == "" {
- // This if-statement is nested, since checking if both are empty at once will always result in the else-branch
- // being executed if at least one is specified. For example, in the case where the signer URI is specified and
- // the guardianKeyPath not, then the else-statement will create an empty `file://` URI.
- if *guardianSignerUri == "" {
- logger.Fatal("Please specify --guardianKey or --guardianSignerUri")
- }
- } else {
- // To avoid confusion, require that only guardianKey or guardianSignerUri can be specified
- if *guardianSignerUri != "" {
- logger.Fatal("Please only specify --guardianKey or --guardianSignerUri")
- }
- // If guardianKeyPath is set, set guardianSignerUri to the file signer URI, pointing to guardianKeyPath.
- // This ensures that the signer-abstracted guardian has backwards compatibility with guardians that would
- // just like to ignore the new guardianSignerUri altogether.
- *guardianSignerUri = fmt.Sprintf("file://%s", *guardianKeyPath)
- }
- if *adminSocketPath == "" {
- logger.Fatal("Please specify --adminSocket")
- }
- 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")
- }
- if *dataDir == "" {
- logger.Fatal("Please specify --dataDir")
- }
- // Ethereum is required since we use it to get the guardian set. All other chains are optional.
- if *ethRPC == "" {
- logger.Fatal("Please specify --ethRPC")
- }
- // In devnet mode, we generate a deterministic guardian key and write it to disk.
- if env == common.UnsafeDevNet {
- // Only if the signer is file-based should we generate the deterministic key and write it to disk
- if st, _, _ := guardiansigner.ParseSignerUri(*guardianSignerUri); st == guardiansigner.FileSignerType {
- err := devnet.GenerateAndStoreDevnetGuardianKey(*guardianKeyPath)
- if err != nil {
- logger.Fatal("failed to generate devnet guardian key", zap.Error(err))
- }
- }
- }
- // Node's main lifecycle context.
- rootCtx, rootCtxCancel = context.WithCancel(context.Background())
- defer rootCtxCancel()
- // Create the Guardian Signer
- guardianSigner, err := guardiansigner.NewGuardianSignerFromUri(rootCtx, *guardianSignerUri, env == common.UnsafeDevNet)
- if err != nil {
- logger.Fatal("failed to create a new guardian signer", zap.Error(err))
- }
- logger.Info("Created the guardian signer", zap.String(
- "address", ethcrypto.PubkeyToAddress(guardianSigner.PublicKey(rootCtx)).String()))
- // Load p2p private key
- var p2pKey libp2p_crypto.PrivKey
- if env == common.UnsafeDevNet {
- idx, err := devnet.GetDevnetIndex()
- if err != nil {
- logger.Fatal("Failed to parse hostname - are we running in devnet?")
- }
- p2pKey = devnet.DeterministicP2PPrivKeyByIndex(int64(idx))
- if idx != 0 {
- firstGuardianName, err := devnet.GetFirstGuardianNameFromBootstrapPeers(*p2pBootstrap)
- if err != nil {
- logger.Fatal("failed to get first guardian name from bootstrap peers", zap.String("bootstrapPeers", *p2pBootstrap), zap.Error(err))
- }
- // try to connect to guardian-0
- for {
- //nolint:noctx // TODO: this should be refactored to use context.
- _, err := net.LookupIP(firstGuardianName)
- if err == nil {
- break
- }
- logger.Info(fmt.Sprintf("Error resolving %s. Trying again...", firstGuardianName))
- time.Sleep(time.Second)
- }
- // TODO this is a hack. If this is not the bootstrap Guardian, we wait 10s such that the bootstrap Guardian has enough time to start.
- // This may no longer be necessary because now the p2p.go ensures that it can connect to at least one bootstrap peer and will
- // exit the whole guardian if it is unable to. Sleeping here for a bit may reduce overall startup time by preventing unnecessary restarts, though.
- logger.Info("This is not a bootstrap Guardian. Waiting another 10 seconds for the bootstrap guardian to come online.")
- time.Sleep(time.Second * 10)
- }
- } else {
- p2pKey, err = common.GetOrCreateNodeKey(logger, *nodeKeyPath)
- if err != nil {
- logger.Fatal("Failed to load node key", zap.Error(err))
- }
- }
- // Set up telemetry if it is enabled. We can't do this until we have the p2p key and the guardian key.
- // Telemetry is enabled by default in mainnet/testnet. In devnet it is disabled by default.
- usingLoki := *telemetryLokiURL != ""
- if !*disableTelemetry && (env != common.UnsafeDevNet || (env == common.UnsafeDevNet && usingLoki)) {
- if !usingLoki {
- logger.Fatal("Please specify --telemetryLokiURL or set --disableTelemetry=false")
- }
- if *nodeName == "" {
- logger.Fatal("If telemetry is enabled, --nodeName must be set")
- }
- // Get libp2p peer ID from private key
- pk := p2pKey.GetPublic()
- peerID, err := peer.IDFromPublicKey(pk)
- if err != nil {
- logger.Fatal("Failed to get peer ID from private key", zap.Error(err))
- }
- labels := map[string]string{
- "node_name": *nodeName,
- "node_key": peerID.String(),
- "guardian_addr": ethcrypto.PubkeyToAddress(guardianSigner.PublicKey(rootCtx)).String(),
- "network": *p2pNetworkID,
- "version": version.Version(),
- }
- skipPrivateLogs := !*publicRpcLogToTelemetry
- var tm *telemetry.Telemetry
- if usingLoki {
- logger.Info("Using Loki telemetry logger",
- zap.String("publicRpcLogDetail", *publicRpcLogDetailStr),
- zap.Bool("logPublicRpcToTelemetry", *publicRpcLogToTelemetry))
- tm, err = telemetry.NewLokiCloudLogger(context.Background(), logger, *telemetryLokiURL, "wormhole", skipPrivateLogs, labels)
- if err != nil {
- logger.Fatal("Failed to initialize telemetry", zap.Error(err))
- }
- }
- defer tm.Close()
- logger = tm.WrapLogger(logger) // Wrap logger with telemetry logger
- }
- // Validate the args for all the EVM chains. The last flag indicates if the chain is allowed in mainnet.
- *ethContract = checkEvmArgs(logger, *ethRPC, *ethContract, vaa.ChainIDEthereum)
- *bscContract = checkEvmArgs(logger, *bscRPC, *bscContract, vaa.ChainIDBSC)
- *polygonContract = checkEvmArgs(logger, *polygonRPC, *polygonContract, vaa.ChainIDPolygon)
- *avalancheContract = checkEvmArgs(logger, *avalancheRPC, *avalancheContract, vaa.ChainIDAvalanche)
- *fantomContract = checkEvmArgs(logger, *fantomRPC, *fantomContract, vaa.ChainIDFantom)
- *klaytnContract = checkEvmArgs(logger, *klaytnRPC, *klaytnContract, vaa.ChainIDKlaytn)
- *celoContract = checkEvmArgs(logger, *celoRPC, *celoContract, vaa.ChainIDCelo)
- *moonbeamContract = checkEvmArgs(logger, *moonbeamRPC, *moonbeamContract, vaa.ChainIDMoonbeam)
- *arbitrumContract = checkEvmArgs(logger, *arbitrumRPC, *arbitrumContract, vaa.ChainIDArbitrum)
- *optimismContract = checkEvmArgs(logger, *optimismRPC, *optimismContract, vaa.ChainIDOptimism)
- *baseContract = checkEvmArgs(logger, *baseRPC, *baseContract, vaa.ChainIDBase)
- *scrollContract = checkEvmArgs(logger, *scrollRPC, *scrollContract, vaa.ChainIDScroll)
- *mantleContract = checkEvmArgs(logger, *mantleRPC, *mantleContract, vaa.ChainIDMantle)
- *xlayerContract = checkEvmArgs(logger, *xlayerRPC, *xlayerContract, vaa.ChainIDXLayer)
- *lineaContract = checkEvmArgs(logger, *lineaRPC, *lineaContract, vaa.ChainIDLinea)
- *berachainContract = checkEvmArgs(logger, *berachainRPC, *berachainContract, vaa.ChainIDBerachain)
- *unichainContract = checkEvmArgs(logger, *unichainRPC, *unichainContract, vaa.ChainIDUnichain)
- *worldchainContract = checkEvmArgs(logger, *worldchainRPC, *worldchainContract, vaa.ChainIDWorldchain)
- *inkContract = checkEvmArgs(logger, *inkRPC, *inkContract, vaa.ChainIDInk)
- *hyperEvmContract = checkEvmArgs(logger, *hyperEvmRPC, *hyperEvmContract, vaa.ChainIDHyperEVM)
- *monadContract = checkEvmArgs(logger, *monadRPC, *monadContract, vaa.ChainIDMonad)
- *seiEvmContract = checkEvmArgs(logger, *seiEvmRPC, *seiEvmContract, vaa.ChainIDSeiEVM)
- *mezoContract = checkEvmArgs(logger, *mezoRPC, *mezoContract, vaa.ChainIDMezo)
- *convergeContract = checkEvmArgs(logger, *convergeRPC, *convergeContract, vaa.ChainIDConverge)
- *plumeContract = checkEvmArgs(logger, *plumeRPC, *plumeContract, vaa.ChainIDPlume)
- *xrplEvmContract = checkEvmArgs(logger, *xrplEvmRPC, *xrplEvmContract, vaa.ChainIDXRPLEVM)
- *plasmaContract = checkEvmArgs(logger, *plasmaRPC, *plasmaContract, vaa.ChainIDPlasma)
- *creditCoinContract = checkEvmArgs(logger, *creditCoinRPC, *creditCoinContract, vaa.ChainIDCreditCoin)
- *mocaContract = checkEvmArgs(logger, *mocaRPC, *mocaContract, vaa.ChainIDMoca)
- // These chains will only ever be testnet / devnet.
- *sepoliaContract = checkEvmArgs(logger, *sepoliaRPC, *sepoliaContract, vaa.ChainIDSepolia)
- *arbitrumSepoliaContract = checkEvmArgs(logger, *arbitrumSepoliaRPC, *arbitrumSepoliaContract, vaa.ChainIDArbitrumSepolia)
- *baseSepoliaContract = checkEvmArgs(logger, *baseSepoliaRPC, *baseSepoliaContract, vaa.ChainIDBaseSepolia)
- *optimismSepoliaContract = checkEvmArgs(logger, *optimismSepoliaRPC, *optimismSepoliaContract, vaa.ChainIDOptimismSepolia)
- *holeskyContract = checkEvmArgs(logger, *holeskyRPC, *holeskyContract, vaa.ChainIDHolesky)
- *polygonSepoliaContract = checkEvmArgs(logger, *polygonSepoliaRPC, *polygonSepoliaContract, vaa.ChainIDPolygonSepolia)
- if !argsConsistent([]string{*solanaContract, *solanaRPC}) {
- logger.Fatal("Both --solanaContract and --solanaRPC must be set or both unset")
- }
- if *solanaShimContract != "" && *solanaContract == "" {
- logger.Fatal("--solanaShimContract may only be specified if --solanaContract is specified")
- }
- if !argsConsistent([]string{*fogoContract, *fogoRPC}) {
- logger.Fatal("Both --fogoContract and --fogoRPC must be set or both unset")
- }
- if *fogoShimContract != "" && *fogoContract == "" {
- logger.Fatal("--fogoShimContract may only be specified if --fogoContract is specified")
- }
- if !argsConsistent([]string{*pythnetContract, *pythnetRPC, *pythnetWS}) {
- logger.Fatal("Either --pythnetContract, --pythnetRPC and --pythnetWS must all be set or all unset")
- }
- if !argsConsistent([]string{*terraContract, *terraWS, *terraLCD}) {
- logger.Fatal("Either --terraContract, --terraWS and --terraLCD must all be set or all unset")
- }
- if !argsConsistent([]string{*terra2Contract, *terra2WS, *terra2LCD}) {
- logger.Fatal("Either --terra2Contract, --terra2WS and --terra2LCD must all be set or all unset")
- }
- if !argsConsistent([]string{*injectiveContract, *injectiveWS, *injectiveLCD}) {
- logger.Fatal("Either --injectiveContract, --injectiveWS and --injectiveLCD must all be set or all unset")
- }
- if !argsConsistent([]string{*algorandIndexerRPC, *algorandAlgodRPC, *algorandAlgodToken}) {
- logger.Fatal("Either --algorandIndexerRPC, --algorandAlgodRPC and --algorandAlgodToken must all be set or all unset")
- }
- if *algorandIndexerRPC != "" {
- if *algorandAppID == 0 {
- logger.Fatal("If --algorandIndexerRPC is set, --algorandAppID must be set")
- }
- } else if *algorandAppID != 0 {
- logger.Fatal("If --algorandIndexerRPC is not set, --algorandAppID may not be set")
- }
- if !argsConsistent([]string{*nearContract, *nearRPC}) {
- logger.Fatal("Both --nearContract and --nearRPC must be set or both unset")
- }
- if !argsConsistent([]string{*aptosAccount, *aptosRPC, *aptosHandle}) {
- logger.Fatal("Either --aptosAccount, --aptosRPC and --aptosHandle must all be set or all unset")
- }
- if !argsConsistent([]string{*movementAccount, *movementRPC, *movementHandle}) {
- logger.Fatal("Either --movementAccount, --movementRPC and --movementHandle must all be set or all unset")
- }
- if !argsConsistent([]string{*suiRPC, *suiMoveEventType}) {
- logger.Fatal("Either --suiRPC and --suiMoveEventType must all be set or all unset")
- }
- if !argsConsistent([]string{*gatewayContract, *gatewayWS, *gatewayLCD}) {
- logger.Fatal("Either --gatewayContract, --gatewayWS and --gatewayLCD must all be set or all unset")
- }
- if !*chainGovernorEnabled && *coinGeckoApiKey != "" {
- logger.Fatal("If coinGeckoApiKey is set, then chainGovernorEnabled must be set")
- }
- // NOTE: If this flag isn't set, or the list is empty, Transfer Verifier should not be enabled.
- if len(*transferVerifierEnabledChainIDs) != 0 {
- var parseErr error
- // NOTE: avoid shadowing txVerifierChains here. It should refer to the global variable.
- txVerifierChains, parseErr = txverifier.ValidateChains(*transferVerifierEnabledChainIDs)
- logger.Debug("validated txVerifierChains", zap.Any("chains", txVerifierChains))
- if parseErr != nil {
- logger.Fatal("transferVerifierEnabledChainIDs input is invalid", zap.Error(parseErr))
- }
- // Format the feature string in the form "txverifier:ethereum|sui" and append it to the feature flags.
- chainNames := make([]string, 0, len(txVerifierChains))
- for _, cid := range txVerifierChains {
- chainNames = append(chainNames, cid.String())
- }
- featureFlags = append(featureFlags, fmt.Sprintf("txverifier:%s", strings.Join(chainNames, "|")))
- }
- var publicRpcLogDetail common.GrpcLogDetail
- switch *publicRpcLogDetailStr {
- case "none":
- publicRpcLogDetail = common.GrpcLogDetailNone
- case "minimal":
- publicRpcLogDetail = common.GrpcLogDetailMinimal
- case "full":
- publicRpcLogDetail = common.GrpcLogDetailFull
- default:
- logger.Fatal("--publicRpcLogDetail should be one of (none, minimal, full)")
- }
- // 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.
- //
- if strings.Contains(*ethRPC, "mainnet.infura.io") ||
- strings.Contains(*polygonRPC, "polygon-mainnet.infura.io") {
- logger.Fatal("Infura is known to send incorrect blocks - please use your own nodes")
- }
- // NOTE: Please keep these in numerical order by chain ID.
- rpcMap := make(map[string]string)
- rpcMap["solanaRPC"] = *solanaRPC
- rpcMap["fogoRPC"] = *fogoRPC
- rpcMap["ethRPC"] = *ethRPC
- rpcMap["bscRPC"] = *bscRPC
- rpcMap["polygonRPC"] = *polygonRPC
- rpcMap["avalancheRPC"] = *avalancheRPC
- rpcMap["algorandIndexerRPC"] = *algorandIndexerRPC
- rpcMap["algorandAlgodRPC"] = *algorandAlgodRPC
- rpcMap["fantomRPC"] = *fantomRPC
- rpcMap["klaytnRPC"] = *klaytnRPC
- rpcMap["celoRPC"] = *celoRPC
- rpcMap["nearRPC"] = *nearRPC
- rpcMap["moonbeamRPC"] = *moonbeamRPC
- rpcMap["injectiveLCD"] = *injectiveLCD
- rpcMap["injectiveWS"] = *injectiveWS
- // ChainIDOsmosis is not supported in the guardian.
- rpcMap["suiRPC"] = *suiRPC
- rpcMap["aptosRPC"] = *aptosRPC
- rpcMap["arbitrumRPC"] = *arbitrumRPC
- rpcMap["optimismRPC"] = *optimismRPC
- // ChainIDGnosis is not supported in the guardian.
- rpcMap["pythnetRPC"] = *pythnetRPC
- rpcMap["pythnetWS"] = *pythnetWS
- // ChainIDBtc is not supported in the guardian.
- rpcMap["baseRPC"] = *baseRPC
- // ChainIDSei is supported over IBC, so it's not listed here.
- // ChainIDRootstock is not supported in the guardian.
- rpcMap["scrollRPC"] = *scrollRPC
- rpcMap["mantleRPC"] = *mantleRPC
- rpcMap["xlayerRPC"] = *xlayerRPC
- rpcMap["lineaRPC"] = *lineaRPC
- rpcMap["berachainRPC"] = *berachainRPC
- rpcMap["seiEvmRPC"] = *seiEvmRPC
- rpcMap["unichainRPC"] = *unichainRPC
- rpcMap["worldchainRPC"] = *worldchainRPC
- rpcMap["inkRPC"] = *inkRPC
- rpcMap["hyperEvmRPC"] = *hyperEvmRPC
- rpcMap["monadRPC"] = *monadRPC
- rpcMap["movementRPC"] = *movementRPC
- rpcMap["mezoRPC"] = *mezoRPC
- rpcMap["convergeRPC"] = *convergeRPC
- rpcMap["plumeRPC"] = *plumeRPC
- rpcMap["xrplevmRPC"] = *xrplEvmRPC
- rpcMap["plasmaRPC"] = *plasmaRPC
- rpcMap["creditcoinRPC"] = *creditCoinRPC
- // Wormchain is in the 3000 range.
- rpcMap["wormchainURL"] = *wormchainURL
- // Generate the IBC chains (3000 range).
- for _, ibcChain := range ibc.Chains {
- rpcMap[ibcChain.String()] = "IBC"
- }
- // The testnet only chains (10000 range) go here.
- if env == common.TestNet {
- rpcMap["sepoliaRPC"] = *sepoliaRPC
- rpcMap["arbitrumSepoliaRPC"] = *arbitrumSepoliaRPC
- rpcMap["baseSepoliaRPC"] = *baseSepoliaRPC
- rpcMap["optimismSepoliaRPC"] = *optimismSepoliaRPC
- rpcMap["holeskyRPC"] = *holeskyRPC
- rpcMap["polygonSepoliaRPC"] = *polygonSepoliaRPC
- }
- // Other, non-chain specific parameters go here.
- rpcMap["accountantWS"] = *accountantWS
- rpcMap["gatewayWS"] = *gatewayWS
- rpcMap["gatewayLCD"] = *gatewayLCD
- rpcMap["ibcBlockHeightURL"] = *ibcBlockHeightURL
- rpcMap["ibcLCD"] = *ibcLCD
- rpcMap["ibcWS"] = *ibcWS
- // Handle SIGTERM
- sigterm := make(chan os.Signal, 1)
- signal.Notify(sigterm, syscall.SIGTERM)
- go func() {
- <-sigterm
- logger.Info("Received sigterm. exiting.")
- rootCtxCancel()
- }()
- // log golang version
- logger.Info("golang version", zap.String("golang_version", runtime.Version()))
- // Redirect ipfs logs to plain zap
- ipfslog.SetPrimaryCore(logger.Core())
- // Database
- db := guardianDB.OpenDb(logger.With(zap.String("component", "badgerDb")), dataDir)
- defer db.Close()
- wormchainId := "wormchain"
- if env == common.TestNet {
- wormchainId = "wormchain-testnet-0"
- }
- var accountantWormchainConn, accountantNttWormchainConn *wormconn.ClientConn
- if *accountantContract != "" {
- if *wormchainURL == "" {
- logger.Fatal("if accountantContract is specified, wormchainURL is required", zap.String("component", "gacct"))
- }
- if *accountantKeyPath == "" {
- logger.Fatal("if accountantContract is specified, accountantKeyPath is required", zap.String("component", "gacct"))
- }
- if *accountantKeyPassPhrase == "" {
- logger.Fatal("if accountantContract is specified, accountantKeyPassPhrase is required", zap.String("component", "gacct"))
- }
- keyPathName := *accountantKeyPath
- if env == common.UnsafeDevNet {
- idx, err := devnet.GetDevnetIndex()
- if err != nil {
- logger.Fatal("failed to get devnet index", zap.Error(err), zap.String("component", "gacct"))
- }
- keyPathName = fmt.Sprint(*accountantKeyPath, idx)
- }
- wormchainKey, err := wormconn.LoadWormchainPrivKey(keyPathName, *accountantKeyPassPhrase)
- if err != nil {
- logger.Fatal("failed to load accountant private key", zap.Error(err), zap.String("component", "gacct"))
- }
- // Connect to wormchain for the accountant.
- logger.Info("Connecting to wormchain for accountant", zap.String("wormchainURL", *wormchainURL), zap.String("keyPath", keyPathName), zap.String("component", "gacct"))
- accountantWormchainConn, err = wormconn.NewConn(rootCtx, *wormchainURL, wormchainKey, wormchainId)
- if err != nil {
- logger.Fatal("failed to connect to wormchain for accountant", zap.Error(err), zap.String("component", "gacct"))
- }
- }
- // If the NTT accountant is enabled, create a wormchain connection for it.
- if *accountantNttContract != "" {
- if *wormchainURL == "" {
- logger.Fatal("if accountantNttContract is specified, wormchainURL is required", zap.String("component", "gacct"))
- }
- if *accountantNttKeyPath == "" {
- logger.Fatal("if accountantNttContract is specified, accountantNttKeyPath is required", zap.String("component", "gacct"))
- }
- if *accountantNttKeyPassPhrase == "" {
- logger.Fatal("if accountantNttContract is specified, accountantNttKeyPassPhrase is required", zap.String("component", "gacct"))
- }
- keyPathName := *accountantNttKeyPath
- if env == common.UnsafeDevNet {
- idx, err := devnet.GetDevnetIndex()
- if err != nil {
- logger.Fatal("failed to get devnet index", zap.Error(err), zap.String("component", "gacct"))
- }
- keyPathName = fmt.Sprint(*accountantNttKeyPath, idx)
- }
- wormchainKey, err := wormconn.LoadWormchainPrivKey(keyPathName, *accountantNttKeyPassPhrase)
- if err != nil {
- logger.Fatal("failed to load NTT accountant private key", zap.Error(err), zap.String("component", "gacct"))
- }
- // Connect to wormchain for the NTT accountant.
- logger.Info("Connecting to wormchain for NTT accountant", zap.String("wormchainURL", *wormchainURL), zap.String("keyPath", keyPathName), zap.String("component", "gacct"))
- accountantNttWormchainConn, err = wormconn.NewConn(rootCtx, *wormchainURL, wormchainKey, wormchainId)
- if err != nil {
- logger.Fatal("failed to connect to wormchain for NTT accountant", zap.Error(err), zap.String("component", "gacct"))
- }
- }
- var gatewayRelayerWormchainConn *wormconn.ClientConn
- if *gatewayRelayerContract != "" {
- if *wormchainURL == "" {
- logger.Fatal("if gatewayRelayerContract is specified, wormchainURL is required", zap.String("component", "gwrelayer"))
- }
- if *gatewayRelayerKeyPath == "" {
- logger.Fatal("if gatewayRelayerContract is specified, gatewayRelayerKeyPath is required", zap.String("component", "gwrelayer"))
- }
- if *gatewayRelayerKeyPassPhrase == "" {
- logger.Fatal("if gatewayRelayerContract is specified, gatewayRelayerKeyPassPhrase is required", zap.String("component", "gwrelayer"))
- }
- wormchainKeyPathName := *gatewayRelayerKeyPath
- if env == common.UnsafeDevNet {
- idx, err := devnet.GetDevnetIndex()
- if err != nil {
- logger.Fatal("failed to get devnet index", zap.Error(err), zap.String("component", "gwrelayer"))
- }
- wormchainKeyPathName = fmt.Sprint(*gatewayRelayerKeyPath, idx)
- }
- wormchainKey, err := wormconn.LoadWormchainPrivKey(wormchainKeyPathName, *gatewayRelayerKeyPassPhrase)
- if err != nil {
- logger.Fatal("failed to load private key", zap.Error(err), zap.String("component", "gwrelayer"))
- }
- logger.Info("Connecting to wormchain", zap.String("wormchainURL", *wormchainURL), zap.String("keyPath", wormchainKeyPathName), zap.String("component", "gwrelayer"))
- gatewayRelayerWormchainConn, err = wormconn.NewConn(rootCtx, *wormchainURL, wormchainKey, wormchainId)
- if err != nil {
- logger.Fatal("failed to connect to wormchain", zap.Error(err), zap.String("component", "gwrelayer"))
- }
- }
- usingPromRemoteWrite := *promRemoteURL != ""
- if usingPromRemoteWrite {
- var info promremotew.PromTelemetryInfo
- info.PromRemoteURL = *promRemoteURL
- info.Labels = map[string]string{
- "node_name": *nodeName,
- "guardian_addr": ethcrypto.PubkeyToAddress(guardianSigner.PublicKey(rootCtx)).String(),
- "network": *p2pNetworkID,
- "version": version.Version(),
- "product": "wormhole",
- }
- promLogger := logger.With(zap.String("component", "prometheus_scraper"))
- errC := make(chan error)
- common.StartRunnable(rootCtx, errC, false, "prometheus_scraper", func(ctx context.Context) error {
- t := time.NewTicker(15 * time.Second)
- for {
- select {
- case <-ctx.Done():
- return nil
- case <-t.C:
- err := promremotew.ScrapeAndSendLocalMetrics(ctx, info, promLogger)
- if err != nil {
- promLogger.Error("ScrapeAndSendLocalMetrics error", zap.Error(err))
- continue
- }
- }
- }
- })
- }
- watcherConfigs := []watchers.WatcherConfig{}
- if shouldStart(ethRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "eth",
- ChainID: vaa.ChainIDEthereum,
- Rpc: *ethRPC,
- Contract: *ethContract,
- GuardianSetUpdateChain: true,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDEthereum),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(bscRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "bsc",
- ChainID: vaa.ChainIDBSC,
- Rpc: *bscRPC,
- Contract: *bscContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDBSC),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(polygonRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "polygon",
- ChainID: vaa.ChainIDPolygon,
- Rpc: *polygonRPC,
- Contract: *polygonContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDPolygon),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(avalancheRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "avalanche",
- ChainID: vaa.ChainIDAvalanche,
- Rpc: *avalancheRPC,
- Contract: *avalancheContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDAvalanche),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(fantomRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "fantom",
- ChainID: vaa.ChainIDFantom,
- Rpc: *fantomRPC,
- Contract: *fantomContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDFantom),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(klaytnRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "klaytn",
- ChainID: vaa.ChainIDKlaytn,
- Rpc: *klaytnRPC,
- Contract: *klaytnContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDKlaytn),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(celoRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "celo",
- ChainID: vaa.ChainIDCelo,
- Rpc: *celoRPC,
- Contract: *celoContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDCelo),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(moonbeamRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "moonbeam",
- ChainID: vaa.ChainIDMoonbeam,
- Rpc: *moonbeamRPC,
- Contract: *moonbeamContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDMoonbeam),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(arbitrumRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "arbitrum",
- ChainID: vaa.ChainIDArbitrum,
- Rpc: *arbitrumRPC,
- Contract: *arbitrumContract,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDArbitrum),
- CcqBackfillCache: *ccqBackfillCache,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(optimismRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "optimism",
- ChainID: vaa.ChainIDOptimism,
- Rpc: *optimismRPC,
- Contract: *optimismContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDOptimism),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(baseRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "base",
- ChainID: vaa.ChainIDBase,
- Rpc: *baseRPC,
- Contract: *baseContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDBase),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(scrollRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "scroll",
- ChainID: vaa.ChainIDScroll,
- Rpc: *scrollRPC,
- Contract: *scrollContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDScroll),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(mantleRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "mantle",
- ChainID: vaa.ChainIDMantle,
- Rpc: *mantleRPC,
- Contract: *mantleContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDMantle),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(xlayerRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "xlayer",
- ChainID: vaa.ChainIDXLayer,
- Rpc: *xlayerRPC,
- Contract: *xlayerContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDXLayer),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(lineaRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "linea",
- ChainID: vaa.ChainIDLinea,
- Rpc: *lineaRPC,
- Contract: *lineaContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDLinea),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(berachainRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "berachain",
- ChainID: vaa.ChainIDBerachain,
- Rpc: *berachainRPC,
- Contract: *berachainContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDBerachain),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(unichainRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "unichain",
- ChainID: vaa.ChainIDUnichain,
- Rpc: *unichainRPC,
- Contract: *unichainContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDUnichain),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(worldchainRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "worldchain",
- ChainID: vaa.ChainIDWorldchain,
- Rpc: *worldchainRPC,
- Contract: *worldchainContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDWorldchain),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(inkRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "ink",
- ChainID: vaa.ChainIDInk,
- Rpc: *inkRPC,
- Contract: *inkContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDInk),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(hyperEvmRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "hyperevm",
- ChainID: vaa.ChainIDHyperEVM,
- Rpc: *hyperEvmRPC,
- Contract: *hyperEvmContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDHyperEVM),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(monadRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "monad",
- ChainID: vaa.ChainIDMonad,
- Rpc: *monadRPC,
- Contract: *monadContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDMonad),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(seiEvmRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "seievm",
- ChainID: vaa.ChainIDSeiEVM,
- Rpc: *seiEvmRPC,
- Contract: *seiEvmContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDSeiEVM),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(mezoRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "mezo",
- ChainID: vaa.ChainIDMezo,
- Rpc: *mezoRPC,
- Contract: *mezoContract,
- CcqBackfillCache: *ccqBackfillCache,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(convergeRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "converge",
- ChainID: vaa.ChainIDConverge,
- Rpc: *convergeRPC,
- Contract: *convergeContract,
- CcqBackfillCache: *ccqBackfillCache,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(plumeRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "plume",
- ChainID: vaa.ChainIDPlume,
- Rpc: *plumeRPC,
- Contract: *plumeContract,
- CcqBackfillCache: *ccqBackfillCache,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(xrplEvmRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "xrplevm",
- ChainID: vaa.ChainIDXRPLEVM,
- Rpc: *xrplEvmRPC,
- Contract: *xrplEvmContract,
- CcqBackfillCache: *ccqBackfillCache,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(plasmaRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "plasma",
- ChainID: vaa.ChainIDPlasma,
- Rpc: *plasmaRPC,
- Contract: *plasmaContract,
- CcqBackfillCache: *ccqBackfillCache,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(creditCoinRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "creditcoin",
- ChainID: vaa.ChainIDCreditCoin,
- Rpc: *creditCoinRPC,
- Contract: *creditCoinContract,
- CcqBackfillCache: *ccqBackfillCache,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(mocaRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "moca",
- ChainID: vaa.ChainIDMoca,
- Rpc: *mocaRPC,
- Contract: *mocaContract,
- CcqBackfillCache: *ccqBackfillCache,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(terraWS) {
- if env != common.UnsafeDevNet {
- logger.Fatal("Terra classic is only allowed in unsafe dev mode")
- }
- wc := &cosmwasm.WatcherConfig{
- NetworkID: "terra",
- ChainID: vaa.ChainIDTerra,
- Websocket: *terraWS,
- Lcd: *terraLCD,
- Contract: *terraContract,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(terra2WS) {
- if env != common.UnsafeDevNet {
- logger.Fatal("Terra2 classic is only allowed in unsafe dev mode")
- }
- wc := &cosmwasm.WatcherConfig{
- NetworkID: "terra2",
- ChainID: vaa.ChainIDTerra2,
- Websocket: *terra2WS,
- Lcd: *terra2LCD,
- Contract: *terra2Contract,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(injectiveWS) {
- wc := &cosmwasm.WatcherConfig{
- NetworkID: "injective",
- ChainID: vaa.ChainIDInjective,
- Websocket: *injectiveWS,
- Lcd: *injectiveLCD,
- Contract: *injectiveContract,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(algorandIndexerRPC) {
- wc := &algorand.WatcherConfig{
- NetworkID: "algorand",
- ChainID: vaa.ChainIDAlgorand,
- IndexerRPC: *algorandIndexerRPC,
- IndexerToken: *algorandIndexerToken,
- AlgodRPC: *algorandAlgodRPC,
- AlgodToken: *algorandAlgodToken,
- AppID: *algorandAppID,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(nearRPC) {
- wc := &near.WatcherConfig{
- NetworkID: "near",
- ChainID: vaa.ChainIDNear,
- Rpc: *nearRPC,
- Contract: *nearContract,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(aptosRPC) {
- wc := &aptos.WatcherConfig{
- NetworkID: "aptos",
- ChainID: vaa.ChainIDAptos,
- Rpc: *aptosRPC,
- Account: *aptosAccount,
- Handle: *aptosHandle,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(movementRPC) {
- wc := &aptos.WatcherConfig{
- NetworkID: "movement",
- ChainID: vaa.ChainIDMovement,
- Rpc: *movementRPC,
- Account: *movementAccount,
- Handle: *movementHandle,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(suiRPC) {
- wc := &sui.WatcherConfig{
- NetworkID: "sui",
- ChainID: vaa.ChainIDSui,
- Rpc: *suiRPC,
- SuiMoveEventType: *suiMoveEventType,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDSui),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(solanaRPC) {
- // confirmed watcher
- wc := &solana.WatcherConfig{
- NetworkID: "solana-confirmed",
- ChainID: vaa.ChainIDSolana,
- Rpc: *solanaRPC,
- Websocket: "",
- Contract: *solanaContract,
- ShimContract: *solanaShimContract,
- ReceiveObsReq: false,
- Commitment: rpc.CommitmentConfirmed,
- }
- watcherConfigs = append(watcherConfigs, wc)
- // finalized watcher
- wc = &solana.WatcherConfig{
- NetworkID: "solana-finalized",
- ChainID: vaa.ChainIDSolana,
- Rpc: *solanaRPC,
- Websocket: "",
- Contract: *solanaContract,
- ShimContract: *solanaShimContract,
- ReceiveObsReq: true,
- Commitment: rpc.CommitmentFinalized,
- }
- watcherConfigs = append(watcherConfigs, wc)
- if *solanaShimContract != "" {
- featureFlags = append(featureFlags, fmt.Sprintf("solshim:%s", *solanaShimContract))
- }
- }
- if shouldStart(fogoRPC) {
- // confirmed watcher
- wc := &solana.WatcherConfig{
- NetworkID: "fogo-confirmed",
- ChainID: vaa.ChainIDFogo,
- Rpc: *fogoRPC,
- Websocket: "",
- Contract: *fogoContract,
- ShimContract: *fogoShimContract,
- ReceiveObsReq: false,
- Commitment: rpc.CommitmentConfirmed,
- PollForTx: true,
- }
- watcherConfigs = append(watcherConfigs, wc)
- // finalized watcher
- wc = &solana.WatcherConfig{
- NetworkID: "fogo-finalized",
- ChainID: vaa.ChainIDFogo,
- Rpc: *fogoRPC,
- Websocket: "",
- Contract: *fogoContract,
- ShimContract: *fogoShimContract,
- ReceiveObsReq: true,
- Commitment: rpc.CommitmentFinalized,
- PollForTx: true,
- }
- watcherConfigs = append(watcherConfigs, wc)
- if *fogoShimContract != "" {
- featureFlags = append(featureFlags, fmt.Sprintf("fogoshim:%s", *fogoShimContract))
- }
- }
- if shouldStart(pythnetRPC) {
- wc := &solana.WatcherConfig{
- NetworkID: "pythnet",
- ChainID: vaa.ChainIDPythNet,
- Rpc: *pythnetRPC,
- Websocket: *pythnetWS,
- Contract: *pythnetContract,
- ReceiveObsReq: false,
- Commitment: rpc.CommitmentConfirmed,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(gatewayWS) {
- wc := &cosmwasm.WatcherConfig{
- NetworkID: "gateway",
- ChainID: vaa.ChainIDWormchain,
- Websocket: *gatewayWS,
- Lcd: *gatewayLCD,
- Contract: *gatewayContract,
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if env == common.TestNet || env == common.UnsafeDevNet {
- if shouldStart(sepoliaRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "sepolia",
- ChainID: vaa.ChainIDSepolia,
- Rpc: *sepoliaRPC,
- Contract: *sepoliaContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDSepolia),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(holeskyRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "holesky",
- ChainID: vaa.ChainIDHolesky,
- Rpc: *holeskyRPC,
- Contract: *holeskyContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDHolesky),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(arbitrumSepoliaRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "arbitrum_sepolia",
- ChainID: vaa.ChainIDArbitrumSepolia,
- Rpc: *arbitrumSepoliaRPC,
- Contract: *arbitrumSepoliaContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDArbitrumSepolia),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(baseSepoliaRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "base_sepolia",
- ChainID: vaa.ChainIDBaseSepolia,
- Rpc: *baseSepoliaRPC,
- Contract: *baseSepoliaContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDBaseSepolia),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(optimismSepoliaRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "optimism_sepolia",
- ChainID: vaa.ChainIDOptimismSepolia,
- Rpc: *optimismSepoliaRPC,
- Contract: *optimismSepoliaContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDOptimismSepolia),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- if shouldStart(polygonSepoliaRPC) {
- wc := &evm.WatcherConfig{
- NetworkID: "polygon_sepolia",
- ChainID: vaa.ChainIDPolygonSepolia,
- Rpc: *polygonSepoliaRPC,
- Contract: *polygonSepoliaContract,
- CcqBackfillCache: *ccqBackfillCache,
- TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDPolygonSepolia),
- }
- watcherConfigs = append(watcherConfigs, wc)
- }
- }
- var ibcWatcherConfig *node.IbcWatcherConfig = nil
- if shouldStart(ibcWS) {
- ibcWatcherConfig = &node.IbcWatcherConfig{
- Websocket: *ibcWS,
- Lcd: *ibcLCD,
- BlockHeightURL: *ibcBlockHeightURL,
- Contract: *ibcContract,
- }
- }
- guardianNode := node.NewGuardianNode(
- env,
- guardianSigner,
- )
- var guardianAddrAsBytes []byte
- if len(*additionalPublishers) > 0 {
- guardianAddrAsBytes = ethcrypto.PubkeyToAddress(guardianSigner.PublicKey(rootCtx)).Bytes()
- }
- guardianOptions := []*node.GuardianOption{
- node.GuardianOptionDatabase(db),
- node.GuardianOptionWatchers(watcherConfigs, ibcWatcherConfig),
- node.GuardianOptionAccountant(*accountantWS, *accountantContract, *accountantCheckEnabled, accountantWormchainConn, *accountantNttContract, accountantNttWormchainConn),
- node.GuardianOptionGovernor(*chainGovernorEnabled, *governorFlowCancelEnabled, *coinGeckoApiKey),
- node.GuardianOptionNotary(*notaryEnabled),
- node.GuardianOptionGatewayRelayer(*gatewayRelayerContract, gatewayRelayerWormchainConn),
- node.GuardianOptionQueryHandler(*ccqEnabled, *ccqAllowedRequesters),
- node.GuardianOptionAdminService(*adminSocketPath, ethRPC, ethContract, rpcMap),
- node.GuardianOptionStatusServer(*statusAddr),
- node.GuardianOptionAlternatePublisher(guardianAddrAsBytes, *additionalPublishers),
- node.GuardianOptionProcessor(*p2pNetworkID),
- // Keep this last so that all of its dependencies are met.
- node.GuardianOptionP2P(
- p2pKey,
- *p2pNetworkID,
- *p2pBootstrap,
- *nodeName,
- *subscribeToVAAs,
- *disableHeartbeatVerify,
- *p2pPort,
- *ccqP2pBootstrap,
- *ccqP2pPort,
- *ccqAllowedPeers,
- *gossipAdvertiseAddress,
- ibcWatcherConfig != nil,
- protectedPeers,
- ccqProtectedPeers,
- featureFlags,
- ),
- }
- if shouldStart(publicGRPCSocketPath) {
- guardianOptions = append(guardianOptions, node.GuardianOptionPublicRpcSocket(*publicGRPCSocketPath, publicRpcLogDetail))
- if shouldStart(publicRPC) {
- guardianOptions = append(guardianOptions, node.GuardianOptionPublicrpcTcpService(*publicRPC, publicRpcLogDetail))
- }
- if shouldStart(publicWeb) {
- guardianOptions = append(guardianOptions,
- node.GuardianOptionPublicWeb(*publicWeb, *publicGRPCSocketPath, *tlsHostname, *tlsProdEnv, path.Join(*dataDir, "autocert")),
- )
- }
- }
- // Run supervisor with Guardian Node as root.
- supervisor.New(rootCtx, logger, guardianNode.Run(rootCtxCancel, guardianOptions...),
- // It's safer to crash and restart the process in case we encounter a panic,
- // rather than attempting to reschedule the runnable.
- supervisor.WithPropagatePanic)
- <-rootCtx.Done()
- logger.Info("root context cancelled, exiting...")
- }
- func shouldStart(rpcURL *string) bool {
- return *rpcURL != "" && *rpcURL != "none"
- }
- // checkEvmArgs verifies that the RPC and contract address parameters for an EVM chain make sense, given the environment.
- // If we are in devnet mode and the contract address is not specified, it returns the deterministic one for tilt.
- func checkEvmArgs(logger *zap.Logger, rpcURL string, contractAddr string, chainID vaa.ChainID) string {
- if env != common.UnsafeDevNet {
- // In mainnet / testnet, if either parameter is specified, they must both be specified.
- if (rpcURL == "") != (contractAddr == "") {
- logger.Fatal(fmt.Sprintf("Both contract and RPC for chain %s must be set or both unset", chainID.String()))
- }
- } else {
- // In devnet, if RPC is set but contract is not set, use the deterministic one for tilt.
- if rpcURL == "" {
- if contractAddr != "" {
- logger.Fatal(fmt.Sprintf("If RPC is not set for chain %s, contract must not be set", chainID.String()))
- }
- } else {
- if contractAddr == "" {
- contractAddr = sdk.KnownDevnetCoreContracts[vaa.ChainIDEthereum]
- }
- }
- }
- mainnetSupported := evm.SupportedInMainnet(chainID)
- if contractAddr != "" && !mainnetSupported && env == common.MainNet {
- logger.Fatal(fmt.Sprintf("Chain %s is not supported in mainnet", chainID.String()))
- }
- return contractAddr
- }
- // argsConsistent verifies that the arguments in the array are all set or all unset.
- // Note that it doesn't validate the values, just whether they are blank or not.
- func argsConsistent(args []string) bool {
- if len(args) < 2 {
- panic("argsConsistent expects at least two args")
- }
- shouldBeUnset := args[0] == ""
- for idx := 1; idx < len(args); idx++ {
- if shouldBeUnset != (args[idx] == "") {
- return false
- }
- }
- return true
- }
|