add nextblock, 0slot support
This commit is contained in:
Executable
+158
@@ -0,0 +1,158 @@
|
||||
use std::{
|
||||
cmp::min,
|
||||
net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use bincode::serialize;
|
||||
use solana_perf::packet::{Packet, PacketBatch, PACKET_DATA_SIZE};
|
||||
use solana_sdk::{
|
||||
packet::{Meta, PacketFlags},
|
||||
transaction::VersionedTransaction,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
packet::{
|
||||
Meta as ProtoMeta, Packet as ProtoPacket, PacketBatch as ProtoPacketBatch,
|
||||
PacketFlags as ProtoPacketFlags,
|
||||
},
|
||||
shared::Socket,
|
||||
};
|
||||
|
||||
/// Converts a Solana packet to a protobuf packet
|
||||
/// NOTE: the packet.data() function will filter packets marked for discard
|
||||
pub fn packet_to_proto_packet(p: &Packet) -> Option<ProtoPacket> {
|
||||
Some(ProtoPacket {
|
||||
data: p.data(..)?.to_vec(),
|
||||
meta: Some(ProtoMeta {
|
||||
size: p.meta().size as u64,
|
||||
addr: p.meta().addr.to_string(),
|
||||
port: p.meta().port as u32,
|
||||
flags: Some(ProtoPacketFlags {
|
||||
discard: p.meta().discard(),
|
||||
forwarded: p.meta().forwarded(),
|
||||
repair: p.meta().repair(),
|
||||
simple_vote_tx: p.meta().is_simple_vote_tx(),
|
||||
tracer_packet: p.meta().is_perf_track_packet(),
|
||||
from_staked_node: p.meta().is_from_staked_node(),
|
||||
}),
|
||||
sender_stake: 0,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn packet_batches_to_proto_packets(
|
||||
batches: &[PacketBatch],
|
||||
) -> impl Iterator<Item = ProtoPacket> + '_ {
|
||||
batches
|
||||
.iter()
|
||||
.flat_map(|b| b.iter().filter_map(packet_to_proto_packet))
|
||||
}
|
||||
|
||||
/// converts from a protobuf packet to packet
|
||||
pub fn proto_packet_to_packet(p: &ProtoPacket) -> Packet {
|
||||
let mut data = [0u8; PACKET_DATA_SIZE];
|
||||
let copy_len = min(data.len(), p.data.len());
|
||||
data[..copy_len].copy_from_slice(&p.data[..copy_len]);
|
||||
let mut packet = Packet::new(data, Meta::default());
|
||||
if let Some(meta) = &p.meta {
|
||||
packet.meta_mut().size = meta.size as usize;
|
||||
packet.meta_mut().addr = meta
|
||||
.addr
|
||||
.parse()
|
||||
.unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED));
|
||||
packet.meta_mut().port = meta.port as u16;
|
||||
if let Some(flags) = &meta.flags {
|
||||
if flags.simple_vote_tx {
|
||||
packet.meta_mut().flags.insert(PacketFlags::SIMPLE_VOTE_TX);
|
||||
}
|
||||
if flags.forwarded {
|
||||
packet.meta_mut().flags.insert(PacketFlags::FORWARDED);
|
||||
}
|
||||
if flags.tracer_packet {
|
||||
packet.meta_mut().flags.insert(PacketFlags::PERF_TRACK_PACKET);
|
||||
}
|
||||
if flags.repair {
|
||||
packet.meta_mut().flags.insert(PacketFlags::REPAIR);
|
||||
}
|
||||
if flags.discard {
|
||||
packet.meta_mut().flags.insert(PacketFlags::DISCARD);
|
||||
}
|
||||
}
|
||||
}
|
||||
packet
|
||||
}
|
||||
|
||||
pub fn proto_packet_batch_to_packets(
|
||||
packet_batch: ProtoPacketBatch,
|
||||
) -> impl Iterator<Item = Packet> {
|
||||
packet_batch
|
||||
.packets
|
||||
.into_iter()
|
||||
.map(|proto_packet| proto_packet_to_packet(&proto_packet))
|
||||
}
|
||||
|
||||
/// Converts a protobuf packet to a VersionedTransaction
|
||||
pub fn versioned_tx_from_packet(p: &ProtoPacket) -> Option<VersionedTransaction> {
|
||||
let mut data = [0; PACKET_DATA_SIZE];
|
||||
let copy_len = min(data.len(), p.data.len());
|
||||
data[..copy_len].copy_from_slice(&p.data[..copy_len]);
|
||||
let mut packet = Packet::new(data, Default::default());
|
||||
if let Some(meta) = &p.meta {
|
||||
packet.meta_mut().size = meta.size as usize;
|
||||
}
|
||||
packet.deserialize_slice(..).ok()
|
||||
}
|
||||
|
||||
/// Coverts a VersionedTransaction to packet
|
||||
pub fn packet_from_versioned_tx(tx: VersionedTransaction) -> Packet {
|
||||
let tx_data = serialize(&tx).expect("serializes");
|
||||
let mut data = [0; PACKET_DATA_SIZE];
|
||||
let copy_len = min(tx_data.len(), data.len());
|
||||
data[..copy_len].copy_from_slice(&tx_data[..copy_len]);
|
||||
let mut packet = Packet::new(data, Default::default());
|
||||
packet.meta_mut().size = copy_len;
|
||||
packet
|
||||
}
|
||||
|
||||
/// Converts a VersionedTransaction to a protobuf packet
|
||||
pub fn proto_packet_from_versioned_tx(tx: &VersionedTransaction) -> ProtoPacket {
|
||||
let data = serialize(tx).expect("serializes");
|
||||
let size = data.len() as u64;
|
||||
ProtoPacket {
|
||||
data,
|
||||
meta: Some(ProtoMeta {
|
||||
size,
|
||||
addr: "".to_string(),
|
||||
port: 0,
|
||||
flags: None,
|
||||
sender_stake: 0,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a GRPC Socket to stdlib SocketAddr
|
||||
impl TryFrom<&Socket> for SocketAddr {
|
||||
type Error = AddrParseError;
|
||||
|
||||
fn try_from(value: &Socket) -> Result<Self, Self::Error> {
|
||||
IpAddr::from_str(&value.ip).map(|ip| SocketAddr::new(ip, value.port as u16))
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use solana_perf::test_tx::test_tx;
|
||||
// use solana_sdk::transaction::VersionedTransaction;
|
||||
|
||||
// use crate::convert::{proto_packet_from_versioned_tx, versioned_tx_from_packet};
|
||||
|
||||
// #[test]
|
||||
// fn test_proto_to_packet() {
|
||||
// let tx_before = VersionedTransaction::from(test_tx());
|
||||
// let tx_after = versioned_tx_from_packet(&proto_packet_from_versioned_tx(&tx_before))
|
||||
// .expect("tx_after");
|
||||
|
||||
// assert_eq!(tx_before, tx_after);
|
||||
// }
|
||||
// }
|
||||
Executable
+260
@@ -0,0 +1,260 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
// 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,
|
||||
}
|
||||
Executable
+462
@@ -0,0 +1,462 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+171
@@ -0,0 +1,171 @@
|
||||
// This file is @generated by prost-build.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Bundle {
|
||||
#[prost(message, optional, tag = "2")]
|
||||
pub header: ::core::option::Option<super::shared::Header>,
|
||||
#[prost(message, repeated, tag = "3")]
|
||||
pub packets: ::prost::alloc::vec::Vec<super::packet::Packet>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BundleUuid {
|
||||
#[prost(message, optional, tag = "1")]
|
||||
pub bundle: ::core::option::Option<Bundle>,
|
||||
#[prost(string, tag = "2")]
|
||||
pub uuid: ::prost::alloc::string::String,
|
||||
}
|
||||
/// Indicates the bundle was accepted and forwarded to a validator.
|
||||
/// NOTE: A single bundle may have multiple events emitted if forwarded to many validators.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Accepted {
|
||||
/// Slot at which bundle was forwarded.
|
||||
#[prost(uint64, tag = "1")]
|
||||
pub slot: u64,
|
||||
/// Validator identity bundle was forwarded to.
|
||||
#[prost(string, tag = "2")]
|
||||
pub validator_identity: ::prost::alloc::string::String,
|
||||
}
|
||||
/// Indicates the bundle was dropped and therefore not forwarded to any validator.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Rejected {
|
||||
#[prost(oneof = "rejected::Reason", tags = "1, 2, 3, 4, 5")]
|
||||
pub reason: ::core::option::Option<rejected::Reason>,
|
||||
}
|
||||
/// Nested message and enum types in `Rejected`.
|
||||
pub mod rejected {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Reason {
|
||||
#[prost(message, tag = "1")]
|
||||
StateAuctionBidRejected(super::StateAuctionBidRejected),
|
||||
#[prost(message, tag = "2")]
|
||||
WinningBatchBidRejected(super::WinningBatchBidRejected),
|
||||
#[prost(message, tag = "3")]
|
||||
SimulationFailure(super::SimulationFailure),
|
||||
#[prost(message, tag = "4")]
|
||||
InternalError(super::InternalError),
|
||||
#[prost(message, tag = "5")]
|
||||
DroppedBundle(super::DroppedBundle),
|
||||
}
|
||||
}
|
||||
/// Indicates the bundle's bid was high enough to win its state auction.
|
||||
/// However, not high enough relative to other state auction winners and therefore excluded from being forwarded.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct WinningBatchBidRejected {
|
||||
/// Auction's unique identifier.
|
||||
#[prost(string, tag = "1")]
|
||||
pub auction_id: ::prost::alloc::string::String,
|
||||
/// Bundle's simulated bid.
|
||||
#[prost(uint64, tag = "2")]
|
||||
pub simulated_bid_lamports: u64,
|
||||
#[prost(string, optional, tag = "3")]
|
||||
pub msg: ::core::option::Option<::prost::alloc::string::String>,
|
||||
}
|
||||
/// Indicates the bundle's bid was __not__ high enough to be included in its state auction's set of winners.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StateAuctionBidRejected {
|
||||
/// Auction's unique identifier.
|
||||
#[prost(string, tag = "1")]
|
||||
pub auction_id: ::prost::alloc::string::String,
|
||||
/// Bundle's simulated bid.
|
||||
#[prost(uint64, tag = "2")]
|
||||
pub simulated_bid_lamports: u64,
|
||||
#[prost(string, optional, tag = "3")]
|
||||
pub msg: ::core::option::Option<::prost::alloc::string::String>,
|
||||
}
|
||||
/// Bundle dropped due to simulation failure.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SimulationFailure {
|
||||
/// Signature of the offending transaction.
|
||||
#[prost(string, tag = "1")]
|
||||
pub tx_signature: ::prost::alloc::string::String,
|
||||
#[prost(string, optional, tag = "2")]
|
||||
pub msg: ::core::option::Option<::prost::alloc::string::String>,
|
||||
}
|
||||
/// Bundle dropped due to an internal error.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct InternalError {
|
||||
#[prost(string, tag = "1")]
|
||||
pub msg: ::prost::alloc::string::String,
|
||||
}
|
||||
/// Bundle dropped (e.g. because no leader upcoming)
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DroppedBundle {
|
||||
#[prost(string, tag = "1")]
|
||||
pub msg: ::prost::alloc::string::String,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct Finalized {}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Processed {
|
||||
#[prost(string, tag = "1")]
|
||||
pub validator_identity: ::prost::alloc::string::String,
|
||||
#[prost(uint64, tag = "2")]
|
||||
pub slot: u64,
|
||||
/// / Index within the block.
|
||||
#[prost(uint64, tag = "3")]
|
||||
pub bundle_index: u64,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct Dropped {
|
||||
#[prost(enumeration = "DroppedReason", tag = "1")]
|
||||
pub reason: i32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BundleResult {
|
||||
/// Bundle's Uuid.
|
||||
#[prost(string, tag = "1")]
|
||||
pub bundle_id: ::prost::alloc::string::String,
|
||||
#[prost(oneof = "bundle_result::Result", tags = "2, 3, 4, 5, 6")]
|
||||
pub result: ::core::option::Option<bundle_result::Result>,
|
||||
}
|
||||
/// Nested message and enum types in `BundleResult`.
|
||||
pub mod bundle_result {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Result {
|
||||
/// Indicated accepted by the block-engine and forwarded to a jito-solana validator.
|
||||
#[prost(message, tag = "2")]
|
||||
Accepted(super::Accepted),
|
||||
/// Rejected by the block-engine.
|
||||
#[prost(message, tag = "3")]
|
||||
Rejected(super::Rejected),
|
||||
/// Reached finalized commitment level.
|
||||
#[prost(message, tag = "4")]
|
||||
Finalized(super::Finalized),
|
||||
/// Reached a processed commitment level.
|
||||
#[prost(message, tag = "5")]
|
||||
Processed(super::Processed),
|
||||
/// Was accepted and forwarded by the block-engine but never landed on-chain.
|
||||
#[prost(message, tag = "6")]
|
||||
Dropped(super::Dropped),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum DroppedReason {
|
||||
BlockhashExpired = 0,
|
||||
/// One or more transactions in the bundle landed on-chain, invalidating the bundle.
|
||||
PartiallyProcessed = 1,
|
||||
/// This indicates bundle was processed but not finalized. This could occur during forks.
|
||||
NotFinalized = 2,
|
||||
}
|
||||
impl DroppedReason {
|
||||
/// 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::BlockhashExpired => "BlockhashExpired",
|
||||
Self::PartiallyProcessed => "PartiallyProcessed",
|
||||
Self::NotFinalized => "NotFinalized",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
pub fn from_str_name(value: &str) -> ::core::option::Option<Self> {
|
||||
match value {
|
||||
"BlockhashExpired" => Some(Self::BlockhashExpired),
|
||||
"PartiallyProcessed" => Some(Self::PartiallyProcessed),
|
||||
"NotFinalized" => Some(Self::NotFinalized),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+10
@@ -0,0 +1,10 @@
|
||||
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;
|
||||
Executable
+41
@@ -0,0 +1,41 @@
|
||||
// This file is @generated by prost-build.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PacketBatch {
|
||||
#[prost(message, repeated, tag = "1")]
|
||||
pub packets: ::prost::alloc::vec::Vec<Packet>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Packet {
|
||||
#[prost(bytes = "vec", tag = "1")]
|
||||
pub data: ::prost::alloc::vec::Vec<u8>,
|
||||
#[prost(message, optional, tag = "2")]
|
||||
pub meta: ::core::option::Option<Meta>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Meta {
|
||||
#[prost(uint64, tag = "1")]
|
||||
pub size: u64,
|
||||
#[prost(string, tag = "2")]
|
||||
pub addr: ::prost::alloc::string::String,
|
||||
#[prost(uint32, tag = "3")]
|
||||
pub port: u32,
|
||||
#[prost(message, optional, tag = "4")]
|
||||
pub flags: ::core::option::Option<PacketFlags>,
|
||||
#[prost(uint64, tag = "5")]
|
||||
pub sender_stake: u64,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct PacketFlags {
|
||||
#[prost(bool, tag = "1")]
|
||||
pub discard: bool,
|
||||
#[prost(bool, tag = "2")]
|
||||
pub forwarded: bool,
|
||||
#[prost(bool, tag = "3")]
|
||||
pub repair: bool,
|
||||
#[prost(bool, tag = "4")]
|
||||
pub simple_vote_tx: bool,
|
||||
#[prost(bool, tag = "5")]
|
||||
pub tracer_packet: bool,
|
||||
#[prost(bool, tag = "6")]
|
||||
pub from_staked_node: bool,
|
||||
}
|
||||
Executable
+178
@@ -0,0 +1,178 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+363
@@ -0,0 +1,363 @@
|
||||
// This file is @generated by prost-build.
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SlotList {
|
||||
#[prost(uint64, repeated, tag = "1")]
|
||||
pub slots: ::prost::alloc::vec::Vec<u64>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ConnectedLeadersResponse {
|
||||
/// Mapping of validator pubkey to leader slots for the current epoch.
|
||||
#[prost(map = "string, message", tag = "1")]
|
||||
pub connected_validators: ::std::collections::HashMap<
|
||||
::prost::alloc::string::String,
|
||||
SlotList,
|
||||
>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SendBundleRequest {
|
||||
#[prost(message, optional, tag = "1")]
|
||||
pub bundle: ::core::option::Option<super::bundle::Bundle>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SendBundleResponse {
|
||||
/// server uuid for the bundle
|
||||
#[prost(string, tag = "1")]
|
||||
pub uuid: ::prost::alloc::string::String,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct NextScheduledLeaderRequest {
|
||||
/// Defaults to the currently connected region if no region provided.
|
||||
#[prost(string, repeated, tag = "1")]
|
||||
pub regions: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct NextScheduledLeaderResponse {
|
||||
/// the current slot the backend is on
|
||||
#[prost(uint64, tag = "1")]
|
||||
pub current_slot: u64,
|
||||
/// the slot of the next leader
|
||||
#[prost(uint64, tag = "2")]
|
||||
pub next_leader_slot: u64,
|
||||
/// the identity pubkey (base58) of the next leader
|
||||
#[prost(string, tag = "3")]
|
||||
pub next_leader_identity: ::prost::alloc::string::String,
|
||||
/// the block engine region of the next leader
|
||||
#[prost(string, tag = "4")]
|
||||
pub next_leader_region: ::prost::alloc::string::String,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct ConnectedLeadersRequest {}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ConnectedLeadersRegionedRequest {
|
||||
/// Defaults to the currently connected region if no region provided.
|
||||
#[prost(string, repeated, tag = "1")]
|
||||
pub regions: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ConnectedLeadersRegionedResponse {
|
||||
#[prost(map = "string, message", tag = "1")]
|
||||
pub connected_validators: ::std::collections::HashMap<
|
||||
::prost::alloc::string::String,
|
||||
ConnectedLeadersResponse,
|
||||
>,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct GetTipAccountsRequest {}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetTipAccountsResponse {
|
||||
#[prost(string, repeated, tag = "1")]
|
||||
pub accounts: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct SubscribeBundleResultsRequest {}
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct GetRegionsRequest {}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetRegionsResponse {
|
||||
/// The region the client is currently connected to
|
||||
#[prost(string, tag = "1")]
|
||||
pub current_region: ::prost::alloc::string::String,
|
||||
/// Regions that are online and ready for connections
|
||||
/// All regions: <https://jito-labs.gitbook.io/mev/systems/connecting/mainnet>
|
||||
#[prost(string, repeated, tag = "2")]
|
||||
pub available_regions: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
|
||||
}
|
||||
/// Generated client implementations.
|
||||
pub mod searcher_service_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 SearcherServiceClient<T> {
|
||||
inner: tonic::client::Grpc<T>,
|
||||
}
|
||||
impl SearcherServiceClient<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> SearcherServiceClient<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,
|
||||
) -> SearcherServiceClient<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,
|
||||
{
|
||||
SearcherServiceClient::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
|
||||
}
|
||||
/// Searchers can invoke this endpoint to subscribe to their respective bundle results.
|
||||
/// A success result would indicate the bundle won its state auction and was submitted to the validator.
|
||||
pub async fn subscribe_bundle_results(
|
||||
&mut self,
|
||||
request: impl tonic::IntoRequest<super::SubscribeBundleResultsRequest>,
|
||||
) -> std::result::Result<
|
||||
tonic::Response<tonic::codec::Streaming<super::super::bundle::BundleResult>>,
|
||||
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(
|
||||
"/searcher.SearcherService/SubscribeBundleResults",
|
||||
);
|
||||
let mut req = request.into_request();
|
||||
req.extensions_mut()
|
||||
.insert(
|
||||
GrpcMethod::new("searcher.SearcherService", "SubscribeBundleResults"),
|
||||
);
|
||||
self.inner.server_streaming(req, path, codec).await
|
||||
}
|
||||
pub async fn send_bundle(
|
||||
&mut self,
|
||||
request: impl tonic::IntoRequest<super::SendBundleRequest>,
|
||||
) -> std::result::Result<
|
||||
tonic::Response<super::SendBundleResponse>,
|
||||
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(
|
||||
"/searcher.SearcherService/SendBundle",
|
||||
);
|
||||
let mut req = request.into_request();
|
||||
req.extensions_mut()
|
||||
.insert(GrpcMethod::new("searcher.SearcherService", "SendBundle"));
|
||||
self.inner.unary(req, path, codec).await
|
||||
}
|
||||
/// Returns the next scheduled leader connected to the block engine.
|
||||
pub async fn get_next_scheduled_leader(
|
||||
&mut self,
|
||||
request: impl tonic::IntoRequest<super::NextScheduledLeaderRequest>,
|
||||
) -> std::result::Result<
|
||||
tonic::Response<super::NextScheduledLeaderResponse>,
|
||||
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(
|
||||
"/searcher.SearcherService/GetNextScheduledLeader",
|
||||
);
|
||||
let mut req = request.into_request();
|
||||
req.extensions_mut()
|
||||
.insert(
|
||||
GrpcMethod::new("searcher.SearcherService", "GetNextScheduledLeader"),
|
||||
);
|
||||
self.inner.unary(req, path, codec).await
|
||||
}
|
||||
/// Returns leader slots for connected jito validators during the current epoch. Only returns data for this region.
|
||||
pub async fn get_connected_leaders(
|
||||
&mut self,
|
||||
request: impl tonic::IntoRequest<super::ConnectedLeadersRequest>,
|
||||
) -> std::result::Result<
|
||||
tonic::Response<super::ConnectedLeadersResponse>,
|
||||
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(
|
||||
"/searcher.SearcherService/GetConnectedLeaders",
|
||||
);
|
||||
let mut req = request.into_request();
|
||||
req.extensions_mut()
|
||||
.insert(
|
||||
GrpcMethod::new("searcher.SearcherService", "GetConnectedLeaders"),
|
||||
);
|
||||
self.inner.unary(req, path, codec).await
|
||||
}
|
||||
/// Returns leader slots for connected jito validators during the current epoch.
|
||||
pub async fn get_connected_leaders_regioned(
|
||||
&mut self,
|
||||
request: impl tonic::IntoRequest<super::ConnectedLeadersRegionedRequest>,
|
||||
) -> std::result::Result<
|
||||
tonic::Response<super::ConnectedLeadersRegionedResponse>,
|
||||
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(
|
||||
"/searcher.SearcherService/GetConnectedLeadersRegioned",
|
||||
);
|
||||
let mut req = request.into_request();
|
||||
req.extensions_mut()
|
||||
.insert(
|
||||
GrpcMethod::new(
|
||||
"searcher.SearcherService",
|
||||
"GetConnectedLeadersRegioned",
|
||||
),
|
||||
);
|
||||
self.inner.unary(req, path, codec).await
|
||||
}
|
||||
/// Returns the tip accounts searchers shall transfer funds to for the leader to claim.
|
||||
pub async fn get_tip_accounts(
|
||||
&mut self,
|
||||
request: impl tonic::IntoRequest<super::GetTipAccountsRequest>,
|
||||
) -> std::result::Result<
|
||||
tonic::Response<super::GetTipAccountsResponse>,
|
||||
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(
|
||||
"/searcher.SearcherService/GetTipAccounts",
|
||||
);
|
||||
let mut req = request.into_request();
|
||||
req.extensions_mut()
|
||||
.insert(GrpcMethod::new("searcher.SearcherService", "GetTipAccounts"));
|
||||
self.inner.unary(req, path, codec).await
|
||||
}
|
||||
/// Returns region the client is directly connected to, along with all available regions
|
||||
pub async fn get_regions(
|
||||
&mut self,
|
||||
request: impl tonic::IntoRequest<super::GetRegionsRequest>,
|
||||
) -> std::result::Result<
|
||||
tonic::Response<super::GetRegionsResponse>,
|
||||
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(
|
||||
"/searcher.SearcherService/GetRegions",
|
||||
);
|
||||
let mut req = request.into_request();
|
||||
req.extensions_mut()
|
||||
.insert(GrpcMethod::new("searcher.SearcherService", "GetRegions"));
|
||||
self.inner.unary(req, path, codec).await
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
// This file is @generated by prost-build.
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct Header {
|
||||
#[prost(message, optional, tag = "1")]
|
||||
pub ts: ::core::option::Option<::prost_types::Timestamp>,
|
||||
}
|
||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
||||
pub struct Heartbeat {
|
||||
#[prost(uint64, tag = "1")]
|
||||
pub count: u64,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Socket {
|
||||
#[prost(string, tag = "1")]
|
||||
pub ip: ::prost::alloc::string::String,
|
||||
#[prost(int64, tag = "2")]
|
||||
pub port: i64,
|
||||
}
|
||||
Executable
+136
@@ -0,0 +1,136 @@
|
||||
// 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
// 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,
|
||||
}
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
pub mod convert;
|
||||
pub mod grpc;
|
||||
pub use grpc::*;
|
||||
Reference in New Issue
Block a user