diff --git a/applications/minotari_merge_mining_proxy/src/config.rs b/applications/minotari_merge_mining_proxy/src/config.rs index e217f1c47a..92ce6ec0c1 100644 --- a/applications/minotari_merge_mining_proxy/src/config.rs +++ b/applications/minotari_merge_mining_proxy/src/config.rs @@ -36,7 +36,8 @@ use tari_comms::multiaddr::Multiaddr; use tari_core::transactions::transaction_components::RangeProofType; // The default Monero fail URL for mainnet -const MONERO_FAIL_MAINNET_URL: &str = "https://monero.fail/?chain=monero&network=mainnet&all=true"; +pub(crate) const MONERO_FAIL_MAINNET_URL: &str = "https://monero.fail/?chain=monero&network=mainnet&all=true"; +pub(crate) const TARI_MONEROD_SERVERS: [&str; 1] = ["https://xmr-01.tari.com"]; #[derive(Clone, Debug, Deserialize, Serialize)] #[serde(deny_unknown_fields)] @@ -117,44 +118,45 @@ pub(crate) enum MonerodFallback { impl Default for MergeMiningProxyConfig { fn default() -> Self { + let mut monerod_servers = TARI_MONEROD_SERVERS.iter().map(|v| v.to_string()).collect::>(); + monerod_servers.append(&mut vec![ + "http://node.c3pool.org:18081".to_string(), + "http://xmr-full.p2pool.uk:18089".to_string(), + "http://monero.stackwallet.com:18081".to_string(), + "http://xmr.support:18081".to_string(), + "http://node1.xmr-tw.org:18081".to_string(), + "http://monero-g2.hexhex.online:18081".to_string(), + "http://137.220.120.19:18089".to_string(), + "http://185.218.124.120:18489".to_string(), + "http://185.218.124.120:18789".to_string(), + "https://xmr-de-2.boldsuck.org:18081".to_string(), + "http://46.32.46.171:18081".to_string(), + "http://185.218.124.120:18089".to_string(), + "http://185.218.124.120:18589".to_string(), + "http://xmr-de-1.boldsuck.org:18081".to_string(), + "http://185.218.124.120:18889".to_string(), + "http://pinodexmr.hopto.org:18081".to_string(), + "http://node.tincloud.eu:18081".to_string(), + "http://183.6.24.33:18081".to_string(), + "http://147.45.196.232:18089".to_string(), + "http://h-helix.com:18089".to_string(), + "http://185.218.124.120:18689".to_string(), + "http://185.218.124.120:18289".to_string(), + "https://node.tincloud.eu".to_string(), + "https://xmr-de.boldsuck.org:18081".to_string(), + "https://monero.booze.org".to_string(), + "https://xmr.mailia.be:18088".to_string(), + "https://xmr.lolfox.au".to_string(), + "https://xmr1.doggett.tech:18089".to_string(), + "https://node.icefiles.nz:18081".to_string(), + "http://45.8.132.220:18089".to_string(), + "http://82.147.85.13:18089".to_string(), + ]); Self { override_from: None, use_dynamic_fail_data: true, monero_fail_url: MONERO_FAIL_MAINNET_URL.into(), - monerod_url: StringList::from(vec![ - "http://node.c3pool.org:18081".to_string(), - "http://xmr-full.p2pool.uk:18089".to_string(), - "http://monero.stackwallet.com:18081".to_string(), - "http://xmr.support:18081".to_string(), - "https://xmr-01.tari.com".to_string(), - "http://node1.xmr-tw.org:18081".to_string(), - "http://monero-g2.hexhex.online:18081".to_string(), - "http://137.220.120.19:18089".to_string(), - "http://185.218.124.120:18489".to_string(), - "http://185.218.124.120:18789".to_string(), - "https://xmr-de-2.boldsuck.org:18081".to_string(), - "http://46.32.46.171:18081".to_string(), - "http://185.218.124.120:18089".to_string(), - "http://185.218.124.120:18589".to_string(), - "http://xmr-de-1.boldsuck.org:18081".to_string(), - "http://185.218.124.120:18889".to_string(), - "http://pinodexmr.hopto.org:18081".to_string(), - "http://node.tincloud.eu:18081".to_string(), - "http://183.6.24.33:18081".to_string(), - "http://147.45.196.232:18089".to_string(), - "http://h-helix.com:18089".to_string(), - "http://185.218.124.120:18689".to_string(), - "http://185.218.124.120:18289".to_string(), - "https://node.tincloud.eu".to_string(), - "https://xmr-de.boldsuck.org:18081".to_string(), - "https://monero.booze.org".to_string(), - "https://xmr.mailia.be:18088".to_string(), - "https://xmr.lolfox.au".to_string(), - "https://xmr1.doggett.tech:18089".to_string(), - "https://node.icefiles.nz:18081".to_string(), - "http://45.8.132.220:18089".to_string(), - "http://82.147.85.13:18089".to_string(), - ]), + monerod_url: StringList::from(monerod_servers), monerod_username: String::new(), monerod_password: String::new(), monerod_use_auth: false, diff --git a/applications/minotari_merge_mining_proxy/src/error.rs b/applications/minotari_merge_mining_proxy/src/error.rs index 8e350121dd..536cb9d8c1 100644 --- a/applications/minotari_merge_mining_proxy/src/error.rs +++ b/applications/minotari_merge_mining_proxy/src/error.rs @@ -124,6 +124,8 @@ pub enum MmProxyError { MaxSizeBytesError(#[from] MaxSizeBytesError), #[error("Max sized vector error: {0}")] MaxSizeVecError(#[from] MaxSizeVecError), + #[error("Monerod timeout: {0}")] + MonerodTimeout(String), } impl From for MmProxyError { diff --git a/applications/minotari_merge_mining_proxy/src/monero_fail.rs b/applications/minotari_merge_mining_proxy/src/monero_fail.rs index 793b92c9cb..9dc81f9af9 100644 --- a/applications/minotari_merge_mining_proxy/src/monero_fail.rs +++ b/applications/minotari_merge_mining_proxy/src/monero_fail.rs @@ -65,6 +65,7 @@ pub async fn get_monerod_info( number_of_entries: usize, connection_test_timeout: Duration, monero_fail_url: &str, + tari_monerod_entries: Vec, ) -> Result, MmProxyError> { let document = get_monerod_html(monero_fail_url).await?; let table_structure = extract_table_structure(&document); @@ -216,19 +217,25 @@ pub async fn get_monerod_info( }); // Only retain non-tor and non-i2p nodes entries.retain(|entry| entry.address_type != *"tor" && entry.address_type != *"i2p"); - // Give preference to nodes with the best height - entries.sort_by(|a, b| b.height.cmp(&a.height)); - // Determine connection times - use slightly more nodes than requested - entries.truncate(number_of_entries + 10); - - let entries = order_and_select_monerod_info(number_of_entries, connection_test_timeout, &entries).await?; - if entries.is_empty() { return Err(MmProxyError::HtmlParseError( "No public monero servers available".to_string(), )); } - Ok(entries) + // Give preference to nodes with the best height - use slightly more nodes than requested + entries.sort_by(|a, b| b.height.cmp(&a.height)); + entries.truncate(number_of_entries + 10); + // Insert Tari monerod entries at the beginning + let mut pre_ordered_entries = tari_monerod_entries; + pre_ordered_entries.extend(entries); + // Dedup entries (if the Tari monerod entries are already in the list) + pre_ordered_entries.sort_by(|a, b| a.url.cmp(&b.url)); + pre_ordered_entries.dedup_by(|a, b| a.url == b.url); + // Determine connection times + let ordered_entries = + order_and_select_monerod_info(number_of_entries, connection_test_timeout, &pre_ordered_entries).await?; + + Ok(ordered_entries) } pub async fn order_and_select_monerod_info( @@ -242,13 +249,9 @@ pub async fn order_and_select_monerod_info( let start = std::time::Instant::now(); if (timeout(connection_test_timeout, reqwest::get(url.clone())).await).is_ok() { entry.response_time = Some(start.elapsed()); - debug!( - target: LOG_TARGET, "Response time '{:.2?}' for Monerod server at: {}", - entry.response_time, url.as_str() - ); } else { debug!( - target: LOG_TARGET, "Response time 'n/a' for Monerod server at: {}, timed out", + target: LOG_TARGET, "Response for Monerod server at {} timed out", url.as_str() ); } @@ -264,6 +267,14 @@ pub async fn order_and_select_monerod_info( }); // Truncate to the requested number of entries entries.truncate(number_of_entries); + for entry in &mut entries { + if let Ok(url) = format!("{}/getheight", entry.url).parse::() { + debug!( + target: LOG_TARGET, "Response time '{:.2?}' for Monerod server at: {}", + entry.response_time, url.as_str() + ); + } + } Ok(entries) } @@ -345,6 +356,7 @@ mod test { order_and_select_monerod_info, MonerodEntry, }, + run_merge_miner::get_tari_monerod_entries, }; async fn get_monerod_info_if_online( @@ -352,7 +364,14 @@ mod test { connection_test_timeout: Duration, monero_fail_url: &str, ) -> Vec { - match get_monerod_info(number_of_entries, connection_test_timeout, monero_fail_url).await { + match get_monerod_info( + number_of_entries, + connection_test_timeout, + monero_fail_url, + get_tari_monerod_entries(monero_fail_url), + ) + .await + { Ok(val) => val, Err(HtmlParseError(val)) => { if val.contains("No public monero servers available") { diff --git a/applications/minotari_merge_mining_proxy/src/proxy/inner.rs b/applications/minotari_merge_mining_proxy/src/proxy/inner.rs index 1f4c98ab02..13462fd3dc 100644 --- a/applications/minotari_merge_mining_proxy/src/proxy/inner.rs +++ b/applications/minotari_merge_mining_proxy/src/proxy/inner.rs @@ -58,7 +58,7 @@ use crate::{ config::{MergeMiningProxyConfig, MonerodFallback}, error::MmProxyError, proxy::{ - monerod_method::{parse_monerod_rpc_method, MonerodMethod}, + monerod_method::MonerodMethod, static_responses::{ convert_static_monerod_response_to_hyper_response, self_select_submit_block_monerod_response, @@ -608,27 +608,48 @@ impl InnerService { trace!(target: LOG_TARGET, "Monerod status - Current: {}, Last assigned: {}", server, server); } + #[allow(clippy::too_many_lines)] async fn get_monerod_url(&self, request_uri: &Uri) -> Result, MmProxyError> { if self.config.monerod_fallback == MonerodFallback::StaticOnly { return Ok(None); } // Return the previously qualified monerod URL if it exists let mut parse_error = None; - { - let lock = self - .current_monerod_server - .read() - .expect("Read lock should not fail") - .clone(); + let mut busy_qualifying = 0; + let start_reading_lock_time = Instant::now(); + loop { + let lock = { + self.current_monerod_server + .read() + .expect("Read lock should not fail") + .clone() + }; if let Some(server) = lock { + // Give some time for the server to be qualified if server == BUSY_QUALIFYING { - return Err(MmProxyError::ServersUnavailable(BUSY_QUALIFYING.to_string())); + let time_lapsed = start_reading_lock_time.elapsed(); + if time_lapsed > self.config.monerod_connection_timeout { + return Err(MmProxyError::ServersUnavailable(BUSY_QUALIFYING.to_string())); + } + trace!( + target: LOG_TARGET, + "Waiting for lock data ({} - {:.2?}), {}, {}", + {busy_qualifying += 1; busy_qualifying}, time_lapsed, BUSY_QUALIFYING, request_uri.path() + ); + tokio::time::sleep(std::time::Duration::from_millis(50)).await; + continue; } + // Parse the URL if qualifying is done match format!("{}{}", server, request_uri.path()).parse::() { Ok(url) => return Ok(Some(url)), - Err(e) => parse_error = Some(e), + Err(e) => { + parse_error = Some(e); + break; + }, } } + // If no server is qualified, proceed with qualifying + break; } if let Some(e) = parse_error { self.clear_current_monerod_server_lock(None); @@ -647,12 +668,13 @@ impl InnerService { .clone(); lock.unwrap_or_default() }; - let pos = self + let mut pos = self .config .monerod_url .iter() .position(|x| x == &last_used_url) .unwrap_or(0); + pos = (pos + 1) % self.config.monerod_url.len(); let (left, right) = self.config.monerod_url.split_at_checked(pos).ok_or_else(|| { self.clear_current_monerod_server_lock(None); MmProxyError::ConversionError("Invalid utf 8 url".to_string()) @@ -677,6 +699,17 @@ impl InnerService { url.as_str(), pos + 1, self.config.monerod_url.len() ); match timeout(self.config.monerod_connection_timeout, reqwest::get(url.clone())).await { + // For this availability check we deliberately do not provide the body of the request if it is a POST + // request and turns it into an invalid GET request. This is because we are only interested in the + // connection. A typical response of a monerod daemon upon an invalid POST request + // `https:///json_rpc` would be: + // "error": { + // "code": -32600, + // "message": "Invalid Request" + // }, + // "id": 0, + // "jsonrpc": "2.0" + // This approach is used to verify the server's availability without needing a valid request body. Ok(response) => { self.update_monerod_server_locks(server); let data_len = match response { @@ -723,6 +756,7 @@ impl InnerService { let request_id = json["id"].as_i64(); let self_select_response = monerod_method == MonerodMethod::SubmitBlock && !self.config.submit_to_origin; + let start = Instant::now(); let json_response = if let Some(monerod_url) = self.get_monerod_url(request.uri()).await? { let mut headers = request.headers().clone(); // Some public monerod setups (e.g. those that are reverse proxied by nginx) require the Host header. @@ -733,48 +767,49 @@ impl InnerService { None => host.parse()?, }; headers.insert("host", host); - debug!( - target: LOG_TARGET, - "Host header updated to match monerod_uri. Request headers: {:?}", headers - ); + debug!(target: LOG_TARGET, "Host header updated to match monerod_uri. Request headers: {:?}", headers); } let mut builder = self .http_client .request(request.method().clone(), monerod_url.clone()) - .headers(headers.clone()); + .headers(headers.clone()) + .timeout(self.config.monerod_connection_timeout); if self.config.monerod_use_auth { // Use HTTP basic auth. This is the only reason we are using `reqwest` over the standard hyper client. builder = builder.basic_auth(&self.config.monerod_username, Some(&self.config.monerod_password)); } - debug!( - target: LOG_TARGET, - "[monerod] request: {} {}", - request.method(), - monerod_url, - ); + debug!(target: LOG_TARGET, "[monerod] '{}' request: {} {}", monerod_method, request.method(), monerod_url); if self_select_response { let accept_response = self_select_submit_block_monerod_response(request_id); convert_json_to_hyper_json_response(accept_response, StatusCode::OK, monerod_url.clone()).await? } else { - let resp = match builder - .body(body.clone()) - .send() - .await - .map_err(MmProxyError::MonerodRequestFailed) + // Send the request to the current monerod server + match timeout( + self.config.monerod_connection_timeout, + builder.body(body.clone()).send(), + ) + .await { - Ok(val) => val, + Ok(response) => match response.map_err(MmProxyError::MonerodRequestFailed) { + Ok(val) => { + let hyper_json_response = convert_reqwest_response_to_hyper_json_response(val).await?; + self.update_monerod_cache_values(monerod_method, hyper_json_response.body())?; + hyper_json_response + }, + Err(e) => { + warn!(target: LOG_TARGET, "[monerod] '{}' request response '{}'", monerod_method, e); + self.handle_monerod_error_response(monerod_method, request_id, e)? + }, + }, Err(e) => { - debug!(target: LOG_TARGET, "[monerod] request '{}' response error '{}'", monerod_method, e); - return Err(e); + let err = MmProxyError::MonerodTimeout(e.to_string()); + warn!(target: LOG_TARGET, "[monerod] '{}' request response '{}'", monerod_method, err); + self.handle_monerod_error_response(monerod_method, request_id, err)? }, - }; - - let hyper_json_response = convert_reqwest_response_to_hyper_json_response(resp).await?; - self.update_monerod_cache_values(monerod_method, hyper_json_response.body())?; - hyper_json_response + } } } else if self_select_response { let accept_response = self_select_submit_block_monerod_response(request_id); @@ -788,23 +823,47 @@ impl InnerService { convert_static_monerod_response_to_hyper_response(monerod_method, request_id, cache_values)? }; - let rpc_status = if json_response.body()["error"].is_null() { - "ok" - } else { - json_response.body()["error"]["message"] - .as_str() - .unwrap_or("unknown error") - }; debug!( target: LOG_TARGET, - "[monerod] response: status = {}, monerod_rpc = {}", + "[monerod] '{}' response status = {},{} response time: {}ms", + monerod_method, json_response.status(), - rpc_status + if json_response.body()["error"].is_null() { + "".to_string() + } else { + format!(" error = {},", json_response.body()["error"]["message"] + .as_str() + .unwrap_or("unknown error")) + }, + start.elapsed().as_millis(), ); trace!(target: LOG_TARGET, "[monerod] '{}' response '{:?}'", monerod_method, json_response); Ok((request, json_response)) } + fn handle_monerod_error_response( + &self, + monerod_method: MonerodMethod, + request_id: Option, + err: MmProxyError, + ) -> Result, MmProxyError> { + self.clear_current_monerod_server_lock(None); + if self.config.monerod_fallback == MonerodFallback::MonerodOnly { + Err(err) + } else { + let cache_values = self + .monerod_cache_values + .read() + .expect("Read lock should not fail") + .clone(); + Ok(convert_static_monerod_response_to_hyper_response( + monerod_method, + request_id, + cache_values, + )?) + } + } + fn update_monerod_cache_values( &self, monerod_method: MonerodMethod, @@ -910,8 +969,9 @@ impl InnerService { monerod_resp: Response, monerod_method: MonerodMethod, ) -> Result, MmProxyError> { - trace!(target: LOG_TARGET, "get_proxy_response: '{}'", monerod_method); - match monerod_method { + let start = Instant::now(); + trace!(target: LOG_TARGET, "[get_proxy_response] '{}'", monerod_method); + let proxy_response = match monerod_method { MonerodMethod::GetHeight => self.handle_get_height(monerod_resp).await, MonerodMethod::GetBlockTemplate => self.handle_get_block_template(monerod_resp).await, MonerodMethod::SubmitBlock => { @@ -927,65 +987,63 @@ impl InnerService { // Simply return the response "as is" Ok(proxy::into_body_from_response(monerod_resp)) }, - } + }; + trace!( + target: LOG_TARGET, + "[get_proxy_response] '{}' response time: {}ms", + monerod_method, start.elapsed().as_millis() + ); + proxy_response } pub(crate) async fn handle( self, - method_name: &str, + monerod_method: MonerodMethod, request: Request, ) -> Result, MmProxyError> { let start = Instant::now(); debug!( target: LOG_TARGET, - "request - method: {}, uri: {}, headers: {:?}, body: {}", + "[handle request] '{}' method: {}, uri: {}, headers: {:?}, body: {}", + monerod_method, request.method(), request.uri(), request.headers(), String::from_utf8_lossy(&request.body().clone()[..]), ); - let monerod_method = parse_monerod_rpc_method(request.method(), request.uri(), request.body()); match self.proxy_request_to_monerod(request, monerod_method).await { Ok((request, monerod_resp)) => { // Any failed (!= 200 OK) responses from Monero are immediately returned to the requester let monerod_status = monerod_resp.status(); if !monerod_status.is_success() { - // we dont break on monerod returning an error code. - warn!(target: LOG_TARGET, "Monerod returned an error: {}", monerod_resp.status()); - debug!( - "Method: {}, MoneroD Status: {}, Proxy Status: N/A, Response Time: {}ms", - method_name, - monerod_status, - start.elapsed().as_millis() + warn!( + target: LOG_TARGET, + "[handle request] '{}' monerod status: {}, response time: {}ms", + monerod_method, monerod_resp.status(), start.elapsed().as_millis() ); return Ok(monerod_resp.map(|json| json.to_string().into())); } match self.get_proxy_response(request, monerod_resp, monerod_method).await { - Ok(response) => { - debug!( - "Method: {}, MoneroD Status: {}, Proxy Status: {}, Response Time: {}ms", - method_name, - monerod_status, - response.status(), - start.elapsed().as_millis() - ); - Ok(response) - }, + Ok(response) => Ok(response), Err(e) => { - error!(target: LOG_TARGET, "get_proxy_response: {}", e); - // Monero Server encountered a problem processing the request, reset the current monerod server - self.clear_current_monerod_server_lock(None); + error!( + target: LOG_TARGET, + "[handle request] '{}' get_proxy_response error: {}, response time: {}ms", + monerod_method, e, start.elapsed().as_millis() + ); Err(e) }, } }, Err(e) => { - error!(target: LOG_TARGET, "proxy_request_to_monerod: {}", e); - // Monero Server encountered a problem processing the request, reset the current monerod server - self.clear_current_monerod_server_lock(None); + error!( + target: LOG_TARGET, + "[handle request] '{}' proxy_request_to_monerod error: {}, response time: {}ms", + monerod_method, e, start.elapsed().as_millis() + ); Err(e) }, } diff --git a/applications/minotari_merge_mining_proxy/src/proxy/service.rs b/applications/minotari_merge_mining_proxy/src/proxy/service.rs index 39a2ebd666..f4b0b6e2e1 100644 --- a/applications/minotari_merge_mining_proxy/src/proxy/service.rs +++ b/applications/minotari_merge_mining_proxy/src/proxy/service.rs @@ -41,7 +41,7 @@ use crate::{ common::{json_rpc, proxy}, config::MergeMiningProxyConfig, error::MmProxyError, - proxy::{inner::InnerService, utils::parse_method_name}, + proxy::{inner::InnerService, monerod_method::parse_monerod_rpc_method}, }; const LOG_TARGET: &str = "minotari_mm_proxy::proxy::service"; @@ -63,6 +63,8 @@ impl MergeMiningProxyService { ) -> Result { trace!(target: LOG_TARGET, "Config: {:?}", config); let consensus_manager = ConsensusManager::builder(config.network).build()?; + // Assign the slowest response monerod server as the last assigned monerod server + let last_assigned_monerod_url = config.monerod_url.last().cloned(); Ok(Self { inner: InnerService { config: Arc::new(config), @@ -72,7 +74,7 @@ impl MergeMiningProxyService { p2pool_client, initial_sync_achieved: Arc::new(AtomicBool::new(false)), current_monerod_server: Arc::new(RwLock::new(None)), - last_assigned_monerod_url: Arc::new(RwLock::new(None)), + last_assigned_monerod_url: Arc::new(RwLock::new(last_assigned_monerod_url)), monerod_cache_values: Arc::new(RwLock::new(None)), randomx_factory, consensus_manager, @@ -112,11 +114,12 @@ impl Service> for MergeMiningProxyService { }, }; let request = request.map(|_| bytes.freeze()); - let method_name = parse_method_name(&request); - match inner.handle(&method_name, request).await { + let monerod_method = parse_monerod_rpc_method(request.method(), request.uri(), request.body()); + + match inner.handle(monerod_method, request).await { Ok(resp) => Ok(resp), Err(err) => { - error!(target: LOG_TARGET, "Method \"{}\" failed handling request: {:?}", method_name, err); + error!(target: LOG_TARGET, "Method \"{}\" failed handling request: {:?}", monerod_method, err); Ok(proxy::json_response( StatusCode::INTERNAL_SERVER_ERROR, &json_rpc::standard_error_response( diff --git a/applications/minotari_merge_mining_proxy/src/proxy/utils.rs b/applications/minotari_merge_mining_proxy/src/proxy/utils.rs index c32158316a..e50eaa3327 100644 --- a/applications/minotari_merge_mining_proxy/src/proxy/utils.rs +++ b/applications/minotari_merge_mining_proxy/src/proxy/utils.rs @@ -21,7 +21,7 @@ // USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use bytes::Bytes; -use hyper::{Method, Request, Response}; +use hyper::{Request, Response}; use minotari_app_grpc::tari_rpc; use reqwest::ResponseBuilderExt; use serde_json as json; @@ -126,22 +126,6 @@ pub fn try_into_json_block_header(header: tari_rpc::BlockHeaderResponse) -> Resu })) } -/// Parse the method name from the request -pub fn parse_method_name(request: &Request) -> String { - match *request.method() { - Method::GET => { - let mut chars = request.uri().path().chars(); - chars.next(); - chars.as_str().to_string() - }, - Method::POST => { - let json = json::from_slice::(request.body()).unwrap_or_default(); - str::replace(json["method"].as_str().unwrap_or_default(), "\"", "") - }, - _ => "unsupported".to_string(), - } -} - /// Convert a request with a Bytes body to a request with a json Value body pub fn request_bytes_to_value(request: Request) -> Result, MmProxyError> { let json = json::from_slice::(request.body())?; diff --git a/applications/minotari_merge_mining_proxy/src/run_merge_miner.rs b/applications/minotari_merge_mining_proxy/src/run_merge_miner.rs index 1ad8d1d1bf..273e3cab0a 100644 --- a/applications/minotari_merge_mining_proxy/src/run_merge_miner.rs +++ b/applications/minotari_merge_mining_proxy/src/run_merge_miner.rs @@ -43,7 +43,7 @@ use tonic::transport::{Certificate, ClientTlsConfig, Endpoint}; use crate::{ block_template_data::BlockTemplateRepository, - config::{MergeMiningProxyConfig, MonerodFallback}, + config::{MergeMiningProxyConfig, MonerodFallback, MONERO_FAIL_MAINNET_URL, TARI_MONEROD_SERVERS}, error::MmProxyError, monero_fail::{get_monerod_info, order_and_select_monerod_info, MonerodEntry}, proxy::service::MergeMiningProxyService, @@ -67,6 +67,7 @@ pub async fn start_merge_miner(cli: Cli) -> Result<(), anyhow::Error> { NUMBER_OF_MONEROD_SERVERS, config.monerod_connection_timeout, &config.monero_fail_url, + get_tari_monerod_entries(&config.monero_fail_url), ) .await { @@ -186,6 +187,25 @@ pub async fn start_merge_miner(cli: Cli) -> Result<(), anyhow::Error> { } } +pub(crate) fn get_tari_monerod_entries(monero_fail_url: &str) -> Vec { + if monero_fail_url == MONERO_FAIL_MAINNET_URL { + TARI_MONEROD_SERVERS + .iter() + .map(|v| MonerodEntry { + address_type: "clear".to_string(), + url: v.to_string(), + network: "mainnet".to_string(), + up: true, + up_history: vec![true, true, true, true, true, true], + last_checked: "2 hours ago".to_string(), + ..Default::default() + }) + .collect::>() + } else { + vec![] + } +} + async fn verify_base_node_responses(node_conn: &mut BaseNodeGrpcClient) -> Result<(), MmProxyError> { if let Err(e) = verify_base_node_grpc_mining_responses(node_conn, grpc::NewBlockTemplateRequest { algo: Some(grpc::PowAlgo {