Tiltfile 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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. # Moar updates (default is 3)
  13. update_settings(max_parallel_updates=10)
  14. # Runtime configuration
  15. config.define_bool("ci", False, "We are running in CI")
  16. config.define_bool("manual", False, "Set TRIGGER_MODE_MANUAL by default")
  17. config.define_string("num", False, "Number of guardian nodes to run")
  18. # You do not usually need to set this argument - this argument is for debugging only. If you do use a different
  19. # namespace, note that the "wormhole" namespace is hardcoded in tests and don't forget specifying the argument
  20. # when running "tilt down".
  21. #
  22. config.define_string("namespace", False, "Kubernetes namespace to use")
  23. # These arguments will enable writing Guardian events to a cloud BigTable instance.
  24. # Writing to a cloud BigTable is optional. These arguments are not required to run the devnet.
  25. config.define_string("gcpProject", False, "GCP project ID for BigTable persistence")
  26. config.define_string("bigTableKeyPath", False, "Path to BigTable json key file")
  27. # When running Tilt on a server, this can be used to set the public hostname Tilt runs on
  28. # for service links in the UI to work.
  29. config.define_string("webHost", False, "Public hostname for port forwards")
  30. # Components
  31. config.define_bool("pyth", False, "Enable Pyth-to-Wormhole component")
  32. cfg = config.parse()
  33. num_guardians = int(cfg.get("num", "1"))
  34. namespace = cfg.get("namespace", "wormhole")
  35. gcpProject = cfg.get("gcpProject", "local-dev")
  36. bigTableKeyPath = cfg.get("bigTableKeyPath", "./event_database/devnet_key.json")
  37. webHost = cfg.get("webHost", "localhost")
  38. ci = cfg.get("ci", False)
  39. pyth = cfg.get("pyth", ci)
  40. if cfg.get("manual", False):
  41. trigger_mode = TRIGGER_MODE_MANUAL
  42. else:
  43. trigger_mode = TRIGGER_MODE_AUTO
  44. # namespace
  45. if not ci:
  46. namespace_create(namespace)
  47. def k8s_yaml_with_ns(objects):
  48. return k8s_yaml(namespace_inject(objects, namespace))
  49. # protos
  50. proto_deps = ["./proto", "buf.yaml", "buf.gen.yaml"]
  51. local_resource(
  52. name = "proto-gen",
  53. deps = proto_deps,
  54. cmd = "tilt docker build -- --target go-export -f Dockerfile.proto -o type=local,dest=node .",
  55. env = {"DOCKER_BUILDKIT": "1"},
  56. labels = ["protobuf"],
  57. allow_parallel=True,
  58. trigger_mode = trigger_mode,
  59. )
  60. # wasm
  61. local_resource(
  62. name = "wasm-gen",
  63. cmd = "tilt docker build -- -f Dockerfile.wasm -o type=local,dest=. .",
  64. env = {"DOCKER_BUILDKIT": "1"},
  65. labels = ["wasm"],
  66. allow_parallel=True,
  67. trigger_mode = trigger_mode,
  68. )
  69. docker_build(
  70. ref = "guardiand-image",
  71. context = "node",
  72. dockerfile = "node/Dockerfile",
  73. )
  74. def build_node_yaml():
  75. node_yaml = read_yaml_stream("devnet/node.yaml")
  76. for obj in node_yaml:
  77. if obj["kind"] == "StatefulSet" and obj["metadata"]["name"] == "guardian":
  78. obj["spec"]["replicas"] = num_guardians
  79. container = obj["spec"]["template"]["spec"]["containers"][0]
  80. if container["name"] != "guardiand":
  81. fail("container 0 is not guardiand")
  82. container["command"] += ["--devNumGuardians", str(num_guardians)]
  83. return encode_yaml_stream(node_yaml)
  84. k8s_yaml_with_ns(build_node_yaml())
  85. k8s_resource(
  86. "guardian",
  87. resource_deps = ["proto-gen", "eth-devnet", "eth-devnet2", "terra-terrad", "solana-devnet"],
  88. port_forwards = [
  89. port_forward(6060, name = "Debug/Status Server [:6060]", host = webHost),
  90. port_forward(7070, name = "Public gRPC [:7070]", host = webHost),
  91. port_forward(7071, name = "Public REST [:7071]", host = webHost),
  92. port_forward(2345, name = "Debugger [:2345]", host = webHost),
  93. ],
  94. labels = ["guardian"],
  95. trigger_mode = trigger_mode,
  96. )
  97. # spy
  98. k8s_yaml_with_ns("devnet/spy.yaml")
  99. k8s_resource(
  100. "spy",
  101. resource_deps = ["proto-gen", "guardian"],
  102. port_forwards = [
  103. port_forward(6061, container_port = 6060, name = "Debug/Status Server [:6061]", host = webHost),
  104. port_forward(7072, name = "Spy gRPC [:7072]", host = webHost),
  105. ],
  106. labels = ["guardian"],
  107. trigger_mode = trigger_mode,
  108. )
  109. # solana client cli (used for devnet setup)
  110. docker_build(
  111. ref = "bridge-client",
  112. context = ".",
  113. only = ["./proto", "./solana", "./clients"],
  114. dockerfile = "Dockerfile.client",
  115. # Ignore target folders from local (non-container) development.
  116. ignore = ["./solana/*/target"],
  117. )
  118. # solana smart contract
  119. docker_build(
  120. ref = "solana-contract",
  121. context = ".",
  122. dockerfile = "Dockerfile.solana",
  123. )
  124. # solana local devnet
  125. k8s_yaml_with_ns("devnet/solana-devnet.yaml")
  126. k8s_resource(
  127. "solana-devnet",
  128. port_forwards = [
  129. port_forward(8899, name = "Solana RPC [:8899]", host = webHost),
  130. port_forward(8900, name = "Solana WS [:8900]", host = webHost),
  131. port_forward(9000, name = "Solana PubSub [:9000]", host = webHost),
  132. ],
  133. labels = ["solana"],
  134. trigger_mode = trigger_mode,
  135. )
  136. # eth devnet
  137. docker_build(
  138. ref = "eth-node",
  139. context = "./ethereum",
  140. dockerfile = "./ethereum/Dockerfile",
  141. # ignore local node_modules (in case they're present)
  142. ignore = ["./ethereum/node_modules"],
  143. # sync external scripts for incremental development
  144. # (everything else needs to be restarted from scratch for determinism)
  145. #
  146. # This relies on --update-mode=exec to work properly with a non-root user.
  147. # https://github.com/tilt-dev/tilt/issues/3708
  148. live_update = [
  149. sync("./ethereum/src", "/home/node/app/src"),
  150. ],
  151. )
  152. if pyth:
  153. # pyth autopublisher
  154. docker_build(
  155. ref = "pyth",
  156. context = ".",
  157. dockerfile = "third_party/pyth/Dockerfile.pyth",
  158. )
  159. k8s_yaml_with_ns("./devnet/pyth.yaml")
  160. k8s_resource(
  161. "pyth",
  162. resource_deps = ["solana-devnet"],
  163. labels = ["pyth"],
  164. trigger_mode = trigger_mode,
  165. )
  166. # pyth2wormhole client autoattester
  167. docker_build(
  168. ref = "p2w-attest",
  169. context = ".",
  170. only = ["./solana", "./third_party"],
  171. dockerfile = "./third_party/pyth/Dockerfile.p2w-attest",
  172. ignore = ["./solana/*/target"],
  173. )
  174. # Automatic pyth2wormhole relay, showcasing p2w-sdk
  175. docker_build(
  176. ref = "p2w-integration-observer",
  177. context = ".",
  178. dockerfile = "./third_party/pyth/p2w-integration-observer/Dockerfile",
  179. )
  180. k8s_yaml_with_ns("devnet/p2w-attest.yaml")
  181. k8s_resource(
  182. "p2w-attest",
  183. resource_deps = ["solana-devnet", "pyth", "guardian"],
  184. port_forwards = [],
  185. labels = ["pyth"],
  186. trigger_mode = trigger_mode,
  187. )
  188. k8s_yaml_with_ns("devnet/p2w-integration-observer.yaml")
  189. k8s_resource(
  190. "p2w-integration-observer",
  191. resource_deps = ["solana-devnet", "eth-devnet", "pyth", "guardian", "p2w-attest", "wasm-gen"],
  192. port_forwards = [],
  193. labels = ["pyth"]
  194. )
  195. # Pyth2wormhole relay
  196. docker_build(
  197. ref = "p2w-relay",
  198. context = ".",
  199. dockerfile = "third_party/pyth/p2w-relay/Dockerfile.pyth_relay",
  200. )
  201. k8s_yaml_with_ns("devnet/p2w-terra-relay.yaml")
  202. k8s_resource(
  203. "p2w-terra-relay",
  204. resource_deps = ["pyth", "p2w-attest", "spy", "terra-terrad"],
  205. port_forwards = [
  206. port_forward(4200, name = "Rest API (Status + Query) [:4200]", host = webHost),
  207. port_forward(8081, name = "Prometheus [:8081]", host = webHost)],
  208. labels = ["pyth"]
  209. )
  210. k8s_yaml_with_ns("devnet/p2w-evm-relay.yaml")
  211. k8s_resource(
  212. "p2w-evm-relay",
  213. resource_deps = ["pyth", "p2w-attest", "spy", "eth-devnet"],
  214. port_forwards = [
  215. port_forward(4201, container_port = 4200, name = "Rest API (Status + Query) [:4201]", host = webHost),
  216. port_forward(8082, container_port = 8081, name = "Prometheus [:8082]", host = webHost)],
  217. labels = ["pyth"]
  218. )
  219. # Pyth Price service
  220. docker_build(
  221. ref = "pyth-price-service",
  222. context = ".",
  223. dockerfile = "third_party/pyth/price-service/Dockerfile.price_service",
  224. )
  225. k8s_yaml_with_ns("devnet/pyth-price-service.yaml")
  226. k8s_resource(
  227. "pyth-price-service",
  228. resource_deps = ["pyth", "p2w-attest", "spy", "eth-devnet"],
  229. port_forwards = [
  230. port_forward(4202, container_port = 4200, name = "Rest API (Status + Query) [:4202]", host = webHost),
  231. port_forward(8083, container_port = 8081, name = "Prometheus [:8083]", host = webHost)],
  232. labels = ["pyth"]
  233. )
  234. k8s_yaml_with_ns("devnet/eth-devnet.yaml")
  235. k8s_resource(
  236. "eth-devnet",
  237. port_forwards = [
  238. port_forward(8545, name = "Ganache RPC [:8545]", host = webHost),
  239. ],
  240. labels = ["evm"],
  241. trigger_mode = trigger_mode,
  242. )
  243. k8s_resource(
  244. "eth-devnet2",
  245. port_forwards = [
  246. port_forward(8546, name = "Ganache RPC [:8546]", host = webHost),
  247. ],
  248. labels = ["evm"],
  249. trigger_mode = trigger_mode,
  250. )
  251. # terra devnet
  252. docker_build(
  253. ref = "terra-image",
  254. context = "./terra/devnet",
  255. dockerfile = "terra/devnet/Dockerfile",
  256. )
  257. docker_build(
  258. ref = "terra-contracts",
  259. context = ".",
  260. dockerfile = "Dockerfile.terra",
  261. )
  262. k8s_yaml_with_ns("devnet/terra-devnet.yaml")
  263. k8s_resource(
  264. "terra-terrad",
  265. port_forwards = [
  266. port_forward(26657, name = "Terra RPC [:26657]", host = webHost),
  267. port_forward(1317, name = "Terra LCD [:1317]", host = webHost),
  268. ],
  269. labels = ["terra"],
  270. trigger_mode = trigger_mode,
  271. )
  272. k8s_resource(
  273. "terra-postgres",
  274. labels = ["terra"],
  275. trigger_mode = trigger_mode,
  276. )
  277. k8s_resource(
  278. "terra-fcd",
  279. resource_deps = ["terra-terrad", "terra-postgres"],
  280. port_forwards = [port_forward(3060, name = "Terra FCD [:3060]", host = webHost)],
  281. labels = ["terra"],
  282. trigger_mode = trigger_mode,
  283. )