From 0abcc49626d1bdbb5002636f3c661f12b90b7c0e Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 3 Oct 2023 12:41:37 +0400 Subject: [PATCH 1/8] geyser::proto, rename convert to convert_to --- yellowstone-grpc-geyser/src/grpc.rs | 20 ++++++++++++-------- yellowstone-grpc-geyser/src/proto.rs | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/yellowstone-grpc-geyser/src/grpc.rs b/yellowstone-grpc-geyser/src/grpc.rs index 97cf800a..bec77f31 100644 --- a/yellowstone-grpc-geyser/src/grpc.rs +++ b/yellowstone-grpc-geyser/src/grpc.rs @@ -155,8 +155,8 @@ impl MessageTransactionInfo { SubscribeUpdateTransactionInfo { signature: self.signature.as_ref().into(), is_vote: self.is_vote, - transaction: Some(proto::convert::create_transaction(&self.transaction)), - meta: Some(proto::convert::create_transaction_meta(&self.meta)), + transaction: Some(proto::convert_to::create_transaction(&self.transaction)), + meta: Some(proto::convert_to::create_transaction_meta(&self.meta)), index: self.index as u64, } } @@ -412,11 +412,13 @@ impl<'a> MessageRef<'a> { Self::Block(message) => UpdateOneof::Block(SubscribeUpdateBlock { slot: message.slot, blockhash: message.blockhash.clone(), - rewards: Some(proto::convert::create_rewards(message.rewards.as_slice())), - block_time: message.block_time.map(proto::convert::create_timestamp), + rewards: Some(proto::convert_to::create_rewards( + message.rewards.as_slice(), + )), + block_time: message.block_time.map(proto::convert_to::create_timestamp), block_height: message .block_height - .map(proto::convert::create_block_height), + .map(proto::convert_to::create_block_height), parent_slot: message.parent_slot, parent_blockhash: message.parent_blockhash.clone(), executed_transaction_count: message.executed_transaction_count, @@ -441,11 +443,13 @@ impl<'a> MessageRef<'a> { Self::BlockMeta(message) => UpdateOneof::BlockMeta(SubscribeUpdateBlockMeta { slot: message.slot, blockhash: message.blockhash.clone(), - rewards: Some(proto::convert::create_rewards(message.rewards.as_slice())), - block_time: message.block_time.map(proto::convert::create_timestamp), + rewards: Some(proto::convert_to::create_rewards( + message.rewards.as_slice(), + )), + block_time: message.block_time.map(proto::convert_to::create_timestamp), block_height: message .block_height - .map(proto::convert::create_block_height), + .map(proto::convert_to::create_block_height), parent_slot: message.parent_slot, parent_blockhash: message.parent_blockhash.clone(), executed_transaction_count: message.executed_transaction_count, diff --git a/yellowstone-grpc-geyser/src/proto.rs b/yellowstone-grpc-geyser/src/proto.rs index 07b2f68d..8ec69d22 100644 --- a/yellowstone-grpc-geyser/src/proto.rs +++ b/yellowstone-grpc-geyser/src/proto.rs @@ -1,6 +1,6 @@ pub use yellowstone_grpc_proto::prelude::*; -pub mod convert { +pub mod convert_to { use { solana_sdk::{ clock::UnixTimestamp, From 0eb70082adaea89c3af31ae06431cf0f5a86cf82 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 3 Oct 2023 13:05:27 +0400 Subject: [PATCH 2/8] geyser: add proto::convert_from --- Cargo.lock | 1 + yellowstone-grpc-geyser/Cargo.toml | 1 + yellowstone-grpc-geyser/src/proto.rs | 306 +++++++++++++++++++++++++++ 3 files changed, 308 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 064ed8a1..0855f40f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4517,6 +4517,7 @@ dependencies = [ "prometheus", "serde", "serde_json", + "solana-account-decoder", "solana-geyser-plugin-interface", "solana-logger", "solana-sdk", diff --git a/yellowstone-grpc-geyser/Cargo.toml b/yellowstone-grpc-geyser/Cargo.toml index 7e314588..b9c01c5c 100644 --- a/yellowstone-grpc-geyser/Cargo.toml +++ b/yellowstone-grpc-geyser/Cargo.toml @@ -25,6 +25,7 @@ log = "0.4.17" prometheus = "0.13.2" serde = { version = "1.0.145", features = ["derive"] } serde_json = "1.0.86" +solana-account-decoder = "=1.16.14" solana-geyser-plugin-interface = "=1.16.14" solana-logger = "=1.16.14" solana-sdk = "=1.16.14" diff --git a/yellowstone-grpc-geyser/src/proto.rs b/yellowstone-grpc-geyser/src/proto.rs index 8ec69d22..ff3fd897 100644 --- a/yellowstone-grpc-geyser/src/proto.rs +++ b/yellowstone-grpc-geyser/src/proto.rs @@ -239,3 +239,309 @@ pub mod convert_to { super::UnixTimestamp { timestamp } } } + +pub mod convert_from { + use { + solana_account_decoder::parse_token::UiTokenAmount, + solana_sdk::{ + hash::{Hash, HASH_BYTES}, + instruction::CompiledInstruction, + message::{ + v0::{LoadedAddresses, Message as MessageV0, MessageAddressTableLookup}, + Message, MessageHeader, VersionedMessage, + }, + pubkey::Pubkey, + signature::Signature, + transaction::{TransactionError, VersionedTransaction}, + transaction_context::TransactionReturnData, + }, + solana_transaction_status::{ + ConfirmedBlock, InnerInstruction, InnerInstructions, Reward, RewardType, + TransactionStatusMeta, TransactionTokenBalance, TransactionWithStatusMeta, + VersionedTransactionWithStatusMeta, + }, + }; + + fn ensure_some(maybe_value: Option, message: impl Into) -> Result { + match maybe_value { + Some(value) => Ok(value), + None => Err(message.into()), + } + } + + pub fn create_block(block: super::SubscribeUpdateBlock) -> Result { + let mut transactions = vec![]; + for tx in block.transactions { + transactions.push(create_tx_with_meta(tx)?); + } + + let mut rewards = vec![]; + for reward in ensure_some(block.rewards, "failed to get rewards")?.rewards { + rewards.push(create_reward(reward)?); + } + + Ok(ConfirmedBlock { + previous_blockhash: block.parent_blockhash, + blockhash: block.blockhash, + parent_slot: block.parent_slot, + transactions, + rewards, + block_time: Some(ensure_some( + block.block_time.map(|wrapper| wrapper.timestamp), + "failed to get block_time", + )?), + block_height: Some(ensure_some( + block.block_height.map(|wrapper| wrapper.block_height), + "failed to get block_height", + )?), + }) + } + + pub fn create_tx_with_meta( + tx: super::SubscribeUpdateTransactionInfo, + ) -> Result { + let meta = ensure_some(tx.meta, "failed to get transaction meta")?; + let tx = ensure_some(tx.transaction, "failed to get transaction transaction")?; + + Ok(TransactionWithStatusMeta::Complete( + VersionedTransactionWithStatusMeta { + transaction: create_tx_versioned(tx)?, + meta: create_tx_meta(meta)?, + }, + )) + } + + pub fn create_tx_versioned(tx: super::Transaction) -> Result { + let mut signatures = Vec::with_capacity(tx.signatures.len()); + for signature in tx.signatures { + signatures.push(match Signature::try_from(signature.as_slice()) { + Ok(signature) => signature, + Err(_error) => return Err("failed to parse Signature".to_owned()), + }); + } + + Ok(VersionedTransaction { + signatures, + message: create_message(ensure_some(tx.message, "failed to get message")?)?, + }) + } + + fn create_message(message: super::Message) -> Result { + let header = ensure_some(message.header, "failed to get MessageHeader")?; + let header = MessageHeader { + num_required_signatures: ensure_some( + header.num_required_signatures.try_into().ok(), + "failed to parse num_required_signatures", + )?, + num_readonly_signed_accounts: ensure_some( + header.num_readonly_signed_accounts.try_into().ok(), + "failed to parse num_readonly_signed_accounts", + )?, + num_readonly_unsigned_accounts: ensure_some( + header.num_readonly_unsigned_accounts.try_into().ok(), + "failed to parse num_readonly_unsigned_accounts", + )?, + }; + + if message.recent_blockhash.len() != HASH_BYTES { + return Err("failed to parse hash".to_owned()); + } + + let mut instructions = Vec::with_capacity(message.instructions.len()); + for ix in message.instructions { + instructions.push(CompiledInstruction { + program_id_index: ensure_some( + ix.program_id_index.try_into().ok(), + "failed to decode CompiledInstruction.program_id_index)", + )?, + accounts: ix.accounts, + data: ix.data, + }); + } + + Ok(if message.versioned { + let mut address_table_lookups = Vec::with_capacity(message.address_table_lookups.len()); + for table in message.address_table_lookups { + address_table_lookups.push(MessageAddressTableLookup { + account_key: ensure_some( + Pubkey::try_from(table.account_key.as_slice()).ok(), + "failed to parse Pubkey", + )?, + writable_indexes: table.writable_indexes, + readonly_indexes: table.readonly_indexes, + }); + } + + VersionedMessage::V0(MessageV0 { + header, + account_keys: create_pubkey_vec(message.account_keys)?, + recent_blockhash: Hash::new(message.recent_blockhash.as_slice()), + instructions, + address_table_lookups, + }) + } else { + VersionedMessage::Legacy(Message { + header, + account_keys: create_pubkey_vec(message.account_keys)?, + recent_blockhash: Hash::new(message.recent_blockhash.as_slice()), + instructions, + }) + }) + } + + pub fn create_tx_meta( + meta: super::TransactionStatusMeta, + ) -> Result { + let meta_status = match create_tx_error(meta.err.as_ref())? { + Some(err) => Err(err), + None => Ok(()), + }; + let mut meta_inner_instructions = vec![]; + for ix in meta.inner_instructions { + meta_inner_instructions.push(create_inner_instruction(ix)?); + } + let mut meta_rewards = vec![]; + for reward in meta.rewards { + meta_rewards.push(create_reward(reward)?); + } + + Ok(TransactionStatusMeta { + status: meta_status, + fee: meta.fee, + pre_balances: meta.pre_balances, + post_balances: meta.post_balances, + inner_instructions: Some(meta_inner_instructions), + log_messages: Some(meta.log_messages), + pre_token_balances: Some(create_token_balances(meta.pre_token_balances)?), + post_token_balances: Some(create_token_balances(meta.post_token_balances)?), + rewards: Some(meta_rewards), + loaded_addresses: create_loaded_addresses( + meta.loaded_writable_addresses, + meta.loaded_readonly_addresses, + )?, + return_data: if meta.return_data_none { + None + } else { + let data = ensure_some(meta.return_data, "failed to get return_data")?; + Some(TransactionReturnData { + program_id: ensure_some( + Pubkey::try_from(data.program_id.as_slice()).ok(), + "failed to parse program_id", + )?, + data: data.data, + }) + }, + compute_units_consumed: meta.compute_units_consumed, + }) + } + + pub fn create_tx_error( + err: Option<&super::TransactionError>, + ) -> Result, String> { + ensure_some( + err.map(|err| bincode::deserialize::(&err.err)) + .transpose() + .ok(), + "failed to decode TransactionError", + ) + } + + fn create_inner_instruction(ix: super::InnerInstructions) -> Result { + let mut instructions = vec![]; + for ix in ix.instructions { + instructions.push(InnerInstruction { + instruction: CompiledInstruction { + program_id_index: ensure_some( + ix.program_id_index.try_into().ok(), + "failed to decode CompiledInstruction.program_id_index)", + )?, + accounts: ix.accounts, + data: ix.data, + }, + stack_height: ix.stack_height, + }); + } + Ok(InnerInstructions { + index: ensure_some( + ix.index.try_into().ok(), + "failed to decode InnerInstructions.index", + )?, + instructions, + }) + } + + pub fn create_reward(reward: super::Reward) -> Result { + Ok(Reward { + pubkey: reward.pubkey, + lamports: reward.lamports, + post_balance: reward.post_balance, + reward_type: match ensure_some( + super::RewardType::from_i32(reward.reward_type), + "failed to parse reward_type", + )? { + super::RewardType::Unspecified => None, + super::RewardType::Fee => Some(RewardType::Fee), + super::RewardType::Rent => Some(RewardType::Rent), + super::RewardType::Staking => Some(RewardType::Staking), + super::RewardType::Voting => Some(RewardType::Voting), + }, + commission: if reward.commission.is_empty() { + None + } else { + Some(ensure_some( + reward.commission.parse().ok(), + "failed to parse reward commission", + )?) + }, + }) + } + + fn create_token_balances( + balances: Vec, + ) -> Result, String> { + let mut vec = Vec::with_capacity(balances.len()); + for balance in balances { + let ui_amount = ensure_some(balance.ui_token_amount, "failed to get ui_token_amount")?; + vec.push(TransactionTokenBalance { + account_index: ensure_some( + balance.account_index.try_into().ok(), + "failed to parse account_index", + )?, + mint: balance.mint, + ui_token_amount: UiTokenAmount { + ui_amount: Some(ui_amount.ui_amount), + decimals: ensure_some( + ui_amount.decimals.try_into().ok(), + "failed to parse decimals", + )?, + amount: ui_amount.amount, + ui_amount_string: ui_amount.ui_amount_string, + }, + owner: balance.owner, + program_id: balance.program_id, + }); + } + Ok(vec) + } + + fn create_loaded_addresses( + writable: Vec>, + readonly: Vec>, + ) -> Result { + Ok(LoadedAddresses { + writable: create_pubkey_vec(writable)?, + readonly: create_pubkey_vec(readonly)?, + }) + } + + fn create_pubkey_vec(pubkeys: Vec>) -> Result, String> { + let mut vec = Vec::with_capacity(pubkeys.len()); + for pubkey in pubkeys { + vec.push(ensure_some( + Pubkey::try_from(pubkey.as_slice()).ok(), + "failed to parse Pubkey", + )?) + } + Ok(vec) + } +} From a8a329c2afeb98b0aae9b54a743589d0f40c6f66 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 3 Oct 2023 13:25:30 +0400 Subject: [PATCH 3/8] client: add tx pretty print to rust --- CHANGELOG.md | 3 ++ Cargo.lock | 3 ++ examples/rust/Cargo.toml | 3 ++ examples/rust/src/bin/client.rs | 57 +++++++++++++++++++++++++++++++-- 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 568f8761..ac5c9c7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ The minor version will be incremented upon a breaking change and the patch versi ### Features +- client: add tx pretty print to rust ([#188](https://github.com/rpcpool/yellowstone-grpc/pull/188)). +- geyser: add mod `proto::convert_from` ([#188](https://github.com/rpcpool/yellowstone-grpc/pull/188)). + ### Fixes ### Breaking diff --git a/Cargo.lock b/Cargo.lock index 0855f40f..73593d17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4493,9 +4493,12 @@ dependencies = [ "hex", "log", "maplit", + "serde_json", "solana-sdk", + "solana-transaction-status", "tokio", "yellowstone-grpc-client", + "yellowstone-grpc-geyser", "yellowstone-grpc-proto", ] diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml index 3e6ec7e6..5d80e062 100644 --- a/examples/rust/Cargo.toml +++ b/examples/rust/Cargo.toml @@ -20,7 +20,10 @@ futures = "0.3.24" hex = "0.4.3" log = { version = "0.4.14", features = ["std"] } maplit = "1.0.2" +serde_json = "1.0.86" solana-sdk = "=1.16.14" +solana-transaction-status = "=1.16.14" tokio = { version = "1.21.2", features = ["rt-multi-thread", "macros", "time"] } yellowstone-grpc-client = { path = "../../yellowstone-grpc-client" } +yellowstone-grpc-geyser = { path = "../../yellowstone-grpc-geyser" } yellowstone-grpc-proto = { path = "../../yellowstone-grpc-proto" } diff --git a/examples/rust/src/bin/client.rs b/examples/rust/src/bin/client.rs index 109b2fcd..ec024f32 100644 --- a/examples/rust/src/bin/client.rs +++ b/examples/rust/src/bin/client.rs @@ -3,10 +3,11 @@ use { clap::{Parser, Subcommand, ValueEnum}, futures::{future::TryFutureExt, sink::SinkExt, stream::StreamExt}, log::{error, info}, - solana_sdk::pubkey::Pubkey, + solana_sdk::{pubkey::Pubkey, signature::Signature}, + solana_transaction_status::{EncodedTransactionWithStatusMeta, UiTransactionEncoding}, std::{ collections::HashMap, - env, + env, fmt, sync::{Arc, Mutex}, time::Duration, }, @@ -20,7 +21,7 @@ use { SubscribeRequestFilterAccountsFilter, SubscribeRequestFilterAccountsFilterMemcmp, SubscribeRequestFilterBlocks, SubscribeRequestFilterBlocksMeta, SubscribeRequestFilterEntry, SubscribeRequestFilterSlots, - SubscribeRequestFilterTransactions, SubscribeUpdateAccount, + SubscribeRequestFilterTransactions, SubscribeUpdateAccount, SubscribeUpdateTransaction, }, tonic::service::Interceptor, }, @@ -353,6 +354,48 @@ impl From for AccountPretty { } } +#[allow(dead_code)] +pub struct TransactionPretty { + slot: u64, + signature: Signature, + is_vote: bool, + tx: EncodedTransactionWithStatusMeta, +} + +impl fmt::Debug for TransactionPretty { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + struct TxWrap<'a>(&'a EncodedTransactionWithStatusMeta); + impl<'a> fmt::Debug for TxWrap<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let serialized = serde_json::to_string(self.0).expect("failed to serialize"); + fmt::Display::fmt(&serialized, f) + } + } + + f.debug_struct("TransactionPretty") + .field("slot", &self.slot) + .field("signature", &self.signature) + .field("is_vote", &self.is_vote) + .field("tx", &TxWrap(&self.tx)) + .finish() + } +} + +impl From for TransactionPretty { + fn from(SubscribeUpdateTransaction { transaction, slot }: SubscribeUpdateTransaction) -> Self { + let tx = transaction.expect("should be defined"); + Self { + slot, + signature: Signature::try_from(tx.signature.as_slice()).expect("valid signature"), + is_vote: tx.is_vote, + tx: yellowstone_grpc_geyser::proto::convert_from::create_tx_with_meta(tx) + .expect("valid tx with meta") + .encode(UiTransactionEncoding::Base64, Some(u8::MAX), true) + .expect("failed to encode"), + } + } +} + #[tokio::main] async fn main() -> anyhow::Result<()> { env::set_var( @@ -485,6 +528,14 @@ async fn geyser_subscribe( ); continue; } + Some(UpdateOneof::Transaction(tx)) => { + let tx: TransactionPretty = tx.into(); + info!( + "new transaction update: filters {:?}, transaction: {:#?}", + msg.filters, tx + ); + continue; + } _ => {} } info!("new message: {msg:?}") From 52eb8c059654a32f95e4d6e4c08325caf8d4ead3 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 3 Oct 2023 13:34:27 +0400 Subject: [PATCH 4/8] backward compt --- yellowstone-grpc-geyser/src/proto.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/yellowstone-grpc-geyser/src/proto.rs b/yellowstone-grpc-geyser/src/proto.rs index ff3fd897..39fbb4d4 100644 --- a/yellowstone-grpc-geyser/src/proto.rs +++ b/yellowstone-grpc-geyser/src/proto.rs @@ -1,5 +1,10 @@ pub use yellowstone_grpc_proto::prelude::*; +#[deprecated(note = "Please use `convert_to`")] +pub mod convert { + pub use super::convert_to::*; +} + pub mod convert_to { use { solana_sdk::{ From 863117adaacdee6bae0f408d3a30291c2966a5a8 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 3 Oct 2023 13:35:26 +0400 Subject: [PATCH 5/8] fix changelog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac5c9c7a..236777b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,8 @@ The minor version will be incremented upon a breaking change and the patch versi ### Features -- client: add tx pretty print to rust ([#188](https://github.com/rpcpool/yellowstone-grpc/pull/188)). -- geyser: add mod `proto::convert_from` ([#188](https://github.com/rpcpool/yellowstone-grpc/pull/188)). +- client: add tx pretty print to rust ([#189](https://github.com/rpcpool/yellowstone-grpc/pull/189)). +- geyser: add mod `proto::convert_to`, `proto::convert_from` ([#189](https://github.com/rpcpool/yellowstone-grpc/pull/189)). ### Fixes From bb1ef5e5a92c765b02a3f9ec27f1430b53a359e6 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 3 Oct 2023 16:44:59 +0400 Subject: [PATCH 6/8] move to proto --- CHANGELOG.md | 2 +- Cargo.lock | 14 +- Cargo.toml | 8 +- examples/rust/Cargo.toml | 3 +- examples/rust/src/bin/client.rs | 2 +- yellowstone-grpc-client/Cargo.toml | 4 +- yellowstone-grpc-geyser/Cargo.toml | 3 +- yellowstone-grpc-geyser/src/filters.rs | 18 +- yellowstone-grpc-geyser/src/grpc.rs | 50 +-- yellowstone-grpc-geyser/src/lib.rs | 1 - yellowstone-grpc-geyser/src/proto.rs | 552 ------------------------- yellowstone-grpc-proto/Cargo.toml | 6 +- yellowstone-grpc-proto/src/lib.rs | 548 ++++++++++++++++++++++++ 13 files changed, 602 insertions(+), 609 deletions(-) delete mode 100644 yellowstone-grpc-geyser/src/proto.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 236777b6..4f163c2f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ The minor version will be incremented upon a breaking change and the patch versi ### Features - client: add tx pretty print to rust ([#189](https://github.com/rpcpool/yellowstone-grpc/pull/189)). -- geyser: add mod `proto::convert_to`, `proto::convert_from` ([#189](https://github.com/rpcpool/yellowstone-grpc/pull/189)). +- proto: add mod `convert_to`, `convert_from` ([#189](https://github.com/rpcpool/yellowstone-grpc/pull/189)). ### Fixes diff --git a/Cargo.lock b/Cargo.lock index 73593d17..7955d87f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4466,7 +4466,7 @@ dependencies = [ [[package]] name = "yellowstone-grpc-client" -version = "1.10.0+solana.1.16.14" +version = "1.11.0+solana.1.16.14" dependencies = [ "bytes", "futures", @@ -4480,7 +4480,7 @@ dependencies = [ [[package]] name = "yellowstone-grpc-client-simple" -version = "1.9.0+solana.1.16.14" +version = "1.10.0+solana.1.16.14" dependencies = [ "anyhow", "backoff", @@ -4498,13 +4498,12 @@ dependencies = [ "solana-transaction-status", "tokio", "yellowstone-grpc-client", - "yellowstone-grpc-geyser", "yellowstone-grpc-proto", ] [[package]] name = "yellowstone-grpc-geyser" -version = "1.8.0+solana.1.16.14" +version = "1.9.0+solana.1.16.14" dependencies = [ "anyhow", "base64 0.21.2", @@ -4520,7 +4519,6 @@ dependencies = [ "prometheus", "serde", "serde_json", - "solana-account-decoder", "solana-geyser-plugin-interface", "solana-logger", "solana-sdk", @@ -4564,11 +4562,15 @@ dependencies = [ [[package]] name = "yellowstone-grpc-proto" -version = "1.9.0+solana.1.16.14" +version = "1.10.0+solana.1.16.14" dependencies = [ "anyhow", + "bincode", "prost", "protobuf-src", + "solana-account-decoder", + "solana-sdk", + "solana-transaction-status", "tonic", "tonic-build", ] diff --git a/Cargo.toml b/Cargo.toml index 7a602d04..a809444b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [workspace] members = [ - "examples/rust", # 1.9.0+solana.1.16.14 - "yellowstone-grpc-client", # 1.10.0+solana.1.16.14 - "yellowstone-grpc-geyser", # 1.8.0+solana.1.16.14 + "examples/rust", # 1.10.0+solana.1.16.14 + "yellowstone-grpc-client", # 1.11.0+solana.1.16.14 + "yellowstone-grpc-geyser", # 1.9.0+solana.1.16.14 "yellowstone-grpc-kafka", # 1.0.0+solana.1.16.14 - "yellowstone-grpc-proto", # 1.9.0+solana.1.16.14 + "yellowstone-grpc-proto", # 1.10.0+solana.1.16.14 ] [profile.release] diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml index 5d80e062..97321352 100644 --- a/examples/rust/Cargo.toml +++ b/examples/rust/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yellowstone-grpc-client-simple" -version = "1.9.0+solana.1.16.14" +version = "1.10.0+solana.1.16.14" authors = ["Triton One"] edition = "2021" publish = false @@ -25,5 +25,4 @@ solana-sdk = "=1.16.14" solana-transaction-status = "=1.16.14" tokio = { version = "1.21.2", features = ["rt-multi-thread", "macros", "time"] } yellowstone-grpc-client = { path = "../../yellowstone-grpc-client" } -yellowstone-grpc-geyser = { path = "../../yellowstone-grpc-geyser" } yellowstone-grpc-proto = { path = "../../yellowstone-grpc-proto" } diff --git a/examples/rust/src/bin/client.rs b/examples/rust/src/bin/client.rs index ec024f32..afb631e3 100644 --- a/examples/rust/src/bin/client.rs +++ b/examples/rust/src/bin/client.rs @@ -388,7 +388,7 @@ impl From for TransactionPretty { slot, signature: Signature::try_from(tx.signature.as_slice()).expect("valid signature"), is_vote: tx.is_vote, - tx: yellowstone_grpc_geyser::proto::convert_from::create_tx_with_meta(tx) + tx: yellowstone_grpc_proto::convert_from::create_tx_with_meta(tx) .expect("valid tx with meta") .encode(UiTransactionEncoding::Base64, Some(u8::MAX), true) .expect("failed to encode"), diff --git a/yellowstone-grpc-client/Cargo.toml b/yellowstone-grpc-client/Cargo.toml index 53dc68e2..b8d62d3d 100644 --- a/yellowstone-grpc-client/Cargo.toml +++ b/yellowstone-grpc-client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yellowstone-grpc-client" -version = "1.10.0+solana.1.16.14" +version = "1.11.0+solana.1.16.14" authors = ["Triton One"] edition = "2021" description = "Yellowstone gRPC Geyser Simple Client" @@ -16,7 +16,7 @@ http = "0.2.8" thiserror = "1.0" tonic = { version = "0.9.2", features = ["gzip", "tls", "tls-roots"] } tonic-health = "0.9.2" -yellowstone-grpc-proto = { path = "../yellowstone-grpc-proto", version = "1.9.0+solana.1.16.14" } +yellowstone-grpc-proto = { path = "../yellowstone-grpc-proto", version = "1.10.0+solana.1.16.14" } [dev-dependencies] tokio = { version = "1.21.2", features = ["macros"] } diff --git a/yellowstone-grpc-geyser/Cargo.toml b/yellowstone-grpc-geyser/Cargo.toml index b9c01c5c..3466f299 100644 --- a/yellowstone-grpc-geyser/Cargo.toml +++ b/yellowstone-grpc-geyser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yellowstone-grpc-geyser" -version = "1.8.0+solana.1.16.14" +version = "1.9.0+solana.1.16.14" authors = ["Triton One"] edition = "2021" description = "Yellowstone gRPC Geyser Plugin" @@ -25,7 +25,6 @@ log = "0.4.17" prometheus = "0.13.2" serde = { version = "1.0.145", features = ["derive"] } serde_json = "1.0.86" -solana-account-decoder = "=1.16.14" solana-geyser-plugin-interface = "=1.16.14" solana-logger = "=1.16.14" solana-sdk = "=1.16.14" diff --git a/yellowstone-grpc-geyser/src/filters.rs b/yellowstone-grpc-geyser/src/filters.rs index e6dd979d..3ffd1ced 100644 --- a/yellowstone-grpc-geyser/src/filters.rs +++ b/yellowstone-grpc-geyser/src/filters.rs @@ -9,15 +9,6 @@ use { Message, MessageAccount, MessageBlock, MessageBlockMeta, MessageEntry, MessageRef, MessageSlot, MessageTransaction, }, - proto::{ - subscribe_request_filter_accounts_filter::Filter as AccountsFilterDataOneof, - subscribe_request_filter_accounts_filter_memcmp::Data as AccountsFilterMemcmpOneof, - CommitmentLevel, SubscribeRequest, SubscribeRequestAccountsDataSlice, - SubscribeRequestFilterAccounts, SubscribeRequestFilterAccountsFilter, - SubscribeRequestFilterBlocks, SubscribeRequestFilterBlocksMeta, - SubscribeRequestFilterEntry, SubscribeRequestFilterSlots, - SubscribeRequestFilterTransactions, SubscribeUpdate, - }, }, base64::{engine::general_purpose::STANDARD as base64_engine, Engine}, solana_sdk::{pubkey::Pubkey, signature::Signature}, @@ -27,6 +18,15 @@ use { iter::FromIterator, str::FromStr, }, + yellowstone_grpc_proto::prelude::{ + subscribe_request_filter_accounts_filter::Filter as AccountsFilterDataOneof, + subscribe_request_filter_accounts_filter_memcmp::Data as AccountsFilterMemcmpOneof, + CommitmentLevel, SubscribeRequest, SubscribeRequestAccountsDataSlice, + SubscribeRequestFilterAccounts, SubscribeRequestFilterAccountsFilter, + SubscribeRequestFilterBlocks, SubscribeRequestFilterBlocksMeta, + SubscribeRequestFilterEntry, SubscribeRequestFilterSlots, + SubscribeRequestFilterTransactions, SubscribeUpdate, + }, }; #[derive(Debug, Clone)] diff --git a/yellowstone-grpc-geyser/src/grpc.rs b/yellowstone-grpc-geyser/src/grpc.rs index bec77f31..b646a374 100644 --- a/yellowstone-grpc-geyser/src/grpc.rs +++ b/yellowstone-grpc-geyser/src/grpc.rs @@ -3,18 +3,6 @@ use { config::{ConfigBlockFailAction, ConfigGrpc}, filters::{Filter, FilterAccountsDataSlice}, prom::{self, CONNECTIONS_TOTAL, MESSAGE_QUEUE_SIZE}, - proto::{ - self, - geyser_server::{Geyser, GeyserServer}, - subscribe_update::UpdateOneof, - CommitmentLevel, GetBlockHeightRequest, GetBlockHeightResponse, - GetLatestBlockhashRequest, GetLatestBlockhashResponse, GetSlotRequest, GetSlotResponse, - GetVersionRequest, GetVersionResponse, IsBlockhashValidRequest, - IsBlockhashValidResponse, PingRequest, PongResponse, SubscribeRequest, SubscribeUpdate, - SubscribeUpdateAccount, SubscribeUpdateAccountInfo, SubscribeUpdateBlock, - SubscribeUpdateBlockMeta, SubscribeUpdateEntry, SubscribeUpdatePing, - SubscribeUpdateSlot, SubscribeUpdateTransaction, SubscribeUpdateTransactionInfo, - }, version::VERSION, }, log::{error, info}, @@ -51,6 +39,20 @@ use { Request, Response, Result as TonicResult, Status, Streaming, }, tonic_health::server::health_reporter, + yellowstone_grpc_proto::{ + convert_to, + prelude::{ + geyser_server::{Geyser, GeyserServer}, + subscribe_update::UpdateOneof, + CommitmentLevel, GetBlockHeightRequest, GetBlockHeightResponse, + GetLatestBlockhashRequest, GetLatestBlockhashResponse, GetSlotRequest, GetSlotResponse, + GetVersionRequest, GetVersionResponse, IsBlockhashValidRequest, + IsBlockhashValidResponse, PingRequest, PongResponse, SubscribeRequest, SubscribeUpdate, + SubscribeUpdateAccount, SubscribeUpdateAccountInfo, SubscribeUpdateBlock, + SubscribeUpdateBlockMeta, SubscribeUpdateEntry, SubscribeUpdatePing, + SubscribeUpdateSlot, SubscribeUpdateTransaction, SubscribeUpdateTransactionInfo, + }, + }, }; #[derive(Debug, Clone)] @@ -155,8 +157,8 @@ impl MessageTransactionInfo { SubscribeUpdateTransactionInfo { signature: self.signature.as_ref().into(), is_vote: self.is_vote, - transaction: Some(proto::convert_to::create_transaction(&self.transaction)), - meta: Some(proto::convert_to::create_transaction_meta(&self.meta)), + transaction: Some(convert_to::create_transaction(&self.transaction)), + meta: Some(convert_to::create_transaction_meta(&self.meta)), index: self.index as u64, } } @@ -412,13 +414,9 @@ impl<'a> MessageRef<'a> { Self::Block(message) => UpdateOneof::Block(SubscribeUpdateBlock { slot: message.slot, blockhash: message.blockhash.clone(), - rewards: Some(proto::convert_to::create_rewards( - message.rewards.as_slice(), - )), - block_time: message.block_time.map(proto::convert_to::create_timestamp), - block_height: message - .block_height - .map(proto::convert_to::create_block_height), + rewards: Some(convert_to::create_rewards(message.rewards.as_slice())), + block_time: message.block_time.map(convert_to::create_timestamp), + block_height: message.block_height.map(convert_to::create_block_height), parent_slot: message.parent_slot, parent_blockhash: message.parent_blockhash.clone(), executed_transaction_count: message.executed_transaction_count, @@ -443,13 +441,9 @@ impl<'a> MessageRef<'a> { Self::BlockMeta(message) => UpdateOneof::BlockMeta(SubscribeUpdateBlockMeta { slot: message.slot, blockhash: message.blockhash.clone(), - rewards: Some(proto::convert_to::create_rewards( - message.rewards.as_slice(), - )), - block_time: message.block_time.map(proto::convert_to::create_timestamp), - block_height: message - .block_height - .map(proto::convert_to::create_block_height), + rewards: Some(convert_to::create_rewards(message.rewards.as_slice())), + block_time: message.block_time.map(convert_to::create_timestamp), + block_height: message.block_height.map(convert_to::create_block_height), parent_slot: message.parent_slot, parent_blockhash: message.parent_blockhash.clone(), executed_transaction_count: message.executed_transaction_count, diff --git a/yellowstone-grpc-geyser/src/lib.rs b/yellowstone-grpc-geyser/src/lib.rs index 2ab97231..192cc6e4 100644 --- a/yellowstone-grpc-geyser/src/lib.rs +++ b/yellowstone-grpc-geyser/src/lib.rs @@ -7,5 +7,4 @@ pub mod filters; pub mod grpc; pub mod plugin; pub mod prom; -pub mod proto; pub mod version; diff --git a/yellowstone-grpc-geyser/src/proto.rs b/yellowstone-grpc-geyser/src/proto.rs deleted file mode 100644 index 39fbb4d4..00000000 --- a/yellowstone-grpc-geyser/src/proto.rs +++ /dev/null @@ -1,552 +0,0 @@ -pub use yellowstone_grpc_proto::prelude::*; - -#[deprecated(note = "Please use `convert_to`")] -pub mod convert { - pub use super::convert_to::*; -} - -pub mod convert_to { - use { - solana_sdk::{ - clock::UnixTimestamp, - instruction::CompiledInstruction, - message::{ - v0::{LoadedMessage, MessageAddressTableLookup}, - LegacyMessage, MessageHeader, SanitizedMessage, - }, - pubkey::Pubkey, - signature::Signature, - transaction::SanitizedTransaction, - transaction_context::TransactionReturnData, - }, - solana_transaction_status::{ - InnerInstruction, InnerInstructions, Reward, RewardType, TransactionStatusMeta, - TransactionTokenBalance, - }, - }; - - pub fn create_transaction(tx: &SanitizedTransaction) -> super::Transaction { - super::Transaction { - signatures: tx - .signatures() - .iter() - .map(|signature| >::as_ref(signature).into()) - .collect(), - message: Some(create_message(tx.message())), - } - } - - pub fn create_message(message: &SanitizedMessage) -> super::Message { - match message { - SanitizedMessage::Legacy(LegacyMessage { message, .. }) => super::Message { - header: Some(create_header(&message.header)), - account_keys: message - .account_keys - .iter() - .map(|key| >::as_ref(key).into()) - .collect(), - recent_blockhash: message.recent_blockhash.to_bytes().into(), - instructions: message - .instructions - .iter() - .map(create_instruction) - .collect(), - versioned: false, - address_table_lookups: vec![], - }, - SanitizedMessage::V0(LoadedMessage { message, .. }) => super::Message { - header: Some(create_header(&message.header)), - account_keys: message - .account_keys - .iter() - .map(|key| >::as_ref(key).into()) - .collect(), - recent_blockhash: message.recent_blockhash.to_bytes().into(), - instructions: message - .instructions - .iter() - .map(create_instruction) - .collect(), - versioned: true, - address_table_lookups: message - .address_table_lookups - .iter() - .map(create_lookup) - .collect(), - }, - } - } - - pub const fn create_header(header: &MessageHeader) -> super::MessageHeader { - super::MessageHeader { - num_required_signatures: header.num_required_signatures as u32, - num_readonly_signed_accounts: header.num_readonly_signed_accounts as u32, - num_readonly_unsigned_accounts: header.num_readonly_unsigned_accounts as u32, - } - } - - pub fn create_instruction(ix: &CompiledInstruction) -> super::CompiledInstruction { - super::CompiledInstruction { - program_id_index: ix.program_id_index as u32, - accounts: ix.accounts.clone(), - data: ix.data.clone(), - } - } - - pub fn create_lookup(lookup: &MessageAddressTableLookup) -> super::MessageAddressTableLookup { - super::MessageAddressTableLookup { - account_key: >::as_ref(&lookup.account_key).into(), - writable_indexes: lookup.writable_indexes.clone(), - readonly_indexes: lookup.readonly_indexes.clone(), - } - } - - pub fn create_transaction_meta(meta: &TransactionStatusMeta) -> super::TransactionStatusMeta { - let TransactionStatusMeta { - status, - fee, - pre_balances, - post_balances, - inner_instructions, - log_messages, - pre_token_balances, - post_token_balances, - rewards, - loaded_addresses, - return_data, - compute_units_consumed, - } = meta; - let err = match status { - Ok(()) => None, - Err(err) => Some(super::TransactionError { - err: bincode::serialize(&err).expect("transaction error to serialize to bytes"), - }), - }; - let inner_instructions_none = inner_instructions.is_none(); - let inner_instructions = inner_instructions - .as_ref() - .map(|v| v.iter().map(create_inner_instructions).collect()) - .unwrap_or_default(); - let log_messages_none = log_messages.is_none(); - let log_messages = log_messages.clone().unwrap_or_default(); - let pre_token_balances = pre_token_balances - .as_ref() - .map(|v| v.iter().map(create_token_balance).collect()) - .unwrap_or_default(); - let post_token_balances = post_token_balances - .as_ref() - .map(|v| v.iter().map(create_token_balance).collect()) - .unwrap_or_default(); - let rewards = rewards - .as_ref() - .map(|vec| vec.iter().map(create_reward).collect()) - .unwrap_or_default(); - let loaded_writable_addresses = loaded_addresses - .writable - .iter() - .map(|key| >::as_ref(key).into()) - .collect(); - let loaded_readonly_addresses = loaded_addresses - .readonly - .iter() - .map(|key| >::as_ref(key).into()) - .collect(); - - super::TransactionStatusMeta { - err, - fee: *fee, - pre_balances: pre_balances.clone(), - post_balances: post_balances.clone(), - inner_instructions, - inner_instructions_none, - log_messages, - log_messages_none, - pre_token_balances, - post_token_balances, - rewards, - loaded_writable_addresses, - loaded_readonly_addresses, - return_data: return_data.as_ref().map(create_return_data), - return_data_none: return_data.is_none(), - compute_units_consumed: *compute_units_consumed, - } - } - - pub fn create_inner_instructions(instructions: &InnerInstructions) -> super::InnerInstructions { - super::InnerInstructions { - index: instructions.index as u32, - instructions: instructions - .instructions - .iter() - .map(create_inner_instruction) - .collect(), - } - } - - pub fn create_inner_instruction(instruction: &InnerInstruction) -> super::InnerInstruction { - super::InnerInstruction { - program_id_index: instruction.instruction.program_id_index as u32, - accounts: instruction.instruction.accounts.clone(), - data: instruction.instruction.data.clone(), - stack_height: instruction.stack_height, - } - } - - pub fn create_token_balance(balance: &TransactionTokenBalance) -> super::TokenBalance { - super::TokenBalance { - account_index: balance.account_index as u32, - mint: balance.mint.clone(), - ui_token_amount: Some(super::UiTokenAmount { - ui_amount: balance.ui_token_amount.ui_amount.unwrap_or_default(), - decimals: balance.ui_token_amount.decimals as u32, - amount: balance.ui_token_amount.amount.clone(), - ui_amount_string: balance.ui_token_amount.ui_amount_string.clone(), - }), - owner: balance.owner.clone(), - program_id: balance.program_id.clone(), - } - } - - pub fn create_reward(reward: &Reward) -> super::Reward { - super::Reward { - pubkey: reward.pubkey.clone(), - lamports: reward.lamports, - post_balance: reward.post_balance, - reward_type: match reward.reward_type { - None => super::RewardType::Unspecified, - Some(RewardType::Fee) => super::RewardType::Fee, - Some(RewardType::Rent) => super::RewardType::Rent, - Some(RewardType::Staking) => super::RewardType::Staking, - Some(RewardType::Voting) => super::RewardType::Voting, - } as i32, - commission: reward.commission.map(|c| c.to_string()).unwrap_or_default(), - } - } - - pub fn create_return_data(return_data: &TransactionReturnData) -> super::ReturnData { - super::ReturnData { - program_id: return_data.program_id.to_bytes().into(), - data: return_data.data.clone(), - } - } - - pub fn create_rewards(rewards: &[Reward]) -> super::Rewards { - super::Rewards { - rewards: rewards.iter().map(create_reward).collect(), - } - } - - pub const fn create_block_height(block_height: u64) -> super::BlockHeight { - super::BlockHeight { block_height } - } - - pub const fn create_timestamp(timestamp: UnixTimestamp) -> super::UnixTimestamp { - super::UnixTimestamp { timestamp } - } -} - -pub mod convert_from { - use { - solana_account_decoder::parse_token::UiTokenAmount, - solana_sdk::{ - hash::{Hash, HASH_BYTES}, - instruction::CompiledInstruction, - message::{ - v0::{LoadedAddresses, Message as MessageV0, MessageAddressTableLookup}, - Message, MessageHeader, VersionedMessage, - }, - pubkey::Pubkey, - signature::Signature, - transaction::{TransactionError, VersionedTransaction}, - transaction_context::TransactionReturnData, - }, - solana_transaction_status::{ - ConfirmedBlock, InnerInstruction, InnerInstructions, Reward, RewardType, - TransactionStatusMeta, TransactionTokenBalance, TransactionWithStatusMeta, - VersionedTransactionWithStatusMeta, - }, - }; - - fn ensure_some(maybe_value: Option, message: impl Into) -> Result { - match maybe_value { - Some(value) => Ok(value), - None => Err(message.into()), - } - } - - pub fn create_block(block: super::SubscribeUpdateBlock) -> Result { - let mut transactions = vec![]; - for tx in block.transactions { - transactions.push(create_tx_with_meta(tx)?); - } - - let mut rewards = vec![]; - for reward in ensure_some(block.rewards, "failed to get rewards")?.rewards { - rewards.push(create_reward(reward)?); - } - - Ok(ConfirmedBlock { - previous_blockhash: block.parent_blockhash, - blockhash: block.blockhash, - parent_slot: block.parent_slot, - transactions, - rewards, - block_time: Some(ensure_some( - block.block_time.map(|wrapper| wrapper.timestamp), - "failed to get block_time", - )?), - block_height: Some(ensure_some( - block.block_height.map(|wrapper| wrapper.block_height), - "failed to get block_height", - )?), - }) - } - - pub fn create_tx_with_meta( - tx: super::SubscribeUpdateTransactionInfo, - ) -> Result { - let meta = ensure_some(tx.meta, "failed to get transaction meta")?; - let tx = ensure_some(tx.transaction, "failed to get transaction transaction")?; - - Ok(TransactionWithStatusMeta::Complete( - VersionedTransactionWithStatusMeta { - transaction: create_tx_versioned(tx)?, - meta: create_tx_meta(meta)?, - }, - )) - } - - pub fn create_tx_versioned(tx: super::Transaction) -> Result { - let mut signatures = Vec::with_capacity(tx.signatures.len()); - for signature in tx.signatures { - signatures.push(match Signature::try_from(signature.as_slice()) { - Ok(signature) => signature, - Err(_error) => return Err("failed to parse Signature".to_owned()), - }); - } - - Ok(VersionedTransaction { - signatures, - message: create_message(ensure_some(tx.message, "failed to get message")?)?, - }) - } - - fn create_message(message: super::Message) -> Result { - let header = ensure_some(message.header, "failed to get MessageHeader")?; - let header = MessageHeader { - num_required_signatures: ensure_some( - header.num_required_signatures.try_into().ok(), - "failed to parse num_required_signatures", - )?, - num_readonly_signed_accounts: ensure_some( - header.num_readonly_signed_accounts.try_into().ok(), - "failed to parse num_readonly_signed_accounts", - )?, - num_readonly_unsigned_accounts: ensure_some( - header.num_readonly_unsigned_accounts.try_into().ok(), - "failed to parse num_readonly_unsigned_accounts", - )?, - }; - - if message.recent_blockhash.len() != HASH_BYTES { - return Err("failed to parse hash".to_owned()); - } - - let mut instructions = Vec::with_capacity(message.instructions.len()); - for ix in message.instructions { - instructions.push(CompiledInstruction { - program_id_index: ensure_some( - ix.program_id_index.try_into().ok(), - "failed to decode CompiledInstruction.program_id_index)", - )?, - accounts: ix.accounts, - data: ix.data, - }); - } - - Ok(if message.versioned { - let mut address_table_lookups = Vec::with_capacity(message.address_table_lookups.len()); - for table in message.address_table_lookups { - address_table_lookups.push(MessageAddressTableLookup { - account_key: ensure_some( - Pubkey::try_from(table.account_key.as_slice()).ok(), - "failed to parse Pubkey", - )?, - writable_indexes: table.writable_indexes, - readonly_indexes: table.readonly_indexes, - }); - } - - VersionedMessage::V0(MessageV0 { - header, - account_keys: create_pubkey_vec(message.account_keys)?, - recent_blockhash: Hash::new(message.recent_blockhash.as_slice()), - instructions, - address_table_lookups, - }) - } else { - VersionedMessage::Legacy(Message { - header, - account_keys: create_pubkey_vec(message.account_keys)?, - recent_blockhash: Hash::new(message.recent_blockhash.as_slice()), - instructions, - }) - }) - } - - pub fn create_tx_meta( - meta: super::TransactionStatusMeta, - ) -> Result { - let meta_status = match create_tx_error(meta.err.as_ref())? { - Some(err) => Err(err), - None => Ok(()), - }; - let mut meta_inner_instructions = vec![]; - for ix in meta.inner_instructions { - meta_inner_instructions.push(create_inner_instruction(ix)?); - } - let mut meta_rewards = vec![]; - for reward in meta.rewards { - meta_rewards.push(create_reward(reward)?); - } - - Ok(TransactionStatusMeta { - status: meta_status, - fee: meta.fee, - pre_balances: meta.pre_balances, - post_balances: meta.post_balances, - inner_instructions: Some(meta_inner_instructions), - log_messages: Some(meta.log_messages), - pre_token_balances: Some(create_token_balances(meta.pre_token_balances)?), - post_token_balances: Some(create_token_balances(meta.post_token_balances)?), - rewards: Some(meta_rewards), - loaded_addresses: create_loaded_addresses( - meta.loaded_writable_addresses, - meta.loaded_readonly_addresses, - )?, - return_data: if meta.return_data_none { - None - } else { - let data = ensure_some(meta.return_data, "failed to get return_data")?; - Some(TransactionReturnData { - program_id: ensure_some( - Pubkey::try_from(data.program_id.as_slice()).ok(), - "failed to parse program_id", - )?, - data: data.data, - }) - }, - compute_units_consumed: meta.compute_units_consumed, - }) - } - - pub fn create_tx_error( - err: Option<&super::TransactionError>, - ) -> Result, String> { - ensure_some( - err.map(|err| bincode::deserialize::(&err.err)) - .transpose() - .ok(), - "failed to decode TransactionError", - ) - } - - fn create_inner_instruction(ix: super::InnerInstructions) -> Result { - let mut instructions = vec![]; - for ix in ix.instructions { - instructions.push(InnerInstruction { - instruction: CompiledInstruction { - program_id_index: ensure_some( - ix.program_id_index.try_into().ok(), - "failed to decode CompiledInstruction.program_id_index)", - )?, - accounts: ix.accounts, - data: ix.data, - }, - stack_height: ix.stack_height, - }); - } - Ok(InnerInstructions { - index: ensure_some( - ix.index.try_into().ok(), - "failed to decode InnerInstructions.index", - )?, - instructions, - }) - } - - pub fn create_reward(reward: super::Reward) -> Result { - Ok(Reward { - pubkey: reward.pubkey, - lamports: reward.lamports, - post_balance: reward.post_balance, - reward_type: match ensure_some( - super::RewardType::from_i32(reward.reward_type), - "failed to parse reward_type", - )? { - super::RewardType::Unspecified => None, - super::RewardType::Fee => Some(RewardType::Fee), - super::RewardType::Rent => Some(RewardType::Rent), - super::RewardType::Staking => Some(RewardType::Staking), - super::RewardType::Voting => Some(RewardType::Voting), - }, - commission: if reward.commission.is_empty() { - None - } else { - Some(ensure_some( - reward.commission.parse().ok(), - "failed to parse reward commission", - )?) - }, - }) - } - - fn create_token_balances( - balances: Vec, - ) -> Result, String> { - let mut vec = Vec::with_capacity(balances.len()); - for balance in balances { - let ui_amount = ensure_some(balance.ui_token_amount, "failed to get ui_token_amount")?; - vec.push(TransactionTokenBalance { - account_index: ensure_some( - balance.account_index.try_into().ok(), - "failed to parse account_index", - )?, - mint: balance.mint, - ui_token_amount: UiTokenAmount { - ui_amount: Some(ui_amount.ui_amount), - decimals: ensure_some( - ui_amount.decimals.try_into().ok(), - "failed to parse decimals", - )?, - amount: ui_amount.amount, - ui_amount_string: ui_amount.ui_amount_string, - }, - owner: balance.owner, - program_id: balance.program_id, - }); - } - Ok(vec) - } - - fn create_loaded_addresses( - writable: Vec>, - readonly: Vec>, - ) -> Result { - Ok(LoadedAddresses { - writable: create_pubkey_vec(writable)?, - readonly: create_pubkey_vec(readonly)?, - }) - } - - fn create_pubkey_vec(pubkeys: Vec>) -> Result, String> { - let mut vec = Vec::with_capacity(pubkeys.len()); - for pubkey in pubkeys { - vec.push(ensure_some( - Pubkey::try_from(pubkey.as_slice()).ok(), - "failed to parse Pubkey", - )?) - } - Ok(vec) - } -} diff --git a/yellowstone-grpc-proto/Cargo.toml b/yellowstone-grpc-proto/Cargo.toml index e98484b0..df7383fe 100644 --- a/yellowstone-grpc-proto/Cargo.toml +++ b/yellowstone-grpc-proto/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "yellowstone-grpc-proto" -version = "1.9.0+solana.1.16.14" +version = "1.10.0+solana.1.16.14" authors = ["Triton One"] edition = "2021" description = "Yellowstone gRPC Geyser Protobuf Definitions" @@ -10,7 +10,11 @@ license = "Apache-2.0" keywords = ["solana"] [dependencies] +bincode = "1.3.3" prost = "0.11.9" +solana-account-decoder = "=1.16.14" +solana-sdk = "=1.16.14" +solana-transaction-status = "=1.16.14" tonic = "0.9.2" [build-dependencies] diff --git a/yellowstone-grpc-proto/src/lib.rs b/yellowstone-grpc-proto/src/lib.rs index 9a897cd8..c4c61c40 100644 --- a/yellowstone-grpc-proto/src/lib.rs +++ b/yellowstone-grpc-proto/src/lib.rs @@ -19,3 +19,551 @@ pub mod prelude { pub use prost; pub use tonic; + +pub mod convert_to { + use { + super::prelude as proto, + solana_sdk::{ + clock::UnixTimestamp, + instruction::CompiledInstruction, + message::{ + v0::{LoadedMessage, MessageAddressTableLookup}, + LegacyMessage, MessageHeader, SanitizedMessage, + }, + pubkey::Pubkey, + signature::Signature, + transaction::SanitizedTransaction, + transaction_context::TransactionReturnData, + }, + solana_transaction_status::{ + InnerInstruction, InnerInstructions, Reward, RewardType, TransactionStatusMeta, + TransactionTokenBalance, + }, + }; + + pub fn create_transaction(tx: &SanitizedTransaction) -> proto::Transaction { + proto::Transaction { + signatures: tx + .signatures() + .iter() + .map(|signature| >::as_ref(signature).into()) + .collect(), + message: Some(create_message(tx.message())), + } + } + + pub fn create_message(message: &SanitizedMessage) -> proto::Message { + match message { + SanitizedMessage::Legacy(LegacyMessage { message, .. }) => proto::Message { + header: Some(create_header(&message.header)), + account_keys: message + .account_keys + .iter() + .map(|key| >::as_ref(key).into()) + .collect(), + recent_blockhash: message.recent_blockhash.to_bytes().into(), + instructions: message + .instructions + .iter() + .map(create_instruction) + .collect(), + versioned: false, + address_table_lookups: vec![], + }, + SanitizedMessage::V0(LoadedMessage { message, .. }) => proto::Message { + header: Some(create_header(&message.header)), + account_keys: message + .account_keys + .iter() + .map(|key| >::as_ref(key).into()) + .collect(), + recent_blockhash: message.recent_blockhash.to_bytes().into(), + instructions: message + .instructions + .iter() + .map(create_instruction) + .collect(), + versioned: true, + address_table_lookups: message + .address_table_lookups + .iter() + .map(create_lookup) + .collect(), + }, + } + } + + pub const fn create_header(header: &MessageHeader) -> proto::MessageHeader { + proto::MessageHeader { + num_required_signatures: header.num_required_signatures as u32, + num_readonly_signed_accounts: header.num_readonly_signed_accounts as u32, + num_readonly_unsigned_accounts: header.num_readonly_unsigned_accounts as u32, + } + } + + pub fn create_instruction(ix: &CompiledInstruction) -> proto::CompiledInstruction { + proto::CompiledInstruction { + program_id_index: ix.program_id_index as u32, + accounts: ix.accounts.clone(), + data: ix.data.clone(), + } + } + + pub fn create_lookup(lookup: &MessageAddressTableLookup) -> proto::MessageAddressTableLookup { + proto::MessageAddressTableLookup { + account_key: >::as_ref(&lookup.account_key).into(), + writable_indexes: lookup.writable_indexes.clone(), + readonly_indexes: lookup.readonly_indexes.clone(), + } + } + + pub fn create_transaction_meta(meta: &TransactionStatusMeta) -> proto::TransactionStatusMeta { + let TransactionStatusMeta { + status, + fee, + pre_balances, + post_balances, + inner_instructions, + log_messages, + pre_token_balances, + post_token_balances, + rewards, + loaded_addresses, + return_data, + compute_units_consumed, + } = meta; + let err = match status { + Ok(()) => None, + Err(err) => Some(proto::TransactionError { + err: bincode::serialize(&err).expect("transaction error to serialize to bytes"), + }), + }; + let inner_instructions_none = inner_instructions.is_none(); + let inner_instructions = inner_instructions + .as_ref() + .map(|v| v.iter().map(create_inner_instructions).collect()) + .unwrap_or_default(); + let log_messages_none = log_messages.is_none(); + let log_messages = log_messages.clone().unwrap_or_default(); + let pre_token_balances = pre_token_balances + .as_ref() + .map(|v| v.iter().map(create_token_balance).collect()) + .unwrap_or_default(); + let post_token_balances = post_token_balances + .as_ref() + .map(|v| v.iter().map(create_token_balance).collect()) + .unwrap_or_default(); + let rewards = rewards + .as_ref() + .map(|vec| vec.iter().map(create_reward).collect()) + .unwrap_or_default(); + let loaded_writable_addresses = loaded_addresses + .writable + .iter() + .map(|key| >::as_ref(key).into()) + .collect(); + let loaded_readonly_addresses = loaded_addresses + .readonly + .iter() + .map(|key| >::as_ref(key).into()) + .collect(); + + proto::TransactionStatusMeta { + err, + fee: *fee, + pre_balances: pre_balances.clone(), + post_balances: post_balances.clone(), + inner_instructions, + inner_instructions_none, + log_messages, + log_messages_none, + pre_token_balances, + post_token_balances, + rewards, + loaded_writable_addresses, + loaded_readonly_addresses, + return_data: return_data.as_ref().map(create_return_data), + return_data_none: return_data.is_none(), + compute_units_consumed: *compute_units_consumed, + } + } + + pub fn create_inner_instructions(instructions: &InnerInstructions) -> proto::InnerInstructions { + proto::InnerInstructions { + index: instructions.index as u32, + instructions: instructions + .instructions + .iter() + .map(create_inner_instruction) + .collect(), + } + } + + pub fn create_inner_instruction(instruction: &InnerInstruction) -> proto::InnerInstruction { + proto::InnerInstruction { + program_id_index: instruction.instruction.program_id_index as u32, + accounts: instruction.instruction.accounts.clone(), + data: instruction.instruction.data.clone(), + stack_height: instruction.stack_height, + } + } + + pub fn create_token_balance(balance: &TransactionTokenBalance) -> proto::TokenBalance { + proto::TokenBalance { + account_index: balance.account_index as u32, + mint: balance.mint.clone(), + ui_token_amount: Some(proto::UiTokenAmount { + ui_amount: balance.ui_token_amount.ui_amount.unwrap_or_default(), + decimals: balance.ui_token_amount.decimals as u32, + amount: balance.ui_token_amount.amount.clone(), + ui_amount_string: balance.ui_token_amount.ui_amount_string.clone(), + }), + owner: balance.owner.clone(), + program_id: balance.program_id.clone(), + } + } + + pub fn create_reward(reward: &Reward) -> proto::Reward { + proto::Reward { + pubkey: reward.pubkey.clone(), + lamports: reward.lamports, + post_balance: reward.post_balance, + reward_type: match reward.reward_type { + None => proto::RewardType::Unspecified, + Some(RewardType::Fee) => proto::RewardType::Fee, + Some(RewardType::Rent) => proto::RewardType::Rent, + Some(RewardType::Staking) => proto::RewardType::Staking, + Some(RewardType::Voting) => proto::RewardType::Voting, + } as i32, + commission: reward.commission.map(|c| c.to_string()).unwrap_or_default(), + } + } + + pub fn create_return_data(return_data: &TransactionReturnData) -> proto::ReturnData { + proto::ReturnData { + program_id: return_data.program_id.to_bytes().into(), + data: return_data.data.clone(), + } + } + + pub fn create_rewards(rewards: &[Reward]) -> proto::Rewards { + proto::Rewards { + rewards: rewards.iter().map(create_reward).collect(), + } + } + + pub const fn create_block_height(block_height: u64) -> proto::BlockHeight { + proto::BlockHeight { block_height } + } + + pub const fn create_timestamp(timestamp: UnixTimestamp) -> proto::UnixTimestamp { + proto::UnixTimestamp { timestamp } + } +} + +pub mod convert_from { + use { + super::prelude as proto, + solana_account_decoder::parse_token::UiTokenAmount, + solana_sdk::{ + hash::{Hash, HASH_BYTES}, + instruction::CompiledInstruction, + message::{ + v0::{LoadedAddresses, Message as MessageV0, MessageAddressTableLookup}, + Message, MessageHeader, VersionedMessage, + }, + pubkey::Pubkey, + signature::Signature, + transaction::{TransactionError, VersionedTransaction}, + transaction_context::TransactionReturnData, + }, + solana_transaction_status::{ + ConfirmedBlock, InnerInstruction, InnerInstructions, Reward, RewardType, + TransactionStatusMeta, TransactionTokenBalance, TransactionWithStatusMeta, + VersionedTransactionWithStatusMeta, + }, + }; + + fn ensure_some(maybe_value: Option, message: impl Into) -> Result { + match maybe_value { + Some(value) => Ok(value), + None => Err(message.into()), + } + } + + pub fn create_block(block: proto::SubscribeUpdateBlock) -> Result { + let mut transactions = vec![]; + for tx in block.transactions { + transactions.push(create_tx_with_meta(tx)?); + } + + let mut rewards = vec![]; + for reward in ensure_some(block.rewards, "failed to get rewards")?.rewards { + rewards.push(create_reward(reward)?); + } + + Ok(ConfirmedBlock { + previous_blockhash: block.parent_blockhash, + blockhash: block.blockhash, + parent_slot: block.parent_slot, + transactions, + rewards, + block_time: Some(ensure_some( + block.block_time.map(|wrapper| wrapper.timestamp), + "failed to get block_time", + )?), + block_height: Some(ensure_some( + block.block_height.map(|wrapper| wrapper.block_height), + "failed to get block_height", + )?), + }) + } + + pub fn create_tx_with_meta( + tx: proto::SubscribeUpdateTransactionInfo, + ) -> Result { + let meta = ensure_some(tx.meta, "failed to get transaction meta")?; + let tx = ensure_some(tx.transaction, "failed to get transaction transaction")?; + + Ok(TransactionWithStatusMeta::Complete( + VersionedTransactionWithStatusMeta { + transaction: create_tx_versioned(tx)?, + meta: create_tx_meta(meta)?, + }, + )) + } + + pub fn create_tx_versioned(tx: proto::Transaction) -> Result { + let mut signatures = Vec::with_capacity(tx.signatures.len()); + for signature in tx.signatures { + signatures.push(match Signature::try_from(signature.as_slice()) { + Ok(signature) => signature, + Err(_error) => return Err("failed to parse Signature".to_owned()), + }); + } + + Ok(VersionedTransaction { + signatures, + message: create_message(ensure_some(tx.message, "failed to get message")?)?, + }) + } + + fn create_message(message: proto::Message) -> Result { + let header = ensure_some(message.header, "failed to get MessageHeader")?; + let header = MessageHeader { + num_required_signatures: ensure_some( + header.num_required_signatures.try_into().ok(), + "failed to parse num_required_signatures", + )?, + num_readonly_signed_accounts: ensure_some( + header.num_readonly_signed_accounts.try_into().ok(), + "failed to parse num_readonly_signed_accounts", + )?, + num_readonly_unsigned_accounts: ensure_some( + header.num_readonly_unsigned_accounts.try_into().ok(), + "failed to parse num_readonly_unsigned_accounts", + )?, + }; + + if message.recent_blockhash.len() != HASH_BYTES { + return Err("failed to parse hash".to_owned()); + } + + let mut instructions = Vec::with_capacity(message.instructions.len()); + for ix in message.instructions { + instructions.push(CompiledInstruction { + program_id_index: ensure_some( + ix.program_id_index.try_into().ok(), + "failed to decode CompiledInstruction.program_id_index)", + )?, + accounts: ix.accounts, + data: ix.data, + }); + } + + Ok(if message.versioned { + let mut address_table_lookups = Vec::with_capacity(message.address_table_lookups.len()); + for table in message.address_table_lookups { + address_table_lookups.push(MessageAddressTableLookup { + account_key: ensure_some( + Pubkey::try_from(table.account_key.as_slice()).ok(), + "failed to parse Pubkey", + )?, + writable_indexes: table.writable_indexes, + readonly_indexes: table.readonly_indexes, + }); + } + + VersionedMessage::V0(MessageV0 { + header, + account_keys: create_pubkey_vec(message.account_keys)?, + recent_blockhash: Hash::new(message.recent_blockhash.as_slice()), + instructions, + address_table_lookups, + }) + } else { + VersionedMessage::Legacy(Message { + header, + account_keys: create_pubkey_vec(message.account_keys)?, + recent_blockhash: Hash::new(message.recent_blockhash.as_slice()), + instructions, + }) + }) + } + + pub fn create_tx_meta( + meta: proto::TransactionStatusMeta, + ) -> Result { + let meta_status = match create_tx_error(meta.err.as_ref())? { + Some(err) => Err(err), + None => Ok(()), + }; + let mut meta_inner_instructions = vec![]; + for ix in meta.inner_instructions { + meta_inner_instructions.push(create_inner_instruction(ix)?); + } + let mut meta_rewards = vec![]; + for reward in meta.rewards { + meta_rewards.push(create_reward(reward)?); + } + + Ok(TransactionStatusMeta { + status: meta_status, + fee: meta.fee, + pre_balances: meta.pre_balances, + post_balances: meta.post_balances, + inner_instructions: Some(meta_inner_instructions), + log_messages: Some(meta.log_messages), + pre_token_balances: Some(create_token_balances(meta.pre_token_balances)?), + post_token_balances: Some(create_token_balances(meta.post_token_balances)?), + rewards: Some(meta_rewards), + loaded_addresses: create_loaded_addresses( + meta.loaded_writable_addresses, + meta.loaded_readonly_addresses, + )?, + return_data: if meta.return_data_none { + None + } else { + let data = ensure_some(meta.return_data, "failed to get return_data")?; + Some(TransactionReturnData { + program_id: ensure_some( + Pubkey::try_from(data.program_id.as_slice()).ok(), + "failed to parse program_id", + )?, + data: data.data, + }) + }, + compute_units_consumed: meta.compute_units_consumed, + }) + } + + pub fn create_tx_error( + err: Option<&proto::TransactionError>, + ) -> Result, String> { + ensure_some( + err.map(|err| bincode::deserialize::(&err.err)) + .transpose() + .ok(), + "failed to decode TransactionError", + ) + } + + fn create_inner_instruction(ix: proto::InnerInstructions) -> Result { + let mut instructions = vec![]; + for ix in ix.instructions { + instructions.push(InnerInstruction { + instruction: CompiledInstruction { + program_id_index: ensure_some( + ix.program_id_index.try_into().ok(), + "failed to decode CompiledInstruction.program_id_index)", + )?, + accounts: ix.accounts, + data: ix.data, + }, + stack_height: ix.stack_height, + }); + } + Ok(InnerInstructions { + index: ensure_some( + ix.index.try_into().ok(), + "failed to decode InnerInstructions.index", + )?, + instructions, + }) + } + + pub fn create_reward(reward: proto::Reward) -> Result { + Ok(Reward { + pubkey: reward.pubkey, + lamports: reward.lamports, + post_balance: reward.post_balance, + reward_type: match ensure_some( + proto::RewardType::from_i32(reward.reward_type), + "failed to parse reward_type", + )? { + proto::RewardType::Unspecified => None, + proto::RewardType::Fee => Some(RewardType::Fee), + proto::RewardType::Rent => Some(RewardType::Rent), + proto::RewardType::Staking => Some(RewardType::Staking), + proto::RewardType::Voting => Some(RewardType::Voting), + }, + commission: if reward.commission.is_empty() { + None + } else { + Some(ensure_some( + reward.commission.parse().ok(), + "failed to parse reward commission", + )?) + }, + }) + } + + fn create_token_balances( + balances: Vec, + ) -> Result, String> { + let mut vec = Vec::with_capacity(balances.len()); + for balance in balances { + let ui_amount = ensure_some(balance.ui_token_amount, "failed to get ui_token_amount")?; + vec.push(TransactionTokenBalance { + account_index: ensure_some( + balance.account_index.try_into().ok(), + "failed to parse account_index", + )?, + mint: balance.mint, + ui_token_amount: UiTokenAmount { + ui_amount: Some(ui_amount.ui_amount), + decimals: ensure_some( + ui_amount.decimals.try_into().ok(), + "failed to parse decimals", + )?, + amount: ui_amount.amount, + ui_amount_string: ui_amount.ui_amount_string, + }, + owner: balance.owner, + program_id: balance.program_id, + }); + } + Ok(vec) + } + + fn create_loaded_addresses( + writable: Vec>, + readonly: Vec>, + ) -> Result { + Ok(LoadedAddresses { + writable: create_pubkey_vec(writable)?, + readonly: create_pubkey_vec(readonly)?, + }) + } + + fn create_pubkey_vec(pubkeys: Vec>) -> Result, String> { + let mut vec = Vec::with_capacity(pubkeys.len()); + for pubkey in pubkeys { + vec.push(ensure_some( + Pubkey::try_from(pubkey.as_slice()).ok(), + "failed to parse Pubkey", + )?) + } + Ok(vec) + } +} From bf0a1bf5a29938b5599ae9fde6196e5597495a0c Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 3 Oct 2023 16:46:56 +0400 Subject: [PATCH 7/8] remove txpretty --- CHANGELOG.md | 3 +- Cargo.lock | 1 - examples/rust/Cargo.toml | 1 - examples/rust/src/bin/client.rs | 57 ++------------------------------- 4 files changed, 4 insertions(+), 58 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f163c2f..9aa1ffe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,7 @@ The minor version will be incremented upon a breaking change and the patch versi ### Features -- client: add tx pretty print to rust ([#189](https://github.com/rpcpool/yellowstone-grpc/pull/189)). -- proto: add mod `convert_to`, `convert_from` ([#189](https://github.com/rpcpool/yellowstone-grpc/pull/189)). +- proto: add mod `convert_to`, `convert_from` ([#190](https://github.com/rpcpool/yellowstone-grpc/pull/190)). ### Fixes diff --git a/Cargo.lock b/Cargo.lock index 7955d87f..468b3a53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4495,7 +4495,6 @@ dependencies = [ "maplit", "serde_json", "solana-sdk", - "solana-transaction-status", "tokio", "yellowstone-grpc-client", "yellowstone-grpc-proto", diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml index 97321352..7d98ddc5 100644 --- a/examples/rust/Cargo.toml +++ b/examples/rust/Cargo.toml @@ -22,7 +22,6 @@ log = { version = "0.4.14", features = ["std"] } maplit = "1.0.2" serde_json = "1.0.86" solana-sdk = "=1.16.14" -solana-transaction-status = "=1.16.14" tokio = { version = "1.21.2", features = ["rt-multi-thread", "macros", "time"] } yellowstone-grpc-client = { path = "../../yellowstone-grpc-client" } yellowstone-grpc-proto = { path = "../../yellowstone-grpc-proto" } diff --git a/examples/rust/src/bin/client.rs b/examples/rust/src/bin/client.rs index afb631e3..109b2fcd 100644 --- a/examples/rust/src/bin/client.rs +++ b/examples/rust/src/bin/client.rs @@ -3,11 +3,10 @@ use { clap::{Parser, Subcommand, ValueEnum}, futures::{future::TryFutureExt, sink::SinkExt, stream::StreamExt}, log::{error, info}, - solana_sdk::{pubkey::Pubkey, signature::Signature}, - solana_transaction_status::{EncodedTransactionWithStatusMeta, UiTransactionEncoding}, + solana_sdk::pubkey::Pubkey, std::{ collections::HashMap, - env, fmt, + env, sync::{Arc, Mutex}, time::Duration, }, @@ -21,7 +20,7 @@ use { SubscribeRequestFilterAccountsFilter, SubscribeRequestFilterAccountsFilterMemcmp, SubscribeRequestFilterBlocks, SubscribeRequestFilterBlocksMeta, SubscribeRequestFilterEntry, SubscribeRequestFilterSlots, - SubscribeRequestFilterTransactions, SubscribeUpdateAccount, SubscribeUpdateTransaction, + SubscribeRequestFilterTransactions, SubscribeUpdateAccount, }, tonic::service::Interceptor, }, @@ -354,48 +353,6 @@ impl From for AccountPretty { } } -#[allow(dead_code)] -pub struct TransactionPretty { - slot: u64, - signature: Signature, - is_vote: bool, - tx: EncodedTransactionWithStatusMeta, -} - -impl fmt::Debug for TransactionPretty { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - struct TxWrap<'a>(&'a EncodedTransactionWithStatusMeta); - impl<'a> fmt::Debug for TxWrap<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let serialized = serde_json::to_string(self.0).expect("failed to serialize"); - fmt::Display::fmt(&serialized, f) - } - } - - f.debug_struct("TransactionPretty") - .field("slot", &self.slot) - .field("signature", &self.signature) - .field("is_vote", &self.is_vote) - .field("tx", &TxWrap(&self.tx)) - .finish() - } -} - -impl From for TransactionPretty { - fn from(SubscribeUpdateTransaction { transaction, slot }: SubscribeUpdateTransaction) -> Self { - let tx = transaction.expect("should be defined"); - Self { - slot, - signature: Signature::try_from(tx.signature.as_slice()).expect("valid signature"), - is_vote: tx.is_vote, - tx: yellowstone_grpc_proto::convert_from::create_tx_with_meta(tx) - .expect("valid tx with meta") - .encode(UiTransactionEncoding::Base64, Some(u8::MAX), true) - .expect("failed to encode"), - } - } -} - #[tokio::main] async fn main() -> anyhow::Result<()> { env::set_var( @@ -528,14 +485,6 @@ async fn geyser_subscribe( ); continue; } - Some(UpdateOneof::Transaction(tx)) => { - let tx: TransactionPretty = tx.into(); - info!( - "new transaction update: filters {:?}, transaction: {:#?}", - msg.filters, tx - ); - continue; - } _ => {} } info!("new message: {msg:?}") From fb7f5a3831c90216b877ee92b1286d0239f30d22 Mon Sep 17 00:00:00 2001 From: Kirill Fomichev Date: Tue, 3 Oct 2023 16:55:23 +0400 Subject: [PATCH 8/8] remove dep --- Cargo.lock | 1 - examples/rust/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 468b3a53..6d8cb911 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4493,7 +4493,6 @@ dependencies = [ "hex", "log", "maplit", - "serde_json", "solana-sdk", "tokio", "yellowstone-grpc-client", diff --git a/examples/rust/Cargo.toml b/examples/rust/Cargo.toml index 7d98ddc5..19252e47 100644 --- a/examples/rust/Cargo.toml +++ b/examples/rust/Cargo.toml @@ -20,7 +20,6 @@ futures = "0.3.24" hex = "0.4.3" log = { version = "0.4.14", features = ["std"] } maplit = "1.0.2" -serde_json = "1.0.86" solana-sdk = "=1.16.14" tokio = { version = "1.21.2", features = ["rt-multi-thread", "macros", "time"] } yellowstone-grpc-client = { path = "../../yellowstone-grpc-client" }