1use crate::bip152::ShortTxId;
8use crate::error::ProtocolError;
9use crate::validation::ProtocolValidationContext;
10use crate::{BitcoinProtocolEngine, ProtocolConfig, Result};
11use blvm_consensus::error::ConsensusError;
12use blvm_consensus::types::UtxoSet;
13use blvm_consensus::types::{Block, BlockHeader, Hash, Transaction, ValidationResult};
14use std::sync::Arc;
15use thiserror::Error;
16
17pub mod commons {
19 pub use crate::commons::*;
20}
21
22#[cfg(all(
24 feature = "bip324",
25 any(target_arch = "x86_64", target_arch = "aarch64")
26))]
27pub mod v2_transport {
28 pub use crate::v2_transport::*;
29}
30
31#[cfg(test)]
32mod bip155_tests;
33
34#[derive(Debug, Clone, PartialEq)]
38pub enum NetworkMessage {
39 Version(VersionMessage),
40 VerAck,
41 Addr(AddrMessage),
42 AddrV2(AddrV2Message), Inv(InvMessage),
44 GetData(GetDataMessage),
45 GetHeaders(GetHeadersMessage),
46 Headers(HeadersMessage),
47 Block(Arc<Block>),
48 Tx(Arc<Transaction>),
49 Ping(PingMessage),
50 Pong(PongMessage),
51 MemPool,
52 FeeFilter(FeeFilterMessage),
53 GetBlocks(GetBlocksMessage),
55 GetAddr,
56 NotFound(NotFoundMessage),
57 Reject(RejectMessage),
58 SendHeaders,
59 SendCmpct(SendCmpctMessage),
61 CmpctBlock(CmpctBlockMessage),
62 GetBlockTxn(GetBlockTxnMessage),
63 BlockTxn(BlockTxnMessage),
64 #[cfg(feature = "utxo-commitments")]
66 GetUTXOSet(commons::GetUTXOSetMessage),
67 #[cfg(feature = "utxo-commitments")]
68 UTXOSet(commons::UTXOSetMessage),
69 #[cfg(feature = "utxo-commitments")]
70 GetFilteredBlock(commons::GetFilteredBlockMessage),
71 #[cfg(feature = "utxo-commitments")]
72 FilteredBlock(commons::FilteredBlockMessage),
73 GetBanList(commons::GetBanListMessage),
74 BanList(commons::BanListMessage),
75}
76
77#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
79pub struct VersionMessage {
80 pub version: u32,
81 pub services: u64,
82 pub timestamp: i64,
83 pub addr_recv: NetworkAddress,
84 pub addr_from: NetworkAddress,
85 pub nonce: u64,
86 pub user_agent: String,
87 pub start_height: i32,
88 pub relay: bool,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
97pub struct BlockMessage {
98 pub block: Block,
99 #[serde(skip_serializing_if = "Vec::is_empty", default)]
101 pub witnesses: Vec<Vec<blvm_consensus::segwit::Witness>>,
102}
103
104#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
106pub struct TxMessage {
107 pub transaction: Transaction,
108}
109
110#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
115pub struct CompactBlockMessage {
116 pub compact_block: crate::bip152::CompactBlock,
117}
118
119#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
121pub struct AddrMessage {
122 pub addresses: Vec<NetworkAddress>,
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
127pub struct InvMessage {
128 pub inventory: Vec<InventoryVector>,
129}
130
131#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
133pub struct GetDataMessage {
134 pub inventory: Vec<InventoryVector>,
135}
136
137#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
139pub struct GetHeadersMessage {
140 pub version: u32,
141 pub block_locator_hashes: Vec<Hash>,
142 pub hash_stop: Hash,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
147pub struct HeadersMessage {
148 pub headers: Vec<BlockHeader>,
149}
150
151#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
153pub struct PingMessage {
154 pub nonce: u64,
155}
156
157#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
159pub struct PongMessage {
160 pub nonce: u64,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
165pub struct FeeFilterMessage {
166 pub feerate: u64,
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
171pub struct GetBlocksMessage {
172 pub version: u32,
173 pub block_locator_hashes: Vec<Hash>,
174 pub hash_stop: Hash,
175}
176
177#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
179pub struct NotFoundMessage {
180 pub inventory: Vec<InventoryVector>,
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
185pub struct RejectMessage {
186 pub message: String, pub code: u8, pub reason: String, pub extra_data: Option<Hash>, }
191
192#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
194pub struct SendCmpctMessage {
195 pub version: u64,
197 pub prefer_cmpct: u8,
199}
200
201#[derive(Debug, Clone, PartialEq, Eq)]
203pub struct CmpctBlockMessage {
204 pub header: BlockHeader,
206 pub nonce: u64,
208 pub short_ids: Vec<ShortTxId>,
210 pub prefilled_txs: Vec<PrefilledTransaction>,
212}
213
214#[derive(Debug, Clone, PartialEq, Eq)]
216pub struct PrefilledTransaction {
217 pub index: u16,
219 pub tx: Transaction,
221 pub witness: Option<Vec<blvm_consensus::segwit::Witness>>,
223}
224
225#[derive(Debug, Clone, PartialEq, Eq, Error)]
227pub enum CompactBlockWireConvertError {
228 #[error("prefilled transaction index {0} does not fit in BIP152 u16 index")]
229 PrefilledIndexTooLarge(usize),
230 #[error("duplicate prefilled transaction index {0}")]
231 DuplicatePrefilledIndex(usize),
232}
233
234impl TryFrom<crate::bip152::CompactBlock> for CmpctBlockMessage {
235 type Error = CompactBlockWireConvertError;
236
237 fn try_from(mut value: crate::bip152::CompactBlock) -> std::result::Result<Self, Self::Error> {
242 value.prefilled_txs.sort_by_key(|(i, _)| *i);
243 let mut prefilled_txs = Vec::with_capacity(value.prefilled_txs.len());
244 let mut prev_idx: Option<usize> = None;
245 for (idx, tx) in value.prefilled_txs {
246 if prev_idx == Some(idx) {
247 return Err(CompactBlockWireConvertError::DuplicatePrefilledIndex(idx));
248 }
249 prev_idx = Some(idx);
250 let index = u16::try_from(idx)
251 .map_err(|_| CompactBlockWireConvertError::PrefilledIndexTooLarge(idx))?;
252 prefilled_txs.push(PrefilledTransaction {
253 index,
254 tx,
255 witness: None,
256 });
257 }
258 Ok(CmpctBlockMessage {
259 header: value.header,
260 nonce: value.nonce,
261 short_ids: value.short_ids,
262 prefilled_txs,
263 })
264 }
265}
266
267impl From<&CmpctBlockMessage> for crate::bip152::CompactBlock {
268 fn from(msg: &CmpctBlockMessage) -> Self {
269 Self {
270 header: msg.header.clone(),
271 nonce: msg.nonce,
272 short_ids: msg.short_ids.clone(),
273 prefilled_txs: msg
274 .prefilled_txs
275 .iter()
276 .map(|p| (usize::from(p.index), p.tx.clone()))
277 .collect(),
278 }
279 }
280}
281
282impl From<CmpctBlockMessage> for crate::bip152::CompactBlock {
283 fn from(msg: CmpctBlockMessage) -> Self {
284 Self {
285 header: msg.header,
286 nonce: msg.nonce,
287 short_ids: msg.short_ids,
288 prefilled_txs: msg
289 .prefilled_txs
290 .into_iter()
291 .map(|p| (usize::from(p.index), p.tx))
292 .collect(),
293 }
294 }
295}
296
297#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
299pub struct GetBlockTxnMessage {
300 pub block_hash: Hash,
302 pub indices: Vec<u16>,
304}
305
306#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
308pub struct BlockTxnMessage {
309 pub block_hash: Hash,
311 pub transactions: Vec<Transaction>,
313 pub witnesses: Option<Vec<Vec<blvm_consensus::segwit::Witness>>>,
315}
316
317#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
319pub struct NetworkAddress {
320 pub services: u64,
321 pub ip: [u8; 16], pub port: u16,
323}
324
325#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
327#[repr(u8)]
328pub enum AddressType {
329 IPv4 = 1,
330 IPv6 = 2,
331 TorV2 = 3,
332 TorV3 = 4,
333 I2P = 5,
334 CJDNS = 6,
335}
336
337impl AddressType {
338 pub fn address_length(&self) -> usize {
340 match self {
341 AddressType::IPv4 => 4,
342 AddressType::IPv6 => 16,
343 AddressType::TorV2 => 10,
344 AddressType::TorV3 => 32,
345 AddressType::I2P => 32,
346 AddressType::CJDNS => 16,
347 }
348 }
349
350 pub fn from_u8(value: u8) -> Option<Self> {
352 match value {
353 1 => Some(AddressType::IPv4),
354 2 => Some(AddressType::IPv6),
355 3 => Some(AddressType::TorV2),
356 4 => Some(AddressType::TorV3),
357 5 => Some(AddressType::I2P),
358 6 => Some(AddressType::CJDNS),
359 _ => None,
360 }
361 }
362}
363
364#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
366pub struct AddrV2Message {
367 pub addresses: Vec<NetworkAddressV2>,
368}
369
370#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
372pub struct NetworkAddressV2 {
373 pub time: u32,
374 pub services: u64,
375 pub address_type: AddressType,
376 pub address: Vec<u8>, pub port: u16,
378}
379
380impl NetworkAddressV2 {
381 pub fn new(
383 time: u32,
384 services: u64,
385 address_type: AddressType,
386 address: Vec<u8>,
387 port: u16,
388 ) -> Result<Self> {
389 let expected_len = address_type.address_length();
390 if address.len() != expected_len {
391 return Err(ProtocolError::Consensus(ConsensusError::Serialization(
392 std::borrow::Cow::Owned(format!(
393 "Invalid address length for type {:?}: expected {}, got {}",
394 address_type,
395 expected_len,
396 address.len()
397 )),
398 )));
399 }
400 Ok(Self {
401 time,
402 services,
403 address_type,
404 address,
405 port,
406 })
407 }
408
409 pub fn to_legacy(&self) -> Option<NetworkAddress> {
411 match self.address_type {
412 AddressType::IPv4 => {
413 if self.address.len() == 4 {
414 let mut ipv6 = [0u8; 16];
416 ipv6[10] = 0xff;
417 ipv6[11] = 0xff;
418 ipv6[12..16].copy_from_slice(&self.address);
419 Some(NetworkAddress {
420 services: self.services,
421 ip: ipv6,
422 port: self.port,
423 })
424 } else {
425 None
426 }
427 }
428 AddressType::IPv6 => {
429 if self.address.len() == 16 {
430 let mut ipv6 = [0u8; 16];
431 ipv6.copy_from_slice(&self.address);
432 Some(NetworkAddress {
433 services: self.services,
434 ip: ipv6,
435 port: self.port,
436 })
437 } else {
438 None
439 }
440 }
441 _ => None, }
443 }
444}
445
446#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
448pub struct InventoryVector {
449 pub inv_type: u32,
450 pub hash: Hash,
451}
452
453#[derive(Debug, Clone)]
455pub enum NetworkResponse {
456 Ok,
457 SendMessage(Box<NetworkMessage>),
458 SendMessages(Vec<NetworkMessage>),
459 Reject(String),
460}
461
462#[derive(Clone)]
464pub struct PeerState {
465 pub version: u32,
466 pub services: u64,
467 pub user_agent: String,
468 pub start_height: i32,
469 pub handshake_complete: bool,
470 pub known_addresses: Vec<NetworkAddress>,
471 pub ping_nonce: Option<u64>,
472 pub last_pong: Option<std::time::SystemTime>,
473 pub min_fee_rate: Option<u64>,
474 #[cfg(all(
477 feature = "bip324",
478 any(target_arch = "x86_64", target_arch = "aarch64")
479 ))]
480 pub v2_transport: Option<std::sync::Arc<crate::v2_transport::V2Transport>>,
481 #[cfg(all(
483 feature = "bip324",
484 any(target_arch = "x86_64", target_arch = "aarch64")
485 ))]
486 pub v2_handshake: Option<std::sync::Arc<crate::v2_transport::V2Handshake>>,
487}
488
489impl PeerState {
490 pub fn new() -> Self {
491 Self {
492 version: 0,
493 services: 0,
494 user_agent: String::new(),
495 start_height: 0,
496 handshake_complete: false,
497 known_addresses: Vec::new(),
498 ping_nonce: None,
499 last_pong: None,
500 min_fee_rate: None,
501 #[cfg(all(
502 feature = "bip324",
503 any(target_arch = "x86_64", target_arch = "aarch64")
504 ))]
505 v2_transport: None,
506 #[cfg(all(
507 feature = "bip324",
508 any(target_arch = "x86_64", target_arch = "aarch64")
509 ))]
510 v2_handshake: None,
511 }
512 }
513
514 #[cfg(all(
516 feature = "bip324",
517 any(target_arch = "x86_64", target_arch = "aarch64")
518 ))]
519 pub fn supports_v2_transport(&self) -> bool {
520 use crate::service_flags::{has_flag, standard};
521 has_flag(self.services, standard::NODE_V2_TRANSPORT)
522 }
523
524 #[cfg(all(
526 feature = "bip324",
527 any(target_arch = "x86_64", target_arch = "aarch64")
528 ))]
529 pub fn is_v2_transport_active(&self) -> bool {
530 self.v2_transport.is_some()
531 }
532}
533
534impl Default for PeerState {
535 fn default() -> Self {
536 Self::new()
537 }
538}
539
540#[derive(Debug, Clone)]
542pub enum ChainObject {
543 Block(Arc<Block>),
544 Transaction(Arc<Transaction>),
545}
546
547impl ChainObject {
548 pub fn as_block(&self) -> Option<&Arc<Block>> {
549 match self {
550 ChainObject::Block(block) => Some(block),
551 _ => None,
552 }
553 }
554
555 pub fn as_transaction(&self) -> Option<&Arc<Transaction>> {
556 match self {
557 ChainObject::Transaction(tx) => Some(tx),
558 _ => None,
559 }
560 }
561}
562
563pub trait ChainStateAccess {
569 fn has_object(&self, hash: &Hash) -> bool;
571
572 fn get_object(&self, hash: &Hash) -> Option<ChainObject>;
574
575 fn get_headers_for_locator(&self, locator: &[Hash], stop: &Hash) -> Vec<BlockHeader>;
578
579 fn get_mempool_transactions(&self) -> Vec<Transaction>;
581}
582
583pub fn process_network_message(
601 engine: &BitcoinProtocolEngine,
602 message: &NetworkMessage,
603 peer_state: &mut PeerState,
604 chain_access: Option<&dyn ChainStateAccess>,
605 utxo_set: Option<&UtxoSet>,
606 height: Option<u64>,
607) -> Result<NetworkResponse> {
608 let config = engine.get_config();
609 match message {
610 NetworkMessage::Version(version) => process_version_message(version, peer_state, config),
611 NetworkMessage::VerAck => process_verack_message(peer_state),
612 NetworkMessage::Addr(addr) => process_addr_message(addr, peer_state, config),
613 NetworkMessage::AddrV2(addrv2) => process_addrv2_message(addrv2, peer_state, config),
614 NetworkMessage::Inv(inv) => process_inv_message(inv, chain_access, config),
615 NetworkMessage::GetData(getdata) => process_getdata_message(getdata, chain_access, config),
616 NetworkMessage::GetHeaders(getheaders) => {
617 process_getheaders_message(getheaders, chain_access, config)
618 }
619 NetworkMessage::Headers(headers) => process_headers_message(headers, config),
620 NetworkMessage::Block(block) => {
621 process_block_message(engine, block, utxo_set, height, config)
622 }
623 NetworkMessage::Tx(tx) => process_tx_message(engine, tx, height),
624 NetworkMessage::Ping(ping) => process_ping_message(ping, peer_state),
625 NetworkMessage::Pong(pong) => process_pong_message(pong, peer_state),
626 NetworkMessage::MemPool => process_mempool_message(chain_access),
627 NetworkMessage::FeeFilter(feefilter) => process_feefilter_message(feefilter, peer_state),
628 NetworkMessage::GetBlocks(getblocks) => {
629 process_getblocks_message(getblocks, chain_access, config)
630 }
631 NetworkMessage::GetAddr => process_getaddr_message(peer_state, config),
632 NetworkMessage::NotFound(notfound) => process_notfound_message(notfound, config),
633 NetworkMessage::Reject(reject) => process_reject_message(reject, config),
634 NetworkMessage::SendHeaders => process_sendheaders_message(peer_state),
635 NetworkMessage::SendCmpct(sendcmpct) => {
636 process_sendcmpct_message(sendcmpct, peer_state, config)
637 }
638 NetworkMessage::CmpctBlock(cmpctblock) => process_cmpctblock_message(cmpctblock),
639 NetworkMessage::GetBlockTxn(getblocktxn) => {
640 process_getblocktxn_message(getblocktxn, chain_access, config)
641 }
642 NetworkMessage::BlockTxn(blocktxn) => process_blocktxn_message(blocktxn),
643 #[cfg(feature = "utxo-commitments")]
644 NetworkMessage::GetUTXOSet(getutxoset) => process_getutxoset_message(getutxoset),
645 #[cfg(feature = "utxo-commitments")]
646 NetworkMessage::UTXOSet(utxoset) => process_utxoset_message(utxoset),
647 #[cfg(feature = "utxo-commitments")]
648 NetworkMessage::GetFilteredBlock(getfiltered) => {
649 process_getfilteredblock_message(getfiltered)
650 }
651 #[cfg(feature = "utxo-commitments")]
652 NetworkMessage::FilteredBlock(filtered) => process_filteredblock_message(filtered),
653 NetworkMessage::GetBanList(getbanlist) => process_getbanlist_message(getbanlist),
654 NetworkMessage::BanList(banlist) => process_banlist_message(banlist),
655 }
656}
657
658fn process_version_message(
660 version: &VersionMessage,
661 peer_state: &mut PeerState,
662 config: &ProtocolConfig,
663) -> Result<NetworkResponse> {
664 if version.version < 70001 {
666 return Ok(NetworkResponse::Reject("Version too old".into()));
667 }
668
669 if version.user_agent.len() > config.network_limits.max_user_agent_length {
671 return Ok(NetworkResponse::Reject(format!(
672 "User agent too long (max {} bytes)",
673 config.network_limits.max_user_agent_length
674 )));
675 }
676
677 peer_state.version = version.version;
679 peer_state.services = version.services;
680 peer_state.user_agent = version.user_agent.clone();
681 peer_state.start_height = version.start_height;
682
683 #[cfg(all(
685 feature = "bip324",
686 any(target_arch = "x86_64", target_arch = "aarch64")
687 ))]
688 {
689 use crate::service_flags::{has_flag, standard};
690 let peer_supports_v2 = has_flag(version.services, standard::NODE_V2_TRANSPORT);
691 let we_support_v2 = config.service_flags.node_v2_transport;
692
693 if peer_supports_v2 && we_support_v2 {
694 let handshake = crate::v2_transport::V2Handshake::new_responder();
696 peer_state.v2_handshake = Some(std::sync::Arc::new(handshake));
697 }
700 }
701
702 Ok(NetworkResponse::SendMessage(Box::new(
704 NetworkMessage::VerAck,
705 )))
706}
707
708fn process_verack_message(peer_state: &mut PeerState) -> Result<NetworkResponse> {
710 peer_state.handshake_complete = true;
711 Ok(NetworkResponse::Ok)
712}
713
714fn process_addr_message(
716 addr: &AddrMessage,
717 peer_state: &mut PeerState,
718 config: &ProtocolConfig,
719) -> Result<NetworkResponse> {
720 if addr.addresses.len() > config.network_limits.max_addr_addresses {
722 return Ok(NetworkResponse::Reject(format!(
723 "Too many addresses (max {})",
724 config.network_limits.max_addr_addresses
725 )));
726 }
727
728 peer_state.known_addresses.extend(addr.addresses.clone());
730
731 Ok(NetworkResponse::Ok)
732}
733
734fn process_addrv2_message(
736 addrv2: &AddrV2Message,
737 peer_state: &mut PeerState,
738 config: &ProtocolConfig,
739) -> Result<NetworkResponse> {
740 if addrv2.addresses.len() > config.network_limits.max_addr_addresses {
742 return Ok(NetworkResponse::Reject(format!(
743 "Too many addresses (max {})",
744 config.network_limits.max_addr_addresses
745 )));
746 }
747
748 for addr_v2 in &addrv2.addresses {
750 if let Some(legacy_addr) = addr_v2.to_legacy() {
751 peer_state.known_addresses.push(legacy_addr);
752 }
753 }
756
757 Ok(NetworkResponse::Ok)
758}
759
760fn process_inv_message(
762 inv: &InvMessage,
763 chain_access: Option<&dyn ChainStateAccess>,
764 config: &ProtocolConfig,
765) -> Result<NetworkResponse> {
766 if inv.inventory.len() > config.network_limits.max_inv_items {
768 return Ok(NetworkResponse::Reject(format!(
769 "Too many inventory items (max {})",
770 config.network_limits.max_inv_items
771 )));
772 }
773
774 if let Some(chain) = chain_access {
776 let mut needed_items = Vec::with_capacity(inv.inventory.len());
777 for item in &inv.inventory {
778 if !chain.has_object(&item.hash) {
779 needed_items.push(item.clone());
780 }
781 }
782
783 if !needed_items.is_empty() {
784 return Ok(NetworkResponse::SendMessage(Box::new(
785 NetworkMessage::GetData(GetDataMessage {
786 inventory: needed_items,
787 }),
788 )));
789 }
790 }
791
792 Ok(NetworkResponse::Ok)
793}
794
795fn process_getdata_message(
797 getdata: &GetDataMessage,
798 chain_access: Option<&dyn ChainStateAccess>,
799 config: &ProtocolConfig,
800) -> Result<NetworkResponse> {
801 if getdata.inventory.len() > config.network_limits.max_inv_items {
803 return Ok(NetworkResponse::Reject(format!(
804 "Too many getdata items (max {})",
805 config.network_limits.max_inv_items
806 )));
807 }
808
809 if let Some(chain) = chain_access {
811 let mut responses = Vec::with_capacity(getdata.inventory.len());
812 for item in &getdata.inventory {
813 if let Some(obj) = chain.get_object(&item.hash) {
814 match item.inv_type {
815 1 => {
816 if let Some(tx) = obj.as_transaction() {
818 responses.push(NetworkMessage::Tx(Arc::clone(tx)));
819 }
820 }
821 2 => {
822 if let Some(block) = obj.as_block() {
824 responses.push(NetworkMessage::Block(Arc::clone(block)));
825 }
826 }
827 _ => {
828 }
830 }
831 }
832 }
833
834 if !responses.is_empty() {
835 return Ok(NetworkResponse::SendMessages(responses));
836 }
837 }
838
839 Ok(NetworkResponse::Ok)
840}
841
842fn process_getheaders_message(
844 getheaders: &GetHeadersMessage,
845 chain_access: Option<&dyn ChainStateAccess>,
846 config: &ProtocolConfig,
847) -> Result<NetworkResponse> {
848 if getheaders.block_locator_hashes.len() > config.validation.max_locator_hashes {
850 return Ok(NetworkResponse::Reject(format!(
851 "Too many locator hashes (max {})",
852 config.validation.max_locator_hashes
853 )));
854 }
855
856 if let Some(chain) = chain_access {
858 let headers =
859 chain.get_headers_for_locator(&getheaders.block_locator_hashes, &getheaders.hash_stop);
860 return Ok(NetworkResponse::SendMessage(Box::new(
861 NetworkMessage::Headers(HeadersMessage { headers }),
862 )));
863 }
864
865 Ok(NetworkResponse::Reject("Chain access not available".into()))
866}
867
868fn process_headers_message(
870 headers: &HeadersMessage,
871 config: &ProtocolConfig,
872) -> Result<NetworkResponse> {
873 if headers.headers.len() > config.network_limits.max_headers {
875 return Ok(NetworkResponse::Reject(format!(
876 "Too many headers (max {})",
877 config.network_limits.max_headers
878 )));
879 }
880
881 Ok(NetworkResponse::Ok)
884}
885
886fn process_block_message(
888 engine: &BitcoinProtocolEngine,
889 block: &Block,
890 utxo_set: Option<&UtxoSet>,
891 height: Option<u64>,
892 config: &ProtocolConfig,
893) -> Result<NetworkResponse> {
894 if block.transactions.len() > config.validation.max_txs_per_block {
896 return Err(crate::error::ProtocolError::MessageTooLarge {
897 size: block.transactions.len(),
898 max: config.validation.max_txs_per_block,
899 });
900 }
901
902 if let (Some(utxos), Some(h)) = (utxo_set, height) {
904 let context = ProtocolValidationContext::new(engine.get_protocol_version(), h)?;
905 let result = engine.validate_block_with_protocol(block, utxos, h, &context)?;
906
907 match result {
908 ValidationResult::Valid => Ok(NetworkResponse::Ok),
909 ValidationResult::Invalid(reason) => {
910 Ok(NetworkResponse::Reject(format!("Invalid block: {reason}")))
911 }
912 }
913 } else {
914 Err(crate::error::ProtocolError::Configuration(
915 "Missing validation context (utxo_set and height required)".into(),
916 ))
917 }
918}
919
920fn process_tx_message(
922 engine: &BitcoinProtocolEngine,
923 tx: &Transaction,
924 height: Option<u64>,
925) -> Result<NetworkResponse> {
926 let context =
928 ProtocolValidationContext::new(engine.get_protocol_version(), height.unwrap_or(0))?;
929 let result = engine.validate_transaction_with_protocol(tx, &context)?;
930
931 match result {
932 ValidationResult::Valid => Ok(NetworkResponse::Ok),
933 ValidationResult::Invalid(reason) => Ok(NetworkResponse::Reject(format!(
934 "Invalid transaction: {reason}"
935 ))),
936 }
937}
938
939fn process_ping_message(
941 ping: &PingMessage,
942 _peer_state: &mut PeerState,
943) -> Result<NetworkResponse> {
944 let pong = NetworkMessage::Pong(PongMessage { nonce: ping.nonce });
945 Ok(NetworkResponse::SendMessage(Box::new(pong)))
946}
947
948fn process_pong_message(pong: &PongMessage, peer_state: &mut PeerState) -> Result<NetworkResponse> {
950 if peer_state.ping_nonce == Some(pong.nonce) {
952 peer_state.ping_nonce = None;
953 peer_state.last_pong = Some(std::time::SystemTime::now());
954 }
955
956 Ok(NetworkResponse::Ok)
957}
958
959fn process_mempool_message(chain_access: Option<&dyn ChainStateAccess>) -> Result<NetworkResponse> {
961 if let Some(chain) = chain_access {
963 let mempool_txs = chain.get_mempool_transactions();
964 let mut responses = Vec::with_capacity(mempool_txs.len());
965
966 for tx in mempool_txs {
967 responses.push(NetworkMessage::Tx(Arc::new(tx)));
968 }
969
970 if !responses.is_empty() {
971 return Ok(NetworkResponse::SendMessages(responses));
972 }
973 }
974
975 Ok(NetworkResponse::Ok)
976}
977
978fn process_feefilter_message(
980 feefilter: &FeeFilterMessage,
981 peer_state: &mut PeerState,
982) -> Result<NetworkResponse> {
983 peer_state.min_fee_rate = Some(feefilter.feerate);
984 Ok(NetworkResponse::Ok)
985}
986
987fn process_getblocks_message(
989 getblocks: &GetBlocksMessage,
990 chain_access: Option<&dyn ChainStateAccess>,
991 config: &ProtocolConfig,
992) -> Result<NetworkResponse> {
993 if getblocks.block_locator_hashes.len() > config.validation.max_locator_hashes {
995 return Ok(NetworkResponse::Reject(format!(
996 "Too many locator hashes (max {})",
997 config.validation.max_locator_hashes
998 )));
999 }
1000
1001 if let Some(chain) = chain_access {
1005 let mut inventory = Vec::with_capacity(getblocks.block_locator_hashes.len());
1007 for hash in &getblocks.block_locator_hashes {
1008 if chain.has_object(hash) {
1009 inventory.push(InventoryVector {
1010 inv_type: 2, hash: *hash,
1012 });
1013 }
1014 }
1015
1016 if !inventory.is_empty() {
1017 return Ok(NetworkResponse::SendMessage(Box::new(NetworkMessage::Inv(
1018 InvMessage { inventory },
1019 ))));
1020 }
1021 }
1022
1023 Ok(NetworkResponse::Ok)
1024}
1025
1026fn process_getaddr_message(
1028 peer_state: &mut PeerState,
1029 config: &ProtocolConfig,
1030) -> Result<NetworkResponse> {
1031 if !peer_state.known_addresses.is_empty() {
1033 let max_addrs = config
1035 .network_limits
1036 .max_addr_addresses
1037 .min(peer_state.known_addresses.len());
1038 let mut addresses = Vec::with_capacity(max_addrs);
1039 addresses.extend(peer_state.known_addresses.iter().take(max_addrs).cloned());
1040
1041 return Ok(NetworkResponse::SendMessage(Box::new(
1042 NetworkMessage::Addr(AddrMessage { addresses }),
1043 )));
1044 }
1045
1046 Ok(NetworkResponse::Ok)
1047}
1048
1049fn process_notfound_message(
1051 notfound: &NotFoundMessage,
1052 config: &ProtocolConfig,
1053) -> Result<NetworkResponse> {
1054 if notfound.inventory.len() > config.network_limits.max_inv_items {
1056 return Ok(NetworkResponse::Reject(format!(
1057 "Too many notfound items (max {})",
1058 config.network_limits.max_inv_items
1059 )));
1060 }
1061
1062 Ok(NetworkResponse::Ok)
1064}
1065
1066fn process_reject_message(
1068 reject: &RejectMessage,
1069 _config: &ProtocolConfig,
1070) -> Result<NetworkResponse> {
1071 if reject.message.len() > 12 {
1074 return Ok(NetworkResponse::Reject(
1075 "Invalid reject message name".into(),
1076 ));
1077 }
1078
1079 if reject.reason.len() > 111 {
1082 return Ok(NetworkResponse::Reject("Reject reason too long".into()));
1083 }
1084
1085 Ok(NetworkResponse::Ok)
1088}
1089
1090fn process_sendheaders_message(_peer_state: &mut PeerState) -> Result<NetworkResponse> {
1092 Ok(NetworkResponse::Ok)
1096}
1097
1098fn process_sendcmpct_message(
1100 sendcmpct: &SendCmpctMessage,
1101 _peer_state: &mut PeerState,
1102 config: &ProtocolConfig,
1103) -> Result<NetworkResponse> {
1104 let valid_versions = [1, 2];
1106 if !valid_versions.contains(&sendcmpct.version) {
1107 return Ok(NetworkResponse::Reject(
1108 "Invalid compact block version".into(),
1109 ));
1110 }
1111
1112 if !config.compact_blocks.enabled {
1114 return Ok(NetworkResponse::Reject("Compact blocks not enabled".into()));
1115 }
1116
1117 let _ = (sendcmpct.version, sendcmpct.prefer_cmpct);
1120 Ok(NetworkResponse::Ok)
1121}
1122
1123fn process_cmpctblock_message(_cmpctblock: &CmpctBlockMessage) -> Result<NetworkResponse> {
1125 Ok(NetworkResponse::Ok)
1128}
1129
1130fn process_getblocktxn_message(
1132 getblocktxn: &GetBlockTxnMessage,
1133 chain_access: Option<&dyn ChainStateAccess>,
1134 config: &ProtocolConfig,
1135) -> Result<NetworkResponse> {
1136 if getblocktxn.indices.len() > config.compact_blocks.max_blocktxn_indices {
1138 return Ok(NetworkResponse::Reject(format!(
1139 "Too many transaction indices (max {})",
1140 config.compact_blocks.max_blocktxn_indices
1141 )));
1142 }
1143
1144 if let Some(chain) = chain_access {
1146 let mut transactions = Vec::new();
1147 for &index in &getblocktxn.indices {
1148 if let Some(obj) = chain.get_object(&getblocktxn.block_hash) {
1151 if let Some(block) = obj.as_block() {
1152 if (index as usize) < block.transactions.len() {
1153 transactions.push(block.transactions[index as usize].clone());
1154 }
1155 }
1156 }
1157 }
1158
1159 if !transactions.is_empty() {
1160 return Ok(NetworkResponse::SendMessage(Box::new(
1161 NetworkMessage::BlockTxn(BlockTxnMessage {
1162 block_hash: getblocktxn.block_hash,
1163 transactions,
1164 witnesses: None, }),
1166 )));
1167 }
1168 }
1169
1170 Ok(NetworkResponse::Ok)
1171}
1172
1173fn process_blocktxn_message(_blocktxn: &BlockTxnMessage) -> Result<NetworkResponse> {
1175 Ok(NetworkResponse::Ok)
1178}
1179
1180#[cfg(feature = "utxo-commitments")]
1181fn process_getutxoset_message(_getutxoset: &commons::GetUTXOSetMessage) -> Result<NetworkResponse> {
1183 Ok(NetworkResponse::Ok)
1186}
1187
1188#[cfg(feature = "utxo-commitments")]
1189fn process_utxoset_message(_utxoset: &commons::UTXOSetMessage) -> Result<NetworkResponse> {
1191 Ok(NetworkResponse::Ok)
1194}
1195
1196#[cfg(feature = "utxo-commitments")]
1197fn process_getfilteredblock_message(
1199 _getfiltered: &commons::GetFilteredBlockMessage,
1200) -> Result<NetworkResponse> {
1201 Ok(NetworkResponse::Ok)
1204}
1205
1206#[cfg(feature = "utxo-commitments")]
1207fn process_filteredblock_message(
1209 _filtered: &commons::FilteredBlockMessage,
1210) -> Result<NetworkResponse> {
1211 Ok(NetworkResponse::Ok)
1214}
1215
1216fn process_getbanlist_message(_getbanlist: &commons::GetBanListMessage) -> Result<NetworkResponse> {
1218 Ok(NetworkResponse::Ok)
1221}
1222
1223fn process_banlist_message(_banlist: &commons::BanListMessage) -> Result<NetworkResponse> {
1225 Ok(NetworkResponse::Ok)
1228}