Skip to content

Commit 687e130

Browse files
authored
Merge branch 'main' into fix/ignore-product-without-price
2 parents e2071c1 + e4683c7 commit 687e130

File tree

11 files changed

+98
-130
lines changed

11 files changed

+98
-130
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.10.2"
3+
version = "2.10.3"
44
edition = "2021"
55

66
[[bin]]

config/config.sample.pythnet.toml

Lines changed: 4 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ listen_address = "127.0.0.1:8910"
33

44
[primary_network]
55

6-
# HTTP(S) endpoint of the RPC node. Public RPC endpoints are usually rate-limited, so a private
7-
# endpoint should be used in most cases.
6+
# HTTP(S) endpoint of the RPC node. Public Pythnet RPC endpoints are usually
7+
# rate-limited, so a private endpoint should be used in most cases.
88
rpc_url = "https://api2.pythnet.pyth.network"
99

1010
# WS(S) endpoint of the RRC node. This is used to subscribe to account changes on the network.
@@ -20,48 +20,8 @@ key_store.program_key = "FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH"
2020
# Oracle mapping pubkey
2121
key_store.mapping_key = "AHtgzX45WTKfkPG53L6WYhGEXwQkN1BVknET3sVsLL8J"
2222

23-
# Pythnet accumulator key
24-
# The pythnet accumulator key settings are only valid for pythnet. Do not apply these settings for any other environment i.e. mainnet, pythtest-conformance
25-
key_store.accumulator_key = "7Vbmv1jt4vyuqBZcpYPpnVhrqVe5e6ZPb6JxDcffRHUM"
26-
27-
# IMPORTANT: Exporter batch size must be decreased to 7 to support
28-
# larger accumulator transactions, when accumulator_key is set.
29-
exporter.max_batch_size = 7
30-
31-
# Duration of the interval at which to publish updates
32-
exporter.publish_interval_duration = "1s"
33-
34-
# Configuration for the optional secondary network this agent will publish data to.
35-
# In most cases this should be a Solana endpoint.
36-
[secondary_network]
37-
38-
# Please use other endpoints as these are rate limited
39-
rpc_url = "https://api.mainnet-beta.solana.com"
40-
wss_url = "wss://api.mainnet-beta.solana.com"
41-
42-
# Path to your publishing keypair.
43-
key_store.publish_keypair_path = "/path/to/keypair.json"
44-
45-
# Oracle program pubkey
46-
key_store.program_key = "FsJ3A3u2vn5cTVofAjvy6y5kwABJAqYWpe4975bi2epH"
47-
48-
# Oracle mapping pubkey
49-
key_store.mapping_key = "AHtgzX45WTKfkPG53L6WYhGEXwQkN1BVknET3sVsLL8J"
50-
51-
# Compute unit limit requested per instruction for transactions that update the price.
52-
# This should be an upper bound of the compute units a single upd_price instruction might consume.
53-
# For solana mainnet, this should be set to 20000 instead of the default 40000 since there is no accumulator.
54-
exporter.compute_unit_limit = 20000
55-
56-
# Whether the dynamic compute unit pricing is enabled.
57-
# This is needed for solana to be able to land transactions on the network
58-
# during periods of high network congestion.
59-
exporter.dynamic_compute_unit_pricing_enabled = true
60-
61-
# Price per compute unit offered for update_price transactions
62-
exporter.compute_unit_price_micro_lamports = 1000
63-
64-
exporter.maximum_compute_unit_price_micro_lamports = 100000
23+
# Compute unit per price update.
24+
exporter.compute_unit_limit = 5000
6525

6626
# Configuration for the JRPC API
6727
[pythd_adapter]

config/config.sample.pythtest.toml

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ listen_address = "127.0.0.1:8910"
33

44
[primary_network]
55

6-
# HTTP(S) endpoint of the RPC node. Public RPC endpoints are usually rate-limited, so a private
7-
# endpoint should be used in most cases.
6+
# HTTP(S) endpoint of the RPC node.
87
rpc_url = "https://api.pythtest.pyth.network"
98

10-
# WS(S) endpoint of the RRC node. This is used to subscribe to account changes on the network.
11-
# This can be omitted when oracle.subscriber_enabled is set to false.
9+
# WS(S) endpoint of the RRC node. This is used to subscribe to account changes
10+
# on the network. This can be omitted when oracle.subscriber_enabled is set to
11+
# false.
1212
wss_url = "wss://api.pythtest.pyth.network"
1313

1414
# Path to your publishing keypair.
@@ -28,31 +28,6 @@ key_store.mapping_key = "AFmdnt9ng1uVxqCmqwQJDAYC5cKTkw8gJKSM5PnzuF6z" # conform
2828
# Duration of the interval at which to publish updates
2929
exporter.publish_interval_duration = "400ms"
3030

31-
# Configuration for the optional secondary network this agent will publish data to.
32-
# In most cases this should be a Solana endpoint.
33-
[secondary_network]
34-
35-
# Please use other endpoints as these are rate limited
36-
rpc_url = "https://api.testnet.solana.com"
37-
wss_url = "wss://api.testnet.solana.com"
38-
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"
47-
48-
# Duration of the interval at which to publish updates. Default interval is 1 seconds.
49-
# exporter.publish_interval_duration = "1s"
50-
51-
# Price per compute unit offered for update_price transactions.
52-
# This is needed for solana to be able to land transactions on the network
53-
# during periods of high network congestion.
54-
exporter.compute_unit_price_micro_lamports = 1000
55-
5631
# Configuration for the JRPC API
5732
[pythd_adapter]
5833

config/config.toml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,29 @@
66
# connection is not exposed for unauthorized access.
77
listen_address = "127.0.0.1:8910"
88

9+
# Size of the buffer of each Server's channel on which `notify_price` events are
10+
# received from the Price state.
11+
# notify_price_tx_buffer = 10000
12+
13+
# Size of the buffer of each Server's channel on which `notify_price_sched` events are
14+
# received from the Price state.
15+
# notify_price_sched_tx_buffer = 10000
16+
17+
# Flush interval for responses and notifications. This is the maximum time the
18+
# server will wait before flushing the messages to the client.
19+
# flush_interval_duration = "50ms"
20+
921
# Configuration for the primary network this agent will publish data to. In most cases this should be a Pythnet endpoint.
1022
[primary_network]
1123
### Required fields ###
1224

13-
# HTTP(S) endpoint of the RPC node. Public RPC endpoints are usually rate-limited, so a private endpoint should be used in most cases.
14-
# Note that api.pythtest.pyth.network is a private endpoint: please contact us for access.
25+
# HTTP(S) endpoint of the RPC node. Public RPC endpoints are usually
26+
# rate-limited for Pythnet, and so a private endpoint should be used in most
27+
# cases. For Pythtest, the public endpoint can be used.
1528
rpc_url = "https://api.pythtest.pyth.network"
1629

1730
# WS(S) endpoint of the RRC node. This is used to subscribe to account changes on the network.
1831
# This can be omitted when oracle.subscriber_enabled is set to false.
19-
# Note that api.pythtest.pyth.network is a private endpoint: please contact us for access.
2032
wss_url = "wss://api.pythtest.pyth.network"
2133

2234
# Path to the keypair used to publish price updates. If set to a
@@ -186,8 +198,8 @@ key_store.mapping_key = "RelevantOracleMappingAddress"
186198
## Configuration for OpenTelemetry ##
187199
[opentelemetry]
188200

189-
# Timeout in seconds for the OpenTelemetry exporter
190-
exporter_timeout_secs = 3
201+
# Timeout duration for the OpenTelemetry exporter
202+
exporter_timeout_duration = "3s"
191203

192204
# Endpoint URL for the OpenTelemetry exporter
193205
exporter_endpoint = "http://127.0.0.1:4317"

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[toolchain]
2-
channel = "stable"
2+
channel = "1.79.0"
33
profile = "minimal"
44
components = ["rustfmt", "clippy"]

src/agent/config.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ use {
1313
File,
1414
},
1515
serde::Deserialize,
16-
std::path::Path,
16+
std::{
17+
path::Path,
18+
time::Duration,
19+
},
1720
};
1821

1922
/// Configuration for all components of the Agent
@@ -88,6 +91,7 @@ impl Default for ChannelCapacities {
8891

8992
#[derive(Deserialize, Debug)]
9093
pub struct OpenTelemetryConfig {
91-
pub exporter_timeout_secs: u64,
92-
pub exporter_endpoint: String,
94+
#[serde(with = "humantime_serde")]
95+
pub exporter_timeout_duration: Duration,
96+
pub exporter_endpoint: String,
9397
}

src/agent/pyth/rpc.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ use {
4848
fmt::Debug,
4949
net::SocketAddr,
5050
sync::Arc,
51+
time::Duration,
5152
},
5253
tokio::sync::mpsc,
5354
tracing::instrument,
@@ -115,6 +116,7 @@ async fn handle_connection<S>(
115116
state: Arc<S>,
116117
notify_price_tx_buffer: usize,
117118
notify_price_sched_tx_buffer: usize,
119+
flush_interval_duration: Duration,
118120
) where
119121
S: state::Prices,
120122
S: Send,
@@ -127,6 +129,8 @@ async fn handle_connection<S>(
127129
let (mut notify_price_sched_tx, mut notify_price_sched_rx) =
128130
mpsc::channel(notify_price_sched_tx_buffer);
129131

132+
let mut flush_interval = tokio::time::interval(flush_interval_duration);
133+
130134
loop {
131135
if let Err(err) = handle_next(
132136
&*state,
@@ -136,6 +140,7 @@ async fn handle_connection<S>(
136140
&mut notify_price_rx,
137141
&mut notify_price_sched_tx,
138142
&mut notify_price_sched_rx,
143+
&mut flush_interval,
139144
)
140145
.await
141146
{
@@ -159,6 +164,7 @@ async fn handle_next<S>(
159164
notify_price_rx: &mut mpsc::Receiver<NotifyPrice>,
160165
notify_price_sched_tx: &mut mpsc::Sender<NotifyPriceSched>,
161166
notify_price_sched_rx: &mut mpsc::Receiver<NotifyPriceSched>,
167+
flush_interval: &mut tokio::time::Interval,
162168
) -> Result<()>
163169
where
164170
S: state::Prices,
@@ -183,13 +189,16 @@ where
183189
}
184190
}
185191
Some(notify_price) = notify_price_rx.recv() => {
186-
send_notification(ws_tx, Method::NotifyPrice, Some(notify_price))
192+
feed_notification(ws_tx, Method::NotifyPrice, Some(notify_price))
187193
.await
188194
}
189195
Some(notify_price_sched) = notify_price_sched_rx.recv() => {
190-
send_notification(ws_tx, Method::NotifyPriceSched, Some(notify_price_sched))
196+
feed_notification(ws_tx, Method::NotifyPriceSched, Some(notify_price_sched))
191197
.await
192198
}
199+
_ = flush_interval.tick() => {
200+
flush(ws_tx).await
201+
}
193202
}
194203
}
195204

@@ -229,9 +238,9 @@ where
229238
// Send an array if we're handling a batch
230239
// request, single response object otherwise
231240
if is_batch {
232-
send_text(ws_tx, &serde_json::to_string(&responses)?).await?;
241+
feed_text(ws_tx, &serde_json::to_string(&responses)?).await?;
233242
} else {
234-
send_text(ws_tx, &serde_json::to_string(&responses[0])?).await?;
243+
feed_text(ws_tx, &serde_json::to_string(&responses[0])?).await?;
235244
}
236245
}
237246
// The top-level parsing errors are fine to share with client
@@ -354,21 +363,21 @@ async fn send_error(
354363
error.to_string(),
355364
None,
356365
);
357-
send_text(ws_tx, &response.to_string()).await
366+
feed_text(ws_tx, &response.to_string()).await
358367
}
359368

360-
async fn send_notification<T>(
369+
async fn feed_notification<T>(
361370
ws_tx: &mut SplitSink<WebSocket, Message>,
362371
method: Method,
363372
params: Option<T>,
364373
) -> Result<()>
365374
where
366375
T: Sized + Serialize + DeserializeOwned,
367376
{
368-
send_request(ws_tx, IdReq::Notification, method, params).await
377+
feed_request(ws_tx, IdReq::Notification, method, params).await
369378
}
370379

371-
async fn send_request<I, T>(
380+
async fn feed_request<I, T>(
372381
ws_tx: &mut SplitSink<WebSocket, Message>,
373382
id: I,
374383
method: Method,
@@ -379,16 +388,20 @@ where
379388
T: Sized + Serialize + DeserializeOwned,
380389
{
381390
let request = Request::with_params(id, method, params);
382-
send_text(ws_tx, &request.to_string()).await
391+
feed_text(ws_tx, &request.to_string()).await
383392
}
384393

385-
async fn send_text(ws_tx: &mut SplitSink<WebSocket, Message>, msg: &str) -> Result<()> {
394+
async fn feed_text(ws_tx: &mut SplitSink<WebSocket, Message>, msg: &str) -> Result<()> {
386395
ws_tx
387-
.send(Message::text(msg.to_string()))
396+
.feed(Message::text(msg.to_string()))
388397
.await
389398
.map_err(|e| e.into())
390399
}
391400

401+
async fn flush(ws_tx: &mut SplitSink<WebSocket, Message>) -> Result<()> {
402+
ws_tx.flush().await.map_err(|e| e.into())
403+
}
404+
392405
#[derive(Clone, Debug, Serialize, Deserialize)]
393406
#[serde(default)]
394407
pub struct Config {
@@ -400,6 +413,9 @@ pub struct Config {
400413
/// Size of the buffer of each Server's channel on which `notify_price_sched` events are
401414
/// received from the Price state.
402415
pub notify_price_sched_tx_buffer: usize,
416+
/// Flush interval duration for the notifications.
417+
#[serde(with = "humantime_serde")]
418+
pub flush_interval_duration: Duration,
403419
}
404420

405421
impl Default for Config {
@@ -408,6 +424,7 @@ impl Default for Config {
408424
listen_address: "127.0.0.1:8910".to_string(),
409425
notify_price_tx_buffer: 10000,
410426
notify_price_sched_tx_buffer: 10000,
427+
flush_interval_duration: Duration::from_millis(50),
411428
}
412429
}
413430
}
@@ -448,6 +465,7 @@ where
448465
state,
449466
config.notify_price_tx_buffer,
450467
config.notify_price_sched_tx_buffer,
468+
config.flush_interval_duration,
451469
)
452470
.await
453471
})

src/agent/services/exporter.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ mod exporter {
262262
config.exporter.unchanged_publish_threshold,
263263
).await {
264264
if let Err(err) = publish_batches(
265-
&*state,
265+
state.clone(),
266266
client.clone(),
267267
network,
268268
&network_state_rx,

0 commit comments

Comments
 (0)