Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: add aux chain support for merge mining #5976

Merged
merged 14 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 28 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions applications/minotari_merge_mining_proxy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ hex = "0.4.2"
hyper = "0.14.12"
jsonrpc = "0.12.0"
log = { version = "0.4.8", features = ["std"] }
monero = { version = "0.18" }
reqwest = { version = "0.11.4", features = ["json"] }
serde = { version = "1.0.106", features = ["derive"] }
serde_json = "1.0.57"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use std::{collections::HashMap, sync::Arc};
use chrono::Duration;
use chrono::{self, DateTime, Utc};
use minotari_node_grpc_client::grpc;
use tari_common_types::types::FixedHash;
use tari_core::proof_of_work::monero_rx::FixedByteArray;
use tokio::sync::RwLock;
use tracing::trace;
Expand Down Expand Up @@ -125,6 +126,8 @@ pub struct BlockTemplateData {
pub tari_miner_data: grpc::MinerData,
pub monero_difficulty: u64,
pub tari_difficulty: u64,
pub tari_hash: FixedHash,
pub aux_chain_hashes: Vec<monero::Hash>,
}

impl BlockTemplateData {}
Expand All @@ -137,6 +140,8 @@ pub struct BlockTemplateDataBuilder {
tari_miner_data: Option<grpc::MinerData>,
monero_difficulty: Option<u64>,
tari_difficulty: Option<u64>,
tari_hash: Option<FixedHash>,
aux_chain_hashes: Vec<monero::Hash>,
}

impl BlockTemplateDataBuilder {
Expand Down Expand Up @@ -169,6 +174,16 @@ impl BlockTemplateDataBuilder {
self
}

pub fn tari_hash(mut self, hash: FixedHash) -> Self {
self.tari_hash = Some(hash);
self
}

pub fn aux_hashes(mut self, aux_chain_hashes: Vec<monero::Hash>) -> Self {
self.aux_chain_hashes = aux_chain_hashes;
self
}

/// Build a new [BlockTemplateData], all the values have to be set.
///
/// # Errors
Expand All @@ -190,13 +205,21 @@ impl BlockTemplateDataBuilder {
let tari_difficulty = self
.tari_difficulty
.ok_or_else(|| MmProxyError::MissingDataError("tari_difficulty not provided".to_string()))?;
let tari_hash = self
.tari_hash
.ok_or_else(|| MmProxyError::MissingDataError("tari_hash not provided".to_string()))?;
if self.aux_chain_hashes.is_empty() {
return Err(MmProxyError::MissingDataError("aux chain hashes are empty".to_string()));
};

Ok(BlockTemplateData {
monero_seed,
tari_block,
tari_miner_data,
monero_difficulty,
tari_difficulty,
tari_hash,
aux_chain_hashes: self.aux_chain_hashes,
})
}
}
Expand All @@ -216,6 +239,7 @@ pub mod test {
let header = BlockHeader::new(100);
let body = AggregateBody::empty();
let block = Block::new(header, body);
let hash = block.hash();
let miner_data = grpc::MinerData {
reward: 10000,
target_difficulty: 600000,
Expand All @@ -227,7 +251,9 @@ pub mod test {
.tari_block(block.try_into().unwrap())
.tari_miner_data(miner_data)
.monero_difficulty(123456)
.tari_difficulty(12345);
.tari_difficulty(12345)
.tari_hash(hash)
.aux_hashes(vec![monero::Hash::from_slice(hash.as_slice())]);
btdb.build().unwrap()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

//! Methods for seting up a new block.

use std::{cmp, str::FromStr, sync::Arc};
use std::{cmp, convert::TryFrom, str::FromStr, sync::Arc};

use log::*;
use minotari_app_grpc::{authentication::ClientAuthenticationInterceptor, tari_rpc::base_node_client::BaseNodeClient};
use minotari_node_grpc_client::grpc;
use tari_common_types::tari_address::TariAddress;
use tari_common_types::{tari_address::TariAddress, types::FixedHash};
use tari_core::{
consensus::ConsensusManager,
proof_of_work::{monero_rx, monero_rx::FixedByteArray, Difficulty},
Expand Down Expand Up @@ -61,11 +60,11 @@ impl<'a> BlockTemplateProtocol<'a> {
pub async fn new(
base_node_client: &'a mut BaseNodeClient<InterceptedService<Channel, ClientAuthenticationInterceptor>>,
config: Arc<MergeMiningProxyConfig>,
consensus_manager: ConsensusManager,
) -> Result<BlockTemplateProtocol<'a>, MmProxyError> {
let key_manager = create_memory_db_key_manager();
let wallet_payment_address = TariAddress::from_str(&config.wallet_payment_address)
.map_err(|err| MmProxyError::WalletPaymentAddress(err.to_string()))?;
let consensus_manager = ConsensusManager::builder(config.network).build()?;
Ok(Self {
config,
base_node_client,
Expand Down Expand Up @@ -242,6 +241,11 @@ impl BlockTemplateProtocol<'_> {
.monero_seed(monero_mining_data.seed_hash)
.monero_difficulty(monero_mining_data.difficulty)
.tari_difficulty(tari_difficulty)
.tari_hash(
FixedHash::try_from(tari_block.merge_mining_hash.clone())
.map_err(|e| MmProxyError::MissingDataError(e.to_string()))?,
)
.aux_hashes(vec![monero::Hash::from_slice(&tari_block.merge_mining_hash)])
.build()?;

// Deserialize the block template blob
Expand All @@ -250,7 +254,15 @@ impl BlockTemplateProtocol<'_> {

debug!(target: LOG_TARGET, "Insert Merged Mining Tag",);
// Add the Tari merge mining tag to the retrieved block template
monero_rx::insert_merge_mining_tag_into_block(&mut monero_block, &tari_block.merge_mining_hash)?;
// We need to send the MR al all aux chains, but a single chain, aka minotari only, means we only need the tari
// hash
let aux_chain_mr = tari_block.merge_mining_hash.clone();
monero_rx::insert_merge_mining_tag_and_aux_chain_merkle_root_into_block(
&mut monero_block,
&aux_chain_mr,
1,
0,
)?;

debug!(target: LOG_TARGET, "Creating blockhashing blob from blocktemplate blob",);
// Must be done after the tag is inserted since it will affect the hash of the miner tx
Expand All @@ -266,12 +278,16 @@ impl BlockTemplateProtocol<'_> {
monero_mining_data.difficulty,
mining_difficulty
);
let merge_mining_hash = FixedHash::try_from(tari_block.merge_mining_hash.clone())
.map_err(|e| MmProxyError::MissingDataError(e.to_string()))?;
Ok(FinalBlockTemplateData {
template: block_template_data,
target_difficulty: Difficulty::from_u64(mining_difficulty)?,
blockhashing_blob,
blocktemplate_blob,
merge_mining_hash: tari_block.merge_mining_hash,
merge_mining_hash,
aux_chain_hashes: vec![monero::Hash::from_slice(&tari_block.merge_mining_hash)],
aux_chain_mr: tari_block.merge_mining_hash,
})
}
}
Expand All @@ -296,7 +312,9 @@ pub struct FinalBlockTemplateData {
pub target_difficulty: Difficulty,
pub blockhashing_blob: String,
pub blocktemplate_blob: String,
pub merge_mining_hash: Vec<u8>,
pub merge_mining_hash: FixedHash,
pub aux_chain_hashes: Vec<monero::Hash>,
pub aux_chain_mr: Vec<u8>,
}

/// Container struct for monero mining data inputs obtained from monerod
Expand Down
39 changes: 25 additions & 14 deletions applications/minotari_merge_mining_proxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,9 @@ use minotari_node_grpc_client::{grpc, grpc::base_node_client::BaseNodeClient};
use minotari_wallet_grpc_client::ClientAuthenticationInterceptor;
use reqwest::{ResponseBuilderExt, Url};
use serde_json as json;
use tari_core::proof_of_work::{
monero_rx,
monero_rx::FixedByteArray,
randomx_difficulty,
randomx_factory::RandomXFactory,
use tari_core::{
consensus::ConsensusManager,
proof_of_work::{monero_rx, monero_rx::FixedByteArray, randomx_difficulty, randomx_factory::RandomXFactory},
};
use tari_utilities::hex::Hex;
use tonic::{codegen::InterceptedService, transport::Channel};
Expand Down Expand Up @@ -79,9 +77,10 @@ impl MergeMiningProxyService {
base_node_client: BaseNodeClient<InterceptedService<Channel, ClientAuthenticationInterceptor>>,
block_templates: BlockTemplateRepository,
randomx_factory: RandomXFactory,
) -> Self {
) -> Result<Self, MmProxyError> {
debug!(target: LOG_TARGET, "Config: {:?}", config);
Self {
let consensus_manager = ConsensusManager::builder(config.network).build()?;
Ok(Self {
inner: InnerService {
config: Arc::new(config),
block_templates,
Expand All @@ -91,8 +90,9 @@ impl MergeMiningProxyService {
current_monerod_server: Arc::new(RwLock::new(None)),
last_assigned_monerod_server: Arc::new(RwLock::new(None)),
randomx_factory,
consensus_manager,
},
}
})
}
}

Expand Down Expand Up @@ -161,6 +161,7 @@ struct InnerService {
current_monerod_server: Arc<RwLock<Option<String>>>,
last_assigned_monerod_server: Arc<RwLock<Option<String>>>,
randomx_factory: RandomXFactory,
consensus_manager: ConsensusManager,
}

impl InnerService {
Expand Down Expand Up @@ -238,10 +239,12 @@ impl InnerService {
},
};

let gen_hash = *self.consensus_manager.get_genesis_block().hash();

for param in params.iter().filter_map(|p| p.as_str()) {
let monero_block = monero_rx::deserialize_monero_block_from_hex(param)?;
debug!(target: LOG_TARGET, "Monero block: {}", monero_block);
let hash = monero_rx::extract_tari_hash_from_block(&monero_block)?.ok_or_else(|| {
let hash = monero_rx::extract_aux_merkle_root_from_block(&monero_block)?.ok_or_else(|| {
MmProxyError::MissingDataError("Could not find Minotari header in coinbase".to_string())
})?;

Expand All @@ -262,8 +265,12 @@ impl InnerService {
continue;
},
};

let monero_data = monero_rx::construct_monero_data(monero_block, block_data.monero_seed.clone())?;
let monero_data = monero_rx::construct_monero_data(
monero_block,
block_data.monero_seed.clone(),
block_data.aux_chain_hashes.clone(),
block_data.tari_hash,
)?;

debug!(target: LOG_TARGET, "Monero PoW Data: {:?}", monero_data);

Expand All @@ -276,7 +283,7 @@ impl InnerService {
let start = Instant::now();
let achieved_target = if self.config.check_tari_difficulty_before_submit {
trace!(target: LOG_TARGET, "Starting calculate achieved Tari difficultly");
let diff = randomx_difficulty(&tari_header, &self.randomx_factory)?;
let diff = randomx_difficulty(&tari_header, &self.randomx_factory, &gen_hash)?;
trace!(
target: LOG_TARGET,
"Finished calculate achieved Tari difficultly - achieved {} vs. target {}",
Expand Down Expand Up @@ -425,7 +432,8 @@ impl InnerService {
}
}

let new_block_protocol = BlockTemplateProtocol::new(&mut grpc_client, self.config.clone()).await?;
let new_block_protocol =
BlockTemplateProtocol::new(&mut grpc_client, self.config.clone(), self.consensus_manager.clone()).await?;

let seed_hash = FixedByteArray::from_hex(&monerod_resp["result"]["seed_hash"].to_string().replace('\"', ""))
.map_err(|err| MmProxyError::InvalidMonerodResponse(format!("seed hash hex is invalid: {}", err)))?;
Expand Down Expand Up @@ -472,7 +480,10 @@ impl InnerService {
);

self.block_templates
.save(mining_hash, final_block_template_data.template)
.save(
final_block_template_data.aux_chain_mr,
final_block_template_data.template,
)
.await;

debug!(target: LOG_TARGET, "Returning template result: {}", monerod_resp);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub async fn start_merge_miner(cli: Cli) -> Result<(), anyhow::Error> {
base_node_client,
BlockTemplateRepository::new(),
randomx_factory,
);
)?;
let service = make_service_fn(|_conn| future::ready(Result::<_, Infallible>::Ok(randomx_service.clone())));

match Server::try_bind(&listen_addr) {
Expand Down