diff --git a/Cargo.toml b/Cargo.toml index 639502ce..3f9b2aa3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ path = "src/bin/saorsa-client/main.rs" [dependencies] # Core (provides EVERYTHING: networking, DHT, security, trust, storage) -saorsa-core = "0.11.1" +saorsa-core = "0.12.1" saorsa-pqc = "0.4.0" # Payment verification - autonomi network lookup + EVM payment diff --git a/src/ant_protocol/mod.rs b/src/ant_protocol/mod.rs index 0d9b7457..f993b454 100644 --- a/src/ant_protocol/mod.rs +++ b/src/ant_protocol/mod.rs @@ -52,5 +52,5 @@ pub mod chunk; pub use chunk::{ ChunkGetRequest, ChunkGetResponse, ChunkMessage, ChunkMessageBody, ChunkPutRequest, ChunkPutResponse, ChunkQuoteRequest, ChunkQuoteResponse, ProtocolError, XorName, - CHUNK_PROTOCOL_ID, DATA_TYPE_CHUNK, MAX_CHUNK_SIZE, PROTOCOL_VERSION, + CHUNK_PROTOCOL_ID, DATA_TYPE_CHUNK, MAX_CHUNK_SIZE, MAX_WIRE_MESSAGE_SIZE, PROTOCOL_VERSION, }; diff --git a/src/config.rs b/src/config.rs index 8e55be6e..a710b1ca 100644 --- a/src/config.rs +++ b/src/config.rs @@ -136,6 +136,15 @@ pub struct NodeConfig { #[serde(default)] pub storage: StorageConfig, + /// Maximum application-layer message size in bytes. + /// + /// Tunes the QUIC stream receive window and per-stream read buffer. + /// Default: [`MAX_WIRE_MESSAGE_SIZE`](crate::ant_protocol::MAX_WIRE_MESSAGE_SIZE) + /// (5 MiB — sufficient for 4 MiB data chunks plus serialization + /// envelope overhead). + #[serde(default = "default_max_message_size")] + pub max_message_size: usize, + /// Log level. #[serde(default = "default_log_level")] pub log_level: String, @@ -248,6 +257,7 @@ impl Default for NodeConfig { payment: PaymentConfig::default(), bootstrap_cache: BootstrapCacheConfig::default(), storage: StorageConfig::default(), + max_message_size: default_max_message_size(), log_level: default_log_level(), } } @@ -349,6 +359,10 @@ pub fn default_nodes_dir() -> PathBuf { default_root_dir().join(NODES_SUBDIR) } +fn default_max_message_size() -> usize { + crate::ant_protocol::MAX_WIRE_MESSAGE_SIZE +} + fn default_log_level() -> String { "info".to_string() } diff --git a/src/node.rs b/src/node.rs index d03b17f1..ca9dadb9 100644 --- a/src/node.rs +++ b/src/node.rs @@ -145,6 +145,9 @@ impl NodeBuilder { // Add bootstrap peers core_config.bootstrap_peers.clone_from(&config.bootstrap); + // Forward max_message_size to the transport layer. + core_config.max_message_size = Some(config.max_message_size); + // Propagate network-mode tuning into saorsa-core where supported. match config.network_mode { NetworkMode::Production => { diff --git a/tests/e2e/data_types/chunk.rs b/tests/e2e/data_types/chunk.rs index 76f4520b..b3acbe91 100644 --- a/tests/e2e/data_types/chunk.rs +++ b/tests/e2e/data_types/chunk.rs @@ -212,15 +212,16 @@ mod tests { // Cross-Node Tests (require P2P network) // ========================================================================= - /// Test 8: One node asks another to store a chunk via P2P. + /// Test 8: One node asks another to store a max-size chunk (4 MiB) via P2P. /// - /// This test validates the full cross-node protocol flow: + /// This test validates the full cross-node protocol flow with the largest + /// allowed payload, exercising QUIC stream flow-control limits: /// 1. Spins up a minimal 5-node local testnet /// 2. A regular node (node 3) discovers connected peers - /// 3. Picks a random peer and sends a `ChunkPutRequest` to it + /// 3. Picks a random peer and sends a `ChunkPutRequest` with a 4 MiB chunk /// 4. The target node stores the chunk and responds with success /// 5. The regular node then sends a `ChunkGetRequest` to retrieve it - /// 6. Verifies the data round-trips correctly + /// 6. Verifies the 4 MiB data round-trips correctly #[tokio::test(flavor = "multi_thread")] async fn test_chunk_store_on_remote_node() { let harness = TestHarness::setup_minimal() @@ -240,13 +241,14 @@ mod tests { let mut rng = rand::thread_rng(); let target_peer_id = peers.choose(&mut rng).expect("peers is non-empty"); + // Use the max-size (4 MiB) chunk to exercise QUIC stream limits let address = requester - .store_chunk_on_peer(target_peer_id, &fixture.small) + .store_chunk_on_peer(target_peer_id, &fixture.large) .await - .expect("Failed to store chunk on remote node"); + .expect("Failed to store max-size chunk on remote node"); // Verify the returned address matches the expected content hash - let expected_address = ChunkTestFixture::compute_address(&fixture.small); + let expected_address = ChunkTestFixture::compute_address(&fixture.large); assert_eq!( address, expected_address, "Returned address should match computed content address" @@ -256,12 +258,17 @@ mod tests { let retrieved = requester .get_chunk_from_peer(target_peer_id, &address) .await - .expect("Failed to retrieve chunk from remote node"); + .expect("Failed to retrieve max-size chunk from remote node"); - let chunk = retrieved.expect("Chunk should exist on remote storage node"); + let chunk = retrieved.expect("Max-size chunk should exist on remote storage node"); + assert_eq!( + chunk.content.len(), + fixture.large.len(), + "Retrieved chunk size should match original (4 MiB)" + ); assert_eq!( chunk.content.as_ref(), - fixture.small.as_slice(), + fixture.large.as_slice(), "Retrieved data should match original" ); assert_eq!( diff --git a/tests/e2e/testnet.rs b/tests/e2e/testnet.rs index 9cfb42b5..769e6eef 100644 --- a/tests/e2e/testnet.rs +++ b/tests/e2e/testnet.rs @@ -1003,6 +1003,9 @@ impl TestNetwork { core_config .bootstrap_peers .clone_from(&node.bootstrap_addrs); + // Override the transport-layer message size to accommodate max-size + // chunks (4 MiB payload + serialization overhead = 5 MiB wire). + core_config.max_message_size = Some(saorsa_node::ant_protocol::MAX_WIRE_MESSAGE_SIZE); // Create and start the P2P node let p2p_node = P2PNode::new(core_config).await.map_err(|e| {