mirror of
https://github.com/0xfnzero/solana-streamer.git
synced 2026-08-24 22:38:08 +00:00
add nextblock, 0slot support
This commit is contained in:
Executable
+17
@@ -0,0 +1,17 @@
|
||||
[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"
|
||||
Executable
+56
@@ -0,0 +1,56 @@
|
||||
# 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.
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
|
||||
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();
|
||||
}
|
||||
Executable
+245
@@ -0,0 +1,245 @@
|
||||
# JSON RPC HTTP Methods
|
||||
|
||||
The block engine accepts HTTP requests using the [JSON-RPC 2.0](https://www.jsonrpc.org/specification) specification.
|
||||
|
||||
## RPC HTTP Endpoint
|
||||
|
||||
**Default port:** 443 e.g. [https://mainnet.block-engine.jito.wtf:443/api/v1/bundles](https://mainnet.block-engine.jito.wtf:443/api/v1/bundles), [https://{REGION}.mainnet.block-engine.jito.wtf:443/api/v1/bundles](https://${REGION}.mainnet.block-engine.jito.wtf:443/api/v1/bundles)
|
||||
|
||||
## Request Formatting
|
||||
|
||||
To make a JSON-RPC request, send an HTTP POST request with a `Content-Type: application/json` header. The JSON request data should contain 4 fields:
|
||||
|
||||
- `jsonrpc`: `string` - set to "2.0"
|
||||
- `id`: `number` - a unique client-generated identifying integer
|
||||
- `method`: `string` - a string containing the method to be invoked
|
||||
- `params`: `array` - a JSON array of ordered parameter values
|
||||
|
||||
We follow the same request formatting as Solana json rpc requests. You can find the documentation [here](https://docs.solana.com/api/http#request-formatting)
|
||||
|
||||
## Authorization
|
||||
|
||||
In the short-term we don't require authentication to send the requests.
|
||||
|
||||
If there are any changes to the authentication mechanism it would be updated in the document and communicated with all the stakeholders.
|
||||
|
||||
## Definitions
|
||||
|
||||
- Bundle: Bundles are a list of transactions that execute sequentially and atomically. “All or nothing” so to speak. This means that a user can send a bundle that contains multiple transactions and guarantee that they are all executed one after the other and the bundle succeeds only if all individual transactions succeed.
|
||||
- Hash: A SHA-256 hash of a chunk of data.
|
||||
- Pubkey: The public key of a Ed25519 key-pair.
|
||||
- Tip Account: List of accounts to which a tip can be paid for processing the bundles. Clients submitting bundles must pay a tip for bundle processing.
|
||||
- Transaction: A list of Solana instructions signed by a client keypair to authorize those actions.
|
||||
- Signature: An Ed25519 signature of transaction's payload data including instructions. This can be used to identify transactions.
|
||||
|
||||
## State Commitment
|
||||
|
||||
The commitment describes how finalized a block is at that point in time.
|
||||
|
||||
In descending order of commitment (most finalized to least finalized), these are the commitment levels:
|
||||
|
||||
- `"finalized"` - the node will query the most recent block confirmed by supermajority
|
||||
of the cluster as having reached maximum lockout, meaning the cluster has
|
||||
recognized this block as finalized
|
||||
- `"confirmed"` - the node will query the most recent block that has been voted on by supermajority of the cluster.
|
||||
- It incorporates votes from gossip and replay.
|
||||
- It does not count votes on descendants of a block, only direct votes on that block.
|
||||
- This confirmation level also upholds "optimistic confirmation" guarantees in
|
||||
release 1.3 and onwards.
|
||||
- `"processed"` - the node will query its most recent block. Note that the block
|
||||
may still be skipped by the cluster.
|
||||
|
||||
Please refer to [configuring-state-commitment](https://docs.solana.com/api/http#configuring-state-commitment) for more details.
|
||||
|
||||
#### RpcResponse Structure
|
||||
|
||||
Many methods that take a commitment parameter return an RpcResponse JSON object comprised of two parts:
|
||||
|
||||
- `context` : An RpcResponseContext JSON structure including a `slot` field at which the operation was evaluated. example:
|
||||
|
||||
```json
|
||||
"context": {
|
||||
"slot": 1
|
||||
},
|
||||
```
|
||||
|
||||
- `value` : The value returned by the operation itself. example:
|
||||
|
||||
```json
|
||||
"value": [
|
||||
{
|
||||
"bundle": {
|
||||
"signatures": [
|
||||
"3Eq21vXNB5s86c62bVuUfTeaMif1N2kUqRPBmGRJhyTA",
|
||||
"2nBhEBYYvfaAe16UMNqRHre4YNSskvuYgx3M6E4JP1oDYvZEJHvoPzyUidNgNX5r9sTyN1J9UxtbCXy2rqYcuyuv"
|
||||
]
|
||||
},
|
||||
"slot": 1234,
|
||||
"confirmationStatus": "finalized",
|
||||
"err": "null"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## JSON RPC API Reference
|
||||
|
||||
## getTipAccounts
|
||||
|
||||
Returns the tip accounts for tip payment for the bundles.
|
||||
|
||||
### Parameters
|
||||
|
||||
None
|
||||
|
||||
### Result
|
||||
|
||||
The result field will be a JSON object with the following fields:
|
||||
|
||||
- `result`: `<array>` - Tip accounts as a list of `strings`
|
||||
|
||||
### Code sample
|
||||
|
||||
#### Request
|
||||
|
||||
```bash
|
||||
curl https://mainnet.block-engine.jito.wtf:443/api/v1/bundles -X POST -H "Content-Type: application/json" -d '
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "getTipAccounts",
|
||||
"params": []
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"result": [
|
||||
"9n3d1K5YD2vECAbRFhFFGYNNjiXtHXJWn9F31t89vsAV",
|
||||
"aTtUk2DHgLhKZRDjePq6eiHRKC1XXFMBiSUfQ2JNDbN",
|
||||
"B1mrQSpdeMU9gCvkJ6VsXVVoYjRGkNA7TtjMyqxrhecH",
|
||||
"9ttgPBBhRYFuQccdR1DSnb7hydsWANoDsV3P9kaGMCEh",
|
||||
"4xgEmT58RwTNsF5xm2RMYCnR1EVukdK8a1i2qFjnJFu3",
|
||||
"EoW3SUQap7ZeynXQ2QJ847aerhxbPVr843uMeTfc9dxM",
|
||||
"E2eSqe33tuhAHKTrwky5uEjaVqnb2T9ns6nHHUrN8588",
|
||||
"ARTtviJkLLt6cHGQDydfo1Wyk6M4VGZdKZ2ZhdnJL336"
|
||||
],
|
||||
"id": 1
|
||||
}
|
||||
```
|
||||
|
||||
## sendBundle
|
||||
|
||||
Submits a bundled list of signed transaction(s) (base-58 encoded string) to the cluster for processing. The transactions will be atomically processed in order, meaning if any of the transactions fail, the entire bundle won’t be processed (all or nothing). This method does not alter the transaction in any way; it relays the bundle created by clients to the leader as-is. If the bundle is not set to expire before the next upcoming Jito-Solana leader, this method will immediately return a success response acknowledging that the bundle has been received with a bundle_id. This does not guarantee the bundle is processed or landed on-chain. For the bundle status regarding whether it landed or not, getBundleStatuses should be used with the bundle id
|
||||
|
||||
Please note that a tip is necessary for the bundle to considered. A tip can be any instruction, top-level or CPI, that transfers SOL to one of the 8 tip accounts. Clients should make sure they have balance and state assertions that allow the tip to only go thru conditionally, especially if tipping as a separate tx. If the tip is low, there is a chance that the bundle does not get selected during the auction. You can get the tip accounts using [getTipAccounts](#gettipaccounts). Ideally select one of the accounts in random to reduce contention.
|
||||
|
||||
### Parameters
|
||||
|
||||
`<array[string]>`: `required` Fully-signed Transactions, as encoded string (base-58) upto a maximum of 5. Please note that at this point, we don't support base-64 encoded transactions
|
||||
|
||||
### Result
|
||||
|
||||
The result field will be a JSON object with the following fields:
|
||||
|
||||
- `result`: `<string>` - A bundle id, used to identify the bundle. This is the Sha256 hashes of the bundle's tx signatures.
|
||||
|
||||
### Code sample
|
||||
|
||||
#### Request
|
||||
|
||||
```bash
|
||||
curl https://mainnet.block-engine.jito.wtf:443/api/v1/bundles -X POST -H "Content-Type: application/json" -d '
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "sendBundle",
|
||||
"params": [
|
||||
[
|
||||
"4VbvoRYXFaXzDBUYfMXP1irhMZ9XRE6F1keS8GbYzKxgdpEasZtRv6GXxbygPp3yBVeSR4wN9JEauSTnVTKjuq3ktM3JpMebYpdGxZWUttJv9N2DzxBm4vhySdq2hbu1LQX7WxS2xsHG6vNwVCjP33Z2ZLP7S5dZujcan1Xq5Z2HibbbK3M3LD59QVuczyK44Fe3k27kVQ43oRH5L7KgpUS1vBoqTd9ZTzC32H62WPHJeLrQiNkmSB668FivXBAfMg13Svgiu9E",
|
||||
"6HZu11s3SDBz5ytDj1tyBuoeUnwa1wPoKvq6ffivmfhTGahe3xvGpizJkofHCeDn1UgPN8sLABueKE326aGLXkn5yQyrrpuRF9q1TPZqqBMzcDvoJS1khPBprxnXcxNhMUbV78cS2R8LrCU29wjYk5b4JpVtF23ys4ZBZoNZKmPekAW9odcPVXb9HoMnWvx8xwqd7GsVB56R343vAX6HGUMoiB1WgR9jznG655WiXQTff5gPsCP3QJFTXC7iYEYtrcA3dUeZ3q4YK9ipdYZsgAS9H46i9dhDP2Zx3"
|
||||
]
|
||||
]
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
#### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"result": "2id3YC2jK9G5Wo2phDx4gJVAew8DcY5NAojnVuao8rkxwPYPe8cSwE5GzhEgJA2y8fVjDEo6iR6ykBvDxrTQrtpb",
|
||||
"id": 1
|
||||
}
|
||||
```
|
||||
|
||||
## getBundleStatuses
|
||||
|
||||
Returns bundle statuses for submitted bundle(s). The behavior is similar to the solana rpc method [getSignatureStatuses](https://docs.solana.com/api/http#getsignaturestatuses). If the bundle_id is not found or if the bundle has not landed, we return null. If found and landed, we return the context information including the slot at which the request was made and result with the bundle_id(s) and the transactions with the slot and confirmation status.
|
||||
|
||||
### Parameters
|
||||
|
||||
- `<array[string]>`: `required` An array of bundle ids to confirm, as base-58 encoded strings (up to a maximum of 5).
|
||||
|
||||
### Result
|
||||
|
||||
An array of RpcResponse`<object>` consisting of either:
|
||||
|
||||
- `<null>`: If the bundle is not found.
|
||||
- `<object>`: If the bundle is found, an array of objects with the following fields:
|
||||
- `bundle_id`: `<String>` Bundle id
|
||||
- `transactions`: `<array[string]>` - A list of base-58 encoded signatures applied by the bundle. The list will not be empty.
|
||||
- `slot`: `<u64>` The slot this bundle was processed in.
|
||||
- `confirmationStatus`: `<string|null>` - The bundle transaction's cluster confirmation status; Either processed, confirmed, or finalized. See [Commitment](#state-commitment) for more on optimistic confirmation.
|
||||
- `err`: `<object|null>`: This will show any retryable or non-retryable error encountered when getting the bundle status. If retryable, please query again
|
||||
|
||||
### Code sample
|
||||
|
||||
### Request
|
||||
|
||||
```bash
|
||||
curl https://mainnet.block-engine.jito.wtf:443/api/v1/bundles -X POST -H "Content-Type: application/json" -d '
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "getBundleStatuses",
|
||||
"params": [
|
||||
[
|
||||
"892b79ed49138bfb3aa5441f0df6e06ef34f9ee8f3976c15b323605bae0cf51d"
|
||||
]
|
||||
]
|
||||
}
|
||||
'
|
||||
```
|
||||
|
||||
### Response
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"result": {
|
||||
"context": {
|
||||
"slot": 242806119
|
||||
},
|
||||
"value": [
|
||||
{
|
||||
"bundle_id": "892b79ed49138bfb3aa5441f0df6e06ef34f9ee8f3976c15b323605bae0cf51d",
|
||||
"transactions": [
|
||||
"3bC2M9fiACSjkTXZDgeNAuQ4ScTsdKGwR42ytFdhUvikqTmBheUxfsR1fDVsM5ADCMMspuwGkdm1uKbU246x5aE3",
|
||||
"8t9hKYEYNbLvNqiSzP96S13XF1C2f1ro271Kdf7bkZ6EpjPLuDff1ywRy4gfaGSTubsM2FeYGDoT64ZwPm1cQUt"
|
||||
],
|
||||
"slot": 242804011,
|
||||
"confirmation_status": "finalized",
|
||||
"err": {
|
||||
"Ok": null
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": 1
|
||||
}
|
||||
```
|
||||
Executable
+76
@@ -0,0 +1,76 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package auth;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
enum Role {
|
||||
RELAYER = 0;
|
||||
SEARCHER = 1;
|
||||
VALIDATOR = 2;
|
||||
SHREDSTREAM_SUBSCRIBER = 3;
|
||||
}
|
||||
|
||||
message GenerateAuthChallengeRequest {
|
||||
/// Role the client is attempting to generate tokens for.
|
||||
Role role = 1;
|
||||
|
||||
/// Client's 32 byte pubkey.
|
||||
bytes pubkey = 2;
|
||||
}
|
||||
|
||||
message GenerateAuthChallengeResponse {
|
||||
string challenge = 1;
|
||||
}
|
||||
|
||||
message GenerateAuthTokensRequest {
|
||||
/// The pre-signed challenge.
|
||||
string challenge = 1;
|
||||
|
||||
/// The signing keypair's corresponding 32 byte pubkey.
|
||||
bytes client_pubkey = 2;
|
||||
|
||||
/// 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).
|
||||
bytes signed_challenge = 3;
|
||||
}
|
||||
|
||||
message Token {
|
||||
/// The token.
|
||||
string value = 1;
|
||||
|
||||
/// When the token will expire.
|
||||
google.protobuf.Timestamp expires_at_utc = 2;
|
||||
}
|
||||
|
||||
message GenerateAuthTokensResponse {
|
||||
/// The token granting access to resources.
|
||||
Token access_token = 1;
|
||||
|
||||
/// The token used to refresh the access_token. This has a longer TTL than the access_token.
|
||||
Token refresh_token = 2;
|
||||
}
|
||||
|
||||
message RefreshAccessTokenRequest {
|
||||
/// Non-expired refresh token obtained from the [GenerateAuthTokens] method.
|
||||
string refresh_token = 1;
|
||||
}
|
||||
|
||||
message RefreshAccessTokenResponse {
|
||||
/// Fresh access_token.
|
||||
Token access_token = 1;
|
||||
}
|
||||
|
||||
/// This service is responsible for issuing auth tokens to clients for API access.
|
||||
service AuthService {
|
||||
/// Returns a challenge, client is expected to sign this challenge with an appropriate keypair in order to obtain access tokens.
|
||||
rpc GenerateAuthChallenge(GenerateAuthChallengeRequest) returns (GenerateAuthChallengeResponse) {}
|
||||
|
||||
/// Provides the client with the initial pair of auth tokens for API access.
|
||||
rpc GenerateAuthTokens(GenerateAuthTokensRequest) returns (GenerateAuthTokensResponse) {}
|
||||
|
||||
/// Call this method with a non-expired refresh token to obtain a new access token.
|
||||
rpc RefreshAccessToken(RefreshAccessTokenRequest) returns (RefreshAccessTokenResponse) {}
|
||||
}
|
||||
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package block;
|
||||
import "shared.proto";
|
||||
|
||||
// Condensed block helpful for getting data around efficiently internal to our system.
|
||||
message CondensedBlock {
|
||||
shared.Header header = 1;
|
||||
string previous_blockhash = 2;
|
||||
string blockhash = 3;
|
||||
uint64 parent_slot = 4;
|
||||
repeated bytes versioned_transactions = 5;
|
||||
uint64 slot = 6;
|
||||
string commitment = 7;
|
||||
}
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "packet.proto";
|
||||
import "shared.proto";
|
||||
import "bundle.proto";
|
||||
|
||||
package block_engine;
|
||||
|
||||
message SubscribePacketsRequest {}
|
||||
message SubscribePacketsResponse {
|
||||
shared.Header header = 1;
|
||||
packet.PacketBatch batch = 2;
|
||||
}
|
||||
|
||||
message SubscribeBundlesRequest {}
|
||||
message SubscribeBundlesResponse {
|
||||
repeated bundle.BundleUuid bundles = 1;
|
||||
}
|
||||
|
||||
message BlockBuilderFeeInfoRequest {}
|
||||
message BlockBuilderFeeInfoResponse {
|
||||
string pubkey = 1;
|
||||
|
||||
// commission (0-100)
|
||||
uint64 commission = 2;
|
||||
}
|
||||
|
||||
message AccountsOfInterest {
|
||||
// use * for all accounts
|
||||
repeated string accounts = 1;
|
||||
}
|
||||
|
||||
message AccountsOfInterestRequest {}
|
||||
message AccountsOfInterestUpdate {
|
||||
repeated string accounts = 1;
|
||||
}
|
||||
|
||||
message ProgramsOfInterestRequest {}
|
||||
message ProgramsOfInterestUpdate {
|
||||
repeated string programs = 1;
|
||||
}
|
||||
|
||||
// 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.
|
||||
message ExpiringPacketBatch {
|
||||
shared.Header header = 1;
|
||||
packet.PacketBatch batch = 2;
|
||||
uint32 expiry_ms = 3;
|
||||
}
|
||||
|
||||
// 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.
|
||||
message PacketBatchUpdate {
|
||||
oneof msg {
|
||||
ExpiringPacketBatch batches = 1;
|
||||
shared.Heartbeat heartbeat = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message StartExpiringPacketStreamResponse {
|
||||
shared.Heartbeat heartbeat = 1;
|
||||
}
|
||||
|
||||
/// Validators can connect to Block Engines to receive packets and bundles.
|
||||
service BlockEngineValidator {
|
||||
/// Validators can subscribe to the block engine to receive a stream of packets
|
||||
rpc SubscribePackets (SubscribePacketsRequest) returns (stream SubscribePacketsResponse) {}
|
||||
|
||||
/// Validators can subscribe to the block engine to receive a stream of simulated and profitable bundles
|
||||
rpc SubscribeBundles (SubscribeBundlesRequest) returns (stream SubscribeBundlesResponse) {}
|
||||
|
||||
// Block builders can optionally collect fees. This returns fee information if a block builder wants to
|
||||
// collect one.
|
||||
rpc GetBlockBuilderFeeInfo (BlockBuilderFeeInfoRequest) returns (BlockBuilderFeeInfoResponse) {}
|
||||
}
|
||||
|
||||
/// Relayers can forward packets to Block Engines.
|
||||
/// Block Engines provide an AccountsOfInterest field to only send transactions that are of interest.
|
||||
service BlockEngineRelayer {
|
||||
/// 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.
|
||||
rpc SubscribeAccountsOfInterest (AccountsOfInterestRequest) returns (stream AccountsOfInterestUpdate) {}
|
||||
|
||||
rpc SubscribeProgramsOfInterest (ProgramsOfInterestRequest) returns (stream ProgramsOfInterestUpdate) {}
|
||||
|
||||
// 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.
|
||||
rpc StartExpiringPacketStream (stream PacketBatchUpdate) returns (stream StartExpiringPacketStreamResponse) {}
|
||||
}
|
||||
Executable
+111
@@ -0,0 +1,111 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "packet.proto";
|
||||
import "shared.proto";
|
||||
|
||||
package bundle;
|
||||
|
||||
message Bundle {
|
||||
shared.Header header = 2;
|
||||
repeated packet.Packet packets = 3;
|
||||
}
|
||||
|
||||
message BundleUuid {
|
||||
bundle.Bundle bundle = 1;
|
||||
string uuid = 2;
|
||||
}
|
||||
|
||||
/* Bundle Result Types */
|
||||
|
||||
// Indicates the bundle was accepted and forwarded to a validator.
|
||||
// NOTE: A single bundle may have multiple events emitted if forwarded to many validators.
|
||||
message Accepted {
|
||||
// Slot at which bundle was forwarded.
|
||||
uint64 slot = 1;
|
||||
|
||||
// Validator identity bundle was forwarded to.
|
||||
string validator_identity = 2;
|
||||
}
|
||||
|
||||
// Indicates the bundle was dropped and therefore not forwarded to any validator.
|
||||
message Rejected {
|
||||
oneof reason {
|
||||
StateAuctionBidRejected state_auction_bid_rejected = 1;
|
||||
WinningBatchBidRejected winning_batch_bid_rejected = 2;
|
||||
SimulationFailure simulation_failure = 3;
|
||||
InternalError internal_error = 4;
|
||||
DroppedBundle dropped_bundle = 5;
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
message WinningBatchBidRejected {
|
||||
// Auction's unique identifier.
|
||||
string auction_id = 1;
|
||||
// Bundle's simulated bid.
|
||||
uint64 simulated_bid_lamports = 2;
|
||||
optional string msg = 3;
|
||||
}
|
||||
|
||||
// Indicates the bundle's bid was __not__ high enough to be included in its state auction's set of winners.
|
||||
message StateAuctionBidRejected {
|
||||
// Auction's unique identifier.
|
||||
string auction_id = 1;
|
||||
// Bundle's simulated bid.
|
||||
uint64 simulated_bid_lamports = 2;
|
||||
optional string msg = 3;
|
||||
}
|
||||
|
||||
// Bundle dropped due to simulation failure.
|
||||
message SimulationFailure {
|
||||
// Signature of the offending transaction.
|
||||
string tx_signature = 1;
|
||||
optional string msg = 2;
|
||||
}
|
||||
|
||||
// Bundle dropped due to an internal error.
|
||||
message InternalError {
|
||||
string msg = 1;
|
||||
}
|
||||
|
||||
// Bundle dropped (e.g. because no leader upcoming)
|
||||
message DroppedBundle {
|
||||
string msg = 1;
|
||||
}
|
||||
|
||||
message Finalized {}
|
||||
message Processed {
|
||||
string validator_identity = 1;
|
||||
uint64 slot = 2;
|
||||
/// Index within the block.
|
||||
uint64 bundle_index = 3;
|
||||
}
|
||||
message Dropped {
|
||||
DroppedReason reason = 1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
message BundleResult {
|
||||
// Bundle's Uuid.
|
||||
string bundle_id = 1;
|
||||
|
||||
oneof result {
|
||||
// Indicated accepted by the block-engine and forwarded to a jito-solana validator.
|
||||
Accepted accepted = 2;
|
||||
// Rejected by the block-engine.
|
||||
Rejected rejected = 3;
|
||||
// Reached finalized commitment level.
|
||||
Finalized finalized = 4;
|
||||
// Reached a processed commitment level.
|
||||
Processed processed = 5;
|
||||
// Was accepted and forwarded by the block-engine but never landed on-chain.
|
||||
Dropped dropped = 6;
|
||||
}
|
||||
}
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package packet;
|
||||
|
||||
message PacketBatch {
|
||||
repeated Packet packets = 1;
|
||||
}
|
||||
|
||||
message Packet {
|
||||
bytes data = 1;
|
||||
Meta meta = 2;
|
||||
}
|
||||
|
||||
message Meta {
|
||||
uint64 size = 1;
|
||||
string addr = 2;
|
||||
uint32 port = 3;
|
||||
PacketFlags flags = 4;
|
||||
uint64 sender_stake = 5;
|
||||
}
|
||||
|
||||
message PacketFlags {
|
||||
bool discard = 1;
|
||||
bool forwarded = 2;
|
||||
bool repair = 3;
|
||||
bool simple_vote_tx = 4;
|
||||
bool tracer_packet = 5;
|
||||
bool from_staked_node = 6;
|
||||
}
|
||||
|
||||
Executable
+35
@@ -0,0 +1,35 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "packet.proto";
|
||||
import "shared.proto";
|
||||
|
||||
package relayer;
|
||||
|
||||
message GetTpuConfigsRequest {}
|
||||
message GetTpuConfigsResponse {
|
||||
shared.Socket tpu = 1;
|
||||
shared.Socket tpu_forward = 2;
|
||||
}
|
||||
|
||||
message SubscribePacketsRequest {}
|
||||
message SubscribePacketsResponse {
|
||||
shared.Header header = 1;
|
||||
oneof msg {
|
||||
shared.Heartbeat heartbeat = 2;
|
||||
packet.PacketBatch batch = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/// 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
|
||||
service Relayer {
|
||||
// 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.
|
||||
rpc GetTpuConfigs (GetTpuConfigsRequest) returns (GetTpuConfigsResponse) {}
|
||||
|
||||
// Validators can subscribe to packets from the relayer and receive a multiplexed signal that contains a mixture
|
||||
// of packets and heartbeats
|
||||
rpc SubscribePackets (SubscribePacketsRequest) returns (stream SubscribePacketsResponse) {}
|
||||
}
|
||||
Executable
+92
@@ -0,0 +1,92 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package searcher;
|
||||
|
||||
import "bundle.proto";
|
||||
|
||||
message SlotList {
|
||||
repeated uint64 slots = 1;
|
||||
}
|
||||
|
||||
message ConnectedLeadersResponse {
|
||||
// Mapping of validator pubkey to leader slots for the current epoch.
|
||||
map<string /* validator pubkey */, SlotList> connected_validators = 1;
|
||||
}
|
||||
|
||||
message SendBundleRequest {
|
||||
bundle.Bundle bundle = 1;
|
||||
}
|
||||
|
||||
message SendBundleResponse {
|
||||
// server uuid for the bundle
|
||||
string uuid = 1;
|
||||
}
|
||||
|
||||
message NextScheduledLeaderRequest {
|
||||
// Defaults to the currently connected region if no region provided.
|
||||
repeated string regions = 1;
|
||||
}
|
||||
|
||||
message NextScheduledLeaderResponse {
|
||||
// the current slot the backend is on
|
||||
uint64 current_slot = 1;
|
||||
|
||||
// the slot of the next leader
|
||||
uint64 next_leader_slot = 2;
|
||||
// the identity pubkey (base58) of the next leader
|
||||
string next_leader_identity = 3;
|
||||
// the block engine region of the next leader
|
||||
string next_leader_region = 4;
|
||||
}
|
||||
|
||||
message ConnectedLeadersRequest {}
|
||||
|
||||
message ConnectedLeadersRegionedRequest {
|
||||
// Defaults to the currently connected region if no region provided.
|
||||
repeated string regions = 1;
|
||||
}
|
||||
message ConnectedLeadersRegionedResponse {
|
||||
map<string /* region */, ConnectedLeadersResponse> connected_validators = 1;
|
||||
}
|
||||
|
||||
|
||||
message GetTipAccountsRequest {}
|
||||
|
||||
message GetTipAccountsResponse {
|
||||
repeated string accounts = 1;
|
||||
}
|
||||
|
||||
message SubscribeBundleResultsRequest {}
|
||||
|
||||
message GetRegionsRequest {}
|
||||
message GetRegionsResponse {
|
||||
// The region the client is currently connected to
|
||||
string current_region = 1;
|
||||
|
||||
// Regions that are online and ready for connections
|
||||
// All regions: https://jito-labs.gitbook.io/mev/systems/connecting/mainnet
|
||||
repeated string available_regions = 2;
|
||||
}
|
||||
|
||||
service SearcherService {
|
||||
// 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.
|
||||
rpc SubscribeBundleResults (SubscribeBundleResultsRequest) returns (stream bundle.BundleResult) {}
|
||||
|
||||
rpc SendBundle (SendBundleRequest) returns (SendBundleResponse) {}
|
||||
|
||||
// Returns the next scheduled leader connected to the block engine.
|
||||
rpc GetNextScheduledLeader (NextScheduledLeaderRequest) returns (NextScheduledLeaderResponse) {}
|
||||
|
||||
// Returns leader slots for connected jito validators during the current epoch. Only returns data for this region.
|
||||
rpc GetConnectedLeaders (ConnectedLeadersRequest) returns (ConnectedLeadersResponse) {}
|
||||
|
||||
// Returns leader slots for connected jito validators during the current epoch.
|
||||
rpc GetConnectedLeadersRegioned (ConnectedLeadersRegionedRequest) returns (ConnectedLeadersRegionedResponse) {}
|
||||
|
||||
// Returns the tip accounts searchers shall transfer funds to for the leader to claim.
|
||||
rpc GetTipAccounts (GetTipAccountsRequest) returns (GetTipAccountsResponse) {}
|
||||
|
||||
// Returns region the client is directly connected to, along with all available regions
|
||||
rpc GetRegions (GetRegionsRequest) returns (GetRegionsResponse) {}
|
||||
}
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
syntax = "proto3";
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
package shared;
|
||||
|
||||
message Header {
|
||||
google.protobuf.Timestamp ts = 1;
|
||||
}
|
||||
|
||||
message Heartbeat {
|
||||
uint64 count = 1;
|
||||
}
|
||||
|
||||
message Socket {
|
||||
string ip = 1;
|
||||
int64 port = 2;
|
||||
}
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package shredstream;
|
||||
|
||||
import "shared.proto";
|
||||
|
||||
message 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
|
||||
shared.Socket socket = 1;
|
||||
|
||||
// regions for shredstream proxy to receive shreds from
|
||||
// list of valid regions: https://jito-labs.gitbook.io/mev/systems/connecting/mainnet
|
||||
repeated string regions = 2;
|
||||
}
|
||||
|
||||
message HeartbeatResponse {
|
||||
// client must respond within `ttl_ms` to keep stream alive
|
||||
uint32 ttl_ms = 1;
|
||||
}
|
||||
|
||||
service Shredstream {
|
||||
// RPC endpoint to send heartbeats to keep shreds flowing
|
||||
rpc SendHeartbeat (Heartbeat) returns (HeartbeatResponse) {}
|
||||
}
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package trace_shred;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
message TraceShred {
|
||||
// source region, one of: https://jito-labs.gitbook.io/mev/systems/connecting/mainnet
|
||||
string region = 1;
|
||||
// timestamp of creation
|
||||
google.protobuf.Timestamp created_at = 2;
|
||||
// monotonically increases, resets upon service restart
|
||||
uint32 seq_num = 3;
|
||||
}
|
||||
|
||||
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