Bladeren bron

pyth-lazer-agent readme and clippy config

Mike Rolish 4 maanden geleden
bovenliggende
commit
249a49c41a

+ 5 - 5
apps/pyth-lazer-agent/Cargo.lock

@@ -436,9 +436,9 @@ dependencies = [
 
 [[package]]
 name = "crunchy"
-version = "0.2.3"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
+checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
 
 [[package]]
 name = "crypto-common"
@@ -1146,9 +1146,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
+checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
 dependencies = [
  "equivalent",
  "hashbrown 0.15.4",
@@ -1643,7 +1643,7 @@ dependencies = [
 
 [[package]]
 name = "pyth-lazer-agent"
-version = "0.1.2"
+version = "0.1.3"
 dependencies = [
  "anyhow",
  "backoff",

+ 41 - 1
apps/pyth-lazer-agent/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "pyth-lazer-agent"
-version = "0.1.2"
+version = "0.1.3"
 edition = "2024"
 
 [dependencies]
@@ -36,3 +36,43 @@ url = { version = "2.5.4", features = ["serde"] }
 
 [dev-dependencies]
 tempfile = "3.20.0"
+
+[lints.rust]
+unsafe_code = "deny"
+
+[lints.clippy]
+wildcard_dependencies = "deny"
+
+collapsible_if = "allow"
+collapsible_else_if = "allow"
+
+allow_attributes_without_reason = "warn"
+
+# Panics
+expect_used = "warn"
+fallible_impl_from = "warn"
+indexing_slicing = "warn"
+panic = "warn"
+panic_in_result_fn = "warn"
+string_slice = "warn"
+todo = "warn"
+unchecked_duration_subtraction = "warn"
+unreachable = "warn"
+unwrap_in_result = "warn"
+unwrap_used = "warn"
+
+# Correctness
+cast_lossless = "warn"
+cast_possible_truncation = "warn"
+cast_possible_wrap = "warn"
+cast_sign_loss = "warn"
+collection_is_never_read = "warn"
+match_wild_err_arm = "warn"
+path_buf_push_overwrite = "warn"
+read_zero_byte_vec = "warn"
+same_name_method = "warn"
+suspicious_operation_groupings = "warn"
+suspicious_xor_used_as_pow = "warn"
+unused_self = "warn"
+used_underscore_binding = "warn"
+while_float = "warn"

+ 51 - 0
apps/pyth-lazer-agent/README.md

@@ -0,0 +1,51 @@
+# pyth-lazer-agent
+
+pyth-lazer-agent is intended to be run by Lazer publishers analogous to [pyth-agent](https://github.com/pyth-network/pyth-agent)
+for pythnet publishers. Currently it retains [the existing Lazer publishing interface](https://github.com/pyth-network/pyth-examples/tree/main/lazer/publisher),
+but will batch and sign transactions before publishing them to Lazer.
+
+## Keypair
+
+You will need to generate an ed25519 keypair and provide the pubkey to the Lazer team. `solana-keygen` is the recommended utility.
+```bash
+solana-keygen new -o /path/to/keypair.json
+solana-keygen pubkey /path/to/keypair.json
+```
+
+pyth-lazer-agent will need to configure access to this keypair file to sign transactions.
+
+## Build and run
+
+### From source
+Please check [rust-toolchain](rust-toolchain.toml) to see the version of Rust needed to build (currently 1.88).
+You will also need SSL and CA certificates. `cargo build` should then work as usual.
+
+### Docker
+See the included [Dockerfile](Dockerfile) to build an image yourself.
+
+### Container
+We also publish images to the [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry#pulling-container-images).
+The latest will be available at `ghcr.io/pyth-network/pyth-lazer-agent:latest`.
+
+## Configure
+The agent takes a single `--config` CLI option, pointing at
+`config/config.toml` by default. Configuration is currently minimal:
+
+```toml
+relayer_urls = ["ws://relayer-0.pyth-lazer.dourolabs.app/v1/transaction", "ws://relayer-0.pyth-lazer.dourolabs.app/v1/transaction"]
+publish_keypair_path = "/path/to/keypair.json"
+authorization_token = "your_token"
+listen_address = "0.0.0.0:8910"
+publish_interval_duration = "25ms"
+```
+
+- `relayers_urls`: The Lazer team will provide these.
+- `publish_keypair_path`: The keypair file generated with `solana-keygen` or similar.
+- `authorization_token`: The Lazer team will provide this or instruct that it can be omitted.
+- `listen_address`: The local port the agent will be listening on; can be anything you want.
+- `publisher_interval`: The agent will batch and send transaction bundles at this interval. The Lazer team will provide guidance here.
+
+## Publish
+
+Please use the `/v1/publisher` or `/v2/publisher` endpoints and the corresponding `PriceFeedDataV1` and `PriceFeedDataV2`
+schemas as defined in [the sdk](https://github.com/pyth-network/pyth-crosschain/blob/main/lazer/sdk/rust/protocol/src/publisher.rs).

+ 3 - 0
apps/pyth-lazer-agent/clippy.toml

@@ -0,0 +1,3 @@
+allow-unwrap-in-tests = true
+allow-expect-in-tests = true
+allow-indexing-slicing-in-tests = true

+ 1 - 1
apps/pyth-lazer-agent/rust-toolchain.toml

@@ -1,4 +1,4 @@
 [toolchain]
-channel = "1.87.0"
+channel = "1.88.0"
 profile = "minimal"
 components = ["rustfmt", "clippy"]

+ 1 - 1
apps/pyth-lazer-agent/src/lazer_publisher.rs

@@ -49,12 +49,12 @@ impl LazerPublisher {
             .context("Failed to create signing key from keypair")
     }
 
+    #[allow(clippy::panic, reason = "can't run agent without keypair")]
     pub async fn new(config: &Config) -> Self {
         let signing_key = match Self::load_signing_key(&config.publish_keypair_path) {
             Ok(signing_key) => signing_key,
             Err(e) => {
                 tracing::error!("Failed to load signing key: {e:?}");
-                // Can't proceed on key failure
                 panic!("Failed to load signing key: {e:?}");
             }
         };

+ 1 - 0
apps/pyth-lazer-agent/src/main.rs

@@ -22,6 +22,7 @@ struct Cli {
 
 #[tokio::main]
 async fn main() -> anyhow::Result<()> {
+    #[allow(clippy::expect_used, reason = "application can fail on invalid RUST_LOG")]
     tracing_subscriber::fmt()
         .with_env_filter(
             EnvFilter::builder()

+ 5 - 1
apps/pyth-lazer-agent/src/publisher_handle.rs

@@ -69,7 +69,7 @@ async fn try_handle_publisher(
             // in the inner loop.
             let receive = async { ws_receiver.receive(&mut receive_buf).await };
             pin!(receive);
-            #[allow(clippy::never_loop)] // false positive
+            #[allow(clippy::never_loop, reason = "false positive")]
             loop {
                 select! {
                     _result = &mut receive => {
@@ -88,7 +88,9 @@ async fn try_handle_publisher(
                 ) {
                     Ok((data, _)) => {
                         let source_timestamp = MessageField::some(Timestamp {
+                            #[allow(clippy::cast_possible_wrap, reason = "Unix seconds won't wrap any time soon")]
                             seconds: (data.source_timestamp_us.0 / 1_000_000) as i64,
+                            #[allow(clippy::cast_possible_truncation, reason = "this value will always be less than one billion")]
                             nanos: (data.source_timestamp_us.0 % 1_000_000 * 1000) as i32,
                             special_fields: Default::default(),
                         });
@@ -131,7 +133,9 @@ async fn try_handle_publisher(
                 ) {
                     Ok((data, _)) => {
                         let source_timestamp = MessageField::some(Timestamp {
+                            #[allow(clippy::cast_possible_wrap, reason = "Unix seconds won't wrap any time soon")]
                             seconds: (data.source_timestamp_us.0 / 1_000_000) as i64,
+                            #[allow(clippy::cast_possible_truncation, reason = "this value will always be less than one billion")]
                             nanos: (data.source_timestamp_us.0 % 1_000_000 * 1000) as i32,
                             special_fields: Default::default(),
                         });