Tiltfile 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. # This Tiltfile contains the deployment and build config for the Wormhole devnet.
  2. #
  3. # We use Buildkit cache mounts and careful layering to avoid unnecessary rebuilds - almost
  4. # all source code changes result in small, incremental rebuilds. Dockerfiles are written such
  5. # that, for example, changing the contract source code won't cause Solana itself to be rebuilt.
  6. #
  7. load("ext://namespace", "namespace_create", "namespace_inject")
  8. load("ext://secret", "secret_yaml_generic")
  9. allow_k8s_contexts("ci")
  10. # Disable telemetry by default
  11. analytics_settings(False)
  12. # Runtime configuration
  13. config.define_bool("ci", False, "We are running in CI")
  14. config.define_bool("manual", False, "Set TRIGGER_MODE_MANUAL by default")
  15. config.define_string("num", False, "Number of guardian nodes to run")
  16. # You do not usually need to set this argument - this argument is for debugging only. If you do use a different
  17. # namespace, note that the "wormhole" namespace is hardcoded in tests and don't forget specifying the argument
  18. # when running "tilt down".
  19. #
  20. config.define_string("namespace", False, "Kubernetes namespace to use")
  21. # These arguments will enable writing Guardian events to a cloud BigTable instance.
  22. # Writing to a cloud BigTable is optional. These arguments are not required to run the devnet.
  23. config.define_string("gcpProject", False, "GCP project ID for BigTable persistence")
  24. config.define_string("bigTableKeyPath", False, "Path to BigTable json key file")
  25. # When running Tilt on a server, this can be used to set the public hostname Tilt runs on
  26. # for service links in the UI to work.
  27. config.define_string("webHost", False, "Public hostname for port forwards")
  28. # Components
  29. config.define_bool("pyth", False, "Enable Pyth-to-Wormhole component")
  30. config.define_bool("explorer", False, "Enable explorer component")
  31. config.define_bool("bridge_ui", False, "Enable bridge UI component")
  32. config.define_bool("e2e", False, "Enable E2E testing stack")
  33. config.define_bool("ci_tests", False, "Enable tests runner component")
  34. cfg = config.parse()
  35. num_guardians = int(cfg.get("num", "1"))
  36. namespace = cfg.get("namespace", "wormhole")
  37. gcpProject = cfg.get("gcpProject", "local-dev")
  38. bigTableKeyPath = cfg.get("bigTableKeyPath", "./event_database/devnet_key.json")
  39. webHost = cfg.get("webHost", "localhost")
  40. ci = cfg.get("ci", False)
  41. pyth = cfg.get("pyth", ci)
  42. explorer = cfg.get("explorer", ci)
  43. bridge_ui = cfg.get("bridge_ui", ci)
  44. e2e = cfg.get("e2e", ci)
  45. ci_tests = cfg.get("ci_tests", ci)
  46. if cfg.get("manual", False):
  47. trigger_mode = TRIGGER_MODE_MANUAL
  48. else:
  49. trigger_mode = TRIGGER_MODE_AUTO
  50. # namespace
  51. if not ci:
  52. namespace_create(namespace)
  53. def k8s_yaml_with_ns(objects):
  54. return k8s_yaml(namespace_inject(objects, namespace))
  55. # protos
  56. proto_deps = ["./proto", "./generate-protos.sh", "buf.yaml", "buf.gen.yaml"]
  57. local_resource(
  58. name = "proto-gen",
  59. deps = proto_deps,
  60. cmd = "tilt docker build -- --target go-export -f Dockerfile.proto -o type=local,dest=node .",
  61. env = {"DOCKER_BUILDKIT": "1"},
  62. trigger_mode = trigger_mode,
  63. )
  64. local_resource(
  65. name = "proto-gen-web",
  66. deps = proto_deps,
  67. resource_deps = ["proto-gen"],
  68. cmd = "tilt docker build -- --target node-export -f Dockerfile.proto -o type=local,dest=. .",
  69. env = {"DOCKER_BUILDKIT": "1"},
  70. trigger_mode = trigger_mode,
  71. )
  72. local_resource(
  73. name = "teal-gen",
  74. deps = ["staging/algorand/teal"],
  75. cmd = "tilt docker build -- --target teal-export -f Dockerfile.teal -o type=local,dest=. .",
  76. env = {"DOCKER_BUILDKIT": "1"},
  77. trigger_mode = trigger_mode,
  78. )
  79. # wasm
  80. local_resource(
  81. name = "wasm-gen",
  82. deps = ["solana"],
  83. dir = "solana",
  84. cmd = "tilt docker build -- -f Dockerfile.wasm -o type=local,dest=.. .",
  85. env = {"DOCKER_BUILDKIT": "1"},
  86. trigger_mode = trigger_mode,
  87. )
  88. # node
  89. if explorer:
  90. k8s_yaml_with_ns(
  91. secret_yaml_generic(
  92. "node-bigtable-key",
  93. from_file = "bigtable-key.json=" + bigTableKeyPath,
  94. ),
  95. )
  96. docker_build(
  97. ref = "guardiand-image",
  98. context = "node",
  99. dockerfile = "node/Dockerfile",
  100. )
  101. def build_node_yaml():
  102. node_yaml = read_yaml_stream("devnet/node.yaml")
  103. for obj in node_yaml:
  104. if obj["kind"] == "StatefulSet" and obj["metadata"]["name"] == "guardian":
  105. obj["spec"]["replicas"] = num_guardians
  106. container = obj["spec"]["template"]["spec"]["containers"][0]
  107. if container["name"] != "guardiand":
  108. fail("container 0 is not guardiand")
  109. container["command"] += ["--devNumGuardians", str(num_guardians)]
  110. if explorer:
  111. container["command"] += [
  112. "--bigTablePersistenceEnabled",
  113. "--bigTableInstanceName",
  114. "wormhole",
  115. "--bigTableTableName",
  116. "v2Events",
  117. "--bigTableTopicName",
  118. "new-vaa-devnet",
  119. "--bigTableKeyPath",
  120. "/tmp/mounted-keys/bigtable-key.json",
  121. "--bigTableGCPProject",
  122. gcpProject,
  123. ]
  124. return encode_yaml_stream(node_yaml)
  125. k8s_yaml_with_ns(build_node_yaml())
  126. k8s_resource(
  127. "guardian",
  128. resource_deps = ["proto-gen", "solana-devnet"],
  129. port_forwards = [
  130. port_forward(6060, name = "Debug/Status Server [:6060]", host = webHost),
  131. port_forward(7070, name = "Public gRPC [:7070]", host = webHost),
  132. port_forward(7071, name = "Public REST [:7071]", host = webHost),
  133. port_forward(2345, name = "Debugger [:2345]", host = webHost),
  134. ],
  135. trigger_mode = trigger_mode,
  136. )
  137. # spy
  138. k8s_yaml_with_ns("devnet/spy.yaml")
  139. k8s_resource(
  140. "spy",
  141. resource_deps = ["proto-gen", "guardian"],
  142. port_forwards = [
  143. port_forward(6061, container_port = 6060, name = "Debug/Status Server [:6061]", host = webHost),
  144. port_forward(7072, name = "Spy gRPC [:7072]", host = webHost),
  145. ],
  146. trigger_mode = trigger_mode,
  147. )
  148. # solana client cli (used for devnet setup)
  149. docker_build(
  150. ref = "bridge-client",
  151. context = ".",
  152. only = ["./proto", "./solana", "./ethereum", "./clients"],
  153. dockerfile = "Dockerfile.client",
  154. # Ignore target folders from local (non-container) development.
  155. ignore = ["./solana/*/target"],
  156. )
  157. # solana smart contract
  158. docker_build(
  159. ref = "solana-contract",
  160. context = "solana",
  161. dockerfile = "solana/Dockerfile",
  162. )
  163. # solana local devnet
  164. k8s_yaml_with_ns("devnet/solana-devnet.yaml")
  165. k8s_resource(
  166. "solana-devnet",
  167. resource_deps = ["wasm-gen"],
  168. port_forwards = [
  169. port_forward(8899, name = "Solana RPC [:8899]", host = webHost),
  170. port_forward(8900, name = "Solana WS [:8900]", host = webHost),
  171. port_forward(9000, name = "Solana PubSub [:9000]", host = webHost),
  172. ],
  173. trigger_mode = trigger_mode,
  174. )
  175. # eth devnet
  176. docker_build(
  177. ref = "eth-node",
  178. context = "./ethereum",
  179. dockerfile = "./ethereum/Dockerfile",
  180. # ignore local node_modules (in case they're present)
  181. ignore = ["./ethereum/node_modules"],
  182. # sync external scripts for incremental development
  183. # (everything else needs to be restarted from scratch for determinism)
  184. #
  185. # This relies on --update-mode=exec to work properly with a non-root user.
  186. # https://github.com/tilt-dev/tilt/issues/3708
  187. live_update = [
  188. sync("./ethereum/src", "/home/node/app/src"),
  189. ],
  190. )
  191. if pyth:
  192. # pyth autopublisher
  193. docker_build(
  194. ref = "pyth",
  195. context = ".",
  196. dockerfile = "third_party/pyth/Dockerfile.pyth",
  197. )
  198. k8s_yaml_with_ns("./devnet/pyth.yaml")
  199. k8s_resource("pyth", resource_deps = ["solana-devnet"], trigger_mode = trigger_mode)
  200. # pyth2wormhole client autoattester
  201. docker_build(
  202. ref = "p2w-attest",
  203. context = ".",
  204. only = ["./solana", "./third_party"],
  205. dockerfile = "./third_party/pyth/Dockerfile.p2w-attest",
  206. ignore = ["./solana/*/target"],
  207. )
  208. k8s_yaml_with_ns("devnet/p2w-attest.yaml")
  209. k8s_resource(
  210. "p2w-attest",
  211. resource_deps = ["solana-devnet", "pyth", "guardian"],
  212. port_forwards = [],
  213. trigger_mode = trigger_mode,
  214. )
  215. k8s_yaml_with_ns("devnet/eth-devnet.yaml")
  216. k8s_resource(
  217. "eth-devnet",
  218. port_forwards = [
  219. port_forward(8545, name = "Ganache RPC [:8545]", host = webHost),
  220. ],
  221. trigger_mode = trigger_mode,
  222. )
  223. k8s_resource(
  224. "eth-devnet2",
  225. port_forwards = [
  226. port_forward(8546, name = "Ganache RPC [:8546]", host = webHost),
  227. ],
  228. trigger_mode = trigger_mode,
  229. )
  230. if bridge_ui:
  231. docker_build(
  232. ref = "bridge-ui",
  233. context = ".",
  234. only = ["./bridge_ui"],
  235. dockerfile = "bridge_ui/Dockerfile",
  236. live_update = [
  237. sync("./bridge_ui/src", "/app/bridge_ui/src"),
  238. ],
  239. )
  240. k8s_yaml_with_ns("devnet/bridge-ui.yaml")
  241. k8s_resource(
  242. "bridge-ui",
  243. resource_deps = [],
  244. port_forwards = [
  245. port_forward(3000, name = "Bridge UI [:3000]", host = webHost),
  246. ],
  247. trigger_mode = trigger_mode,
  248. )
  249. if ci_tests:
  250. docker_build(
  251. ref = "tests-image",
  252. context = ".",
  253. dockerfile = "testing/Dockerfile.tests",
  254. only = [],
  255. live_update = [
  256. sync("./spydk/js/src", "/app/spydk/js/src"),
  257. sync("./sdk/js/src", "/app/sdk/js/src"),
  258. sync("./testing", "/app/testing"),
  259. sync("./bridge_ui/src", "/app/bridge_ui/src"),
  260. ],
  261. )
  262. k8s_yaml_with_ns("devnet/tests.yaml")
  263. k8s_resource(
  264. "ci-tests",
  265. resource_deps = ["eth-devnet", "eth-devnet2", "terra-terrad", "terra-fcd", "solana-devnet", "spy", "guardian"],
  266. trigger_mode = trigger_mode,
  267. )
  268. # algorand
  269. k8s_yaml_with_ns("devnet/algorand.yaml")
  270. docker_build(
  271. ref = "algorand",
  272. context = "third_party/algorand",
  273. dockerfile = "third_party/algorand/Dockerfile",
  274. )
  275. k8s_resource(
  276. "algorand",
  277. resource_deps = ["teal-gen"],
  278. port_forwards = [
  279. port_forward(4001, name = "Algorand RPC [:4001]", host = webHost),
  280. port_forward(4002, name = "Algorand KMD [:4002]", host = webHost),
  281. ],
  282. trigger_mode = trigger_mode,
  283. )
  284. # e2e
  285. if e2e:
  286. k8s_yaml_with_ns("devnet/e2e.yaml")
  287. docker_build(
  288. ref = "e2e",
  289. context = "e2e",
  290. dockerfile = "e2e/Dockerfile",
  291. network = "host",
  292. )
  293. k8s_resource(
  294. "e2e",
  295. port_forwards = [
  296. port_forward(6080, name = "VNC [:6080]", host = webHost, link_path = "/vnc_auto.html"),
  297. ],
  298. trigger_mode = trigger_mode,
  299. )
  300. # bigtable
  301. if explorer:
  302. k8s_yaml_with_ns("devnet/bigtable.yaml")
  303. k8s_resource(
  304. "bigtable-emulator",
  305. port_forwards = [port_forward(8086, name = "BigTable clients [:8086]", host = webHost)],
  306. labels = ["explorer"],
  307. trigger_mode = trigger_mode,
  308. )
  309. k8s_resource("pubsub-emulator",
  310. port_forwards = [port_forward(8085, name = "PubSub listeners [:8085]")],
  311. labels = ["explorer"],
  312. )
  313. docker_build(
  314. ref = "cloud-functions",
  315. context = "./event_database/cloud_functions",
  316. dockerfile = "./event_database/cloud_functions/Dockerfile",
  317. live_update = [
  318. sync("./event_database/cloud_functions", "/app"),
  319. ],
  320. )
  321. k8s_resource(
  322. "cloud-functions",
  323. resource_deps = ["proto-gen", "bigtable-emulator", "pubsub-emulator"],
  324. port_forwards = [port_forward(8090, name = "Cloud Functions [:8090]")],
  325. labels = ["explorer"],
  326. trigger_mode = trigger_mode,
  327. )
  328. # explorer web app
  329. docker_build(
  330. ref = "explorer",
  331. context = "./explorer",
  332. dockerfile = "./explorer/Dockerfile",
  333. ignore = ["./explorer/node_modules"],
  334. live_update = [
  335. sync("./explorer/src", "/home/node/app/src"),
  336. sync("./explorer/public", "/home/node/app/public"),
  337. ],
  338. )
  339. k8s_yaml_with_ns("devnet/explorer.yaml")
  340. k8s_resource(
  341. "explorer",
  342. port_forwards = [
  343. port_forward(8001, name = "Explorer Web UI [:8001]", host = webHost),
  344. ],
  345. labels = ["explorer"],
  346. trigger_mode = trigger_mode,
  347. )
  348. # terra devnet
  349. docker_build(
  350. ref = "terra-image",
  351. context = "./terra/devnet",
  352. dockerfile = "terra/devnet/Dockerfile",
  353. )
  354. docker_build(
  355. ref = "terra-contracts",
  356. context = "./terra",
  357. dockerfile = "./terra/Dockerfile",
  358. )
  359. k8s_yaml_with_ns("devnet/terra-devnet.yaml")
  360. k8s_resource(
  361. "terra-terrad",
  362. port_forwards = [
  363. port_forward(26657, name = "Terra RPC [:26657]", host = webHost),
  364. port_forward(1317, name = "Terra LCD [:1317]", host = webHost),
  365. ],
  366. trigger_mode = trigger_mode,
  367. )
  368. k8s_resource(
  369. "terra-fcd",
  370. port_forwards = [port_forward(3060, name = "Terra FCD [:3060]", host = webHost)],
  371. trigger_mode = trigger_mode,
  372. )