mod block_template_storage;
mod error;
mod inner;
mod service;
use std::time::Duration;
use futures::FutureExt;
use hyper::server::conn::http1;
use hyper_util::rt::TokioIo;
use log::{error, info};
use tari_common_types::tari_address::TariAddress;
use tari_comms::{multiaddr::Multiaddr, utils::multiaddr::multiaddr_to_socketaddr};
use tari_core::{
base_node::{LocalNodeCommsInterface, StateMachineHandle},
consensus::BaseNodeConsensusManager,
};
use tari_shutdown::ShutdownSignal;
use tari_transaction_components::transaction_components::RangeProofType;
use tokio::net::TcpListener;
use self::{block_template_storage::BlockTemplateStorage, inner::InnerService, service::XmrigProxyService};
const LOG_TARGET: &str = "minotari::base_node::xmrig_proxy";
const CLEANUP_INTERVAL_SECS: u64 = 10 * 60;
pub async fn run_xmrig_proxy(
node_service: LocalNodeCommsInterface,
consensus_rules: BaseNodeConsensusManager,
state_machine: StateMachineHandle,
listener_address: Multiaddr,
wallet_payment_address: TariAddress,
coinbase_extra: Vec<u8>,
range_proof_type: RangeProofType,
shutdown: ShutdownSignal,
) -> Result<(), anyhow::Error> {
let listen_addr = multiaddr_to_socketaddr(&listener_address)?;
let block_templates = BlockTemplateStorage::new();
let cleanup_storage = block_templates.clone();
tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(CLEANUP_INTERVAL_SECS));
loop {
interval.tick().await;
if let Err(e) = std::panic::AssertUnwindSafe(cleanup_storage.remove_outdated())
.catch_unwind()
.await
{
error!(target: LOG_TARGET, "Template cleanup panicked: {e:?}");
}
}
});
let service = XmrigProxyService::new(InnerService {
node_service,
consensus_rules,
state_machine,
block_templates,
wallet_payment_address,
coinbase_extra,
range_proof_type,
});
match TcpListener::bind(listen_addr).await {
Ok(listener) => {
info!(target: LOG_TARGET, "XMRig proxy listening on {listen_addr}");
println!(
"XMRig proxy listening on {listen_addr}. Configure XMRig with: \"coin\": \"tari\", \"url\": \
\"{listen_addr}\", \"daemon\": true"
);
let mut shutdown = shutdown;
loop {
tokio::select! {
_ = &mut shutdown => {
info!(target: LOG_TARGET, "Shutdown signal received, stopping XMRig proxy");
break;
}
result = listener.accept() => {
match result {
Ok((tcp, addr)) => {
info!(target: LOG_TARGET, "XMRig proxy: new connection from {addr}");
let svc = service.clone();
let io = TokioIo::new(tcp);
tokio::task::spawn(async move {
if let Err(e) = http1::Builder::new().serve_connection(io, &svc).await {
error!(target: LOG_TARGET, "XMRig proxy connection error: {e}");
}
});
},
Err(e) => {
error!(target: LOG_TARGET, "XMRig proxy accept error: {e}");
},
}
}
}
}
Ok(())
},
Err(e) => {
error!(
target: LOG_TARGET,
"Cannot bind XMRig proxy to '{listen_addr}': {e}. XMRig solo mining will not be available."
);
Err(e.into())
},
}
}