diff --git a/Cargo.lock b/Cargo.lock index f49e94e..054b095 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3431,6 +3431,7 @@ dependencies = [ "serde", "serde-this-or-that", "serde_json", + "smol_str", "soketto", "solana-account-decoder", "solana-client", @@ -4052,9 +4053,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", @@ -4460,6 +4461,16 @@ version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +[[package]] +name = "smol_str" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9676b89cd56310a87b93dec47b11af744f34d5fc9f367b829474eec0a891350d" +dependencies = [ + "borsh 1.4.0", + "serde", +] + [[package]] name = "socket2" version = "0.5.6" @@ -4487,9 +4498,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b359495f76e0570a3e611e8963f4703828f7516e6577d38d642644ad205c16" +checksum = "b109fd3a106e079005167e5b0e6f6d2c88bbedec32530837b584791a8b5abf36" dependencies = [ "Inflector", "base64 0.21.7", @@ -4512,9 +4523,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94d44534a77097037399d613994d521a3bb56ce63d423d77efdb1d4b06666d2d" +checksum = "074ef478856a45d5627270fbc6b331f91de9aae7128242d9e423931013fb8a2a" dependencies = [ "chrono", "clap 2.34.0", @@ -4529,9 +4540,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a55322d541c2147ea979832641ca718651eb7a9284fa25b9d6c4cb21fd6f1850" +checksum = "24a9f32c42402c4b9484d5868ac74b7e0a746e3905d8bfd756e1203e50cbb87e" dependencies = [ "async-trait", "bincode", @@ -4562,9 +4573,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63f328bb6c0a8013218fb71ef31c6524359eae1d328f4ffef4d14e3e7141f84f" +checksum = "9d75b803860c0098e021a26f0624129007c15badd5b0bc2fbd9f0e1a73060d3b" dependencies = [ "bincode", "chrono", @@ -4576,9 +4587,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb39f5996aa944722975efe70adb01f91705cf42e0d302eacb868f51d5c92601" +checksum = "b9306ede13e8ceeab8a096bcf5fa7126731e44c201ca1721ea3c38d89bcd4111" dependencies = [ "async-trait", "bincode", @@ -4598,9 +4609,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "033e98b727d281cc22381ff703f58b70822b8c32ddb7aca9e7eb3a9c1d465371" +checksum = "03ab2c30c15311b511c0d1151e4ab6bc9a3e080a37e7c6e7c2d96f5784cf9434" dependencies = [ "block-buffer 0.10.4", "bs58", @@ -4623,9 +4634,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aab7183079f7a0c0b71454fd365e12bce9a773b8099f6c2a92ba6887c42a9d0f" +checksum = "c142f779c3633ac83c84d04ff06c70e1f558c876f13358bed77ba629c7417932" dependencies = [ "proc-macro2", "quote", @@ -4635,9 +4646,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5559aeadd3adc219fa7169e96a8c5dda618c7f06985f91f2a5f55b9814c7a2" +checksum = "121d36ffb3c6b958763312cbc697fbccba46ee837d3a0aa4fc0e90fcb3b884f3" dependencies = [ "env_logger", "lazy_static", @@ -4646,9 +4657,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "041ab11f1e02d4dbe4f45e6854c312ae2518a5cbe3327b767cab2bc9a8fc0740" +checksum = "5c01a7f9cdc9d9d37a3d5651b2fe7ec9d433c2a3470b9f35897e373b421f0737" dependencies = [ "log", "solana-sdk", @@ -4656,9 +4667,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aab373e70aa970e62d16ba1e7e21c54519582c57b680fd31d80421aa3a983a1" +checksum = "71e36052aff6be1536bdf6f737c6e69aca9dbb6a2f3f582e14ecb0ddc0cd66ce" dependencies = [ "crossbeam-channel", "gethostname", @@ -4671,9 +4682,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736fc2f0fc5a0948d8cb74152d68733c7a682ff8b8ef8df27e75d164c2ed6969" +checksum = "2a1f5c6be9c5b272866673741e1ebc64b2ea2118e5c6301babbce526fdfb15f4" dependencies = [ "bincode", "clap 3.2.25", @@ -4693,9 +4704,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e9a1f74df1265cc43c843367a833cff05b8a1b5467676ae540f479751aab3c" +checksum = "28acaf22477566a0fbddd67249ea5d859b39bacdb624aff3fadd3c5745e2643c" dependencies = [ "ahash 0.8.11", "bincode", @@ -4722,9 +4733,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0af84e0c085510c9d1660d1f7e50e8b94ec97f27e23e13d960db353d98b55c8a" +checksum = "c10f4588cefd716b24a1a40dd32c278e43a560ab8ce4de6b5805c9d113afdfa1" dependencies = [ "ark-bn254", "ark-ec", @@ -4777,9 +4788,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69c13c6ac710cb7e4325de42e7f382109d0b9d6495942b38d0e4b528a8a9961a" +checksum = "fbf0c3eab2a80f514289af1f422c121defb030937643c43b117959d6f1932fb5" dependencies = [ "base64 0.21.7", "bincode", @@ -4805,9 +4816,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c0575b3106c15019ad451cc81d5bf328ab07a27e0eadc4af31740b88faf586" +checksum = "b064e76909d33821b80fdd826e6757251934a52958220c92639f634bea90366d" dependencies = [ "crossbeam-channel", "futures-util", @@ -4830,9 +4841,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a81e5186b7cf170616579921da3027b6f94f7275153d38e83b9b2be3fb07ac2" +checksum = "5a90e40ee593f6e9ddd722d296df56743514ae804975a76d47e7afed4e3da244" dependencies = [ "async-mutex", "async-trait", @@ -4857,9 +4868,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881229e01194a0fc5d6115867d2ee5ce0abfb80d53cab3822c4a6bf96210d474" +checksum = "66468f9c014992167de10cc68aad6ac8919a8c8ff428dc88c0d2b4da8c02b8b7" dependencies = [ "lazy_static", "num_cpus", @@ -4867,9 +4878,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf5b80ef02505a7cd7e248c25f839ba5669a13595462eac212dde0895d690ad" +checksum = "c191019f4d4f84281a6d0dd9a43181146b33019627fc394e42e08ade8976b431" dependencies = [ "console", "dialoguer", @@ -4886,9 +4897,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbb2a4cace9ef7c02062efdaa54cfefa13c91fa48cc0c827852adadf7e406963" +checksum = "36ed4628e338077c195ddbf790693d410123d17dec0a319b5accb4aaee3fb15c" dependencies = [ "async-trait", "base64 0.21.7", @@ -4912,9 +4923,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb658d90dca6aece251e0d4288e6e1b06c1b10315abb118032a2e230f8d872f" +checksum = "83c913551faa4a1ae4bbfef6af19f3a5cf847285c05b4409e37c8993b3444229" dependencies = [ "base64 0.21.7", "bs58", @@ -4934,9 +4945,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2d0a1b6936a90b1d831a32605118c6f11d7c0dd3b37fb174eab5e1a0b5f3" +checksum = "1a47b6bb1834e6141a799db62bbdcf80d17a7d58d7bc1684c614e01a7293d7cf" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4947,9 +4958,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68caf1d34891521523df18dc3c13ce20d54a59c3a390729450267a4c9aa96017" +checksum = "580ad66c2f7a4c3cb3244fe21440546bd500f5ecb955ad9826e92a78dded8009" dependencies = [ "assert_matches", "base64 0.21.7", @@ -5002,9 +5013,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cff24eec74815028ebcffe639cf63ff50fb78dadcbf71a8b95b44e7ad1bb6b2" +checksum = "1b75d0f193a27719257af19144fdaebec0415d1c9e9226ae4bd29b791be5e9bd" dependencies = [ "bs58", "proc-macro2", @@ -5021,9 +5032,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-streamer" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af7e0e90d5b6e4aa7182b9f8221fe5a9da4106afc031ac3697a860c2da7c8ac" +checksum = "f8476e41ad94fe492e8c06697ee35912cf3080aae0c9e9ac6430835256ccf056" dependencies = [ "async-channel", "bytes", @@ -5043,6 +5054,7 @@ dependencies = [ "rand 0.8.5", "rcgen", "rustls", + "smallvec", "solana-metrics", "solana-perf", "solana-sdk", @@ -5053,9 +5065,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e55c9d6f7970a9e846256bbf57a571ada379fb300ba39958992fbadf5c24ca5" +checksum = "d8c02245d0d232430e79dc0d624aa42d50006097c3aec99ac82ac299eaa3a73f" dependencies = [ "bincode", "log", @@ -5068,9 +5080,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8859de54d3fbfee458b11536af0f357977044c3b31c9a1154af5c8874ae485" +checksum = "67251506ed03de15f1347b46636b45c47da6be75015b4a13f0620b21beb00566" dependencies = [ "async-trait", "bincode", @@ -5092,9 +5104,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2be62abd39aad39d5377e3ad4f1af7fc7e12577edb0d6ac6405f533f9ce74e7" +checksum = "2d3d36db1b2ab2801afd5482aad9fb15ed7959f774c81a77299fdd0ddcf839d4" dependencies = [ "Inflector", "base64 0.21.7", @@ -5117,9 +5129,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d67fd02dc01d0e7f06079625aaaa7de9ea86d757e16df3ec76cd6e162a91f23" +checksum = "3a754a3c2265eb02e0c35aeaca96643951f03cee6b376afe12e0cf8860ffccd1" dependencies = [ "async-trait", "solana-connection-cache", @@ -5132,9 +5144,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26db373e381b715773164fb9ae47a89f56bbb6fb50469b1b970134d5c6f6ce4d" +checksum = "f44776bd685cc02e67ba264384acc12ef2931d01d1a9f851cb8cdbd3ce455b9e" dependencies = [ "log", "rustc_version", @@ -5148,9 +5160,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c579e4599523cefa128db4075d0fc7b1177434b23ac4f72140a394dd4b4f648" +checksum = "25810970c91feb579bd3f67dca215fce971522e42bfd59696af89c5dfebd997c" dependencies = [ "bincode", "log", @@ -5170,9 +5182,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.18.8" +version = "1.18.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09a78337e50d3ed0b8a6e521969c0e81dfa3649f4d718e88a7e9a0d04ca0d0e0" +checksum = "7cbdf4249b6dfcbba7d84e2b53313698043f60f8e22ce48286e6fbe8a17c8d16" dependencies = [ "aes-gcm-siv", "base64 0.21.7", @@ -5199,9 +5211,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.8.0" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" +checksum = "da5d083187e3b3f453e140f292c09186881da8a02a7b5e27f645ee26de3d9cc5" dependencies = [ "byteorder", "combine", diff --git a/Cargo.toml b/Cargo.toml index 1393f69..b92d9a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ lazy_static = "1.4.0" toml_edit = "0.22.9" winnow = "0.6.5" proptest = "1.4.0" +smol_str = {version="0.3.2", features=["serde"]} tracing = { version = "0.1.40", features = ["log"] } tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] } tracing-opentelemetry = "0.24.0" diff --git a/src/agent/legacy_schedule.rs b/src/agent/legacy_schedule.rs index 49d9c1f..cb4584b 100644 --- a/src/agent/legacy_schedule.rs +++ b/src/agent/legacy_schedule.rs @@ -327,7 +327,7 @@ mod tests { // Prepare UTC datetimes that fall before, within and after market hours let format = "%Y-%m-%d %H:%M"; - let bad_datetimes_before = vec![ + let bad_datetimes_before = [ NaiveDateTime::parse_from_str("2023-11-20 04:30", format)?.and_utc(), NaiveDateTime::parse_from_str("2023-11-21 05:30", format)?.and_utc(), NaiveDateTime::parse_from_str("2023-11-22 06:30", format)?.and_utc(), @@ -337,7 +337,7 @@ mod tests { NaiveDateTime::parse_from_str("2023-11-26 10:30", format)?.and_utc(), ]; - let ok_datetimes = vec![ + let ok_datetimes = [ NaiveDateTime::parse_from_str("2023-11-20 05:30", format)?.and_utc(), NaiveDateTime::parse_from_str("2023-11-21 06:30", format)?.and_utc(), NaiveDateTime::parse_from_str("2023-11-22 07:30", format)?.and_utc(), @@ -347,7 +347,7 @@ mod tests { NaiveDateTime::parse_from_str("2023-11-26 11:30", format)?.and_utc(), ]; - let bad_datetimes_after = vec![ + let bad_datetimes_after = [ NaiveDateTime::parse_from_str("2023-11-20 06:30", format)?.and_utc(), NaiveDateTime::parse_from_str("2023-11-21 07:30", format)?.and_utc(), NaiveDateTime::parse_from_str("2023-11-22 08:30", format)?.and_utc(), @@ -384,10 +384,10 @@ mod tests { "Europe/Amsterdam,23:00-24:00,00:00-01:00,O,C,C,C,C".parse()?; let format = "%Y-%m-%d %H:%M"; - let ok_datetimes = vec![ + let ok_datetimes = [ NaiveDate::from_ymd_opt(2023, 11, 20) .unwrap() - .and_time(MAX_TIME_INSTANT.clone()) + .and_time(*MAX_TIME_INSTANT) .and_local_timezone(Tz::Europe__Amsterdam) .unwrap(), NaiveDateTime::parse_from_str("2023-11-21 00:00", format)? @@ -395,7 +395,7 @@ mod tests { .unwrap(), ]; - let bad_datetimes = vec![ + let bad_datetimes = [ // Start of Monday Nov 20th, must not be confused for MAX_TIME_INSTANT on that day NaiveDateTime::parse_from_str("2023-11-20 00:00", format)? .and_local_timezone(Tz::Europe__Amsterdam) @@ -404,7 +404,7 @@ mod tests { // confused for Wednesday 00:00 which is open. NaiveDate::from_ymd_opt(2023, 11, 21) .unwrap() - .and_time(MAX_TIME_INSTANT.clone()) + .and_time(*MAX_TIME_INSTANT) .and_local_timezone(Tz::Europe__Amsterdam) .unwrap(), ]; diff --git a/src/agent/market_schedule.rs b/src/agent/market_schedule.rs index ba44ed0..02484a1 100644 --- a/src/agent/market_schedule.rs +++ b/src/agent/market_schedule.rs @@ -47,7 +47,7 @@ const MAX_TIME_INSTANT: NaiveTime = NaiveTime::MIN .overflowing_sub_signed(Duration::nanoseconds(1)) .0; -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq, Clone)] pub struct MarketSchedule { pub timezone: Tz, pub weekly_schedule: Vec, @@ -193,8 +193,9 @@ impl Display for HolidayDaySchedule { } } -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Default, Clone, Debug, Eq, PartialEq)] pub enum ScheduleDayKind { + #[default] Open, Closed, TimeRanges(Vec>), @@ -210,12 +211,6 @@ impl ScheduleDayKind { } } -impl Default for ScheduleDayKind { - fn default() -> Self { - Self::Open - } -} - impl Display for ScheduleDayKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/src/agent/metrics.rs b/src/agent/metrics.rs index 424bc32..705d57d 100644 --- a/src/agent/metrics.rs +++ b/src/agent/metrics.rs @@ -15,6 +15,7 @@ use { registry::Registry, }, serde::Deserialize, + smol_str::SmolStr, solana_sdk::pubkey::Pubkey, std::{ net::SocketAddr, @@ -64,9 +65,7 @@ pub async fn spawn(addr: impl Into + 'static) { let mut buf = String::new(); let response = encode(&mut buf, &&PROMETHEUS_REGISTRY.lock().await) .map_err(|e| -> Box { e.into() }) - .and_then(|_| -> Result<_, Box> { - Ok(Box::new(reply::with_status(buf, StatusCode::OK))) - }) + .map(|_| Box::new(reply::with_status(buf, StatusCode::OK))) .unwrap_or_else(|e| { tracing::error!(err = ?e, "Metrics: Could not gather metrics from registry"); Box::new(reply::with_status( @@ -115,8 +114,10 @@ impl ProductGlobalMetrics { metrics } - pub fn update(&self, product_key: &Pubkey, maybe_symbol: Option) { - let symbol_string = maybe_symbol.unwrap_or(format!("unknown_{}", product_key)); + pub fn update(&self, product_key: &Pubkey, maybe_symbol: Option) { + let symbol_string = maybe_symbol + .map(|x| x.into()) + .unwrap_or(format!("unknown_{}", product_key)); #[deny(unused_variables)] let Self { update_count } = self; diff --git a/src/agent/pyth.rs b/src/agent/pyth.rs index 0ab98a5..da8f0b7 100644 --- a/src/agent/pyth.rs +++ b/src/agent/pyth.rs @@ -3,46 +3,50 @@ use { Deserialize, Serialize, }, - std::collections::BTreeMap, + smol_str::SmolStr, + std::{ + collections::BTreeMap, + sync::Arc, + }, }; pub mod rpc; -pub type Pubkey = String; -pub type Attrs = BTreeMap; +pub type Pubkey = SmolStr; +pub type Attrs = BTreeMap; pub type Price = i64; pub type Exponent = i64; pub type Conf = u64; pub type Slot = u64; -#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct ProductAccountMetadata { pub account: Pubkey, pub attr_dict: Attrs, - pub price: Vec, + pub price: Arc<[PriceAccountMetadata]>, } -#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct PriceAccountMetadata { pub account: Pubkey, - pub price_type: String, + pub price_type: SmolStr, pub price_exponent: Exponent, } -#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct ProductAccount { pub account: Pubkey, pub attr_dict: Attrs, - pub price_accounts: Vec, + pub price_accounts: Arc<[PriceAccount]>, } -#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct PriceAccount { pub account: Pubkey, - pub price_type: String, + pub price_type: SmolStr, pub price_exponent: Exponent, - pub status: String, + pub status: SmolStr, pub price: Price, pub conf: Conf, pub twap: Price, @@ -52,36 +56,36 @@ pub struct PriceAccount { pub prev_slot: Slot, pub prev_price: Price, pub prev_conf: Conf, - pub publisher_accounts: Vec, + pub publisher_accounts: Arc<[PublisherAccount]>, } -#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct PublisherAccount { pub account: Pubkey, - pub status: String, + pub status: SmolStr, pub price: Price, pub conf: Conf, pub slot: Slot, } -#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct NotifyPrice { pub subscription: SubscriptionID, pub result: PriceUpdate, } -#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct NotifyPriceSched { pub subscription: SubscriptionID, } pub type SubscriptionID = i64; -#[derive(Serialize, Deserialize, Debug, Clone, Ord, PartialOrd, PartialEq, Eq)] +#[derive(Serialize, Deserialize, Debug, Ord, PartialOrd, PartialEq, Eq)] pub struct PriceUpdate { pub price: Price, pub conf: Conf, - pub status: String, + pub status: SmolStr, pub valid_slot: Slot, pub pub_slot: Slot, } diff --git a/src/agent/state.rs b/src/agent/state.rs index 1edcbd1..2a0b9a1 100644 --- a/src/agent/state.rs +++ b/src/agent/state.rs @@ -89,8 +89,8 @@ impl State { local_store: local::Store::new(registry), keypairs: keypairs::KeypairState::default(), prices: api::PricesState::new(config.state.clone()), - oracle: oracle::OracleState::new(), exporter: exporter::ExporterState::new(), + oracle: oracle::OracleState::default(), transactions: transactions::TransactionsState::new( config .primary_network @@ -109,8 +109,8 @@ impl State { local_store: local::Store::new(registry), keypairs: keypairs::KeypairState::default(), prices: api::PricesState::new(config), - oracle: oracle::OracleState::new(), exporter: exporter::ExporterState::new(), + oracle: oracle::OracleState::default(), transactions: transactions::TransactionsState::new(100), } } @@ -157,6 +157,7 @@ mod tests { Rational, SolanaPriceAccount, }, + smol_str::ToSmolStr, std::{ collections::{ BTreeMap, @@ -245,9 +246,9 @@ mod tests { ("generic_symbol", "LTCUSD"), ("base", "LTC"), ] - .map(|(k, v)| (k.to_string(), v.to_string())), + .map(|(k, v)| (k.into(), v.into())), ), - price_accounts: vec![ + price_accounts: [ solana_sdk::pubkey::Pubkey::from_str( "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU", ) @@ -260,7 +261,8 @@ mod tests { "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6", ) .unwrap(), - ], + ] + .into(), }, ), ( @@ -278,9 +280,9 @@ mod tests { ("generic_symbol", "ETHUSD"), ("base", "ETH"), ] - .map(|(k, v)| (k.to_string(), v.to_string())), + .map(|(k, v)| (k.into(), v.into())), ), - price_accounts: vec![ + price_accounts: [ solana_sdk::pubkey::Pubkey::from_str( "GG3FTE7xhc9Diy7dn9P6BWzoCrAEE4D3p5NBYrDAm5DD", ) @@ -293,7 +295,8 @@ mod tests { "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ", ) .unwrap(), - ], + ] + .into(), }, ), ]), @@ -360,7 +363,7 @@ mod tests { // Check that the result is what we expected let expected = vec![ ProductAccountMetadata { - account: "BjHoZWRxo9dgbR1NQhPyTiUs6xFiX6mGS4TMYvy3b2yc".to_string(), + account: "BjHoZWRxo9dgbR1NQhPyTiUs6xFiX6mGS4TMYvy3b2yc".into(), attr_dict: BTreeMap::from( [ ("symbol", "Crypto.ETH/USD"), @@ -370,28 +373,29 @@ mod tests { ("generic_symbol", "ETHUSD"), ("base", "ETH"), ] - .map(|(k, v)| (k.to_string(), v.to_string())), + .map(|(k, v)| (k.into(), v.into())), ), - price: vec![ + price: [ PriceAccountMetadata { - account: "GG3FTE7xhc9Diy7dn9P6BWzoCrAEE4D3p5NBYrDAm5DD".to_string(), - price_type: "price".to_string(), + account: "GG3FTE7xhc9Diy7dn9P6BWzoCrAEE4D3p5NBYrDAm5DD".into(), + price_type: "price".into(), price_exponent: -9, }, PriceAccountMetadata { - account: "fTNjSfj5uW9e4CAMHzUcm65ftRNBxCN1gG5GS1mYfid".to_string(), - price_type: "price".to_string(), + account: "fTNjSfj5uW9e4CAMHzUcm65ftRNBxCN1gG5GS1mYfid".into(), + price_type: "price".into(), price_exponent: -6, }, PriceAccountMetadata { - account: "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ".to_string(), - price_type: "price".to_string(), + account: "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ".into(), + price_type: "price".into(), price_exponent: 2, }, - ], + ] + .into(), }, ProductAccountMetadata { - account: "CkMrDWtmFJZcmAUC11qNaWymbXQKvnRx4cq1QudLav7t".to_string(), + account: "CkMrDWtmFJZcmAUC11qNaWymbXQKvnRx4cq1QudLav7t".into(), attr_dict: BTreeMap::from( [ ("symbol", "Crypto.LTC/USD"), @@ -401,25 +405,26 @@ mod tests { ("generic_symbol", "LTCUSD"), ("base", "LTC"), ] - .map(|(k, v)| (k.to_string(), v.to_string())), + .map(|(k, v)| (k.into(), v.into())), ), - price: vec![ + price: [ PriceAccountMetadata { - account: "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU".to_string(), - price_type: "price".to_string(), + account: "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU".into(), + price_type: "price".into(), price_exponent: -8, }, PriceAccountMetadata { - account: "3VQwtcntVQN1mj1MybQw8qK7Li3KNrrgNskSQwZAPGNr".to_string(), - price_type: "price".to_string(), + account: "3VQwtcntVQN1mj1MybQw8qK7Li3KNrrgNskSQwZAPGNr".into(), + price_type: "price".into(), price_exponent: -10, }, PriceAccountMetadata { - account: "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6".to_string(), - price_type: "price".to_string(), + account: "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6".into(), + price_type: "price".into(), price_exponent: -6, }, - ], + ] + .into(), }, ]; @@ -482,7 +487,7 @@ mod tests { }, schedule: Default::default(), publish_interval: None, - price_accounts: vec![ + price_accounts: [ solana_sdk::pubkey::Pubkey::from_str( "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU", ) @@ -495,8 +500,10 @@ mod tests { "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6", ) .unwrap(), - ], - }, + ] + .into(), + } + .into(), ), ( solana_sdk::pubkey::Pubkey::from_str( @@ -543,7 +550,7 @@ mod tests { }, schedule: Default::default(), publish_interval: None, - price_accounts: vec![ + price_accounts: [ solana_sdk::pubkey::Pubkey::from_str( "GG3FTE7xhc9Diy7dn9P6BWzoCrAEE4D3p5NBYrDAm5DD", ) @@ -556,8 +563,10 @@ mod tests { "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ", ) .unwrap(), - ], - }, + ] + .into(), + } + .into(), ), ]), price_accounts: HashMap::from([ @@ -566,7 +575,7 @@ mod tests { "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU", ) .unwrap(), - SolanaPriceAccount { + Arc::new(PriceEntry::from(SolanaPriceAccount { magic: 0xa1b2c3d4, ver: 7, atype: 9, @@ -613,15 +622,14 @@ mod tests { }, comp: [PriceComp::default(); 32], extended: (), - } - .into(), + })), ), ( solana_sdk::pubkey::Pubkey::from_str( "3VQwtcntVQN1mj1MybQw8qK7Li3KNrrgNskSQwZAPGNr", ) .unwrap(), - SolanaPriceAccount { + Arc::new(PriceEntry::from(SolanaPriceAccount { magic: 0xa1b2c3d4, ver: 6, atype: 4, @@ -687,15 +695,14 @@ mod tests { }, }]), extended: (), - } - .into(), + })), ), ( solana_sdk::pubkey::Pubkey::from_str( "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6", ) .unwrap(), - SolanaPriceAccount { + Arc::new(PriceEntry::from(SolanaPriceAccount { magic: 0xa1b2c3d4, ver: 7, atype: 6, @@ -783,15 +790,14 @@ mod tests { }, ]), extended: (), - } - .into(), + })), ), ( solana_sdk::pubkey::Pubkey::from_str( "GG3FTE7xhc9Diy7dn9P6BWzoCrAEE4D3p5NBYrDAm5DD", ) .unwrap(), - SolanaPriceAccount { + Arc::new(PriceEntry::from(SolanaPriceAccount { magic: 0xa1b2c3d4, ver: 6, atype: 6, @@ -876,15 +882,14 @@ mod tests { }, ]), extended: (), - } - .into(), + })), ), ( solana_sdk::pubkey::Pubkey::from_str( "fTNjSfj5uW9e4CAMHzUcm65ftRNBxCN1gG5GS1mYfid", ) .unwrap(), - SolanaPriceAccount { + Arc::new(PriceEntry::from(SolanaPriceAccount { magic: 0xa1b2c3d4, ver: 8, atype: 4, @@ -972,15 +977,14 @@ mod tests { }, ]), extended: (), - } - .into(), + })), ), ( solana_sdk::pubkey::Pubkey::from_str( "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ", ) .unwrap(), - SolanaPriceAccount { + Arc::new(PriceEntry::from(SolanaPriceAccount { magic: 0xa1b2c3d4, ver: 6, atype: 3, @@ -1043,8 +1047,7 @@ mod tests { }, }]), extended: (), - } - .into(), + })), ), ]), } @@ -1066,7 +1069,7 @@ mod tests { // Check that the result of the conversion to the Pythd API format is what we expected let expected = vec![ pyth::ProductAccount { - account: "BjHoZWRxo9dgbR1NQhPyTiUs6xFiX6mGS4TMYvy3b2yc".to_string(), + account: "BjHoZWRxo9dgbR1NQhPyTiUs6xFiX6mGS4TMYvy3b2yc".into(), attr_dict: BTreeMap::from( [ ("symbol", "Crypto.ETH/USD"), @@ -1076,15 +1079,14 @@ mod tests { ("generic_symbol", "ETHUSD"), ("base", "ETH"), ] - .map(|(k, v)| (k.to_string(), v.to_string())), + .map(|(k, v)| (k.into(), v.into())), ), - price_accounts: vec![ + price_accounts: [ pyth::PriceAccount { - account: "GG3FTE7xhc9Diy7dn9P6BWzoCrAEE4D3p5NBYrDAm5DD" - .to_string(), - price_type: "price".to_string(), + account: "GG3FTE7xhc9Diy7dn9P6BWzoCrAEE4D3p5NBYrDAm5DD".into(), + price_type: "price".into(), price_exponent: -9, - status: "trading".to_string(), + status: "trading".into(), price: 876384, conf: 1349364, twap: 863947389, @@ -1094,29 +1096,29 @@ mod tests { prev_slot: 791279274, prev_price: 98272648, prev_conf: 124986284, - publisher_accounts: vec![ + publisher_accounts: [ PublisherAccount { - account: "F42dQ3SMssashRsA4SRfwJxFkGKV1bE3TcmpkagX8vvX".to_string(), - status: "trading".to_string(), + account: "F42dQ3SMssashRsA4SRfwJxFkGKV1bE3TcmpkagX8vvX".into(), + status: "trading".into(), price: 54842, conf: 599755, slot: 1976465, }, PublisherAccount { - account: "AmmvowPnL2z1CVGR2fQNjgAmmJvRfpCKqpQMpTg9QsoG".to_string(), - status: "unknown".to_string(), + account: "AmmvowPnL2z1CVGR2fQNjgAmmJvRfpCKqpQMpTg9QsoG".into(), + status: "unknown".into(), price: 65649, conf: 55896, slot: 32976, }, - ], + ] + .into(), }, pyth::PriceAccount { - account: "fTNjSfj5uW9e4CAMHzUcm65ftRNBxCN1gG5GS1mYfid" - .to_string(), - price_type: "price".to_string(), + account: "fTNjSfj5uW9e4CAMHzUcm65ftRNBxCN1gG5GS1mYfid".into(), + price_type: "price".into(), price_exponent: -6, - status: "trading".to_string(), + status: "trading".into(), price: 397492, conf: 33487, twap: 46280183, @@ -1126,29 +1128,29 @@ mod tests { prev_slot: 893734828, prev_price: 13947294, prev_conf: 349274938, - publisher_accounts: vec![ + publisher_accounts: [ PublisherAccount { - account: "8MMroLyuyxyeDRrzMNfpymC5RvmHtQiYooXX9bgeUJdM".to_string(), - status: "unknown".to_string(), + account: "8MMroLyuyxyeDRrzMNfpymC5RvmHtQiYooXX9bgeUJdM".into(), + status: "unknown".into(), price: 69854, conf: 732565, slot: 213654, }, PublisherAccount { - account: "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ".to_string(), - status: "trading".to_string(), + account: "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ".into(), + status: "trading".into(), price: 3265, conf: 8962196, slot: 301541, }, - ], + ] + .into(), }, pyth::PriceAccount { - account: "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ" - .to_string(), - price_type: "price".to_string(), + account: "GKNcUmNacSJo4S2Kq3DuYRYRGw3sNUfJ4tyqd198t6vQ".into(), + price_type: "price".into(), price_exponent: 2, - status: "trading".to_string(), + status: "trading".into(), price: 836489, conf: 6769467, twap: 876979749, @@ -1158,18 +1160,20 @@ mod tests { prev_slot: 8878456286, prev_price: 24746384, prev_conf: 6373957, - publisher_accounts: vec![PublisherAccount { - account: "33B2brfdz16kizEXeQvYzJXHiS1X95L8pfetuyntEiXg".to_string(), - status: "trading".to_string(), + publisher_accounts: [PublisherAccount { + account: "33B2brfdz16kizEXeQvYzJXHiS1X95L8pfetuyntEiXg".into(), + status: "trading".into(), price: 61478, conf: 312545, slot: 302156, - }], + }] + .into(), }, - ], + ] + .into(), }, pyth::ProductAccount { - account: "CkMrDWtmFJZcmAUC11qNaWymbXQKvnRx4cq1QudLav7t".to_string(), + account: "CkMrDWtmFJZcmAUC11qNaWymbXQKvnRx4cq1QudLav7t".into(), attr_dict: BTreeMap::from( [ ("symbol", "Crypto.LTC/USD"), @@ -1179,15 +1183,14 @@ mod tests { ("generic_symbol", "LTCUSD"), ("base", "LTC"), ] - .map(|(k, v)| (k.to_string(), v.to_string())), + .map(|(k, v)| (k.into(), v.into())), ), - price_accounts: vec![ + price_accounts: [ pyth::PriceAccount { - account: "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU" - .to_string(), - price_type: "price".to_string(), + account: "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU".into(), + price_type: "price".into(), price_exponent: -8, - status: "unknown".to_string(), + status: "unknown".into(), price: 736382, conf: 85623946, twap: 5882210200, @@ -1197,14 +1200,13 @@ mod tests { prev_slot: 172761778, prev_price: 22691000, prev_conf: 398674, - publisher_accounts: vec![], + publisher_accounts: [].into(), }, pyth::PriceAccount { - account: "3VQwtcntVQN1mj1MybQw8qK7Li3KNrrgNskSQwZAPGNr" - .to_string(), - price_type: "price".to_string(), + account: "3VQwtcntVQN1mj1MybQw8qK7Li3KNrrgNskSQwZAPGNr".into(), + price_type: "price".into(), price_exponent: -10, - status: "unknown".to_string(), + status: "unknown".into(), price: 8474837, conf: 27468478, twap: 84739769, @@ -1214,20 +1216,20 @@ mod tests { prev_slot: 1727612348, prev_price: 746383678, prev_conf: 757368, - publisher_accounts: vec![PublisherAccount { - account: "C9syZ2MoGUwbPyGEgiy8MxesaEEKLdJw8gnwx2jLK1cV".to_string(), - status: "trading".to_string(), + publisher_accounts: [PublisherAccount { + account: "C9syZ2MoGUwbPyGEgiy8MxesaEEKLdJw8gnwx2jLK1cV".into(), + status: "trading".into(), price: 85698, conf: 23645, slot: 14765, - }], + }] + .into(), }, pyth::PriceAccount { - account: "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6" - .to_string(), - price_type: "price".to_string(), + account: "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6".into(), + price_type: "price".into(), price_exponent: -6, - status: "trading".to_string(), + status: "trading".into(), price: 8254826, conf: 6385638, twap: 12895763, @@ -1237,24 +1239,26 @@ mod tests { prev_slot: 86484638, prev_price: 28463947, prev_conf: 83628234, - publisher_accounts: vec![ + publisher_accounts: [ PublisherAccount { - account: "DaMuPaW5dhGfRJaX7TzLWXd8hDCMJ5WA2XibJ12hjBNQ".to_string(), - status: "trading".to_string(), + account: "DaMuPaW5dhGfRJaX7TzLWXd8hDCMJ5WA2XibJ12hjBNQ".into(), + status: "trading".into(), price: 8251, conf: 7653, slot: 365545, }, PublisherAccount { - account: "FHuAg9vpDGeyhZn4W4FRcCzx6MC18r4bF9fTVJqeMijU".to_string(), - status: "unknown".to_string(), + account: "FHuAg9vpDGeyhZn4W4FRcCzx6MC18r4bF9fTVJqeMijU".into(), + status: "unknown".into(), price: 39865, conf: 7456, slot: 865, }, - ], + ] + .into(), }, - ], + ] + .into(), }, ]; @@ -1282,13 +1286,13 @@ mod tests { // Check that the result of the conversion to the Pythd API format is what we expected let expected = ProductAccount { - account: account.to_string(), - price_accounts: vec![ + account: account.to_smolstr(), + price_accounts: [ pyth::PriceAccount { - account: "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU".to_string(), - price_type: "price".to_string(), + account: "GVXRSBjFk6e6J3NbVPXohDJetcTjaeeuykUpbQF8UoMU".into(), + price_type: "price".into(), price_exponent: -8, - status: "unknown".to_string(), + status: "unknown".into(), price: 736382, conf: 85623946, twap: 5882210200, @@ -1298,13 +1302,13 @@ mod tests { prev_slot: 172761778, prev_price: 22691000, prev_conf: 398674, - publisher_accounts: vec![], + publisher_accounts: [].into(), }, pyth::PriceAccount { - account: "3VQwtcntVQN1mj1MybQw8qK7Li3KNrrgNskSQwZAPGNr".to_string(), - price_type: "price".to_string(), + account: "3VQwtcntVQN1mj1MybQw8qK7Li3KNrrgNskSQwZAPGNr".into(), + price_type: "price".into(), price_exponent: -10, - status: "unknown".to_string(), + status: "unknown".into(), price: 8474837, conf: 27468478, twap: 84739769, @@ -1314,19 +1318,20 @@ mod tests { prev_slot: 1727612348, prev_price: 746383678, prev_conf: 757368, - publisher_accounts: vec![PublisherAccount { - account: "C9syZ2MoGUwbPyGEgiy8MxesaEEKLdJw8gnwx2jLK1cV".to_string(), - status: "trading".to_string(), + publisher_accounts: [PublisherAccount { + account: "C9syZ2MoGUwbPyGEgiy8MxesaEEKLdJw8gnwx2jLK1cV".into(), + status: "trading".into(), price: 85698, conf: 23645, slot: 14765, - }], + }] + .into(), }, pyth::PriceAccount { - account: "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6".to_string(), - price_type: "price".to_string(), + account: "2V7t5NaKY7aGkwytCWQgvUYZfEr9XMwNChhJEakTExk6".into(), + price_type: "price".into(), price_exponent: -6, - status: "trading".to_string(), + status: "trading".into(), price: 8254826, conf: 6385638, twap: 12895763, @@ -1336,24 +1341,26 @@ mod tests { prev_slot: 86484638, prev_price: 28463947, prev_conf: 83628234, - publisher_accounts: vec![ + publisher_accounts: [ PublisherAccount { - account: "DaMuPaW5dhGfRJaX7TzLWXd8hDCMJ5WA2XibJ12hjBNQ".to_string(), - status: "trading".to_string(), + account: "DaMuPaW5dhGfRJaX7TzLWXd8hDCMJ5WA2XibJ12hjBNQ".into(), + status: "trading".into(), price: 8251, conf: 7653, slot: 365545, }, PublisherAccount { - account: "FHuAg9vpDGeyhZn4W4FRcCzx6MC18r4bF9fTVJqeMijU".to_string(), - status: "unknown".to_string(), + account: "FHuAg9vpDGeyhZn4W4FRcCzx6MC18r4bF9fTVJqeMijU".into(), + status: "unknown".into(), price: 39865, conf: 7456, slot: 865, }, - ], + ] + .into(), }, - ], + ] + .into(), attr_dict: BTreeMap::from( [ ("symbol", "Crypto.LTC/USD"), @@ -1363,7 +1370,7 @@ mod tests { ("generic_symbol", "LTCUSD"), ("base", "LTC"), ] - .map(|(k, v)| (k.to_string(), v.to_string())), + .map(|(k, v)| (k.into(), v.into())), ), }; @@ -1382,9 +1389,9 @@ mod tests { .unwrap(); let price = 2365; let conf = 98754; - let _ = state + state .state - .update_local_price(&account, price, conf, "trading".to_string()) + .update_local_price(&account, price, conf, "trading".into()) .await .unwrap(); @@ -1464,7 +1471,7 @@ mod tests { } .into(); - let _ = state + state .state .update_global_price( Network::Primary, @@ -1485,7 +1492,7 @@ mod tests { result: PriceUpdate { price: test_price.agg.price, conf: test_price.agg.conf, - status: "trading".to_string(), + status: "trading".into(), valid_slot: test_price.valid_slot, pub_slot: test_price.agg.pub_slot, }, diff --git a/src/agent/state/api.rs b/src/agent/state/api.rs index dc92f5d..12ac73b 100644 --- a/src/agent/state/api.rs +++ b/src/agent/state/api.rs @@ -44,6 +44,10 @@ use { PriceComp, PriceStatus, }, + smol_str::{ + SmolStr, + ToSmolStr, + }, std::{ collections::HashMap, sync::atomic::AtomicI64, @@ -57,7 +61,7 @@ use { }; // TODO: implement Display on PriceStatus and then just call PriceStatus::to_string -fn price_status_to_str(price_status: PriceStatus) -> String { +fn price_status_to_str(price_status: PriceStatus) -> SmolStr { match price_status { PriceStatus::Unknown => "unknown", PriceStatus::Trading => "trading", @@ -65,7 +69,7 @@ fn price_status_to_str(price_status: PriceStatus) -> String { PriceStatus::Auction => "auction", PriceStatus::Ignored => "ignored", } - .to_string() + .into() } fn solana_product_account_to_pythd_api_product_account( @@ -90,12 +94,12 @@ fn solana_product_account_to_pythd_api_product_account( // Create the product account metadata struct ProductAccount { - account: product_account_key.to_string(), + account: product_account_key.to_smolstr(), attr_dict: product_account .account_data .iter() .filter(|(key, val)| !key.is_empty() && !val.is_empty()) - .map(|(key, val)| (key.to_owned(), val.to_owned())) + .map(|(key, val)| (key.into(), val.into())) .collect(), price_accounts, } @@ -106,8 +110,8 @@ fn solana_price_account_to_pythd_api_price_account( price_account: &PriceEntry, ) -> PriceAccount { PriceAccount { - account: price_account_key.to_string(), - price_type: "price".to_string(), + account: price_account_key.to_smolstr(), + price_type: "price".into(), price_exponent: price_account.expo as i64, status: price_status_to_str(price_account.agg.status), price: price_account.agg.price, @@ -124,7 +128,7 @@ fn solana_price_account_to_pythd_api_price_account( .iter() .filter(|comp| *comp != &PriceComp::default()) .map(|comp| PublisherAccount { - account: comp.publisher.to_string(), + account: comp.publisher.to_smolstr(), status: price_status_to_str(comp.agg.status), price: comp.agg.price, conf: comp.agg.conf, @@ -222,15 +226,15 @@ where .map(|acc| (price_account_key, acc)) }) .map(|(price_account_key, price_account)| PriceAccountMetadata { - account: price_account_key.to_string(), - price_type: "price".to_owned(), + account: price_account_key.to_smolstr(), + price_type: "price".into(), price_exponent: price_account.expo as i64, }) .collect(); // Create the product account metadata struct result.push(ProductAccountMetadata { - account: product_account_key.to_string(), + account: product_account_key.to_smolstr(), attr_dict: product_account.attr_dict, price: price_accounts_metadata, }) diff --git a/src/agent/state/exporter.rs b/src/agent/state/exporter.rs index 151a6f2..269b6ac 100644 --- a/src/agent/state/exporter.rs +++ b/src/agent/state/exporter.rs @@ -215,7 +215,7 @@ where } }) .filter_map(|(feed_id, info)| { - let key_from_id = Pubkey::from(feed_id.clone().to_bytes()); + let key_from_id = Pubkey::from(feed_id.to_bytes()); if let Some(publisher_permission) = our_prices.get(&key_from_id) { let now_utc = Utc::now(); let can_publish = publisher_permission.schedule.can_publish_at(&now_utc); @@ -257,7 +257,7 @@ where } }; - let key_from_id = Pubkey::from((update.feed_id).clone().to_bytes()); + let key_from_id = Pubkey::from(update.feed_id.to_bytes()); let publisher_metadata = match our_prices.get(&key_from_id) { Some(metadata) => metadata, None => { @@ -515,7 +515,7 @@ where )); for update in batch { - batch_state.insert(update.feed_id, update.info.clone()); + batch_state.insert(update.feed_id, update.info); } } @@ -579,11 +579,10 @@ where let local_store_contents = LocalStore::get_all_price_infos(&*state).await; for update in batch { let mut update = update.clone(); - update.info = local_store_contents + update.info = *local_store_contents .get(&update.feed_id) .ok_or_else(|| anyhow!("price identifier not found in local store")) - .with_context(|| update.feed_id.to_string())? - .clone(); + .with_context(|| update.feed_id.to_string())?; let stale_price = now > update.info.timestamp + staleness_threshold; if stale_price { diff --git a/src/agent/state/global.rs b/src/agent/state/global.rs index f703457..ff9d2cf 100644 --- a/src/agent/state/global.rs +++ b/src/agent/state/global.rs @@ -21,11 +21,15 @@ use { Result, }, prometheus_client::registry::Registry, + smol_str::SmolStr, solana_sdk::pubkey::Pubkey, - std::collections::{ - BTreeMap, - HashMap, - HashSet, + std::{ + collections::{ + BTreeMap, + HashMap, + HashSet, + }, + sync::Arc, }, tokio::sync::RwLock, }; @@ -34,8 +38,8 @@ use { /// from the primary network. #[derive(Debug, Clone, Default)] pub struct AllAccountsData { - pub product_accounts: HashMap, - pub price_accounts: HashMap, + pub product_accounts: HashMap>, + pub price_accounts: HashMap>, } /// AllAccountsMetadata contains the metadata for all the price and product accounts. @@ -51,20 +55,20 @@ pub struct AllAccountsMetadata { #[derive(Debug, Clone, Default)] pub struct ProductAccountMetadata { /// Attribute dictionary - pub attr_dict: BTreeMap, + pub attr_dict: BTreeMap, /// Price accounts associated with this product pub price_accounts: Vec, } -impl From for ProductAccountMetadata { - fn from(product_account: ProductEntry) -> Self { +impl From<&ProductEntry> for ProductAccountMetadata { + fn from(product_account: &ProductEntry) -> Self { ProductAccountMetadata { attr_dict: product_account .account_data .iter() - .map(|(key, val)| (key.to_owned(), val.to_owned())) + .map(|(key, val)| (key.into(), val.into())) .collect(), - price_accounts: product_account.price_accounts, + price_accounts: product_account.price_accounts.clone(), } } } @@ -76,8 +80,8 @@ pub struct PriceAccountMetadata { pub expo: i32, } -impl From for PriceAccountMetadata { - fn from(price_account: PriceEntry) -> Self { +impl From<&PriceEntry> for PriceAccountMetadata { + fn from(price_account: &PriceEntry) -> Self { PriceAccountMetadata { expo: price_account.expo, } @@ -88,11 +92,11 @@ impl From for PriceAccountMetadata { pub enum Update { ProductAccountUpdate { account_key: Pubkey, - account: ProductEntry, + account: Arc, }, PriceAccountUpdate { account_key: Pubkey, - account: PriceEntry, + account: Arc, }, } @@ -153,7 +157,7 @@ pub trait GlobalStore { &self, network: Network, price_ids: HashSet, - ) -> Result>; + ) -> Result>>; } // Allow downcasting State into GlobalStore for functions that depend on the `GlobalStore` service. @@ -190,7 +194,7 @@ where &self, network: Network, price_ids: HashSet, - ) -> Result> { + ) -> Result>> { let account_data = match network { Network::Primary => &self.into().account_data_primary, Network::Secondary => &self.into().account_data_secondary, @@ -229,7 +233,7 @@ where account_key, account, } => { - let attr_dict = ProductAccountMetadata::from(account.clone()).attr_dict; + let attr_dict = ProductAccountMetadata::from(account.as_ref()).attr_dict; let maybe_symbol = attr_dict.get("symbol").cloned(); store.product_metrics.update(account_key, maybe_symbol); @@ -269,7 +273,7 @@ where .write() .await .price_accounts - .insert(*account_key, *account); + .insert(*account_key, account.clone()); } } @@ -292,7 +296,7 @@ where .write() .await .product_accounts_metadata - .insert(*account_key, account.clone().into()); + .insert(*account_key, account.as_ref().into()); Ok(()) } @@ -305,7 +309,7 @@ where .write() .await .price_accounts_metadata - .insert(*account_key, (*account).into()); + .insert(*account_key, account.as_ref().into()); Ok(()) } diff --git a/src/agent/state/local.rs b/src/agent/state/local.rs index a8d9a14..f1758fc 100644 --- a/src/agent/state/local.rs +++ b/src/agent/state/local.rs @@ -16,7 +16,7 @@ use { tokio::sync::RwLock, }; -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub struct PriceInfo { pub status: PriceStatus, pub price: i64, diff --git a/src/agent/state/oracle.rs b/src/agent/state/oracle.rs index 5d6b02a..761280d 100644 --- a/src/agent/state/oracle.rs +++ b/src/agent/state/oracle.rs @@ -43,13 +43,14 @@ use { HashMap, HashSet, }, + sync::Arc, time::Duration, }, tokio::sync::RwLock, tracing::instrument, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct ProductEntry { pub account_data: pyth_sdk_solana::state::ProductAccount, pub schedule: MarketSchedule, @@ -128,10 +129,10 @@ impl std::ops::Deref for PriceEntry { } } -#[derive(Default, Debug, Clone)] +#[derive(Default, Debug)] pub struct Data { - pub product_accounts: HashMap, - pub price_accounts: HashMap, + pub product_accounts: HashMap>, + pub price_accounts: HashMap>, /// publisher => {their permissioned price accounts => price publishing metadata} pub publisher_permissions: HashMap>, pub publisher_buffer_key: Option, @@ -173,18 +174,11 @@ impl Default for Config { } } +#[derive(Default)] pub struct OracleState { data: RwLock, } -impl OracleState { - pub fn new() -> Self { - Self { - data: Default::default(), - } - } -} - #[async_trait::async_trait] pub trait Oracle { async fn sync_global_store(&self, network: Network) -> Result<()>; @@ -246,14 +240,14 @@ where "Observed on-chain price account update.", ); - data.price_accounts.insert(*account_key, price_entry); + data.price_accounts.insert(*account_key, price_entry.into()); Prices::update_global_price( self, network, &Update::PriceAccountUpdate { account_key: *account_key, - account: price_entry, + account: Arc::new(price_entry), }, ) .await?; @@ -376,7 +370,7 @@ where network, &Update::PriceAccountUpdate { account_key: *price_account_key, - account: *price_account, + account: price_account.clone(), }, ) .await @@ -403,12 +397,17 @@ async fn fetch_publisher_buffer_key( Ok(config.buffer_account.into()) } +type ProductAndPriceAccounts = ( + HashMap>, + HashMap>, +); + #[instrument(skip(rpc_client))] async fn fetch_product_and_price_accounts( rpc_client: &RpcClient, oracle_program_key: Pubkey, max_lookup_batch_size: usize, -) -> Result<(HashMap, HashMap)> { +) -> Result { let mut product_entries = HashMap::new(); let mut price_entries = HashMap::new(); @@ -485,7 +484,7 @@ async fn fetch_product_and_price_accounts( ProductEntry { account_data: *product, schedule: market_schedule.unwrap_or_else(|| legacy_schedule.into()), - price_accounts: vec![], + price_accounts: [].into(), publish_interval, }, ); @@ -509,7 +508,16 @@ async fn fetch_product_and_price_accounts( } } - Ok((product_entries, price_entries)) + Ok(( + product_entries + .into_iter() + .map(|(x, y)| (x, Arc::new(y))) + .collect(), + price_entries + .into_iter() + .map(|(x, y)| (x, Arc::new(y))) + .collect(), + )) } #[instrument(skip(rpc_client, product_key_batch))]