Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: progress in quoting land #2498

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
24 changes: 0 additions & 24 deletions ant-networking/src/event/request_response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,30 +48,6 @@ impl SwarmDriver {

self.add_keys_to_replication_fetcher(holder, keys);
}
Request::Cmd(ant_protocol::messages::Cmd::QuoteVerification {
quotes,
..
}) => {
let response = Response::Cmd(
ant_protocol::messages::CmdResponse::QuoteVerification(Ok(())),
);
self.queue_network_swarm_cmd(NetworkSwarmCmd::SendResponse {
resp: response,
channel: MsgResponder::FromPeer(channel),
});

// The keypair is required to verify the quotes,
// hence throw it up to Network layer for further actions.
let quotes = quotes
.iter()
.filter_map(|(peer_address, quote)| {
peer_address
.as_peer_id()
.map(|peer_id| (peer_id, quote.clone()))
})
.collect();
self.send_event(NetworkEvent::QuoteVerification { quotes })
}
Request::Cmd(ant_protocol::messages::Cmd::PeerConsideredAsBad {
detected_by,
bad_peer,
Expand Down
36 changes: 18 additions & 18 deletions ant-networking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ use self::{cmd::NetworkSwarmCmd, error::Result};
use ant_evm::{PaymentQuote, QuotingMetrics};
use ant_protocol::{
error::Error as ProtocolError,
messages::{ChunkProof, Cmd, Nonce, Query, QueryResponse, Request, Response},
messages::{ChunkProof, Nonce, Query, QueryResponse, Request, Response},
storage::{RecordType, RetryStrategy, Scratchpad},
NetworkAddress, PrettyPrintKBucketKey, PrettyPrintRecordKey, CLOSE_GROUP_SIZE,
};
Expand Down Expand Up @@ -83,8 +83,10 @@ use {
std::collections::HashSet,
};

/// The type of quote for a selected payee.
pub type PayeeQuote = (PeerId, PaymentQuote);
/// Selected quotes to pay for a data address
pub struct SelectedQuotes {
pub quotes: Vec<(PeerId, PaymentQuote)>,
}

/// Majority of a given group (i.e. > 1/2).
#[inline]
Expand Down Expand Up @@ -382,7 +384,7 @@ impl Network {
&self,
record_address: NetworkAddress,
ignore_peers: Vec<PeerId>,
) -> Result<Vec<PayeeQuote>> {
) -> Result<SelectedQuotes> {
// The requirement of having at least CLOSE_GROUP_SIZE
// close nodes will be checked internally automatically.
let mut close_nodes = self
Expand All @@ -392,7 +394,7 @@ impl Network {
close_nodes.retain(|peer_id| !ignore_peers.contains(peer_id));

if close_nodes.is_empty() {
error!("Cann't get store_cost of {record_address:?}, as all close_nodes are ignored");
error!("Can't get store_cost of {record_address:?}, as all close_nodes are ignored");
return Err(NetworkError::NoStoreCostResponses);
}

Expand All @@ -406,6 +408,10 @@ impl Network {
.send_and_get_responses(&close_nodes, &request, true)
.await;

// consider data to be already paid for if 1/3 of the close nodes already have it
let mut peer_already_have_it = 0;
let enough_peers_already_have_it = close_nodes.len() / 3;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to avoid malicious attacke, better at least have 2 holders.
for close_nodes.len() = 5, enough_peers_already_have_it will have a value of 1, which is somehow vulunerable.
maybe make it std::cmp::max(2, close_nodes.len()/3) or close_nodes.len() / 2 instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense let's go with: close_nodes.len() / 2


// loop over responses
let mut all_quotes = vec![];
let mut quotes_to_pay = vec![];
Expand Down Expand Up @@ -438,8 +444,12 @@ impl Network {
if !storage_proofs.is_empty() {
debug!("Storage proofing during GetStoreQuote to be implemented.");
}
info!("Address {record_address:?} was already paid for according to {peer_address:?}, ending quote request");
return Ok(vec![]);
peer_already_have_it += 1;
info!("Address {record_address:?} was already paid for according to {peer_address:?} ({peer_already_have_it}/{enough_peers_already_have_it})");
if peer_already_have_it >= enough_peers_already_have_it {
info!("Address {record_address:?} was already paid for according to {peer_already_have_it} peers, ending quote request");
return Ok(SelectedQuotes { quotes: vec![] });
}
}
Err(err) => {
error!("Got an error while requesting quote from peer {peer:?}: {err}");
Expand All @@ -450,17 +460,7 @@ impl Network {
}
}

// send the quotes to the other peers for verification
for peer_id in close_nodes.iter() {
let request = Request::Cmd(Cmd::QuoteVerification {
target: NetworkAddress::from_peer(*peer_id),
quotes: all_quotes.clone(),
});

self.send_req_ignore_reply(request, *peer_id);
}

Ok(quotes_to_pay)
Ok(SelectedQuotes { quotes: quotes_to_pay })
}

/// Get register from network.
Expand Down
14 changes: 10 additions & 4 deletions ant-node/src/put_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use ant_protocol::{
};
use ant_registers::SignedRegister;
use libp2p::kad::{Record, RecordKey};
use std::time::{Duration, UNIX_EPOCH};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use xor_name::XorName;

impl Node {
Expand Down Expand Up @@ -614,24 +614,30 @@ impl Node {
// verify quote timestamp
let quote_timestamp = payment.quote.timestamp;
let quote_expiration_time = quote_timestamp + Duration::from_secs(QUOTE_EXPIRATION_SECS);
let quote_expiration_time_in_secs = quote_expiration_time
let _quote_expiration_time_in_secs = quote_expiration_time
.duration_since(UNIX_EPOCH)
.map_err(|e| {
Error::InvalidRequest(format!(
"Payment quote timestamp is invalid for record {pretty_key}: {e}"
))
})?
.as_secs();
// NB TODO @mick: can we check if the quote has expired with block time in evmlib? Or should nodes do it manually here? Else keep the block below
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the quote was made by the node, not related to the block time, hence have to do it manually ?
unless node using block time on quote, which requires an extra query to the block?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't really couple a transaction to a quote anymore since we no longer use the transaction's event logs to verify payments. So we'd have to do it manually.

// manually check if the quote has expired
if quote_expiration_time < SystemTime::now() {
warn!("Payment quote has expired for record {pretty_key}");
return Err(Error::InvalidRequest(format!(
"Payment quote has expired for record {pretty_key}"
)));
}

// check if payment is valid on chain
debug!("Verifying payment for record {pretty_key}");
let reward_amount = self.evm_network()
.verify_data_payment(
payment.tx_hash,
payment.quote.hash(),
payment.quote.quoting_metrics,
*self.reward_address(),
quote_expiration_time_in_secs,
)
.await
.map_err(|e| Error::EvmNetwork(format!("Failed to verify chunk payment: {e}")))?;
Expand Down
19 changes: 0 additions & 19 deletions ant-protocol/src/messages/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
#![allow(clippy::mutable_key_type)] // for Bytes in NetworkAddress

use crate::{storage::RecordType, NetworkAddress};
pub use ant_evm::PaymentQuote;
use serde::{Deserialize, Serialize};

/// Data and CashNote cmds - recording transactions or creating, updating, and removing data.
Expand All @@ -28,11 +27,6 @@ pub enum Cmd {
/// Keys of copy that shall be replicated.
keys: Vec<(NetworkAddress, RecordType)>,
},
/// Write operation to notify nodes a list of PaymentQuote collected.
QuoteVerification {
target: NetworkAddress,
quotes: Vec<(NetworkAddress, PaymentQuote)>,
},
/// Notify the peer it is now being considered as BAD due to the included behaviour
PeerConsideredAsBad {
detected_by: NetworkAddress,
Expand All @@ -52,11 +46,6 @@ impl std::fmt::Debug for Cmd {
.field("first_ten_keys", &first_ten_keys)
.finish()
}
Cmd::QuoteVerification { target, quotes } => f
.debug_struct("Cmd::QuoteVerification")
.field("target", target)
.field("quotes_len", &quotes.len())
.finish(),
Cmd::PeerConsideredAsBad {
detected_by,
bad_peer,
Expand All @@ -76,7 +65,6 @@ impl Cmd {
pub fn dst(&self) -> NetworkAddress {
match self {
Cmd::Replicate { holder, .. } => holder.clone(),
Cmd::QuoteVerification { target, .. } => target.clone(),
Cmd::PeerConsideredAsBad { bad_peer, .. } => bad_peer.clone(),
}
}
Expand All @@ -93,13 +81,6 @@ impl std::fmt::Display for Cmd {
keys.len()
)
}
Cmd::QuoteVerification { target, quotes } => {
write!(
f,
"Cmd::QuoteVerification(sent to {target:?} has {} quotes)",
quotes.len()
)
}
Cmd::PeerConsideredAsBad {
detected_by,
bad_peer,
Expand Down
5 changes: 0 additions & 5 deletions ant-protocol/src/messages/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,6 @@ pub enum CmdResponse {
/// Response to replication cmd
Replicate(Result<()>),
//
// ===== QuoteVerification =====
//
/// Response to quote verification cmd
QuoteVerification(Result<()>),
//
// ===== PeerConsideredAsBad =====
//
/// Response to the considered as bad notification
Expand Down
8 changes: 4 additions & 4 deletions autonomi/src/client/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

use ant_evm::{PaymentQuote, ProofOfPayment, QuoteHash, TxHash};
use ant_evm::{Amount, AttoTokens, QuotePayment};
use ant_networking::{Network, NetworkError, PayeeQuote};
use ant_networking::{Network, NetworkError, SelectedQuotes};
use ant_protocol::{
storage::ChunkAddress,
NetworkAddress,
Expand All @@ -21,7 +21,7 @@ use super::{data::CostError, Client};

pub struct QuotesToPay {
pub nodes_to_pay: Vec<QuotePayment>,
pub nodes_to_upload_to: Vec<PayeeQuote>,
pub nodes_to_upload_to: Vec<SelectedQuotes>,
pub cost_per_node: AttoTokens,
pub total_cost: AttoTokens,
}
Expand Down Expand Up @@ -66,7 +66,7 @@ impl Client {
async fn fetch_store_quote(
network: &Network,
content_addr: XorName,
) -> Result<Vec<PayeeQuote>, NetworkError> {
) -> Result<Vec<SelectedQuotes>, NetworkError> {
network
.get_store_quote_from_network(
NetworkAddress::from_chunk_address(ChunkAddress::new(content_addr)),
Expand All @@ -79,7 +79,7 @@ async fn fetch_store_quote(
async fn fetch_store_quote_with_retries(
network: &Network,
content_addr: XorName,
) -> Result<(XorName, Vec<PayeeQuote>), CostError> {
) -> Result<(XorName, Vec<SelectedQuotes>), CostError> {
let mut retries = 0;

loop {
Expand Down
12 changes: 6 additions & 6 deletions autonomi/src/client/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
use crate::client::payment::Receipt;
use ant_evm::{EvmWallet, ProofOfPayment, QuotePayment};
use ant_networking::{
GetRecordCfg, Network, NetworkError, PayeeQuote, PutRecordCfg, VerificationKind,
GetRecordCfg, Network, NetworkError, SelectedQuotes, PutRecordCfg, VerificationKind,
};
use ant_protocol::{
messages::ChunkProof,
Expand Down Expand Up @@ -197,23 +197,23 @@ impl Client {
pub(crate) async fn get_store_quotes(
&self,
content_addrs: impl Iterator<Item = XorName>,
) -> Result<HashMap<XorName, PayeeQuote>, CostError> {
) -> Result<HashMap<XorName, SelectedQuotes>, CostError> {
let futures: Vec<_> = content_addrs
.into_iter()
.map(|content_addr| fetch_store_quote_with_retries(&self.network, content_addr))
.collect();

let quotes = futures::future::try_join_all(futures).await?;

Ok(quotes.into_iter().collect::<HashMap<XorName, PayeeQuote>>())
Ok(quotes.into_iter().collect::<HashMap<XorName, SelectedQuotes>>())
}
}

/// Fetch a store quote for a content address with a retry strategy.
async fn fetch_store_quote_with_retries(
network: &Network,
content_addr: XorName,
) -> Result<(XorName, PayeeQuote), CostError> {
) -> Result<(XorName, SelectedQuotes), CostError> {
let mut retries = 0;

loop {
Expand All @@ -239,7 +239,7 @@ async fn fetch_store_quote_with_retries(
async fn fetch_store_quote(
network: &Network,
content_addr: XorName,
) -> Result<PayeeQuote, NetworkError> {
) -> Result<SelectedQuotes, NetworkError> {
network
.get_store_costs_from_network(
NetworkAddress::from_chunk_address(ChunkAddress::new(content_addr)),
Expand All @@ -250,7 +250,7 @@ async fn fetch_store_quote(

/// Form to be executed payments and already executed payments from a cost map.
pub(crate) fn extract_quote_payments(
cost_map: &HashMap<XorName, PayeeQuote>,
cost_map: &HashMap<XorName, SelectedQuotes>,
) -> (Vec<QuotePayment>, Vec<XorName>) {
let mut to_be_paid = vec![];
let mut already_paid = vec![];
Expand Down
8 changes: 4 additions & 4 deletions autonomi/src/utils.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use crate::client::payment::Receipt;
use ant_evm::{PaymentQuote, ProofOfPayment, QuoteHash, TxHash};
use ant_networking::PayeeQuote;
use ant_networking::SelectedQuotes;
use std::collections::{BTreeMap, HashMap};
use xor_name::XorName;

pub fn cost_map_to_quotes(
cost_map: HashMap<XorName, PayeeQuote>,
cost_map: HashMap<XorName, SelectedQuotes>,
) -> HashMap<XorName, PaymentQuote> {
cost_map.into_iter().map(|(k, (_, _, v))| (k, v)).collect()
cost_map.into_iter().map(|(k, (_, q))| (k, q)).collect()
}

pub fn receipt_from_cost_map_and_payments(
cost_map: HashMap<XorName, PayeeQuote>,
cost_map: HashMap<XorName, SelectedQuotes>,
payments: &BTreeMap<QuoteHash, TxHash>,
) -> Receipt {
let quotes = cost_map_to_quotes(cost_map);
Expand Down
12 changes: 7 additions & 5 deletions evmlib/src/external_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
// permissions and limitations relating to use of the SAFE Network Software.

use crate::common::{Address, Amount, Calldata, QuoteHash, QuotePayment, U256};
use crate::contract::data_payments::{DataPaymentsHandler, MAX_TRANSFERS_PER_TRANSACTION};
use crate::contract::network_token::NetworkToken;
use crate::contract::{data_payments, network_token};
use crate::contract::network_token::{NetworkToken, self};
use crate::contract::payment_vault::MAX_TRANSFERS_PER_TRANSACTION;
use crate::utils::http_provider;
use crate::Network;
use serde::{Deserialize, Serialize};
Expand All @@ -20,7 +19,7 @@ pub enum Error {
#[error("Network token contract error: {0}")]
NetworkTokenContract(#[from] network_token::Error),
#[error("Data payments contract error: {0}")]
DataPaymentsContract(#[from] data_payments::error::Error),
DataPaymentsContract(#[from] crate::contract::payment_vault::error::Error),
}

/// Approve an address / smart contract to spend this wallet's payment tokens.
Expand Down Expand Up @@ -73,7 +72,10 @@ pub fn pay_for_quotes_calldata<T: IntoIterator<Item = QuotePayment>>(
let approve_amount = total_amount;

let provider = http_provider(network.rpc_url().clone());
let data_payments = DataPaymentsHandler::new(*network.data_payments_address(), provider);
let data_payments = crate::contract::payment_vault::handler::PaymentVaultHandler::new(
*network.data_payments_address(),
provider,
);

// Divide transfers over multiple transactions if they exceed the max per transaction.
let chunks = payments.chunks(MAX_TRANSFERS_PER_TRANSACTION);
Expand Down
3 changes: 2 additions & 1 deletion evmlib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::common::{Address, QuoteHash};
use crate::transaction::verify_data_payment;
use alloy::primitives::address;
use alloy::transports::http::reqwest;
use common::Amount;
use quoting_metrics::QuotingMetrics;
use serde::{Deserialize, Serialize};
use serde_with::{serde_as, DisplayFromStr};
Expand Down Expand Up @@ -140,7 +141,7 @@ impl Network {
quote_hash: QuoteHash,
quoting_metrics: QuotingMetrics,
reward_addr: Address,
) -> Result<(), transaction::Error> {
) -> Result<Amount, transaction::Error> {
verify_data_payment(self, quote_hash, reward_addr, quoting_metrics).await
}
}
Loading
Loading