Skip to content

Commit

Permalink
fix!: multiple monerod addresses in tari merge mining proxy
Browse files Browse the repository at this point in the history
This PR allows multiple monero daemons to be specified in the configuration of tari_merge_mining_proxy, this will help ensure that the proxy is still able to service requests in the event a monero daemon in the list were to become unreachable whether it be  temporarily or permanently.

update cucumber
  • Loading branch information
StriderDM committed Nov 30, 2021
1 parent 73d862f commit 776f6db
Show file tree
Hide file tree
Showing 8 changed files with 176 additions and 130 deletions.
66 changes: 57 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,20 @@ And then depending on if you are using solo mining or self-select mining you wil
- For the Tari Merge Mining Proxy, under section **`merge_mining_proxy.weatherwax`**
```
[merge_mining_proxy.weatherwax]
monerod_url = "http://monero-stagenet.exan.tech:38081"
monerod_url = [ # stagenet
"http://stagenet.xmr-tw.org:38081",
"http://stagenet.community.xmr.to:38081",
"http://monero-stagenet.exan.tech:38081",
"http://xmr-lux.boldsuck.org:38081",
"http://singapore.node.xmr.pm:38081",
]
#monerod_url = [ # mainnet
# "http://18.132.124.81:18081",
# "http://xmr.support:18081",
# "http://node1.xmr-tw.org:18081",
# "http://xmr.nthrow.nyc:18081",
#]
proxy_host_address = "127.0.0.1:7878"
proxy_submit_to_origin = true
monerod_use_auth = false
Expand All @@ -640,7 +653,20 @@ And then depending on if you are using solo mining or self-select mining you wil
- For the Tari Merge Mining Proxy, under section **`merge_mining_proxy.weatherwax`**
```
[merge_mining_proxy.weatherwax]
monerod_url = "http://18.132.124.81:18081"
monerod_url = [ # stagenet
"http://stagenet.xmr-tw.org:38081",
"http://stagenet.community.xmr.to:38081",
"http://monero-stagenet.exan.tech:38081",
"http://xmr-lux.boldsuck.org:38081",
"http://singapore.node.xmr.pm:38081",
]
#monerod_url = [ # mainnet
# "http://18.132.124.81:18081",
# "http://xmr.support:18081",
# "http://node1.xmr-tw.org:18081",
# "http://xmr.nthrow.nyc:18081",
#]
proxy_host_address = "127.0.0.1:7878"
proxy_submit_to_origin = false
monerod_use_auth = false
Expand All @@ -651,8 +677,8 @@ And then depending on if you are using solo mining or self-select mining you wil
**Note:** The ports `7878`, `18142` and `18143` shown in the example above should not be in use by other processes. If
they are, choose different ports. You will need to update the ports in the steps below as well.

The `monerod_url` must be set to a valid address (`host:port`) for `monerod` that is running Monero mainnet (e.g.
`http://18.132.124.81:18081`) or stagenet (e.g. `http://monero-stagenet.exan.tech:38081`), which can be a
The `monerod_url` set must contain valid addresses (`host:port`) for `monerod` that is running Monero mainnet (e.g.
`["http://18.132.124.81:18081"]`) or stagenet (e.g. `["http://monero-stagenet.exan.tech:38081"]`), which can be a
[public node hosted by XMR.to](https://community.xmr.to/nodes.html), or to a local instance. To test if the
`monerod_url` address is working properly, try to paste `host:port/get_height` in an internet browser, for example:

Expand Down Expand Up @@ -688,7 +714,7 @@ in via the command line upon runtime.
being a subaddress. It is possible to do with the self-select configuration since the template is requested by the miner
with the wallet address of the pool.

###### Solo mining
###### Solo-mining

The [XMRig configuration wizard](https://xmrig.com/wizard) can be used to create a solo mining configuration file
in JSON format:
Expand Down Expand Up @@ -832,8 +858,19 @@ Monero wallet address:

```
# URL to monerod
#monerod_url = "http://18.132.124.81:18081" # mainnet
monerod_url = "http://monero-stagenet.exan.tech:38081" # stagenet
monerod_url = [ # mainnet
"http://18.132.124.81:18081",
"http://xmr.support:18081",
"http://node1.xmr-tw.org:18081",
"http://xmr.nthrow.nyc:18081",
]
monerod_url = [ # stagenet
"http://stagenet.xmr-tw.org:38081",
"http://stagenet.community.xmr.to:38081",
"http://monero-stagenet.exan.tech:38081",
"http://xmr-lux.boldsuck.org:38081",
"http://singapore.node.xmr.pm:38081",
]
```

###### Runtime
Expand Down Expand Up @@ -891,8 +928,19 @@ The `monerod_url` field in the `config.toml` should be enabled for the mainnet v

```
# URL to monerod
monerod_url = "http://18.132.124.81:18081" # mainnet
#monerod_url = "http://monero-stagenet.exan.tech:38081" # stagenet
monerod_url = [ # mainnet
"http://18.132.124.81:18081",
"http://xmr.support:18081",
"http://node1.xmr-tw.org:18081",
"http://xmr.nthrow.nyc:18081",
]
monerod_url = [ # stagenet
"http://stagenet.xmr-tw.org:38081",
"http://stagenet.community.xmr.to:38081",
"http://monero-stagenet.exan.tech:38081",
"http://xmr-lux.boldsuck.org:38081",
"http://singapore.node.xmr.pm:38081",
]
```

###### Runtime
Expand Down
5 changes: 1 addition & 4 deletions applications/launchpad/docker_rig/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ services:
TARI_NETWORK: ${TARI_NETWORK}
TARI_BASE_NODE__WEATHERWAX__GRPC_BASE_NODE_ADDRESS: "/dns4/base_node/tcp/18142"
TARI_WALLET__GRPC_ADDRESS: "/dns4/wallet/tcp/18143"
TARI_MERGE_MINING_PROXY__WEATHERWAX__MONEROD_URL: ${TARI_MONEROD_URL:-http://monero-stagenet.exan.tech:38081}
TARI_MERGE_MINING_PROXY__WEATHERWAX__MONEROD_URL: ${TARI_MONEROD_URL:-["http://stagenet.community.xmr.to:38081","http://monero-stagenet.exan.tech:38081","http://stagenet.xmr-tw.org:38081","http://xmr-lux.boldsuck.org:38081","http://singapore.node.xmr.pm:38081"]}
TARI_MERGE_MINING_PROXY__WEATHERWAX__MONEROD_USERNAME: ${TARI_MONEROD_USERNAME}
TARI_MERGE_MINING_PROXY__WEATHERWAX__MONEROD_PASSWORD: ${TARI_MONEROD_PASSWORD}
TARI_MERGE_MINING_PROXY__WEATHERWAX__MONEROD_USE_AUTH: ${TARI_MONEROD_USE_AUTH:-0}
Expand All @@ -179,6 +179,3 @@ volumes:
# `docker run --rm -v $(pwd):/backup -v blockchain:/blockchain ubuntu tar czvf /backup/backup.tar.gz /blockchain`
blockchain:
monero-blockchain:



2 changes: 2 additions & 0 deletions applications/tari_merge_mining_proxy/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ pub enum MmProxyError {
InvalidHeaderValue(#[from] InvalidHeaderValue),
#[error("Block was lost due to a failed precondition, and should be retried")]
FailedPreconditionBlockLostRetry,
#[error("No reachable servers in configuration")]
ServersUnavailable,
}

impl From<tonic::Status> for MmProxyError {
Expand Down
109 changes: 74 additions & 35 deletions applications/tari_merge_mining_proxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use std::{
sync::{
atomic::{AtomicBool, Ordering},
Arc,
RwLock,
},
task::{Context, Poll},
time::Instant,
Expand All @@ -61,7 +62,7 @@ const TARI_CHAIN_ID: &str = "xtr";
#[derive(Debug, Clone)]
pub struct MergeMiningProxyConfig {
pub network: Network,
pub monerod_url: String,
pub monerod_url: Vec<String>,
pub monerod_username: String,
pub monerod_password: String,
pub monerod_use_auth: bool,
Expand Down Expand Up @@ -114,6 +115,7 @@ impl MergeMiningProxyService {
base_node_client,
wallet_client,
initial_sync_achieved: Arc::new(AtomicBool::new(false)),
last_available_server: Arc::new(RwLock::new(None)),
},
}
}
Expand All @@ -135,7 +137,7 @@ impl Service<Request<Body>> for MergeMiningProxyService {
let bytes = match proxy::read_body_until_end(request.body_mut()).await {
Ok(b) => b,
Err(err) => {
eprintln!("Method: Unknown, Failed to read request: {}", err);
eprintln!("Method: Unknown, Failed to read request: {:?}", err);
let resp = proxy::json_response(
StatusCode::BAD_REQUEST,
&json_rpc::standard_error_response(
Expand All @@ -153,8 +155,8 @@ impl Service<Request<Body>> for MergeMiningProxyService {
match inner.handle(&method_name, request).await {
Ok(resp) => Ok(resp),
Err(err) => {
error!(target: LOG_TARGET, "Error handling request: {}", err);
eprintln!("Method: {}, Failed to handle request: {}", method_name, err);
error!(target: LOG_TARGET, "Error handling request: {:?}", err);
eprintln!("Method: {}, Failed to handle request: {:?}", method_name, err);
Ok(proxy::json_response(
StatusCode::INTERNAL_SERVER_ERROR,
&json_rpc::standard_error_response(
Expand All @@ -180,6 +182,7 @@ struct InnerService {
base_node_client: grpc::base_node_client::BaseNodeClient<tonic::transport::Channel>,
wallet_client: grpc::wallet_client::WalletClient<tonic::transport::Channel>,
initial_sync_achieved: Arc<AtomicBool>,
last_available_server: Arc<RwLock<Option<String>>>,
}

impl InnerService {
Expand Down Expand Up @@ -582,17 +585,44 @@ impl InnerService {
Ok(proxy::into_response(parts, &resp))
}

fn get_fully_qualified_monerod_url(&self, uri: &Uri) -> Result<Url, MmProxyError> {
let uri = format!("{}{}", self.config.monerod_url, uri.path()).parse::<Url>()?;
Ok(uri)
async fn get_fully_qualified_monerod_url(&self, uri: &Uri) -> Result<Url, MmProxyError> {
{
let lock = self
.last_available_server
.read()
.expect("Read lock should not fail")
.clone();
if let Some(server) = lock {
let uri = format!("{}{}", server, uri.path()).parse::<Url>()?;
return Ok(uri);
}
}

for monerod_url in self.config.monerod_url.iter() {
let uri = format!("{}{}", monerod_url, uri.path()).parse::<Url>()?;
match reqwest::get(uri.clone()).await {
Ok(_) => {
let mut lock = self.last_available_server.write().expect("Write lock should not fail");
*lock = Some(monerod_url.to_string());
info!(target: LOG_TARGET, "Monerod server available: {:?}", uri.clone());
return Ok(uri);
},
Err(_) => {
warn!(target: LOG_TARGET, "Monerod server unavailable: {:?}", uri);
continue;
},
}
}

Err(MmProxyError::ServersUnavailable)
}

/// Proxy a request received by this server to Monerod
async fn proxy_request_to_monerod(
&self,
request: Request<Bytes>,
) -> Result<(Request<Bytes>, Response<json::Value>), MmProxyError> {
let monerod_uri = self.get_fully_qualified_monerod_url(request.uri())?;
let monerod_uri = self.get_fully_qualified_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.
Expand Down Expand Up @@ -744,34 +774,43 @@ impl InnerService {
.join(","),
);

let (request, monerod_resp) = self.proxy_request_to_monerod(request).await?;
// 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 xmrig returned error.
warn!(
target: LOG_TARGET,
"Monerod returned an error: {}",
monerod_resp.status()
);
println!(
"Method: {}, MoneroD Status: {}, Proxy Status: N/A, Response Time: {}ms",
method_name,
monerod_status,
start.elapsed().as_millis()
);
return Ok(monerod_resp.map(|json| json.to_string().into()));
}
match self.proxy_request_to_monerod(request).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()
);
println!(
"Method: {}, MoneroD Status: {}, Proxy Status: N/A, Response Time: {}ms",
method_name,
monerod_status,
start.elapsed().as_millis()
);
return Ok(monerod_resp.map(|json| json.to_string().into()));
}

let response = self.get_proxy_response(request, monerod_resp).await?;
println!(
"Method: {}, MoneroD Status: {}, Proxy Status: {}, Response Time: {}ms",
method_name,
monerod_status,
response.status(),
start.elapsed().as_millis()
);
Ok(response)
let response = self.get_proxy_response(request, monerod_resp).await?;
println!(
"Method: {}, MoneroD Status: {}, Proxy Status: {}, Response Time: {}ms",
method_name,
monerod_status,
response.status(),
start.elapsed().as_millis()
);
Ok(response)
},
Err(e) => {
// Monero Server encountered a problem processing the request, reset the last_available_server
let mut lock = self.last_available_server.write().expect("Write lock should not fail");
*lock = None;
Err(e)
},
}
}
}

Expand Down
17 changes: 13 additions & 4 deletions common/config/presets/merge_mining_proxy.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,19 @@
[merge_mining_proxy.weatherwax]

# URL to monerod
monerod_url = "http://monero-stagenet.exan.tech:38081" # stagenet
#monerod_url = "http://18.133.59.45:28081" # testnet
#monerod_url = "http://18.132.124.81:18081" # mainnet
#monerod_url = "http://monero.exan.tech:18081" # mainnet alternative
monerod_url = [ # stagenet
"http://stagenet.xmr-tw.org:38081",
"http://stagenet.community.xmr.to:38081",
"http://monero-stagenet.exan.tech:38081",
"http://xmr-lux.boldsuck.org:38081",
"http://singapore.node.xmr.pm:38081",
]
#monerod_url = [ # mainnet
# "http://18.132.124.81:18081",
# "http://xmr.support:18081",
# "http://node1.xmr-tw.org:18081",
# "http://xmr.nthrow.nyc:18081",
#]

# Address of the tari_merge_mining_proxy application
proxy_host_address = "127.0.0.1:7878"
Expand Down
24 changes: 20 additions & 4 deletions common/src/configuration/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ pub struct GlobalConfig {
pub wallet_base_node_service_request_max_age: u64,
pub wallet_balance_enquiry_cooldown_period: u64,
pub prevent_fee_gt_amount: bool,
pub monerod_url: String,
pub monerod_url: Vec<String>,
pub monerod_username: String,
pub monerod_password: String,
pub monerod_use_auth: bool,
Expand Down Expand Up @@ -613,9 +613,25 @@ fn convert_node_config(
);

let key = config_string("merge_mining_proxy", net_str, "monerod_url");
let monerod_url = cfg
.get_str(&key)
.map_err(|e| ConfigurationError::new(&key, &e.to_string()))?;
let mut monerod_url: Vec<String> = cfg
.get_array(&key)
.unwrap_or_default()
.into_iter()
.map(|v| {
v.into_str()
.map_err(|err| ConfigurationError::new(&key, &err.to_string()))
})
.collect::<Result<_, _>>()?;

// default to stagenet on empty
if monerod_url.is_empty() {
monerod_url = vec![
"http://stagenet.xmr-tw.org:38081".to_string(),
"http://singapore.node.xmr.pm:38081".to_string(),
"http://xmr-lux.boldsuck.org:38081".to_string(),
"http://monero-stagenet.exan.tech:38081".to_string(),
];
}

let key = config_string("merge_mining_proxy", net_str, "monerod_use_auth");
let monerod_use_auth = cfg
Expand Down
7 changes: 6 additions & 1 deletion integration_tests/helpers/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,13 @@ function baseEnvs(peerSeeds = [], forceSyncPeers = []) {
TARI_BASE_NODE__LOCALNET__MAX_RANDOMX_VMS: "1",
TARI_BASE_NODE__LOCALNET__AUTO_PING_INTERVAL: "15",
TARI_BASE_NODE__LOCALNET__FLOOD_BAN_MAX_MSG_COUNT: "100000",
TARI_MERGE_MINING_PROXY__LOCALNET__MONEROD_URL:
TARI_MERGE_MINING_PROXY__LOCALNET__MONEROD_URL: [
"http://stagenet.xmr-tw.org:38081",
"http://stagenet.community.xmr.to:38081",
"http://monero-stagenet.exan.tech:38081",
"http://xmr-lux.boldsuck.org:38081",
"http://singapore.node.xmr.pm:38081",
],
TARI_MERGE_MINING_PROXY__LOCALNET__MONEROD_USE_AUTH: false,
TARI_MERGE_MINING_PROXY__LOCALNET__MONEROD_USERNAME: '""',
TARI_MERGE_MINING_PROXY__LOCALNET__MONEROD_PASSWORD: '""',
Expand Down
Loading

0 comments on commit 776f6db

Please sign in to comment.