Skip to content

Commit

Permalink
miner difficulty settings
Browse files Browse the repository at this point in the history
  • Loading branch information
miralandlabs committed Aug 12, 2024
1 parent d1e15d3 commit d0987a5
Show file tree
Hide file tree
Showing 11 changed files with 367 additions and 125 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ core_affinity = "0.8.1"
drillx = "2.0.0"
# drillx = { git = "https://github.com/regolith-labs/drillx", branch = "master", features = ["solana"] }
futures = "0.3.30"
indicatif = "0.17.8"
num_cpus = "1.16.0"
ore-api = "2.1.0"
ore-utils = "2.1.0"
Expand All @@ -53,6 +54,8 @@ spl-associated-token-account = { version = "^2.3", features = [
] }
tokio = "1.35.1"
url = "2.5"
# tokio-tungstenite = "0.16"
# serde = { version = "1.0", features = ["derive"] }

# [patch.crates-io]
# drillx = { path = "../drillx/drillx" }
Expand Down
18 changes: 18 additions & 0 deletions src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,24 @@ pub struct MineArgs {
default_value = "0"
)]
pub risk_time: u64,

#[arg(
long,
short,
value_name = "EXTRA_FEE_DIFFICULTY",
help = "The min difficulty that the miner thinks deserves to pay more priority fee.",
default_value = "27"
)]
pub extra_fee_difficulty: u32,

#[arg(
long,
short,
value_name = "EXTRA_FEE_PERCENT",
help = "The extra percentage that the miner thinks deserves to pay more priority fee. Integer range 0..100 inclusive and the final priority fee cannot exceed the priority fee cap.",
default_value = "0"
)]
pub extra_fee_percent: u64,
}

#[derive(Parser, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion src/claim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ impl Miner {
&ore_api::consts::MINT_ADDRESS,
&spl_token::id(),
);
self.send_and_confirm(&[ix], ComputeBudget::Dynamic, false, None)
self.send_and_confirm(&[ix], ComputeBudget::Fixed(400_000), false, None)
.await
.ok();

Expand Down
2 changes: 1 addition & 1 deletion src/close.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl Miner {

// Submit close transaction
let ix = ore_api::instruction::close(signer.pubkey());
self.send_and_confirm(&[ix], ComputeBudget::Dynamic, false, None)
self.send_and_confirm(&[ix], ComputeBudget::Fixed(500_000), false, None)
.await
.ok();
}
Expand Down
182 changes: 120 additions & 62 deletions src/dynamic_fee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,20 @@ use crate::Miner;
use ore_api::consts::BUS_ADDRESSES;
use reqwest::Client;
use serde_json::{json, Value};

use solana_sdk::pubkey::Pubkey;
use std::{collections::HashMap, str::FromStr};

use solana_client::rpc_response::RpcPrioritizationFee;

use url::Url;

pub const DEFAULT_PRIORITY_FEE: u64 = 10_000;

enum FeeStrategy {
Helius,
Triton,
LOCAL,
Alchemy,
Quiknode,
}
Expand Down Expand Up @@ -36,7 +44,7 @@ impl Miner {
} else if host.contains("rpcpool.com") {
FeeStrategy::Triton
} else {
return Err("Dynamic fees not supported by this RPC.".to_string());
FeeStrategy::LOCAL
};

// Build fee estimate request
Expand All @@ -45,53 +53,46 @@ impl Miner {
.chain(BUS_ADDRESSES.iter().map(|pubkey| pubkey.to_string()))
.collect();
let body = match strategy {
FeeStrategy::Helius => {
json!({
"jsonrpc": "2.0",
"id": "priority-fee-estimate",
"method": "getPriorityFeeEstimate",
"params": [{
"accountKeys": ore_addresses,
"options": {
"recommended": true
}
}]
})
}
FeeStrategy::Alchemy => {
json!({
"jsonrpc": "2.0",
"id": "priority-fee-estimate",
"method": "getRecentPrioritizationFees",
"params": [
ore_addresses
]
})
}
FeeStrategy::Quiknode => {
json!({
"jsonrpc": "2.0",
"id": "1",
"method": "qn_estimatePriorityFees",
"params": {
"account": BUS_ADDRESSES[0].to_string(),
"last_n_blocks": 100
FeeStrategy::Helius => Some(json!({
"jsonrpc": "2.0",
"id": "priority-fee-estimate",
"method": "getPriorityFeeEstimate",
"params": [{
"accountKeys": ore_addresses,
"options": {
"recommended": true
}
})
}
FeeStrategy::Triton => {
json!({
"jsonrpc": "2.0",
"id": "priority-fee-estimate",
"method": "getRecentPrioritizationFees",
"params": [
ore_addresses,
{
"percentile": 5000,
}
]
})
}
}]
})),
FeeStrategy::Alchemy => Some(json!({
"jsonrpc": "2.0",
"id": "priority-fee-estimate",
"method": "getRecentPrioritizationFees",
"params": [
ore_addresses
]
})),
FeeStrategy::Quiknode => Some(json!({
"jsonrpc": "2.0",
"id": "1",
"method": "qn_estimatePriorityFees",
"params": {
"account": "oreV2ZymfyeXgNgBdqMkumTqqAprVqgBWQfoYkrtKWQ",
"last_n_blocks": 100
}
})),
FeeStrategy::Triton => Some(json!({
"jsonrpc": "2.0",
"id": "priority-fee-estimate",
"method": "getRecentPrioritizationFees",
"params": [
ore_addresses,
{
"percentile": 5000,
}
]
})),
FeeStrategy::LOCAL => None,
};

// // Send request in one step
Expand All @@ -105,22 +106,25 @@ impl Miner {
// .await
// .unwrap();

// MI, Send request in two steps
// split json from send
// 1) handle response
let Ok(resp) = client
.post(rpc_url)
.json(&body)
.send()
.await else {
// Send rpc request
let response = if let Some(body) = body {
// MI, Send request in two steps
// split json from send
// 1) handle response
let Ok(resp) = client.post(rpc_url).json(&body).send().await else {
eprintln!("didn't get dynamic fee estimate, use default instead.");
return Ok(5000);
return Ok(DEFAULT_PRIORITY_FEE);
};

// 2) handle json
let Ok(response) = resp.json::<Value>().await else {
eprintln!("didn't get json data from fee estimate response, use default instead.");
return Ok(5000);

// 2) handle json
let Ok(response) = resp.json::<Value>().await else {
eprintln!("didn't get json data from fee estimate response, use default instead.");
return Ok(DEFAULT_PRIORITY_FEE);
};

response
} else {
Value::Null
};

// Parse response
Expand Down Expand Up @@ -158,7 +162,12 @@ impl Miner {
"Failed to parse priority fee response: {response:?}, error: {error}"
))
})
}
},
FeeStrategy::LOCAL => {
self.local_dynamic_fee().await.or_else(|err| {
Err(format!("Failed to parse priority fee response: {err}"))
})
},
};

// Check if the calculated fee is higher than max
Expand All @@ -173,6 +182,55 @@ impl Miner {
}
}
}

pub async fn local_dynamic_fee(&self) -> Result<u64, Box<dyn std::error::Error>> {
let client = self.rpc_client.clone();
let pubkey = [
"oreV2ZymfyeXgNgBdqMkumTqqAprVqgBWQfoYkrtKWQ",
"5HngGmYzvSuh3XyU11brHDpMTHXQQRQQT4udGFtQSjgR",
"2oLNTQKRb4a2117kFi6BYTUDu3RPrMVAHFhCfPKMosxX",
];
let address_strings = pubkey;

// Convert strings to Pubkey
let addresses: Vec<Pubkey> = address_strings
.into_iter()
.map(|addr_str| Pubkey::from_str(addr_str).expect("Invalid address"))
.collect();

// Get recent prioritization fees
let recent_prioritization_fees = client.get_recent_prioritization_fees(&addresses).await?;
if recent_prioritization_fees.is_empty() {
return Err("No recent prioritization fees".into());
}
let mut sorted_fees: Vec<_> = recent_prioritization_fees.into_iter().collect();
sorted_fees.sort_by(|a, b| b.slot.cmp(&a.slot));
let chunk_size = 150;
let chunks: Vec<_> = sorted_fees.chunks(chunk_size).take(3).collect();
let mut percentiles: HashMap<u8, u64> = HashMap::new();
for (_, chunk) in chunks.iter().enumerate() {
let fees: Vec<u64> = chunk.iter().map(|fee| fee.prioritization_fee).collect();
percentiles = Self::calculate_percentiles(&fees);
}

// Default to 75 percentile
let fee = *percentiles.get(&75).unwrap_or(&0);
Ok(fee)
}

fn calculate_percentiles(fees: &[u64]) -> HashMap<u8, u64> {
let mut sorted_fees = fees.to_vec();
sorted_fees.sort_unstable();
let len = sorted_fees.len();
let percentiles = vec![10, 25, 50, 60, 70, 75, 80, 85, 90, 100];
percentiles
.into_iter()
.map(|p| {
let index = (p as f64 / 100.0 * len as f64).round() as usize;
(p, sorted_fees[index.saturating_sub(1)])
})
.collect()
}
}

/// Our estimate is the average over the last 20 slots
Expand Down
19 changes: 18 additions & 1 deletion src/mine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ enum ParallelStrategy {
Threads(u64),
}

pub struct DifficultyPayload {
pub solution_difficulty: u32,
pub expected_min_difficulty: u32,
pub extra_fee_difficulty: u32,
pub extra_fee_percent: u64,
}

impl Miner {
pub async fn mine(&self, args: MineArgs) {
// Open account, if needed.
Expand Down Expand Up @@ -64,6 +71,8 @@ impl Miner {

let nonce_checkpoint_step: u64 = args.nonce_checkpoint_step;
let expected_min_difficulty: u32 = args.expected_min_difficulty;
let extra_fee_difficulty: u32 = args.extra_fee_difficulty;
let extra_fee_percent: u64 = args.extra_fee_percent;
let risk_time: u64 = args.risk_time;

// Start mining loop
Expand Down Expand Up @@ -122,6 +131,13 @@ impl Miner {
}
};

let difficulty_payload = DifficultyPayload {
solution_difficulty: solution.to_hash().difficulty(),
expected_min_difficulty,
extra_fee_difficulty,
extra_fee_percent,
};

// Build instruction set
let mut ixs = vec![ore_api::instruction::auth(proof_pubkey(signer.pubkey()))];
let mut compute_budget = 500_000;
Expand Down Expand Up @@ -149,7 +165,8 @@ impl Miner {
&ixs,
ComputeBudget::Fixed(compute_budget),
false,
Some(solution.to_hash().difficulty()),
// Some(solution.to_hash().difficulty()),
Some(difficulty_payload),
)
.await
.is_ok()
Expand Down
2 changes: 1 addition & 1 deletion src/open.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ impl Miner {
// Sign and send transaction.
println!("Generating challenge...");
let ix = ore_api::instruction::open(signer.pubkey(), signer.pubkey(), fee_payer.pubkey());
self.send_and_confirm(&[ix], ComputeBudget::Dynamic, false, None)
self.send_and_confirm(&[ix], ComputeBudget::Fixed(400_000), false, None)
.await
.ok();
}
Expand Down
Loading

0 comments on commit d0987a5

Please sign in to comment.