From 6e4cb07e9be69c4a8883c9066c5c195ad461a9bb Mon Sep 17 00:00:00 2001 From: Warm Beer Date: Wed, 25 Mar 2026 10:52:32 +0100 Subject: [PATCH 1/3] feat!: replace saorsa-node dependency with ant-node 0.6 Migrate from the saorsa-node git dependency to the published ant-node 0.6 crate. Updates all imports, binary resolution constants, API call sites (new peer_addrs parameter), and comments/strings throughout. Co-Authored-By: Claude Opus 4.6 (1M context) --- Cargo.lock | 176 +++++++++++++++++------- ant-core/Cargo.toml | 4 +- ant-core/examples/start-local-devnet.rs | 6 +- ant-core/src/data/client/cache.rs | 2 +- ant-core/src/data/client/chunk.rs | 16 ++- ant-core/src/data/client/data.rs | 4 +- ant-core/src/data/client/file.rs | 9 +- ant-core/src/data/client/merkle.rs | 19 +-- ant-core/src/data/client/mod.rs | 14 +- ant-core/src/data/client/payment.rs | 10 +- ant-core/src/data/client/quote.rs | 11 +- ant-core/src/data/error.rs | 4 +- ant-core/src/data/mod.rs | 12 +- ant-core/src/data/network.rs | 8 +- ant-core/src/node/binary.rs | 10 +- ant-core/src/node/devnet.rs | 6 +- ant-core/tests/e2e_chunk.rs | 2 +- ant-core/tests/e2e_file.rs | 2 +- ant-core/tests/e2e_payment.rs | 2 +- ant-core/tests/e2e_security.rs | 8 +- ant-core/tests/support/mod.rs | 21 +-- ant-core/tests/unit_self_encrypt.rs | 2 +- 22 files changed, 213 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 501e537..9ae4e45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -849,6 +849,7 @@ version = "0.1.0" dependencies = [ "alloy", "ant-evm", + "ant-node", "anyhow", "async-stream", "axum", @@ -868,7 +869,6 @@ dependencies = [ "rand 0.8.5", "reqwest 0.12.28", "rmp-serde", - "saorsa-node", "saorsa-pqc 0.5.0", "self_encryption", "serde", @@ -921,6 +921,58 @@ dependencies = [ "sha2", ] +[[package]] +name = "ant-node" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b335e0d9258602b176fd94a3175d2b52094081b7cf246d01b0c6bb3ca781d7aa" +dependencies = [ + "aes-gcm-siv", + "ant-evm", + "blake3", + "bytes", + "chrono", + "clap", + "color-eyre", + "directories", + "evmlib", + "flate2", + "fs2", + "futures", + "heed", + "hex", + "hkdf", + "libp2p", + "lru", + "multihash", + "objc2", + "objc2-foundation", + "parking_lot", + "postcard", + "rand 0.8.5", + "reqwest 0.13.2", + "rmp-serde", + "saorsa-core", + "saorsa-pqc 0.5.0", + "self-replace", + "self_encryption", + "semver 1.0.27", + "serde", + "serde_json", + "sha2", + "tar", + "tempfile", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "toml", + "tracing", + "tracing-appender", + "tracing-subscriber", + "xor_name", + "zip", +] + [[package]] name = "anyhow" version = "1.0.102" @@ -1461,6 +1513,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" +dependencies = [ + "objc2", +] + [[package]] name = "blst" version = "0.3.16" @@ -2354,6 +2415,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "dispatch2" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" +dependencies = [ + "bitflags", + "objc2", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -4180,6 +4251,45 @@ dependencies = [ "smallvec", ] +[[package]] +name = "objc2" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a12a8ed07aefc768292f076dc3ac8c48f3781c8f2d5851dd3d98950e8c5a89f" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags", + "block2", + "libc", + "objc2", + "objc2-core-foundation", +] + [[package]] name = "object" version = "0.37.3" @@ -5374,9 +5484,9 @@ dependencies = [ [[package]] name = "saorsa-core" -version = "0.17.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fdd3338ffac1884d98a80db6741a448bfdc755fca3f20e0ddb37026eb16389" +checksum = "0d3d05b97f789b0e0b7d54b2fe05f05edfafb94f72d065482fc20ce1e9fab69e" dependencies = [ "anyhow", "async-trait", @@ -5402,51 +5512,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "saorsa-node" -version = "0.4.0" -source = "git+https://github.com/saorsa-labs/saorsa-node?branch=merkle_payments#01c54ba78997d2c2eea51e505fa725a02bbdd3a0" -dependencies = [ - "aes-gcm-siv", - "ant-evm", - "blake3", - "bytes", - "chrono", - "clap", - "color-eyre", - "directories", - "evmlib", - "flate2", - "futures", - "heed", - "hex", - "hkdf", - "libp2p", - "lru", - "multihash", - "parking_lot", - "postcard", - "rand 0.8.5", - "reqwest 0.13.2", - "rmp-serde", - "saorsa-core", - "saorsa-pqc 0.5.0", - "self_encryption", - "semver 1.0.27", - "serde", - "serde_json", - "tar", - "tempfile", - "thiserror 2.0.18", - "tokio", - "tokio-util", - "toml", - "tracing", - "tracing-appender", - "tracing-subscriber", - "xor_name", -] - [[package]] name = "saorsa-pqc" version = "0.4.2" @@ -5535,9 +5600,9 @@ dependencies = [ [[package]] name = "saorsa-transport" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10c184b50089077179857d41a78afcbf80eca790eedf34b022cae0ad51f64cf" +checksum = "9647e1797e760d73568fb6f7035f40945e70b789579bffccd6a5305e9d5d0136" dependencies = [ "anyhow", "async-trait", @@ -5704,6 +5769,17 @@ dependencies = [ "libc", ] +[[package]] +name = "self-replace" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03ec815b5eab420ab893f63393878d89c90fdd94c0bcc44c07abb8ad95552fb7" +dependencies = [ + "fastrand", + "tempfile", + "windows-sys 0.52.0", +] + [[package]] name = "self_encryption" version = "0.35.0" diff --git a/ant-core/Cargo.toml b/ant-core/Cargo.toml index da4c938..06071c7 100644 --- a/ant-core/Cargo.toml +++ b/ant-core/Cargo.toml @@ -22,7 +22,7 @@ utoipa = { version = "5", features = ["axum_extras"] } zip = "2" tower-http = { version = "0.6.8", features = ["cors"] } -# Data operations (from saorsa-client) +# Data operations ant-evm = "0.1.19" evmlib = "0.4.7" xor_name = "5" @@ -37,7 +37,7 @@ tracing = "0.1" bytes = "1" lru = "0.16" rand = "0.8" -saorsa-node = { git = "https://github.com/saorsa-labs/saorsa-node", branch = "merkle_payments" } +ant-node = "0.6" saorsa-pqc = "0.5" tracing-subscriber = { version = "0.3", features = ["env-filter"] } diff --git a/ant-core/examples/start-local-devnet.rs b/ant-core/examples/start-local-devnet.rs index b3bbbd0..5867e5d 100644 --- a/ant-core/examples/start-local-devnet.rs +++ b/ant-core/examples/start-local-devnet.rs @@ -1,7 +1,7 @@ //! Start a local devnet with EVM payments. //! -//! Launches a minimal Saorsa network (5 nodes) with an embedded Anvil -//! blockchain, writes a manifest to `/tmp/saorsa-devnet-manifest.json`, +//! Launches a minimal Autonomi network (5 nodes) with an embedded Anvil +//! blockchain, writes a manifest to `/tmp/ant-devnet-manifest.json`, //! and waits for Ctrl+C. //! //! # Usage @@ -27,7 +27,7 @@ async fn main() -> Result<(), Box> { let devnet = LocalDevnet::start_minimal().await?; // Write manifest so the CLI example can use it - let manifest_path = PathBuf::from("/tmp/saorsa-devnet-manifest.json"); + let manifest_path = PathBuf::from("/tmp/ant-devnet-manifest.json"); devnet.write_manifest(&manifest_path).await?; println!(); diff --git a/ant-core/src/data/client/cache.rs b/ant-core/src/data/client/cache.rs index d272a95..3e8957e 100644 --- a/ant-core/src/data/client/cache.rs +++ b/ant-core/src/data/client/cache.rs @@ -3,9 +3,9 @@ //! Caches recently fetched chunks in memory to avoid re-fetching //! the same content-addressed data from the network. +use ant_node::client::XorName; use bytes::Bytes; use lru::LruCache; -use saorsa_node::client::XorName; use std::num::NonZeroUsize; use std::sync::{Mutex, PoisonError}; diff --git a/ant-core/src/data/client/chunk.rs b/ant-core/src/data/client/chunk.rs index 90c803c..d64983e 100644 --- a/ant-core/src/data/client/chunk.rs +++ b/ant-core/src/data/client/chunk.rs @@ -5,13 +5,13 @@ use crate::data::client::Client; use crate::data::error::{Error, Result}; -use bytes::Bytes; -use saorsa_node::ant_protocol::{ +use ant_node::ant_protocol::{ ChunkGetRequest, ChunkGetResponse, ChunkMessage, ChunkMessageBody, ChunkPutRequest, ChunkPutResponse, }; -use saorsa_node::client::{compute_address, send_and_await_chunk_response, DataChunk, XorName}; -use saorsa_node::core::PeerId; +use ant_node::client::{compute_address, send_and_await_chunk_response, DataChunk, XorName}; +use ant_node::core::PeerId; +use bytes::Bytes; use std::time::Duration; use tracing::{debug, info}; @@ -19,7 +19,7 @@ use tracing::{debug, info}; const CHUNK_DATA_TYPE: u32 = 0; impl Client { - /// Store a chunk on the saorsa network with payment. + /// Store a chunk on the Autonomi network with payment. /// /// Checks if the chunk already exists before paying. If it does, /// returns the address immediately without incurring on-chain costs. @@ -52,7 +52,7 @@ impl Client { } } - /// Store a chunk on the saorsa network with a pre-built payment proof. + /// Store a chunk on the Autonomi network with a pre-built payment proof. /// /// `target_peer` must be one of the peers that was quoted during payment — /// sending the proof to a different peer will cause rejection because the @@ -90,6 +90,7 @@ impl Client { message_bytes, request_id, timeout, + &[], |body| match body { ChunkMessageBody::PutResponse(ChunkPutResponse::Success { address: addr }) => { info!("Chunk stored at {}", hex::encode(addr)); @@ -119,7 +120,7 @@ impl Client { .await } - /// Retrieve a chunk from the saorsa network. + /// Retrieve a chunk from the Autonomi network. /// /// Queries all peers in the close group for the chunk address, /// returning the first successful response. This handles the case @@ -195,6 +196,7 @@ impl Client { message_bytes, request_id, timeout, + &[], |body| match body { ChunkMessageBody::GetResponse(ChunkGetResponse::Success { address: addr, diff --git a/ant-core/src/data/client/data.rs b/ant-core/src/data/client/data.rs index 6ec2f83..b2cdf11 100644 --- a/ant-core/src/data/client/data.rs +++ b/ant-core/src/data/client/data.rs @@ -9,10 +9,10 @@ use crate::data::client::merkle::PaymentMode; use crate::data::client::Client; use crate::data::error::{Error, Result}; +use ant_node::ant_protocol::DATA_TYPE_CHUNK; +use ant_node::client::compute_address; use bytes::Bytes; use futures::stream::{self, StreamExt, TryStreamExt}; -use saorsa_node::ant_protocol::DATA_TYPE_CHUNK; -use saorsa_node::client::compute_address; use self_encryption::{decrypt, encrypt, DataMap, EncryptedChunk}; use tracing::{debug, info, warn}; diff --git a/ant-core/src/data/client/file.rs b/ant-core/src/data/client/file.rs index bfb30e7..0c138d2 100644 --- a/ant-core/src/data/client/file.rs +++ b/ant-core/src/data/client/file.rs @@ -8,11 +8,11 @@ use crate::data::client::merkle::PaymentMode; use crate::data::client::Client; use crate::data::error::{Error, Result}; +use ant_node::ant_protocol::DATA_TYPE_CHUNK; +use ant_node::client::compute_address; use bytes::Bytes; use futures::stream; use futures::StreamExt; -use saorsa_node::ant_protocol::DATA_TYPE_CHUNK; -use saorsa_node::client::compute_address; use self_encryption::{stream_encrypt, streaming_decrypt, DataMap}; use std::io::Write; use std::path::{Path, PathBuf}; @@ -358,10 +358,7 @@ impl Client { // Write decrypted chunks to a temp file, then rename atomically. let parent = output.parent().unwrap_or_else(|| Path::new(".")); let unique: u64 = rand::random(); - let tmp_path = parent.join(format!( - ".saorsa_download_{}_{unique}.tmp", - std::process::id() - )); + let tmp_path = parent.join(format!(".ant_download_{}_{unique}.tmp", std::process::id())); let write_result = (|| -> Result { let mut file = std::fs::File::create(&tmp_path)?; diff --git a/ant-core/src/data/client/merkle.rs b/ant-core/src/data/client/merkle.rs index 8794164..d49a3cb 100644 --- a/ant-core/src/data/client/merkle.rs +++ b/ant-core/src/data/client/merkle.rs @@ -1,4 +1,4 @@ -//! Merkle batch payment support for the saorsa client. +//! Merkle batch payment support for the Autonomi client. //! //! When uploading batches of 64+ chunks, merkle payments reduce gas costs //! by paying for the entire batch in a single on-chain transaction instead @@ -10,14 +10,14 @@ use ant_evm::merkle_payments::{ MerklePaymentCandidateNode, MerklePaymentCandidatePool, MerklePaymentProof, MerkleTree, MidpointProof, CANDIDATES_PER_POOL, MAX_LEAVES, }; -use evmlib::merkle_batch_payment::PoolCommitment; -use futures::stream::{FuturesUnordered, StreamExt}; -use saorsa_node::ant_protocol::{ +use ant_node::ant_protocol::{ ChunkMessage, ChunkMessageBody, MerkleCandidateQuoteRequest, MerkleCandidateQuoteResponse, }; -use saorsa_node::client::send_and_await_chunk_response; -use saorsa_node::payment::quote::verify_merkle_candidate_signature; -use saorsa_node::payment::serialize_merkle_proof; +use ant_node::client::send_and_await_chunk_response; +use ant_node::payment::quote::verify_merkle_candidate_signature; +use ant_node::payment::serialize_merkle_proof; +use evmlib::merkle_batch_payment::PoolCommitment; +use futures::stream::{FuturesUnordered, StreamExt}; use std::collections::HashMap; use std::time::Duration; use tracing::{debug, info, warn}; @@ -334,6 +334,7 @@ impl Client { message_bytes, request_id, timeout, + &[], |body| match body { ChunkMessageBody::MerkleCandidateQuoteResponse( MerkleCandidateQuoteResponse::Success { candidate_node }, @@ -387,7 +388,7 @@ impl Client { futures: &mut FuturesUnordered< impl std::future::Future< Output = ( - saorsa_node::core::PeerId, + ant_node::core::PeerId, std::result::Result, ), >, @@ -570,7 +571,7 @@ mod tests { use ant_evm::merkle_payments::MerklePaymentCandidateNode; use ant_evm::QuotingMetrics; use ant_evm::RewardsAddress; - use saorsa_node::payment::{deserialize_merkle_proof, serialize_merkle_proof}; + use ant_node::payment::{deserialize_merkle_proof, serialize_merkle_proof}; let addrs = make_test_addresses(4); let xornames: Vec = addrs.iter().map(|a| XorName(*a)).collect(); diff --git a/ant-core/src/data/client/mod.rs b/ant-core/src/data/client/mod.rs index ba5d00c..bc5c879 100644 --- a/ant-core/src/data/client/mod.rs +++ b/ant-core/src/data/client/mod.rs @@ -1,7 +1,7 @@ -//! Client operations for the saorsa network. +//! Client operations for the Autonomi network. //! //! Provides high-level APIs for storing and retrieving data -//! on the saorsa decentralized network. +//! on the Autonomi decentralized network. pub mod cache; pub mod chunk; @@ -14,14 +14,14 @@ pub mod quote; use crate::data::client::cache::ChunkCache; use crate::data::error::{Error, Result}; use crate::data::network::Network; +use ant_node::client::XorName; +use ant_node::core::{P2PNode, PeerId}; use evmlib::wallet::Wallet; -use saorsa_node::client::XorName; -use saorsa_node::core::{P2PNode, PeerId}; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; use tracing::debug; -/// Configuration for the saorsa client. +/// Configuration for the Autonomi client. #[derive(Debug, Clone)] pub struct ClientConfig { /// Timeout for network operations in seconds. @@ -39,7 +39,7 @@ impl Default for ClientConfig { } } -/// Client for the saorsa decentralized network. +/// Client for the Autonomi decentralized network. /// /// Provides high-level APIs for storing and retrieving chunks /// and files on the network. @@ -75,7 +75,7 @@ impl Client { config: ClientConfig, ) -> Result { debug!( - "Connecting to saorsa network with {} bootstrap peers", + "Connecting to Autonomi network with {} bootstrap peers", bootstrap_peers.len() ); let network = Network::new(bootstrap_peers).await?; diff --git a/ant-core/src/data/client/payment.rs b/ant-core/src/data/client/payment.rs index f9f85c6..6704373 100644 --- a/ant-core/src/data/client/payment.rs +++ b/ant-core/src/data/client/payment.rs @@ -1,4 +1,4 @@ -//! Payment orchestration for the saorsa client. +//! Payment orchestration for the Autonomi client. //! //! Connects quote collection, on-chain EVM payment, and proof serialization. //! Every PUT to the network requires a valid payment proof. @@ -6,10 +6,10 @@ use crate::data::client::Client; use crate::data::error::{Error, Result}; use ant_evm::{EncodedPeerId, ProofOfPayment}; +use ant_node::client::hex_node_id_to_encoded_peer_id; +use ant_node::core::PeerId; +use ant_node::payment::{serialize_single_node_proof, PaymentProof, SingleNodePayment}; use evmlib::wallet::Wallet; -use saorsa_node::client::hex_node_id_to_encoded_peer_id; -use saorsa_node::core::PeerId; -use saorsa_node::payment::{serialize_single_node_proof, PaymentProof, SingleNodePayment}; use std::sync::Arc; use tracing::{debug, info}; @@ -154,7 +154,7 @@ impl Client { } } -/// Convert a saorsa-core `PeerId` to an `EncodedPeerId` for payment proofs. +/// Convert an ant-node `PeerId` to an `EncodedPeerId` for payment proofs. fn peer_id_to_encoded(peer_id: &PeerId) -> Result { hex_node_id_to_encoded_peer_id(&peer_id.to_hex()) .map_err(|e| Error::Payment(format!("Failed to encode peer ID: {e}"))) diff --git a/ant-core/src/data/client/quote.rs b/ant-core/src/data/client/quote.rs index 78ae2b9..eb66215 100644 --- a/ant-core/src/data/client/quote.rs +++ b/ant-core/src/data/client/quote.rs @@ -6,13 +6,13 @@ use crate::data::client::Client; use crate::data::error::{Error, Result}; use ant_evm::{Amount, PaymentQuote}; -use futures::stream::{FuturesUnordered, StreamExt}; -use saorsa_node::ant_protocol::{ +use ant_node::ant_protocol::{ ChunkMessage, ChunkMessageBody, ChunkQuoteRequest, ChunkQuoteResponse, }; -use saorsa_node::client::send_and_await_chunk_response; -use saorsa_node::core::PeerId; -use saorsa_node::payment::{calculate_price, single_node::REQUIRED_QUOTES}; +use ant_node::client::send_and_await_chunk_response; +use ant_node::core::PeerId; +use ant_node::payment::{calculate_price, single_node::REQUIRED_QUOTES}; +use futures::stream::{FuturesUnordered, StreamExt}; use std::time::Duration; use tracing::{debug, info, warn}; @@ -84,6 +84,7 @@ impl Client { message_bytes, request_id, timeout, + &[], |body| match body { ChunkMessageBody::QuoteResponse(ChunkQuoteResponse::Success { quote, diff --git a/ant-core/src/data/error.rs b/ant-core/src/data/error.rs index 9e2f83b..e637ecb 100644 --- a/ant-core/src/data/error.rs +++ b/ant-core/src/data/error.rs @@ -65,8 +65,8 @@ pub enum Error { AlreadyStored, } -impl From for Error { - fn from(e: saorsa_node::Error) -> Self { +impl From for Error { + fn from(e: ant_node::Error) -> Self { Self::Network(e.to_string()) } } diff --git a/ant-core/src/data/mod.rs b/ant-core/src/data/mod.rs index 3b43ec9..c8f7c9c 100644 --- a/ant-core/src/data/mod.rs +++ b/ant-core/src/data/mod.rs @@ -1,4 +1,4 @@ -//! Data operations for the saorsa decentralized network. +//! Data operations for the Autonomi decentralized network. //! //! Provides high-level APIs for storing and retrieving data //! using post-quantum cryptography. @@ -15,8 +15,8 @@ pub use network::Network; // Re-export LocalDevnet from its new home in the node module pub use crate::node::devnet::LocalDevnet; -// Re-export commonly used types from saorsa-node -pub use saorsa_node::client::{compute_address, DataChunk, XorName}; +// Re-export commonly used types from ant-node +pub use ant_node::client::{compute_address, DataChunk, XorName}; // Re-export client data types pub use client::data::DataUploadResult; @@ -27,9 +27,9 @@ pub use client::merkle::{MerkleBatchPaymentResult, PaymentMode, DEFAULT_MERKLE_T pub use self_encryption::DataMap; // Re-export networking types needed by CLI for P2P node creation -pub use saorsa_node::ant_protocol::{MAX_CHUNK_SIZE, MAX_WIRE_MESSAGE_SIZE}; -pub use saorsa_node::core::{CoreNodeConfig, MultiAddr, NodeMode, P2PNode}; -pub use saorsa_node::devnet::DevnetManifest; +pub use ant_node::ant_protocol::{MAX_CHUNK_SIZE, MAX_WIRE_MESSAGE_SIZE}; +pub use ant_node::core::{CoreNodeConfig, MultiAddr, NodeMode, P2PNode}; +pub use ant_node::devnet::DevnetManifest; // Re-export EVM types needed by CLI for wallet and network setup pub use evmlib::common::{Address as EvmAddress, U256}; diff --git a/ant-core/src/data/network.rs b/ant-core/src/data/network.rs index 049fc46..6ddca7d 100644 --- a/ant-core/src/data/network.rs +++ b/ant-core/src/data/network.rs @@ -1,15 +1,15 @@ -//! Network layer wrapping saorsa-core's P2P node. +//! Network layer wrapping ant-node's P2P node. //! //! Provides peer discovery, message sending, and DHT operations //! for the client library. use crate::data::error::{Error, Result}; -use saorsa_node::ant_protocol::MAX_WIRE_MESSAGE_SIZE; -use saorsa_node::core::{CoreNodeConfig, MultiAddr, NodeMode, P2PNode, PeerId}; +use ant_node::ant_protocol::MAX_WIRE_MESSAGE_SIZE; +use ant_node::core::{CoreNodeConfig, MultiAddr, NodeMode, P2PNode, PeerId}; use std::net::SocketAddr; use std::sync::Arc; -/// Network abstraction for the saorsa client. +/// Network abstraction for the Autonomi client. /// /// Wraps a `P2PNode` providing high-level operations for /// peer discovery and message routing. diff --git a/ant-core/src/node/binary.rs b/ant-core/src/node/binary.rs index cfd0708..a0db0e9 100644 --- a/ant-core/src/node/binary.rs +++ b/ant-core/src/node/binary.rs @@ -5,8 +5,8 @@ use futures_util::StreamExt; use crate::error::{Error, Result}; use crate::node::types::BinarySource; -const GITHUB_REPO: &str = "saorsa-labs/saorsa-node"; -pub const BINARY_NAME: &str = "saorsa-node"; +const GITHUB_REPO: &str = "WithAutonomi/ant-node"; +pub const BINARY_NAME: &str = "ant-node"; /// Trait for reporting progress during long-running operations like binary downloads. pub trait ProgressReporter: Send + Sync { @@ -323,7 +323,7 @@ async fn extract_version(binary_path: &Path) -> Result { } let stdout = String::from_utf8_lossy(&output.stdout); - // Expect output like "saorsa-node 0.3.4" — extract the version part. + // Expect output like "ant-node 0.3.4" — extract the version part. let version = stdout .split_whitespace() .last() @@ -365,7 +365,7 @@ fn platform_asset_name() -> Result { "tar.gz" }; - Ok(format!("saorsa-node-cli-{os}-{arch}.{ext}")) + Ok(format!("ant-node-cli-{os}-{arch}.{ext}")) } /// Returns the directory where downloaded binaries are cached. @@ -393,7 +393,7 @@ mod tests { #[test] fn platform_asset_name_has_correct_format() { let name = platform_asset_name().unwrap(); - assert!(name.starts_with("saorsa-node-cli-")); + assert!(name.starts_with("ant-node-cli-")); assert!( name.ends_with(".tar.gz") || name.ends_with(".zip"), "unexpected extension: {name}" diff --git a/ant-core/src/node/devnet.rs b/ant-core/src/node/devnet.rs index 28a69dc..1286dea 100644 --- a/ant-core/src/node/devnet.rs +++ b/ant-core/src/node/devnet.rs @@ -1,16 +1,16 @@ //! Local devnet launcher for development and testing. //! -//! Wraps `saorsa_node::devnet::Devnet` and `evmlib::testnet::Testnet` (Anvil) +//! Wraps [`ant_node::devnet::Devnet`] and `evmlib::testnet::Testnet` (Anvil) //! to spin up a local network with EVM payments in a few lines of code. use crate::data::client::ClientConfig; use crate::data::error::{Error, Result}; use crate::data::Client; +use ant_node::core::MultiAddr; +use ant_node::devnet::{Devnet, DevnetConfig, DevnetEvmInfo, DevnetManifest}; use evmlib::testnet::Testnet; use evmlib::wallet::Wallet; use evmlib::Network as EvmNetwork; -use saorsa_node::core::MultiAddr; -use saorsa_node::devnet::{Devnet, DevnetConfig, DevnetEvmInfo, DevnetManifest}; use std::path::Path; use std::time::SystemTime; use tracing::info; diff --git a/ant-core/tests/e2e_chunk.rs b/ant-core/tests/e2e_chunk.rs index 3dcb755..57a1c3e 100644 --- a/ant-core/tests/e2e_chunk.rs +++ b/ant-core/tests/e2e_chunk.rs @@ -30,7 +30,7 @@ async fn setup() -> (Client, MiniTestnet) { async fn test_chunk_put_get_round_trip() { let (client, testnet) = setup().await; - let content = Bytes::from("saorsa-client chunk e2e test payload"); + let content = Bytes::from("ant-core chunk e2e test payload"); let address = client .chunk_put(content.clone()) .await diff --git a/ant-core/tests/e2e_file.rs b/ant-core/tests/e2e_file.rs index ae244dd..7016a45 100644 --- a/ant-core/tests/e2e_file.rs +++ b/ant-core/tests/e2e_file.rs @@ -105,7 +105,7 @@ async fn test_file_large_content() { async fn test_file_upload_nonexistent_path_fails() { let (client, testnet) = setup().await; - let nonexistent = PathBuf::from("/tmp/saorsa_test_nonexistent_file_12345.bin"); + let nonexistent = PathBuf::from("/tmp/ant_test_nonexistent_file_12345.bin"); let result = client.file_upload(&nonexistent).await; assert!( result.is_err(), diff --git a/ant-core/tests/e2e_payment.rs b/ant-core/tests/e2e_payment.rs index 61d30ba..2756e30 100644 --- a/ant-core/tests/e2e_payment.rs +++ b/ant-core/tests/e2e_payment.rs @@ -1,4 +1,4 @@ -//! Payment flow E2E tests for saorsa-client. +//! Payment flow E2E tests for ant-core. //! //! Tests legitimate payment flows: paid chunk storage, concurrent uploads, //! payment enforcement, large chunks, idempotency, and quote collection. diff --git a/ant-core/tests/e2e_security.rs b/ant-core/tests/e2e_security.rs index 7b0dbc5..daf19c0 100644 --- a/ant-core/tests/e2e_security.rs +++ b/ant-core/tests/e2e_security.rs @@ -1,4 +1,4 @@ -//! Security attack tests for saorsa-client. +//! Security attack tests for ant-core. //! //! Each test sets up a `MiniTestnet`, collects real quotes, tampers with the //! proof in a specific way, and asserts the attack is REJECTED by the network. @@ -9,11 +9,11 @@ mod support; use ant_core::data::{compute_address, Client, ClientConfig}; use ant_evm::ProofOfPayment; +use ant_node::client::hex_node_id_to_encoded_peer_id; +use ant_node::core::PeerId; +use ant_node::payment::{serialize_single_node_proof, PaymentProof, SingleNodePayment}; use bytes::Bytes; use evmlib::common::TxHash; -use saorsa_node::client::hex_node_id_to_encoded_peer_id; -use saorsa_node::core::PeerId; -use saorsa_node::payment::{serialize_single_node_proof, PaymentProof, SingleNodePayment}; use serial_test::serial; use std::sync::Arc; use support::MiniTestnet; diff --git a/ant-core/tests/support/mod.rs b/ant-core/tests/support/mod.rs index d4a140e..52aa965 100644 --- a/ant-core/tests/support/mod.rs +++ b/ant-core/tests/support/mod.rs @@ -1,4 +1,4 @@ -//! Minimal test infrastructure for saorsa-client E2E tests. +//! Minimal test infrastructure for ant-core E2E tests. //! //! Spawns a small local testnet with `AntProtocol` handlers and an Anvil //! EVM testnet for real on-chain payment verification. @@ -16,19 +16,19 @@ )] use ant_evm::RewardsAddress; -use evmlib::testnet::Testnet; -use evmlib::wallet::Wallet; -use evmlib::Network as EvmNetwork; -use rand::Rng; -use saorsa_node::ant_protocol::MAX_WIRE_MESSAGE_SIZE; -use saorsa_node::core::{ +use ant_node::ant_protocol::MAX_WIRE_MESSAGE_SIZE; +use ant_node::core::{ CoreNodeConfig, IPDiversityConfig, MlDsa65, MultiAddr, NodeIdentity, P2PEvent, P2PNode, }; -use saorsa_node::payment::{ +use ant_node::payment::{ EvmVerifierConfig, PaymentVerifier, PaymentVerifierConfig, QuoteGenerator, QuotingMetricsTracker, }; -use saorsa_node::storage::{AntProtocol, LmdbStorage, LmdbStorageConfig}; +use ant_node::storage::{AntProtocol, LmdbStorage, LmdbStorageConfig}; +use evmlib::testnet::Testnet; +use evmlib::wallet::Wallet; +use evmlib::Network as EvmNetwork; +use rand::Rng; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; use std::time::Duration; @@ -289,7 +289,7 @@ impl MiniTestnet { let node = Arc::clone(&handler_node); let topic_clone = topic.clone(); tokio::spawn(async move { - let result = if topic_clone == saorsa_node::CHUNK_PROTOCOL_ID { + let result = if topic_clone == ant_node::CHUNK_PROTOCOL_ID { protocol.handle_message(&data).await } else { return; @@ -301,6 +301,7 @@ impl MiniTestnet { &source_peer, &topic_clone, response_bytes.to_vec(), + &[], ) .await { diff --git a/ant-core/tests/unit_self_encrypt.rs b/ant-core/tests/unit_self_encrypt.rs index 9252eb4..81033aa 100644 --- a/ant-core/tests/unit_self_encrypt.rs +++ b/ant-core/tests/unit_self_encrypt.rs @@ -1,7 +1,7 @@ //! Local self-encryption unit tests (no network required). //! //! These validate encryption correctness, `DataMap` integrity, and edge cases -//! using only in-memory chunk stores. Ported from saorsa-node's +//! using only in-memory chunk stores. Ported from ant-node's //! `src/client/self_encrypt.rs` tests. #![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)] From bcac656747f264e17740da4fec0b3b9ddcb20a3f Mon Sep 17 00:00:00 2001 From: Warm Beer Date: Wed, 25 Mar 2026 12:39:37 +0100 Subject: [PATCH 2/3] feat: propagate peer addresses through send_and_await_chunk_response Thread MultiAddr from DHT lookups through the entire request pipeline so send_and_await_chunk_response can establish faster connections. Network::find_closest_peers now returns (PeerId, Vec) instead of discarding the addresses from DHTNode. Co-Authored-By: Claude Opus 4.6 (1M context) --- ant-core/src/data/client/chunk.rs | 16 ++++++++------- ant-core/src/data/client/data.rs | 5 +++-- ant-core/src/data/client/file.rs | 5 +++-- ant-core/src/data/client/merkle.rs | 9 +++++---- ant-core/src/data/client/mod.rs | 8 ++++++-- ant-core/src/data/client/payment.rs | 21 +++++++++---------- ant-core/src/data/client/quote.rs | 15 +++++++------- ant-core/src/data/network.rs | 12 +++++++++-- ant-core/tests/e2e_chunk.rs | 8 ++++---- ant-core/tests/e2e_payment.rs | 8 ++++---- ant-core/tests/e2e_security.rs | 31 +++++++++++++++++------------ 11 files changed, 81 insertions(+), 57 deletions(-) diff --git a/ant-core/src/data/client/chunk.rs b/ant-core/src/data/client/chunk.rs index d64983e..02bc28f 100644 --- a/ant-core/src/data/client/chunk.rs +++ b/ant-core/src/data/client/chunk.rs @@ -10,7 +10,7 @@ use ant_node::ant_protocol::{ ChunkPutResponse, }; use ant_node::client::{compute_address, send_and_await_chunk_response, DataChunk, XorName}; -use ant_node::core::PeerId; +use ant_node::core::{MultiAddr, PeerId}; use bytes::Bytes; use std::time::Duration; use tracing::{debug, info}; @@ -37,8 +37,8 @@ impl Client { .pay_for_storage(&address, data_size, CHUNK_DATA_TYPE) .await { - Ok((proof, target_peer)) => { - self.chunk_put_with_proof(content, proof, &target_peer) + Ok((proof, target_peer, peer_addrs)) => { + self.chunk_put_with_proof(content, proof, &target_peer, &peer_addrs) .await } Err(Error::AlreadyStored) => { @@ -66,6 +66,7 @@ impl Client { content: Bytes, proof: Vec, target_peer: &PeerId, + peer_addrs: &[MultiAddr], ) -> Result { let address = compute_address(&content); let node = self.network().node(); @@ -90,7 +91,7 @@ impl Client { message_bytes, request_id, timeout, - &[], + peer_addrs, |body| match body { ChunkMessageBody::PutResponse(ChunkPutResponse::Success { address: addr }) => { info!("Chunk stored at {}", hex::encode(addr)); @@ -149,8 +150,8 @@ impl Client { let peers = self.close_group_peers(address).await?; let addr_hex = hex::encode(address); - for peer in &peers { - match self.chunk_get_from_peer(address, peer).await { + for (peer, addrs) in &peers { + match self.chunk_get_from_peer(address, peer, addrs).await { Ok(Some(chunk)) => { self.chunk_cache().put(chunk.address, chunk.content.clone()); return Ok(Some(chunk)); @@ -174,6 +175,7 @@ impl Client { &self, address: &XorName, peer: &PeerId, + peer_addrs: &[MultiAddr], ) -> Result> { let node = self.network().node(); let request_id = self.next_request_id(); @@ -196,7 +198,7 @@ impl Client { message_bytes, request_id, timeout, - &[], + peer_addrs, |body| match body { ChunkMessageBody::GetResponse(ChunkGetResponse::Success { address: addr, diff --git a/ant-core/src/data/client/data.rs b/ant-core/src/data/client/data.rs index b2cdf11..207b7a0 100644 --- a/ant-core/src/data/client/data.rs +++ b/ant-core/src/data/client/data.rs @@ -151,10 +151,11 @@ impl Client { )) })?; let peers = self.close_group_peers(addr).await?; - let target = peers.first().ok_or_else(|| { + let (target, addrs) = peers.first().ok_or_else(|| { Error::InsufficientPeers("no peers for chunk".to_string()) })?; - self.chunk_put_with_proof(content, proof, target).await + self.chunk_put_with_proof(content, proof, target, addrs) + .await } }, )) diff --git a/ant-core/src/data/client/file.rs b/ant-core/src/data/client/file.rs index 0c138d2..3341715 100644 --- a/ant-core/src/data/client/file.rs +++ b/ant-core/src/data/client/file.rs @@ -250,10 +250,11 @@ impl Client { )) })?; let peers = self.close_group_peers(addr).await?; - let target = peers.first().ok_or_else(|| { + let (target, addrs) = peers.first().ok_or_else(|| { Error::InsufficientPeers("no peers for chunk".to_string()) })?; - self.chunk_put_with_proof(content, proof, target).await + self.chunk_put_with_proof(content, proof, target, addrs) + .await } }, )) diff --git a/ant-core/src/data/client/merkle.rs b/ant-core/src/data/client/merkle.rs index d49a3cb..0d3958c 100644 --- a/ant-core/src/data/client/merkle.rs +++ b/ant-core/src/data/client/merkle.rs @@ -287,8 +287,8 @@ impl Client { if remote_peers.len() < CANDIDATES_PER_POOL { let connected = self.network().connected_peers().await; for peer in connected { - if !remote_peers.contains(&peer) { - remote_peers.push(peer); + if !remote_peers.iter().any(|(id, _)| *id == peer) { + remote_peers.push((peer, vec![])); } } } @@ -303,7 +303,7 @@ impl Client { let mut candidate_futures = FuturesUnordered::new(); - for peer_id in &remote_peers { + for (peer_id, peer_addrs) in &remote_peers { let request_id = self.next_request_id(); let request = MerkleCandidateQuoteRequest { address: *address, @@ -325,6 +325,7 @@ impl Client { }; let peer_id_clone = *peer_id; + let addrs_clone = peer_addrs.clone(); let node_clone = node.clone(); let fut = async move { @@ -334,7 +335,7 @@ impl Client { message_bytes, request_id, timeout, - &[], + &addrs_clone, |body| match body { ChunkMessageBody::MerkleCandidateQuoteResponse( MerkleCandidateQuoteResponse::Success { candidate_node }, diff --git a/ant-core/src/data/client/mod.rs b/ant-core/src/data/client/mod.rs index bc5c879..348d083 100644 --- a/ant-core/src/data/client/mod.rs +++ b/ant-core/src/data/client/mod.rs @@ -15,7 +15,7 @@ use crate::data::client::cache::ChunkCache; use crate::data::error::{Error, Result}; use crate::data::network::Network; use ant_node::client::XorName; -use ant_node::core::{P2PNode, PeerId}; +use ant_node::core::{MultiAddr, P2PNode, PeerId}; use evmlib::wallet::Wallet; use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::Arc; @@ -127,7 +127,11 @@ impl Client { /// Return all peers in the close group for a target address. /// /// Queries the DHT for the closest peers by XOR distance. - pub(crate) async fn close_group_peers(&self, target: &XorName) -> Result> { + /// Returns each peer paired with its known network addresses. + pub(crate) async fn close_group_peers( + &self, + target: &XorName, + ) -> Result)>> { let peers = self .network() .find_closest_peers(target, self.config().close_group_size) diff --git a/ant-core/src/data/client/payment.rs b/ant-core/src/data/client/payment.rs index 6704373..3a9e556 100644 --- a/ant-core/src/data/client/payment.rs +++ b/ant-core/src/data/client/payment.rs @@ -7,7 +7,7 @@ use crate::data::client::Client; use crate::data::error::{Error, Result}; use ant_evm::{EncodedPeerId, ProofOfPayment}; use ant_node::client::hex_node_id_to_encoded_peer_id; -use ant_node::core::PeerId; +use ant_node::core::{MultiAddr, PeerId}; use ant_node::payment::{serialize_single_node_proof, PaymentProof, SingleNodePayment}; use evmlib::wallet::Wallet; use std::sync::Arc; @@ -33,15 +33,16 @@ impl Client { /// /// Returns an error if the wallet is not set, quotes cannot be collected, /// on-chain payment fails, or serialization fails. - /// Returns `(proof_bytes, target_peer)`. The `target_peer` is the closest - /// peer from quote collection — callers **must** send the PUT to this peer - /// to avoid a mismatch between the paid quotes and the storage target. + /// Returns `(proof_bytes, target_peer, peer_addrs)`. The `target_peer` is + /// the closest peer from quote collection — callers **must** send the PUT + /// to this peer to avoid a mismatch between the paid quotes and the + /// storage target. `peer_addrs` are the target's known network addresses. pub async fn pay_for_storage( &self, address: &[u8; 32], data_size: u64, data_type: u32, - ) -> Result<(Vec, PeerId)> { + ) -> Result<(Vec, PeerId, Vec)> { let wallet = self.require_wallet()?; debug!("Collecting quotes for address {}", hex::encode(address)); @@ -51,9 +52,9 @@ impl Client { // Pin the closest peer from the quote set as the PUT target. // This peer was among the quoted set so the proof includes it. - let target_peer = quotes_with_peers + let (target_peer, target_addrs) = quotes_with_peers .first() - .map(|(peer_id, _, _)| *peer_id) + .map(|(peer_id, addrs, _, _)| (*peer_id, addrs.clone())) .ok_or_else(|| Error::InsufficientPeers("no quotes collected".to_string()))?; // 2. Fetch prices from the on-chain contract rather than using the @@ -62,7 +63,7 @@ impl Client { // using the same formula, so we must use matching prices. let metrics_batch: Vec<_> = quotes_with_peers .iter() - .map(|(_, quote, _)| quote.quoting_metrics.clone()) + .map(|(_, _, quote, _)| quote.quoting_metrics.clone()) .collect(); let contract_prices = @@ -84,7 +85,7 @@ impl Client { let mut peer_quotes = Vec::with_capacity(quotes_with_peers.len()); let mut quotes_for_payment = Vec::with_capacity(quotes_with_peers.len()); - for ((peer_id, quote, _local_price), contract_price) in + for ((peer_id, _addrs, quote, _local_price), contract_price) in quotes_with_peers.into_iter().zip(contract_prices) { let encoded = peer_id_to_encoded(&peer_id)?; @@ -118,7 +119,7 @@ impl Client { let proof_bytes = serialize_single_node_proof(&proof) .map_err(|e| Error::Serialization(format!("Failed to serialize payment proof: {e}")))?; - Ok((proof_bytes, target_peer)) + Ok((proof_bytes, target_peer, target_addrs)) } /// Approve the wallet to spend tokens on the payment vault contract. diff --git a/ant-core/src/data/client/quote.rs b/ant-core/src/data/client/quote.rs index eb66215..aefe292 100644 --- a/ant-core/src/data/client/quote.rs +++ b/ant-core/src/data/client/quote.rs @@ -10,7 +10,7 @@ use ant_node::ant_protocol::{ ChunkMessage, ChunkMessageBody, ChunkQuoteRequest, ChunkQuoteResponse, }; use ant_node::client::send_and_await_chunk_response; -use ant_node::core::PeerId; +use ant_node::core::{MultiAddr, PeerId}; use ant_node::payment::{calculate_price, single_node::REQUIRED_QUOTES}; use futures::stream::{FuturesUnordered, StreamExt}; use std::time::Duration; @@ -31,7 +31,7 @@ impl Client { address: &[u8; 32], data_size: u64, data_type: u32, - ) -> Result> { + ) -> Result, PaymentQuote, Amount)>> { let node = self.network().node(); debug!( @@ -54,7 +54,7 @@ impl Client { // Request quotes from all peers concurrently let mut quote_futures = FuturesUnordered::new(); - for peer_id in &remote_peers { + for (peer_id, peer_addrs) in &remote_peers { let request_id = self.next_request_id(); let request = ChunkQuoteRequest { address: *address, @@ -75,6 +75,7 @@ impl Client { }; let peer_id_clone = *peer_id; + let addrs_clone = peer_addrs.clone(); let node_clone = node.clone(); let quote_future = async move { @@ -84,7 +85,7 @@ impl Client { message_bytes, request_id, timeout, - &[], + &addrs_clone, |body| match body { ChunkMessageBody::QuoteResponse(ChunkQuoteResponse::Success { quote, @@ -119,7 +120,7 @@ impl Client { ) .await; - (peer_id_clone, result) + (peer_id_clone, addrs_clone, result) }; quote_futures.push(quote_future); @@ -130,10 +131,10 @@ impl Client { let mut already_stored_count = 0usize; let mut failures: Vec = Vec::new(); - while let Some((peer_id, quote_result)) = quote_futures.next().await { + while let Some((peer_id, addrs, quote_result)) = quote_futures.next().await { match quote_result { Ok((quote, price)) => { - quotes_with_peers.push((peer_id, quote, price)); + quotes_with_peers.push((peer_id, addrs, quote, price)); if quotes_with_peers.len() >= REQUIRED_QUOTES { break; } diff --git a/ant-core/src/data/network.rs b/ant-core/src/data/network.rs index 6ddca7d..f4979b8 100644 --- a/ant-core/src/data/network.rs +++ b/ant-core/src/data/network.rs @@ -71,10 +71,18 @@ impl Network { /// Find the closest peers to a target address. /// + /// Returns each peer paired with its known network addresses, enabling + /// callers to pass addresses to `send_and_await_chunk_response` for + /// faster connection establishment. + /// /// # Errors /// /// Returns an error if the DHT lookup fails. - pub async fn find_closest_peers(&self, target: &[u8; 32], count: usize) -> Result> { + pub async fn find_closest_peers( + &self, + target: &[u8; 32], + count: usize, + ) -> Result)>> { let local_peer_id = self.node.peer_id(); // Request one extra to account for filtering out our own peer ID @@ -89,7 +97,7 @@ impl Network { .into_iter() .filter(|n| n.peer_id != *local_peer_id) .take(count) - .map(|n| n.peer_id) + .map(|n| (n.peer_id, n.addresses)) .collect()) } diff --git a/ant-core/tests/e2e_chunk.rs b/ant-core/tests/e2e_chunk.rs index 57a1c3e..63fdc6e 100644 --- a/ant-core/tests/e2e_chunk.rs +++ b/ant-core/tests/e2e_chunk.rs @@ -136,7 +136,7 @@ async fn test_chunk_put_with_insufficient_proof_rejected() { // Send a too-short proof (not even valid msgpack) let insufficient_proof = vec![0x00; 16]; - let target_peer = client + let (target_peer, target_addrs) = client .network() .find_closest_peers(&address, 1) .await @@ -145,7 +145,7 @@ async fn test_chunk_put_with_insufficient_proof_rejected() { .next() .expect("should have at least one peer"); let result = client - .chunk_put_with_proof(content, insufficient_proof, &target_peer) + .chunk_put_with_proof(content, insufficient_proof, &target_peer, &target_addrs) .await; assert!( @@ -218,7 +218,7 @@ async fn test_chunk_put_with_invalid_proof_rejected() { let address = compute_address(&content); let invalid_proof = vec![0xDE, 0xAD, 0xBE, 0xEF]; - let target_peer = client + let (target_peer, target_addrs) = client .network() .find_closest_peers(&address, 1) .await @@ -227,7 +227,7 @@ async fn test_chunk_put_with_invalid_proof_rejected() { .next() .expect("should have at least one peer"); let result = client - .chunk_put_with_proof(content, invalid_proof, &target_peer) + .chunk_put_with_proof(content, invalid_proof, &target_peer, &target_addrs) .await; // The node should reject this — either a deserialization error or payment verification failure diff --git a/ant-core/tests/e2e_payment.rs b/ant-core/tests/e2e_payment.rs index 2756e30..d2173ff 100644 --- a/ant-core/tests/e2e_payment.rs +++ b/ant-core/tests/e2e_payment.rs @@ -130,7 +130,7 @@ async fn test_payment_required_enforcement() { let content = Bytes::from("payment enforcement test data"); let address = ant_core::data::compute_address(&content); let garbage_proof = vec![0xDE, 0xAD, 0xBE, 0xEF]; - let target_peer = client_with_wallet + let (target_peer, target_addrs) = client_with_wallet .network() .find_closest_peers(&address, 1) .await @@ -139,7 +139,7 @@ async fn test_payment_required_enforcement() { .next() .expect("should have at least one peer"); let unpaid_result = client_with_wallet - .chunk_put_with_proof(content.clone(), garbage_proof, &target_peer) + .chunk_put_with_proof(content.clone(), garbage_proof, &target_peer, &target_addrs) .await; assert!( @@ -271,7 +271,7 @@ async fn test_quote_collection() { ); // All prices should be > 0 - for (peer_id, _quote, price) in "es { + for (peer_id, _addrs, _quote, price) in "es { assert!( !price.is_zero(), "Quote price from peer {peer_id} should be > 0" @@ -279,7 +279,7 @@ async fn test_quote_collection() { } // All peer IDs should be unique - let unique_peers: std::collections::HashSet<_> = quotes.iter().map(|(p, _, _)| *p).collect(); + let unique_peers: std::collections::HashSet<_> = quotes.iter().map(|(p, _, _, _)| *p).collect(); assert_eq!( unique_peers.len(), quotes.len(), diff --git a/ant-core/tests/e2e_security.rs b/ant-core/tests/e2e_security.rs index daf19c0..8748c7b 100644 --- a/ant-core/tests/e2e_security.rs +++ b/ant-core/tests/e2e_security.rs @@ -49,7 +49,7 @@ async fn collect_and_pay(client: &Client, content: &Bytes) -> (PaymentProof, Vec // Build peer_quotes and payment let mut peer_quotes = Vec::with_capacity(quotes.len()); let mut quotes_for_payment = Vec::with_capacity(quotes.len()); - for (peer_id, quote, price) in quotes { + for (peer_id, _addrs, quote, price) in quotes { let encoded = hex_node_id_to_encoded_peer_id(&peer_id.to_hex()).expect("peer ID conversion"); peer_quotes.push((encoded, quote.clone())); @@ -98,7 +98,7 @@ async fn test_attack_forged_signature() { let tampered_bytes = rmp_serde::to_vec(&tampered_proof).expect("serialize tampered proof"); let result = client - .chunk_put_with_proof(content, tampered_bytes, &target_peer) + .chunk_put_with_proof(content, tampered_bytes, &target_peer, &[]) .await; assert!( @@ -124,7 +124,7 @@ async fn test_attack_wrong_chunk_address() { // Try to store chunk B using A's proof let content_b = Bytes::from("chunk B - the interloper"); let result = client - .chunk_put_with_proof(content_b, proof_bytes, &target_peer) + .chunk_put_with_proof(content_b, proof_bytes, &target_peer, &[]) .await; assert!( @@ -145,13 +145,18 @@ async fn test_attack_replay_different_chunk() { // Legitimately store chunk A let content_a = Bytes::from("replay attack - legitimate chunk A"); - let (proof_bytes_a, target_peer_a) = client + let (proof_bytes_a, target_peer_a, target_addrs_a) = client .pay_for_storage(&compute_address(&content_a), content_a.len() as u64, 0) .await .expect("payment for chunk A should succeed"); let addr_a = client - .chunk_put_with_proof(content_a, proof_bytes_a.clone(), &target_peer_a) + .chunk_put_with_proof( + content_a, + proof_bytes_a.clone(), + &target_peer_a, + &target_addrs_a, + ) .await .expect("storing chunk A should succeed"); @@ -162,7 +167,7 @@ async fn test_attack_replay_different_chunk() { // Try to store chunk B using A's proof let content_b = Bytes::from("replay attack - sneaky chunk B"); let result = client - .chunk_put_with_proof(content_b, proof_bytes_a, &target_peer_a) + .chunk_put_with_proof(content_b, proof_bytes_a, &target_peer_a, &target_addrs_a) .await; assert!( @@ -193,7 +198,7 @@ async fn test_attack_zero_amount_payment() { let target_peer = quotes.first().expect("should have quotes").0; let mut peer_quotes = Vec::with_capacity(quotes.len()); - for (peer_id, quote, _price) in quotes { + for (peer_id, _addrs, quote, _price) in quotes { let encoded = hex_node_id_to_encoded_peer_id(&peer_id.to_hex()).expect("peer ID conversion"); peer_quotes.push((encoded, quote)); @@ -207,7 +212,7 @@ async fn test_attack_zero_amount_payment() { let fake_bytes = rmp_serde::to_vec(&fake_proof).expect("serialize fake proof"); let result = client - .chunk_put_with_proof(content, fake_bytes, &target_peer) + .chunk_put_with_proof(content, fake_bytes, &target_peer, &[]) .await; assert!( @@ -238,7 +243,7 @@ async fn test_attack_fabricated_tx_hash() { let target_peer = quotes.first().expect("should have quotes").0; let mut peer_quotes = Vec::with_capacity(quotes.len()); - for (peer_id, quote, _price) in quotes { + for (peer_id, _addrs, quote, _price) in quotes { let encoded = hex_node_id_to_encoded_peer_id(&peer_id.to_hex()).expect("peer ID conversion"); peer_quotes.push((encoded, quote)); @@ -253,7 +258,7 @@ async fn test_attack_fabricated_tx_hash() { let fake_bytes = rmp_serde::to_vec(&fake_proof).expect("serialize fake proof"); let result = client - .chunk_put_with_proof(content, fake_bytes, &target_peer) + .chunk_put_with_proof(content, fake_bytes, &target_peer, &[]) .await; assert!( @@ -277,13 +282,13 @@ async fn test_attack_double_spend_same_proof() { // Store chunk A successfully let addr1 = client - .chunk_put_with_proof(content.clone(), proof_bytes.clone(), &target_peer) + .chunk_put_with_proof(content.clone(), proof_bytes.clone(), &target_peer, &[]) .await .expect("first PUT should succeed"); // Try to store the SAME chunk with the SAME proof again let addr2 = client - .chunk_put_with_proof(content, proof_bytes, &target_peer) + .chunk_put_with_proof(content, proof_bytes, &target_peer, &[]) .await .expect("second PUT (idempotent AlreadyExists) should succeed"); @@ -324,7 +329,7 @@ async fn test_attack_corrupted_public_key() { let tampered_bytes = rmp_serde::to_vec(&tampered_proof).expect("serialize tampered proof"); let result = client - .chunk_put_with_proof(content, tampered_bytes, &target_peer) + .chunk_put_with_proof(content, tampered_bytes, &target_peer, &[]) .await; assert!( From 48302bb4c837f2e936a28f86fd7d8fb3b62169e6 Mon Sep 17 00:00:00 2001 From: Warm Beer Date: Wed, 25 Mar 2026 13:48:32 +0100 Subject: [PATCH 3/3] refactor: update node request handling with try_handle_request Simplify handler logic by replacing handle_message with try_handle_request. Add explicit handling for non-request messages and improve error messaging. --- ant-core/tests/support/mod.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/ant-core/tests/support/mod.rs b/ant-core/tests/support/mod.rs index 52aa965..66b81ab 100644 --- a/ant-core/tests/support/mod.rs +++ b/ant-core/tests/support/mod.rs @@ -289,13 +289,11 @@ impl MiniTestnet { let node = Arc::clone(&handler_node); let topic_clone = topic.clone(); tokio::spawn(async move { - let result = if topic_clone == ant_node::CHUNK_PROTOCOL_ID { - protocol.handle_message(&data).await - } else { + if topic_clone != ant_node::CHUNK_PROTOCOL_ID { return; - }; - match result { - Ok(response_bytes) => { + } + match protocol.try_handle_request(&data).await { + Ok(Some(response_bytes)) => { if let Err(e) = node .send_message( &source_peer, @@ -308,9 +306,12 @@ impl MiniTestnet { eprintln!("ERROR: node {node_index} failed to send response to {source_peer}: {e}"); } } + Ok(None) => { + // Non-request message (e.g. response) — nothing to reply + } Err(e) => { eprintln!( - "ERROR: node {node_index} handle_message failed: {e}" + "ERROR: node {node_index} try_handle_request failed: {e}" ); } }