1use crate::ConsensusError;
13use crate::Result;
14use crate::error::ProtocolError;
15use crate::network::NetworkMessage;
16use std::borrow::Cow;
17use std::io::Read;
18use std::sync::Arc;
19
20mod frame_header;
21pub use frame_header::{MAX_MESSAGE_PAYLOAD, MESSAGE_HEADER_SIZE, calculate_checksum};
22
23pub fn serialize_message(message: &NetworkMessage, magic_bytes: [u8; 4]) -> Result<Vec<u8>> {
25 use crate::network::*;
26
27 let (command, payload) = match message {
29 NetworkMessage::Version(v) => ("version", serialize_version(v)?),
30 NetworkMessage::VerAck => ("verack", vec![]),
31 NetworkMessage::Addr(a) => ("addr", serialize_addr(a)?),
32 NetworkMessage::AddrV2(a) => ("addrv2", serialize_addrv2(a)?),
33 NetworkMessage::Inv(i) => ("inv", serialize_inv(i)?),
34 NetworkMessage::GetData(g) => ("getdata", serialize_getdata(g)?),
35 NetworkMessage::GetHeaders(gh) => ("getheaders", serialize_getheaders(gh)?),
36 NetworkMessage::Headers(h) => ("headers", serialize_headers(h)?),
37 NetworkMessage::Block(b, witnesses) => ("block", serialize_block_witnesses(b, witnesses)?),
38 NetworkMessage::Tx(tx, witnesses) => ("tx", serialize_tx_with_witness(tx, witnesses)?),
39 NetworkMessage::Ping(p) => ("ping", serialize_ping(p)?),
40 NetworkMessage::Pong(p) => ("pong", serialize_pong(p)?),
41 NetworkMessage::MemPool => ("mempool", vec![]),
42 NetworkMessage::FeeFilter(f) => ("feefilter", serialize_feefilter(f)?),
43 NetworkMessage::GetBlocks(gb) => ("getblocks", serialize_getblocks(gb)?),
44 NetworkMessage::GetAddr => ("getaddr", vec![]),
45 NetworkMessage::NotFound(nf) => ("notfound", serialize_notfound(nf)?),
46 NetworkMessage::Reject(r) => ("reject", serialize_reject(r)?),
47 NetworkMessage::SendHeaders => ("sendheaders", vec![]),
48 NetworkMessage::SendCmpct(sc) => ("sendcmpct", serialize_sendcmpct(sc)?),
49 NetworkMessage::CmpctBlock(cb) => ("cmpctblock", serialize_cmpctblock(cb)?),
50 NetworkMessage::GetBlockTxn(gbt) => ("getblocktxn", serialize_getblocktxn(gbt)?),
51 NetworkMessage::BlockTxn(bt) => ("blocktxn", serialize_blocktxn(bt)?),
52 #[cfg(feature = "utxo-commitments")]
53 NetworkMessage::GetUTXOSet(gus) => ("getutxoset", serialize_getutxoset(gus)?),
54 #[cfg(feature = "utxo-commitments")]
55 NetworkMessage::UTXOSet(us) => ("utxoset", serialize_utxoset(us)?),
56 #[cfg(feature = "utxo-commitments")]
57 NetworkMessage::GetFilteredBlock(gfb) => {
58 ("getfilteredblock", serialize_getfilteredblock(gfb)?)
59 }
60 #[cfg(feature = "utxo-commitments")]
61 NetworkMessage::FilteredBlock(fb) => ("filteredblock", serialize_filteredblock(fb)?),
62 NetworkMessage::GetBanList(gbl) => ("getbanlist", serialize_getbanlist(gbl)?),
63 NetworkMessage::BanList(bl) => ("banlist", serialize_banlist(bl)?),
64 };
65
66 if payload.len() > MAX_MESSAGE_PAYLOAD {
68 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
69 Cow::Owned(format!(
70 "Message payload too large: {} bytes",
71 payload.len()
72 )),
73 )));
74 }
75
76 let checksum = calculate_checksum(&payload);
78
79 let mut message_bytes = Vec::with_capacity(MESSAGE_HEADER_SIZE + payload.len());
81
82 message_bytes.extend_from_slice(&magic_bytes);
84
85 let mut command_bytes = [0u8; 12];
87 let cmd_len = command.len().min(12);
88 command_bytes[..cmd_len].copy_from_slice(&command.as_bytes()[..cmd_len]);
89 message_bytes.extend_from_slice(&command_bytes);
90
91 message_bytes.extend_from_slice(&(payload.len() as u32).to_le_bytes());
93
94 message_bytes.extend_from_slice(&checksum);
96
97 message_bytes.extend_from_slice(&payload);
99
100 Ok(message_bytes)
101}
102
103pub fn deserialize_message<R: Read>(
105 reader: &mut R,
106 expected_magic: [u8; 4],
107) -> Result<(NetworkMessage, usize)> {
108 use crate::network::*;
109
110 let mut header = [0u8; MESSAGE_HEADER_SIZE];
112 reader.read_exact(&mut header).map_err(|e| {
113 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
114 "IO error: {e}"
115 ))))
116 })?;
117
118 let magic = [header[0], header[1], header[2], header[3]];
120 if magic != expected_magic {
121 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
122 Cow::Owned(format!(
123 "Invalid magic bytes: {magic:?}, expected {expected_magic:?}"
124 )),
125 )));
126 }
127
128 let command_bytes = &header[4..16];
130 let command_len = command_bytes.iter().position(|&b| b == 0).unwrap_or(12);
131 if command_bytes[command_len..].iter().any(|&b| b != 0) {
132 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
133 Cow::Owned(format!("Non-zero command padding in {command_bytes:?}")),
134 )));
135 }
136 let command = std::str::from_utf8(&command_bytes[..command_len]).map_err(|e| {
137 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
138 "Invalid command: {e}"
139 ))))
140 })?;
141
142 let length_bytes = [header[16], header[17], header[18], header[19]];
144 let payload_length = u32::from_le_bytes(length_bytes) as usize;
145
146 if payload_length > MAX_MESSAGE_PAYLOAD {
147 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
148 Cow::Owned(format!("Payload length too large: {payload_length} bytes")),
149 )));
150 }
151
152 let checksum = [header[20], header[21], header[22], header[23]];
154
155 let mut payload = vec![0u8; payload_length];
157 if payload_length > 0 {
158 reader.read_exact(&mut payload).map_err(|e| {
159 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
160 "IO error: {e}"
161 ))))
162 })?;
163 }
164
165 let calculated_checksum = calculate_checksum(&payload);
167 if calculated_checksum != checksum {
168 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
169 Cow::Owned("Checksum mismatch".to_string()),
170 )));
171 }
172
173 let message = match command {
175 "version" => NetworkMessage::Version(deserialize_version(&payload)?),
176 "verack" => NetworkMessage::VerAck,
177 "addr" => NetworkMessage::Addr(deserialize_addr(&payload)?),
178 "addrv2" => NetworkMessage::AddrV2(deserialize_addrv2(&payload)?),
179 "inv" => NetworkMessage::Inv(deserialize_inv(&payload)?),
180 "getdata" => NetworkMessage::GetData(deserialize_getdata(&payload)?),
181 "getheaders" => NetworkMessage::GetHeaders(deserialize_getheaders(&payload)?),
182 "headers" => NetworkMessage::Headers(deserialize_headers(&payload)?),
183 "block" => {
184 let (block, witnesses) = deserialize_block_with_witnesses_pair(&payload)?;
185 NetworkMessage::Block(Arc::new(block), witnesses)
186 }
187 "tx" => {
188 let (tx, witnesses) = deserialize_tx_with_witness(&payload)?;
189 NetworkMessage::Tx(Arc::new(tx), witnesses)
190 }
191 "ping" => NetworkMessage::Ping(deserialize_ping(&payload)?),
192 "pong" => NetworkMessage::Pong(deserialize_pong(&payload)?),
193 "mempool" => NetworkMessage::MemPool,
194 "feefilter" => NetworkMessage::FeeFilter(deserialize_feefilter(&payload)?),
195 "getblocks" => NetworkMessage::GetBlocks(deserialize_getblocks(&payload)?),
196 "getaddr" => NetworkMessage::GetAddr,
197 "notfound" => NetworkMessage::NotFound(deserialize_notfound(&payload)?),
198 "reject" => NetworkMessage::Reject(deserialize_reject(&payload)?),
199 "sendheaders" => NetworkMessage::SendHeaders,
200 "sendcmpct" => NetworkMessage::SendCmpct(deserialize_sendcmpct(&payload)?),
201 "cmpctblock" => NetworkMessage::CmpctBlock(deserialize_cmpctblock(&payload)?),
202 "getblocktxn" => NetworkMessage::GetBlockTxn(deserialize_getblocktxn(&payload)?),
203 "blocktxn" => NetworkMessage::BlockTxn(deserialize_blocktxn(&payload)?),
204 #[cfg(feature = "utxo-commitments")]
205 "getutxoset" => NetworkMessage::GetUTXOSet(deserialize_getutxoset(&payload)?),
206 #[cfg(feature = "utxo-commitments")]
207 "utxoset" => NetworkMessage::UTXOSet(deserialize_utxoset(&payload)?),
208 #[cfg(feature = "utxo-commitments")]
209 "getfilteredblock" => {
210 NetworkMessage::GetFilteredBlock(deserialize_getfilteredblock(&payload)?)
211 }
212 #[cfg(feature = "utxo-commitments")]
213 "filteredblock" => NetworkMessage::FilteredBlock(deserialize_filteredblock(&payload)?),
214 "getbanlist" => NetworkMessage::GetBanList(deserialize_getbanlist(&payload)?),
215 "banlist" => NetworkMessage::BanList(deserialize_banlist(&payload)?),
216 _ => {
217 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
218 Cow::Owned(format!("Unknown command: {command}")),
219 )));
220 }
221 };
222
223 Ok((message, MESSAGE_HEADER_SIZE + payload_length))
224}
225
226fn serialize_network_address(addr: &crate::network::NetworkAddress) -> Vec<u8> {
231 let mut buf = Vec::with_capacity(26);
232 buf.extend_from_slice(&addr.services.to_le_bytes());
234 buf.extend_from_slice(&addr.ip);
236 buf.extend_from_slice(&addr.port.to_be_bytes());
238 buf
239}
240
241fn deserialize_network_address(data: &[u8]) -> Result<crate::network::NetworkAddress> {
243 if data.len() < 26 {
244 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
245 Cow::Owned("NetworkAddress too short".to_string()),
246 )));
247 }
248
249 let services = u64::from_le_bytes([
251 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
252 ]);
253
254 let mut ip = [0u8; 16];
256 ip.copy_from_slice(&data[8..24]);
257
258 let port = u16::from_be_bytes([data[24], data[25]]);
260
261 Ok(crate::network::NetworkAddress {
262 time: 0,
263 services,
264 ip,
265 port,
266 })
267}
268
269pub fn serialize_version(v: &crate::network::VersionMessage) -> Result<Vec<u8>> {
281 use crate::varint::write_varint;
282
283 let mut buf = Vec::new();
284
285 buf.extend_from_slice(&v.version.to_le_bytes());
286
287 buf.extend_from_slice(&v.services.to_le_bytes());
289
290 buf.extend_from_slice(&v.timestamp.to_le_bytes());
292
293 buf.extend_from_slice(&serialize_network_address(&v.addr_recv));
295
296 buf.extend_from_slice(&serialize_network_address(&v.addr_from));
298
299 buf.extend_from_slice(&v.nonce.to_le_bytes());
301
302 let user_agent_bytes = v.user_agent.as_bytes();
304 write_varint(&mut buf, user_agent_bytes.len() as u64)?;
305 buf.extend_from_slice(user_agent_bytes);
306
307 buf.extend_from_slice(&v.start_height.to_le_bytes());
309
310 buf.push(if v.relay { 1 } else { 0 });
312
313 Ok(buf)
314}
315
316pub fn deserialize_version(data: &[u8]) -> Result<crate::network::VersionMessage> {
318 use crate::varint::read_varint;
319 use std::io::Cursor;
320
321 let mut cursor = Cursor::new(data);
322
323 let mut version_bytes = [0u8; 4];
325 cursor.read_exact(&mut version_bytes).map_err(|e| {
326 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
327 "Failed to read version: {e}"
328 ))))
329 })?;
330 let version = i32::from_le_bytes(version_bytes);
331
332 let mut services_bytes = [0u8; 8];
334 cursor.read_exact(&mut services_bytes).map_err(|e| {
335 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
336 "Failed to read services: {e}"
337 ))))
338 })?;
339 let services = u64::from_le_bytes(services_bytes);
340
341 let mut timestamp_bytes = [0u8; 8];
343 cursor.read_exact(&mut timestamp_bytes).map_err(|e| {
344 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
345 "Failed to read timestamp: {e}"
346 ))))
347 })?;
348 let timestamp = i64::from_le_bytes(timestamp_bytes);
349
350 let mut addr_recv_bytes = [0u8; 26];
352 cursor.read_exact(&mut addr_recv_bytes).map_err(|e| {
353 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
354 "Failed to read addr_recv: {e}"
355 ))))
356 })?;
357 let addr_recv = deserialize_network_address(&addr_recv_bytes)?;
358
359 let mut addr_from_bytes = [0u8; 26];
361 cursor.read_exact(&mut addr_from_bytes).map_err(|e| {
362 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
363 "Failed to read addr_from: {e}"
364 ))))
365 })?;
366 let addr_from = deserialize_network_address(&addr_from_bytes)?;
367
368 let mut nonce_bytes = [0u8; 8];
370 cursor.read_exact(&mut nonce_bytes).map_err(|e| {
371 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
372 "Failed to read nonce: {e}"
373 ))))
374 })?;
375 let nonce = u64::from_le_bytes(nonce_bytes);
376
377 let user_agent_len = read_varint(&mut cursor)?;
379 if user_agent_len > 10000 {
380 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
381 Cow::Owned("User agent too long".to_string()),
382 )));
383 }
384 let mut user_agent_bytes = vec![0u8; user_agent_len as usize];
385 cursor.read_exact(&mut user_agent_bytes).map_err(|e| {
386 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
387 "Failed to read user_agent: {e}"
388 ))))
389 })?;
390 let user_agent = String::from_utf8_lossy(&user_agent_bytes).into_owned();
392
393 let mut start_height_bytes = [0u8; 4];
395 cursor.read_exact(&mut start_height_bytes).map_err(|e| {
396 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
397 "Failed to read start_height: {e}"
398 ))))
399 })?;
400 let start_height = i32::from_le_bytes(start_height_bytes);
401
402 let relay = {
404 let mut relay_byte = [0u8; 1];
405 match cursor.read_exact(&mut relay_byte) {
406 Ok(_) => relay_byte[0] != 0,
407 Err(_) => true, }
409 };
410
411 Ok(crate::network::VersionMessage {
412 version,
413 services,
414 timestamp,
415 addr_recv,
416 addr_from,
417 nonce,
418 user_agent,
419 start_height,
420 relay,
421 })
422}
423
424pub fn serialize_addr(a: &crate::network::AddrMessage) -> Result<Vec<u8>> {
427 use crate::varint::write_varint;
428
429 let mut buf = Vec::new();
430 write_varint(&mut buf, a.addresses.len() as u64)?;
431
432 for addr in &a.addresses {
433 buf.extend_from_slice(&addr.time.to_le_bytes());
434 buf.extend_from_slice(&addr.services.to_le_bytes());
436 buf.extend_from_slice(&addr.ip);
438 buf.extend_from_slice(&addr.port.to_be_bytes());
440 }
441 Ok(buf)
442}
443pub fn deserialize_addr(data: &[u8]) -> Result<crate::network::AddrMessage> {
444 use crate::varint::read_varint;
445 use std::io::Read;
446
447 let mut cursor = std::io::Cursor::new(data);
448 let count = read_varint(&mut cursor)?;
449 if count > 1000 {
450 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
451 Cow::Owned("Too many addresses in addr".to_string()),
452 )));
453 }
454
455 let mut addresses = Vec::with_capacity(count as usize);
456 for _ in 0..count {
457 let mut time_bytes = [0u8; 4];
458 cursor.read_exact(&mut time_bytes).map_err(|e| {
459 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
460 "Addr time: {e}"
461 ))))
462 })?;
463 let time = u32::from_le_bytes(time_bytes);
464
465 let mut services_bytes = [0u8; 8];
466 cursor.read_exact(&mut services_bytes).map_err(|e| {
467 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
468 "Addr services: {e}"
469 ))))
470 })?;
471 let services = u64::from_le_bytes(services_bytes);
472
473 let mut ip = [0u8; 16];
474 cursor.read_exact(&mut ip).map_err(|e| {
475 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
476 "Addr ip: {e}"
477 ))))
478 })?;
479
480 let mut port_bytes = [0u8; 2];
481 cursor.read_exact(&mut port_bytes).map_err(|e| {
482 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
483 "Addr port: {e}"
484 ))))
485 })?;
486 let port = u16::from_be_bytes(port_bytes);
487
488 addresses.push(crate::network::NetworkAddress {
489 services,
490 ip,
491 port,
492 time,
493 });
494 }
495 Ok(crate::network::AddrMessage { addresses })
496}
497
498pub fn serialize_addrv2(addrv2: &crate::network::AddrV2Message) -> Result<Vec<u8>> {
501 use crate::varint::write_varint;
502
503 let mut buf = Vec::new();
504
505 write_varint(&mut buf, addrv2.addresses.len() as u64)?;
507
508 for addr in &addrv2.addresses {
510 buf.extend_from_slice(&addr.time.to_le_bytes());
512
513 buf.extend_from_slice(&addr.services.to_le_bytes());
515
516 buf.push(addr.address_type as u8);
518
519 buf.extend_from_slice(&addr.address);
521
522 buf.extend_from_slice(&addr.port.to_be_bytes());
524 }
525
526 Ok(buf)
527}
528
529pub fn deserialize_addrv2(data: &[u8]) -> Result<crate::network::AddrV2Message> {
531 use crate::varint::read_varint;
532 use std::io::Cursor;
533
534 let mut cursor = Cursor::new(data);
535
536 let count = read_varint(&mut cursor)?;
538 if count > 1000 {
539 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
540 Cow::Owned("Too many addresses in addrv2".to_string()),
541 )));
542 }
543
544 let mut addresses = Vec::with_capacity(count as usize);
545
546 for _ in 0..count {
548 let mut time_bytes = [0u8; 4];
550 cursor.read_exact(&mut time_bytes).map_err(|e| {
551 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
552 "Failed to read time: {e}"
553 ))))
554 })?;
555 let time = u32::from_le_bytes(time_bytes);
556
557 let mut services_bytes = [0u8; 8];
559 cursor.read_exact(&mut services_bytes).map_err(|e| {
560 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
561 "Failed to read services: {e}"
562 ))))
563 })?;
564 let services = u64::from_le_bytes(services_bytes);
565
566 let mut addr_type_byte = [0u8; 1];
568 cursor.read_exact(&mut addr_type_byte).map_err(|e| {
569 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
570 "Failed to read address_type: {e}"
571 ))))
572 })?;
573 let address_type =
574 crate::network::AddressType::from_u8(addr_type_byte[0]).ok_or_else(|| {
575 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
576 "Invalid address type: {}",
577 addr_type_byte[0]
578 ))))
579 })?;
580
581 let addr_len = address_type.address_length();
583 let mut address = vec![0u8; addr_len];
584 cursor.read_exact(&mut address).map_err(|e| {
585 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
586 "Failed to read address: {e}"
587 ))))
588 })?;
589
590 let mut port_bytes = [0u8; 2];
592 cursor.read_exact(&mut port_bytes).map_err(|e| {
593 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
594 "Failed to read port: {e}"
595 ))))
596 })?;
597 let port = u16::from_be_bytes(port_bytes);
598
599 let addr_v2 =
601 crate::network::NetworkAddressV2::new(time, services, address_type, address, port)?;
602
603 addresses.push(addr_v2);
604 }
605
606 Ok(crate::network::AddrV2Message { addresses })
607}
608
609pub fn serialize_inv(i: &crate::network::InvMessage) -> Result<Vec<u8>> {
612 use crate::varint::write_varint;
613
614 let capacity = 9 + (36 * i.inventory.len()); let mut buf = Vec::with_capacity(capacity);
616
617 write_varint(&mut buf, i.inventory.len() as u64)?;
618
619 for item in &i.inventory {
620 buf.extend_from_slice(&item.inv_type.to_le_bytes());
621 buf.extend_from_slice(&item.hash);
622 }
623
624 Ok(buf)
625}
626
627pub fn deserialize_inv(data: &[u8]) -> Result<crate::network::InvMessage> {
629 use crate::varint::read_varint;
630 use std::io::Cursor;
631
632 if data.is_empty() {
633 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
634 Cow::Owned("Inv message is empty".to_string()),
635 )));
636 }
637
638 let mut cursor = Cursor::new(data);
639
640 let count = read_varint(&mut cursor)? as usize;
641
642 if count > 50000 {
644 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
645 Cow::Owned(format!("Too many inventory items: {count}")),
646 )));
647 }
648
649 let mut inventory = Vec::with_capacity(count);
650
651 for _ in 0..count {
652 let mut type_bytes = [0u8; 4];
653 std::io::Read::read_exact(&mut cursor, &mut type_bytes).map_err(|e| {
654 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
655 })?;
656 let inv_type = u32::from_le_bytes(type_bytes);
657
658 let mut hash = [0u8; 32];
659 std::io::Read::read_exact(&mut cursor, &mut hash).map_err(|e| {
660 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
661 })?;
662
663 inventory.push(crate::network::InventoryVector { inv_type, hash });
664 }
665
666 Ok(crate::network::InvMessage { inventory })
667}
668
669pub fn serialize_getdata(g: &crate::network::GetDataMessage) -> Result<Vec<u8>> {
672 use crate::varint::write_varint;
673
674 let capacity = 9 + (36 * g.inventory.len());
675 let mut buf = Vec::with_capacity(capacity);
676
677 write_varint(&mut buf, g.inventory.len() as u64)?;
678
679 for item in &g.inventory {
680 buf.extend_from_slice(&item.inv_type.to_le_bytes());
681 buf.extend_from_slice(&item.hash);
682 }
683
684 Ok(buf)
685}
686
687pub fn deserialize_getdata(data: &[u8]) -> Result<crate::network::GetDataMessage> {
689 use crate::varint::read_varint;
690 use std::io::Cursor;
691
692 if data.is_empty() {
693 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
694 Cow::Owned("GetData message is empty".to_string()),
695 )));
696 }
697
698 let mut cursor = Cursor::new(data);
699
700 let count = read_varint(&mut cursor)? as usize;
701
702 if count > 50000 {
703 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
704 Cow::Owned(format!("Too many inventory items: {count}")),
705 )));
706 }
707
708 let mut inventory = Vec::with_capacity(count);
709
710 for _ in 0..count {
711 let mut type_bytes = [0u8; 4];
712 std::io::Read::read_exact(&mut cursor, &mut type_bytes).map_err(|e| {
713 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
714 })?;
715 let inv_type = u32::from_le_bytes(type_bytes);
716
717 let mut hash = [0u8; 32];
718 std::io::Read::read_exact(&mut cursor, &mut hash).map_err(|e| {
719 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
720 })?;
721
722 inventory.push(crate::network::InventoryVector { inv_type, hash });
723 }
724
725 Ok(crate::network::GetDataMessage { inventory })
726}
727
728pub fn serialize_getheaders(gh: &crate::network::GetHeadersMessage) -> Result<Vec<u8>> {
731 use crate::varint::write_varint;
732 use std::io::Cursor;
733
734 let capacity = 4 + 9 + (32 * gh.block_locator_hashes.len()) + 32;
736 let mut buf = Vec::with_capacity(capacity);
737
738 buf.extend_from_slice(&(gh.version as i32).to_le_bytes());
740
741 let mut cursor = Cursor::new(&mut buf);
743 cursor.set_position(4);
744 write_varint(&mut buf, gh.block_locator_hashes.len() as u64)?;
745
746 for hash in &gh.block_locator_hashes {
748 buf.extend_from_slice(hash);
749 }
750
751 buf.extend_from_slice(&gh.hash_stop);
753
754 Ok(buf)
755}
756
757pub fn deserialize_getheaders(data: &[u8]) -> Result<crate::network::GetHeadersMessage> {
759 use crate::varint::read_varint;
760 use std::io::Cursor;
761
762 if data.len() < 4 + 1 + 32 {
763 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
764 Cow::Owned("GetHeaders message too short".to_string()),
765 )));
766 }
767
768 let mut cursor = Cursor::new(data);
769
770 let mut version_bytes = [0u8; 4];
772 std::io::Read::read_exact(&mut cursor, &mut version_bytes).map_err(|e| {
773 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
774 })?;
775 let version = i32::from_le_bytes(version_bytes) as u32;
776
777 let hash_count = read_varint(&mut cursor)? as usize;
779
780 if hash_count > 2000 {
782 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
783 Cow::Owned(format!("Too many locator hashes: {hash_count}")),
784 )));
785 }
786
787 let mut block_locator_hashes = Vec::with_capacity(hash_count);
789 for _ in 0..hash_count {
790 let mut hash = [0u8; 32];
791 std::io::Read::read_exact(&mut cursor, &mut hash).map_err(|e| {
792 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
793 })?;
794 block_locator_hashes.push(hash);
795 }
796
797 let mut hash_stop = [0u8; 32];
799 std::io::Read::read_exact(&mut cursor, &mut hash_stop).map_err(|e| {
800 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
801 })?;
802
803 Ok(crate::network::GetHeadersMessage {
804 version,
805 block_locator_hashes,
806 hash_stop,
807 })
808}
809
810pub fn serialize_headers(h: &crate::network::HeadersMessage) -> Result<Vec<u8>> {
813 use crate::varint::write_varint;
814
815 let capacity = 9 + (81 * h.headers.len());
817 let mut buf = Vec::with_capacity(capacity);
818
819 write_varint(&mut buf, h.headers.len() as u64)?;
821
822 for header in &h.headers {
824 buf.extend_from_slice(&(header.version as i32).to_le_bytes());
826 buf.extend_from_slice(&header.prev_block_hash);
828 buf.extend_from_slice(&header.merkle_root);
830 buf.extend_from_slice(&(header.timestamp as u32).to_le_bytes());
832 buf.extend_from_slice(&(header.bits as u32).to_le_bytes());
834 buf.extend_from_slice(&(header.nonce as u32).to_le_bytes());
836 buf.push(0);
838 }
839
840 Ok(buf)
841}
842
843pub fn deserialize_headers(data: &[u8]) -> Result<crate::network::HeadersMessage> {
845 use crate::varint::read_varint;
846 use std::io::Cursor;
847
848 if data.is_empty() {
849 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
850 Cow::Owned("Headers message is empty".to_string()),
851 )));
852 }
853
854 let mut cursor = Cursor::new(data);
855
856 let header_count = read_varint(&mut cursor)? as usize;
858
859 if header_count > 2000 {
861 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
862 Cow::Owned(format!("Too many headers: {header_count}")),
863 )));
864 }
865
866 let mut headers = Vec::with_capacity(header_count);
867
868 for _ in 0..header_count {
869 let mut version_bytes = [0u8; 4];
871 std::io::Read::read_exact(&mut cursor, &mut version_bytes).map_err(|e| {
872 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
873 })?;
874 let version = i32::from_le_bytes(version_bytes) as i64;
875
876 let mut prev_block_hash = [0u8; 32];
878 std::io::Read::read_exact(&mut cursor, &mut prev_block_hash).map_err(|e| {
879 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
880 })?;
881
882 let mut merkle_root = [0u8; 32];
884 std::io::Read::read_exact(&mut cursor, &mut merkle_root).map_err(|e| {
885 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
886 })?;
887
888 let mut timestamp_bytes = [0u8; 4];
890 std::io::Read::read_exact(&mut cursor, &mut timestamp_bytes).map_err(|e| {
891 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
892 })?;
893 let timestamp = u32::from_le_bytes(timestamp_bytes) as u64;
894
895 let mut bits_bytes = [0u8; 4];
897 std::io::Read::read_exact(&mut cursor, &mut bits_bytes).map_err(|e| {
898 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
899 })?;
900 let bits = u32::from_le_bytes(bits_bytes) as u64;
901
902 let mut nonce_bytes = [0u8; 4];
904 std::io::Read::read_exact(&mut cursor, &mut nonce_bytes).map_err(|e| {
905 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
906 })?;
907 let nonce = u32::from_le_bytes(nonce_bytes) as u64;
908
909 let tx_count = read_varint(&mut cursor)?;
910 if tx_count != 0 {
911 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
912 Cow::Owned(format!(
913 "Headers message transaction count must be 0, got {tx_count}"
914 )),
915 )));
916 }
917
918 headers.push(crate::BlockHeader {
919 version,
920 prev_block_hash,
921 merkle_root,
922 timestamp,
923 bits,
924 nonce,
925 });
926 }
927
928 Ok(crate::network::HeadersMessage { headers })
929}
930
931pub fn serialize_block_witnesses(
936 b: &crate::Block,
937 witnesses: &[Vec<blvm_consensus::segwit::Witness>],
938) -> Result<Vec<u8>> {
939 use crate::serialization::serialize_block_with_witnesses;
940
941 let include_witness = !witnesses.is_empty() && witnesses.iter().any(|tx_w| !tx_w.is_empty());
942
943 let padded;
945 let ws: &[Vec<blvm_consensus::segwit::Witness>] = if witnesses.len() < b.transactions.len() {
946 padded = {
947 let mut v = witnesses.to_vec();
948 v.resize(b.transactions.len(), Vec::new());
949 v
950 };
951 &padded
952 } else {
953 witnesses
954 };
955
956 Ok(serialize_block_with_witnesses(b, ws, include_witness))
957}
958
959pub fn deserialize_block_with_witnesses_pair(
964 data: &[u8],
965) -> Result<(crate::Block, Vec<Vec<blvm_consensus::segwit::Witness>>)> {
966 use crate::serialization::block::deserialize_block_with_witnesses;
967
968 deserialize_block_with_witnesses(data).map_err(|e| {
969 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
970 })
971}
972
973pub fn deserialize_block(data: &[u8]) -> Result<crate::Block> {
978 let (block, _witnesses) = deserialize_block_with_witnesses_pair(data)?;
979 Ok(block)
980}
981
982pub fn serialize_tx(tx: &crate::Transaction) -> Result<Vec<u8>> {
983 Ok(crate::serialization::serialize_transaction(tx))
984}
985
986pub fn serialize_tx_with_witness(
988 tx: &crate::Transaction,
989 witnesses: &[crate::segwit::Witness],
990) -> Result<Vec<u8>> {
991 let has_witness =
992 witnesses.len() == tx.inputs.len() && witnesses.iter().any(|stack| !stack.is_empty());
993 if has_witness {
994 crate::serialization::serialize_transaction_with_witness(tx, witnesses).map_err(|e| {
995 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
996 })
997 } else {
998 serialize_tx(tx)
999 }
1000}
1001
1002pub fn deserialize_tx(data: &[u8]) -> Result<crate::Transaction> {
1003 deserialize_tx_with_witness(data).map(|(tx, _)| tx)
1004}
1005
1006pub fn deserialize_tx_with_witness(
1008 data: &[u8],
1009) -> Result<(crate::Transaction, Vec<crate::segwit::Witness>)> {
1010 crate::serialization::deserialize_transaction_with_witness(data)
1011 .map(|(tx, witnesses, _)| (tx, witnesses))
1012 .map_err(|e| {
1013 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1014 })
1015}
1016
1017pub fn serialize_ping(p: &crate::network::PingMessage) -> Result<Vec<u8>> {
1019 Ok(p.nonce.to_le_bytes().to_vec())
1020}
1021
1022pub fn deserialize_ping(data: &[u8]) -> Result<crate::network::PingMessage> {
1024 if data.len() < 8 {
1025 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1026 Cow::Owned(format!("Ping message too short: {} bytes", data.len())),
1027 )));
1028 }
1029
1030 let nonce = u64::from_le_bytes([
1031 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
1032 ]);
1033
1034 Ok(crate::network::PingMessage { nonce })
1035}
1036
1037pub fn serialize_pong(p: &crate::network::PongMessage) -> Result<Vec<u8>> {
1039 Ok(p.nonce.to_le_bytes().to_vec())
1040}
1041
1042pub fn deserialize_pong(data: &[u8]) -> Result<crate::network::PongMessage> {
1044 if data.len() < 8 {
1045 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1046 Cow::Owned(format!("Pong message too short: {} bytes", data.len())),
1047 )));
1048 }
1049
1050 let nonce = u64::from_le_bytes([
1051 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
1052 ]);
1053
1054 Ok(crate::network::PongMessage { nonce })
1055}
1056
1057pub fn serialize_feefilter(f: &crate::network::FeeFilterMessage) -> Result<Vec<u8>> {
1059 Ok(f.feerate.to_le_bytes().to_vec())
1060}
1061pub fn deserialize_feefilter(data: &[u8]) -> Result<crate::network::FeeFilterMessage> {
1062 if data.len() < 8 {
1063 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1064 Cow::Owned("FeeFilter message too short".to_string()),
1065 )));
1066 }
1067 let feerate = u64::from_le_bytes([
1068 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
1069 ]);
1070 Ok(crate::network::FeeFilterMessage { feerate })
1071}
1072
1073pub fn serialize_getblocks(gb: &crate::network::GetBlocksMessage) -> Result<Vec<u8>> {
1075 use crate::varint::write_varint;
1076
1077 let mut buf = Vec::new();
1078 buf.extend_from_slice(&gb.version.to_le_bytes());
1079 write_varint(&mut buf, gb.block_locator_hashes.len() as u64)?;
1080 for hash in &gb.block_locator_hashes {
1081 buf.extend_from_slice(hash);
1082 }
1083 buf.extend_from_slice(&gb.hash_stop);
1084 Ok(buf)
1085}
1086pub fn deserialize_getblocks(data: &[u8]) -> Result<crate::network::GetBlocksMessage> {
1087 use crate::varint::read_varint;
1088 use std::io::Read;
1089
1090 if data.len() < 4 {
1091 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1092 Cow::Owned("GetBlocks message too short".to_string()),
1093 )));
1094 }
1095 let mut cursor = std::io::Cursor::new(data);
1096 let version = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
1097 cursor.set_position(4);
1098
1099 let count = read_varint(&mut cursor)? as usize;
1100 if count > 101 {
1101 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1102 Cow::Owned("GetBlocks locator too long".to_string()),
1103 )));
1104 }
1105 let mut block_locator_hashes = Vec::with_capacity(count);
1106 for _ in 0..count {
1107 let mut hash = [0u8; 32];
1108 cursor.read_exact(&mut hash).map_err(|e| {
1109 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
1110 "GetBlocks: {e}"
1111 ))))
1112 })?;
1113 block_locator_hashes.push(hash);
1114 }
1115 let mut hash_stop = [0u8; 32];
1116 cursor.read_exact(&mut hash_stop).map_err(|e| {
1117 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
1118 "GetBlocks hash_stop: {e}"
1119 ))))
1120 })?;
1121
1122 Ok(crate::network::GetBlocksMessage {
1123 version,
1124 block_locator_hashes,
1125 hash_stop,
1126 })
1127}
1128
1129pub fn serialize_notfound(nf: &crate::network::NotFoundMessage) -> Result<Vec<u8>> {
1132 use crate::varint::write_varint;
1133
1134 let capacity = 9 + (36 * nf.inventory.len());
1135 let mut buf = Vec::with_capacity(capacity);
1136
1137 write_varint(&mut buf, nf.inventory.len() as u64)?;
1138
1139 for item in &nf.inventory {
1140 buf.extend_from_slice(&item.inv_type.to_le_bytes());
1141 buf.extend_from_slice(&item.hash);
1142 }
1143
1144 Ok(buf)
1145}
1146
1147pub fn deserialize_notfound(data: &[u8]) -> Result<crate::network::NotFoundMessage> {
1149 use crate::varint::read_varint;
1150 use std::io::Cursor;
1151
1152 if data.is_empty() {
1153 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1154 Cow::Owned("NotFound message is empty".to_string()),
1155 )));
1156 }
1157
1158 let mut cursor = Cursor::new(data);
1159
1160 let count = read_varint(&mut cursor)? as usize;
1161
1162 if count > 50000 {
1163 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1164 Cow::Owned(format!("Too many inventory items: {count}")),
1165 )));
1166 }
1167
1168 let mut inventory = Vec::with_capacity(count);
1169
1170 for _ in 0..count {
1171 let mut type_bytes = [0u8; 4];
1172 std::io::Read::read_exact(&mut cursor, &mut type_bytes).map_err(|e| {
1173 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1174 })?;
1175 let inv_type = u32::from_le_bytes(type_bytes);
1176
1177 let mut hash = [0u8; 32];
1178 std::io::Read::read_exact(&mut cursor, &mut hash).map_err(|e| {
1179 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1180 })?;
1181
1182 inventory.push(crate::network::InventoryVector { inv_type, hash });
1183 }
1184
1185 Ok(crate::network::NotFoundMessage { inventory })
1186}
1187
1188pub fn serialize_reject(r: &crate::network::RejectMessage) -> Result<Vec<u8>> {
1190 use crate::varint::write_varint;
1191
1192 let mut buf = Vec::with_capacity(12 + 1 + 9 + r.reason.len() + 32);
1193 let msg_bytes = r.message.as_bytes();
1194 if msg_bytes.len() > 12 {
1195 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1196 Cow::Owned("Reject message field too long".to_string()),
1197 )));
1198 }
1199 buf.extend_from_slice(msg_bytes);
1200 buf.extend_from_slice(&[0u8; 12][msg_bytes.len()..]);
1201
1202 buf.push(r.code);
1203
1204 write_varint(&mut buf, r.reason.len() as u64)?;
1205 buf.extend_from_slice(r.reason.as_bytes());
1206
1207 if let Some(ref h) = r.extra_data {
1208 buf.extend_from_slice(h);
1209 }
1210 Ok(buf)
1211}
1212pub fn deserialize_reject(data: &[u8]) -> Result<crate::network::RejectMessage> {
1213 use crate::varint::read_varint;
1214
1215 if data.len() < 13 {
1216 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1217 Cow::Owned("Reject message too short".to_string()),
1218 )));
1219 }
1220 let message = String::from_utf8_lossy(&data[0..12])
1221 .trim_end_matches('\0')
1222 .to_string();
1223 let code = data[12];
1224 let mut cursor = std::io::Cursor::new(&data[13..]);
1225 let reason_len_u64 = read_varint(&mut cursor)?;
1226 let pos: usize = 13_usize.saturating_add(cursor.position() as usize);
1227 if reason_len_u64 > (data.len() as u64).saturating_sub(pos as u64) {
1228 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1229 Cow::Owned("Reject reason truncated".to_string()),
1230 )));
1231 }
1232 let reason_len: usize = reason_len_u64.try_into().map_err(|_| {
1233 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1234 "Reject reason length out of range".to_string(),
1235 )))
1236 })?;
1237 let end = pos.checked_add(reason_len).ok_or_else(|| {
1238 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1239 "Reject reason length out of range".to_string(),
1240 )))
1241 })?;
1242 if end > data.len() {
1243 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1244 Cow::Owned("Reject reason truncated".to_string()),
1245 )));
1246 }
1247 let reason = String::from_utf8_lossy(&data[pos..end]).to_string();
1248 let pos = end;
1249 let extra_data = if data.len() >= pos + 32 {
1250 Some({
1251 let mut h = [0u8; 32];
1252 h.copy_from_slice(&data[pos..pos + 32]);
1253 h
1254 })
1255 } else {
1256 None
1257 };
1258 Ok(crate::network::RejectMessage {
1259 message,
1260 code,
1261 reason,
1262 extra_data,
1263 })
1264}
1265
1266pub fn serialize_sendcmpct(sc: &crate::network::SendCmpctMessage) -> Result<Vec<u8>> {
1268 let mut buf = Vec::with_capacity(9);
1269 buf.push(sc.prefer_cmpct);
1270 buf.extend_from_slice(&sc.version.to_le_bytes());
1271 Ok(buf)
1272}
1273pub fn deserialize_sendcmpct(data: &[u8]) -> Result<crate::network::SendCmpctMessage> {
1274 if data.len() < 9 {
1275 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1276 Cow::Owned("SendCmpct message too short".to_string()),
1277 )));
1278 }
1279 Ok(crate::network::SendCmpctMessage {
1280 prefer_cmpct: data[0],
1281 version: u64::from_le_bytes([
1282 data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
1283 ]),
1284 })
1285}
1286
1287pub fn serialize_cmpctblock(cb: &crate::network::CmpctBlockMessage) -> Result<Vec<u8>> {
1289 use crate::varint::write_varint;
1290
1291 let mut buf = Vec::new();
1292 buf.extend_from_slice(&crate::serialization::serialize_block_header(&cb.header));
1293 buf.extend_from_slice(&cb.nonce.to_le_bytes());
1294 write_varint(&mut buf, cb.short_ids.len() as u64)?;
1295 for sid in &cb.short_ids {
1296 buf.extend_from_slice(sid);
1297 }
1298 write_varint(&mut buf, cb.prefilled_txs.len() as u64)?;
1299 let mut last_index = -1i64;
1300 for pt in &cb.prefilled_txs {
1301 let diff = (pt.index as i64) - last_index - 1;
1302 write_varint(&mut buf, diff as u64)?;
1303 last_index = pt.index as i64;
1304 let tx_bytes = match &pt.witness {
1305 Some(wit) if wit.iter().any(|w| !w.is_empty()) => {
1306 crate::serialization::serialize_transaction_with_witness(&pt.tx, wit)?
1307 }
1308 _ => crate::serialization::serialize_transaction(&pt.tx),
1309 };
1310 buf.extend_from_slice(&tx_bytes);
1311 }
1312 Ok(buf)
1313}
1314pub fn deserialize_cmpctblock(data: &[u8]) -> Result<crate::network::CmpctBlockMessage> {
1315 use crate::varint::read_varint;
1316 use std::io::Read;
1317
1318 const MAX_CMPCT_SHORTIDS: u64 = 50_000;
1320 const MAX_CMPCT_PREFILLED: u64 = 50_000;
1321
1322 if data.len() < 80 + 8 {
1323 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1324 Cow::Owned("CmpctBlock message too short".to_string()),
1325 )));
1326 }
1327 let header = crate::serialization::deserialize_block_header(&data[0..80]).map_err(|e| {
1328 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1329 })?;
1330 let nonce = u64::from_le_bytes([
1331 data[80], data[81], data[82], data[83], data[84], data[85], data[86], data[87],
1332 ]);
1333 let mut cursor = std::io::Cursor::new(&data[88..]);
1334 let shortids_len_u64 = read_varint(&mut cursor)?;
1335 if shortids_len_u64 > MAX_CMPCT_SHORTIDS {
1336 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1337 Cow::Owned("CmpctBlock too many shortids".to_string()),
1338 )));
1339 }
1340 let shortids_len: usize = shortids_len_u64.try_into().map_err(|_| {
1341 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1342 "CmpctBlock shortid count out of range".to_string(),
1343 )))
1344 })?;
1345 let rem_after_count = data.len().saturating_sub(88 + cursor.position() as usize);
1346 let need_shortids = shortids_len.checked_mul(6).ok_or_else(|| {
1347 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1348 "CmpctBlock shortid size overflow".to_string(),
1349 )))
1350 })?;
1351 if need_shortids > rem_after_count {
1352 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1353 Cow::Owned("CmpctBlock shortids truncated".to_string()),
1354 )));
1355 }
1356 let mut short_ids = Vec::with_capacity(shortids_len);
1357 for _ in 0..shortids_len {
1358 let mut sid = [0u8; 6];
1359 cursor.read_exact(&mut sid).map_err(|e| {
1360 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
1361 "CmpctBlock shortid: {e}"
1362 ))))
1363 })?;
1364 short_ids.push(sid);
1365 }
1366 let prefilled_len_u64 = read_varint(&mut cursor)?;
1367 if prefilled_len_u64 > MAX_CMPCT_PREFILLED {
1368 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1369 Cow::Owned("CmpctBlock too many prefilled txs".to_string()),
1370 )));
1371 }
1372 let prefilled_len: usize = prefilled_len_u64.try_into().map_err(|_| {
1373 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1374 "CmpctBlock prefilled count out of range".to_string(),
1375 )))
1376 })?;
1377 let mut prefilled_txs = Vec::with_capacity(prefilled_len);
1378 let mut last_index: i64 = -1;
1379 let mut pos;
1380 for _ in 0..prefilled_len {
1381 let diff = read_varint(&mut cursor)? as i64;
1382 if diff < 0 {
1383 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1384 Cow::Owned("CmpctBlock prefilled index diff invalid".to_string()),
1385 )));
1386 }
1387 let index = last_index
1388 .checked_add(diff)
1389 .and_then(|v| v.checked_add(1))
1390 .ok_or_else(|| {
1391 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1392 "CmpctBlock prefilled index overflow".to_string(),
1393 )))
1394 })?;
1395 if index > 0xffff {
1396 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1397 Cow::Owned("CmpctBlock prefilled index too large".to_string()),
1398 )));
1399 }
1400 last_index = index;
1401 pos = cursor.position() as usize;
1402 let slice = &data[88..];
1403 if pos >= slice.len() {
1404 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1405 Cow::Owned("CmpctBlock prefilled tx truncated".to_string()),
1406 )));
1407 }
1408 let (tx, witnesses, consumed) = crate::serialization::deserialize_transaction_with_witness(
1412 &slice[pos..],
1413 )
1414 .map_err(|e| {
1415 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1416 })?;
1417 cursor.set_position((pos + consumed) as u64);
1418 let witness = witnesses.iter().any(|w| !w.is_empty()).then_some(witnesses);
1419 prefilled_txs.push(crate::network::PrefilledTransaction {
1420 index: index as u16,
1421 tx,
1422 witness,
1423 });
1424 }
1425 Ok(crate::network::CmpctBlockMessage {
1426 header,
1427 nonce,
1428 short_ids,
1429 prefilled_txs,
1430 })
1431}
1432
1433pub fn serialize_getblocktxn(gbt: &crate::network::GetBlockTxnMessage) -> Result<Vec<u8>> {
1435 use crate::varint::write_varint;
1436
1437 let mut buf = Vec::new();
1438 buf.extend_from_slice(&gbt.block_hash);
1439 write_varint(&mut buf, gbt.indices.len() as u64)?;
1440 let mut last: i64 = -1;
1441 for &idx in &gbt.indices {
1442 let diff = (idx as i64) - last - 1;
1443 if diff < 0 {
1444 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1445 Cow::Owned("GetBlockTxn indices must be strictly increasing".to_string()),
1446 )));
1447 }
1448 write_varint(&mut buf, diff as u64)?;
1449 last = idx as i64;
1450 }
1451 Ok(buf)
1452}
1453pub fn deserialize_getblocktxn(data: &[u8]) -> Result<crate::network::GetBlockTxnMessage> {
1454 use crate::varint::read_varint;
1455
1456 if data.len() < 32 {
1457 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1458 Cow::Owned("GetBlockTxn message too short".to_string()),
1459 )));
1460 }
1461 let mut block_hash = [0u8; 32];
1462 block_hash.copy_from_slice(&data[0..32]);
1463 let mut cursor = std::io::Cursor::new(&data[32..]);
1464 let count = read_varint(&mut cursor)? as usize;
1465 if count > 50000 {
1466 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1467 Cow::Owned("GetBlockTxn too many indices".to_string()),
1468 )));
1469 }
1470 let mut indices = Vec::with_capacity(count);
1471 let mut last: i64 = -1;
1472 for _ in 0..count {
1473 let diff = read_varint(&mut cursor)? as i64;
1474 if diff < 0 {
1475 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1476 Cow::Owned("GetBlockTxn index diff invalid".to_string()),
1477 )));
1478 }
1479 last = last
1480 .checked_add(diff)
1481 .and_then(|v| v.checked_add(1))
1482 .ok_or_else(|| {
1483 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1484 "GetBlockTxn index overflow".to_string(),
1485 )))
1486 })?;
1487 if last > 0xffff {
1488 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1489 Cow::Owned("GetBlockTxn index too large".to_string()),
1490 )));
1491 }
1492 indices.push(last as u16);
1493 }
1494 Ok(crate::network::GetBlockTxnMessage {
1495 block_hash,
1496 indices,
1497 })
1498}
1499
1500pub fn serialize_blocktxn(bt: &crate::network::BlockTxnMessage) -> Result<Vec<u8>> {
1502 use crate::varint::write_varint;
1503
1504 let mut buf = Vec::new();
1505 buf.extend_from_slice(&bt.block_hash);
1506 write_varint(&mut buf, bt.transactions.len() as u64)?;
1507 match (&bt.witnesses, bt.transactions.len()) {
1508 (Some(witnesses), len) if witnesses.len() == len => {
1509 for (tx, wit) in bt.transactions.iter().zip(witnesses.iter()) {
1510 buf.extend_from_slice(&crate::serialization::serialize_transaction_with_witness(
1511 tx, wit,
1512 )?);
1513 }
1514 }
1515 _ => {
1516 for tx in &bt.transactions {
1517 buf.extend_from_slice(&crate::serialization::serialize_transaction(tx));
1518 }
1519 }
1520 }
1521 Ok(buf)
1522}
1523pub fn deserialize_blocktxn(data: &[u8]) -> Result<crate::network::BlockTxnMessage> {
1524 use crate::varint::read_varint;
1525
1526 if data.len() < 32 {
1527 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1528 Cow::Owned("BlockTxn message too short".to_string()),
1529 )));
1530 }
1531 let mut block_hash = [0u8; 32];
1532 block_hash.copy_from_slice(&data[0..32]);
1533 let mut cursor = std::io::Cursor::new(&data[32..]);
1534 let count = read_varint(&mut cursor)? as usize;
1535 if count > 50_000 {
1537 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1538 Cow::Owned("BlockTxn too many transactions".to_string()),
1539 )));
1540 }
1541 let mut transactions = Vec::with_capacity(count);
1542 let mut all_witnesses = Vec::with_capacity(count);
1543 let mut pos = 32 + (cursor.position() as usize);
1544 for _ in 0..count {
1545 if pos >= data.len() {
1546 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1547 Cow::Owned("BlockTxn truncated".to_string()),
1548 )));
1549 }
1550 let (tx, witnesses, consumed) = crate::serialization::deserialize_transaction_with_witness(
1553 &data[pos..],
1554 )
1555 .map_err(|e| {
1556 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1557 })?;
1558 pos += consumed;
1559 transactions.push(tx);
1560 all_witnesses.push(witnesses);
1561 }
1562 let witnesses = all_witnesses
1563 .iter()
1564 .any(|w| w.iter().any(|s| !s.is_empty()))
1565 .then_some(all_witnesses);
1566 Ok(crate::network::BlockTxnMessage {
1567 block_hash,
1568 transactions,
1569 witnesses,
1570 })
1571}
1572
1573#[cfg(feature = "utxo-commitments")]
1574fn serialize_getutxoset(gus: &crate::commons::GetUTXOSetMessage) -> Result<Vec<u8>> {
1575 let mut buf = Vec::with_capacity(40);
1576 buf.extend_from_slice(&gus.height.to_le_bytes());
1577 buf.extend_from_slice(&gus.block_hash);
1578 Ok(buf)
1579}
1580#[cfg(feature = "utxo-commitments")]
1581fn deserialize_getutxoset(data: &[u8]) -> Result<crate::commons::GetUTXOSetMessage> {
1582 if data.len() < 40 {
1583 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1584 Cow::Owned("GetUTXOSet message too short".to_string()),
1585 )));
1586 }
1587 let height = u64::from_le_bytes([
1588 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
1589 ]);
1590 let mut block_hash = [0u8; 32];
1591 block_hash.copy_from_slice(&data[8..40]);
1592 Ok(crate::commons::GetUTXOSetMessage { height, block_hash })
1593}
1594
1595#[cfg(feature = "utxo-commitments")]
1596fn serialize_utxoset(us: &crate::commons::UTXOSetMessage) -> Result<Vec<u8>> {
1597 bincode::serialize(us).map_err(|e| {
1598 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1599 })
1600}
1601#[cfg(feature = "utxo-commitments")]
1602fn deserialize_utxoset(data: &[u8]) -> Result<crate::commons::UTXOSetMessage> {
1603 bincode::deserialize(data).map_err(|e| {
1604 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1605 })
1606}
1607
1608#[cfg(feature = "utxo-commitments")]
1609fn serialize_getfilteredblock(gfb: &crate::commons::GetFilteredBlockMessage) -> Result<Vec<u8>> {
1610 bincode::serialize(gfb).map_err(|e| {
1611 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1612 })
1613}
1614#[cfg(feature = "utxo-commitments")]
1615fn deserialize_getfilteredblock(data: &[u8]) -> Result<crate::commons::GetFilteredBlockMessage> {
1616 bincode::deserialize(data).map_err(|e| {
1617 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1618 })
1619}
1620
1621#[cfg(feature = "utxo-commitments")]
1622fn serialize_filteredblock(fb: &crate::commons::FilteredBlockMessage) -> Result<Vec<u8>> {
1623 bincode::serialize(fb).map_err(|e| {
1624 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1625 })
1626}
1627#[cfg(feature = "utxo-commitments")]
1628fn deserialize_filteredblock(data: &[u8]) -> Result<crate::commons::FilteredBlockMessage> {
1629 bincode::deserialize(data).map_err(|e| {
1630 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1631 })
1632}
1633
1634fn serialize_getbanlist(gbl: &crate::commons::GetBanListMessage) -> Result<Vec<u8>> {
1635 bincode::serialize(gbl).map_err(|e| {
1636 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1637 })
1638}
1639fn deserialize_getbanlist(data: &[u8]) -> Result<crate::commons::GetBanListMessage> {
1640 bincode::deserialize(data).map_err(|e| {
1641 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1642 })
1643}
1644
1645fn serialize_banlist(bl: &crate::commons::BanListMessage) -> Result<Vec<u8>> {
1646 bincode::serialize(bl).map_err(|e| {
1647 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1648 })
1649}
1650fn deserialize_banlist(data: &[u8]) -> Result<crate::commons::BanListMessage> {
1651 bincode::deserialize(data).map_err(|e| {
1652 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1653 })
1654}
1655
1656#[cfg(test)]
1657mod blocktxn_count {
1658 use super::deserialize_blocktxn;
1659
1660 fn minimal_tx() -> Vec<u8> {
1661 let mut tx = Vec::new();
1662 tx.extend_from_slice(&1i32.to_le_bytes());
1663 tx.push(0);
1664 tx.push(0);
1665 tx.extend_from_slice(&0u32.to_le_bytes());
1666 tx
1667 }
1668
1669 #[test]
1670 fn twelve_thousand_transactions_decode() {
1671 let one = minimal_tx();
1672 let mut payload = vec![0u8; 32];
1673 payload.push(0xfd);
1674 payload.extend_from_slice(&12_239u16.to_le_bytes());
1675 for _ in 0..12_239 {
1676 payload.extend_from_slice(&one);
1677 }
1678 let msg = deserialize_blocktxn(&payload).expect("12239 transactions fit");
1679 assert_eq!(msg.transactions.len(), 12_239);
1680
1681 let mut over = vec![0u8; 32];
1682 over.push(0xfd);
1683 over.extend_from_slice(&50_001u16.to_le_bytes());
1684 let err = deserialize_blocktxn(&over).unwrap_err();
1685 let text = format!("{err:?}");
1686 assert!(text.contains("too many"), "{text}");
1687 }
1688}