Skip to content

Commit 3835e58

Browse files
feat: release the agent with multi-rpc and lazer support (#160)
* fix: add build-essential to docker * fix: change wss_url to wss_urls * Bump solana cli install url and version * chore: bump version as a major change * chore: add docs for lazer config * refactor: move routes out of the config to the code * refactor: read key from file * fix: use transaction route * refactor: use err instead of warn on key loading failure * refactor: remove authorization token as it's not needed anymore * Revert "refactor: remove authorization token as it's not needed anymore" This reverts commit f89b9cd. --------- Co-authored-by: Mike Rolish <mrolish@dourolabs.xyz>
1 parent 4ffe002 commit 3835e58

File tree

8 files changed

+54
-13
lines changed

8 files changed

+54
-13
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pyth-agent"
3-
version = "2.12.3"
3+
version = "3.0.0"
44
edition = "2024"
55

66
[[bin]]

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM rust:slim-bookworm as builder
22

3-
RUN apt update && apt install -y curl libssl-dev pkg-config && apt clean all
3+
RUN apt update && apt install -y curl libssl-dev pkg-config build-essential && apt clean all
44

55
ADD . /agent
66
WORKDIR /agent

config/config.sample.pythnet.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ rpc_urls = ["https://api2.pythnet.pyth.network"]
1010

1111
# WS(S) endpoint of the RRC node. This is used to subscribe to account changes on the network.
1212
# This can be omitted when oracle.subscriber_enabled is set to false.
13-
wss_url = "wss://api2.pythnet.pyth.network"
13+
wss_urls = ["wss://api2.pythnet.pyth.network"]
1414

1515
# Path to your publishing keypair.
1616
key_store.publish_keypair_path = "/path/to/keypair.json"

config/config.sample.pythtest.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ rpc_urls = ["https://api.pythtest.pyth.network"]
1010
# WS(S) endpoint of the RRC node. This is used to subscribe to account changes
1111
# on the network. This can be omitted when oracle.subscriber_enabled is set to
1212
# false.
13-
wss_url = "wss://api.pythtest.pyth.network"
13+
wss_urls = ["wss://api.pythtest.pyth.network"]
1414

1515
# Path to your publishing keypair.
1616
key_store.publish_keypair_path = "/path/to/keypair.json"

config/config.toml

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ rpc_urls = ["https://api.pythtest.pyth.network"]
3737

3838
# WS(S) endpoint of the RRC node. This is used to subscribe to account changes on the network.
3939
# This can be omitted when oracle.subscriber_enabled is set to false.
40-
wss_url = "wss://api.pythtest.pyth.network"
40+
wss_urls = ["wss://api.pythtest.pyth.network"]
4141

4242
# Path to the keypair used to publish price updates. If set to a
4343
# non-existent file path, the system expects a keypair to be loaded
@@ -218,3 +218,24 @@ exporter_timeout_duration = "3s"
218218

219219
# Endpoint URL for the OpenTelemetry exporter
220220
exporter_endpoint = "http://127.0.0.1:4317"
221+
222+
## Configuration for Pyth Lazer ##
223+
224+
# [pyth_lazer]
225+
# URL for the history service
226+
# history_url = "https://pyth-lazer-staging.dourolabs.app"
227+
228+
# URLs for the Lazer relayers to connect to
229+
# relayer_urls = ["wss://pyth-lazer-staging.dourolabs.app"]
230+
231+
# Unique identifier for this publisher
232+
# publisher_id = 1
233+
234+
# Authorization token for connecting to relayers
235+
# authorization_token = "your-auth-token"
236+
237+
# Path to the publisher's secret key file
238+
# publish_keypair_path = "/path/to/publisher-key.json"
239+
240+
# Duration between price updates (defaults to 200ms if not specified)
241+
# publish_interval_duration = "200ms"

integration-tests/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ ENV PATH="${PATH}:/root/.local/bin"
1212
RUN poetry config virtualenvs.in-project true
1313

1414
# Install Solana Tool Suite
15-
RUN sh -c "$(curl -sSfL https://release.solana.com/v1.14.17/install)"
15+
RUN sh -c "$(curl -sSfL https://release.anza.xyz/v2.2.1/install)"
1616
ENV PATH="${PATH}:/root/.local/share/solana/install/active_release/bin"
1717

1818
ADD . /agent

src/agent/services/lazer_exporter.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use {
1919
reqwest::Client,
2020
serde::Deserialize,
2121
std::{
22+
path::PathBuf,
2223
sync::Arc,
2324
time::Duration,
2425
},
@@ -48,7 +49,7 @@ pub struct Config {
4849
pub relayer_urls: Vec<Url>,
4950
pub publisher_id: u32,
5051
pub authorization_token: String,
51-
publisher_secret_key: PublisherSecretKey,
52+
pub publish_keypair_path: PathBuf,
5253
#[serde(with = "humantime_serde", default = "default_publish_interval")]
5354
pub publish_interval_duration: Duration,
5455
}
@@ -62,7 +63,7 @@ impl std::fmt::Debug for PublisherSecretKey {
6263
}
6364

6465
fn default_publish_interval() -> Duration {
65-
Duration::from_millis(10)
66+
Duration::from_millis(200)
6667
}
6768

6869
struct RelayerSender {
@@ -85,13 +86,14 @@ impl RelayerSender {
8586
}
8687

8788
async fn connect_to_relayer(
88-
url: &Url,
89+
mut url: Url,
8990
token: &str,
9091
) -> Result<(
9192
SplitSink<WebSocketStream<MaybeTlsStream<TcpStream>>, TungsteniteMessage>,
9293
SplitStream<WebSocketStream<MaybeTlsStream<TcpStream>>>,
9394
)> {
9495
tracing::info!("connecting to the relayer at {}", url);
96+
url.set_path("/v1/transaction");
9597
let mut req = url.clone().into_client_request()?;
9698
let headers = req.headers_mut();
9799
headers.insert(
@@ -112,7 +114,7 @@ async fn connect_to_relayers(
112114
let mut relayer_receivers = Vec::new();
113115
for url in config.relayer_urls.clone() {
114116
let (relayer_sender, relayer_receiver) =
115-
connect_to_relayer(&url, &config.authorization_token).await?;
117+
connect_to_relayer(url, &config.authorization_token).await?;
116118
relayer_senders.push(relayer_sender);
117119
relayer_receivers.push(relayer_receiver);
118120
}
@@ -172,7 +174,10 @@ mod lazer_exporter {
172174
},
173175
state::local::LocalStore,
174176
},
175-
anyhow::bail,
177+
anyhow::{
178+
Context,
179+
bail,
180+
},
176181
ed25519_dalek::{
177182
Signer,
178183
SigningKey,
@@ -197,6 +202,7 @@ mod lazer_exporter {
197202
lazer_transaction::Payload,
198203
},
199204
},
205+
solana_sdk::signer::keypair,
200206
std::{
201207
collections::HashMap,
202208
sync::Arc,
@@ -259,7 +265,21 @@ mod lazer_exporter {
259265
stream_map.insert(config.relayer_urls[i].clone(), receiver);
260266
}
261267

262-
let signing_key = SigningKey::from_bytes(&config.publisher_secret_key.0);
268+
// Read the keypair from the file using Solana SDK because it's the same key used by the Pythnet publisher
269+
let publish_keypair = match keypair::read_keypair_file(&config.publish_keypair_path) {
270+
Ok(k) => k,
271+
Err(e) => {
272+
tracing::error!(
273+
error = ?e,
274+
publish_keypair_path = config.publish_keypair_path.display().to_string(),
275+
"Reading publish keypair returned an error. ",
276+
);
277+
bail!("Reading publish keypair returned an error. ");
278+
}
279+
};
280+
281+
let signing_key = SigningKey::from_keypair_bytes(&publish_keypair.to_bytes())
282+
.context("Failed to create signing key from keypair")?;
263283
let mut publish_interval = tokio::time::interval(config.publish_interval_duration);
264284

265285
loop {

0 commit comments

Comments
 (0)