Skip to content

Commit aeaaaf5

Browse files
authored
Literal pubkeys in agent config, v2.0.0 (#77)
* solana.rs: Modify KeyStore config to accept literal pubkeys This **breaking** change improves on the legacy file-based keystore appoach to program/mapping public keys. With it, the user can name the public keys in-line, e.g.: 'key_store.program_key_path = "program_key.json"' is now expressed as: 'key_store.program_key = "FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH"' This change is accompanied with a small tool to inline the public keys from an older file-based config, named "agent-migrate-config". The sample configs are rewritten to use the new format and name the appropriate pubkeys out-of-the-box. Tests include a sanity-check for the migration tool. * README.md: Include key store migration information for v2.0.0 * README.md: add pipe for migrator output * test_integration.py: Add missing manual agent invocation This is necessary to provide the agent with an altered migrated config. * README.md: typo * solana.rs: strinigified -> stringified We don't like our SOL addresses strinigified. * config.sample.pythtest.toml: The perils of Ctrl-C + Ctrl-V
1 parent 9c1dbbc commit aeaaaf5

11 files changed

+550
-103
lines changed

Cargo.lock

+54-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
[package]
22
name = "pyth-agent"
3-
version = "1.4.0"
3+
version = "2.0.0"
44
edition = "2021"
55

66
[[bin]]
77
name = "agent"
88
path = "src/bin/agent.rs"
99

10+
[[bin]]
11+
name = "agent-migrate-config"
12+
path = "src/bin/agent_migrate_config.rs"
13+
1014
[dependencies]
1115
anyhow = "1.0.55"
1216
serde = { version = "1.0.136", features = ["derive"] }
@@ -46,6 +50,7 @@ typed-html = { git = "https://github.com/bodil/typed-html", rev = "4c13ecca" }
4650
humantime = "2.1.0"
4751
prometheus-client = "0.19.0"
4852
lazy_static = "1.4.0"
53+
toml_edit = "0.19.13"
4954

5055
[dev-dependencies]
5156
tokio-util = { version = "0.7.0", features = ["full"] }

README.md

+36-14
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,46 @@ The logging level can be configured at runtime
3232
through the `RUST_LOG` environment variable using the standard
3333
`error|warn|info|debug|trace` levels.
3434

35-
### Key Store
36-
If you already have a key store set up, you can skip this step. If you haven't, you will need to create one before publishing data. A key store contains the cryptographic keys needed to publish data. Once you have a key store set up, please ensure that the configuration file mentioned above contains the correct path to your key store.
35+
### Key Store Config Migration [v1.x.x LEGACY]
36+
Pyth agent v2.0.0 introduces a simplified program and mapping key configuration. This breaking change alters how you define program/mapping key options in your agent config:
37+
```toml
38+
# Old v1.x.x way
39+
[primary network]
40+
key_store.root_path = "/path/to/keystore"
41+
key_store.publish_keypair_path = "publish_key_pair.json" # Relative path from root_path, "publish_key_pair.json" by default
42+
key_store.program_key_path = "program_key.json" # Relative path from root_path, "program_key.json" by default
43+
key_store.mapping_key_path = "mapping_key.json" # Relative path from root_path, "mapping_key.json" by default
44+
45+
# [...]
46+
47+
# New v2.0.0 way
48+
[primary_network]
49+
key_store.publish_keypair_path = "/path/to/keypair.json" # The root_path is gone, we specify the full path
50+
# Not using separate files anymore
51+
key_store.program_key = "LiteralProgramPubkeyInsideTheConfig" # contents of legacy program_key.json;
52+
key_store.mapping_key = "LiteralMappingPubkeyInsideTheConfig" # contents of legacy mapping_key.json
53+
54+
# [...]
3755

38-
```bash
39-
# Install the Solana Tool Suite, needed for creating the key used to sign your transactions.
40-
sh -c "$(curl -sSfL https://release.solana.com/v1.14.13/install)"
56+
```
4157

42-
# Create the key store directory. This can be any location that is convenient for you.
43-
PYTH_KEY_STORE=$HOME/.pythd
58+
#### Automatic Migration
59+
If you are upgrading to agent v2.0.0 with an existing config, you can use the provided automatic migrator program:
60+
```shell
61+
# Build
62+
$ cargo build --release
63+
# Run the migrator, making sure that the key store with previous keys is reachable
64+
$ target/release/agent-migrate-config -c <existing_config_file>.toml > my_new_config.toml
65+
```
4466

45-
# Create your keypair (pair of private/public keys) that will be used to sign your transactions.
46-
# Pyth Network will need to permission this key, so reach out to us once you have created it.
47-
solana-keygen new --no-bip39-passphrase --outfile $PYTH_KEY_STORE/publish_key_pair.json
67+
#### `Could not open {mapping|program|...} key file`
68+
This error can appear if some of your program/mapping/publish key
69+
files are not reachable under their `key_store.*` setting values.
4870

49-
# Initialize the key store with the public keys of the Pyth Oracle Program on the network you wish to publish to.
50-
PYTH_KEY_ENV=devnet # Can be devnet, testnet or mainnet
51-
./scripts/init_key_store.sh $PYTH_KEY_ENV $PYTH_KEY_STORE
52-
```
71+
Ensure that your current working directory is correct for reaching the
72+
key store path inside your config. You may also migrate manually by
73+
changing `key_store.*_key_path` and `key_store.publish_keypair_path`
74+
options by hand, as described in the config example above.
5375

5476
## Run
5577
`cargo run --release -- --config <your_config.toml>` will build and run the agent in a single step.

config/config.sample.pythnet.toml

+19-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,17 @@ rpc_url = "http://api.pythnet.pyth.network:8899"
1111
# This can be omitted when oracle.subscriber_enabled is set to false.
1212
wss_url = "ws://api.pythnet.pyth.network:8900"
1313

14-
# Path to the key store.
15-
key_store.root_path = "/path/to/keystore"
14+
# Path to your publishing keypair.
15+
key_store.publish_keypair_path = "/path/to/keypair.json"
16+
17+
# Oracle program pubkey
18+
key_store.program_key = "FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH"
19+
20+
# Oracle mapping pubkey
21+
key_store.mapping_key = "AHtgzX45WTKfkPG53L6WYhGEXwQkN1BVknET3sVsLL8J"
22+
23+
# Pythnet accumulator key
24+
key_store.accumulator_key = "7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM"
1625

1726
# Duration of the interval at which to publish updates
1827
exporter.publish_interval_duration = "400ms"
@@ -25,8 +34,14 @@ exporter.publish_interval_duration = "400ms"
2534
rpc_url = "https://api.mainnet-beta.solana.com"
2635
wss_url = "wss://api.mainnet-beta.solana.com"
2736

28-
# Path to the key store.
29-
key_store.root_path = "/path/to/keystore"
37+
# Path to your publishing keypair.
38+
key_store.publish_keypair_path = "/path/to/keypair.json"
39+
40+
# Oracle program pubkey
41+
key_store.program_key = "FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH"
42+
43+
# Oracle mapping pubkey
44+
key_store.mapping_key = "AHtgzX45WTKfkPG53L6WYhGEXwQkN1BVknET3sVsLL8J"
3045

3146
# Duration of the interval at which to publish updates. Default interval is 1 seconds.
3247
# exporter.publish_interval_duration = "1s"

config/config.sample.pythtest.toml

+21-4
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,19 @@ rpc_url = "https://api.pythtest.pyth.network"
1111
# This can be omitted when oracle.subscriber_enabled is set to false.
1212
wss_url = "wss://api.pythtest.pyth.network"
1313

14-
# Path to the key store.
15-
key_store.root_path = "/path/to/keystore"
14+
# Path to your publishing keypair.
15+
key_store.publish_keypair_path = "/path/to/keypair.json"
16+
17+
# Oracle program pubkey
18+
key_store.program_key = "8tfDNiaEyrV6Q1U4DEXrEigs9DoDtkugzFbybENEbCDz" # conformance
19+
# key_store.program_key = "gSbePebfvPy7tRqimPoVecS2UsBvYv46ynrzWocc92s" # cross-chain
20+
21+
# Oracle mapping pubkey
22+
key_store.mapping_key = "AFmdnt9ng1uVxqCmqwQJDAYC5cKTkw8gJKSM5PnzuF6z" # conformance
23+
# key_store.mapping_key = "BmA9Z6FjioHJPpjT39QazZyhDRUdZy2ezwx4GiDdE2u2" # cross-chain
24+
25+
# Pythtest accumulator key (only for the cross-chain oracle)
26+
# key_store.accumulator_key = "7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM"
1627

1728
# Duration of the interval at which to publish updates
1829
exporter.publish_interval_duration = "400ms"
@@ -25,8 +36,14 @@ exporter.publish_interval_duration = "400ms"
2536
rpc_url = "https://api.testnet.solana.com"
2637
wss_url = "wss://api.testnet.solana.com"
2738

28-
# Path to the key store.
29-
key_store.root_path = "/path/to/keystore"
39+
# Path to your publishing keypair.
40+
key_store.publish_keypair_path = "/path/to/keypair.json"
41+
42+
# Oracle program pubkey
43+
key_store.program_key = "8tfDNiaEyrV6Q1U4DEXrEigs9DoDtkugzFbybENEbCDz"
44+
45+
# Oracle mapping pubkey
46+
key_store.mapping_key = "AFmdnt9ng1uVxqCmqwQJDAYC5cKTkw8gJKSM5PnzuF6z"
3047

3148
# Duration of the interval at which to publish updates. Default interval is 1 seconds.
3249
# exporter.publish_interval_duration = "1s"

config/config.toml

+20-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Configuration for the JRPC API Websocket Server
22
[pythd_api_server]
3-
# The address on which the websocket API server will listen on.
3+
# The address on which the websocket API server will listen.
4+
#
5+
# NOTE: non-loopback addresses must be used carefully, making sure the
6+
# connection is not exposed for unauthorized access.
47
listen_address = "127.0.0.1:8910"
58

69
# Configuration for the primary network this agent will publish data to. In most cases this should be a Pythnet endpoint.
@@ -16,19 +19,32 @@ rpc_url = "https://api.pythtest.pyth.network"
1619
# Note that api.pythtest.pyth.network is a private endpoint: please contact us for access.
1720
wss_url = "wss://api.pythtest.pyth.network"
1821

19-
# Path to the key store.
20-
key_store.root_path = "/path/to/keystore"
22+
# Path to the keypair used to publish price updates. If set to a
23+
# non-existent file path, the system expects a keypair to be loaded
24+
# via the remote keypair loader. If the path is valid, the remote
25+
# keypair loading is disabled.
26+
key_store.publish_keypair = "/path/to/keypair.json"
27+
28+
# Public key of the oracle program
29+
key_store.program_key = "RelevantOracleProgramAddress"
30+
31+
# Public key of the root mapping account
32+
key_store.mapping_key = "RelevantOracleMappingAddress"
33+
34+
# Optional public key of the accumulator program (if provided)
35+
key_store.accumulator_key = "RelevantOracleAccumulatorAddress"
2136

2237
### Optional fields ###
2338

2439
# [metrics_server]
2540
#
2641
# Where to serve the quick-access dashboard and metrics. Metrics live under "/metrics"
42+
# NOTE: non-loopback addresses must be used carefully, making sure the
43+
# connection is not exposed for unauthorized access.
2744
# bind_address = "127.0.0.1:8888"
2845

2946
# [remote_keypair_loader}
3047
# Where to serve the remote keypair loading endpoint, under "/primary/load_keypair" and "/secondary/load_keypair"
31-
#
3248
# NOTE: non-loopback addresses must be used carefully, making sure the
3349
# connection is not exposed for unauthorized access.
3450
# bind_address = "127.0.0.1:9001"

integration-tests/agent_conf.toml

-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@
22
bind_address="0.0.0.0:8888"
33

44
[primary_network]
5-
key_store.root_path = "keystore"
65
oracle.poll_interval_duration = "1s"
76
exporter.transaction_monitor.poll_interval_duration = "1s"

0 commit comments

Comments
 (0)