Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 2 additions & 9 deletions src/devnet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,21 +550,14 @@ impl Devnet {
};

let rewards_address = RewardsAddress::new(DEVNET_REWARDS_ADDRESS);
// Shared quoting metrics: generator prices from it, verifier reads the
// same live count for its F2/F5 price-floor defence.
let metrics_tracker = Arc::new(QuotingMetricsTracker::new(DEVNET_INITIAL_RECORDS));
let floor_metrics = Arc::clone(&metrics_tracker);
let payment_config = PaymentVerifierConfig {
evm: evm_config,
cache_capacity: DEVNET_PAYMENT_CACHE_CAPACITY,
local_rewards_address: rewards_address,
price_floor: Some(crate::payment::PriceFloorProvider::new(Arc::new(
move || crate::payment::calculate_price(floor_metrics.records_stored()),
))),
};
let payment_verifier = PaymentVerifier::new(payment_config);
let mut quote_generator =
QuoteGenerator::new(rewards_address, Arc::clone(&metrics_tracker));
let metrics_tracker = QuotingMetricsTracker::new(DEVNET_INITIAL_RECORDS);
let mut quote_generator = QuoteGenerator::new(rewards_address, metrics_tracker);

// Wire ML-DSA-65 signing from the devnet node's identity
crate::payment::wire_ml_dsa_signer(&mut quote_generator, identity)
Expand Down
37 changes: 3 additions & 34 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,49 +381,18 @@ impl NodeBuilder {
}
};

// Shared quoting metrics: the quote generator prices quotes from it,
// and the payment verifier reads the SAME live `records_stored` to
// enforce its price floor (F2/F5 defence).
//
// Hydrate `records_stored` from the LMDB row count on startup so the
// floor reflects this node's actual disk state immediately. Otherwise
// a restarted node would briefly accept proofs priced at baseline/4
// even though its real load (and therefore real quote price) is
// much higher — weakening the F2/F5 underpricing defence across
// restarts. `current_chunks` is a fast metadata read; on the rare
// case it fails we fall back to 0 and log (the recipient binding (d)
// still defeats pay-yourself unconditionally; this only affects the
// underpricing tolerance).
let initial_records = match storage.current_chunks() {
Ok(n) => usize::try_from(n).unwrap_or(usize::MAX),
Err(e) => {
warn!(
"Failed to read stored-chunk count for price floor hydration: {e}; \
starting at 0 (floor will rise as new PUTs land)"
);
0
}
};
let metrics_tracker = Arc::new(QuotingMetricsTracker::new(initial_records));

// Create payment verifier with a live price floor wired to the same
// metrics tracker, so an attacker cannot get this node to accept a
// self-signed, far-underpriced single-node proof.
// Create payment verifier
let evm_network = config.payment.evm_network.clone().into_evm_network();
let floor_metrics = Arc::clone(&metrics_tracker);
let payment_config = PaymentVerifierConfig {
evm: EvmVerifierConfig {
network: evm_network,
},
cache_capacity: config.payment.cache_capacity,
local_rewards_address: rewards_address,
price_floor: Some(crate::payment::PriceFloorProvider::new(Arc::new(
move || crate::payment::calculate_price(floor_metrics.records_stored()),
))),
};
let payment_verifier = PaymentVerifier::new(payment_config);
let mut quote_generator =
QuoteGenerator::new(rewards_address, Arc::clone(&metrics_tracker));
let metrics_tracker = QuotingMetricsTracker::new(0);
let mut quote_generator = QuoteGenerator::new(rewards_address, metrics_tracker);

// Wire ML-DSA-65 signing from node identity.
// This same signer is used for both regular quotes and merkle candidate quotes.
Expand Down
2 changes: 1 addition & 1 deletion src/payment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub use ant_protocol::payment::verify::{
};
pub use single_node::SingleNodePayment;
pub use verifier::{
EvmVerifierConfig, PaymentStatus, PaymentVerifier, PaymentVerifierConfig, PriceFloorProvider,
EvmVerifierConfig, PaymentStatus, PaymentVerifier, PaymentVerifierConfig,
MAX_PAYMENT_PROOF_SIZE_BYTES, MIN_PAYMENT_PROOF_SIZE_BYTES,
};
pub use wallet::{is_valid_address, parse_rewards_address, WalletConfig};
22 changes: 5 additions & 17 deletions src/payment/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use evmlib::RewardsAddress;
use saorsa_core::MlDsa65;
use saorsa_pqc::pqc::types::MlDsaSecretKey;
use saorsa_pqc::pqc::MlDsaOperations;
use std::sync::Arc;
use std::time::SystemTime;

/// Content address type (32-byte `XorName`).
Expand All @@ -33,10 +32,8 @@ pub type SignFn = Box<dyn Fn(&[u8]) -> Vec<u8> + Send + Sync>;
pub struct QuoteGenerator {
/// The rewards address for receiving payments.
rewards_address: RewardsAddress,
/// Metrics tracker for quoting. Shared (`Arc`) so the payment verifier's
/// price-floor defence (F2/F5) reads the exact same live `records_stored`
/// this generator prices quotes from.
metrics_tracker: Arc<QuotingMetricsTracker>,
/// Metrics tracker for quoting.
metrics_tracker: QuotingMetricsTracker,
/// Signing function provided by the node.
/// Takes bytes and returns a signature.
sign_fn: Option<SignFn>,
Expand All @@ -52,21 +49,12 @@ impl QuoteGenerator {
/// # Arguments
///
/// * `rewards_address` - The EVM address for receiving payments
/// * `metrics_tracker` - Shared tracker for quoting metrics (also read by
/// the payment verifier's price-floor defence)
///
/// Accepts either an owned `QuotingMetricsTracker` or a shared
/// `Arc<QuotingMetricsTracker>` (via `Into`), so production can share the
/// tracker with the verifier's price-floor defence while tests can keep
/// passing an owned tracker.
/// * `metrics_tracker` - Tracker for quoting metrics
#[must_use]
pub fn new(
rewards_address: RewardsAddress,
metrics_tracker: impl Into<Arc<QuotingMetricsTracker>>,
) -> Self {
pub fn new(rewards_address: RewardsAddress, metrics_tracker: QuotingMetricsTracker) -> Self {
Self {
rewards_address,
metrics_tracker: metrics_tracker.into(),
metrics_tracker,
sign_fn: None,
pub_key: Vec::new(),
}
Expand Down
Loading
Loading