blvm_primitives/serialization/
block.rs1use super::transaction::{
7 deserialize_transaction_with_witness, serialize_transaction, serialize_transaction_with_witness,
8};
9use super::varint::{decode_varint, encode_varint};
10use crate::error::{ConsensusError, Result};
11use crate::types::*;
12use std::borrow::Cow;
13
14#[derive(Debug, Clone, PartialEq, Eq)]
16pub enum BlockParseError {
17 InsufficientBytes,
18 InvalidVersion,
19 InvalidTimestamp,
20 InvalidBits,
21 InvalidNonce,
22 InvalidTransactionCount,
23 InvalidWitnessMarker,
24}
25
26impl std::fmt::Display for BlockParseError {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 match self {
29 BlockParseError::InsufficientBytes => {
30 write!(f, "Insufficient bytes to parse block header")
31 }
32 BlockParseError::InvalidVersion => write!(f, "Invalid block version"),
33 BlockParseError::InvalidTimestamp => write!(f, "Invalid block timestamp"),
34 BlockParseError::InvalidBits => write!(f, "Invalid block bits"),
35 BlockParseError::InvalidNonce => write!(f, "Invalid block nonce"),
36 BlockParseError::InvalidTransactionCount => write!(f, "Invalid transaction count"),
37 BlockParseError::InvalidWitnessMarker => write!(f, "Invalid witness marker"),
38 }
39 }
40}
41
42impl std::error::Error for BlockParseError {}
43
44pub fn serialize_block_header(header: &BlockHeader) -> Vec<u8> {
46 let mut result = Vec::with_capacity(80);
47 result.extend_from_slice(&(header.version as i32).to_le_bytes());
48 result.extend_from_slice(&header.prev_block_hash);
49 result.extend_from_slice(&header.merkle_root);
50 result.extend_from_slice(&(header.timestamp as u32).to_le_bytes());
51 result.extend_from_slice(&(header.bits as u32).to_le_bytes());
52 result.extend_from_slice(&(header.nonce as u32).to_le_bytes());
53 assert_eq!(result.len(), 80);
54 result
55}
56
57pub fn deserialize_block_header(data: &[u8]) -> Result<BlockHeader> {
59 if data.len() < 80 {
60 return Err(ConsensusError::Serialization(Cow::Owned(
61 BlockParseError::InsufficientBytes.to_string(),
62 )));
63 }
64
65 let mut offset = 0;
66
67 let version = i32::from_le_bytes([
68 data[offset],
69 data[offset + 1],
70 data[offset + 2],
71 data[offset + 3],
72 ]) as i64;
73 offset += 4;
74
75 let mut prev_block_hash = [0u8; 32];
76 prev_block_hash.copy_from_slice(&data[offset..offset + 32]);
77 offset += 32;
78
79 let mut merkle_root = [0u8; 32];
80 merkle_root.copy_from_slice(&data[offset..offset + 32]);
81 offset += 32;
82
83 let timestamp = u32::from_le_bytes([
84 data[offset],
85 data[offset + 1],
86 data[offset + 2],
87 data[offset + 3],
88 ]) as u64;
89 offset += 4;
90
91 let bits = u32::from_le_bytes([
92 data[offset],
93 data[offset + 1],
94 data[offset + 2],
95 data[offset + 3],
96 ]) as u64;
97 offset += 4;
98
99 let nonce = u32::from_le_bytes([
100 data[offset],
101 data[offset + 1],
102 data[offset + 2],
103 data[offset + 3],
104 ]) as u64;
105
106 Ok(BlockHeader {
107 version,
108 prev_block_hash,
109 merkle_root,
110 timestamp,
111 bits,
112 nonce,
113 })
114}
115
116pub fn deserialize_block_with_witnesses(data: &[u8]) -> Result<(Block, Vec<Vec<Witness>>)> {
118 if data.len() < 80 {
119 return Err(ConsensusError::Serialization(Cow::Owned(
120 BlockParseError::InsufficientBytes.to_string(),
121 )));
122 }
123
124 let mut offset = 0;
125
126 let header = deserialize_block_header(&data[offset..offset + 80])?;
127 offset += 80;
128
129 let (tx_count, varint_len) = decode_varint(&data[offset..])?;
130 offset += varint_len;
131
132 if tx_count == 0 {
133 return Err(ConsensusError::Serialization(Cow::Owned(
134 BlockParseError::InvalidTransactionCount.to_string(),
135 )));
136 }
137
138 let mut transactions = Vec::new();
139 let mut all_witnesses: Vec<Vec<Witness>> = Vec::new();
140
141 for _ in 0..tx_count {
142 let (tx, input_witnesses, bytes_consumed) =
143 deserialize_transaction_with_witness(&data[offset..])?;
144 offset += bytes_consumed;
145 transactions.push(tx);
146 all_witnesses.push(input_witnesses);
147 }
148
149 while all_witnesses.len() < transactions.len() {
150 all_witnesses.push(Vec::new());
151 }
152
153 Ok((
154 Block::from_parts(header, transactions.into_boxed_slice()),
155 all_witnesses,
156 ))
157}
158
159pub fn serialize_block_with_witnesses(
161 block: &Block,
162 witnesses: &[Vec<Witness>],
163 include_witness: bool,
164) -> Vec<u8> {
165 let mut result = Vec::new();
166
167 result.extend_from_slice(&serialize_block_header(&block.header));
168 result.extend_from_slice(&encode_varint(block.transactions.len() as u64));
169
170 for (i, tx) in block.transactions.iter().enumerate() {
173 let tx_witnesses = witnesses.get(i);
174 let use_witness = include_witness
175 && tx_witnesses.is_some_and(|stacks| {
176 stacks.len() == tx.inputs.len() && stacks.iter().any(|stack| !stack.is_empty())
177 });
178 if use_witness {
179 result.extend_from_slice(&serialize_transaction_with_witness(
180 tx,
181 tx_witnesses.unwrap(),
182 ));
183 } else {
184 result.extend_from_slice(&serialize_transaction(tx));
185 }
186 }
187
188 result
189}
190
191pub fn serialize_block(block: &Block) -> Vec<u8> {
193 let witnesses: Vec<Vec<Witness>> = block.transactions.iter().map(|_| Vec::new()).collect();
194 serialize_block_with_witnesses(block, &witnesses, false)
195}
196
197pub fn validate_block_serialized_size(
199 block: &Block,
200 witnesses: &[Vec<Witness>],
201 include_witness: bool,
202 provided_size: usize,
203) -> bool {
204 let serialized = serialize_block_with_witnesses(block, witnesses, include_witness);
205 serialized.len() == provided_size
206}