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(core): fix block consensus decoding and add tests #4537

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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 20 additions & 1 deletion base_layer/core/src/blocks/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use thiserror::Error;

use crate::{
blocks::BlockHeader,
consensus::{ConsensusConstants, ConsensusDecoding, ConsensusEncoding},
consensus::{ConsensusConstants, ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized},
proof_of_work::ProofOfWork,
transactions::{
aggregated_body::AggregateBody,
Expand Down Expand Up @@ -274,6 +274,12 @@ impl ConsensusEncoding for Block {
}
}

impl ConsensusEncodingSized for Block {
fn consensus_encode_exact_size(&self) -> usize {
self.header.consensus_encode_exact_size() + self.body.consensus_encode_exact_size()
}
}

impl ConsensusDecoding for Block {
fn consensus_decode<R: Read>(reader: &mut R) -> Result<Self, io::Error> {
let header = BlockHeader::consensus_decode(reader)?;
Expand Down Expand Up @@ -325,3 +331,16 @@ impl From<&Block> for NewBlock {
}
}
}

#[cfg(test)]
mod tests {
use tari_common::configuration::Network;

use crate::{blocks::genesis_block::get_genesis_block, consensus::check_consensus_encoding_correctness};

#[test]
fn block_header_encode_decode() {
let block = get_genesis_block(Network::LocalNet).block().clone();
check_consensus_encoding_correctness(block).unwrap();
}
}
6 changes: 3 additions & 3 deletions base_layer/core/src/consensus/consensus_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ impl<T: ConsensusEncoding + ConsensusEncodingSized + ?Sized> ToConsensusBytes fo
fn to_consensus_bytes(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(self.consensus_encode_exact_size());
// Vec's write impl is infallible, as per the ConsensusEncoding contract, consensus_encode is infallible
self.consensus_encode(&mut buf).expect("unreachable panic");
self.consensus_encode(&mut buf)
.expect("invalid ConsensusEncoding implementation detected");
buf
}
}
Expand Down Expand Up @@ -100,8 +101,7 @@ pub mod test {
/// ConsensusDecoding implementations
pub fn check_consensus_encoding_correctness<T>(subject: T) -> Result<(), io::Error>
where T: ConsensusEncoding + ConsensusEncodingSized + ConsensusDecoding + Eq + std::fmt::Debug {
let mut buf = Vec::new();
subject.consensus_encode(&mut buf)?;
let buf = subject.to_consensus_bytes();
assert_eq!(buf.len(), subject.consensus_encode_exact_size());
let mut reader = buf.as_slice();
let decoded = T::consensus_decode(&mut reader)?;
Expand Down
31 changes: 19 additions & 12 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 @@ -29,11 +29,11 @@ use std::{

use tari_utilities::{ByteArray, ByteArrayError};

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

const MAX_ARR_SIZE: usize = 63;

#[derive(Clone, Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FixedByteArray {
elems: [u8; MAX_ARR_SIZE],
len: u8,
Expand Down Expand Up @@ -134,6 +134,12 @@ impl ConsensusDecoding for FixedByteArray {
}
}

impl ConsensusEncodingSized for FixedByteArray {
fn consensus_encode_exact_size(&self) -> usize {
self.len as usize + 1
}
}

impl ConsensusEncoding for FixedByteArray {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {
writer.write_all(&[self.len][..])?;
Expand All @@ -147,6 +153,7 @@ mod test {
use tari_utilities::hex::Hex;

use super::*;
use crate::consensus::check_consensus_encoding_correctness;

#[test]
fn assert_size() {
Expand All @@ -173,16 +180,6 @@ mod test {
FixedByteArray::from_bytes(&[1u8; 64][..]).unwrap_err();
}

#[test]
fn serialize_deserialize() {
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 = FixedByteArray::consensus_decode(&mut data.as_slice()).unwrap();
assert!(arr.iter().all(|b| *b == 0xff));
}

#[test]
fn length_check() {
let mut buf = [0u8; MAX_ARR_SIZE + 1];
Expand All @@ -204,4 +201,14 @@ mod test {
let data = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f];
let _result = FixedByteArray::consensus_decode(&mut data.as_slice()).unwrap_err();
}

#[test]
fn consensus_encoding() {
let arr = FixedByteArray::from_hex("ffffffffffffffffffffffffff").unwrap();
check_consensus_encoding_correctness(arr).unwrap();

let arr = FixedByteArray::from_hex("0ff1ceb4d455").unwrap();
assert_eq!(arr.len(), 6);
check_consensus_encoding_correctness(arr).unwrap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl ConsensusDecoding for MerkleProof {

impl ConsensusEncoding for MerkleProof {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {
let _ = self.branch.consensus_encode(writer)?;
self.branch.consensus_encode(writer)?;
ConsensusEncoding::consensus_encode(&self.depth, writer)?;
ConsensusEncoding::consensus_encode(&self.path_bitmap, writer)?;
Ok(())
Expand Down
6 changes: 3 additions & 3 deletions base_layer/core/src/proof_of_work/monero_rx/pow_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ impl ConsensusDecoding for MoneroPowData {

impl ConsensusEncoding for MoneroPowData {
fn consensus_encode<W: Write>(&self, writer: &mut W) -> Result<(), io::Error> {
let _ = self.header.consensus_encode(writer)?;
self.header.consensus_encode(writer)?;
self.randomx_key.consensus_encode(writer)?;
ConsensusEncoding::consensus_encode(&self.transaction_count, writer)?;
let _ = self.merkle_root.consensus_encode(writer)?;
self.merkle_root.consensus_encode(writer)?;
self.coinbase_merkle_proof.consensus_encode(writer)?;
let _ = self.coinbase_tx.consensus_encode(writer)?;
self.coinbase_tx.consensus_encode(writer)?;
Ok(())
}
}
Expand Down
20 changes: 18 additions & 2 deletions base_layer/core/src/proof_of_work/proof_of_work.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use serde::{Deserialize, Serialize};
use tari_utilities::hex::Hex;

use crate::{
consensus::{ConsensusDecoding, ConsensusEncoding, MaxSizeBytes},
consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized, MaxSizeBytes},
proof_of_work::PowAlgorithm,
};

Expand Down Expand Up @@ -95,6 +95,12 @@ impl ConsensusEncoding for ProofOfWork {
}
}

impl ConsensusEncodingSized for ProofOfWork {
fn consensus_encode_exact_size(&self) -> usize {
self.pow_algo.as_u64().consensus_encode_exact_size() + self.pow_data.consensus_encode_exact_size()
}
}

impl ConsensusDecoding for ProofOfWork {
fn consensus_decode<R: Read>(reader: &mut R) -> Result<Self, io::Error> {
let pow_algo = PowAlgorithm::try_from(u64::consensus_decode(reader)?)
Expand All @@ -109,7 +115,10 @@ impl ConsensusDecoding for ProofOfWork {

#[cfg(test)]
mod test {
use crate::proof_of_work::proof_of_work::{PowAlgorithm, ProofOfWork};
use crate::{
consensus::check_consensus_encoding_correctness,
proof_of_work::proof_of_work::{PowAlgorithm, ProofOfWork},
};

#[test]
fn display() {
Expand All @@ -125,4 +134,11 @@ mod test {
};
assert_eq!(pow.to_bytes(), vec![1]);
}

#[test]
fn consensus_encoding() {
let mut arr = ProofOfWork::new(PowAlgorithm::Monero);
arr.pow_data = vec![1, 2, 3];
check_consensus_encoding_correctness(arr).unwrap();
}
}
23 changes: 22 additions & 1 deletion base_layer/core/src/transactions/aggregated_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ use tari_crypto::{
use tari_script::ScriptContext;

use crate::{
consensus::{ConsensusDecoding, ConsensusEncoding, MaxSizeVec},
consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized, MaxSizeVec},
transactions::{
crypto_factories::CryptoFactories,
tari_amount::MicroTari,
Expand Down Expand Up @@ -578,6 +578,14 @@ impl ConsensusEncoding for AggregateBody {
}
}

impl ConsensusEncodingSized for AggregateBody {
fn consensus_encode_exact_size(&self) -> usize {
self.inputs.consensus_encode_exact_size() +
self.outputs.consensus_encode_exact_size() +
self.kernels.consensus_encode_exact_size()
}
}

impl ConsensusDecoding for AggregateBody {
fn consensus_decode<R: Read>(reader: &mut R) -> Result<Self, io::Error> {
const MAX_SIZE: usize = 50000;
Expand All @@ -588,3 +596,16 @@ impl ConsensusDecoding for AggregateBody {
Ok(body)
}
}

#[cfg(test)]
mod test {
use tari_common::configuration::Network;

use crate::{blocks::genesis_block::get_genesis_block, consensus::check_consensus_encoding_correctness};

#[test]
fn consensus_encoding() {
let body = get_genesis_block(Network::Esmeralda).block().body.clone();
check_consensus_encoding_correctness(body).unwrap();
}
}
4 changes: 4 additions & 0 deletions base_layer/core/src/transactions/test_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ impl TestParams {
script![Nop].consensus_encode_exact_size() + output_features.consensus_encode_exact_size(),
) * num_outputs
}

pub fn commit_value(&self, value: MicroTari) -> Commitment {
self.commitment_factory.commit_value(&self.spend_key, value.as_u64())
}
}

impl Default for TestParams {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ impl ConsensusEncoding for EncryptedValue {

impl ConsensusEncodingSized for EncryptedValue {
fn consensus_encode_exact_size(&self) -> usize {
self.0.len()
SIZE
}
}

Expand All @@ -157,7 +157,7 @@ mod test {
};

use super::*;
use crate::consensus::ToConsensusBytes;
use crate::consensus::{check_consensus_encoding_correctness, ToConsensusBytes};

#[test]
fn it_encodes_to_bytes() {
Expand Down Expand Up @@ -191,4 +191,10 @@ mod test {
assert_eq!(amount, decrypted_value);
}
}
#[test]
fn consensus_encoding() {
let value = [0u8; SIZE];
let encrypted_value = EncryptedValue(value);
check_consensus_encoding_correctness(encrypted_value).unwrap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ impl Display for OutputType {
#[cfg(test)]
mod tests {
use super::*;
use crate::consensus::check_consensus_encoding_correctness;

#[test]
fn it_converts_from_byte_to_output_type() {
Expand All @@ -114,4 +115,10 @@ mod tests {
assert_eq!(OutputType::from_byte(2), Some(OutputType::Burn));
assert_eq!(OutputType::from_byte(255), None);
}

#[test]
fn consensus_encoding() {
let t = OutputType::Standard;
check_consensus_encoding_correctness(t).unwrap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,13 @@ impl ConsensusDecoding for SideChainFeatures {
}

#[cfg(test)]
mod tests {}
mod test {
use super::*;
use crate::consensus::check_consensus_encoding_correctness;

#[test]
fn consensus_encoding() {
let features = SideChainFeatures {};
check_consensus_encoding_correctness(features).unwrap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use tari_script::{ExecutionStack, ScriptContext, StackItem, TariScript};

use super::{TransactionInputVersion, TransactionOutputVersion};
use crate::{
consensus::{ConsensusDecoding, ConsensusEncoding, DomainSeparatedConsensusHasher},
consensus::{ConsensusDecoding, ConsensusEncoding, ConsensusEncodingSized, DomainSeparatedConsensusHasher},
covenants::Covenant,
transactions::{
tari_amount::MicroTari,
Expand Down Expand Up @@ -484,6 +484,8 @@ impl ConsensusEncoding for TransactionInput {
}
}

impl ConsensusEncodingSized for TransactionInput {}

impl ConsensusDecoding for TransactionInput {
fn consensus_decode<R: Read>(reader: &mut R) -> Result<Self, io::Error> {
let version = TransactionInputVersion::consensus_decode(reader)?;
Expand Down Expand Up @@ -583,3 +585,18 @@ impl ConsensusDecoding for SpentOutput {
}
}
}

#[cfg(test)]
mod tests {

use super::*;
use crate::{consensus::check_consensus_encoding_correctness, transactions::test_helpers::create_test_input};

#[test]
fn consensus_encoding() {
let factory = CommitmentFactory::default();

let (input, _) = create_test_input(123.into(), 321, &factory);
check_consensus_encoding_correctness(input).unwrap();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl TryFrom<u8> for TransactionInputVersion {
match value {
0 => Ok(TransactionInputVersion::V0),
1 => Ok(TransactionInputVersion::V1),
_ => Err("Unknown version!".to_string()),
v => Err(format!("Unknown input version {}!", v)),
}
}
}
Expand All @@ -60,7 +60,7 @@ impl ConsensusDecoding for TransactionInputVersion {
reader.read_exact(&mut buf)?;
let version = buf[0]
.try_into()
.map_err(|_| io::Error::new(ErrorKind::InvalidInput, format!("Unknown version {}", buf[0])))?;
.map_err(|_| io::Error::new(ErrorKind::InvalidInput, format!("Unknown input version {}", buf[0])))?;
Ok(version)
}
}
Expand Down