Skip to content

Commit

Permalink
fix!: change monero consensus encoding an update for hardfork v15 (#4492
Browse files Browse the repository at this point in the history
)

Description
---
Monero-rs has sealed their encoding in the newer version. This means we need to encode the struct using our own encoding trait and only using the encoding for the monero versions. 
Upgrade to the newest monero v15 hardfork code.

Also point towards our own monero-rs fork so we can update code when we want to.
  • Loading branch information
SWvheerden authored Aug 19, 2022
1 parent e21dfdb commit 2a3af27
Show file tree
Hide file tree
Showing 11 changed files with 197 additions and 135 deletions.
35 changes: 28 additions & 7 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion applications/tari_merge_mining_proxy/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ async fn main() -> Result<(), anyhow::Error> {

let config = MergeMiningProxyConfig::load_from(&cfg)?;

error!(target: LOG_TARGET, "Configuration: {:?}", config);
info!(target: LOG_TARGET, "Configuration: {:?}", config);
let client = reqwest::Client::builder()
.connect_timeout(Duration::from_secs(5))
.timeout(Duration::from_secs(10))
Expand Down
11 changes: 4 additions & 7 deletions applications/tari_merge_mining_proxy/src/proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,9 @@ use jsonrpc::error::StandardError;
use reqwest::{ResponseBuilderExt, Url};
use serde_json as json;
use tari_app_grpc::tari_rpc as grpc;
use tari_core::proof_of_work::{
monero_difficulty,
monero_rx,
monero_rx::FixedByteArray,
randomx_factory::RandomXFactory,
use tari_core::{
consensus::ConsensusEncoding,
proof_of_work::{monero_difficulty, monero_rx, monero_rx::FixedByteArray, randomx_factory::RandomXFactory},
};
use tari_utilities::hex::Hex;
use tracing::{debug, error, info, instrument, trace, warn};
Expand Down Expand Up @@ -269,8 +267,7 @@ impl InnerService {

let header_mut = block_data.tari_block.header.as_mut().unwrap();
let height = header_mut.height;
header_mut.pow.as_mut().unwrap().pow_data = monero_rx::serialize(&monero_data);

monero_data.consensus_encode(&mut header_mut.pow.as_mut().unwrap().pow_data)?;
let tari_header = header_mut.clone().try_into().map_err(MmProxyError::ConversionError)?;
let mut base_node_client = self.base_node_client.clone();
let start = Instant::now();
Expand Down
2 changes: 1 addition & 1 deletion base_layer/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ integer-encoding = "3.0.2"
lmdb-zero = "0.4.4"
log = "0.4"
log-mdc = "0.1.0"
monero = { version = "^0.13.0", features = ["serde_support"], optional = true }
monero = { git = "https://github.com/tari-project/monero-rs.git", branch = "main" , features = ["serde"], optional = true }
newtype-ops = "0.1.4"
num-traits = "0.2.15"
num-derive = "0.3.3"
Expand Down
16 changes: 16 additions & 0 deletions base_layer/core/src/consensus/consensus_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,22 @@ impl<T: ConsensusEncoding + ConsensusEncodingSized + ?Sized> ToConsensusBytes fo
}
}

pub trait FromConsensusBytes<T>
where T: ConsensusDecoding + ?Sized
{
fn from_consensus_bytes(bytes: &[u8]) -> io::Result<T>;
}

impl<T: ConsensusDecoding + ?Sized> FromConsensusBytes<T> for T {
fn from_consensus_bytes(mut bytes: &[u8]) -> io::Result<T> {
let decoded = Self::consensus_decode(&mut bytes)?;
if !bytes.is_empty() {
return Err(io::Error::new(io::ErrorKind::InvalidData, "Extra bytes at end of data"));
}
Ok(decoded)
}
}

#[cfg(test)]
pub mod test {
use super::*;
Expand Down
1 change: 1 addition & 0 deletions base_layer/core/src/consensus/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub use consensus_encoding::{
ConsensusEncodingSized,
ConsensusHasher,
DomainSeparatedConsensusHasher,
FromConsensusBytes,
MaxSizeBytes,
MaxSizeVec,
ToConsensusBytes,
Expand Down
54 changes: 31 additions & 23 deletions base_layer/core/src/proof_of_work/monero_rx/fixed_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::{convert::TryFrom, io, ops::Deref};

use monero::{
consensus::{encode, Decodable, Encodable},
VarInt,
use std::{
convert::TryFrom,
io,
io::{Read, Write},
ops::Deref,
};

use tari_utilities::{ByteArray, ByteArrayError};

use crate::consensus::{ConsensusDecoding, ConsensusEncoding};

const MAX_ARR_SIZE: usize = 63;

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -109,33 +112,38 @@ impl ByteArray for FixedByteArray {
}
}

impl Decodable for FixedByteArray {
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, encode::Error> {
#[allow(clippy::cast_possible_truncation)]
let len = VarInt::consensus_decode(d)?.0 as usize;
impl ConsensusDecoding for FixedByteArray {
fn consensus_decode<R: Read>(reader: &mut R) -> Result<Self, io::Error> {
let mut buf = [0u8; 1];
reader.read_exact(&mut buf)?;
let len = buf[0] as usize;
if len > MAX_ARR_SIZE {
return Err(encode::Error::ParseFailed(
"length exceeded maximum of 64-bytes for FixedByteArray",
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("length exceeded maximum of 64-bytes for FixedByteArray: {}", len),
));
}
let mut ret = FixedByteArray::new();
for _ in 0..len {
// PANIC: Cannot happen because len has been checked
ret.push(Decodable::consensus_decode(d)?);
let mut buf = [0u8; 1];
reader.read_exact(&mut buf)?;
ret.push(buf[0]);
}
Ok(ret)
}
}

impl Encodable for FixedByteArray {
fn consensus_encode<E: io::Write>(&self, e: &mut E) -> Result<usize, io::Error> {
self.as_slice().consensus_encode(e)
impl ConsensusEncoding for FixedByteArray {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {
writer.write_all(&[self.len][..])?;
writer.write_all(&self.elems[0..self.len()])?;
Ok(())
}
}

#[cfg(test)]
mod test {
use monero::consensus;
use tari_utilities::hex::Hex;

use super::*;
Expand Down Expand Up @@ -167,9 +175,11 @@ mod test {

#[test]
fn serialize_deserialize() {
let data = consensus::serialize(&FixedByteArray::from_hex("ffffffffffffffffffffffffff").unwrap());
let arr = FixedByteArray::from_hex("ffffffffffffffffffffffffff").unwrap();
let mut data = Vec::new();
arr.consensus_encode(&mut data).unwrap();
assert_eq!(data.len(), 13 + 1);
let arr = consensus::deserialize::<FixedByteArray>(&data).unwrap();
let arr = FixedByteArray::consensus_decode(&mut data.as_slice()).unwrap();
assert!(arr.iter().all(|b| *b == 0xff));
}

Expand All @@ -181,19 +191,17 @@ mod test {
assert_eq!(arr.len(), MAX_ARR_SIZE);

buf[0] = 64;
let err = FixedByteArray::consensus_decode(&mut io::Cursor::new(buf)).unwrap_err();
assert!(matches!(err, encode::Error::ParseFailed(_)));
let _err = FixedByteArray::consensus_decode(&mut io::Cursor::new(buf)).unwrap_err();

// VarInt encoding that doesnt terminate, but _would_ represent a number < MAX_ARR_SIZE
buf[0] = 0b1000000;
buf[1] = 0b1000000;
let err = FixedByteArray::consensus_decode(&mut io::Cursor::new(buf)).unwrap_err();
assert!(matches!(err, encode::Error::ParseFailed(_)));
let _err = FixedByteArray::consensus_decode(&mut io::Cursor::new(buf)).unwrap_err();
}

#[test]
fn capacity_overflow_does_not_panic() {
let data = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f];
let _result = consensus::deserialize::<FixedByteArray>(data);
let _result = FixedByteArray::consensus_decode(&mut data.as_slice()).unwrap_err();
}
}
33 changes: 22 additions & 11 deletions base_layer/core/src/proof_of_work/monero_rx/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,10 @@ mod test {
};

use super::*;
use crate::proof_of_work::{monero_rx::fixed_array::FixedByteArray, PowAlgorithm, ProofOfWork};
use crate::{
consensus::ConsensusEncoding,
proof_of_work::{monero_rx::fixed_array::FixedByteArray, PowAlgorithm, ProofOfWork},
};

// This tests checks the hash of monero-rs
#[test]
Expand Down Expand Up @@ -319,7 +322,8 @@ mod test {
coinbase_merkle_proof,
coinbase_tx: block.miner_tx,
};
let serialized = consensus::serialize(&monero_data);
let mut serialized = Vec::new();
monero_data.consensus_encode(&mut serialized).unwrap();
let pow = ProofOfWork {
pow_algo: PowAlgorithm::Monero,
pow_data: serialized,
Expand Down Expand Up @@ -379,7 +383,8 @@ mod test {
coinbase_merkle_proof,
coinbase_tx: block.miner_tx,
};
let serialized = consensus::serialize(&monero_data);
let mut serialized = Vec::new();
monero_data.consensus_encode(&mut serialized).unwrap();
let pow = ProofOfWork {
pow_algo: PowAlgorithm::Monero,
pow_data: serialized,
Expand Down Expand Up @@ -426,7 +431,9 @@ mod test {
coinbase_merkle_proof,
coinbase_tx: block.miner_tx,
};
let serialized = consensus::serialize(&monero_data);

let mut serialized = Vec::new();
monero_data.consensus_encode(&mut serialized).unwrap();
let pow = ProofOfWork {
pow_algo: PowAlgorithm::Monero,
pow_data: serialized,
Expand Down Expand Up @@ -459,7 +466,7 @@ mod test {
nonce: 0,
pow: ProofOfWork::default(),
};
let hash = Hash::null_hash();
let hash = Hash::null();
append_merge_mining_tag(&mut block, hash).unwrap();
let count = 1 + (u16::try_from(block.tx_hashes.len()).unwrap());
let mut hashes = Vec::with_capacity(count as usize);
Expand All @@ -480,7 +487,8 @@ mod test {
coinbase_merkle_proof,
coinbase_tx: block.miner_tx,
};
let serialized = consensus::serialize(&monero_data);
let mut serialized = Vec::new();
monero_data.consensus_encode(&mut serialized).unwrap();
let pow = ProofOfWork {
pow_algo: PowAlgorithm::Monero,
pow_data: serialized,
Expand Down Expand Up @@ -534,7 +542,8 @@ mod test {
coinbase_merkle_proof,
coinbase_tx: Default::default(),
};
let serialized = consensus::serialize(&monero_data);
let mut serialized = Vec::new();
monero_data.consensus_encode(&mut serialized).unwrap();
let pow = ProofOfWork {
pow_algo: PowAlgorithm::Monero,
pow_data: serialized,
Expand Down Expand Up @@ -568,10 +577,11 @@ mod test {
randomx_key: FixedByteArray::default(),
transaction_count: 1,
merkle_root: Default::default(),
coinbase_merkle_proof: create_merkle_proof(&[Hash::null_hash()], &Hash::null_hash()).unwrap(),
coinbase_merkle_proof: create_merkle_proof(&[Hash::null()], &Hash::null()).unwrap(),
coinbase_tx: Default::default(),
};
let serialized = consensus::serialize(&monero_data);
let mut serialized = Vec::new();
monero_data.consensus_encode(&mut serialized).unwrap();
let pow = ProofOfWork {
pow_algo: PowAlgorithm::Monero,
pow_data: serialized,
Expand Down Expand Up @@ -621,11 +631,12 @@ mod test {
header: block.header,
randomx_key: FixedByteArray::from_bytes(&from_hex(&seed_hash).unwrap()).unwrap(),
transaction_count: count,
merkle_root: Hash::null_hash(),
merkle_root: Hash::null(),
coinbase_merkle_proof,
coinbase_tx: block.miner_tx,
};
let serialized = consensus::serialize(&monero_data);
let mut serialized = Vec::new();
monero_data.consensus_encode(&mut serialized).unwrap();
let pow = ProofOfWork {
pow_algo: PowAlgorithm::Monero,
pow_data: serialized,
Expand Down
Loading

0 comments on commit 2a3af27

Please sign in to comment.