Skip to content

Commit

Permalink
fix: only allow a monero header if it serializes back to the same data (
Browse files Browse the repository at this point in the history
tari-project#5716)

Description
---
Adds a check that the serialized monero POWdata matches the deserialized
data

Co-authored-by: SW van Heerden <swvheerden@gmail.com>
  • Loading branch information
stringhandler and SWvheerden committed Sep 1, 2023
1 parent 5ebeab1 commit e70c752
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 0 deletions.
2 changes: 2 additions & 0 deletions base_layer/core/src/proof_of_work/monero_rx/error.rs
Expand Up @@ -28,6 +28,8 @@ use crate::proof_of_work::DifficultyError;
/// Errors that can occur when merging Monero PoW data with Tari PoW data
#[derive(Debug, thiserror::Error)]
pub enum MergeMineError {
#[error("Serialized POWData does not match provided data: {0}")]
SerializedPowDataDoesNotMatch(String),
#[error("Serialization error: {0}")]
SerializeError(String),
#[error("Error deserializing Monero data: {0}")]
Expand Down
3 changes: 3 additions & 0 deletions base_layer/core/src/proof_of_work/monero_rx/merkle_tree.rs
Expand Up @@ -173,6 +173,9 @@ impl MerkleProof {
}

/// Calculates the merkle root hash from the provide Monero hash
/// The coinbase must be the first transaction in the block, so
/// that you can't have multiple coinbases in a block. That means the coinbase
/// is always the leftmost branch in the merkle tree
pub fn calculate_root(&self, hash: &Hash) -> Hash {
if self.branch.is_empty() {
return *hash;
Expand Down
15 changes: 15 additions & 0 deletions base_layer/core/src/proof_of_work/monero_rx/pow_data.rs
Expand Up @@ -103,6 +103,21 @@ impl MoneroPowData {
v.len()
)));
}
let mut test_serialized_data = vec![];

// This is an inefficient test, so maybe it can be removed in future, but because we rely
// on third party parsing libraries, there could be a case where the data we deserialized
// can be generated from multiple input data. This way we test that there is only one of those
// inputs that is allowed. Remember that the data in powdata is used for the hash, so having
// multiple pow_data that generate the same randomx difficulty could be a problem.
BorshSerialize::serialize(&pow_data, &mut test_serialized_data)
.map_err(|e| MergeMineError::SerializeError(format!("{:?}", e)))?;
if test_serialized_data != tari_header.pow.pow_data {
return Err(MergeMineError::SerializedPowDataDoesNotMatch(
"Serialized pow data does not match original pow data".to_string(),
));
}

Ok(pow_data)
}

Expand Down

0 comments on commit e70c752

Please sign in to comment.