node.go 78 KB

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