Skip to content

Commit

Permalink
[JIT-1661] Faster Autosnapshot (#436)
Browse files Browse the repository at this point in the history
  • Loading branch information
esemeniuc authored Nov 10, 2023
1 parent 1ee03bc commit ff739bd
Show file tree
Hide file tree
Showing 10 changed files with 1,035 additions and 382 deletions.
5 changes: 5 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 15 additions & 13 deletions tip-distributor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,40 @@ version = { workspace = true }
edition = { workspace = true }
license = { workspace = true }
description = "Collection of binaries used to distribute MEV rewards to delegators and validators."
publish = false

[dependencies]
anchor-lang = { workspace = true }
clap = { version = "4.1.11", features = ["derive", "env"] }
env_logger = "0.9.0"
futures = "0.3.21"
im = "15.1.0"
itertools = "0.10.3"
crossbeam-channel = { workspace = true }
env_logger = { workspace = true }
futures = { workspace = true }
gethostname = { workspace = true }
im = { workspace = true }
itertools = { workspace = true }
jito-tip-distribution = { workspace = true }
jito-tip-payment = { workspace = true }
log = "0.4.17"
num-traits = "0.2.15"
serde = "1.0.137"
serde_json = "1.0.81"
log = { workspace = true }
num-traits = { workspace = true }
rand = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
solana-accounts-db = { workspace = true }
solana-client = { workspace = true }
solana-genesis-utils = { workspace = true }
solana-ledger = { workspace = true }
solana-measure = { workspace = true }
solana-merkle-tree = { workspace = true }
solana-metrics = { workspace = true }
solana-program = { workspace = true }
solana-program-runtime = { workspace = true }
solana-rpc-client-api = { workspace = true }
solana-runtime = { workspace = true }
solana-sdk = { workspace = true }
solana-stake-program = { workspace = true }
solana-vote = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "macros", "sync", "time", "full"] }
tokio = { workspace = true, features = ["rt-multi-thread", "macros"] }

[dev-dependencies]
solana-sdk = { workspace = true, features = ["dev-context-only-utils"] }
Expand All @@ -51,7 +57,3 @@ path = "src/bin/merkle-root-uploader.rs"
[[bin]]
name = "solana-claim-mev-tips"
path = "src/bin/claim-mev-tips.rs"

[[bin]]
name = "solana-reclaim-rent"
path = "src/bin/reclaim-rent.rs"
15 changes: 12 additions & 3 deletions tip-distributor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,15 @@ out into the PDA until some slot in epoch N + 1. Due to this we cannot rely on t
in the PDAs. We use the bank solely to take a snapshot of delegations, but an RPC node to fetch the PDA lamports for more up-to-date data.

### merkle-root-generator
This script accepts a path to the above JSON file as one of its arguments, and generates a merkle-root. It'll optionally upload the root
on-chain if specified. Additionally, it'll spit the generated merkle trees out into a JSON file.
This script accepts a path to the above JSON file as one of its arguments, and generates a merkle-root into a JSON file.

### merkle-root-uploader
Uploads the root on-chain.

### claim-mev-tips
This reads the file outputted by `merkle-root-generator` and finds all eligible accounts to receive mev tips. Transactions
are created and sent to the RPC server.


## How it works?
In order to use this library as the merkle root creator one must follow the following steps:
Expand All @@ -38,6 +45,8 @@ In order to use this library as the merkle root creator one must follow the foll
1. The snapshot created at `${WHERE_TO_CREATE_SNAPSHOT}` will have the highest slot of `${YOUR_SLOT}`, assuming you downloaded the correct snapshot.
4. Run `stake-meta-generator --ledger-path ${WHERE_TO_CREATE_SNAPSHOT} --tip-distribution-program-id ${PUBKEY} --out-path ${JSON_OUT_PATH} --snapshot-slot ${SLOT} --rpc-url ${URL}`
1. Note: `${WHERE_TO_CREATE_SNAPSHOT}` must be the same in steps 3 & 4.
5. Run `merkle-root-generator --path-to-my-keypair ${KEYPAIR_PATH} --stake-meta-coll-path ${STAKE_META_COLLECTION_JSON} --rpc-url ${URL} --upload-roots ${BOOL} --force-upload-root ${BOOL}`
5. Run `merkle-root-generator --stake-meta-coll-path ${STAKE_META_COLLECTION_JSON} --rpc-url ${URL} --out-path ${MERKLE_ROOT_PATH}`
6. Run `merkle-root-uploader --out-path ${MERKLE_ROOT_PATH} --keypair-path ${KEYPAIR_PATH} --rpc-url ${URL} --tip-distribution-program-id ${PROGRAM_ID}`
7. Run `solana-claim-mev-tips --merkle-trees-path /solana/ledger/autosnapshot/merkle-tree-221615999.json --rpc-url ${URL} --tip-distribution-program-id ${PROGRAM_ID} --keypair-path ${KEYPAIR_PATH}`

Voila!
163 changes: 141 additions & 22 deletions tip-distributor/src/bin/claim-mev-tips.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
//! This binary claims MEV tips.
use {
clap::Parser,
gethostname::gethostname,
log::*,
solana_sdk::pubkey::Pubkey,
solana_tip_distributor::claim_mev_workflow::claim_mev_tips,
std::{path::PathBuf, str::FromStr},
solana_metrics::{datapoint_error, datapoint_info, set_host_id},
solana_sdk::{pubkey::Pubkey, signature::read_keypair_file},
solana_tip_distributor::{
claim_mev_workflow::{claim_mev_tips, ClaimMevError},
read_json_from_file,
reclaim_rent_workflow::reclaim_rent,
GeneratedMerkleTreeCollection,
},
std::{
path::PathBuf,
sync::Arc,
time::{Duration, Instant},
},
};

#[derive(Parser, Debug)]
Expand All @@ -16,37 +26,146 @@ struct Args {
merkle_trees_path: PathBuf,

/// RPC to send transactions through
#[arg(long, env)]
#[arg(long, env, default_value = "http://localhost:8899")]
rpc_url: String,

/// Tip distribution program ID
#[arg(long, env)]
tip_distribution_program_id: String,
tip_distribution_program_id: Pubkey,

/// Path to keypair
#[arg(long, env)]
keypair_path: PathBuf,

/// Number of unique connections to the RPC server for sending txns
#[arg(long, env, default_value_t = 128)]
rpc_send_connection_count: u64,

/// Rate-limits the maximum number of GET requests per RPC connection
#[arg(long, env, default_value_t = 256)]
max_concurrent_rpc_get_reqs: usize,

/// Number of retries for main claim send loop. Loop is time bounded.
#[arg(long, env, default_value_t = 5)]
max_loop_retries: u64,

/// Limits how long before send loop runs before stopping. Defaults to 10 mins
#[arg(long, env, default_value_t = 10 * 60)]
max_loop_duration_secs: u64,

/// Specifies whether to reclaim any rent.
#[arg(long, env, default_value_t = true)]
should_reclaim_rent: bool,

/// Specifies whether to reclaim rent on behalf of validators from respective TDAs.
#[arg(long, env)]
should_reclaim_tdas: bool,
}

fn main() {
#[tokio::main]
async fn main() -> Result<(), ClaimMevError> {
env_logger::init();
info!("Starting to claim mev tips...");

gethostname()
.into_string()
.map(set_host_id)
.expect("set hostname");
let args: Args = Args::parse();
let keypair = Arc::new(read_keypair_file(&args.keypair_path).expect("read keypair file"));
let merkle_trees: GeneratedMerkleTreeCollection =
read_json_from_file(&args.merkle_trees_path).expect("read GeneratedMerkleTreeCollection");
let max_loop_duration = Duration::from_secs(args.max_loop_duration_secs);

let tip_distribution_program_id = Pubkey::from_str(&args.tip_distribution_program_id)
.expect("valid tip_distribution_program_id");

if let Err(e) = claim_mev_tips(
&args.merkle_trees_path,
&args.rpc_url,
&tip_distribution_program_id,
&args.keypair_path,
) {
panic!("error claiming mev tips: {:?}", e);
}
info!(
"done claiming mev tips from file {:?}",
args.merkle_trees_path
"Starting to claim mev tips for epoch: {}",
merkle_trees.epoch
);
let start = Instant::now();

match claim_mev_tips(
merkle_trees.clone(),
args.rpc_url.clone(),
args.rpc_send_connection_count,
args.max_concurrent_rpc_get_reqs,
&args.tip_distribution_program_id,
keypair.clone(),
args.max_loop_retries,
max_loop_duration,
)
.await
{
Err(e) => {
datapoint_error!(
"claim_mev_workflow-claim_error",
("epoch", merkle_trees.epoch, i64),
("error", 1, i64),
("err_str", e.to_string(), String),
(
"merkle_trees_path",
args.merkle_trees_path.to_string_lossy(),
String
),
("elapsed_us", start.elapsed().as_micros(), i64),
);
Err(e)
}
Ok(()) => {
datapoint_info!(
"claim_mev_workflow-claim_completion",
("epoch", merkle_trees.epoch, i64),
(
"merkle_trees_path",
args.merkle_trees_path.to_string_lossy(),
String
),
("elapsed_us", start.elapsed().as_micros(), i64),
);
Ok(())
}
}?;

if args.should_reclaim_rent {
let start = Instant::now();
match reclaim_rent(
args.rpc_url,
args.rpc_send_connection_count,
args.tip_distribution_program_id,
keypair,
args.max_loop_retries,
max_loop_duration,
args.should_reclaim_tdas,
)
.await
{
Err(e) => {
datapoint_error!(
"claim_mev_workflow-reclaim_rent_error",
("epoch", merkle_trees.epoch, i64),
("error", 1, i64),
("err_str", e.to_string(), String),
(
"merkle_trees_path",
args.merkle_trees_path.to_string_lossy(),
String
),
("elapsed_us", start.elapsed().as_micros(), i64),
);
Err(e)
}
Ok(()) => {
datapoint_info!(
"claim_mev_workflow-reclaim_rent_completion",
("epoch", merkle_trees.epoch, i64),
(
"merkle_trees_path",
args.merkle_trees_path.to_string_lossy(),
String
),
("elapsed_us", start.elapsed().as_micros(), i64),
);
Ok(())
}
}?;
}
solana_metrics::flush(); // sometimes last datapoint doesn't get emitted. this increases likelihood.
Ok(())
}
24 changes: 14 additions & 10 deletions tip-distributor/src/bin/merkle-root-uploader.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use {
clap::Parser,
log::info,
solana_sdk::pubkey::Pubkey,
solana_tip_distributor::merkle_root_upload_workflow::upload_merkle_root,
std::{path::PathBuf, str::FromStr},
clap::Parser, log::info, solana_sdk::pubkey::Pubkey,
solana_tip_distributor::merkle_root_upload_workflow::upload_merkle_root, std::path::PathBuf,
};

#[derive(Parser, Debug)]
Expand All @@ -23,23 +20,30 @@ struct Args {

/// Tip distribution program ID
#[arg(long, env)]
tip_distribution_program_id: String,
tip_distribution_program_id: Pubkey,

/// Rate-limits the maximum number of requests per RPC connection
#[arg(long, env, default_value_t = 100)]
max_concurrent_rpc_get_reqs: usize,

/// Number of transactions to send to RPC at a time.
#[arg(long, env, default_value_t = 64)]
txn_send_batch_size: usize,
}

fn main() {
env_logger::init();

let args: Args = Args::parse();

let tip_distribution_program_id = Pubkey::from_str(&args.tip_distribution_program_id)
.expect("valid tip_distribution_program_id");

info!("starting merkle root uploader...");
if let Err(e) = upload_merkle_root(
&args.merkle_root_path,
&args.keypair_path,
&args.rpc_url,
&tip_distribution_program_id,
&args.tip_distribution_program_id,
args.max_concurrent_rpc_get_reqs,
args.txn_send_batch_size,
) {
panic!("failed to upload merkle roots: {:?}", e);
}
Expand Down
Loading

0 comments on commit ff739bd

Please sign in to comment.