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