Skip to content

Commit

Permalink
Fix NewMiningJob message format
Browse files Browse the repository at this point in the history
- Fix unit test new_mining_job_serialization
- Add testcase for NewMiningJob serialization
  • Loading branch information
jakubtrnka authored and plebhash committed Jan 29, 2025
1 parent e8e8a14 commit 5502fe7
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 2 deletions.
1 change: 1 addition & 0 deletions protocols/v2/roles-logic-sv2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ nohash-hasher = "0.2.0"
siphasher = "1"

[dev-dependencies]
codec_sv2 = { path = "../../../protocols/v2/codec-sv2" }
quickcheck = "1.0.3"
quickcheck_macros = "1"
rand = "0.8.5"
Expand Down
105 changes: 105 additions & 0 deletions protocols/v2/roles-logic-sv2/src/parsers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1295,3 +1295,108 @@ impl<'a> TryFrom<PoolMessages<'a>> for MiningDeviceMessages<'a> {
}
}
}

#[cfg(test)]
mod test {
use crate::{
mining_sv2::NewMiningJob,
parsers::{Mining, PoolMessages},
};
use binary_sv2::{Sv2Option, B032};
use codec_sv2::StandardSv2Frame;
use std::convert::{TryFrom, TryInto};

pub type Message = PoolMessages<'static>;
pub type StdFrame = StandardSv2Frame<Message>;

#[test]
fn new_mining_job_serialization() {
const CORRECTLY_SERIALIZED_MSG: &'static [u8] = &[
0, 128, 21, 49, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 1, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48,
];
let mining_message = PoolMessages::Mining(Mining::NewMiningJob(NewMiningJob {
channel_id: u32::from_le_bytes([1, 2, 3, 4]),
job_id: u32::from_le_bytes([5, 6, 7, 8]),
min_ntime: Sv2Option::new(Some(u32::from_le_bytes([9, 10, 11, 12]))),
version: u32::from_le_bytes([13, 14, 15, 16]),
merkle_root: B032::try_from((17_u8..(17 + 32)).collect::<Vec<u8>>()).unwrap(),
// merkle_root: U256::try_from((17_u8..(17 + 32)).collect::<Vec<u8>>()).unwrap(),
}));
message_serialization_check(mining_message, CORRECTLY_SERIALIZED_MSG);
}

fn message_serialization_check(message: PoolMessages<'static>, expected_result: &[u8]) {
let frame = StdFrame::try_from(message).unwrap();
let encoded_frame_length = frame.encoded_length();

let mut buffer = [0; 0xffff];
frame.serialize(&mut buffer).unwrap();
check_length_consistency(&buffer[..encoded_frame_length]);
check_length_consistency(&expected_result);
assert_eq!(
is_channel_msg(&buffer),
is_channel_msg(&expected_result),
"Unexpected channel_message flag",
);
assert_eq!(
extract_extension_type(&buffer),
extract_extension_type(&expected_result),
"Unexpected extension type",
);
assert_eq!(
extract_message_type(&buffer),
extract_message_type(&expected_result),
"Unexpected message type",
);
assert_eq!(
extract_payload_length(&buffer),
extract_payload_length(&expected_result),
"Unexpected message length",
);
assert_eq!(
encoded_frame_length as u32,
expected_result.len() as u32,
"Method encoded_length() returned different length than the actual message length",
);
assert_eq!(
extract_payload(&buffer[..encoded_frame_length]),
extract_payload(&expected_result),
"Unexpected payload",
)
}

fn is_channel_msg(serialized_frame: &[u8]) -> bool {
let array_repre = serialized_frame[..2].try_into().unwrap();
let decoded_extension_type = u16::from_le_bytes(array_repre);
(decoded_extension_type & (1 << 15)) != 0
}
fn extract_extension_type(serialized_frame: &[u8]) -> u16 {
let array_repre = serialized_frame[..2].try_into().unwrap();
let decoded_extension_type = u16::from_le_bytes(array_repre);
decoded_extension_type & (u16::MAX >> 1)
}
fn extract_message_type(serialized_frame: &[u8]) -> u8 {
serialized_frame[2]
}
fn extract_payload_length(serialized_frame: &[u8]) -> u32 {
let mut array_repre = [0; 4];
array_repre[..3].copy_from_slice(&serialized_frame[3..6]);
u32::from_le_bytes(array_repre)
}
fn extract_payload(serialized_frame: &[u8]) -> &[u8] {
assert!(serialized_frame.len() > 6);
&serialized_frame[6..]
}

fn check_length_consistency(serialized_frame: &[u8]) {
let message_length = extract_payload_length(serialized_frame) as usize;
let payload_length = extract_payload(serialized_frame).len();
assert_eq!(
message_length, payload_length,
"Header declared length [{} bytes] differs from the actual payload length [{} bytes]",
message_length, payload_length,
);
}
}
4 changes: 2 additions & 2 deletions protocols/v2/subprotocols/mining/src/new_mining_job.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use alloc::vec::Vec;
#[cfg(not(feature = "with_serde"))]
use binary_sv2::binary_codec_sv2;
use binary_sv2::{Deserialize, Seq0255, Serialize, Sv2Option, B032, B064K, U256};
use binary_sv2::{Deserialize, Seq0255, Serialize, Sv2Option, B064K, U256};
#[cfg(not(feature = "with_serde"))]
use core::convert::TryInto;

Expand Down Expand Up @@ -49,7 +49,7 @@ pub struct NewMiningJob<'decoder> {
///
/// Note that this field is fixed and cannot be modified by the downstream node.
#[cfg_attr(feature = "with_serde", serde(borrow))]
pub merkle_root: B032<'decoder>,
pub merkle_root: U256<'decoder>,
}

impl<'d> NewMiningJob<'d> {
Expand Down

0 comments on commit 5502fe7

Please sign in to comment.