Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[JIT-1661] Faster Autosnapshot #445

Merged
merged 1 commit into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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