Skip to content

Commit

Permalink
fix: fix merge mining proxy pool mining (#3814)
Browse files Browse the repository at this point in the history
Description
---
Fixed merge mining proxy pool mining:
- XMRig/merge_mininig_proxy error: 'required field "blocktemplate_blob" not found'
- config file was not read correctly;
- global config exited prematurely ;
- round-robin for `monerod_url` - start at the next entry in the list when encountering connection errors;
- updated cucumber integration test.

Motivation and Context
---
When used with Monero mainnet and pool mining, XMRig reported many errors and exited after mining for a while:
- XMRig/merge_mininig_proxy had an issue with pool mining:
   ```
   [2022-02-01 23:56:05.773]  origin   submitted to origin daemon (174/748)  diff 110685 vs. 311330
   [2022-02-01 23:56:06.135]  cpu      accepted (859/61) diff 40000 (361 ms)
   [2022-02-01 23:56:06.517] [127.0.0.1:7878] required field "blocktemplate_blob" not found
   ```
- Default merge mining proxy config on windows was wrong
- When `monerod_url` had an error new connection attempts were always started at the first entry instead of at the last used entry

How Has This Been Tested?
---
Cucumber tests for merge mining
System-level tests
  • Loading branch information
hansieodendaal authored Mar 9, 2022
1 parent bd12b4d commit 407160c
Show file tree
Hide file tree
Showing 13 changed files with 211 additions and 155 deletions.
2 changes: 2 additions & 0 deletions applications/tari_merge_mining_proxy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ async fn main() -> Result<(), anyhow::Error> {
return Ok(());
},
};
println!("\n{}\n", config);

let addr = config.proxy_host_address;
let client = reqwest::Client::builder()
.connect_timeout(Duration::from_secs(5))
Expand Down
101 changes: 87 additions & 14 deletions applications/tari_merge_mining_proxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
use std::{
cmp,
convert::TryFrom,
fmt::{Display, Error, Formatter},
future::Future,
net::SocketAddr,
pin::Pin,
Expand Down Expand Up @@ -82,6 +83,8 @@ impl TryFrom<GlobalConfig> for MergeMiningProxyConfig {
let merge_mining_config = config
.merge_mining_config
.ok_or_else(|| "Merge mining config settings are missing".to_string())?;
let proxy_host_address = multiaddr_to_socketaddr(&merge_mining_config.proxy_host_address)
.map_err(|e| format!("Invalid proxy_host_address: {}", e))?;
let grpc_base_node_address = multiaddr_to_socketaddr(&merge_mining_config.base_node_grpc_address)
.map_err(|e| format!("Invalid base_node_grpc_address: {}", e))?;
let grpc_console_wallet_address = multiaddr_to_socketaddr(&merge_mining_config.wallet_grpc_address)
Expand All @@ -94,13 +97,35 @@ impl TryFrom<GlobalConfig> for MergeMiningProxyConfig {
monerod_use_auth: merge_mining_config.monerod_use_auth,
grpc_base_node_address,
grpc_console_wallet_address,
proxy_host_address: merge_mining_config.proxy_host_address,
proxy_submit_to_origin: config.proxy_submit_to_origin,
wait_for_initial_sync_at_startup: config.wait_for_initial_sync_at_startup,
proxy_host_address,
proxy_submit_to_origin: merge_mining_config.proxy_submit_to_origin,
wait_for_initial_sync_at_startup: merge_mining_config.wait_for_initial_sync_at_startup,
})
}
}

impl Display for MergeMiningProxyConfig {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
writeln!(
f,
"Configuration:\n network ({})\n proxy_host_address ({})\n grpc_base_node_address ({})\n \
grpc_console_wallet_address ({})\n proxy_submit_to_origin ({})\n wait_for_initial_sync_at_startup \
({})\n monerod_url ({:?})\n monerod_password ({})\n monerod_username ({})\n monerod_use_auth ({})",
self.network,
self.proxy_host_address,
self.grpc_base_node_address,
self.grpc_console_wallet_address,
self.proxy_submit_to_origin,
self.wait_for_initial_sync_at_startup,
self.monerod_url,
self.monerod_password,
self.monerod_username,
self.monerod_use_auth
)?;
Ok(())
}
}

#[derive(Debug, Clone)]
pub struct MergeMiningProxyService {
inner: InnerService,
Expand All @@ -114,6 +139,7 @@ impl MergeMiningProxyService {
wallet_client: grpc::wallet_client::WalletClient<tonic::transport::Channel>,
block_templates: BlockTemplateRepository,
) -> Self {
debug!(target: LOG_TARGET, "Config: {:?}", config);
Self {
inner: InnerService {
config,
Expand All @@ -122,7 +148,8 @@ impl MergeMiningProxyService {
base_node_client,
wallet_client,
initial_sync_achieved: Arc::new(AtomicBool::new(false)),
last_available_server: Arc::new(RwLock::new(None)),
current_monerod_server: Arc::new(RwLock::new(None)),
last_assigned_monerod_server: Arc::new(RwLock::new(None)),
},
}
}
Expand Down Expand Up @@ -189,7 +216,8 @@ 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>>>,
current_monerod_server: Arc<RwLock<Option<String>>>,
last_assigned_monerod_server: Arc<RwLock<Option<String>>>,
}

impl InnerService {
Expand Down Expand Up @@ -305,6 +333,12 @@ impl InnerService {
if !self.config.proxy_submit_to_origin {
// self-select related, do not change.
json_resp = json_rpc::default_block_accept_response(request["id"].as_i64());
trace!(
target: LOG_TARGET,
"pool merged mining proxy_submit_to_origin({}) json_resp: {}",
self.config.proxy_submit_to_origin,
json_resp
);
} else {
json_resp = json_rpc::success_response(
request["id"].as_i64(),
Expand Down Expand Up @@ -348,7 +382,12 @@ impl InnerService {
self.block_templates.remove_outdated().await;
}

debug!(target: LOG_TARGET, "Sending submit_block response {}", json_resp);
debug!(
target: LOG_TARGET,
"Sending submit_block response (proxy_submit_to_origin({})): {}",
self.config.proxy_submit_to_origin,
json_resp
);
Ok(proxy::into_response(parts, &json_resp))
}

Expand Down Expand Up @@ -595,7 +634,7 @@ impl InnerService {
async fn get_fully_qualified_monerod_url(&self, uri: &Uri) -> Result<Url, MmProxyError> {
{
let lock = self
.last_available_server
.current_monerod_server
.read()
.expect("Read lock should not fail")
.clone();
Expand All @@ -605,18 +644,45 @@ impl InnerService {
}
}

for monerod_url in self.config.monerod_url.iter() {
let uri = format!("{}{}", monerod_url, uri.path()).parse::<Url>()?;
let last_used_url = {
let lock = self
.last_assigned_monerod_server
.read()
.expect("Read lock should not fail")
.clone();
match lock {
Some(url) => url,
None => "".to_string(),
}
};

// Query the list twice before giving up, starting after the last used entry
let pos = if let Some(index) = self.config.monerod_url.iter().position(|x| x == &last_used_url) {
index
} else {
0
};
let (left, right) = self.config.monerod_url.split_at(pos);
let left = left.to_vec();
let right = right.to_vec();
let iter = right.iter().chain(left.iter()).chain(right.iter()).chain(left.iter());

for next_url in iter {
let uri = format!("{}{}", next_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());
let mut lock = self.current_monerod_server.write().expect("Write lock should not fail");
*lock = Some(next_url.to_string());
let mut lock = self
.last_assigned_monerod_server
.write()
.expect("Write lock should not fail");
*lock = Some(next_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;
},
}
}
Expand Down Expand Up @@ -666,12 +732,19 @@ impl InnerService {
let body: Bytes = request.body().clone();
let json = json::from_slice::<json::Value>(&body[..]).unwrap_or_default();
if let Some(method) = json["method"].as_str() {
trace!(target: LOG_TARGET, "json[\"method\"]: {}", method);
match method {
"submitblock" | "submit_block" => {
submit_block = true;
},
_ => {},
}
trace!(
target: LOG_TARGET,
"submitblock({}), proxy_submit_to_origin({})",
submit_block,
self.config.proxy_submit_to_origin
);
}

let json_response;
Expand Down Expand Up @@ -812,8 +885,8 @@ impl InnerService {
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");
// Monero Server encountered a problem processing the request, reset the current monerod server
let mut lock = self.current_monerod_server.write().expect("Write lock should not fail");
*lock = None;
Err(e)
},
Expand Down
67 changes: 36 additions & 31 deletions common/config/presets/merge_mining_proxy.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,52 @@
# #
########################################################################################################################

[merge_mining_proxy.dibbler]
[merge_mining_proxy]

# URL to monerod
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. (default = "127.0.0.1:7878")
#proxy_host_address = "/ip4/127.0.0.1/tcp/7878"

# GRPC address of base node. (default = "/ip4/127.0.0.1/tcp/18142")
#base_node_grpc_address = "/ip4/127.0.0.1/tcp/18142"

# Address of the tari_merge_mining_proxy application
proxy_host_address = "127.0.0.1:7878"
# GRPC address of console wallet. (default = "/ip4/127.0.0.1/tcp/18143")
#wallet_grpc_address = "/ip4/127.0.0.1/tcp/18143"

# In sole merged mining, the block solution is usually submitted to the Monero blockchain
# (monerod) as well as to the Tari blockchain, then this setting should be "true". With pool
# merged mining, there is no sense in submitting the solution to the Monero blockchain as the
# pool does that, then this setting should be "false". (default = true).
proxy_submit_to_origin = true

# If authentication is being used for curl
monerod_use_auth = false

# Username for curl
monerod_username = ""

# Password for curl
monerod_password = ""
#proxy_submit_to_origin = true

# The merge mining proxy can either wait for the base node to achieve initial sync at startup before it enables mining,
# or not. If merge mining starts before the base node has achieved initial sync, those Tari mined blocks will not be
# accepted. (Default value = true; will wait for base node initial sync).
#wait_for_initial_sync_at_startup = true

[merge_mining_proxy]
monerod_use_auth = false
monerod_username = ""
monerod_password = ""
[merge_mining_proxy.dibbler]

# URL to monerod (default = stagenet)
#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://xmr.support:18081",
# "http://node1.xmr-tw.org:18081",
# "http://xmr.nthrow.nyc:18081",
# "http://node.xmrig.com:18081",
# "http://monero.exan.tech:18081",
# "http://18.132.124.81:18081",
#]

# If authentication is being used for curl. (default = false).
#monerod_use_auth = false

# Username for curl. (default = "").
#monerod_username = ""

# Password for curl. (default = "").
#monerod_password = ""
Loading

0 comments on commit 407160c

Please sign in to comment.