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

fix!: change monero consensus encoding an update for hardfork v15 #4492

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this can be simplified a bit (decodes from slice/vec encoding)

  let len = u64::consensus_decode(reader)? as usize;
        if len > MAX_ARR_SIZE {
            return Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("length exceeded maximum of {}-bytes for FixedByteArray: {}", MAX_ARR_SIZE, len),
            ));
        }
        let mut buf = [0u8; MAX_ARR_SIZE];
        reader.read_exact(&mut buf[..len])?;

        Ok(FixedByteArray{
            elems: buf,
            len: len as u8,
        })

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()])?;
SWvheerden marked this conversation as resolved.
Show resolved Hide resolved
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