rename jito mod

This commit is contained in:
William
2025-04-10 12:29:42 +08:00
parent c7acb32acf
commit 8050d7ea8f
28 changed files with 22 additions and 1379 deletions
+2 -2
View File
@@ -13,8 +13,6 @@ readme = "README.md"
crate-type = ["cdylib", "rlib"]
[dependencies]
jito-protos = { path = "./jito_protos" }
solana-sdk = "2.1.16"
solana-client = "2.1.16"
solana-program = "2.1.16"
@@ -23,6 +21,7 @@ solana-rpc-client-api = "2.1.16"
solana-transaction-status = "2.1.16"
solana-account-decoder = "2.1.16"
solana-hash = "2.1.16"
solana-perf = "2.1.16"
solana-security-txt = "1.1.1"
spl-token = "8.0.0"
@@ -50,6 +49,7 @@ rustls = { version = "0.23.23", features = ["ring"] }
rustls-native-certs = "0.8.1"
tokio-rustls = "0.26.1"
bytes = "1.4.0"
dotenvy = "0.15.7"
pretty_env_logger = "0.5.0"
log = "0.4.22"
-17
View File
@@ -1,17 +0,0 @@
[package]
name = "jito-protos"
version = "0.1.0"
edition = "2021"
publish = false
[dependencies]
bincode = "1.3.3"
bytes = "1.4.0"
prost = "0.13.5"
prost-types = "0.13.5"
solana-perf = "2.1.13"
solana-sdk = "2.1.13"
tonic = "0.12.3"
[build-dependencies]
# tonic-build = "0.12.3"
-56
View File
@@ -1,56 +0,0 @@
# Schemas
This repository contains schemas for [grpc](#grpc) and [json rpc](#json-rpc) endpoints for Jito Lab's MEV system.
## grpc
The below explains how to use the public protobuf definitions for Jito Lab's MEV system.
### Usage
Add this repo as a git submodule to your repo. Here's an example file tree in a Rust codebase:
```
your-rust-repo/
├─ src/
│ ├─ gm/
│ │ ├─ lib.rs
│ ├─ jito-protos/
│ │ ├─ protos/
│ │ │ ├─ *.proto
| | |─ src/
| | | |─ lib.rs
| | |─ build.rs
```
```rust
/// lib.rs
pub mod proto_package {
tonic::include_proto!("proto_package.proto");
}
```
```rust
/// build.rs
use tonic_build::configure;
fn main() {
configure()
.compile(
&[
"protos/proto_package.proto",
],
&["protos"],
)
.unwrap();
}
```
If you are looking for inspiration, a sample client can be found at [searcher examples](https://github.com/jito-labs/searcher-examples)
## json rpc
[json rpc schema](json_rpc/http.md) explains how to use json rpc for Jito Lab's MEV system.
-23
View File
@@ -1,23 +0,0 @@
fn main() {
// tonic_build::configure()
// .protoc_arg("--experimental_allow_proto3_optional")
// .build_server(false)
// .out_dir("src/grpc")
// .compile_protos(
// &[
// "protos/auth.proto",
// "protos/block.proto",
// "protos/block_engine.proto",
// "protos/bundle.proto",
// "protos/packet.proto",
// "protos/relayer.proto",
// "protos/searcher.proto",
// "protos/shared.proto",
// "protos/shredstream.proto",
// "protos/trace_shred.proto",
// ],
// &["protos"],
// )
// .unwrap();
}
-260
View File
@@ -1,260 +0,0 @@
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GenerateAuthChallengeRequest {
/// / Role the client is attempting to generate tokens for.
#[prost(enumeration = "Role", tag = "1")]
pub role: i32,
/// / Client's 32 byte pubkey.
#[prost(bytes = "vec", tag = "2")]
pub pubkey: ::prost::alloc::vec::Vec<u8>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GenerateAuthChallengeResponse {
#[prost(string, tag = "1")]
pub challenge: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GenerateAuthTokensRequest {
/// / The pre-signed challenge.
#[prost(string, tag = "1")]
pub challenge: ::prost::alloc::string::String,
/// / The signing keypair's corresponding 32 byte pubkey.
#[prost(bytes = "vec", tag = "2")]
pub client_pubkey: ::prost::alloc::vec::Vec<u8>,
/// / The 64 byte signature of the challenge signed by the client's private key. The private key must correspond to
/// the pubkey passed in the \[GenerateAuthChallenge\] method. The client is expected to sign the challenge token
/// prepended with their pubkey. For example sign(pubkey, challenge).
#[prost(bytes = "vec", tag = "3")]
pub signed_challenge: ::prost::alloc::vec::Vec<u8>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Token {
/// / The token.
#[prost(string, tag = "1")]
pub value: ::prost::alloc::string::String,
/// / When the token will expire.
#[prost(message, optional, tag = "2")]
pub expires_at_utc: ::core::option::Option<::prost_types::Timestamp>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GenerateAuthTokensResponse {
/// / The token granting access to resources.
#[prost(message, optional, tag = "1")]
pub access_token: ::core::option::Option<Token>,
/// / The token used to refresh the access_token. This has a longer TTL than the access_token.
#[prost(message, optional, tag = "2")]
pub refresh_token: ::core::option::Option<Token>,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RefreshAccessTokenRequest {
/// / Non-expired refresh token obtained from the \[GenerateAuthTokens\] method.
#[prost(string, tag = "1")]
pub refresh_token: ::prost::alloc::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct RefreshAccessTokenResponse {
/// / Fresh access_token.
#[prost(message, optional, tag = "1")]
pub access_token: ::core::option::Option<Token>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
#[repr(i32)]
pub enum Role {
Relayer = 0,
Searcher = 1,
Validator = 2,
ShredstreamSubscriber = 3,
}
impl Role {
/// String value of the enum field names used in the ProtoBuf definition.
///
/// The values are not transformed in any way and thus are considered stable
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
pub fn as_str_name(&self) -> &'static str {
match self {
Self::Relayer => "RELAYER",
Self::Searcher => "SEARCHER",
Self::Validator => "VALIDATOR",
Self::ShredstreamSubscriber => "SHREDSTREAM_SUBSCRIBER",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
match value {
"RELAYER" => Some(Self::Relayer),
"SEARCHER" => Some(Self::Searcher),
"VALIDATOR" => Some(Self::Validator),
"SHREDSTREAM_SUBSCRIBER" => Some(Self::ShredstreamSubscriber),
_ => None,
}
}
}
/// Generated client implementations.
pub mod auth_service_client {
#![allow(
unused_variables,
dead_code,
missing_docs,
clippy::wildcard_imports,
clippy::let_unit_value,
)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
/// / This service is responsible for issuing auth tokens to clients for API access.
#[derive(Debug, Clone)]
pub struct AuthServiceClient<T> {
inner: tonic::client::Grpc<T>,
}
impl AuthServiceClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> AuthServiceClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> AuthServiceClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
{
AuthServiceClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with the given encoding.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.send_compressed(encoding);
self
}
/// Enable decompressing responses.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.accept_compressed(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}
/// / Returns a challenge, client is expected to sign this challenge with an appropriate keypair in order to obtain access tokens.
pub async fn generate_auth_challenge(
&mut self,
request: impl tonic::IntoRequest<super::GenerateAuthChallengeRequest>,
) -> std::result::Result<
tonic::Response<super::GenerateAuthChallengeResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/auth.AuthService/GenerateAuthChallenge",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("auth.AuthService", "GenerateAuthChallenge"));
self.inner.unary(req, path, codec).await
}
/// / Provides the client with the initial pair of auth tokens for API access.
pub async fn generate_auth_tokens(
&mut self,
request: impl tonic::IntoRequest<super::GenerateAuthTokensRequest>,
) -> std::result::Result<
tonic::Response<super::GenerateAuthTokensResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/auth.AuthService/GenerateAuthTokens",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("auth.AuthService", "GenerateAuthTokens"));
self.inner.unary(req, path, codec).await
}
/// / Call this method with a non-expired refresh token to obtain a new access token.
pub async fn refresh_access_token(
&mut self,
request: impl tonic::IntoRequest<super::RefreshAccessTokenRequest>,
) -> std::result::Result<
tonic::Response<super::RefreshAccessTokenResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/auth.AuthService/RefreshAccessToken",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("auth.AuthService", "RefreshAccessToken"));
self.inner.unary(req, path, codec).await
}
}
}
-19
View File
@@ -1,19 +0,0 @@
// This file is @generated by prost-build.
/// Condensed block helpful for getting data around efficiently internal to our system.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct CondensedBlock {
#[prost(message, optional, tag = "1")]
pub header: ::core::option::Option<super::shared::Header>,
#[prost(string, tag = "2")]
pub previous_blockhash: ::prost::alloc::string::String,
#[prost(string, tag = "3")]
pub blockhash: ::prost::alloc::string::String,
#[prost(uint64, tag = "4")]
pub parent_slot: u64,
#[prost(bytes = "vec", repeated, tag = "5")]
pub versioned_transactions: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
#[prost(uint64, tag = "6")]
pub slot: u64,
#[prost(string, tag = "7")]
pub commitment: ::prost::alloc::string::String,
}
-462
View File
@@ -1,462 +0,0 @@
// This file is @generated by prost-build.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct SubscribePacketsRequest {}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SubscribePacketsResponse {
#[prost(message, optional, tag = "1")]
pub header: ::core::option::Option<super::shared::Header>,
#[prost(message, optional, tag = "2")]
pub batch: ::core::option::Option<super::packet::PacketBatch>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct SubscribeBundlesRequest {}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SubscribeBundlesResponse {
#[prost(message, repeated, tag = "1")]
pub bundles: ::prost::alloc::vec::Vec<super::bundle::BundleUuid>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct BlockBuilderFeeInfoRequest {}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct BlockBuilderFeeInfoResponse {
#[prost(string, tag = "1")]
pub pubkey: ::prost::alloc::string::String,
/// commission (0-100)
#[prost(uint64, tag = "2")]
pub commission: u64,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AccountsOfInterest {
/// use * for all accounts
#[prost(string, repeated, tag = "1")]
pub accounts: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct AccountsOfInterestRequest {}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AccountsOfInterestUpdate {
#[prost(string, repeated, tag = "1")]
pub accounts: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct ProgramsOfInterestRequest {}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ProgramsOfInterestUpdate {
#[prost(string, repeated, tag = "1")]
pub programs: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
/// A series of packets with an expiration attached to them.
/// The header contains a timestamp for when this packet was generated.
/// The expiry is how long the packet batches have before they expire and are forwarded to the validator.
/// This provides a more censorship resistant method to MEV than block engines receiving packets directly.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ExpiringPacketBatch {
#[prost(message, optional, tag = "1")]
pub header: ::core::option::Option<super::shared::Header>,
#[prost(message, optional, tag = "2")]
pub batch: ::core::option::Option<super::packet::PacketBatch>,
#[prost(uint32, tag = "3")]
pub expiry_ms: u32,
}
/// Packets and heartbeats are sent over the same stream.
/// ExpiringPacketBatches have an expiration attached to them so the block engine can track
/// how long it has until the relayer forwards the packets to the validator.
/// Heartbeats contain a timestamp from the system and is used as a simple and naive time-sync mechanism
/// so the block engine has some idea on how far their clocks are apart.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct PacketBatchUpdate {
#[prost(oneof = "packet_batch_update::Msg", tags = "1, 2")]
pub msg: ::core::option::Option<packet_batch_update::Msg>,
}
/// Nested message and enum types in `PacketBatchUpdate`.
pub mod packet_batch_update {
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Msg {
#[prost(message, tag = "1")]
Batches(super::ExpiringPacketBatch),
#[prost(message, tag = "2")]
Heartbeat(super::super::shared::Heartbeat),
}
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct StartExpiringPacketStreamResponse {
#[prost(message, optional, tag = "1")]
pub heartbeat: ::core::option::Option<super::shared::Heartbeat>,
}
/// Generated client implementations.
pub mod block_engine_validator_client {
#![allow(
unused_variables,
dead_code,
missing_docs,
clippy::wildcard_imports,
clippy::let_unit_value,
)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
/// / Validators can connect to Block Engines to receive packets and bundles.
#[derive(Debug, Clone)]
pub struct BlockEngineValidatorClient<T> {
inner: tonic::client::Grpc<T>,
}
impl BlockEngineValidatorClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> BlockEngineValidatorClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> BlockEngineValidatorClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
{
BlockEngineValidatorClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with the given encoding.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.send_compressed(encoding);
self
}
/// Enable decompressing responses.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.accept_compressed(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}
/// / Validators can subscribe to the block engine to receive a stream of packets
pub async fn subscribe_packets(
&mut self,
request: impl tonic::IntoRequest<super::SubscribePacketsRequest>,
) -> std::result::Result<
tonic::Response<tonic::codec::Streaming<super::SubscribePacketsResponse>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/block_engine.BlockEngineValidator/SubscribePackets",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"block_engine.BlockEngineValidator",
"SubscribePackets",
),
);
self.inner.server_streaming(req, path, codec).await
}
/// / Validators can subscribe to the block engine to receive a stream of simulated and profitable bundles
pub async fn subscribe_bundles(
&mut self,
request: impl tonic::IntoRequest<super::SubscribeBundlesRequest>,
) -> std::result::Result<
tonic::Response<tonic::codec::Streaming<super::SubscribeBundlesResponse>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/block_engine.BlockEngineValidator/SubscribeBundles",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"block_engine.BlockEngineValidator",
"SubscribeBundles",
),
);
self.inner.server_streaming(req, path, codec).await
}
/// Block builders can optionally collect fees. This returns fee information if a block builder wants to
/// collect one.
pub async fn get_block_builder_fee_info(
&mut self,
request: impl tonic::IntoRequest<super::BlockBuilderFeeInfoRequest>,
) -> std::result::Result<
tonic::Response<super::BlockBuilderFeeInfoResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/block_engine.BlockEngineValidator/GetBlockBuilderFeeInfo",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"block_engine.BlockEngineValidator",
"GetBlockBuilderFeeInfo",
),
);
self.inner.unary(req, path, codec).await
}
}
}
/// Generated client implementations.
pub mod block_engine_relayer_client {
#![allow(
unused_variables,
dead_code,
missing_docs,
clippy::wildcard_imports,
clippy::let_unit_value,
)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
/// / Relayers can forward packets to Block Engines.
/// / Block Engines provide an AccountsOfInterest field to only send transactions that are of interest.
#[derive(Debug, Clone)]
pub struct BlockEngineRelayerClient<T> {
inner: tonic::client::Grpc<T>,
}
impl BlockEngineRelayerClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> BlockEngineRelayerClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> BlockEngineRelayerClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
{
BlockEngineRelayerClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with the given encoding.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.send_compressed(encoding);
self
}
/// Enable decompressing responses.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.accept_compressed(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}
/// / The block engine feeds accounts of interest (AOI) updates to the relayer periodically.
/// / For all transactions the relayer receives, it forwards transactions to the block engine which write-lock
/// / any of the accounts in the AOI.
pub async fn subscribe_accounts_of_interest(
&mut self,
request: impl tonic::IntoRequest<super::AccountsOfInterestRequest>,
) -> std::result::Result<
tonic::Response<tonic::codec::Streaming<super::AccountsOfInterestUpdate>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/block_engine.BlockEngineRelayer/SubscribeAccountsOfInterest",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"block_engine.BlockEngineRelayer",
"SubscribeAccountsOfInterest",
),
);
self.inner.server_streaming(req, path, codec).await
}
pub async fn subscribe_programs_of_interest(
&mut self,
request: impl tonic::IntoRequest<super::ProgramsOfInterestRequest>,
) -> std::result::Result<
tonic::Response<tonic::codec::Streaming<super::ProgramsOfInterestUpdate>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/block_engine.BlockEngineRelayer/SubscribeProgramsOfInterest",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"block_engine.BlockEngineRelayer",
"SubscribeProgramsOfInterest",
),
);
self.inner.server_streaming(req, path, codec).await
}
/// Validators can subscribe to packets from the relayer and receive a multiplexed signal that contains a mixture
/// of packets and heartbeats.
/// NOTE: This is a bi-directional stream due to a bug with how Envoy handles half closed client-side streams.
/// The issue is being tracked here: https://github.com/envoyproxy/envoy/issues/22748. In the meantime, the
/// server will stream heartbeats to clients at some reasonable cadence.
pub async fn start_expiring_packet_stream(
&mut self,
request: impl tonic::IntoStreamingRequest<Message = super::PacketBatchUpdate>,
) -> std::result::Result<
tonic::Response<
tonic::codec::Streaming<super::StartExpiringPacketStreamResponse>,
>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/block_engine.BlockEngineRelayer/StartExpiringPacketStream",
);
let mut req = request.into_streaming_request();
req.extensions_mut()
.insert(
GrpcMethod::new(
"block_engine.BlockEngineRelayer",
"StartExpiringPacketStream",
),
);
self.inner.streaming(req, path, codec).await
}
}
}
-10
View File
@@ -1,10 +0,0 @@
pub mod auth;
pub mod block;
pub mod block_engine;
pub mod bundle;
pub mod packet;
pub mod relayer;
pub mod searcher;
pub mod shared;
pub mod shredstream;
pub mod trace_shred;
-178
View File
@@ -1,178 +0,0 @@
// This file is @generated by prost-build.
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct GetTpuConfigsRequest {}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct GetTpuConfigsResponse {
#[prost(message, optional, tag = "1")]
pub tpu: ::core::option::Option<super::shared::Socket>,
#[prost(message, optional, tag = "2")]
pub tpu_forward: ::core::option::Option<super::shared::Socket>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct SubscribePacketsRequest {}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct SubscribePacketsResponse {
#[prost(message, optional, tag = "1")]
pub header: ::core::option::Option<super::shared::Header>,
#[prost(oneof = "subscribe_packets_response::Msg", tags = "2, 3")]
pub msg: ::core::option::Option<subscribe_packets_response::Msg>,
}
/// Nested message and enum types in `SubscribePacketsResponse`.
pub mod subscribe_packets_response {
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Msg {
#[prost(message, tag = "2")]
Heartbeat(super::super::shared::Heartbeat),
#[prost(message, tag = "3")]
Batch(super::super::packet::PacketBatch),
}
}
/// Generated client implementations.
pub mod relayer_client {
#![allow(
unused_variables,
dead_code,
missing_docs,
clippy::wildcard_imports,
clippy::let_unit_value,
)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
/// / Relayers offer a TPU and TPU forward proxy for Solana validators.
/// / Validators can connect and fetch the TPU configuration for the relayer and start to advertise the
/// / relayer's information in gossip.
/// / They can also subscribe to packets which arrived on the TPU ports at the relayer
#[derive(Debug, Clone)]
pub struct RelayerClient<T> {
inner: tonic::client::Grpc<T>,
}
impl RelayerClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> RelayerClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> RelayerClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
{
RelayerClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with the given encoding.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.send_compressed(encoding);
self
}
/// Enable decompressing responses.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.accept_compressed(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}
/// The relayer has TPU and TPU forward sockets that validators can leverage.
/// A validator can fetch this config and change its TPU and TPU forward port in gossip.
pub async fn get_tpu_configs(
&mut self,
request: impl tonic::IntoRequest<super::GetTpuConfigsRequest>,
) -> std::result::Result<
tonic::Response<super::GetTpuConfigsResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/relayer.Relayer/GetTpuConfigs",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("relayer.Relayer", "GetTpuConfigs"));
self.inner.unary(req, path, codec).await
}
/// Validators can subscribe to packets from the relayer and receive a multiplexed signal that contains a mixture
/// of packets and heartbeats
pub async fn subscribe_packets(
&mut self,
request: impl tonic::IntoRequest<super::SubscribePacketsRequest>,
) -> std::result::Result<
tonic::Response<tonic::codec::Streaming<super::SubscribePacketsResponse>>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/relayer.Relayer/SubscribePackets",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("relayer.Relayer", "SubscribePackets"));
self.inner.server_streaming(req, path, codec).await
}
}
}
-136
View File
@@ -1,136 +0,0 @@
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct Heartbeat {
/// don't trust IP:PORT from tcp header since it can be tampered over the wire
/// `socket.ip` must match incoming packet's ip. this prevents spamming an unwitting destination
#[prost(message, optional, tag = "1")]
pub socket: ::core::option::Option<super::shared::Socket>,
/// regions for shredstream proxy to receive shreds from
/// list of valid regions: <https://jito-labs.gitbook.io/mev/systems/connecting/mainnet>
#[prost(string, repeated, tag = "2")]
pub regions: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
}
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
pub struct HeartbeatResponse {
/// client must respond within `ttl_ms` to keep stream alive
#[prost(uint32, tag = "1")]
pub ttl_ms: u32,
}
/// Generated client implementations.
pub mod shredstream_client {
#![allow(
unused_variables,
dead_code,
missing_docs,
clippy::wildcard_imports,
clippy::let_unit_value,
)]
use tonic::codegen::*;
use tonic::codegen::http::Uri;
#[derive(Debug, Clone)]
pub struct ShredstreamClient<T> {
inner: tonic::client::Grpc<T>,
}
impl ShredstreamClient<tonic::transport::Channel> {
/// Attempt to create a new client by connecting to a given endpoint.
pub async fn connect<D>(dst: D) -> Result<Self, tonic::transport::Error>
where
D: TryInto<tonic::transport::Endpoint>,
D::Error: Into<StdError>,
{
let conn = tonic::transport::Endpoint::new(dst)?.connect().await?;
Ok(Self::new(conn))
}
}
impl<T> ShredstreamClient<T>
where
T: tonic::client::GrpcService<tonic::body::BoxBody>,
T::Error: Into<StdError>,
T::ResponseBody: Body<Data = Bytes> + std::marker::Send + 'static,
<T::ResponseBody as Body>::Error: Into<StdError> + std::marker::Send,
{
pub fn new(inner: T) -> Self {
let inner = tonic::client::Grpc::new(inner);
Self { inner }
}
pub fn with_origin(inner: T, origin: Uri) -> Self {
let inner = tonic::client::Grpc::with_origin(inner, origin);
Self { inner }
}
pub fn with_interceptor<F>(
inner: T,
interceptor: F,
) -> ShredstreamClient<InterceptedService<T, F>>
where
F: tonic::service::Interceptor,
T::ResponseBody: Default,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<
<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody,
>,
>,
<T as tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
>>::Error: Into<StdError> + std::marker::Send + std::marker::Sync,
{
ShredstreamClient::new(InterceptedService::new(inner, interceptor))
}
/// Compress requests with the given encoding.
///
/// This requires the server to support it otherwise it might respond with an
/// error.
#[must_use]
pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.send_compressed(encoding);
self
}
/// Enable decompressing responses.
#[must_use]
pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self {
self.inner = self.inner.accept_compressed(encoding);
self
}
/// Limits the maximum size of a decoded message.
///
/// Default: `4MB`
#[must_use]
pub fn max_decoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_decoding_message_size(limit);
self
}
/// Limits the maximum size of an encoded message.
///
/// Default: `usize::MAX`
#[must_use]
pub fn max_encoding_message_size(mut self, limit: usize) -> Self {
self.inner = self.inner.max_encoding_message_size(limit);
self
}
/// RPC endpoint to send heartbeats to keep shreds flowing
pub async fn send_heartbeat(
&mut self,
request: impl tonic::IntoRequest<super::Heartbeat>,
) -> std::result::Result<
tonic::Response<super::HeartbeatResponse>,
tonic::Status,
> {
self.inner
.ready()
.await
.map_err(|e| {
tonic::Status::unknown(
format!("Service was not ready: {}", e.into()),
)
})?;
let codec = tonic::codec::ProstCodec::default();
let path = http::uri::PathAndQuery::from_static(
"/shredstream.Shredstream/SendHeartbeat",
);
let mut req = request.into_request();
req.extensions_mut()
.insert(GrpcMethod::new("shredstream.Shredstream", "SendHeartbeat"));
self.inner.unary(req, path, codec).await
}
}
}
-13
View File
@@ -1,13 +0,0 @@
// This file is @generated by prost-build.
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct TraceShred {
/// source region, one of: <https://jito-labs.gitbook.io/mev/systems/connecting/mainnet>
#[prost(string, tag = "1")]
pub region: ::prost::alloc::string::String,
/// timestamp of creation
#[prost(message, optional, tag = "2")]
pub created_at: ::core::option::Option<::prost_types::Timestamp>,
/// monotonically increases, resets upon service restart
#[prost(uint32, tag = "3")]
pub seq_num: u32,
}
-3
View File
@@ -1,3 +0,0 @@
pub mod convert;
pub mod grpc;
pub use grpc::*;
+1 -1
View File
@@ -3,7 +3,7 @@ use std::sync::Arc;
use solana_client::rpc_client::RpcClient;
use solana_sdk::{commitment_config::CommitmentConfig, signature::Keypair};
use serde::Deserialize;
use crate::{constants::trade::{DEFAULT_BUY_TIP_FEE, DEFAULT_COMPUTE_UNIT_LIMIT, DEFAULT_COMPUTE_UNIT_PRICE, DEFAULT_SELL_TIP_FEE}, jito::FeeClient};
use crate::{constants::trade::{DEFAULT_BUY_TIP_FEE, DEFAULT_COMPUTE_UNIT_LIMIT, DEFAULT_COMPUTE_UNIT_PRICE, DEFAULT_SELL_TIP_FEE}, swqos::FeeClient};
#[derive(Debug, Clone, PartialEq)]
pub enum FeeType {
-167
View File
@@ -1,167 +0,0 @@
use std::{
sync::{Arc, RwLock},
time::{Duration, SystemTime},
};
use jito_protos::auth::{
auth_service_client::AuthServiceClient, GenerateAuthChallengeRequest,
GenerateAuthTokensRequest, RefreshAccessTokenRequest, Role, Token,
};
use prost_types::Timestamp;
use solana_metrics::datapoint_info;
use solana_sdk::signature::{Keypair, Signer};
use tokio::{task::JoinHandle, time::sleep};
use tonic::{service::Interceptor, transport::Channel, Request, Status};
use super::searcher_client::BlockEngineConnectionResult;
const AUTHORIZATION_HEADER: &str = "authorization";
const BEARER: &str = "Bearer ";
/// Adds the token to each requests' authorization header.
/// Manages refreshing the token in a separate thread.
#[derive(Clone)]
pub struct ClientInterceptor {
/// The token added to each request header.
bearer_token: Arc<RwLock<String>>,
}
impl ClientInterceptor {
pub async fn new(
mut auth_service_client: AuthServiceClient<Channel>,
keypair: &Arc<Keypair>,
role: Role,
) -> BlockEngineConnectionResult<Self> {
let (access_token, refresh_token) =
Self::auth(&mut auth_service_client, keypair, role).await?;
let bearer_token = Arc::new(RwLock::new(access_token.value.clone()));
let _refresh_token_thread = Self::spawn_token_refresh_thread(
auth_service_client,
bearer_token.clone(),
refresh_token,
access_token.expires_at_utc.unwrap(),
keypair.clone(),
role,
);
Ok(Self { bearer_token })
}
async fn auth(
auth_service_client: &mut AuthServiceClient<Channel>,
keypair: &Keypair,
role: Role,
) -> BlockEngineConnectionResult<(Token, Token)> {
let challenge_resp = auth_service_client
.generate_auth_challenge(GenerateAuthChallengeRequest {
role: role as i32,
pubkey: keypair.pubkey().as_ref().to_vec(),
})
.await?
.into_inner();
let challenge = format!("{}-{}", keypair.pubkey(), challenge_resp.challenge);
let signed_challenge = keypair.sign_message(challenge.as_bytes()).as_ref().to_vec();
let tokens = auth_service_client
.generate_auth_tokens(GenerateAuthTokensRequest {
challenge,
client_pubkey: keypair.pubkey().as_ref().to_vec(),
signed_challenge,
})
.await?
.into_inner();
Ok((tokens.access_token.unwrap(), tokens.refresh_token.unwrap()))
}
fn spawn_token_refresh_thread(
mut auth_service_client: AuthServiceClient<Channel>,
bearer_token: Arc<RwLock<String>>,
refresh_token: Token,
access_token_expiration: Timestamp,
keypair: Arc<Keypair>,
role: Role,
) -> JoinHandle<BlockEngineConnectionResult<()>> {
tokio::spawn(async move {
let mut refresh_token = refresh_token;
let mut access_token_expiration = access_token_expiration;
loop {
let access_token_ttl = SystemTime::try_from(access_token_expiration.clone())
.unwrap()
.duration_since(SystemTime::now())
.unwrap_or_else(|_| Duration::from_secs(0));
let refresh_token_ttl =
SystemTime::try_from(refresh_token.expires_at_utc.as_ref().unwrap().clone())
.unwrap()
.duration_since(SystemTime::now())
.unwrap_or_else(|_| Duration::from_secs(0));
let does_access_token_expire_soon = access_token_ttl < Duration::from_secs(5 * 60);
let does_refresh_token_expire_soon =
refresh_token_ttl < Duration::from_secs(5 * 60);
match (
does_refresh_token_expire_soon,
does_access_token_expire_soon,
) {
// re-run entire auth workflow is refresh token expiring soon
(true, _) => {
let is_error = {
if let Ok((new_access_token, new_refresh_token)) =
Self::auth(&mut auth_service_client, &keypair, role).await
{
*bearer_token.write().unwrap() = new_access_token.value.clone();
access_token_expiration = new_access_token.expires_at_utc.unwrap();
refresh_token = new_refresh_token;
false
} else {
true
}
};
datapoint_info!("searcher-full-auth", ("is_error", is_error, bool));
}
// re-up the access token if it expires soon
(_, true) => {
let is_error = {
if let Ok(refresh_resp) = auth_service_client
.refresh_access_token(RefreshAccessTokenRequest {
refresh_token: refresh_token.value.clone(),
})
.await
{
let access_token = refresh_resp.into_inner().access_token.unwrap();
*bearer_token.write().unwrap() = access_token.value.clone();
access_token_expiration = access_token.expires_at_utc.unwrap();
false
} else {
true
}
};
datapoint_info!("searcher-refresh-auth", ("is_error", is_error, bool));
}
_ => {
sleep(Duration::from_secs(60)).await;
}
}
}
})
}
}
impl Interceptor for ClientInterceptor {
fn call(&mut self, mut request: Request<()>) -> Result<Request<()>, Status> {
let l_token = self.bearer_token.read().unwrap();
if !l_token.is_empty() {
request.metadata_mut().insert(
AUTHORIZATION_HEADER,
format!("{BEARER}{l_token}").parse().unwrap(),
);
}
Ok(request)
}
}
+2 -2
View File
@@ -5,12 +5,12 @@ pub mod instruction;
pub mod grpc;
pub mod common;
pub mod ipfs;
pub mod jito;
pub mod swqos;
pub mod pumpfun;
use std::sync::Arc;
use jito::{FeeClient, JitoClient, NextBlockClient, ZeroSlotClient};
use swqos::{FeeClient, JitoClient, NextBlockClient, ZeroSlotClient};
use rustls::crypto::{ring::default_provider, CryptoProvider};
use solana_sdk::{
commitment_config::CommitmentConfig,
+1 -1
View File
@@ -7,7 +7,7 @@ use spl_associated_token_account::instruction::create_associated_token_account;
use tokio::task::JoinHandle;
use std::{str::FromStr, time::Instant, sync::Arc};
use crate::{common::{PriorityFee, SolanaRpcClient}, constants::{self, trade::DEFAULT_SLIPPAGE}, instruction, jito::FeeClient};
use crate::{common::{PriorityFee, SolanaRpcClient}, constants::{self, trade::DEFAULT_SLIPPAGE}, instruction, swqos::FeeClient};
const MAX_LOADED_ACCOUNTS_DATA_SIZE_LIMIT: u32 = 250000;
+1 -1
View File
@@ -11,7 +11,7 @@ use spl_associated_token_account::{
use crate::{
common::{PriorityFee, SolanaRpcClient}, constants, instruction,
ipfs::TokenMetadataIPFS, jito::FeeClient,
ipfs::TokenMetadataIPFS, swqos::FeeClient,
pumpfun::buy::build_buy_transaction_with_tip
};
+1 -1
View File
@@ -10,7 +10,7 @@ use tokio::task::JoinHandle;
use std::{str::FromStr, time::Instant, sync::Arc};
use crate::{common::{PriorityFee, SolanaRpcClient}, constants::trade::{DEFAULT_COMPUTE_UNIT_PRICE, DEFAULT_SLIPPAGE}, instruction, jito::FeeClient};
use crate::{common::{PriorityFee, SolanaRpcClient}, constants::trade::{DEFAULT_COMPUTE_UNIT_PRICE, DEFAULT_SLIPPAGE}, instruction, swqos::FeeClient};
use super::common::{calculate_with_slippage_sell, get_bonding_curve_account, get_global_account};
@@ -11,13 +11,11 @@ use solana_sdk::{
transaction::VersionedTransaction,
};
use crate::{
packet::{
Meta as ProtoMeta, Packet as ProtoPacket, PacketBatch as ProtoPacketBatch,
PacketFlags as ProtoPacketFlags,
},
shared::Socket,
use crate::swqos::jito_grpc::packet::{
Meta as ProtoMeta, Packet as ProtoPacket, PacketBatch as ProtoPacketBatch,
PacketFlags as ProtoPacketFlags,
};
use crate::swqos::jito_grpc::shared::Socket;
/// Converts a Solana packet to a protobuf packet
/// NOTE: the packet.data() function will filter packets marked for discard
+5
View File
@@ -0,0 +1,5 @@
pub mod bundle;
pub mod packet;
pub mod searcher;
pub mod shared;
pub mod convert;
+2 -16
View File
@@ -1,11 +1,10 @@
use api::api_client::ApiClient;
use common::{poll_transaction_confirmation, serialize_smart_transaction_and_encode};
use jito_protos::{searcher::searcher_service_client::SearcherServiceClient, shredstream::shredstream_client::ShredstreamClient};
use crate::swqos::jito_grpc::searcher::searcher_service_client::SearcherServiceClient;
use reqwest::Client;
use searcher_client::{get_searcher_client_no_auth, send_bundle_with_confirmation};
use serde_json::json;
use tonic::transport::Channel;
use tracing::instrument::WithSubscriber;
use yellowstone_grpc_client::Interceptor;
use std::{sync::Arc, time::Instant};
use tokio::sync::{Mutex, RwLock};
@@ -29,6 +28,7 @@ use crate::{common::SolanaRpcClient, constants::accounts::{JITO_TIP_ACCOUNTS, NE
pub mod common;
pub mod searcher_client;
pub mod api;
pub mod jito_grpc;
lazy_static::lazy_static! {
static ref TIP_ACCOUNT_CACHE: RwLock<Vec<String>> = RwLock::new(Vec::new());
@@ -99,20 +99,6 @@ impl JitoClient {
) -> Result<Vec<Signature>, anyhow::Error> {
searcher_client::send_bundle_no_wait(&transactions, self.searcher_client.clone()).await
}
// pub async fn get_tip_accounts(&self) -> Result<Vec<String>, anyhow::Error> {
// let client = ShredstreamClient::connect("dst").await?;
// // let subscriber = Dispatch::new(tracing_subscriber::fmt::Subscriber::builder().finish());
// let subscriber = tracing::subscriber::set_global_default(tracing_subscriber::fmt::Subscriber::builder().finish()).unwrap();
// let aaa = client.with_subscriber(subscriber);
// let mut stream = client.subscribe_accounts_of_interest(tonic::Request::new(()));
// let mut accounts = Vec::new();
// while let Some(Ok(response)) = stream.next().await {
// accounts.extend(response.accounts);
// }
// Ok(accounts)
// }
}
#[derive(Clone)]
@@ -3,7 +3,7 @@ use std::{
time::{Duration, Instant},
};
use jito_protos::{
use crate::swqos::jito_grpc::{
bundle::{
Bundle, BundleResult,
},
@@ -18,12 +18,10 @@ use solana_sdk::{
};
use thiserror::Error;
use tokio::sync::Mutex;
use tonic::{
codec::CompressionEncoding, transport::{self, Channel, Endpoint}, Status
};
use tonic::{transport::{self, Channel, Endpoint}, Status};
use yellowstone_grpc_client::ClientTlsConfig;
use crate::jito::common::poll_transaction_confirmation;
use crate::swqos::common::poll_transaction_confirmation;
use crate::common::SolanaRpcClient;
#[derive(Debug, Error)]