node.go 77 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013
  1. package guardiand
  2. import (
  3. "context"
  4. "fmt"
  5. "net"
  6. _ "net/http/pprof" // #nosec G108 we are using a custom router (`router := mux.NewRouter()`) and thus not automatically expose pprof.
  7. "os"
  8. "os/signal"
  9. "path"
  10. "runtime"
  11. "slices"
  12. "strings"
  13. "syscall"
  14. "time"
  15. "github.com/certusone/wormhole/node/pkg/guardiansigner"
  16. "github.com/certusone/wormhole/node/pkg/watchers"
  17. "github.com/certusone/wormhole/node/pkg/watchers/ibc"
  18. ethcrypto "github.com/ethereum/go-ethereum/crypto"
  19. "github.com/certusone/wormhole/node/pkg/watchers/cosmwasm"
  20. "github.com/certusone/wormhole/node/pkg/watchers/algorand"
  21. "github.com/certusone/wormhole/node/pkg/watchers/aptos"
  22. "github.com/certusone/wormhole/node/pkg/watchers/evm"
  23. "github.com/certusone/wormhole/node/pkg/watchers/near"
  24. "github.com/certusone/wormhole/node/pkg/watchers/solana"
  25. "github.com/certusone/wormhole/node/pkg/watchers/sui"
  26. "github.com/certusone/wormhole/node/pkg/wormconn"
  27. guardianDB "github.com/certusone/wormhole/node/pkg/db"
  28. "github.com/certusone/wormhole/node/pkg/telemetry"
  29. "github.com/certusone/wormhole/node/pkg/version"
  30. "github.com/gagliardetto/solana-go/rpc"
  31. "go.uber.org/zap/zapcore"
  32. "github.com/certusone/wormhole/node/pkg/common"
  33. "github.com/certusone/wormhole/node/pkg/devnet"
  34. "github.com/certusone/wormhole/node/pkg/node"
  35. "github.com/certusone/wormhole/node/pkg/p2p"
  36. "github.com/certusone/wormhole/node/pkg/supervisor"
  37. promremotew "github.com/certusone/wormhole/node/pkg/telemetry/prom_remote_write"
  38. "github.com/certusone/wormhole/node/pkg/txverifier"
  39. libp2p_crypto "github.com/libp2p/go-libp2p/core/crypto"
  40. "github.com/libp2p/go-libp2p/core/peer"
  41. "github.com/spf13/cobra"
  42. "github.com/spf13/viper"
  43. "github.com/wormhole-foundation/wormhole/sdk"
  44. "github.com/wormhole-foundation/wormhole/sdk/vaa"
  45. "go.uber.org/zap"
  46. ipfslog "github.com/ipfs/go-log/v2"
  47. )
  48. var (
  49. p2pNetworkID *string
  50. p2pPort *uint
  51. p2pBootstrap *string
  52. protectedPeers []string
  53. additionalPublishers *[]string
  54. nodeKeyPath *string
  55. adminSocketPath *string
  56. publicGRPCSocketPath *string
  57. dataDir *string
  58. statusAddr *string
  59. guardianKeyPath *string
  60. guardianSignerUri *string
  61. ethRPC *string
  62. ethContract *string
  63. bscRPC *string
  64. bscContract *string
  65. polygonRPC *string
  66. polygonContract *string
  67. fantomRPC *string
  68. fantomContract *string
  69. avalancheRPC *string
  70. avalancheContract *string
  71. klaytnRPC *string
  72. klaytnContract *string
  73. celoRPC *string
  74. celoContract *string
  75. moonbeamRPC *string
  76. moonbeamContract *string
  77. terraWS *string
  78. terraLCD *string
  79. terraContract *string
  80. terra2WS *string
  81. terra2LCD *string
  82. terra2Contract *string
  83. injectiveWS *string
  84. injectiveLCD *string
  85. injectiveContract *string
  86. gatewayWS *string
  87. gatewayLCD *string
  88. gatewayContract *string
  89. algorandIndexerRPC *string
  90. algorandIndexerToken *string
  91. algorandAlgodRPC *string
  92. algorandAlgodToken *string
  93. algorandAppID *uint64
  94. nearRPC *string
  95. nearContract *string
  96. wormchainURL *string
  97. ibcWS *string
  98. ibcLCD *string
  99. ibcBlockHeightURL *string
  100. ibcContract *string
  101. accountantContract *string
  102. accountantWS *string
  103. accountantCheckEnabled *bool
  104. accountantKeyPath *string
  105. accountantKeyPassPhrase *string
  106. accountantNttContract *string
  107. accountantNttKeyPath *string
  108. accountantNttKeyPassPhrase *string
  109. aptosRPC *string
  110. aptosAccount *string
  111. aptosHandle *string
  112. movementRPC *string
  113. movementAccount *string
  114. movementHandle *string
  115. suiRPC *string
  116. suiMoveEventType *string
  117. solanaRPC *string
  118. solanaContract *string
  119. solanaShimContract *string
  120. fogoRPC *string
  121. fogoContract *string
  122. fogoShimContract *string
  123. pythnetContract *string
  124. pythnetRPC *string
  125. pythnetWS *string
  126. arbitrumRPC *string
  127. arbitrumContract *string
  128. optimismRPC *string
  129. optimismContract *string
  130. baseRPC *string
  131. baseContract *string
  132. scrollRPC *string
  133. scrollContract *string
  134. mantleRPC *string
  135. mantleContract *string
  136. xlayerRPC *string
  137. xlayerContract *string
  138. lineaRPC *string
  139. lineaContract *string
  140. berachainRPC *string
  141. berachainContract *string
  142. unichainRPC *string
  143. unichainContract *string
  144. worldchainRPC *string
  145. worldchainContract *string
  146. monadRPC *string
  147. monadContract *string
  148. inkRPC *string
  149. inkContract *string
  150. hyperEvmRPC *string
  151. hyperEvmContract *string
  152. seiEvmRPC *string
  153. seiEvmContract *string
  154. mezoRPC *string
  155. mezoContract *string
  156. convergeRPC *string
  157. convergeContract *string
  158. plumeRPC *string
  159. plumeContract *string
  160. xrplEvmRPC *string
  161. xrplEvmContract *string
  162. plasmaRPC *string
  163. plasmaContract *string
  164. creditCoinRPC *string
  165. creditCoinContract *string
  166. mocaRPC *string
  167. mocaContract *string
  168. sepoliaRPC *string
  169. sepoliaContract *string
  170. holeskyRPC *string
  171. holeskyContract *string
  172. arbitrumSepoliaRPC *string
  173. arbitrumSepoliaContract *string
  174. baseSepoliaRPC *string
  175. baseSepoliaContract *string
  176. optimismSepoliaRPC *string
  177. optimismSepoliaContract *string
  178. polygonSepoliaRPC *string
  179. polygonSepoliaContract *string
  180. logLevel *string
  181. publicRpcLogDetailStr *string
  182. publicRpcLogToTelemetry *bool
  183. unsafeDevMode *bool
  184. testnetMode *bool
  185. nodeName *string
  186. publicRPC *string
  187. publicWeb *string
  188. tlsHostname *string
  189. tlsProdEnv *bool
  190. disableHeartbeatVerify *bool
  191. disableTelemetry *bool
  192. // Loki cloud logging parameters
  193. telemetryLokiURL *string
  194. // Prometheus remote write URL
  195. promRemoteURL *string
  196. chainGovernorEnabled *bool
  197. governorFlowCancelEnabled *bool
  198. coinGeckoApiKey *string
  199. ccqEnabled *bool
  200. ccqAllowedRequesters *string
  201. ccqP2pPort *uint
  202. ccqP2pBootstrap *string
  203. ccqProtectedPeers []string
  204. ccqAllowedPeers *string
  205. ccqBackfillCache *bool
  206. gatewayRelayerContract *string
  207. gatewayRelayerKeyPath *string
  208. gatewayRelayerKeyPassPhrase *string
  209. // This is the externally reachable address advertised over gossip for guardian p2p and ccq p2p.
  210. gossipAdvertiseAddress *string
  211. // env is the mode we are running in, Mainnet, Testnet or UnsafeDevnet.
  212. env common.Environment
  213. subscribeToVAAs *bool
  214. // A list of chain IDs that should enable the Transfer Verifier. If empty, Transfer Verifier will not be enabled.
  215. transferVerifierEnabledChainIDs *[]uint
  216. // Global variable used to store enabled Chain IDs for Transfer Verification. Contents are parsed from
  217. // transferVerifierEnabledChainIDs.
  218. txVerifierChains []vaa.ChainID
  219. // featureFlags are additional static flags that should be published in P2P heartbeats.
  220. featureFlags []string
  221. notaryEnabled *bool
  222. )
  223. func init() {
  224. p2pNetworkID = NodeCmd.Flags().String("network", "", "P2P network identifier (optional, overrides default for environment)")
  225. p2pPort = NodeCmd.Flags().Uint("port", p2p.DefaultPort, "P2P UDP listener port")
  226. p2pBootstrap = NodeCmd.Flags().String("bootstrap", "", "P2P bootstrap peers (optional for mainnet or testnet, overrides default, required for unsafeDevMode)")
  227. NodeCmd.Flags().StringSliceVarP(&protectedPeers, "protectedPeers", "", []string{}, "")
  228. additionalPublishers = NodeCmd.Flags().StringArray("additionalPublishEndpoint", []string{}, "defines an alternate publisher as label;url;delay;chains where delay and chains are optional")
  229. statusAddr = NodeCmd.Flags().String("statusAddr", "[::]:6060", "Listen address for status server (disabled if blank)")
  230. nodeKeyPath = NodeCmd.Flags().String("nodeKey", "", "Path to node key (will be generated if it doesn't exist)")
  231. adminSocketPath = NodeCmd.Flags().String("adminSocket", "", "Admin gRPC service UNIX domain socket path")
  232. publicGRPCSocketPath = NodeCmd.Flags().String("publicGRPCSocket", "", "Public gRPC service UNIX domain socket path")
  233. dataDir = NodeCmd.Flags().String("dataDir", "", "Data directory")
  234. guardianKeyPath = NodeCmd.Flags().String("guardianKey", "", "Path to guardian key")
  235. guardianSignerUri = NodeCmd.Flags().String("guardianSignerUri", "", "Guardian signer URI")
  236. solanaContract = NodeCmd.Flags().String("solanaContract", "", "Address of the Solana program (required if solanaRpc is specified)")
  237. solanaShimContract = NodeCmd.Flags().String("solanaShimContract", "", "Address of the Solana shim program")
  238. fogoContract = NodeCmd.Flags().String("fogoContract", "", "Address of the Fogo program (required if fogoRpc is specified)")
  239. fogoShimContract = NodeCmd.Flags().String("fogoShimContract", "", "Address of the Fogo shim program")
  240. ethRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "ethRPC", "Ethereum RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  241. ethContract = NodeCmd.Flags().String("ethContract", "", "Ethereum contract address")
  242. bscRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "bscRPC", "Binance Smart Chain RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  243. bscContract = NodeCmd.Flags().String("bscContract", "", "Binance Smart Chain contract address")
  244. polygonRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "polygonRPC", "Polygon RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  245. polygonContract = NodeCmd.Flags().String("polygonContract", "", "Polygon contract address")
  246. avalancheRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "avalancheRPC", "Avalanche RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  247. avalancheContract = NodeCmd.Flags().String("avalancheContract", "", "Avalanche contract address")
  248. fantomRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "fantomRPC", "Fantom Websocket RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  249. fantomContract = NodeCmd.Flags().String("fantomContract", "", "Fantom contract address")
  250. klaytnRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "klaytnRPC", "Klaytn RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  251. klaytnContract = NodeCmd.Flags().String("klaytnContract", "", "Klaytn contract address")
  252. celoRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "celoRPC", "Celo RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  253. celoContract = NodeCmd.Flags().String("celoContract", "", "Celo contract address")
  254. moonbeamRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "moonbeamRPC", "Moonbeam RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  255. moonbeamContract = NodeCmd.Flags().String("moonbeamContract", "", "Moonbeam contract address")
  256. terraWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "terraWS", "Path to terrad root for websocket connection", "ws://terra-terrad:26657/websocket", []string{"ws", "wss"})
  257. terraLCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "terraLCD", "Path to LCD service root for http calls", "http://terra-terrad:1317", []string{"http", "https"})
  258. terraContract = NodeCmd.Flags().String("terraContract", "", "Wormhole contract address on Terra blockchain")
  259. terra2WS = node.RegisterFlagWithValidationOrFail(NodeCmd, "terra2WS", "Path to terrad root for websocket connection", "ws://terra2-terrad:26657/websocket", []string{"ws", "wss"})
  260. terra2LCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "terra2LCD", "Path to LCD service root for http calls", "http://terra2-terrad:1317", []string{"http", "https"})
  261. terra2Contract = NodeCmd.Flags().String("terra2Contract", "", "Wormhole contract address on Terra 2 blockchain")
  262. injectiveWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "injectiveWS", "Path to root for Injective websocket connection", "ws://injective:26657/websocket", []string{"ws", "wss"})
  263. injectiveLCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "injectiveLCD", "Path to LCD service root for Injective http calls", "http://injective:1317", []string{"http", "https"})
  264. injectiveContract = NodeCmd.Flags().String("injectiveContract", "", "Wormhole contract address on Injective blockchain")
  265. gatewayWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "gatewayWS", "Path to root for Gateway watcher websocket connection", "ws://wormchain:26657/websocket", []string{"ws", "wss"})
  266. gatewayLCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "gatewayLCD", "Path to LCD service root for Gateway watcher http calls", "http://wormchain:1317", []string{"http", "https"})
  267. gatewayContract = NodeCmd.Flags().String("gatewayContract", "", "Wormhole contract address on Gateway blockchain")
  268. algorandIndexerRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "algorandIndexerRPC", "Algorand Indexer RPC URL", "http://algorand:8980", []string{"http", "https"})
  269. algorandIndexerToken = NodeCmd.Flags().String("algorandIndexerToken", "", "Algorand Indexer access token")
  270. algorandAlgodRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "algorandAlgodRPC", "Algorand Algod RPC URL", "http://algorand:4001", []string{"http", "https"})
  271. algorandAlgodToken = NodeCmd.Flags().String("algorandAlgodToken", "", "Algorand Algod access token")
  272. algorandAppID = NodeCmd.Flags().Uint64("algorandAppID", 0, "Algorand app id")
  273. nearRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "nearRPC", "Near RPC URL", "http://near:3030", []string{"http", "https"})
  274. nearContract = NodeCmd.Flags().String("nearContract", "", "Near contract")
  275. wormchainURL = node.RegisterFlagWithValidationOrFail(NodeCmd, "wormchainURL", "Wormhole-chain gRPC URL", "wormchain:9090", []string{""})
  276. ibcWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "ibcWS", "Websocket used to listen to the IBC receiver smart contract on wormchain", "ws://wormchain:26657/websocket", []string{"ws", "wss"})
  277. ibcLCD = node.RegisterFlagWithValidationOrFail(NodeCmd, "ibcLCD", "Path to LCD service root for http calls", "http://wormchain:1317", []string{"http", "https"})
  278. 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"})
  279. ibcContract = NodeCmd.Flags().String("ibcContract", "", "Address of the IBC smart contract on wormchain")
  280. accountantWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "accountantWS", "Websocket used to listen to the accountant smart contract on wormchain", "http://wormchain:26657", []string{"http", "https"})
  281. accountantContract = NodeCmd.Flags().String("accountantContract", "", "Address of the accountant smart contract on wormchain")
  282. accountantKeyPath = NodeCmd.Flags().String("accountantKeyPath", "", "path to accountant private key for signing transactions")
  283. accountantKeyPassPhrase = NodeCmd.Flags().String("accountantKeyPassPhrase", "", "pass phrase used to unarmor the accountant key file")
  284. accountantCheckEnabled = NodeCmd.Flags().Bool("accountantCheckEnabled", false, "Should accountant be enforced on transfers")
  285. accountantNttContract = NodeCmd.Flags().String("accountantNttContract", "", "Address of the NTT accountant smart contract on wormchain")
  286. accountantNttKeyPath = NodeCmd.Flags().String("accountantNttKeyPath", "", "path to NTT accountant private key for signing transactions")
  287. accountantNttKeyPassPhrase = NodeCmd.Flags().String("accountantNttKeyPassPhrase", "", "pass phrase used to unarmor the NTT accountant key file")
  288. aptosRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "aptosRPC", "Aptos RPC URL", "http://aptos:8080", []string{"http", "https"})
  289. aptosAccount = NodeCmd.Flags().String("aptosAccount", "", "aptos account")
  290. aptosHandle = NodeCmd.Flags().String("aptosHandle", "", "aptos handle")
  291. movementRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "movementRPC", "Movement RPC URL", "", []string{"http", "https"})
  292. movementAccount = NodeCmd.Flags().String("movementAccount", "", "movement account")
  293. movementHandle = NodeCmd.Flags().String("movementHandle", "", "movement handle")
  294. suiRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "suiRPC", "Sui RPC URL", "http://sui:9000", []string{"http", "https"})
  295. suiMoveEventType = NodeCmd.Flags().String("suiMoveEventType", "", "Sui move event type for publish_message")
  296. solanaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "solanaRPC", "Solana RPC URL (required)", "http://solana-devnet:8899", []string{"http", "https"})
  297. fogoRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "fogoRPC", "Fogo RPC URL (required)", "http://solana-devnet:8899", []string{"http", "https"})
  298. pythnetContract = NodeCmd.Flags().String("pythnetContract", "", "Address of the PythNet program (required)")
  299. pythnetRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "pythnetRPC", "PythNet RPC URL (required)", "http://pythnet.rpcpool.com", []string{"http", "https"})
  300. pythnetWS = node.RegisterFlagWithValidationOrFail(NodeCmd, "pythnetWS", "PythNet WS URL", "wss://pythnet.rpcpool.com", []string{"ws", "wss"})
  301. arbitrumRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "arbitrumRPC", "Arbitrum RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  302. arbitrumContract = NodeCmd.Flags().String("arbitrumContract", "", "Arbitrum contract address")
  303. sepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "sepoliaRPC", "Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  304. sepoliaContract = NodeCmd.Flags().String("sepoliaContract", "", "Sepolia contract address")
  305. holeskyRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "holeskyRPC", "Holesky RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  306. holeskyContract = NodeCmd.Flags().String("holeskyContract", "", "Holesky contract address")
  307. optimismRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "optimismRPC", "Optimism RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  308. optimismContract = NodeCmd.Flags().String("optimismContract", "", "Optimism contract address")
  309. scrollRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "scrollRPC", "Scroll RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  310. scrollContract = NodeCmd.Flags().String("scrollContract", "", "Scroll contract address")
  311. mantleRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "mantleRPC", "Mantle RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  312. mantleContract = NodeCmd.Flags().String("mantleContract", "", "Mantle contract address")
  313. xlayerRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "xlayerRPC", "XLayer RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  314. xlayerContract = NodeCmd.Flags().String("xlayerContract", "", "XLayer contract address")
  315. lineaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "lineaRPC", "Linea RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  316. lineaContract = NodeCmd.Flags().String("lineaContract", "", "Linea contract address")
  317. berachainRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "berachainRPC", "Berachain RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  318. berachainContract = NodeCmd.Flags().String("berachainContract", "", "Berachain contract address")
  319. unichainRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "unichainRPC", "Unichain RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  320. unichainContract = NodeCmd.Flags().String("unichainContract", "", "Unichain contract address")
  321. worldchainRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "worldchainRPC", "Worldchain RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  322. worldchainContract = NodeCmd.Flags().String("worldchainContract", "", "Worldchain contract address")
  323. baseRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "baseRPC", "Base RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  324. baseContract = NodeCmd.Flags().String("baseContract", "", "Base contract address")
  325. inkRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "inkRPC", "Ink RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  326. inkContract = NodeCmd.Flags().String("inkContract", "", "Ink contract address")
  327. hyperEvmRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "hyperEvmRPC", "HyperEVM RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  328. hyperEvmContract = NodeCmd.Flags().String("hyperEvmContract", "", "HyperEVM contract address")
  329. monadRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "monadRPC", "Monad RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  330. monadContract = NodeCmd.Flags().String("monadContract", "", "Monad contract address")
  331. seiEvmRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "seiEvmRPC", "SeiEVM RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  332. seiEvmContract = NodeCmd.Flags().String("seiEvmContract", "", "SeiEVM contract address")
  333. mezoRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "mezoRPC", "Mezo RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  334. mezoContract = NodeCmd.Flags().String("mezoContract", "", "Mezo contract address")
  335. convergeRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "convergeRPC", "converge RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  336. convergeContract = NodeCmd.Flags().String("convergeContract", "", "Converge contract address")
  337. plumeRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "plumeRPC", "Plume RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  338. plumeContract = NodeCmd.Flags().String("plumeContract", "", "Plume contract address")
  339. xrplEvmRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "xrplEvmRPC", "XRPLEVM RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  340. xrplEvmContract = NodeCmd.Flags().String("xrplEvmContract", "", "XRPLEVM contract address")
  341. plasmaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "plasmaRPC", "PLASMA RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  342. plasmaContract = NodeCmd.Flags().String("plasmaContract", "", "Plasma contract address")
  343. creditCoinRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "creditCoinRPC", "CREDITCOIN RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  344. creditCoinContract = NodeCmd.Flags().String("creditCoinContract", "", "CreditCoin contract address")
  345. mocaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "MocaRPC", "Moca RPC_URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  346. mocaContract = NodeCmd.Flags().String("mocaContract", "", "Moca contract address")
  347. arbitrumSepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "arbitrumSepoliaRPC", "Arbitrum on Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  348. arbitrumSepoliaContract = NodeCmd.Flags().String("arbitrumSepoliaContract", "", "Arbitrum on Sepolia contract address")
  349. baseSepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "baseSepoliaRPC", "Base on Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  350. baseSepoliaContract = NodeCmd.Flags().String("baseSepoliaContract", "", "Base on Sepolia contract address")
  351. optimismSepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "optimismSepoliaRPC", "Optimism on Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  352. optimismSepoliaContract = NodeCmd.Flags().String("optimismSepoliaContract", "", "Optimism on Sepolia contract address")
  353. polygonSepoliaRPC = node.RegisterFlagWithValidationOrFail(NodeCmd, "polygonSepoliaRPC", "Polygon on Sepolia RPC URL", "ws://eth-devnet:8545", []string{"ws", "wss"})
  354. polygonSepoliaContract = NodeCmd.Flags().String("polygonSepoliaContract", "", "Polygon on Sepolia contract address")
  355. logLevel = NodeCmd.Flags().String("logLevel", "info", "Logging level (debug, info, warn, error, dpanic, panic, fatal)")
  356. 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))")
  357. publicRpcLogToTelemetry = NodeCmd.Flags().Bool("logPublicRpcToTelemetry", true, "whether or not to include publicRpc request logs in telemetry")
  358. unsafeDevMode = NodeCmd.Flags().Bool("unsafeDevMode", false, "Launch node in unsafe, deterministic devnet mode")
  359. testnetMode = NodeCmd.Flags().Bool("testnetMode", false, "Launch node in testnet mode (enables testnet-only features)")
  360. nodeName = NodeCmd.Flags().String("nodeName", "", "Node name to announce in gossip heartbeats")
  361. publicRPC = NodeCmd.Flags().String("publicRPC", "", "Listen address for public gRPC interface")
  362. publicWeb = NodeCmd.Flags().String("publicWeb", "", "Listen address for public REST and gRPC Web interface")
  363. tlsHostname = NodeCmd.Flags().String("tlsHostname", "", "If set, serve publicWeb as TLS with this hostname using Let's Encrypt")
  364. tlsProdEnv = NodeCmd.Flags().Bool("tlsProdEnv", false,
  365. "Use the production Let's Encrypt environment instead of staging")
  366. disableHeartbeatVerify = NodeCmd.Flags().Bool("disableHeartbeatVerify", false,
  367. "Disable heartbeat signature verification (useful during network startup)")
  368. disableTelemetry = NodeCmd.Flags().Bool("disableTelemetry", false,
  369. "Disable telemetry")
  370. telemetryLokiURL = NodeCmd.Flags().String("telemetryLokiURL", "", "Loki cloud logging URL")
  371. promRemoteURL = NodeCmd.Flags().String("promRemoteURL", "", "Prometheus remote write URL (Grafana)")
  372. chainGovernorEnabled = NodeCmd.Flags().Bool("chainGovernorEnabled", false, "Run the chain governor")
  373. governorFlowCancelEnabled = NodeCmd.Flags().Bool("governorFlowCancelEnabled", false, "Enable flow cancel on the governor")
  374. coinGeckoApiKey = NodeCmd.Flags().String("coinGeckoApiKey", "", "CoinGecko Pro API key. If no API key is provided, CoinGecko requests may be throttled or blocked.")
  375. ccqEnabled = NodeCmd.Flags().Bool("ccqEnabled", false, "Enable cross chain query support")
  376. ccqAllowedRequesters = NodeCmd.Flags().String("ccqAllowedRequesters", "", "Comma separated list of signers allowed to submit cross chain queries")
  377. ccqP2pPort = NodeCmd.Flags().Uint("ccqP2pPort", 8996, "CCQ P2P UDP listener port")
  378. ccqP2pBootstrap = NodeCmd.Flags().String("ccqP2pBootstrap", "", "CCQ P2P bootstrap peers (optional for mainnet or testnet, overrides default, required for unsafeDevMode)")
  379. NodeCmd.Flags().StringSliceVarP(&ccqProtectedPeers, "ccqProtectedPeers", "", []string{}, "")
  380. ccqAllowedPeers = NodeCmd.Flags().String("ccqAllowedPeers", "", "CCQ allowed P2P peers (comma-separated)")
  381. ccqBackfillCache = NodeCmd.Flags().Bool("ccqBackfillCache", true, "Should EVM chains backfill CCQ timestamp cache on startup")
  382. gossipAdvertiseAddress = NodeCmd.Flags().String("gossipAdvertiseAddress", "", "External IP to advertize on Guardian and CCQ p2p (use if behind a NAT or running in k8s)")
  383. gatewayRelayerContract = NodeCmd.Flags().String("gatewayRelayerContract", "", "Address of the smart contract on wormchain to receive relayed VAAs")
  384. gatewayRelayerKeyPath = NodeCmd.Flags().String("gatewayRelayerKeyPath", "", "Path to gateway relayer private key for signing transactions")
  385. gatewayRelayerKeyPassPhrase = NodeCmd.Flags().String("gatewayRelayerKeyPassPhrase", "", "Pass phrase used to unarmor the gateway relayer key file")
  386. subscribeToVAAs = NodeCmd.Flags().Bool("subscribeToVAAs", false, "Guardiand should subscribe to incoming signed VAAs, set to true if running a public RPC node")
  387. transferVerifierEnabledChainIDs = NodeCmd.Flags().UintSlice("transferVerifierEnabledChainIDs", make([]uint, 0), "Transfer Verifier will be enabled for these chain IDs (comma-separated)")
  388. notaryEnabled = NodeCmd.Flags().Bool("notaryEnabled", false, "Run the notary")
  389. }
  390. var (
  391. rootCtx context.Context
  392. rootCtxCancel context.CancelFunc
  393. )
  394. const envPrefix = "GUARDIAND"
  395. // "Why would anyone do this?" are famous last words.
  396. //
  397. // We already forcibly override RPC URLs and keys in dev mode to prevent security
  398. // risks from operator error, but an extra warning won't hurt.
  399. const devwarning = `
  400. +++++++++++++++++++++++++++++++++++++++++++++++++++
  401. | NODE IS RUNNING IN INSECURE DEVELOPMENT MODE |
  402. | |
  403. | Do not use --unsafeDevMode in prod. |
  404. +++++++++++++++++++++++++++++++++++++++++++++++++++
  405. `
  406. // NodeCmd represents the node command
  407. var NodeCmd = &cobra.Command{
  408. Use: "node",
  409. Short: "Run the guardiand node",
  410. PersistentPreRunE: initConfig,
  411. Run: runNode,
  412. }
  413. // This variable may be overridden by the -X linker flag to "dev" in which case
  414. // we enforce the --unsafeDevMode flag. Only development binaries/docker images
  415. // are distributed. Production binaries are required to be built from source by
  416. // guardians to reduce risk from a compromised builder.
  417. var Build = "prod"
  418. // initConfig initializes the file configuration.
  419. func initConfig(cmd *cobra.Command, args []string) error {
  420. return node.InitFileConfig(cmd, node.ConfigOptions{
  421. FilePath: viper.ConfigFileUsed(),
  422. EnvPrefix: envPrefix,
  423. })
  424. }
  425. func runNode(cmd *cobra.Command, args []string) {
  426. if *unsafeDevMode && *testnetMode {
  427. fmt.Println("Cannot be in unsafeDevMode and testnetMode at the same time.")
  428. }
  429. // Determine execution mode
  430. if *unsafeDevMode {
  431. env = common.UnsafeDevNet
  432. } else if *testnetMode {
  433. env = common.TestNet
  434. } else {
  435. env = common.MainNet
  436. }
  437. if Build == "dev" && env != common.UnsafeDevNet {
  438. fmt.Println("This is a development build. --unsafeDevMode must be enabled.")
  439. os.Exit(1)
  440. }
  441. if env == common.UnsafeDevNet {
  442. fmt.Print(devwarning)
  443. }
  444. if env != common.MainNet {
  445. fmt.Println("Not locking in memory.")
  446. } else {
  447. common.LockMemory()
  448. }
  449. common.SetRestrictiveUmask()
  450. // Refuse to run as root in production mode.
  451. if env != common.UnsafeDevNet && os.Geteuid() == 0 {
  452. fmt.Println("can't run as uid 0")
  453. os.Exit(1)
  454. }
  455. // Set up logging. The go-log zap wrapper that libp2p uses is compatible with our
  456. // usage of zap in supervisor, which is nice.
  457. lvl, err := ipfslog.LevelFromString(*logLevel)
  458. if err != nil {
  459. fmt.Println("Invalid log level")
  460. os.Exit(1)
  461. }
  462. if !(*chainGovernorEnabled) && *governorFlowCancelEnabled {
  463. fmt.Println("Flow cancel can only be enabled when the governor is enabled")
  464. os.Exit(1)
  465. }
  466. logger := zap.New(zapcore.NewCore(
  467. consoleEncoder{zapcore.NewConsoleEncoder(
  468. zap.NewDevelopmentEncoderConfig())},
  469. zapcore.AddSync(zapcore.Lock(os.Stderr)),
  470. zap.NewAtomicLevelAt(zapcore.Level(lvl))))
  471. if env == common.UnsafeDevNet {
  472. // Use the hostname as nodeName. For production, we don't want to do this to
  473. // prevent accidentally leaking sensitive hostnames.
  474. hostname, err := os.Hostname()
  475. if err != nil {
  476. panic(err)
  477. }
  478. *nodeName = hostname
  479. // Put node name into the log for development.
  480. logger = logger.Named(*nodeName)
  481. }
  482. // Override the default go-log config, which uses a magic environment variable.
  483. logger.Info("setting level for all loggers", zap.String("level", logger.Level().String()))
  484. ipfslog.SetAllLoggers(lvl)
  485. if viper.ConfigFileUsed() != "" {
  486. logger.Info("loaded config file", zap.String("filePath", viper.ConfigFileUsed()))
  487. }
  488. // In devnet mode, we automatically set a number of flags that rely on deterministic keys.
  489. if env == common.UnsafeDevNet {
  490. g0key, err := peer.IDFromPrivateKey(devnet.DeterministicP2PPrivKeyByIndex(0))
  491. if err != nil {
  492. panic(err)
  493. }
  494. // Use the first guardian node as bootstrap
  495. if *p2pBootstrap == "" {
  496. *p2pBootstrap = fmt.Sprintf("/dns4/guardian-0.guardian/udp/%d/quic/p2p/%s", *p2pPort, g0key.String())
  497. }
  498. if *ccqP2pBootstrap == "" {
  499. *ccqP2pBootstrap = fmt.Sprintf("/dns4/guardian-0.guardian/udp/%d/quic/p2p/%s", *ccqP2pPort, g0key.String())
  500. }
  501. if *p2pNetworkID == "" {
  502. *p2pNetworkID = p2p.GetNetworkId(env)
  503. }
  504. } else { // Mainnet or Testnet.
  505. // If the network parameters are not specified, use the defaults. Log a warning if they are specified since we want to discourage this.
  506. // Note that we don't want to prevent it, to allow for network upgrade testing.
  507. if *p2pNetworkID == "" {
  508. *p2pNetworkID = p2p.GetNetworkId(env)
  509. } else {
  510. logger.Warn("overriding default p2p network ID", zap.String("p2pNetworkID", *p2pNetworkID))
  511. }
  512. if *p2pBootstrap == "" {
  513. *p2pBootstrap, err = p2p.GetBootstrapPeers(env)
  514. if err != nil {
  515. logger.Fatal("failed to determine p2p bootstrap peers", zap.String("env", string(env)), zap.Error(err))
  516. }
  517. } else {
  518. logger.Warn("overriding default p2p bootstrap peers", zap.String("p2pBootstrap", *p2pBootstrap))
  519. }
  520. if *ccqP2pBootstrap == "" {
  521. *ccqP2pBootstrap, err = p2p.GetCcqBootstrapPeers(env)
  522. if err != nil {
  523. logger.Fatal("failed to determine ccq bootstrap peers", zap.String("env", string(env)), zap.Error(err))
  524. }
  525. } else {
  526. logger.Warn("overriding default ccq bootstrap peers", zap.String("ccqP2pBootstrap", *ccqP2pBootstrap))
  527. }
  528. }
  529. // Verify flags
  530. if *nodeName == "" && env == common.MainNet {
  531. logger.Fatal("Please specify --nodeName")
  532. }
  533. if *nodeKeyPath == "" && env != common.UnsafeDevNet { // In devnet mode, keys are deterministically generated.
  534. logger.Fatal("Please specify --nodeKey")
  535. }
  536. if *guardianKeyPath == "" {
  537. // This if-statement is nested, since checking if both are empty at once will always result in the else-branch
  538. // being executed if at least one is specified. For example, in the case where the signer URI is specified and
  539. // the guardianKeyPath not, then the else-statement will create an empty `file://` URI.
  540. if *guardianSignerUri == "" {
  541. logger.Fatal("Please specify --guardianKey or --guardianSignerUri")
  542. }
  543. } else {
  544. // To avoid confusion, require that only guardianKey or guardianSignerUri can be specified
  545. if *guardianSignerUri != "" {
  546. logger.Fatal("Please only specify --guardianKey or --guardianSignerUri")
  547. }
  548. // If guardianKeyPath is set, set guardianSignerUri to the file signer URI, pointing to guardianKeyPath.
  549. // This ensures that the signer-abstracted guardian has backwards compatibility with guardians that would
  550. // just like to ignore the new guardianSignerUri altogether.
  551. *guardianSignerUri = fmt.Sprintf("file://%s", *guardianKeyPath)
  552. }
  553. if *adminSocketPath == "" {
  554. logger.Fatal("Please specify --adminSocket")
  555. }
  556. if *adminSocketPath == *publicGRPCSocketPath {
  557. logger.Fatal("--adminSocket must not equal --publicGRPCSocket")
  558. }
  559. if (*publicRPC != "" || *publicWeb != "") && *publicGRPCSocketPath == "" {
  560. logger.Fatal("If either --publicRPC or --publicWeb is specified, --publicGRPCSocket must also be specified")
  561. }
  562. if *dataDir == "" {
  563. logger.Fatal("Please specify --dataDir")
  564. }
  565. // Ethereum is required since we use it to get the guardian set. All other chains are optional.
  566. if *ethRPC == "" {
  567. logger.Fatal("Please specify --ethRPC")
  568. }
  569. // In devnet mode, we generate a deterministic guardian key and write it to disk.
  570. if env == common.UnsafeDevNet {
  571. // Only if the signer is file-based should we generate the deterministic key and write it to disk
  572. if st, _, _ := guardiansigner.ParseSignerUri(*guardianSignerUri); st == guardiansigner.FileSignerType {
  573. err := devnet.GenerateAndStoreDevnetGuardianKey(*guardianKeyPath)
  574. if err != nil {
  575. logger.Fatal("failed to generate devnet guardian key", zap.Error(err))
  576. }
  577. }
  578. }
  579. // Node's main lifecycle context.
  580. rootCtx, rootCtxCancel = context.WithCancel(context.Background())
  581. defer rootCtxCancel()
  582. // Create the Guardian Signer
  583. guardianSigner, err := guardiansigner.NewGuardianSignerFromUri(rootCtx, *guardianSignerUri, env == common.UnsafeDevNet)
  584. if err != nil {
  585. logger.Fatal("failed to create a new guardian signer", zap.Error(err))
  586. }
  587. logger.Info("Created the guardian signer", zap.String(
  588. "address", ethcrypto.PubkeyToAddress(guardianSigner.PublicKey(rootCtx)).String()))
  589. // Load p2p private key
  590. var p2pKey libp2p_crypto.PrivKey
  591. if env == common.UnsafeDevNet {
  592. idx, err := devnet.GetDevnetIndex()
  593. if err != nil {
  594. logger.Fatal("Failed to parse hostname - are we running in devnet?")
  595. }
  596. p2pKey = devnet.DeterministicP2PPrivKeyByIndex(int64(idx))
  597. if idx != 0 {
  598. firstGuardianName, err := devnet.GetFirstGuardianNameFromBootstrapPeers(*p2pBootstrap)
  599. if err != nil {
  600. logger.Fatal("failed to get first guardian name from bootstrap peers", zap.String("bootstrapPeers", *p2pBootstrap), zap.Error(err))
  601. }
  602. // try to connect to guardian-0
  603. for {
  604. //nolint:noctx // TODO: this should be refactored to use context.
  605. _, err := net.LookupIP(firstGuardianName)
  606. if err == nil {
  607. break
  608. }
  609. logger.Info(fmt.Sprintf("Error resolving %s. Trying again...", firstGuardianName))
  610. time.Sleep(time.Second)
  611. }
  612. // 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.
  613. // This may no longer be necessary because now the p2p.go ensures that it can connect to at least one bootstrap peer and will
  614. // exit the whole guardian if it is unable to. Sleeping here for a bit may reduce overall startup time by preventing unnecessary restarts, though.
  615. logger.Info("This is not a bootstrap Guardian. Waiting another 10 seconds for the bootstrap guardian to come online.")
  616. time.Sleep(time.Second * 10)
  617. }
  618. } else {
  619. p2pKey, err = common.GetOrCreateNodeKey(logger, *nodeKeyPath)
  620. if err != nil {
  621. logger.Fatal("Failed to load node key", zap.Error(err))
  622. }
  623. }
  624. // Set up telemetry if it is enabled. We can't do this until we have the p2p key and the guardian key.
  625. // Telemetry is enabled by default in mainnet/testnet. In devnet it is disabled by default.
  626. usingLoki := *telemetryLokiURL != ""
  627. if !*disableTelemetry && (env != common.UnsafeDevNet || (env == common.UnsafeDevNet && usingLoki)) {
  628. if !usingLoki {
  629. logger.Fatal("Please specify --telemetryLokiURL or set --disableTelemetry=false")
  630. }
  631. if *nodeName == "" {
  632. logger.Fatal("If telemetry is enabled, --nodeName must be set")
  633. }
  634. // Get libp2p peer ID from private key
  635. pk := p2pKey.GetPublic()
  636. peerID, err := peer.IDFromPublicKey(pk)
  637. if err != nil {
  638. logger.Fatal("Failed to get peer ID from private key", zap.Error(err))
  639. }
  640. labels := map[string]string{
  641. "node_name": *nodeName,
  642. "node_key": peerID.String(),
  643. "guardian_addr": ethcrypto.PubkeyToAddress(guardianSigner.PublicKey(rootCtx)).String(),
  644. "network": *p2pNetworkID,
  645. "version": version.Version(),
  646. }
  647. skipPrivateLogs := !*publicRpcLogToTelemetry
  648. var tm *telemetry.Telemetry
  649. if usingLoki {
  650. logger.Info("Using Loki telemetry logger",
  651. zap.String("publicRpcLogDetail", *publicRpcLogDetailStr),
  652. zap.Bool("logPublicRpcToTelemetry", *publicRpcLogToTelemetry))
  653. tm, err = telemetry.NewLokiCloudLogger(context.Background(), logger, *telemetryLokiURL, "wormhole", skipPrivateLogs, labels)
  654. if err != nil {
  655. logger.Fatal("Failed to initialize telemetry", zap.Error(err))
  656. }
  657. }
  658. defer tm.Close()
  659. logger = tm.WrapLogger(logger) // Wrap logger with telemetry logger
  660. }
  661. // Validate the args for all the EVM chains. The last flag indicates if the chain is allowed in mainnet.
  662. *ethContract = checkEvmArgs(logger, *ethRPC, *ethContract, vaa.ChainIDEthereum)
  663. *bscContract = checkEvmArgs(logger, *bscRPC, *bscContract, vaa.ChainIDBSC)
  664. *polygonContract = checkEvmArgs(logger, *polygonRPC, *polygonContract, vaa.ChainIDPolygon)
  665. *avalancheContract = checkEvmArgs(logger, *avalancheRPC, *avalancheContract, vaa.ChainIDAvalanche)
  666. *fantomContract = checkEvmArgs(logger, *fantomRPC, *fantomContract, vaa.ChainIDFantom)
  667. *klaytnContract = checkEvmArgs(logger, *klaytnRPC, *klaytnContract, vaa.ChainIDKlaytn)
  668. *celoContract = checkEvmArgs(logger, *celoRPC, *celoContract, vaa.ChainIDCelo)
  669. *moonbeamContract = checkEvmArgs(logger, *moonbeamRPC, *moonbeamContract, vaa.ChainIDMoonbeam)
  670. *arbitrumContract = checkEvmArgs(logger, *arbitrumRPC, *arbitrumContract, vaa.ChainIDArbitrum)
  671. *optimismContract = checkEvmArgs(logger, *optimismRPC, *optimismContract, vaa.ChainIDOptimism)
  672. *baseContract = checkEvmArgs(logger, *baseRPC, *baseContract, vaa.ChainIDBase)
  673. *scrollContract = checkEvmArgs(logger, *scrollRPC, *scrollContract, vaa.ChainIDScroll)
  674. *mantleContract = checkEvmArgs(logger, *mantleRPC, *mantleContract, vaa.ChainIDMantle)
  675. *xlayerContract = checkEvmArgs(logger, *xlayerRPC, *xlayerContract, vaa.ChainIDXLayer)
  676. *lineaContract = checkEvmArgs(logger, *lineaRPC, *lineaContract, vaa.ChainIDLinea)
  677. *berachainContract = checkEvmArgs(logger, *berachainRPC, *berachainContract, vaa.ChainIDBerachain)
  678. *unichainContract = checkEvmArgs(logger, *unichainRPC, *unichainContract, vaa.ChainIDUnichain)
  679. *worldchainContract = checkEvmArgs(logger, *worldchainRPC, *worldchainContract, vaa.ChainIDWorldchain)
  680. *inkContract = checkEvmArgs(logger, *inkRPC, *inkContract, vaa.ChainIDInk)
  681. *hyperEvmContract = checkEvmArgs(logger, *hyperEvmRPC, *hyperEvmContract, vaa.ChainIDHyperEVM)
  682. *monadContract = checkEvmArgs(logger, *monadRPC, *monadContract, vaa.ChainIDMonad)
  683. *seiEvmContract = checkEvmArgs(logger, *seiEvmRPC, *seiEvmContract, vaa.ChainIDSeiEVM)
  684. *mezoContract = checkEvmArgs(logger, *mezoRPC, *mezoContract, vaa.ChainIDMezo)
  685. *convergeContract = checkEvmArgs(logger, *convergeRPC, *convergeContract, vaa.ChainIDConverge)
  686. *plumeContract = checkEvmArgs(logger, *plumeRPC, *plumeContract, vaa.ChainIDPlume)
  687. *xrplEvmContract = checkEvmArgs(logger, *xrplEvmRPC, *xrplEvmContract, vaa.ChainIDXRPLEVM)
  688. *plasmaContract = checkEvmArgs(logger, *plasmaRPC, *plasmaContract, vaa.ChainIDPlasma)
  689. *creditCoinContract = checkEvmArgs(logger, *creditCoinRPC, *creditCoinContract, vaa.ChainIDCreditCoin)
  690. *mocaContract = checkEvmArgs(logger, *mocaRPC, *mocaContract, vaa.ChainIDMoca)
  691. // These chains will only ever be testnet / devnet.
  692. *sepoliaContract = checkEvmArgs(logger, *sepoliaRPC, *sepoliaContract, vaa.ChainIDSepolia)
  693. *arbitrumSepoliaContract = checkEvmArgs(logger, *arbitrumSepoliaRPC, *arbitrumSepoliaContract, vaa.ChainIDArbitrumSepolia)
  694. *baseSepoliaContract = checkEvmArgs(logger, *baseSepoliaRPC, *baseSepoliaContract, vaa.ChainIDBaseSepolia)
  695. *optimismSepoliaContract = checkEvmArgs(logger, *optimismSepoliaRPC, *optimismSepoliaContract, vaa.ChainIDOptimismSepolia)
  696. *holeskyContract = checkEvmArgs(logger, *holeskyRPC, *holeskyContract, vaa.ChainIDHolesky)
  697. *polygonSepoliaContract = checkEvmArgs(logger, *polygonSepoliaRPC, *polygonSepoliaContract, vaa.ChainIDPolygonSepolia)
  698. if !argsConsistent([]string{*solanaContract, *solanaRPC}) {
  699. logger.Fatal("Both --solanaContract and --solanaRPC must be set or both unset")
  700. }
  701. if *solanaShimContract != "" && *solanaContract == "" {
  702. logger.Fatal("--solanaShimContract may only be specified if --solanaContract is specified")
  703. }
  704. if !argsConsistent([]string{*fogoContract, *fogoRPC}) {
  705. logger.Fatal("Both --fogoContract and --fogoRPC must be set or both unset")
  706. }
  707. if *fogoShimContract != "" && *fogoContract == "" {
  708. logger.Fatal("--fogoShimContract may only be specified if --fogoContract is specified")
  709. }
  710. if !argsConsistent([]string{*pythnetContract, *pythnetRPC, *pythnetWS}) {
  711. logger.Fatal("Either --pythnetContract, --pythnetRPC and --pythnetWS must all be set or all unset")
  712. }
  713. if !argsConsistent([]string{*terraContract, *terraWS, *terraLCD}) {
  714. logger.Fatal("Either --terraContract, --terraWS and --terraLCD must all be set or all unset")
  715. }
  716. if !argsConsistent([]string{*terra2Contract, *terra2WS, *terra2LCD}) {
  717. logger.Fatal("Either --terra2Contract, --terra2WS and --terra2LCD must all be set or all unset")
  718. }
  719. if !argsConsistent([]string{*injectiveContract, *injectiveWS, *injectiveLCD}) {
  720. logger.Fatal("Either --injectiveContract, --injectiveWS and --injectiveLCD must all be set or all unset")
  721. }
  722. if !argsConsistent([]string{*algorandIndexerRPC, *algorandAlgodRPC, *algorandAlgodToken}) {
  723. logger.Fatal("Either --algorandIndexerRPC, --algorandAlgodRPC and --algorandAlgodToken must all be set or all unset")
  724. }
  725. if *algorandIndexerRPC != "" {
  726. if *algorandAppID == 0 {
  727. logger.Fatal("If --algorandIndexerRPC is set, --algorandAppID must be set")
  728. }
  729. } else if *algorandAppID != 0 {
  730. logger.Fatal("If --algorandIndexerRPC is not set, --algorandAppID may not be set")
  731. }
  732. if !argsConsistent([]string{*nearContract, *nearRPC}) {
  733. logger.Fatal("Both --nearContract and --nearRPC must be set or both unset")
  734. }
  735. if !argsConsistent([]string{*aptosAccount, *aptosRPC, *aptosHandle}) {
  736. logger.Fatal("Either --aptosAccount, --aptosRPC and --aptosHandle must all be set or all unset")
  737. }
  738. if !argsConsistent([]string{*movementAccount, *movementRPC, *movementHandle}) {
  739. logger.Fatal("Either --movementAccount, --movementRPC and --movementHandle must all be set or all unset")
  740. }
  741. if !argsConsistent([]string{*suiRPC, *suiMoveEventType}) {
  742. logger.Fatal("Either --suiRPC and --suiMoveEventType must all be set or all unset")
  743. }
  744. if !argsConsistent([]string{*gatewayContract, *gatewayWS, *gatewayLCD}) {
  745. logger.Fatal("Either --gatewayContract, --gatewayWS and --gatewayLCD must all be set or all unset")
  746. }
  747. if !*chainGovernorEnabled && *coinGeckoApiKey != "" {
  748. logger.Fatal("If coinGeckoApiKey is set, then chainGovernorEnabled must be set")
  749. }
  750. // NOTE: If this flag isn't set, or the list is empty, Transfer Verifier should not be enabled.
  751. if len(*transferVerifierEnabledChainIDs) != 0 {
  752. var parseErr error
  753. // NOTE: avoid shadowing txVerifierChains here. It should refer to the global variable.
  754. txVerifierChains, parseErr = txverifier.ValidateChains(*transferVerifierEnabledChainIDs)
  755. logger.Debug("validated txVerifierChains", zap.Any("chains", txVerifierChains))
  756. if parseErr != nil {
  757. logger.Fatal("transferVerifierEnabledChainIDs input is invalid", zap.Error(parseErr))
  758. }
  759. // Format the feature string in the form "txverifier:ethereum|sui" and append it to the feature flags.
  760. chainNames := make([]string, 0, len(txVerifierChains))
  761. for _, cid := range txVerifierChains {
  762. chainNames = append(chainNames, cid.String())
  763. }
  764. featureFlags = append(featureFlags, fmt.Sprintf("txverifier:%s", strings.Join(chainNames, "|")))
  765. }
  766. var publicRpcLogDetail common.GrpcLogDetail
  767. switch *publicRpcLogDetailStr {
  768. case "none":
  769. publicRpcLogDetail = common.GrpcLogDetailNone
  770. case "minimal":
  771. publicRpcLogDetail = common.GrpcLogDetailMinimal
  772. case "full":
  773. publicRpcLogDetail = common.GrpcLogDetailFull
  774. default:
  775. logger.Fatal("--publicRpcLogDetail should be one of (none, minimal, full)")
  776. }
  777. // Complain about Infura on mainnet.
  778. //
  779. // As it turns out, Infura has a bug where it would sometimes incorrectly round
  780. // block timestamps, which causes consensus issues - the timestamp is part of
  781. // the VAA and nodes using Infura would sometimes derive an incorrect VAA,
  782. // accidentally attacking the network by signing a conflicting VAA.
  783. //
  784. // Node operators do not usually rely on Infura in the first place - doing
  785. // so is insecure, since nodes blindly trust the connected nodes to verify
  786. // on-chain message proofs. However, node operators sometimes used
  787. // Infura during migrations where their primary node was offline, causing
  788. // the aforementioned consensus oddities which were eventually found to
  789. // be Infura-related. This is generally to the detriment of network security
  790. // and a judgement call made by individual operators. In the case of Infura,
  791. // we know it's actively dangerous so let's make an opinionated argument.
  792. //
  793. // Insert "I'm a sign, not a cop" meme.
  794. //
  795. if strings.Contains(*ethRPC, "mainnet.infura.io") ||
  796. strings.Contains(*polygonRPC, "polygon-mainnet.infura.io") {
  797. logger.Fatal("Infura is known to send incorrect blocks - please use your own nodes")
  798. }
  799. // NOTE: Please keep these in numerical order by chain ID.
  800. rpcMap := make(map[string]string)
  801. rpcMap["solanaRPC"] = *solanaRPC
  802. rpcMap["fogoRPC"] = *fogoRPC
  803. rpcMap["ethRPC"] = *ethRPC
  804. rpcMap["bscRPC"] = *bscRPC
  805. rpcMap["polygonRPC"] = *polygonRPC
  806. rpcMap["avalancheRPC"] = *avalancheRPC
  807. rpcMap["algorandIndexerRPC"] = *algorandIndexerRPC
  808. rpcMap["algorandAlgodRPC"] = *algorandAlgodRPC
  809. rpcMap["fantomRPC"] = *fantomRPC
  810. rpcMap["klaytnRPC"] = *klaytnRPC
  811. rpcMap["celoRPC"] = *celoRPC
  812. rpcMap["nearRPC"] = *nearRPC
  813. rpcMap["moonbeamRPC"] = *moonbeamRPC
  814. rpcMap["injectiveLCD"] = *injectiveLCD
  815. rpcMap["injectiveWS"] = *injectiveWS
  816. // ChainIDOsmosis is not supported in the guardian.
  817. rpcMap["suiRPC"] = *suiRPC
  818. rpcMap["aptosRPC"] = *aptosRPC
  819. rpcMap["arbitrumRPC"] = *arbitrumRPC
  820. rpcMap["optimismRPC"] = *optimismRPC
  821. // ChainIDGnosis is not supported in the guardian.
  822. rpcMap["pythnetRPC"] = *pythnetRPC
  823. rpcMap["pythnetWS"] = *pythnetWS
  824. // ChainIDBtc is not supported in the guardian.
  825. rpcMap["baseRPC"] = *baseRPC
  826. // ChainIDSei is supported over IBC, so it's not listed here.
  827. // ChainIDRootstock is not supported in the guardian.
  828. rpcMap["scrollRPC"] = *scrollRPC
  829. rpcMap["mantleRPC"] = *mantleRPC
  830. rpcMap["xlayerRPC"] = *xlayerRPC
  831. rpcMap["lineaRPC"] = *lineaRPC
  832. rpcMap["berachainRPC"] = *berachainRPC
  833. rpcMap["seiEvmRPC"] = *seiEvmRPC
  834. rpcMap["unichainRPC"] = *unichainRPC
  835. rpcMap["worldchainRPC"] = *worldchainRPC
  836. rpcMap["inkRPC"] = *inkRPC
  837. rpcMap["hyperEvmRPC"] = *hyperEvmRPC
  838. rpcMap["monadRPC"] = *monadRPC
  839. rpcMap["movementRPC"] = *movementRPC
  840. rpcMap["mezoRPC"] = *mezoRPC
  841. rpcMap["convergeRPC"] = *convergeRPC
  842. rpcMap["plumeRPC"] = *plumeRPC
  843. rpcMap["xrplevmRPC"] = *xrplEvmRPC
  844. rpcMap["plasmaRPC"] = *plasmaRPC
  845. rpcMap["creditcoinRPC"] = *creditCoinRPC
  846. // Wormchain is in the 3000 range.
  847. rpcMap["wormchainURL"] = *wormchainURL
  848. // Generate the IBC chains (3000 range).
  849. for _, ibcChain := range ibc.Chains {
  850. rpcMap[ibcChain.String()] = "IBC"
  851. }
  852. // The testnet only chains (10000 range) go here.
  853. if env == common.TestNet {
  854. rpcMap["sepoliaRPC"] = *sepoliaRPC
  855. rpcMap["arbitrumSepoliaRPC"] = *arbitrumSepoliaRPC
  856. rpcMap["baseSepoliaRPC"] = *baseSepoliaRPC
  857. rpcMap["optimismSepoliaRPC"] = *optimismSepoliaRPC
  858. rpcMap["holeskyRPC"] = *holeskyRPC
  859. rpcMap["polygonSepoliaRPC"] = *polygonSepoliaRPC
  860. }
  861. // Other, non-chain specific parameters go here.
  862. rpcMap["accountantWS"] = *accountantWS
  863. rpcMap["gatewayWS"] = *gatewayWS
  864. rpcMap["gatewayLCD"] = *gatewayLCD
  865. rpcMap["ibcBlockHeightURL"] = *ibcBlockHeightURL
  866. rpcMap["ibcLCD"] = *ibcLCD
  867. rpcMap["ibcWS"] = *ibcWS
  868. // Handle SIGTERM
  869. sigterm := make(chan os.Signal, 1)
  870. signal.Notify(sigterm, syscall.SIGTERM)
  871. go func() {
  872. <-sigterm
  873. logger.Info("Received sigterm. exiting.")
  874. rootCtxCancel()
  875. }()
  876. // log golang version
  877. logger.Info("golang version", zap.String("golang_version", runtime.Version()))
  878. // Redirect ipfs logs to plain zap
  879. ipfslog.SetPrimaryCore(logger.Core())
  880. // Database
  881. db := guardianDB.OpenDb(logger.With(zap.String("component", "badgerDb")), dataDir)
  882. defer db.Close()
  883. wormchainId := "wormchain"
  884. if env == common.TestNet {
  885. wormchainId = "wormchain-testnet-0"
  886. }
  887. var accountantWormchainConn, accountantNttWormchainConn *wormconn.ClientConn
  888. if *accountantContract != "" {
  889. if *wormchainURL == "" {
  890. logger.Fatal("if accountantContract is specified, wormchainURL is required", zap.String("component", "gacct"))
  891. }
  892. if *accountantKeyPath == "" {
  893. logger.Fatal("if accountantContract is specified, accountantKeyPath is required", zap.String("component", "gacct"))
  894. }
  895. if *accountantKeyPassPhrase == "" {
  896. logger.Fatal("if accountantContract is specified, accountantKeyPassPhrase is required", zap.String("component", "gacct"))
  897. }
  898. keyPathName := *accountantKeyPath
  899. if env == common.UnsafeDevNet {
  900. idx, err := devnet.GetDevnetIndex()
  901. if err != nil {
  902. logger.Fatal("failed to get devnet index", zap.Error(err), zap.String("component", "gacct"))
  903. }
  904. keyPathName = fmt.Sprint(*accountantKeyPath, idx)
  905. }
  906. wormchainKey, err := wormconn.LoadWormchainPrivKey(keyPathName, *accountantKeyPassPhrase)
  907. if err != nil {
  908. logger.Fatal("failed to load accountant private key", zap.Error(err), zap.String("component", "gacct"))
  909. }
  910. // Connect to wormchain for the accountant.
  911. logger.Info("Connecting to wormchain for accountant", zap.String("wormchainURL", *wormchainURL), zap.String("keyPath", keyPathName), zap.String("component", "gacct"))
  912. accountantWormchainConn, err = wormconn.NewConn(rootCtx, *wormchainURL, wormchainKey, wormchainId)
  913. if err != nil {
  914. logger.Fatal("failed to connect to wormchain for accountant", zap.Error(err), zap.String("component", "gacct"))
  915. }
  916. }
  917. // If the NTT accountant is enabled, create a wormchain connection for it.
  918. if *accountantNttContract != "" {
  919. if *wormchainURL == "" {
  920. logger.Fatal("if accountantNttContract is specified, wormchainURL is required", zap.String("component", "gacct"))
  921. }
  922. if *accountantNttKeyPath == "" {
  923. logger.Fatal("if accountantNttContract is specified, accountantNttKeyPath is required", zap.String("component", "gacct"))
  924. }
  925. if *accountantNttKeyPassPhrase == "" {
  926. logger.Fatal("if accountantNttContract is specified, accountantNttKeyPassPhrase is required", zap.String("component", "gacct"))
  927. }
  928. keyPathName := *accountantNttKeyPath
  929. if env == common.UnsafeDevNet {
  930. idx, err := devnet.GetDevnetIndex()
  931. if err != nil {
  932. logger.Fatal("failed to get devnet index", zap.Error(err), zap.String("component", "gacct"))
  933. }
  934. keyPathName = fmt.Sprint(*accountantNttKeyPath, idx)
  935. }
  936. wormchainKey, err := wormconn.LoadWormchainPrivKey(keyPathName, *accountantNttKeyPassPhrase)
  937. if err != nil {
  938. logger.Fatal("failed to load NTT accountant private key", zap.Error(err), zap.String("component", "gacct"))
  939. }
  940. // Connect to wormchain for the NTT accountant.
  941. logger.Info("Connecting to wormchain for NTT accountant", zap.String("wormchainURL", *wormchainURL), zap.String("keyPath", keyPathName), zap.String("component", "gacct"))
  942. accountantNttWormchainConn, err = wormconn.NewConn(rootCtx, *wormchainURL, wormchainKey, wormchainId)
  943. if err != nil {
  944. logger.Fatal("failed to connect to wormchain for NTT accountant", zap.Error(err), zap.String("component", "gacct"))
  945. }
  946. }
  947. var gatewayRelayerWormchainConn *wormconn.ClientConn
  948. if *gatewayRelayerContract != "" {
  949. if *wormchainURL == "" {
  950. logger.Fatal("if gatewayRelayerContract is specified, wormchainURL is required", zap.String("component", "gwrelayer"))
  951. }
  952. if *gatewayRelayerKeyPath == "" {
  953. logger.Fatal("if gatewayRelayerContract is specified, gatewayRelayerKeyPath is required", zap.String("component", "gwrelayer"))
  954. }
  955. if *gatewayRelayerKeyPassPhrase == "" {
  956. logger.Fatal("if gatewayRelayerContract is specified, gatewayRelayerKeyPassPhrase is required", zap.String("component", "gwrelayer"))
  957. }
  958. wormchainKeyPathName := *gatewayRelayerKeyPath
  959. if env == common.UnsafeDevNet {
  960. idx, err := devnet.GetDevnetIndex()
  961. if err != nil {
  962. logger.Fatal("failed to get devnet index", zap.Error(err), zap.String("component", "gwrelayer"))
  963. }
  964. wormchainKeyPathName = fmt.Sprint(*gatewayRelayerKeyPath, idx)
  965. }
  966. wormchainKey, err := wormconn.LoadWormchainPrivKey(wormchainKeyPathName, *gatewayRelayerKeyPassPhrase)
  967. if err != nil {
  968. logger.Fatal("failed to load private key", zap.Error(err), zap.String("component", "gwrelayer"))
  969. }
  970. logger.Info("Connecting to wormchain", zap.String("wormchainURL", *wormchainURL), zap.String("keyPath", wormchainKeyPathName), zap.String("component", "gwrelayer"))
  971. gatewayRelayerWormchainConn, err = wormconn.NewConn(rootCtx, *wormchainURL, wormchainKey, wormchainId)
  972. if err != nil {
  973. logger.Fatal("failed to connect to wormchain", zap.Error(err), zap.String("component", "gwrelayer"))
  974. }
  975. }
  976. usingPromRemoteWrite := *promRemoteURL != ""
  977. if usingPromRemoteWrite {
  978. var info promremotew.PromTelemetryInfo
  979. info.PromRemoteURL = *promRemoteURL
  980. info.Labels = map[string]string{
  981. "node_name": *nodeName,
  982. "guardian_addr": ethcrypto.PubkeyToAddress(guardianSigner.PublicKey(rootCtx)).String(),
  983. "network": *p2pNetworkID,
  984. "version": version.Version(),
  985. "product": "wormhole",
  986. }
  987. promLogger := logger.With(zap.String("component", "prometheus_scraper"))
  988. errC := make(chan error)
  989. common.StartRunnable(rootCtx, errC, false, "prometheus_scraper", func(ctx context.Context) error {
  990. t := time.NewTicker(15 * time.Second)
  991. for {
  992. select {
  993. case <-ctx.Done():
  994. return nil
  995. case <-t.C:
  996. err := promremotew.ScrapeAndSendLocalMetrics(ctx, info, promLogger)
  997. if err != nil {
  998. promLogger.Error("ScrapeAndSendLocalMetrics error", zap.Error(err))
  999. continue
  1000. }
  1001. }
  1002. }
  1003. })
  1004. }
  1005. watcherConfigs := []watchers.WatcherConfig{}
  1006. if shouldStart(ethRPC) {
  1007. wc := &evm.WatcherConfig{
  1008. NetworkID: "eth",
  1009. ChainID: vaa.ChainIDEthereum,
  1010. Rpc: *ethRPC,
  1011. Contract: *ethContract,
  1012. GuardianSetUpdateChain: true,
  1013. CcqBackfillCache: *ccqBackfillCache,
  1014. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDEthereum),
  1015. }
  1016. watcherConfigs = append(watcherConfigs, wc)
  1017. }
  1018. if shouldStart(bscRPC) {
  1019. wc := &evm.WatcherConfig{
  1020. NetworkID: "bsc",
  1021. ChainID: vaa.ChainIDBSC,
  1022. Rpc: *bscRPC,
  1023. Contract: *bscContract,
  1024. CcqBackfillCache: *ccqBackfillCache,
  1025. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDBSC),
  1026. }
  1027. watcherConfigs = append(watcherConfigs, wc)
  1028. }
  1029. if shouldStart(polygonRPC) {
  1030. wc := &evm.WatcherConfig{
  1031. NetworkID: "polygon",
  1032. ChainID: vaa.ChainIDPolygon,
  1033. Rpc: *polygonRPC,
  1034. Contract: *polygonContract,
  1035. CcqBackfillCache: *ccqBackfillCache,
  1036. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDPolygon),
  1037. }
  1038. watcherConfigs = append(watcherConfigs, wc)
  1039. }
  1040. if shouldStart(avalancheRPC) {
  1041. wc := &evm.WatcherConfig{
  1042. NetworkID: "avalanche",
  1043. ChainID: vaa.ChainIDAvalanche,
  1044. Rpc: *avalancheRPC,
  1045. Contract: *avalancheContract,
  1046. CcqBackfillCache: *ccqBackfillCache,
  1047. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDAvalanche),
  1048. }
  1049. watcherConfigs = append(watcherConfigs, wc)
  1050. }
  1051. if shouldStart(fantomRPC) {
  1052. wc := &evm.WatcherConfig{
  1053. NetworkID: "fantom",
  1054. ChainID: vaa.ChainIDFantom,
  1055. Rpc: *fantomRPC,
  1056. Contract: *fantomContract,
  1057. CcqBackfillCache: *ccqBackfillCache,
  1058. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDFantom),
  1059. }
  1060. watcherConfigs = append(watcherConfigs, wc)
  1061. }
  1062. if shouldStart(klaytnRPC) {
  1063. wc := &evm.WatcherConfig{
  1064. NetworkID: "klaytn",
  1065. ChainID: vaa.ChainIDKlaytn,
  1066. Rpc: *klaytnRPC,
  1067. Contract: *klaytnContract,
  1068. CcqBackfillCache: *ccqBackfillCache,
  1069. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDKlaytn),
  1070. }
  1071. watcherConfigs = append(watcherConfigs, wc)
  1072. }
  1073. if shouldStart(celoRPC) {
  1074. wc := &evm.WatcherConfig{
  1075. NetworkID: "celo",
  1076. ChainID: vaa.ChainIDCelo,
  1077. Rpc: *celoRPC,
  1078. Contract: *celoContract,
  1079. CcqBackfillCache: *ccqBackfillCache,
  1080. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDCelo),
  1081. }
  1082. watcherConfigs = append(watcherConfigs, wc)
  1083. }
  1084. if shouldStart(moonbeamRPC) {
  1085. wc := &evm.WatcherConfig{
  1086. NetworkID: "moonbeam",
  1087. ChainID: vaa.ChainIDMoonbeam,
  1088. Rpc: *moonbeamRPC,
  1089. Contract: *moonbeamContract,
  1090. CcqBackfillCache: *ccqBackfillCache,
  1091. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDMoonbeam),
  1092. }
  1093. watcherConfigs = append(watcherConfigs, wc)
  1094. }
  1095. if shouldStart(arbitrumRPC) {
  1096. wc := &evm.WatcherConfig{
  1097. NetworkID: "arbitrum",
  1098. ChainID: vaa.ChainIDArbitrum,
  1099. Rpc: *arbitrumRPC,
  1100. Contract: *arbitrumContract,
  1101. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDArbitrum),
  1102. CcqBackfillCache: *ccqBackfillCache,
  1103. }
  1104. watcherConfigs = append(watcherConfigs, wc)
  1105. }
  1106. if shouldStart(optimismRPC) {
  1107. wc := &evm.WatcherConfig{
  1108. NetworkID: "optimism",
  1109. ChainID: vaa.ChainIDOptimism,
  1110. Rpc: *optimismRPC,
  1111. Contract: *optimismContract,
  1112. CcqBackfillCache: *ccqBackfillCache,
  1113. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDOptimism),
  1114. }
  1115. watcherConfigs = append(watcherConfigs, wc)
  1116. }
  1117. if shouldStart(baseRPC) {
  1118. wc := &evm.WatcherConfig{
  1119. NetworkID: "base",
  1120. ChainID: vaa.ChainIDBase,
  1121. Rpc: *baseRPC,
  1122. Contract: *baseContract,
  1123. CcqBackfillCache: *ccqBackfillCache,
  1124. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDBase),
  1125. }
  1126. watcherConfigs = append(watcherConfigs, wc)
  1127. }
  1128. if shouldStart(scrollRPC) {
  1129. wc := &evm.WatcherConfig{
  1130. NetworkID: "scroll",
  1131. ChainID: vaa.ChainIDScroll,
  1132. Rpc: *scrollRPC,
  1133. Contract: *scrollContract,
  1134. CcqBackfillCache: *ccqBackfillCache,
  1135. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDScroll),
  1136. }
  1137. watcherConfigs = append(watcherConfigs, wc)
  1138. }
  1139. if shouldStart(mantleRPC) {
  1140. wc := &evm.WatcherConfig{
  1141. NetworkID: "mantle",
  1142. ChainID: vaa.ChainIDMantle,
  1143. Rpc: *mantleRPC,
  1144. Contract: *mantleContract,
  1145. CcqBackfillCache: *ccqBackfillCache,
  1146. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDMantle),
  1147. }
  1148. watcherConfigs = append(watcherConfigs, wc)
  1149. }
  1150. if shouldStart(xlayerRPC) {
  1151. wc := &evm.WatcherConfig{
  1152. NetworkID: "xlayer",
  1153. ChainID: vaa.ChainIDXLayer,
  1154. Rpc: *xlayerRPC,
  1155. Contract: *xlayerContract,
  1156. CcqBackfillCache: *ccqBackfillCache,
  1157. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDXLayer),
  1158. }
  1159. watcherConfigs = append(watcherConfigs, wc)
  1160. }
  1161. if shouldStart(lineaRPC) {
  1162. wc := &evm.WatcherConfig{
  1163. NetworkID: "linea",
  1164. ChainID: vaa.ChainIDLinea,
  1165. Rpc: *lineaRPC,
  1166. Contract: *lineaContract,
  1167. CcqBackfillCache: *ccqBackfillCache,
  1168. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDLinea),
  1169. }
  1170. watcherConfigs = append(watcherConfigs, wc)
  1171. }
  1172. if shouldStart(berachainRPC) {
  1173. wc := &evm.WatcherConfig{
  1174. NetworkID: "berachain",
  1175. ChainID: vaa.ChainIDBerachain,
  1176. Rpc: *berachainRPC,
  1177. Contract: *berachainContract,
  1178. CcqBackfillCache: *ccqBackfillCache,
  1179. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDBerachain),
  1180. }
  1181. watcherConfigs = append(watcherConfigs, wc)
  1182. }
  1183. if shouldStart(unichainRPC) {
  1184. wc := &evm.WatcherConfig{
  1185. NetworkID: "unichain",
  1186. ChainID: vaa.ChainIDUnichain,
  1187. Rpc: *unichainRPC,
  1188. Contract: *unichainContract,
  1189. CcqBackfillCache: *ccqBackfillCache,
  1190. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDUnichain),
  1191. }
  1192. watcherConfigs = append(watcherConfigs, wc)
  1193. }
  1194. if shouldStart(worldchainRPC) {
  1195. wc := &evm.WatcherConfig{
  1196. NetworkID: "worldchain",
  1197. ChainID: vaa.ChainIDWorldchain,
  1198. Rpc: *worldchainRPC,
  1199. Contract: *worldchainContract,
  1200. CcqBackfillCache: *ccqBackfillCache,
  1201. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDWorldchain),
  1202. }
  1203. watcherConfigs = append(watcherConfigs, wc)
  1204. }
  1205. if shouldStart(inkRPC) {
  1206. wc := &evm.WatcherConfig{
  1207. NetworkID: "ink",
  1208. ChainID: vaa.ChainIDInk,
  1209. Rpc: *inkRPC,
  1210. Contract: *inkContract,
  1211. CcqBackfillCache: *ccqBackfillCache,
  1212. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDInk),
  1213. }
  1214. watcherConfigs = append(watcherConfigs, wc)
  1215. }
  1216. if shouldStart(hyperEvmRPC) {
  1217. wc := &evm.WatcherConfig{
  1218. NetworkID: "hyperevm",
  1219. ChainID: vaa.ChainIDHyperEVM,
  1220. Rpc: *hyperEvmRPC,
  1221. Contract: *hyperEvmContract,
  1222. CcqBackfillCache: *ccqBackfillCache,
  1223. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDHyperEVM),
  1224. }
  1225. watcherConfigs = append(watcherConfigs, wc)
  1226. }
  1227. if shouldStart(monadRPC) {
  1228. wc := &evm.WatcherConfig{
  1229. NetworkID: "monad",
  1230. ChainID: vaa.ChainIDMonad,
  1231. Rpc: *monadRPC,
  1232. Contract: *monadContract,
  1233. CcqBackfillCache: *ccqBackfillCache,
  1234. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDMonad),
  1235. }
  1236. watcherConfigs = append(watcherConfigs, wc)
  1237. }
  1238. if shouldStart(seiEvmRPC) {
  1239. wc := &evm.WatcherConfig{
  1240. NetworkID: "seievm",
  1241. ChainID: vaa.ChainIDSeiEVM,
  1242. Rpc: *seiEvmRPC,
  1243. Contract: *seiEvmContract,
  1244. CcqBackfillCache: *ccqBackfillCache,
  1245. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDSeiEVM),
  1246. }
  1247. watcherConfigs = append(watcherConfigs, wc)
  1248. }
  1249. if shouldStart(mezoRPC) {
  1250. wc := &evm.WatcherConfig{
  1251. NetworkID: "mezo",
  1252. ChainID: vaa.ChainIDMezo,
  1253. Rpc: *mezoRPC,
  1254. Contract: *mezoContract,
  1255. CcqBackfillCache: *ccqBackfillCache,
  1256. }
  1257. watcherConfigs = append(watcherConfigs, wc)
  1258. }
  1259. if shouldStart(convergeRPC) {
  1260. wc := &evm.WatcherConfig{
  1261. NetworkID: "converge",
  1262. ChainID: vaa.ChainIDConverge,
  1263. Rpc: *convergeRPC,
  1264. Contract: *convergeContract,
  1265. CcqBackfillCache: *ccqBackfillCache,
  1266. }
  1267. watcherConfigs = append(watcherConfigs, wc)
  1268. }
  1269. if shouldStart(plumeRPC) {
  1270. wc := &evm.WatcherConfig{
  1271. NetworkID: "plume",
  1272. ChainID: vaa.ChainIDPlume,
  1273. Rpc: *plumeRPC,
  1274. Contract: *plumeContract,
  1275. CcqBackfillCache: *ccqBackfillCache,
  1276. }
  1277. watcherConfigs = append(watcherConfigs, wc)
  1278. }
  1279. if shouldStart(xrplEvmRPC) {
  1280. wc := &evm.WatcherConfig{
  1281. NetworkID: "xrplevm",
  1282. ChainID: vaa.ChainIDXRPLEVM,
  1283. Rpc: *xrplEvmRPC,
  1284. Contract: *xrplEvmContract,
  1285. CcqBackfillCache: *ccqBackfillCache,
  1286. }
  1287. watcherConfigs = append(watcherConfigs, wc)
  1288. }
  1289. if shouldStart(plasmaRPC) {
  1290. wc := &evm.WatcherConfig{
  1291. NetworkID: "plasma",
  1292. ChainID: vaa.ChainIDPlasma,
  1293. Rpc: *plasmaRPC,
  1294. Contract: *plasmaContract,
  1295. CcqBackfillCache: *ccqBackfillCache,
  1296. }
  1297. watcherConfigs = append(watcherConfigs, wc)
  1298. }
  1299. if shouldStart(creditCoinRPC) {
  1300. wc := &evm.WatcherConfig{
  1301. NetworkID: "creditcoin",
  1302. ChainID: vaa.ChainIDCreditCoin,
  1303. Rpc: *creditCoinRPC,
  1304. Contract: *creditCoinContract,
  1305. CcqBackfillCache: *ccqBackfillCache,
  1306. }
  1307. watcherConfigs = append(watcherConfigs, wc)
  1308. }
  1309. if shouldStart(mocaRPC) {
  1310. wc := &evm.WatcherConfig{
  1311. NetworkID: "moca",
  1312. ChainID: vaa.ChainIDMoca,
  1313. Rpc: *mocaRPC,
  1314. Contract: *mocaContract,
  1315. CcqBackfillCache: *ccqBackfillCache,
  1316. }
  1317. watcherConfigs = append(watcherConfigs, wc)
  1318. }
  1319. if shouldStart(terraWS) {
  1320. if env != common.UnsafeDevNet {
  1321. logger.Fatal("Terra classic is only allowed in unsafe dev mode")
  1322. }
  1323. wc := &cosmwasm.WatcherConfig{
  1324. NetworkID: "terra",
  1325. ChainID: vaa.ChainIDTerra,
  1326. Websocket: *terraWS,
  1327. Lcd: *terraLCD,
  1328. Contract: *terraContract,
  1329. }
  1330. watcherConfigs = append(watcherConfigs, wc)
  1331. }
  1332. if shouldStart(terra2WS) {
  1333. if env != common.UnsafeDevNet {
  1334. logger.Fatal("Terra2 classic is only allowed in unsafe dev mode")
  1335. }
  1336. wc := &cosmwasm.WatcherConfig{
  1337. NetworkID: "terra2",
  1338. ChainID: vaa.ChainIDTerra2,
  1339. Websocket: *terra2WS,
  1340. Lcd: *terra2LCD,
  1341. Contract: *terra2Contract,
  1342. }
  1343. watcherConfigs = append(watcherConfigs, wc)
  1344. }
  1345. if shouldStart(injectiveWS) {
  1346. wc := &cosmwasm.WatcherConfig{
  1347. NetworkID: "injective",
  1348. ChainID: vaa.ChainIDInjective,
  1349. Websocket: *injectiveWS,
  1350. Lcd: *injectiveLCD,
  1351. Contract: *injectiveContract,
  1352. }
  1353. watcherConfigs = append(watcherConfigs, wc)
  1354. }
  1355. if shouldStart(algorandIndexerRPC) {
  1356. wc := &algorand.WatcherConfig{
  1357. NetworkID: "algorand",
  1358. ChainID: vaa.ChainIDAlgorand,
  1359. IndexerRPC: *algorandIndexerRPC,
  1360. IndexerToken: *algorandIndexerToken,
  1361. AlgodRPC: *algorandAlgodRPC,
  1362. AlgodToken: *algorandAlgodToken,
  1363. AppID: *algorandAppID,
  1364. }
  1365. watcherConfigs = append(watcherConfigs, wc)
  1366. }
  1367. if shouldStart(nearRPC) {
  1368. wc := &near.WatcherConfig{
  1369. NetworkID: "near",
  1370. ChainID: vaa.ChainIDNear,
  1371. Rpc: *nearRPC,
  1372. Contract: *nearContract,
  1373. }
  1374. watcherConfigs = append(watcherConfigs, wc)
  1375. }
  1376. if shouldStart(aptosRPC) {
  1377. wc := &aptos.WatcherConfig{
  1378. NetworkID: "aptos",
  1379. ChainID: vaa.ChainIDAptos,
  1380. Rpc: *aptosRPC,
  1381. Account: *aptosAccount,
  1382. Handle: *aptosHandle,
  1383. }
  1384. watcherConfigs = append(watcherConfigs, wc)
  1385. }
  1386. if shouldStart(movementRPC) {
  1387. wc := &aptos.WatcherConfig{
  1388. NetworkID: "movement",
  1389. ChainID: vaa.ChainIDMovement,
  1390. Rpc: *movementRPC,
  1391. Account: *movementAccount,
  1392. Handle: *movementHandle,
  1393. }
  1394. watcherConfigs = append(watcherConfigs, wc)
  1395. }
  1396. if shouldStart(suiRPC) {
  1397. wc := &sui.WatcherConfig{
  1398. NetworkID: "sui",
  1399. ChainID: vaa.ChainIDSui,
  1400. Rpc: *suiRPC,
  1401. SuiMoveEventType: *suiMoveEventType,
  1402. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDSui),
  1403. }
  1404. watcherConfigs = append(watcherConfigs, wc)
  1405. }
  1406. if shouldStart(solanaRPC) {
  1407. // confirmed watcher
  1408. wc := &solana.WatcherConfig{
  1409. NetworkID: "solana-confirmed",
  1410. ChainID: vaa.ChainIDSolana,
  1411. Rpc: *solanaRPC,
  1412. Websocket: "",
  1413. Contract: *solanaContract,
  1414. ShimContract: *solanaShimContract,
  1415. ReceiveObsReq: false,
  1416. Commitment: rpc.CommitmentConfirmed,
  1417. }
  1418. watcherConfigs = append(watcherConfigs, wc)
  1419. // finalized watcher
  1420. wc = &solana.WatcherConfig{
  1421. NetworkID: "solana-finalized",
  1422. ChainID: vaa.ChainIDSolana,
  1423. Rpc: *solanaRPC,
  1424. Websocket: "",
  1425. Contract: *solanaContract,
  1426. ShimContract: *solanaShimContract,
  1427. ReceiveObsReq: true,
  1428. Commitment: rpc.CommitmentFinalized,
  1429. }
  1430. watcherConfigs = append(watcherConfigs, wc)
  1431. if *solanaShimContract != "" {
  1432. featureFlags = append(featureFlags, fmt.Sprintf("solshim:%s", *solanaShimContract))
  1433. }
  1434. }
  1435. if shouldStart(fogoRPC) {
  1436. // confirmed watcher
  1437. wc := &solana.WatcherConfig{
  1438. NetworkID: "fogo-confirmed",
  1439. ChainID: vaa.ChainIDFogo,
  1440. Rpc: *fogoRPC,
  1441. Websocket: "",
  1442. Contract: *fogoContract,
  1443. ShimContract: *fogoShimContract,
  1444. ReceiveObsReq: false,
  1445. Commitment: rpc.CommitmentConfirmed,
  1446. PollForTx: true,
  1447. }
  1448. watcherConfigs = append(watcherConfigs, wc)
  1449. // finalized watcher
  1450. wc = &solana.WatcherConfig{
  1451. NetworkID: "fogo-finalized",
  1452. ChainID: vaa.ChainIDFogo,
  1453. Rpc: *fogoRPC,
  1454. Websocket: "",
  1455. Contract: *fogoContract,
  1456. ShimContract: *fogoShimContract,
  1457. ReceiveObsReq: true,
  1458. Commitment: rpc.CommitmentFinalized,
  1459. PollForTx: true,
  1460. }
  1461. watcherConfigs = append(watcherConfigs, wc)
  1462. if *fogoShimContract != "" {
  1463. featureFlags = append(featureFlags, fmt.Sprintf("fogoshim:%s", *fogoShimContract))
  1464. }
  1465. }
  1466. if shouldStart(pythnetRPC) {
  1467. wc := &solana.WatcherConfig{
  1468. NetworkID: "pythnet",
  1469. ChainID: vaa.ChainIDPythNet,
  1470. Rpc: *pythnetRPC,
  1471. Websocket: *pythnetWS,
  1472. Contract: *pythnetContract,
  1473. ReceiveObsReq: false,
  1474. Commitment: rpc.CommitmentConfirmed,
  1475. }
  1476. watcherConfigs = append(watcherConfigs, wc)
  1477. }
  1478. if shouldStart(gatewayWS) {
  1479. wc := &cosmwasm.WatcherConfig{
  1480. NetworkID: "gateway",
  1481. ChainID: vaa.ChainIDWormchain,
  1482. Websocket: *gatewayWS,
  1483. Lcd: *gatewayLCD,
  1484. Contract: *gatewayContract,
  1485. }
  1486. watcherConfigs = append(watcherConfigs, wc)
  1487. }
  1488. if env == common.TestNet || env == common.UnsafeDevNet {
  1489. if shouldStart(sepoliaRPC) {
  1490. wc := &evm.WatcherConfig{
  1491. NetworkID: "sepolia",
  1492. ChainID: vaa.ChainIDSepolia,
  1493. Rpc: *sepoliaRPC,
  1494. Contract: *sepoliaContract,
  1495. CcqBackfillCache: *ccqBackfillCache,
  1496. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDSepolia),
  1497. }
  1498. watcherConfigs = append(watcherConfigs, wc)
  1499. }
  1500. if shouldStart(holeskyRPC) {
  1501. wc := &evm.WatcherConfig{
  1502. NetworkID: "holesky",
  1503. ChainID: vaa.ChainIDHolesky,
  1504. Rpc: *holeskyRPC,
  1505. Contract: *holeskyContract,
  1506. CcqBackfillCache: *ccqBackfillCache,
  1507. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDHolesky),
  1508. }
  1509. watcherConfigs = append(watcherConfigs, wc)
  1510. }
  1511. if shouldStart(arbitrumSepoliaRPC) {
  1512. wc := &evm.WatcherConfig{
  1513. NetworkID: "arbitrum_sepolia",
  1514. ChainID: vaa.ChainIDArbitrumSepolia,
  1515. Rpc: *arbitrumSepoliaRPC,
  1516. Contract: *arbitrumSepoliaContract,
  1517. CcqBackfillCache: *ccqBackfillCache,
  1518. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDArbitrumSepolia),
  1519. }
  1520. watcherConfigs = append(watcherConfigs, wc)
  1521. }
  1522. if shouldStart(baseSepoliaRPC) {
  1523. wc := &evm.WatcherConfig{
  1524. NetworkID: "base_sepolia",
  1525. ChainID: vaa.ChainIDBaseSepolia,
  1526. Rpc: *baseSepoliaRPC,
  1527. Contract: *baseSepoliaContract,
  1528. CcqBackfillCache: *ccqBackfillCache,
  1529. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDBaseSepolia),
  1530. }
  1531. watcherConfigs = append(watcherConfigs, wc)
  1532. }
  1533. if shouldStart(optimismSepoliaRPC) {
  1534. wc := &evm.WatcherConfig{
  1535. NetworkID: "optimism_sepolia",
  1536. ChainID: vaa.ChainIDOptimismSepolia,
  1537. Rpc: *optimismSepoliaRPC,
  1538. Contract: *optimismSepoliaContract,
  1539. CcqBackfillCache: *ccqBackfillCache,
  1540. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDOptimismSepolia),
  1541. }
  1542. watcherConfigs = append(watcherConfigs, wc)
  1543. }
  1544. if shouldStart(polygonSepoliaRPC) {
  1545. wc := &evm.WatcherConfig{
  1546. NetworkID: "polygon_sepolia",
  1547. ChainID: vaa.ChainIDPolygonSepolia,
  1548. Rpc: *polygonSepoliaRPC,
  1549. Contract: *polygonSepoliaContract,
  1550. CcqBackfillCache: *ccqBackfillCache,
  1551. TxVerifierEnabled: slices.Contains(txVerifierChains, vaa.ChainIDPolygonSepolia),
  1552. }
  1553. watcherConfigs = append(watcherConfigs, wc)
  1554. }
  1555. }
  1556. var ibcWatcherConfig *node.IbcWatcherConfig = nil
  1557. if shouldStart(ibcWS) {
  1558. ibcWatcherConfig = &node.IbcWatcherConfig{
  1559. Websocket: *ibcWS,
  1560. Lcd: *ibcLCD,
  1561. BlockHeightURL: *ibcBlockHeightURL,
  1562. Contract: *ibcContract,
  1563. }
  1564. }
  1565. guardianNode := node.NewGuardianNode(
  1566. env,
  1567. guardianSigner,
  1568. )
  1569. var guardianAddrAsBytes []byte
  1570. if len(*additionalPublishers) > 0 {
  1571. guardianAddrAsBytes = ethcrypto.PubkeyToAddress(guardianSigner.PublicKey(rootCtx)).Bytes()
  1572. }
  1573. guardianOptions := []*node.GuardianOption{
  1574. node.GuardianOptionDatabase(db),
  1575. node.GuardianOptionWatchers(watcherConfigs, ibcWatcherConfig),
  1576. node.GuardianOptionAccountant(*accountantWS, *accountantContract, *accountantCheckEnabled, accountantWormchainConn, *accountantNttContract, accountantNttWormchainConn),
  1577. node.GuardianOptionGovernor(*chainGovernorEnabled, *governorFlowCancelEnabled, *coinGeckoApiKey),
  1578. node.GuardianOptionNotary(*notaryEnabled),
  1579. node.GuardianOptionGatewayRelayer(*gatewayRelayerContract, gatewayRelayerWormchainConn),
  1580. node.GuardianOptionQueryHandler(*ccqEnabled, *ccqAllowedRequesters),
  1581. node.GuardianOptionAdminService(*adminSocketPath, ethRPC, ethContract, rpcMap),
  1582. node.GuardianOptionStatusServer(*statusAddr),
  1583. node.GuardianOptionAlternatePublisher(guardianAddrAsBytes, *additionalPublishers),
  1584. node.GuardianOptionProcessor(*p2pNetworkID),
  1585. // Keep this last so that all of its dependencies are met.
  1586. node.GuardianOptionP2P(
  1587. p2pKey,
  1588. *p2pNetworkID,
  1589. *p2pBootstrap,
  1590. *nodeName,
  1591. *subscribeToVAAs,
  1592. *disableHeartbeatVerify,
  1593. *p2pPort,
  1594. *ccqP2pBootstrap,
  1595. *ccqP2pPort,
  1596. *ccqAllowedPeers,
  1597. *gossipAdvertiseAddress,
  1598. ibcWatcherConfig != nil,
  1599. protectedPeers,
  1600. ccqProtectedPeers,
  1601. featureFlags,
  1602. ),
  1603. }
  1604. if shouldStart(publicGRPCSocketPath) {
  1605. guardianOptions = append(guardianOptions, node.GuardianOptionPublicRpcSocket(*publicGRPCSocketPath, publicRpcLogDetail))
  1606. if shouldStart(publicRPC) {
  1607. guardianOptions = append(guardianOptions, node.GuardianOptionPublicrpcTcpService(*publicRPC, publicRpcLogDetail))
  1608. }
  1609. if shouldStart(publicWeb) {
  1610. guardianOptions = append(guardianOptions,
  1611. node.GuardianOptionPublicWeb(*publicWeb, *publicGRPCSocketPath, *tlsHostname, *tlsProdEnv, path.Join(*dataDir, "autocert")),
  1612. )
  1613. }
  1614. }
  1615. // Run supervisor with Guardian Node as root.
  1616. supervisor.New(rootCtx, logger, guardianNode.Run(rootCtxCancel, guardianOptions...),
  1617. // It's safer to crash and restart the process in case we encounter a panic,
  1618. // rather than attempting to reschedule the runnable.
  1619. supervisor.WithPropagatePanic)
  1620. <-rootCtx.Done()
  1621. logger.Info("root context cancelled, exiting...")
  1622. }
  1623. func shouldStart(rpcURL *string) bool {
  1624. return *rpcURL != "" && *rpcURL != "none"
  1625. }
  1626. // checkEvmArgs verifies that the RPC and contract address parameters for an EVM chain make sense, given the environment.
  1627. // If we are in devnet mode and the contract address is not specified, it returns the deterministic one for tilt.
  1628. func checkEvmArgs(logger *zap.Logger, rpcURL string, contractAddr string, chainID vaa.ChainID) string {
  1629. if env != common.UnsafeDevNet {
  1630. // In mainnet / testnet, if either parameter is specified, they must both be specified.
  1631. if (rpcURL == "") != (contractAddr == "") {
  1632. logger.Fatal(fmt.Sprintf("Both contract and RPC for chain %s must be set or both unset", chainID.String()))
  1633. }
  1634. } else {
  1635. // In devnet, if RPC is set but contract is not set, use the deterministic one for tilt.
  1636. if rpcURL == "" {
  1637. if contractAddr != "" {
  1638. logger.Fatal(fmt.Sprintf("If RPC is not set for chain %s, contract must not be set", chainID.String()))
  1639. }
  1640. } else {
  1641. if contractAddr == "" {
  1642. contractAddr = sdk.KnownDevnetCoreContracts[vaa.ChainIDEthereum]
  1643. }
  1644. }
  1645. }
  1646. mainnetSupported := evm.SupportedInMainnet(chainID)
  1647. if contractAddr != "" && !mainnetSupported && env == common.MainNet {
  1648. logger.Fatal(fmt.Sprintf("Chain %s is not supported in mainnet", chainID.String()))
  1649. }
  1650. return contractAddr
  1651. }
  1652. // argsConsistent verifies that the arguments in the array are all set or all unset.
  1653. // Note that it doesn't validate the values, just whether they are blank or not.
  1654. func argsConsistent(args []string) bool {
  1655. if len(args) < 2 {
  1656. panic("argsConsistent expects at least two args")
  1657. }
  1658. shouldBeUnset := args[0] == ""
  1659. for idx := 1; idx < len(args); idx++ {
  1660. if shouldBeUnset != (args[idx] == "") {
  1661. return false
  1662. }
  1663. }
  1664. return true
  1665. }