1use crate::error::ProtocolError;
13use crate::network::NetworkMessage;
14use crate::ConsensusError;
15use crate::Result;
16use std::borrow::Cow;
17use std::io::Read;
18use std::sync::Arc;
19
20mod frame_header;
21pub use frame_header::{calculate_checksum, MAX_MESSAGE_PAYLOAD, MESSAGE_HEADER_SIZE};
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) => ("block", serialize_block(b)?),
38 NetworkMessage::Tx(tx) => ("tx", serialize_tx(tx)?),
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 let command = std::str::from_utf8(&command_bytes[..command_len]).map_err(|e| {
132 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
133 "Invalid command: {e}"
134 ))))
135 })?;
136
137 let length_bytes = [header[16], header[17], header[18], header[19]];
139 let payload_length = u32::from_le_bytes(length_bytes) as usize;
140
141 if payload_length > MAX_MESSAGE_PAYLOAD {
142 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
143 Cow::Owned(format!("Payload length too large: {payload_length} bytes")),
144 )));
145 }
146
147 let checksum = [header[20], header[21], header[22], header[23]];
149
150 let mut payload = vec![0u8; payload_length];
152 if payload_length > 0 {
153 reader.read_exact(&mut payload).map_err(|e| {
154 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
155 "IO error: {e}"
156 ))))
157 })?;
158 }
159
160 let calculated_checksum = calculate_checksum(&payload);
162 if calculated_checksum != checksum {
163 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
164 Cow::Owned("Checksum mismatch".to_string()),
165 )));
166 }
167
168 let message = match command {
170 "version" => NetworkMessage::Version(deserialize_version(&payload)?),
171 "verack" => NetworkMessage::VerAck,
172 "addr" => NetworkMessage::Addr(deserialize_addr(&payload)?),
173 "addrv2" => NetworkMessage::AddrV2(deserialize_addrv2(&payload)?),
174 "inv" => NetworkMessage::Inv(deserialize_inv(&payload)?),
175 "getdata" => NetworkMessage::GetData(deserialize_getdata(&payload)?),
176 "getheaders" => NetworkMessage::GetHeaders(deserialize_getheaders(&payload)?),
177 "headers" => NetworkMessage::Headers(deserialize_headers(&payload)?),
178 "block" => NetworkMessage::Block(Arc::new(deserialize_block(&payload)?)),
179 "tx" => NetworkMessage::Tx(Arc::new(deserialize_tx(&payload)?)),
180 "ping" => NetworkMessage::Ping(deserialize_ping(&payload)?),
181 "pong" => NetworkMessage::Pong(deserialize_pong(&payload)?),
182 "mempool" => NetworkMessage::MemPool,
183 "feefilter" => NetworkMessage::FeeFilter(deserialize_feefilter(&payload)?),
184 "getblocks" => NetworkMessage::GetBlocks(deserialize_getblocks(&payload)?),
185 "getaddr" => NetworkMessage::GetAddr,
186 "notfound" => NetworkMessage::NotFound(deserialize_notfound(&payload)?),
187 "reject" => NetworkMessage::Reject(deserialize_reject(&payload)?),
188 "sendheaders" => NetworkMessage::SendHeaders,
189 "sendcmpct" => NetworkMessage::SendCmpct(deserialize_sendcmpct(&payload)?),
190 "cmpctblock" => NetworkMessage::CmpctBlock(deserialize_cmpctblock(&payload)?),
191 "getblocktxn" => NetworkMessage::GetBlockTxn(deserialize_getblocktxn(&payload)?),
192 "blocktxn" => NetworkMessage::BlockTxn(deserialize_blocktxn(&payload)?),
193 #[cfg(feature = "utxo-commitments")]
194 "getutxoset" => NetworkMessage::GetUTXOSet(deserialize_getutxoset(&payload)?),
195 #[cfg(feature = "utxo-commitments")]
196 "utxoset" => NetworkMessage::UTXOSet(deserialize_utxoset(&payload)?),
197 #[cfg(feature = "utxo-commitments")]
198 "getfilteredblock" => {
199 NetworkMessage::GetFilteredBlock(deserialize_getfilteredblock(&payload)?)
200 }
201 #[cfg(feature = "utxo-commitments")]
202 "filteredblock" => NetworkMessage::FilteredBlock(deserialize_filteredblock(&payload)?),
203 "getbanlist" => NetworkMessage::GetBanList(deserialize_getbanlist(&payload)?),
204 "banlist" => NetworkMessage::BanList(deserialize_banlist(&payload)?),
205 _ => {
206 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
207 Cow::Owned(format!("Unknown command: {command}")),
208 )));
209 }
210 };
211
212 Ok((message, MESSAGE_HEADER_SIZE + payload_length))
213}
214
215fn serialize_network_address(addr: &crate::network::NetworkAddress) -> Vec<u8> {
220 let mut buf = Vec::with_capacity(26);
221 buf.extend_from_slice(&addr.services.to_le_bytes());
223 buf.extend_from_slice(&addr.ip);
225 buf.extend_from_slice(&addr.port.to_be_bytes());
227 buf
228}
229
230fn deserialize_network_address(data: &[u8]) -> Result<crate::network::NetworkAddress> {
232 if data.len() < 26 {
233 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
234 Cow::Owned("NetworkAddress too short".to_string()),
235 )));
236 }
237
238 let services = u64::from_le_bytes([
240 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
241 ]);
242
243 let mut ip = [0u8; 16];
245 ip.copy_from_slice(&data[8..24]);
246
247 let port = u16::from_be_bytes([data[24], data[25]]);
249
250 Ok(crate::network::NetworkAddress { services, ip, port })
251}
252
253pub fn serialize_version(v: &crate::network::VersionMessage) -> Result<Vec<u8>> {
265 use crate::varint::write_varint;
266
267 let mut buf = Vec::new();
268
269 buf.extend_from_slice(&(v.version as i32).to_le_bytes());
272
273 buf.extend_from_slice(&v.services.to_le_bytes());
275
276 buf.extend_from_slice(&v.timestamp.to_le_bytes());
278
279 buf.extend_from_slice(&serialize_network_address(&v.addr_recv));
281
282 buf.extend_from_slice(&serialize_network_address(&v.addr_from));
284
285 buf.extend_from_slice(&v.nonce.to_le_bytes());
287
288 let user_agent_bytes = v.user_agent.as_bytes();
290 write_varint(&mut buf, user_agent_bytes.len() as u64)?;
291 buf.extend_from_slice(user_agent_bytes);
292
293 buf.extend_from_slice(&v.start_height.to_le_bytes());
295
296 buf.push(if v.relay { 1 } else { 0 });
298
299 Ok(buf)
300}
301
302pub fn deserialize_version(data: &[u8]) -> Result<crate::network::VersionMessage> {
304 use crate::varint::read_varint;
305 use std::io::Cursor;
306
307 let mut cursor = Cursor::new(data);
308
309 let mut version_bytes = [0u8; 4];
311 cursor.read_exact(&mut version_bytes).map_err(|e| {
312 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
313 "Failed to read version: {e}"
314 ))))
315 })?;
316 let version = i32::from_le_bytes(version_bytes) as u32;
317
318 let mut services_bytes = [0u8; 8];
320 cursor.read_exact(&mut services_bytes).map_err(|e| {
321 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
322 "Failed to read services: {e}"
323 ))))
324 })?;
325 let services = u64::from_le_bytes(services_bytes);
326
327 let mut timestamp_bytes = [0u8; 8];
329 cursor.read_exact(&mut timestamp_bytes).map_err(|e| {
330 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
331 "Failed to read timestamp: {e}"
332 ))))
333 })?;
334 let timestamp = i64::from_le_bytes(timestamp_bytes);
335
336 let mut addr_recv_bytes = [0u8; 26];
338 cursor.read_exact(&mut addr_recv_bytes).map_err(|e| {
339 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
340 "Failed to read addr_recv: {e}"
341 ))))
342 })?;
343 let addr_recv = deserialize_network_address(&addr_recv_bytes)?;
344
345 let mut addr_from_bytes = [0u8; 26];
347 cursor.read_exact(&mut addr_from_bytes).map_err(|e| {
348 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
349 "Failed to read addr_from: {e}"
350 ))))
351 })?;
352 let addr_from = deserialize_network_address(&addr_from_bytes)?;
353
354 let mut nonce_bytes = [0u8; 8];
356 cursor.read_exact(&mut nonce_bytes).map_err(|e| {
357 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
358 "Failed to read nonce: {e}"
359 ))))
360 })?;
361 let nonce = u64::from_le_bytes(nonce_bytes);
362
363 let user_agent_len = read_varint(&mut cursor)?;
365 if user_agent_len > 10000 {
366 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
367 Cow::Owned("User agent too long".to_string()),
368 )));
369 }
370 let mut user_agent_bytes = vec![0u8; user_agent_len as usize];
371 cursor.read_exact(&mut user_agent_bytes).map_err(|e| {
372 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
373 "Failed to read user_agent: {e}"
374 ))))
375 })?;
376 let user_agent = String::from_utf8(user_agent_bytes).map_err(|e| {
377 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
378 "Invalid user_agent UTF-8: {e}"
379 ))))
380 })?;
381
382 let mut start_height_bytes = [0u8; 4];
384 cursor.read_exact(&mut start_height_bytes).map_err(|e| {
385 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
386 "Failed to read start_height: {e}"
387 ))))
388 })?;
389 let start_height = i32::from_le_bytes(start_height_bytes);
390
391 let relay = {
393 let mut relay_byte = [0u8; 1];
394 match cursor.read_exact(&mut relay_byte) {
395 Ok(_) => relay_byte[0] != 0,
396 Err(_) => true, }
398 };
399
400 Ok(crate::network::VersionMessage {
401 version,
402 services,
403 timestamp,
404 addr_recv,
405 addr_from,
406 nonce,
407 user_agent,
408 start_height,
409 relay,
410 })
411}
412
413pub fn serialize_addr(a: &crate::network::AddrMessage) -> Result<Vec<u8>> {
416 use crate::varint::write_varint;
417
418 let mut buf = Vec::new();
419 write_varint(&mut buf, a.addresses.len() as u64)?;
420
421 for addr in &a.addresses {
422 buf.extend_from_slice(&0u32.to_le_bytes());
424 buf.extend_from_slice(&addr.services.to_le_bytes());
426 buf.extend_from_slice(&addr.ip);
428 buf.extend_from_slice(&addr.port.to_be_bytes());
430 }
431 Ok(buf)
432}
433pub fn deserialize_addr(data: &[u8]) -> Result<crate::network::AddrMessage> {
434 use crate::varint::read_varint;
435 use std::io::Read;
436
437 let mut cursor = std::io::Cursor::new(data);
438 let count = read_varint(&mut cursor)?;
439 if count > 1000 {
440 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
441 Cow::Owned("Too many addresses in addr".to_string()),
442 )));
443 }
444
445 let mut addresses = Vec::with_capacity(count as usize);
446 for _ in 0..count {
447 let mut time_bytes = [0u8; 4];
448 cursor.read_exact(&mut time_bytes).map_err(|e| {
449 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
450 "Addr time: {e}"
451 ))))
452 })?;
453 let _time = u32::from_le_bytes(time_bytes);
454
455 let mut services_bytes = [0u8; 8];
456 cursor.read_exact(&mut services_bytes).map_err(|e| {
457 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
458 "Addr services: {e}"
459 ))))
460 })?;
461 let services = u64::from_le_bytes(services_bytes);
462
463 let mut ip = [0u8; 16];
464 cursor.read_exact(&mut ip).map_err(|e| {
465 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
466 "Addr ip: {e}"
467 ))))
468 })?;
469
470 let mut port_bytes = [0u8; 2];
471 cursor.read_exact(&mut port_bytes).map_err(|e| {
472 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
473 "Addr port: {e}"
474 ))))
475 })?;
476 let port = u16::from_be_bytes(port_bytes);
477
478 addresses.push(crate::network::NetworkAddress { services, ip, port });
479 }
480 Ok(crate::network::AddrMessage { addresses })
481}
482
483pub fn serialize_addrv2(addrv2: &crate::network::AddrV2Message) -> Result<Vec<u8>> {
486 use crate::varint::write_varint;
487
488 let mut buf = Vec::new();
489
490 write_varint(&mut buf, addrv2.addresses.len() as u64)?;
492
493 for addr in &addrv2.addresses {
495 buf.extend_from_slice(&addr.time.to_le_bytes());
497
498 buf.extend_from_slice(&addr.services.to_le_bytes());
500
501 buf.push(addr.address_type as u8);
503
504 buf.extend_from_slice(&addr.address);
506
507 buf.extend_from_slice(&addr.port.to_be_bytes());
509 }
510
511 Ok(buf)
512}
513
514pub fn deserialize_addrv2(data: &[u8]) -> Result<crate::network::AddrV2Message> {
516 use crate::varint::read_varint;
517 use std::io::Cursor;
518
519 let mut cursor = Cursor::new(data);
520
521 let count = read_varint(&mut cursor)?;
523 if count > 1000 {
524 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
525 Cow::Owned("Too many addresses in addrv2".to_string()),
526 )));
527 }
528
529 let mut addresses = Vec::with_capacity(count as usize);
530
531 for _ in 0..count {
533 let mut time_bytes = [0u8; 4];
535 cursor.read_exact(&mut time_bytes).map_err(|e| {
536 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
537 "Failed to read time: {e}"
538 ))))
539 })?;
540 let time = u32::from_le_bytes(time_bytes);
541
542 let mut services_bytes = [0u8; 8];
544 cursor.read_exact(&mut services_bytes).map_err(|e| {
545 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
546 "Failed to read services: {e}"
547 ))))
548 })?;
549 let services = u64::from_le_bytes(services_bytes);
550
551 let mut addr_type_byte = [0u8; 1];
553 cursor.read_exact(&mut addr_type_byte).map_err(|e| {
554 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
555 "Failed to read address_type: {e}"
556 ))))
557 })?;
558 let address_type =
559 crate::network::AddressType::from_u8(addr_type_byte[0]).ok_or_else(|| {
560 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
561 "Invalid address type: {}",
562 addr_type_byte[0]
563 ))))
564 })?;
565
566 let addr_len = address_type.address_length();
568 let mut address = vec![0u8; addr_len];
569 cursor.read_exact(&mut address).map_err(|e| {
570 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
571 "Failed to read address: {e}"
572 ))))
573 })?;
574
575 let mut port_bytes = [0u8; 2];
577 cursor.read_exact(&mut port_bytes).map_err(|e| {
578 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
579 "Failed to read port: {e}"
580 ))))
581 })?;
582 let port = u16::from_be_bytes(port_bytes);
583
584 let addr_v2 =
586 crate::network::NetworkAddressV2::new(time, services, address_type, address, port)?;
587
588 addresses.push(addr_v2);
589 }
590
591 Ok(crate::network::AddrV2Message { addresses })
592}
593
594pub fn serialize_inv(i: &crate::network::InvMessage) -> Result<Vec<u8>> {
597 use crate::varint::write_varint;
598
599 let capacity = 9 + (36 * i.inventory.len()); let mut buf = Vec::with_capacity(capacity);
601
602 write_varint(&mut buf, i.inventory.len() as u64)?;
603
604 for item in &i.inventory {
605 buf.extend_from_slice(&item.inv_type.to_le_bytes());
606 buf.extend_from_slice(&item.hash);
607 }
608
609 Ok(buf)
610}
611
612pub fn deserialize_inv(data: &[u8]) -> Result<crate::network::InvMessage> {
614 use crate::varint::read_varint;
615 use std::io::Cursor;
616
617 if data.is_empty() {
618 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
619 Cow::Owned("Inv message is empty".to_string()),
620 )));
621 }
622
623 let mut cursor = Cursor::new(data);
624
625 let count = read_varint(&mut cursor)? as usize;
626
627 if count > 50000 {
629 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
630 Cow::Owned(format!("Too many inventory items: {count}")),
631 )));
632 }
633
634 let mut inventory = Vec::with_capacity(count);
635
636 for _ in 0..count {
637 let mut type_bytes = [0u8; 4];
638 std::io::Read::read_exact(&mut cursor, &mut type_bytes).map_err(|e| {
639 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
640 })?;
641 let inv_type = u32::from_le_bytes(type_bytes);
642
643 let mut hash = [0u8; 32];
644 std::io::Read::read_exact(&mut cursor, &mut hash).map_err(|e| {
645 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
646 })?;
647
648 inventory.push(crate::network::InventoryVector { inv_type, hash });
649 }
650
651 Ok(crate::network::InvMessage { inventory })
652}
653
654pub fn serialize_getdata(g: &crate::network::GetDataMessage) -> Result<Vec<u8>> {
657 use crate::varint::write_varint;
658
659 let capacity = 9 + (36 * g.inventory.len());
660 let mut buf = Vec::with_capacity(capacity);
661
662 write_varint(&mut buf, g.inventory.len() as u64)?;
663
664 for item in &g.inventory {
665 buf.extend_from_slice(&item.inv_type.to_le_bytes());
666 buf.extend_from_slice(&item.hash);
667 }
668
669 Ok(buf)
670}
671
672pub fn deserialize_getdata(data: &[u8]) -> Result<crate::network::GetDataMessage> {
674 use crate::varint::read_varint;
675 use std::io::Cursor;
676
677 if data.is_empty() {
678 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
679 Cow::Owned("GetData message is empty".to_string()),
680 )));
681 }
682
683 let mut cursor = Cursor::new(data);
684
685 let count = read_varint(&mut cursor)? as usize;
686
687 if count > 50000 {
688 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
689 Cow::Owned(format!("Too many inventory items: {count}")),
690 )));
691 }
692
693 let mut inventory = Vec::with_capacity(count);
694
695 for _ in 0..count {
696 let mut type_bytes = [0u8; 4];
697 std::io::Read::read_exact(&mut cursor, &mut type_bytes).map_err(|e| {
698 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
699 })?;
700 let inv_type = u32::from_le_bytes(type_bytes);
701
702 let mut hash = [0u8; 32];
703 std::io::Read::read_exact(&mut cursor, &mut hash).map_err(|e| {
704 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
705 })?;
706
707 inventory.push(crate::network::InventoryVector { inv_type, hash });
708 }
709
710 Ok(crate::network::GetDataMessage { inventory })
711}
712
713pub fn serialize_getheaders(gh: &crate::network::GetHeadersMessage) -> Result<Vec<u8>> {
716 use crate::varint::write_varint;
717 use std::io::Cursor;
718
719 let capacity = 4 + 9 + (32 * gh.block_locator_hashes.len()) + 32;
721 let mut buf = Vec::with_capacity(capacity);
722
723 buf.extend_from_slice(&(gh.version as i32).to_le_bytes());
725
726 let mut cursor = Cursor::new(&mut buf);
728 cursor.set_position(4);
729 write_varint(&mut buf, gh.block_locator_hashes.len() as u64)?;
730
731 for hash in &gh.block_locator_hashes {
733 buf.extend_from_slice(hash);
734 }
735
736 buf.extend_from_slice(&gh.hash_stop);
738
739 Ok(buf)
740}
741
742pub fn deserialize_getheaders(data: &[u8]) -> Result<crate::network::GetHeadersMessage> {
744 use crate::varint::read_varint;
745 use std::io::Cursor;
746
747 if data.len() < 4 + 1 + 32 {
748 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
749 Cow::Owned("GetHeaders message too short".to_string()),
750 )));
751 }
752
753 let mut cursor = Cursor::new(data);
754
755 let mut version_bytes = [0u8; 4];
757 std::io::Read::read_exact(&mut cursor, &mut version_bytes).map_err(|e| {
758 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
759 })?;
760 let version = i32::from_le_bytes(version_bytes) as u32;
761
762 let hash_count = read_varint(&mut cursor)? as usize;
764
765 if hash_count > 2000 {
767 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
768 Cow::Owned(format!("Too many locator hashes: {hash_count}")),
769 )));
770 }
771
772 let mut block_locator_hashes = Vec::with_capacity(hash_count);
774 for _ in 0..hash_count {
775 let mut hash = [0u8; 32];
776 std::io::Read::read_exact(&mut cursor, &mut hash).map_err(|e| {
777 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
778 })?;
779 block_locator_hashes.push(hash);
780 }
781
782 let mut hash_stop = [0u8; 32];
784 std::io::Read::read_exact(&mut cursor, &mut hash_stop).map_err(|e| {
785 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
786 })?;
787
788 Ok(crate::network::GetHeadersMessage {
789 version,
790 block_locator_hashes,
791 hash_stop,
792 })
793}
794
795pub fn serialize_headers(h: &crate::network::HeadersMessage) -> Result<Vec<u8>> {
798 use crate::varint::write_varint;
799
800 let capacity = 9 + (81 * h.headers.len());
802 let mut buf = Vec::with_capacity(capacity);
803
804 write_varint(&mut buf, h.headers.len() as u64)?;
806
807 for header in &h.headers {
809 buf.extend_from_slice(&(header.version as i32).to_le_bytes());
811 buf.extend_from_slice(&header.prev_block_hash);
813 buf.extend_from_slice(&header.merkle_root);
815 buf.extend_from_slice(&(header.timestamp as u32).to_le_bytes());
817 buf.extend_from_slice(&(header.bits as u32).to_le_bytes());
819 buf.extend_from_slice(&(header.nonce as u32).to_le_bytes());
821 buf.push(0);
823 }
824
825 Ok(buf)
826}
827
828pub fn deserialize_headers(data: &[u8]) -> Result<crate::network::HeadersMessage> {
830 use crate::varint::read_varint;
831 use std::io::Cursor;
832
833 if data.is_empty() {
834 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
835 Cow::Owned("Headers message is empty".to_string()),
836 )));
837 }
838
839 let mut cursor = Cursor::new(data);
840
841 let header_count = read_varint(&mut cursor)? as usize;
843
844 if header_count > 2000 {
846 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
847 Cow::Owned(format!("Too many headers: {header_count}")),
848 )));
849 }
850
851 let mut headers = Vec::with_capacity(header_count);
852
853 for _ in 0..header_count {
854 let mut version_bytes = [0u8; 4];
856 std::io::Read::read_exact(&mut cursor, &mut version_bytes).map_err(|e| {
857 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
858 })?;
859 let version = i32::from_le_bytes(version_bytes) as i64;
860
861 let mut prev_block_hash = [0u8; 32];
863 std::io::Read::read_exact(&mut cursor, &mut prev_block_hash).map_err(|e| {
864 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
865 })?;
866
867 let mut merkle_root = [0u8; 32];
869 std::io::Read::read_exact(&mut cursor, &mut merkle_root).map_err(|e| {
870 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
871 })?;
872
873 let mut timestamp_bytes = [0u8; 4];
875 std::io::Read::read_exact(&mut cursor, &mut timestamp_bytes).map_err(|e| {
876 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
877 })?;
878 let timestamp = u32::from_le_bytes(timestamp_bytes) as u64;
879
880 let mut bits_bytes = [0u8; 4];
882 std::io::Read::read_exact(&mut cursor, &mut bits_bytes).map_err(|e| {
883 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
884 })?;
885 let bits = u32::from_le_bytes(bits_bytes) as u64;
886
887 let mut nonce_bytes = [0u8; 4];
889 std::io::Read::read_exact(&mut cursor, &mut nonce_bytes).map_err(|e| {
890 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
891 })?;
892 let nonce = u32::from_le_bytes(nonce_bytes) as u64;
893
894 let _tx_count = read_varint(&mut cursor)?;
896
897 headers.push(crate::BlockHeader {
898 version,
899 prev_block_hash,
900 merkle_root,
901 timestamp,
902 bits,
903 nonce,
904 });
905 }
906
907 Ok(crate::network::HeadersMessage { headers })
908}
909
910pub fn serialize_block(b: &crate::Block) -> Result<Vec<u8>> {
911 use crate::serialization::serialize_block_with_witnesses;
912
913 let empty_witnesses: Vec<Vec<blvm_consensus::segwit::Witness>> =
917 (0..b.transactions.len()).map(|_| Vec::new()).collect();
918 Ok(serialize_block_with_witnesses(b, &empty_witnesses, false))
919}
920pub fn deserialize_block(data: &[u8]) -> Result<crate::Block> {
921 use crate::serialization::block::deserialize_block_with_witnesses;
922
923 let (block, _witnesses) = deserialize_block_with_witnesses(data)?;
924 Ok(block)
925}
926
927pub fn serialize_tx(tx: &crate::Transaction) -> Result<Vec<u8>> {
928 Ok(crate::serialization::serialize_transaction(tx))
929}
930pub fn deserialize_tx(data: &[u8]) -> Result<crate::Transaction> {
931 crate::serialization::deserialize_transaction(data).map_err(|e| {
932 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
933 })
934}
935
936pub fn serialize_ping(p: &crate::network::PingMessage) -> Result<Vec<u8>> {
938 Ok(p.nonce.to_le_bytes().to_vec())
939}
940
941pub fn deserialize_ping(data: &[u8]) -> Result<crate::network::PingMessage> {
943 if data.len() < 8 {
944 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
945 Cow::Owned(format!("Ping message too short: {} bytes", data.len())),
946 )));
947 }
948
949 let nonce = u64::from_le_bytes([
950 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
951 ]);
952
953 Ok(crate::network::PingMessage { nonce })
954}
955
956pub fn serialize_pong(p: &crate::network::PongMessage) -> Result<Vec<u8>> {
958 Ok(p.nonce.to_le_bytes().to_vec())
959}
960
961pub fn deserialize_pong(data: &[u8]) -> Result<crate::network::PongMessage> {
963 if data.len() < 8 {
964 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
965 Cow::Owned(format!("Pong message too short: {} bytes", data.len())),
966 )));
967 }
968
969 let nonce = u64::from_le_bytes([
970 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
971 ]);
972
973 Ok(crate::network::PongMessage { nonce })
974}
975
976pub fn serialize_feefilter(f: &crate::network::FeeFilterMessage) -> Result<Vec<u8>> {
978 Ok(f.feerate.to_le_bytes().to_vec())
979}
980pub fn deserialize_feefilter(data: &[u8]) -> Result<crate::network::FeeFilterMessage> {
981 if data.len() < 8 {
982 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
983 Cow::Owned("FeeFilter message too short".to_string()),
984 )));
985 }
986 let feerate = u64::from_le_bytes([
987 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
988 ]);
989 Ok(crate::network::FeeFilterMessage { feerate })
990}
991
992pub fn serialize_getblocks(gb: &crate::network::GetBlocksMessage) -> Result<Vec<u8>> {
994 use crate::varint::write_varint;
995
996 let mut buf = Vec::new();
997 buf.extend_from_slice(&gb.version.to_le_bytes());
998 write_varint(&mut buf, gb.block_locator_hashes.len() as u64)?;
999 for hash in &gb.block_locator_hashes {
1000 buf.extend_from_slice(hash);
1001 }
1002 buf.extend_from_slice(&gb.hash_stop);
1003 Ok(buf)
1004}
1005pub fn deserialize_getblocks(data: &[u8]) -> Result<crate::network::GetBlocksMessage> {
1006 use crate::varint::read_varint;
1007 use std::io::Read;
1008
1009 if data.len() < 4 {
1010 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1011 Cow::Owned("GetBlocks message too short".to_string()),
1012 )));
1013 }
1014 let mut cursor = std::io::Cursor::new(data);
1015 let version = u32::from_le_bytes([data[0], data[1], data[2], data[3]]);
1016 cursor.set_position(4);
1017
1018 let count = read_varint(&mut cursor)? as usize;
1019 if count > 101 {
1020 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1021 Cow::Owned("GetBlocks locator too long".to_string()),
1022 )));
1023 }
1024 let mut block_locator_hashes = Vec::with_capacity(count);
1025 for _ in 0..count {
1026 let mut hash = [0u8; 32];
1027 cursor.read_exact(&mut hash).map_err(|e| {
1028 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
1029 "GetBlocks: {e}"
1030 ))))
1031 })?;
1032 block_locator_hashes.push(hash);
1033 }
1034 let mut hash_stop = [0u8; 32];
1035 cursor.read_exact(&mut hash_stop).map_err(|e| {
1036 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
1037 "GetBlocks hash_stop: {e}"
1038 ))))
1039 })?;
1040
1041 Ok(crate::network::GetBlocksMessage {
1042 version,
1043 block_locator_hashes,
1044 hash_stop,
1045 })
1046}
1047
1048pub fn serialize_notfound(nf: &crate::network::NotFoundMessage) -> Result<Vec<u8>> {
1051 use crate::varint::write_varint;
1052
1053 let capacity = 9 + (36 * nf.inventory.len());
1054 let mut buf = Vec::with_capacity(capacity);
1055
1056 write_varint(&mut buf, nf.inventory.len() as u64)?;
1057
1058 for item in &nf.inventory {
1059 buf.extend_from_slice(&item.inv_type.to_le_bytes());
1060 buf.extend_from_slice(&item.hash);
1061 }
1062
1063 Ok(buf)
1064}
1065
1066pub fn deserialize_notfound(data: &[u8]) -> Result<crate::network::NotFoundMessage> {
1068 use crate::varint::read_varint;
1069 use std::io::Cursor;
1070
1071 if data.is_empty() {
1072 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1073 Cow::Owned("NotFound message is empty".to_string()),
1074 )));
1075 }
1076
1077 let mut cursor = Cursor::new(data);
1078
1079 let count = read_varint(&mut cursor)? as usize;
1080
1081 if count > 50000 {
1082 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1083 Cow::Owned(format!("Too many inventory items: {count}")),
1084 )));
1085 }
1086
1087 let mut inventory = Vec::with_capacity(count);
1088
1089 for _ in 0..count {
1090 let mut type_bytes = [0u8; 4];
1091 std::io::Read::read_exact(&mut cursor, &mut type_bytes).map_err(|e| {
1092 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1093 })?;
1094 let inv_type = u32::from_le_bytes(type_bytes);
1095
1096 let mut hash = [0u8; 32];
1097 std::io::Read::read_exact(&mut cursor, &mut hash).map_err(|e| {
1098 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1099 })?;
1100
1101 inventory.push(crate::network::InventoryVector { inv_type, hash });
1102 }
1103
1104 Ok(crate::network::NotFoundMessage { inventory })
1105}
1106
1107pub fn serialize_reject(r: &crate::network::RejectMessage) -> Result<Vec<u8>> {
1109 use crate::varint::write_varint;
1110
1111 let mut buf = Vec::with_capacity(12 + 1 + 9 + r.reason.len() + 32);
1112 let msg_bytes = r.message.as_bytes();
1113 if msg_bytes.len() > 12 {
1114 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1115 Cow::Owned("Reject message field too long".to_string()),
1116 )));
1117 }
1118 buf.extend_from_slice(msg_bytes);
1119 buf.extend_from_slice(&[0u8; 12][msg_bytes.len()..]);
1120
1121 buf.push(r.code);
1122
1123 write_varint(&mut buf, r.reason.len() as u64)?;
1124 buf.extend_from_slice(r.reason.as_bytes());
1125
1126 if let Some(ref h) = r.extra_data {
1127 buf.extend_from_slice(h);
1128 }
1129 Ok(buf)
1130}
1131pub fn deserialize_reject(data: &[u8]) -> Result<crate::network::RejectMessage> {
1132 use crate::varint::read_varint;
1133
1134 if data.len() < 13 {
1135 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1136 Cow::Owned("Reject message too short".to_string()),
1137 )));
1138 }
1139 let message = String::from_utf8_lossy(&data[0..12])
1140 .trim_end_matches('\0')
1141 .to_string();
1142 let code = data[12];
1143 let mut cursor = std::io::Cursor::new(&data[13..]);
1144 let reason_len_u64 = read_varint(&mut cursor)?;
1145 let pos: usize = 13_usize.saturating_add(cursor.position() as usize);
1146 if reason_len_u64 > (data.len() as u64).saturating_sub(pos as u64) {
1147 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1148 Cow::Owned("Reject reason truncated".to_string()),
1149 )));
1150 }
1151 let reason_len: usize = reason_len_u64.try_into().map_err(|_| {
1152 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1153 "Reject reason length out of range".to_string(),
1154 )))
1155 })?;
1156 let end = pos.checked_add(reason_len).ok_or_else(|| {
1157 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1158 "Reject reason length out of range".to_string(),
1159 )))
1160 })?;
1161 if end > data.len() {
1162 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1163 Cow::Owned("Reject reason truncated".to_string()),
1164 )));
1165 }
1166 let reason = String::from_utf8_lossy(&data[pos..end]).to_string();
1167 let pos = end;
1168 let extra_data = if data.len() >= pos + 32 {
1169 Some({
1170 let mut h = [0u8; 32];
1171 h.copy_from_slice(&data[pos..pos + 32]);
1172 h
1173 })
1174 } else {
1175 None
1176 };
1177 Ok(crate::network::RejectMessage {
1178 message,
1179 code,
1180 reason,
1181 extra_data,
1182 })
1183}
1184
1185pub fn serialize_sendcmpct(sc: &crate::network::SendCmpctMessage) -> Result<Vec<u8>> {
1187 let mut buf = Vec::with_capacity(9);
1188 buf.push(sc.prefer_cmpct);
1189 buf.extend_from_slice(&sc.version.to_le_bytes());
1190 Ok(buf)
1191}
1192pub fn deserialize_sendcmpct(data: &[u8]) -> Result<crate::network::SendCmpctMessage> {
1193 if data.len() < 9 {
1194 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1195 Cow::Owned("SendCmpct message too short".to_string()),
1196 )));
1197 }
1198 Ok(crate::network::SendCmpctMessage {
1199 prefer_cmpct: data[0],
1200 version: u64::from_le_bytes([
1201 data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
1202 ]),
1203 })
1204}
1205
1206pub fn serialize_cmpctblock(cb: &crate::network::CmpctBlockMessage) -> Result<Vec<u8>> {
1208 use crate::varint::write_varint;
1209
1210 let mut buf = Vec::new();
1211 buf.extend_from_slice(&crate::serialization::serialize_block_header(&cb.header));
1212 buf.extend_from_slice(&cb.nonce.to_le_bytes());
1213 write_varint(&mut buf, cb.short_ids.len() as u64)?;
1214 for sid in &cb.short_ids {
1215 buf.extend_from_slice(sid);
1216 }
1217 write_varint(&mut buf, cb.prefilled_txs.len() as u64)?;
1218 let mut last_index = -1i64;
1219 for pt in &cb.prefilled_txs {
1220 let diff = (pt.index as i64) - last_index - 1;
1221 write_varint(&mut buf, diff as u64)?;
1222 last_index = pt.index as i64;
1223 let tx_bytes = match &pt.witness {
1224 Some(wit) if wit.iter().any(|w| !w.is_empty()) => {
1225 crate::serialization::serialize_transaction_with_witness(&pt.tx, wit)
1226 }
1227 _ => crate::serialization::serialize_transaction(&pt.tx),
1228 };
1229 buf.extend_from_slice(&tx_bytes);
1230 }
1231 Ok(buf)
1232}
1233pub fn deserialize_cmpctblock(data: &[u8]) -> Result<crate::network::CmpctBlockMessage> {
1234 use crate::varint::read_varint;
1235 use std::io::Read;
1236
1237 const MAX_CMPCT_SHORTIDS: u64 = 50_000;
1239 const MAX_CMPCT_PREFILLED: u64 = 50_000;
1240
1241 if data.len() < 80 + 8 {
1242 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1243 Cow::Owned("CmpctBlock message too short".to_string()),
1244 )));
1245 }
1246 let header = crate::serialization::deserialize_block_header(&data[0..80]).map_err(|e| {
1247 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1248 })?;
1249 let nonce = u64::from_le_bytes([
1250 data[80], data[81], data[82], data[83], data[84], data[85], data[86], data[87],
1251 ]);
1252 let mut cursor = std::io::Cursor::new(&data[88..]);
1253 let shortids_len_u64 = read_varint(&mut cursor)?;
1254 if shortids_len_u64 > MAX_CMPCT_SHORTIDS {
1255 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1256 Cow::Owned("CmpctBlock too many shortids".to_string()),
1257 )));
1258 }
1259 let shortids_len: usize = shortids_len_u64.try_into().map_err(|_| {
1260 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1261 "CmpctBlock shortid count out of range".to_string(),
1262 )))
1263 })?;
1264 let rem_after_count = data.len().saturating_sub(88 + cursor.position() as usize);
1265 let need_shortids = shortids_len.checked_mul(6).ok_or_else(|| {
1266 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1267 "CmpctBlock shortid size overflow".to_string(),
1268 )))
1269 })?;
1270 if need_shortids > rem_after_count {
1271 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1272 Cow::Owned("CmpctBlock shortids truncated".to_string()),
1273 )));
1274 }
1275 let mut short_ids = Vec::with_capacity(shortids_len);
1276 for _ in 0..shortids_len {
1277 let mut sid = [0u8; 6];
1278 cursor.read_exact(&mut sid).map_err(|e| {
1279 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
1280 "CmpctBlock shortid: {e}"
1281 ))))
1282 })?;
1283 short_ids.push(sid);
1284 }
1285 let prefilled_len_u64 = read_varint(&mut cursor)?;
1286 if prefilled_len_u64 > MAX_CMPCT_PREFILLED {
1287 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1288 Cow::Owned("CmpctBlock too many prefilled txs".to_string()),
1289 )));
1290 }
1291 let prefilled_len: usize = prefilled_len_u64.try_into().map_err(|_| {
1292 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1293 "CmpctBlock prefilled count out of range".to_string(),
1294 )))
1295 })?;
1296 let mut prefilled_txs = Vec::with_capacity(prefilled_len);
1297 let mut last_index: i64 = -1;
1298 let mut pos;
1299 for _ in 0..prefilled_len {
1300 let diff = read_varint(&mut cursor)? as i64;
1301 if diff < 0 {
1302 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1303 Cow::Owned("CmpctBlock prefilled index diff invalid".to_string()),
1304 )));
1305 }
1306 let index = last_index
1307 .checked_add(diff)
1308 .and_then(|v| v.checked_add(1))
1309 .ok_or_else(|| {
1310 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1311 "CmpctBlock prefilled index overflow".to_string(),
1312 )))
1313 })?;
1314 if index > 0xffff {
1315 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1316 Cow::Owned("CmpctBlock prefilled index too large".to_string()),
1317 )));
1318 }
1319 last_index = index;
1320 pos = cursor.position() as usize;
1321 let slice = &data[88..];
1322 if pos >= slice.len() {
1323 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1324 Cow::Owned("CmpctBlock prefilled tx truncated".to_string()),
1325 )));
1326 }
1327 let (tx, witnesses, consumed) = crate::serialization::deserialize_transaction_with_witness(
1331 &slice[pos..],
1332 )
1333 .map_err(|e| {
1334 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1335 })?;
1336 cursor.set_position((pos + consumed) as u64);
1337 let witness = witnesses.iter().any(|w| !w.is_empty()).then_some(witnesses);
1338 prefilled_txs.push(crate::network::PrefilledTransaction {
1339 index: index as u16,
1340 tx,
1341 witness,
1342 });
1343 }
1344 Ok(crate::network::CmpctBlockMessage {
1345 header,
1346 nonce,
1347 short_ids,
1348 prefilled_txs,
1349 })
1350}
1351
1352pub fn serialize_getblocktxn(gbt: &crate::network::GetBlockTxnMessage) -> Result<Vec<u8>> {
1354 use crate::varint::write_varint;
1355
1356 let mut buf = Vec::new();
1357 buf.extend_from_slice(&gbt.block_hash);
1358 write_varint(&mut buf, gbt.indices.len() as u64)?;
1359 let mut last: i64 = -1;
1360 for &idx in &gbt.indices {
1361 let diff = (idx as i64) - last - 1;
1362 if diff < 0 {
1363 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1364 Cow::Owned("GetBlockTxn indices must be strictly increasing".to_string()),
1365 )));
1366 }
1367 write_varint(&mut buf, diff as u64)?;
1368 last = idx as i64;
1369 }
1370 Ok(buf)
1371}
1372pub fn deserialize_getblocktxn(data: &[u8]) -> Result<crate::network::GetBlockTxnMessage> {
1373 use crate::varint::read_varint;
1374
1375 if data.len() < 32 {
1376 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1377 Cow::Owned("GetBlockTxn message too short".to_string()),
1378 )));
1379 }
1380 let mut block_hash = [0u8; 32];
1381 block_hash.copy_from_slice(&data[0..32]);
1382 let mut cursor = std::io::Cursor::new(&data[32..]);
1383 let count = read_varint(&mut cursor)? as usize;
1384 if count > 50000 {
1385 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1386 Cow::Owned("GetBlockTxn too many indices".to_string()),
1387 )));
1388 }
1389 let mut indices = Vec::with_capacity(count);
1390 let mut last: i64 = -1;
1391 for _ in 0..count {
1392 let diff = read_varint(&mut cursor)? as i64;
1393 if diff < 0 {
1394 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1395 Cow::Owned("GetBlockTxn index diff invalid".to_string()),
1396 )));
1397 }
1398 last = last
1399 .checked_add(diff)
1400 .and_then(|v| v.checked_add(1))
1401 .ok_or_else(|| {
1402 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1403 "GetBlockTxn index overflow".to_string(),
1404 )))
1405 })?;
1406 if last > 0xffff {
1407 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1408 Cow::Owned("GetBlockTxn index too large".to_string()),
1409 )));
1410 }
1411 indices.push(last as u16);
1412 }
1413 Ok(crate::network::GetBlockTxnMessage {
1414 block_hash,
1415 indices,
1416 })
1417}
1418
1419pub fn serialize_blocktxn(bt: &crate::network::BlockTxnMessage) -> Result<Vec<u8>> {
1421 use crate::varint::write_varint;
1422
1423 let mut buf = Vec::new();
1424 buf.extend_from_slice(&bt.block_hash);
1425 write_varint(&mut buf, bt.transactions.len() as u64)?;
1426 match (&bt.witnesses, bt.transactions.len()) {
1427 (Some(witnesses), len) if witnesses.len() == len => {
1428 for (tx, wit) in bt.transactions.iter().zip(witnesses.iter()) {
1429 buf.extend_from_slice(&crate::serialization::serialize_transaction_with_witness(
1430 tx, wit,
1431 ));
1432 }
1433 }
1434 _ => {
1435 for tx in &bt.transactions {
1436 buf.extend_from_slice(&crate::serialization::serialize_transaction(tx));
1437 }
1438 }
1439 }
1440 Ok(buf)
1441}
1442pub fn deserialize_blocktxn(data: &[u8]) -> Result<crate::network::BlockTxnMessage> {
1443 use crate::varint::read_varint;
1444
1445 if data.len() < 32 {
1446 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1447 Cow::Owned("BlockTxn message too short".to_string()),
1448 )));
1449 }
1450 let mut block_hash = [0u8; 32];
1451 block_hash.copy_from_slice(&data[0..32]);
1452 let mut cursor = std::io::Cursor::new(&data[32..]);
1453 let count = read_varint(&mut cursor)? as usize;
1454 if count > 2000 {
1455 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1456 Cow::Owned("BlockTxn too many transactions".to_string()),
1457 )));
1458 }
1459 let mut transactions = Vec::with_capacity(count);
1460 let mut all_witnesses = Vec::with_capacity(count);
1461 let mut pos = 32 + (cursor.position() as usize);
1462 for _ in 0..count {
1463 if pos >= data.len() {
1464 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1465 Cow::Owned("BlockTxn truncated".to_string()),
1466 )));
1467 }
1468 let (tx, witnesses, consumed) = crate::serialization::deserialize_transaction_with_witness(
1471 &data[pos..],
1472 )
1473 .map_err(|e| {
1474 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1475 })?;
1476 pos += consumed;
1477 transactions.push(tx);
1478 all_witnesses.push(witnesses);
1479 }
1480 let witnesses = all_witnesses
1481 .iter()
1482 .any(|w| w.iter().any(|s| !s.is_empty()))
1483 .then_some(all_witnesses);
1484 Ok(crate::network::BlockTxnMessage {
1485 block_hash,
1486 transactions,
1487 witnesses,
1488 })
1489}
1490
1491#[cfg(feature = "utxo-commitments")]
1492fn serialize_getutxoset(gus: &crate::commons::GetUTXOSetMessage) -> Result<Vec<u8>> {
1493 let mut buf = Vec::with_capacity(40);
1494 buf.extend_from_slice(&gus.height.to_le_bytes());
1495 buf.extend_from_slice(&gus.block_hash);
1496 Ok(buf)
1497}
1498#[cfg(feature = "utxo-commitments")]
1499fn deserialize_getutxoset(data: &[u8]) -> Result<crate::commons::GetUTXOSetMessage> {
1500 if data.len() < 40 {
1501 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1502 Cow::Owned("GetUTXOSet message too short".to_string()),
1503 )));
1504 }
1505 let height = u64::from_le_bytes([
1506 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
1507 ]);
1508 let mut block_hash = [0u8; 32];
1509 block_hash.copy_from_slice(&data[8..40]);
1510 Ok(crate::commons::GetUTXOSetMessage { height, block_hash })
1511}
1512
1513#[cfg(feature = "utxo-commitments")]
1514fn serialize_utxoset(us: &crate::commons::UTXOSetMessage) -> Result<Vec<u8>> {
1515 bincode::serialize(us).map_err(|e| {
1516 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1517 })
1518}
1519#[cfg(feature = "utxo-commitments")]
1520fn deserialize_utxoset(data: &[u8]) -> Result<crate::commons::UTXOSetMessage> {
1521 bincode::deserialize(data).map_err(|e| {
1522 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1523 })
1524}
1525
1526#[cfg(feature = "utxo-commitments")]
1527fn serialize_getfilteredblock(gfb: &crate::commons::GetFilteredBlockMessage) -> Result<Vec<u8>> {
1528 bincode::serialize(gfb).map_err(|e| {
1529 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1530 })
1531}
1532#[cfg(feature = "utxo-commitments")]
1533fn deserialize_getfilteredblock(data: &[u8]) -> Result<crate::commons::GetFilteredBlockMessage> {
1534 bincode::deserialize(data).map_err(|e| {
1535 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1536 })
1537}
1538
1539#[cfg(feature = "utxo-commitments")]
1540fn serialize_filteredblock(fb: &crate::commons::FilteredBlockMessage) -> Result<Vec<u8>> {
1541 bincode::serialize(fb).map_err(|e| {
1542 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1543 })
1544}
1545#[cfg(feature = "utxo-commitments")]
1546fn deserialize_filteredblock(data: &[u8]) -> Result<crate::commons::FilteredBlockMessage> {
1547 bincode::deserialize(data).map_err(|e| {
1548 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1549 })
1550}
1551
1552fn serialize_getbanlist(gbl: &crate::commons::GetBanListMessage) -> Result<Vec<u8>> {
1553 bincode::serialize(gbl).map_err(|e| {
1554 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1555 })
1556}
1557fn deserialize_getbanlist(data: &[u8]) -> Result<crate::commons::GetBanListMessage> {
1558 bincode::deserialize(data).map_err(|e| {
1559 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1560 })
1561}
1562
1563fn serialize_banlist(bl: &crate::commons::BanListMessage) -> Result<Vec<u8>> {
1564 bincode::serialize(bl).map_err(|e| {
1565 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1566 })
1567}
1568fn deserialize_banlist(data: &[u8]) -> Result<crate::commons::BanListMessage> {
1569 bincode::deserialize(data).map_err(|e| {
1570 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1571 })
1572}