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
1146 .saturating_add(cursor.position() as usize);
1147 if reason_len_u64 > (data.len() as u64).saturating_sub(pos as u64) {
1148 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1149 Cow::Owned("Reject reason truncated".to_string()),
1150 )));
1151 }
1152 let reason_len: usize = reason_len_u64
1153 .try_into()
1154 .map_err(|_| {
1155 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1156 "Reject reason length out of range".to_string(),
1157 )))
1158 })?;
1159 let end = pos
1160 .checked_add(reason_len)
1161 .ok_or_else(|| {
1162 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1163 "Reject reason length out of range".to_string(),
1164 )))
1165 })?;
1166 if end > data.len() {
1167 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1168 Cow::Owned("Reject reason truncated".to_string()),
1169 )));
1170 }
1171 let reason = String::from_utf8_lossy(&data[pos..end]).to_string();
1172 let pos = end;
1173 let extra_data = if data.len() >= pos + 32 {
1174 Some({
1175 let mut h = [0u8; 32];
1176 h.copy_from_slice(&data[pos..pos + 32]);
1177 h
1178 })
1179 } else {
1180 None
1181 };
1182 Ok(crate::network::RejectMessage {
1183 message,
1184 code,
1185 reason,
1186 extra_data,
1187 })
1188}
1189
1190pub fn serialize_sendcmpct(sc: &crate::network::SendCmpctMessage) -> Result<Vec<u8>> {
1192 let mut buf = Vec::with_capacity(9);
1193 buf.push(sc.prefer_cmpct);
1194 buf.extend_from_slice(&sc.version.to_le_bytes());
1195 Ok(buf)
1196}
1197pub fn deserialize_sendcmpct(data: &[u8]) -> Result<crate::network::SendCmpctMessage> {
1198 if data.len() < 9 {
1199 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1200 Cow::Owned("SendCmpct message too short".to_string()),
1201 )));
1202 }
1203 Ok(crate::network::SendCmpctMessage {
1204 prefer_cmpct: data[0],
1205 version: u64::from_le_bytes([
1206 data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8],
1207 ]),
1208 })
1209}
1210
1211pub fn serialize_cmpctblock(cb: &crate::network::CmpctBlockMessage) -> Result<Vec<u8>> {
1213 use crate::varint::write_varint;
1214
1215 let mut buf = Vec::new();
1216 buf.extend_from_slice(&crate::serialization::serialize_block_header(&cb.header));
1217 buf.extend_from_slice(&cb.nonce.to_le_bytes());
1218 write_varint(&mut buf, cb.short_ids.len() as u64)?;
1219 for sid in &cb.short_ids {
1220 buf.extend_from_slice(sid);
1221 }
1222 write_varint(&mut buf, cb.prefilled_txs.len() as u64)?;
1223 let mut last_index = -1i64;
1224 for pt in &cb.prefilled_txs {
1225 let diff = (pt.index as i64) - last_index - 1;
1226 write_varint(&mut buf, diff as u64)?;
1227 last_index = pt.index as i64;
1228 let tx_bytes = match &pt.witness {
1229 Some(wit) if wit.iter().any(|w| !w.is_empty()) => {
1230 crate::serialization::serialize_transaction_with_witness(&pt.tx, wit)
1231 }
1232 _ => crate::serialization::serialize_transaction(&pt.tx),
1233 };
1234 buf.extend_from_slice(&tx_bytes);
1235 }
1236 Ok(buf)
1237}
1238pub fn deserialize_cmpctblock(data: &[u8]) -> Result<crate::network::CmpctBlockMessage> {
1239 use crate::varint::read_varint;
1240 use std::io::Read;
1241
1242 const MAX_CMPCT_SHORTIDS: u64 = 50_000;
1244 const MAX_CMPCT_PREFILLED: u64 = 50_000;
1245
1246 if data.len() < 80 + 8 {
1247 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1248 Cow::Owned("CmpctBlock message too short".to_string()),
1249 )));
1250 }
1251 let header = crate::serialization::deserialize_block_header(&data[0..80]).map_err(|e| {
1252 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1253 })?;
1254 let nonce = u64::from_le_bytes([
1255 data[80], data[81], data[82], data[83], data[84], data[85], data[86], data[87],
1256 ]);
1257 let mut cursor = std::io::Cursor::new(&data[88..]);
1258 let shortids_len_u64 = read_varint(&mut cursor)?;
1259 if shortids_len_u64 > MAX_CMPCT_SHORTIDS {
1260 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1261 Cow::Owned("CmpctBlock too many shortids".to_string()),
1262 )));
1263 }
1264 let shortids_len: usize = shortids_len_u64
1265 .try_into()
1266 .map_err(|_| {
1267 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1268 "CmpctBlock shortid count out of range".to_string(),
1269 )))
1270 })?;
1271 let rem_after_count = data.len().saturating_sub(88 + cursor.position() as usize);
1272 let need_shortids = shortids_len
1273 .checked_mul(6)
1274 .ok_or_else(|| {
1275 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1276 "CmpctBlock shortid size overflow".to_string(),
1277 )))
1278 })?;
1279 if need_shortids > rem_after_count {
1280 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1281 Cow::Owned("CmpctBlock shortids truncated".to_string()),
1282 )));
1283 }
1284 let mut short_ids = Vec::with_capacity(shortids_len);
1285 for _ in 0..shortids_len {
1286 let mut sid = [0u8; 6];
1287 cursor.read_exact(&mut sid).map_err(|e| {
1288 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(format!(
1289 "CmpctBlock shortid: {e}"
1290 ))))
1291 })?;
1292 short_ids.push(sid);
1293 }
1294 let prefilled_len_u64 = read_varint(&mut cursor)?;
1295 if prefilled_len_u64 > MAX_CMPCT_PREFILLED {
1296 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1297 Cow::Owned("CmpctBlock too many prefilled txs".to_string()),
1298 )));
1299 }
1300 let prefilled_len: usize = prefilled_len_u64
1301 .try_into()
1302 .map_err(|_| {
1303 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1304 "CmpctBlock prefilled count out of range".to_string(),
1305 )))
1306 })?;
1307 let mut prefilled_txs = Vec::with_capacity(prefilled_len);
1308 let mut last_index: i64 = -1;
1309 let mut pos;
1310 for _ in 0..prefilled_len {
1311 let diff = read_varint(&mut cursor)? as i64;
1312 if diff < 0 {
1313 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1314 Cow::Owned("CmpctBlock prefilled index diff invalid".to_string()),
1315 )));
1316 }
1317 let index = last_index
1318 .checked_add(diff)
1319 .and_then(|v| v.checked_add(1))
1320 .ok_or_else(|| {
1321 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1322 "CmpctBlock prefilled index overflow".to_string(),
1323 )))
1324 })?;
1325 if index > 0xffff {
1326 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1327 Cow::Owned("CmpctBlock prefilled index too large".to_string()),
1328 )));
1329 }
1330 last_index = index;
1331 pos = cursor.position() as usize;
1332 let slice = &data[88..];
1333 if pos >= slice.len() {
1334 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1335 Cow::Owned("CmpctBlock prefilled tx truncated".to_string()),
1336 )));
1337 }
1338 let (tx, witnesses, consumed) = crate::serialization::deserialize_transaction_with_witness(
1342 &slice[pos..],
1343 )
1344 .map_err(|e| {
1345 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1346 })?;
1347 cursor.set_position((pos + consumed) as u64);
1348 let witness = witnesses.iter().any(|w| !w.is_empty()).then_some(witnesses);
1349 prefilled_txs.push(crate::network::PrefilledTransaction {
1350 index: index as u16,
1351 tx,
1352 witness,
1353 });
1354 }
1355 Ok(crate::network::CmpctBlockMessage {
1356 header,
1357 nonce,
1358 short_ids,
1359 prefilled_txs,
1360 })
1361}
1362
1363pub fn serialize_getblocktxn(gbt: &crate::network::GetBlockTxnMessage) -> Result<Vec<u8>> {
1365 use crate::varint::write_varint;
1366
1367 let mut buf = Vec::new();
1368 buf.extend_from_slice(&gbt.block_hash);
1369 write_varint(&mut buf, gbt.indices.len() as u64)?;
1370 let mut last: i64 = -1;
1371 for &idx in &gbt.indices {
1372 let diff = (idx as i64) - last - 1;
1373 if diff < 0 {
1374 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1375 Cow::Owned("GetBlockTxn indices must be strictly increasing".to_string()),
1376 )));
1377 }
1378 write_varint(&mut buf, diff as u64)?;
1379 last = idx as i64;
1380 }
1381 Ok(buf)
1382}
1383pub fn deserialize_getblocktxn(data: &[u8]) -> Result<crate::network::GetBlockTxnMessage> {
1384 use crate::varint::read_varint;
1385
1386 if data.len() < 32 {
1387 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1388 Cow::Owned("GetBlockTxn message too short".to_string()),
1389 )));
1390 }
1391 let mut block_hash = [0u8; 32];
1392 block_hash.copy_from_slice(&data[0..32]);
1393 let mut cursor = std::io::Cursor::new(&data[32..]);
1394 let count = read_varint(&mut cursor)? as usize;
1395 if count > 50000 {
1396 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1397 Cow::Owned("GetBlockTxn too many indices".to_string()),
1398 )));
1399 }
1400 let mut indices = Vec::with_capacity(count);
1401 let mut last: i64 = -1;
1402 for _ in 0..count {
1403 let diff = read_varint(&mut cursor)? as i64;
1404 if diff < 0 {
1405 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1406 Cow::Owned("GetBlockTxn index diff invalid".to_string()),
1407 )));
1408 }
1409 last = last
1410 .checked_add(diff)
1411 .and_then(|v| v.checked_add(1))
1412 .ok_or_else(|| {
1413 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(
1414 "GetBlockTxn index overflow".to_string(),
1415 )))
1416 })?;
1417 if last > 0xffff {
1418 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1419 Cow::Owned("GetBlockTxn index too large".to_string()),
1420 )));
1421 }
1422 indices.push(last as u16);
1423 }
1424 Ok(crate::network::GetBlockTxnMessage {
1425 block_hash,
1426 indices,
1427 })
1428}
1429
1430pub fn serialize_blocktxn(bt: &crate::network::BlockTxnMessage) -> Result<Vec<u8>> {
1432 use crate::varint::write_varint;
1433
1434 let mut buf = Vec::new();
1435 buf.extend_from_slice(&bt.block_hash);
1436 write_varint(&mut buf, bt.transactions.len() as u64)?;
1437 match (&bt.witnesses, bt.transactions.len()) {
1438 (Some(witnesses), len) if witnesses.len() == len => {
1439 for (tx, wit) in bt.transactions.iter().zip(witnesses.iter()) {
1440 buf.extend_from_slice(&crate::serialization::serialize_transaction_with_witness(
1441 tx, wit,
1442 ));
1443 }
1444 }
1445 _ => {
1446 for tx in &bt.transactions {
1447 buf.extend_from_slice(&crate::serialization::serialize_transaction(tx));
1448 }
1449 }
1450 }
1451 Ok(buf)
1452}
1453pub fn deserialize_blocktxn(data: &[u8]) -> Result<crate::network::BlockTxnMessage> {
1454 use crate::varint::read_varint;
1455
1456 if data.len() < 32 {
1457 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1458 Cow::Owned("BlockTxn 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 > 2000 {
1466 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1467 Cow::Owned("BlockTxn too many transactions".to_string()),
1468 )));
1469 }
1470 let mut transactions = Vec::with_capacity(count);
1471 let mut all_witnesses = Vec::with_capacity(count);
1472 let mut pos = 32 + (cursor.position() as usize);
1473 for _ in 0..count {
1474 if pos >= data.len() {
1475 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1476 Cow::Owned("BlockTxn truncated".to_string()),
1477 )));
1478 }
1479 let (tx, witnesses, consumed) = crate::serialization::deserialize_transaction_with_witness(
1482 &data[pos..],
1483 )
1484 .map_err(|e| {
1485 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1486 })?;
1487 pos += consumed;
1488 transactions.push(tx);
1489 all_witnesses.push(witnesses);
1490 }
1491 let witnesses = all_witnesses
1492 .iter()
1493 .any(|w| w.iter().any(|s| !s.is_empty()))
1494 .then_some(all_witnesses);
1495 Ok(crate::network::BlockTxnMessage {
1496 block_hash,
1497 transactions,
1498 witnesses,
1499 })
1500}
1501
1502#[cfg(feature = "utxo-commitments")]
1503fn serialize_getutxoset(gus: &crate::commons::GetUTXOSetMessage) -> Result<Vec<u8>> {
1504 let mut buf = Vec::with_capacity(40);
1505 buf.extend_from_slice(&gus.height.to_le_bytes());
1506 buf.extend_from_slice(&gus.block_hash);
1507 Ok(buf)
1508}
1509#[cfg(feature = "utxo-commitments")]
1510fn deserialize_getutxoset(data: &[u8]) -> Result<crate::commons::GetUTXOSetMessage> {
1511 if data.len() < 40 {
1512 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
1513 Cow::Owned("GetUTXOSet message too short".to_string()),
1514 )));
1515 }
1516 let height = u64::from_le_bytes([
1517 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
1518 ]);
1519 let mut block_hash = [0u8; 32];
1520 block_hash.copy_from_slice(&data[8..40]);
1521 Ok(crate::commons::GetUTXOSetMessage { height, block_hash })
1522}
1523
1524#[cfg(feature = "utxo-commitments")]
1525fn serialize_utxoset(us: &crate::commons::UTXOSetMessage) -> Result<Vec<u8>> {
1526 bincode::serialize(us).map_err(|e| {
1527 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1528 })
1529}
1530#[cfg(feature = "utxo-commitments")]
1531fn deserialize_utxoset(data: &[u8]) -> Result<crate::commons::UTXOSetMessage> {
1532 bincode::deserialize(data).map_err(|e| {
1533 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1534 })
1535}
1536
1537#[cfg(feature = "utxo-commitments")]
1538fn serialize_getfilteredblock(gfb: &crate::commons::GetFilteredBlockMessage) -> Result<Vec<u8>> {
1539 bincode::serialize(gfb).map_err(|e| {
1540 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1541 })
1542}
1543#[cfg(feature = "utxo-commitments")]
1544fn deserialize_getfilteredblock(data: &[u8]) -> Result<crate::commons::GetFilteredBlockMessage> {
1545 bincode::deserialize(data).map_err(|e| {
1546 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1547 })
1548}
1549
1550#[cfg(feature = "utxo-commitments")]
1551fn serialize_filteredblock(fb: &crate::commons::FilteredBlockMessage) -> Result<Vec<u8>> {
1552 bincode::serialize(fb).map_err(|e| {
1553 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1554 })
1555}
1556#[cfg(feature = "utxo-commitments")]
1557fn deserialize_filteredblock(data: &[u8]) -> Result<crate::commons::FilteredBlockMessage> {
1558 bincode::deserialize(data).map_err(|e| {
1559 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1560 })
1561}
1562
1563fn serialize_getbanlist(gbl: &crate::commons::GetBanListMessage) -> Result<Vec<u8>> {
1564 bincode::serialize(gbl).map_err(|e| {
1565 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1566 })
1567}
1568fn deserialize_getbanlist(data: &[u8]) -> Result<crate::commons::GetBanListMessage> {
1569 bincode::deserialize(data).map_err(|e| {
1570 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1571 })
1572}
1573
1574fn serialize_banlist(bl: &crate::commons::BanListMessage) -> Result<Vec<u8>> {
1575 bincode::serialize(bl).map_err(|e| {
1576 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1577 })
1578}
1579fn deserialize_banlist(data: &[u8]) -> Result<crate::commons::BanListMessage> {
1580 bincode::deserialize(data).map_err(|e| {
1581 ProtocolError::Consensus(ConsensusError::Serialization(Cow::Owned(e.to_string())))
1582 })
1583}