node.go 58 KB

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