node.go 70 KB

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