pyth_utils.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import os
  2. import socketserver
  3. import subprocess
  4. import sys
  5. # Settings specific to local devnet Pyth instance
  6. PYTH = os.environ.get("PYTH", "./pyth")
  7. PYTH_ADMIN = os.environ.get("PYTH_ADMIN", "./pyth_admin")
  8. PYTH_KEY_STORE = os.environ.get("PYTH_KEY_STORE", "/home/pyth/.pythd")
  9. PYTH_PROGRAM_KEYPAIR = os.environ.get(
  10. "PYTH_PROGRAM_KEYPAIR", f"{PYTH_KEY_STORE}/publish_key_pair.json"
  11. )
  12. PYTH_PROGRAM_SO_PATH = os.environ.get("PYTH_PROGRAM_SO", "../target/oracle.so")
  13. PYTH_PUBLISHER_KEYPAIR = os.environ.get(
  14. "PYTH_PUBLISHER_KEYPAIR", f"{PYTH_KEY_STORE}/publish_key_pair.json"
  15. )
  16. # How long to sleep between mock Pyth price updates
  17. PYTH_PUBLISHER_INTERVAL_SECS = float(os.environ.get("PYTH_PUBLISHER_INTERVAL_SECS", "5"))
  18. PYTH_TEST_SYMBOL_COUNT = int(os.environ.get("PYTH_TEST_SYMBOL_COUNT", "9"))
  19. # If above 0, adds a new test symbol periodically, waiting at least
  20. # the given number of seconds in between
  21. #
  22. # NOTE: the new symbols are added in the HTTP endpoint used by the
  23. # p2w-attest service in Tilt. You may need to wait to see p2w-attest
  24. # pick up brand new symbols
  25. PYTH_NEW_SYMBOL_INTERVAL_SECS = int(os.environ.get("PYTH_NEW_SYMBOL_INTERVAL_SECS", "120"))
  26. PYTH_MAPPING_KEYPAIR = os.environ.get(
  27. "PYTH_MAPPING_KEYPAIR", f"{PYTH_KEY_STORE}/mapping_key_pair.json"
  28. )
  29. # 0 setting disables airdropping
  30. SOL_AIRDROP_AMT = int(os.environ.get("SOL_AIRDROP_AMT", 0))
  31. # SOL RPC settings
  32. SOL_RPC_HOST = os.environ.get("SOL_RPC_HOST", "solana-devnet")
  33. SOL_RPC_PORT = int(os.environ.get("SOL_RPC_PORT", 8899))
  34. SOL_RPC_URL = os.environ.get(
  35. "SOL_RPC_URL", "http://{0}:{1}".format(SOL_RPC_HOST, SOL_RPC_PORT)
  36. )
  37. # A TCP port we open when a service is ready
  38. READINESS_PORT = int(os.environ.get("READINESS_PORT", "2000"))
  39. def run_or_die(args, die=True, **kwargs):
  40. """
  41. Opinionated subprocess.run() call with fancy logging
  42. """
  43. args_readable = " ".join(args)
  44. print(f"CMD RUN\t{args_readable}", file=sys.stderr)
  45. sys.stderr.flush()
  46. ret = subprocess.run(args, text=True, **kwargs)
  47. if ret.returncode != 0:
  48. print(f"CMD FAIL {ret.returncode}\t{args_readable}", file=sys.stderr)
  49. out = ret.stdout if ret.stdout is not None else "<not captured>"
  50. err = ret.stderr if ret.stderr is not None else "<not captured>"
  51. print(f"CMD STDOUT\n{out}", file=sys.stderr)
  52. print(f"CMD STDERR\n{err}", file=sys.stderr)
  53. if die:
  54. sys.exit(ret.returncode)
  55. else:
  56. print(f'{"CMD DIE FALSE"}', file=sys.stderr)
  57. else:
  58. print(f"CMD OK\t{args_readable}", file=sys.stderr)
  59. sys.stderr.flush()
  60. return ret
  61. def pyth_run_or_die(subcommand, args=[], debug=False, **kwargs):
  62. """
  63. Pyth boilerplate in front of run_or_die.
  64. """
  65. return run_or_die(
  66. [PYTH, subcommand] + args + (["-d"] if debug else [])
  67. + ["-k", PYTH_KEY_STORE]
  68. + ["-r", SOL_RPC_HOST]
  69. + ["-c", "finalized"]
  70. + ["-x"], # These means to bypass transaction proxy server. In this setup it's not running and it's required to bypass
  71. **kwargs,
  72. )
  73. def pyth_admin_run_or_die(subcommand, args=[], debug=False, **kwargs):
  74. """
  75. Pyth_admin boilerplate in front of run_or_die.
  76. """
  77. return run_or_die(
  78. [PYTH_ADMIN, subcommand] + args + (["-d"] if debug else [])
  79. + ["-n"] # These commands require y/n confirmation. This bypasses that
  80. + ["-k", PYTH_KEY_STORE]
  81. + ["-r", SOL_RPC_HOST]
  82. + ["-c", "finalized"],
  83. **kwargs,
  84. )
  85. def sol_run_or_die(subcommand, args=[], **kwargs):
  86. """
  87. Solana boilerplate in front of run_or_die
  88. """
  89. return run_or_die(["solana", subcommand] + args + ["--url", SOL_RPC_URL], **kwargs)
  90. class ReadinessTCPHandler(socketserver.StreamRequestHandler):
  91. def handle(self):
  92. """TCP black hole"""
  93. self.rfile.read(64)
  94. def readiness():
  95. """
  96. Accept connections from readiness probe
  97. """
  98. with socketserver.TCPServer(
  99. ("0.0.0.0", READINESS_PORT), ReadinessTCPHandler
  100. ) as srv:
  101. srv.serve_forever()