use blvm_protocol::network::{
process_network_message, AddrMessage, FeeFilterMessage, GetBlocksMessage, GetDataMessage,
HeadersMessage, InvMessage, NetworkAddress, NetworkMessage, NotFoundMessage, PeerState,
RejectMessage, VersionMessage,
};
use blvm_protocol::{BitcoinProtocolEngine, ProtocolVersion};
use std::sync::Arc;
fn create_test_engine() -> BitcoinProtocolEngine {
BitcoinProtocolEngine::new(ProtocolVersion::BitcoinV1).unwrap()
}
fn create_test_peer_state() -> PeerState {
PeerState::new()
}
#[test]
fn test_addr_message_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let addresses: Vec<NetworkAddress> = (0..1000)
.map(|i| NetworkAddress {
services: 1,
ip: [0u8; 16],
port: 8333 + i as u16,
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::Addr(AddrMessage {
addresses: addresses.clone(),
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::Ok
));
let addresses: Vec<NetworkAddress> = (0..1001)
.map(|i| NetworkAddress {
services: 1,
ip: [0u8; 16],
port: 8333 + i as u16,
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::Addr(AddrMessage { addresses }),
&mut peer_state,
None,
None,
None,
)
.unwrap();
match response {
blvm_protocol::network::NetworkResponse::Reject(reason) => {
assert!(reason.contains("Too many addresses"));
}
_ => panic!("Expected Reject for addresses over limit"),
}
}
#[test]
fn test_inv_message_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let inventory: Vec<blvm_protocol::network::InventoryVector> = (0..50000)
.map(|i| blvm_protocol::network::InventoryVector {
inv_type: 2,
hash: [i as u8; 32],
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::Inv(InvMessage {
inventory: inventory.clone(),
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::Ok
));
let inventory: Vec<blvm_protocol::network::InventoryVector> = (0..50001)
.map(|i| blvm_protocol::network::InventoryVector {
inv_type: 2,
hash: [i as u8; 32],
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::Inv(InvMessage { inventory }),
&mut peer_state,
None,
None,
None,
)
.unwrap();
match response {
blvm_protocol::network::NetworkResponse::Reject(reason) => {
assert!(reason.contains("Too many inventory items"));
}
_ => panic!("Expected Reject for inventory over limit"),
}
}
#[test]
fn test_getdata_message_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let inventory: Vec<blvm_protocol::network::InventoryVector> = (0..50000)
.map(|i| blvm_protocol::network::InventoryVector {
inv_type: 1,
hash: [i as u8; 32],
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::GetData(GetDataMessage {
inventory: inventory.clone(),
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::Ok
));
let inventory: Vec<blvm_protocol::network::InventoryVector> = (0..50001)
.map(|i| blvm_protocol::network::InventoryVector {
inv_type: 1,
hash: [i as u8; 32],
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::GetData(GetDataMessage { inventory }),
&mut peer_state,
None,
None,
None,
)
.unwrap();
match response {
blvm_protocol::network::NetworkResponse::Reject(reason) => {
assert!(reason.contains("Too many getdata items"));
}
_ => panic!("Expected Reject for getdata over limit"),
}
}
#[test]
fn test_headers_message_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let headers: Vec<blvm_consensus::BlockHeader> = (0..2000)
.map(|i| blvm_consensus::BlockHeader {
version: 1,
prev_block_hash: [i as u8; 32],
merkle_root: [0u8; 32],
timestamp: 1231006505u64 + i as u64,
bits: 0x1d00ffff,
nonce: 0,
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::Headers(HeadersMessage {
headers: headers.clone(),
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::Ok
));
let headers: Vec<blvm_consensus::BlockHeader> = (0..2001)
.map(|i| blvm_consensus::BlockHeader {
version: 1,
prev_block_hash: [i as u8; 32],
merkle_root: [0u8; 32],
timestamp: 1231006505u64 + i as u64,
bits: 0x1d00ffff,
nonce: 0,
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::Headers(HeadersMessage { headers }),
&mut peer_state,
None,
None,
None,
)
.unwrap();
match response {
blvm_protocol::network::NetworkResponse::Reject(reason) => {
assert!(reason.contains("Too many headers"));
}
_ => panic!("Expected Reject for headers over limit"),
}
}
#[test]
fn test_getblocks_locator_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let locator_hashes: Vec<blvm_consensus::Hash> = (0..100).map(|i| [i as u8; 32]).collect();
let response = process_network_message(
&engine,
&NetworkMessage::GetBlocks(GetBlocksMessage {
version: 70015,
block_locator_hashes: locator_hashes.clone(),
hash_stop: [0u8; 32],
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::Ok
));
let locator_hashes: Vec<blvm_consensus::Hash> = (0..101).map(|i| [i as u8; 32]).collect();
let response = process_network_message(
&engine,
&NetworkMessage::GetBlocks(GetBlocksMessage {
version: 70015,
block_locator_hashes: locator_hashes,
hash_stop: [0u8; 32],
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
match response {
blvm_protocol::network::NetworkResponse::Reject(reason) => {
assert!(reason.contains("Too many locator hashes"));
}
_ => panic!("Expected Reject for locators over limit"),
}
}
#[test]
fn test_notfound_message_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let inventory: Vec<blvm_protocol::network::InventoryVector> = (0..50000)
.map(|i| blvm_protocol::network::InventoryVector {
inv_type: 2,
hash: [i as u8; 32],
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::NotFound(NotFoundMessage {
inventory: inventory.clone(),
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::Ok
));
let inventory: Vec<blvm_protocol::network::InventoryVector> = (0..50001)
.map(|i| blvm_protocol::network::InventoryVector {
inv_type: 2,
hash: [i as u8; 32],
})
.collect();
let response = process_network_message(
&engine,
&NetworkMessage::NotFound(NotFoundMessage { inventory }),
&mut peer_state,
None,
None,
None,
)
.unwrap();
match response {
blvm_protocol::network::NetworkResponse::Reject(reason) => {
assert!(reason.contains("Too many notfound items"));
}
_ => panic!("Expected Reject for notfound over limit"),
}
}
#[test]
fn test_reject_message_name_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let response = process_network_message(
&engine,
&NetworkMessage::Reject(RejectMessage {
message: "123456789012".to_string(), code: 0x10,
reason: "Test".to_string(),
extra_data: None,
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::Ok
));
let response = process_network_message(
&engine,
&NetworkMessage::Reject(RejectMessage {
message: "1234567890123".to_string(), code: 0x10,
reason: "Test".to_string(),
extra_data: None,
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
match response {
blvm_protocol::network::NetworkResponse::Reject(reason) => {
assert!(reason.contains("Invalid reject message name"));
}
_ => panic!("Expected Reject for message name over limit"),
}
}
#[test]
fn test_reject_message_reason_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let reason = "a".repeat(111);
let response = process_network_message(
&engine,
&NetworkMessage::Reject(RejectMessage {
message: "block".to_string(),
code: 0x10,
reason: reason.clone(),
extra_data: None,
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::Ok
));
let reason = "a".repeat(112);
let response = process_network_message(
&engine,
&NetworkMessage::Reject(RejectMessage {
message: "block".to_string(),
code: 0x10,
reason,
extra_data: None,
}),
&mut peer_state,
None,
None,
None,
)
.unwrap();
match response {
blvm_protocol::network::NetworkResponse::Reject(reason) => {
assert!(reason.contains("Reject reason too long"));
}
_ => panic!("Expected Reject for reason over limit"),
}
}
#[test]
fn test_version_message_user_agent_limit() {
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let user_agent = "a".repeat(256);
let version = VersionMessage {
version: 70015,
services: 1,
timestamp: 1234567890,
addr_recv: NetworkAddress {
services: 1,
ip: [0u8; 16],
port: 8333,
},
addr_from: NetworkAddress {
services: 1,
ip: [0u8; 16],
port: 8333,
},
nonce: 12345,
user_agent: user_agent.clone(),
start_height: 0,
relay: true,
};
let response = process_network_message(
&engine,
&NetworkMessage::Version(version),
&mut peer_state,
None,
None,
None,
)
.unwrap();
assert!(matches!(
response,
blvm_protocol::network::NetworkResponse::SendMessage(_)
));
}
#[test]
fn test_block_transaction_count_limit() {
use blvm_consensus::types::UtxoSet;
use blvm_consensus::{tx_inputs, tx_outputs};
use blvm_consensus::{Block, BlockHeader};
let engine = create_test_engine();
let mut peer_state = create_test_peer_state();
let utxo_set = UtxoSet::default();
let transactions: Vec<blvm_consensus::Transaction> = (0..10000)
.map(|_| blvm_consensus::Transaction {
version: 1,
inputs: tx_inputs![],
outputs: tx_outputs![],
lock_time: 0,
})
.collect();
let block = Block {
header: BlockHeader {
version: 1,
prev_block_hash: [0u8; 32],
merkle_root: [0u8; 32],
timestamp: 1231006505,
bits: 0x1d00ffff,
nonce: 0,
},
transactions: transactions.into_boxed_slice(),
};
let response = process_network_message(
&engine,
&NetworkMessage::Block(Arc::new(block)),
&mut peer_state,
None, Some(&utxo_set),
Some(0), );
let response = match response {
Ok(r) => r,
Err(_) => {
return;
}
};
assert!(!matches!(
response,
blvm_protocol::network::NetworkResponse::Reject(ref r) if r.contains("Too many transactions")
));
let transactions: Vec<blvm_consensus::Transaction> = (0..10001)
.map(|_| blvm_consensus::Transaction {
version: 1,
inputs: tx_inputs![],
outputs: tx_outputs![],
lock_time: 0,
})
.collect();
let block = Block {
header: BlockHeader {
version: 1,
prev_block_hash: [0u8; 32],
merkle_root: [0u8; 32],
timestamp: 1231006505,
bits: 0x1d00ffff,
nonce: 0,
},
transactions: transactions.into_boxed_slice(),
};
let response = process_network_message(
&engine,
&NetworkMessage::Block(Arc::new(block)),
&mut peer_state,
None, Some(&utxo_set),
Some(0), );
match response {
Ok(blvm_protocol::network::NetworkResponse::Reject(ref r)) => {
assert!(r.contains("Too many transactions") || r.contains("Message size exceeds"));
}
Ok(_) => {
}
Err(_) => {
}
}
}