Skip to content

Commit

Permalink
fix: further block deserialization fixes (#46)
Browse files Browse the repository at this point in the history
* fix: qcommitment seqwit always false

* fix: qcommitment quorumIndex field

* fix: qcommitment signers validmembers bitsets

* correct size

* do not unwrap
  • Loading branch information
ogabrielides authored Oct 31, 2024
1 parent 078ae44 commit e148098
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 4 deletions.
3 changes: 3 additions & 0 deletions dash/src/blockdata/transaction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,9 @@ impl Decodable for Transaction {
if special_transaction_type == TransactionType::AssetUnlock {
segwit = false;
}
if special_transaction_type == TransactionType::QuorumCommitment {
segwit = false;
}
if segwit {
let segwit_flag = u8::consensus_decode_from_finite_reader(r)?;
match segwit_flag {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//! It is defined in DIP6 [dip-0006.md](https://github.com/dashpay/dips/blob/master/dip-0006.md).
//!
use std::io::{Read, Write};
use crate::bls_sig_utils::{BLSPublicKey, BLSSignature};
use crate::consensus::{Decodable, Encodable, encode};
use crate::hash_types::{QuorumHash, QuorumVVecHash};
Expand All @@ -33,6 +34,7 @@ pub struct QuorumFinalizationCommitment {
pub version: u16,
pub llmq_type: u8,
pub quorum_hash: QuorumHash,
pub quorum_index: Option<i16>,
pub signers: Vec<u8>,
pub valid_members: Vec<u8>,
pub quorum_public_key: BLSPublicKey,
Expand All @@ -47,6 +49,9 @@ impl QuorumFinalizationCommitment {
let mut size = 2 + 1 + 32 + 48 + 32 + 96 + 96;
size += VarInt(self.signers.len() as u64).len() + self.signers.len();
size += VarInt(self.valid_members.len() as u64).len() + self.valid_members.len();
if self.version == 2 || self.version == 4 {
size += 2;
}
size
}
}
Expand All @@ -57,6 +62,11 @@ impl Encodable for QuorumFinalizationCommitment {
len += self.version.consensus_encode(w)?;
len += self.llmq_type.consensus_encode(w)?;
len += self.quorum_hash.consensus_encode(w)?;
if let Some(q_index) = self.quorum_index {
if self.version == 2 || self.version == 4 {
len += q_index.consensus_encode(w)?;
}
}
len += self.signers.consensus_encode(w)?;
len += self.valid_members.consensus_encode(w)?;
len += self.quorum_public_key.consensus_encode(w)?;
Expand All @@ -72,8 +82,11 @@ impl Decodable for QuorumFinalizationCommitment {
let version = u16::consensus_decode(r)?;
let llmq_type = u8::consensus_decode(r)?;
let quorum_hash = QuorumHash::consensus_decode(r)?;
let signers = Vec::<u8>::consensus_decode(r)?;
let valid_members = Vec::<u8>::consensus_decode(r)?;
let quorum_index = if version == 2 || version == 4 { Some(i16::consensus_decode(r)?) } else { None };
let signers_count = read_compact_size(r)?;
let signers = read_fixed_bitset(r, signers_count as usize)?;
let valid_members_count = read_compact_size(r)?;
let valid_members = read_fixed_bitset(r, valid_members_count as usize)?;
let quorum_public_key = BLSPublicKey::consensus_decode(r)?;
let quorum_vvec_hash = QuorumVVecHash::consensus_decode(r)?;
let quorum_sig = BLSSignature::consensus_decode(r)?;
Expand All @@ -82,8 +95,9 @@ impl Decodable for QuorumFinalizationCommitment {
version,
llmq_type,
quorum_hash,
signers,
valid_members,
quorum_index,
signers: signers.iter().map(|&b| b as u8).collect(),
valid_members: valid_members.iter().map(|&b| b as u8).collect(),
quorum_public_key,
quorum_vvec_hash,
quorum_sig,
Expand Down Expand Up @@ -130,6 +144,54 @@ impl Decodable for QuorumCommitmentPayload {
}
}

fn read_compact_size<R: Read + ?Sized>(r: &mut R) -> io::Result<u64> {
let mut marker = [0u8; 1];
r.read_exact(&mut marker)?;
match marker[0] {
0xFD => {
// Read the next 2 bytes as a little-endian u16
let mut buf = [0u8; 2];
r.read_exact(&mut buf)?;
Ok(u16::from_le_bytes(buf) as u64)
}
0xFE => {
// Read the next 4 bytes as a little-endian u32
let mut buf = [0u8; 4];
r.read_exact(&mut buf)?;
Ok(u32::from_le_bytes(buf) as u64)
}
0xFF => {
// Read the next 8 bytes as a little-endian u64
let mut buf = [0u8; 8];
r.read_exact(&mut buf)?;
Ok(u64::from_le_bytes(buf))
}
value => {
// For values less than 253, the value is stored directly in the marker byte
Ok(value as u64)
}
}
}

fn read_fixed_bitset<R: Read + ?Sized>(r: &mut R, size: usize) -> std::io::Result<Vec<bool>> {
// Calculate the number of bytes needed
let num_bytes = (size + 7) / 8;
let mut bytes = vec![0u8; num_bytes];

// Read bytes from the reader
r.read_exact(&mut bytes)?;

// Unpack bits into a vector of bools
let mut bits = Vec::with_capacity(size);
for p in 0..size {
let byte = bytes[p / 8];
let bit = (byte >> (p % 8)) & 1;
bits.push(bit != 0);
}

Ok(bits)
}

#[cfg(test)]
mod tests {
use hashes::Hash;
Expand All @@ -151,6 +213,7 @@ mod tests {
version: 0,
llmq_type: 0,
quorum_hash: QuorumHash::all_zeros(),
quorum_index: None,
signers: vec![1, 2, 3, 4, 5],
valid_members: vec![6, 7, 8, 9, 0],
quorum_public_key: BLSPublicKey::from([0; 48]),
Expand Down

0 comments on commit e148098

Please sign in to comment.