Skip to content

Commit a4dce0a

Browse files
authored
Merge branch 'master' into fix/triton-take-average-of-last-20-slots
2 parents 0cccdfa + 5e6ef7e commit a4dce0a

File tree

3 files changed

+106
-22
lines changed

3 files changed

+106
-22
lines changed

src/dynamic_fee.rs

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ use url::Url;
99
enum FeeStrategy {
1010
Helius,
1111
Triton,
12+
Alchemy,
13+
Quiknode,
1214
}
1315

1416
impl Miner {
15-
pub async fn dynamic_fee(&self) -> Option<u64> {
17+
pub async fn dynamic_fee(&self) -> Result<u64, String> {
1618
// Get url
1719
let rpc_url = self
1820
.dynamic_fee_url
@@ -27,10 +29,14 @@ impl Miner {
2729
.to_string();
2830
let strategy = if host.contains("helius-rpc.com") {
2931
FeeStrategy::Helius
32+
} else if host.contains("alchemy.com") {
33+
FeeStrategy::Alchemy
34+
} else if host.contains("quiknode.pro") {
35+
FeeStrategy::Quiknode
3036
} else if host.contains("rpcpool.com") {
3137
FeeStrategy::Triton
3238
} else {
33-
return None;
39+
return Err("Dynamic fees not supported by this RPC.".to_string());
3440
};
3541

3642
// Build fee estimate request
@@ -52,6 +58,27 @@ impl Miner {
5258
}]
5359
})
5460
}
61+
FeeStrategy::Alchemy => {
62+
json!({
63+
"jsonrpc": "2.0",
64+
"id": "priority-fee-estimate",
65+
"method": "getRecentPrioritizationFees",
66+
"params": [
67+
ore_addresses
68+
]
69+
})
70+
}
71+
FeeStrategy::Quiknode => {
72+
json!({
73+
"jsonrpc": "2.0",
74+
"id": "1",
75+
"method": "qn_estimatePriorityFees",
76+
"params": {
77+
"account": "oreV2ZymfyeXgNgBdqMkumTqqAprVqgBWQfoYkrtKWQ",
78+
"last_n_blocks": 100
79+
}
80+
})
81+
}
5582
FeeStrategy::Triton => {
5683
json!({
5784
"jsonrpc": "2.0",
@@ -83,27 +110,49 @@ impl Miner {
83110
FeeStrategy::Helius => response["result"]["priorityFeeEstimate"]
84111
.as_f64()
85112
.map(|fee| fee as u64)
86-
.ok_or_else(|| format!("Failed to parse priority fee. Response: {:?}", response))
87-
.unwrap(),
113+
.ok_or_else(|| format!("Failed to parse priority fee response: {:?}", response)),
114+
FeeStrategy::Quiknode => response["result"]["per_compute_unit"]["medium"]
115+
.as_f64()
116+
.map(|fee| fee as u64)
117+
.ok_or_else(|| format!("Please enable the Solana Priority Fee API add-on in your QuickNode account.")),
118+
FeeStrategy::Alchemy => response["result"]
119+
.as_array()
120+
.and_then(|arr| {
121+
Some(
122+
arr.into_iter()
123+
.map(|v| v["prioritizationFee"].as_u64().unwrap())
124+
.collect::<Vec<u64>>(),
125+
)
126+
})
127+
.and_then(|fees| {
128+
Some(
129+
((fees.iter().sum::<u64>() as f32 / fees.len() as f32).ceil() * 1.2) as u64,
130+
)
131+
})
132+
.ok_or_else(|| format!("Failed to parse priority fee response: {:?}", response)),
88133
FeeStrategy::Triton => {
89134
serde_json::from_value::<Vec<RpcPrioritizationFee>>(response["result"].clone())
90135
.map(|prioritization_fees| {
91136
estimate_prioritization_fee_micro_lamports(prioritization_fees)
92137
})
93-
.or_else(|error: serde_json::Error| {
138+
.ok_or_else(|error: serde_json::Error| {
94139
Err(format!(
95140
"Failed to parse priority fee. Response: {response:?}, error: {error}"
96141
))
97142
})
98-
.unwrap()
99143
}
100144
};
101145

102146
// Check if the calculated fee is higher than max
103-
if let Some(max_fee) = self.priority_fee {
104-
Some(calculated_fee.min(max_fee))
105-
} else {
106-
Some(calculated_fee)
147+
match calculated_fee {
148+
Err(err) => Err(err),
149+
Ok(fee) => {
150+
if let Some(max_fee) = self.priority_fee {
151+
Ok(fee.min(max_fee))
152+
} else {
153+
Ok(fee)
154+
}
155+
}
107156
}
108157
}
109158
}

src/mine.rs

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{sync::Arc, time::Instant};
1+
use std::{sync::Arc, sync::RwLock, time::Instant};
22

33
use colored::*;
44
use drillx::{
@@ -35,18 +35,28 @@ impl Miner {
3535

3636
// Start mining loop
3737
let mut last_hash_at = 0;
38+
let mut last_balance = 0;
3839
loop {
3940
// Fetch proof
4041
let config = get_config(&self.rpc_client).await;
4142
let proof =
4243
get_updated_proof_with_authority(&self.rpc_client, signer.pubkey(), last_hash_at)
4344
.await;
44-
last_hash_at = proof.last_hash_at;
4545
println!(
46-
"\nStake: {} ORE\n Multiplier: {:12}x",
46+
"\nStake: {} ORE\n{} Multiplier: {:12}x",
4747
amount_u64_to_string(proof.balance),
48+
if last_hash_at.gt(&0) {
49+
format!(
50+
" Change: {} ORE\n",
51+
amount_u64_to_string(proof.balance.saturating_sub(last_balance))
52+
)
53+
} else {
54+
"".to_string()
55+
},
4856
calculate_multiplier(proof.balance, config.top_balance)
4957
);
58+
last_hash_at = proof.last_hash_at;
59+
last_balance = proof.balance;
5060

5161
// Calculate cutoff time
5262
let cutoff_time = self.get_cutoff(proof, args.buffer_time).await;
@@ -87,11 +97,13 @@ impl Miner {
8797
) -> Solution {
8898
// Dispatch job to each thread
8999
let progress_bar = Arc::new(spinner::new_progress_bar());
100+
let global_best_difficulty = Arc::new(RwLock::new(0u32));
90101
progress_bar.set_message("Mining...");
91102
let core_ids = core_affinity::get_core_ids().unwrap();
92103
let handles: Vec<_> = core_ids
93104
.into_iter()
94105
.map(|i| {
106+
let global_best_difficulty = Arc::clone(&global_best_difficulty);
95107
std::thread::spawn({
96108
let proof = proof.clone();
97109
let progress_bar = progress_bar.clone();
@@ -123,19 +135,34 @@ impl Miner {
123135
best_nonce = nonce;
124136
best_difficulty = difficulty;
125137
best_hash = hx;
138+
// {{ edit_1 }}
139+
if best_difficulty.gt(&*global_best_difficulty.read().unwrap())
140+
{
141+
*global_best_difficulty.write().unwrap() = best_difficulty;
142+
}
143+
// {{ edit_1 }}
126144
}
127145
}
128146

129147
// Exit if time has elapsed
130148
if nonce % 100 == 0 {
149+
let global_best_difficulty =
150+
*global_best_difficulty.read().unwrap();
131151
if timer.elapsed().as_secs().ge(&cutoff_time) {
132-
if best_difficulty.ge(&min_difficulty) {
152+
if i.id == 0 {
153+
progress_bar.set_message(format!(
154+
"Mining... ({} difficulty)",
155+
global_best_difficulty,
156+
));
157+
}
158+
if global_best_difficulty.ge(&min_difficulty) {
133159
// Mine until min difficulty has been met
134160
break;
135161
}
136162
} else if i.id == 0 {
137163
progress_bar.set_message(format!(
138-
"Mining... ({} sec remaining)",
164+
"Mining... ({} difficulty, {} sec remaining)",
165+
global_best_difficulty,
139166
cutoff_time.saturating_sub(timer.elapsed().as_secs()),
140167
));
141168
}

src/send_and_confirm.rs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,21 @@ impl Miner {
8989
if attempts % 10 == 0 {
9090
// Reset the compute unit price
9191
if self.dynamic_fee {
92-
let fee = if let Some(fee) = self.dynamic_fee().await {
93-
progress_bar.println(format!(" Priority fee: {} microlamports", fee));
94-
fee
95-
} else {
96-
let fee = self.priority_fee.unwrap_or(0);
97-
progress_bar.println(format!(" {} Dynamic fees not supported by this RPC. Falling back to static value: {} microlamports", "WARNING".bold().yellow(), fee));
98-
fee
92+
let fee = match self.dynamic_fee().await {
93+
Ok(fee) => {
94+
progress_bar.println(format!(" Priority fee: {} microlamports", fee));
95+
fee
96+
}
97+
Err(err) => {
98+
let fee = self.priority_fee.unwrap_or(0);
99+
progress_bar.println(format!(
100+
" {} {} Falling back to static value: {} microlamports",
101+
"WARNING".bold().yellow(),
102+
err,
103+
fee
104+
));
105+
fee
106+
}
99107
};
100108
final_ixs.remove(1);
101109
final_ixs.insert(1, ComputeBudgetInstruction::set_compute_unit_price(fee));

0 commit comments

Comments
 (0)