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

Feat upgradable smart contracts and updated quotation flow 3 #2

Open
wants to merge 2 commits into
base: feat-upgradable-smart-contracts-and-updated-quotation-flow-2
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion ant-evm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub use evmlib::common::Address as RewardsAddress;
pub use evmlib::common::Address as EvmAddress;
pub use evmlib::common::QuotePayment;
pub use evmlib::common::{QuoteHash, TxHash};
pub use evmlib::contract::payment_vault;
pub use evmlib::cryptography;
#[cfg(feature = "external-signer")]
pub use evmlib::external_signer;
Expand All @@ -28,8 +29,8 @@ mod amount;
mod data_payments;
mod error;

pub use evmlib::quoting_metrics::QuotingMetrics;
pub use data_payments::{PaymentQuote, ProofOfPayment, QUOTE_EXPIRATION_SECS};
pub use evmlib::quoting_metrics::QuotingMetrics;

/// Types used in the public API
pub use amount::{Amount, AttoTokens};
Expand Down
15 changes: 10 additions & 5 deletions ant-node/src/put_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,8 +622,7 @@ impl Node {
))
})?
.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
// 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!(
Expand All @@ -633,7 +632,8 @@ impl Node {

// check if payment is valid on chain
debug!("Verifying payment for record {pretty_key}");
let reward_amount = self.evm_network()
let reward_amount = self
.evm_network()
.verify_data_payment(
payment.quote.hash(),
payment.quote.quoting_metrics,
Expand All @@ -657,7 +657,10 @@ impl Node {
.set(new_value);
}
self.events_channel()
.broadcast(crate::NodeEvent::RewardReceived(AttoTokens::from(reward_amount), address.clone()));
.broadcast(crate::NodeEvent::RewardReceived(
AttoTokens::from(reward_amount),
address.clone(),
));

// vdash metric (if modified please notify at https://github.com/happybeing/vdash/issues):
info!("Total payment of {reward_amount:?} atto tokens accepted for record {pretty_key}");
Expand All @@ -666,7 +669,9 @@ impl Node {
#[cfg(feature = "loud")]
{
println!("🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟 RECEIVED REWARD 🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟");
println!("Total payment of {reward_amount:?} atto tokens accepted for record {pretty_key}");
println!(
"Total payment of {reward_amount:?} atto tokens accepted for record {pretty_key}"
);
println!("🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟");
}

Expand Down
2 changes: 2 additions & 0 deletions autonomi/src/client/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ pub enum CostError {
CouldNotGetStoreCosts(NetworkError),
#[error("Failed to serialize {0}")]
Serialization(String),
#[error("Payment vault error: {0:?}")]
PaymentVaultError(ant_evm::payment_vault::error::Error),
}

impl Client {
Expand Down
1 change: 1 addition & 0 deletions autonomi/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

pub mod address;
pub mod payment;
pub mod quote;

#[cfg(feature = "data")]
pub mod archive;
Expand Down
60 changes: 37 additions & 23 deletions autonomi/src/client/quote.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@
// KIND, either express or implied. Please review the Licences for the specific language governing
// permissions and limitations relating to use of the SAFE Network Software.

use ant_evm::{PaymentQuote, ProofOfPayment, QuoteHash, TxHash};
use super::{data::CostError, Client};
use crate::client::payment::Receipt;
use crate::EvmNetwork;
use ant_evm::payment_vault::get_quote;
use ant_evm::{Amount, AttoTokens, QuotePayment};
use ant_evm::{ProofOfPayment, QuoteHash, TxHash};
use ant_networking::{Network, NetworkError, SelectedQuotes};
use ant_protocol::{
storage::ChunkAddress,
NetworkAddress,
};
use xor_name::XorName;
use ant_protocol::{storage::ChunkAddress, NetworkAddress};
use std::collections::{BTreeMap, HashMap};

use crate::client::payment::Receipt;
use super::{data::CostError, Client};
use xor_name::XorName;

pub struct QuotesToPay {
pub nodes_to_pay: Vec<QuotePayment>,
Expand All @@ -29,6 +27,7 @@ pub struct QuotesToPay {
impl Client {
pub(crate) async fn get_store_quotes(
&self,
network: &EvmNetwork,
content_addrs: impl Iterator<Item = XorName>,
) -> Result<HashMap<XorName, QuotesToPay>, CostError> {
let futures: Vec<_> = content_addrs
Expand All @@ -39,23 +38,38 @@ impl Client {
let quotes = futures::future::try_join_all(futures).await?;

let mut quotes_to_pay_per_addr = HashMap::new();
for (content_addr, quotes) in quotes {
// NB TODO: get cost from smart contract for each quote and set this value to the median of all quotes!
let cost_per_node = Amount::from(1);

for (content_addr, selected_quotes) in quotes {
let mut prices: Vec<Amount> = vec![];

for quote in selected_quotes.quotes {
let price = get_quote(network, quote.1.quoting_metrics.clone()).await?;
prices.push(price);
}

// TODO: set the cost per node by picking the median price of the prices above @anselme
let cost_per_node = Amount::from(1);

// NB TODO: that's all the nodes except the invalid ones (rejected by smart contract)
let nodes_to_pay: Vec<_> = quotes.iter().map(|(_, q)| (q.hash(), q.rewards_address, cost_per_node)).collect();

let nodes_to_pay: Vec<_> = selected_quotes
.quotes
.iter()
.map(|(_, q)| (q.hash(), q.rewards_address, cost_per_node))
.collect();

// NB TODO: that's the lower half (quotes under or equal to the median price)
let nodes_to_upload_to = quotes.clone();
let nodes_to_upload_to = quotes.clone();

let total_cost = cost_per_node * Amount::from(nodes_to_pay.len());
quotes_to_pay_per_addr.insert(content_addr, QuotesToPay {
nodes_to_pay,
nodes_to_upload_to,
cost_per_node: AttoTokens::from_atto(cost_per_node),
total_cost: AttoTokens::from_atto(total_cost),
});
quotes_to_pay_per_addr.insert(
content_addr,
QuotesToPay {
nodes_to_pay,
nodes_to_upload_to,
cost_per_node: AttoTokens::from_atto(cost_per_node),
total_cost: AttoTokens::from_atto(total_cost),
},
);
}

Ok(quotes_to_pay_per_addr)
Expand All @@ -66,7 +80,7 @@ impl Client {
async fn fetch_store_quote(
network: &Network,
content_addr: XorName,
) -> Result<Vec<SelectedQuotes>, NetworkError> {
) -> Result<SelectedQuotes, NetworkError> {
network
.get_store_quote_from_network(
NetworkAddress::from_chunk_address(ChunkAddress::new(content_addr)),
Expand All @@ -79,7 +93,7 @@ async fn fetch_store_quote(
async fn fetch_store_quote_with_retries(
network: &Network,
content_addr: XorName,
) -> Result<(XorName, Vec<SelectedQuotes>), CostError> {
) -> Result<(XorName, SelectedQuotes), CostError> {
let mut retries = 0;

loop {
Expand Down
84 changes: 5 additions & 79 deletions autonomi/src/client/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,22 @@
// permissions and limitations relating to use of the SAFE Network Software.

use crate::client::payment::Receipt;
use ant_evm::{EvmWallet, ProofOfPayment, QuotePayment};
use ant_networking::{
GetRecordCfg, Network, NetworkError, SelectedQuotes, PutRecordCfg, VerificationKind,
};
use ant_evm::{EvmWallet, ProofOfPayment};
use ant_networking::{GetRecordCfg, PutRecordCfg, VerificationKind};
use ant_protocol::{
messages::ChunkProof,
storage::{try_serialize_record, Chunk, ChunkAddress, RecordKind, RetryStrategy},
NetworkAddress,
storage::{try_serialize_record, Chunk, RecordKind, RetryStrategy},
};
use bytes::Bytes;
use futures::stream::{FuturesUnordered, StreamExt};
use libp2p::kad::{Quorum, Record};
use rand::{thread_rng, Rng};
use self_encryption::{decrypt_full_set, DataMap, EncryptedChunk};
use std::{collections::HashMap, future::Future, num::NonZero};
use std::{future::Future, num::NonZero};
use xor_name::XorName;

use super::{
data::{CostError, GetError, PayError, PutError, CHUNK_DOWNLOAD_BATCH_SIZE},
data::{GetError, PayError, PutError, CHUNK_DOWNLOAD_BATCH_SIZE},
Client,
};
use crate::self_encryption::DataMapLevel;
Expand Down Expand Up @@ -193,77 +190,6 @@ impl Client {

Ok((proofs, skipped_chunks))
}

pub(crate) async fn get_store_quotes(
&self,
content_addrs: impl Iterator<Item = XorName>,
) -> 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, 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, SelectedQuotes), CostError> {
let mut retries = 0;

loop {
match fetch_store_quote(network, content_addr).await {
Ok(quote) => {
break Ok((content_addr, quote));
}
Err(err) if retries < 2 => {
retries += 1;
error!("Error while fetching store quote: {err:?}, retry #{retries}");
}
Err(err) => {
error!(
"Error while fetching store quote: {err:?}, stopping after {retries} retries"
);
break Err(CostError::CouldNotGetStoreQuote(content_addr));
}
}
}
}

/// Fetch a store quote for a content address.
async fn fetch_store_quote(
network: &Network,
content_addr: XorName,
) -> Result<SelectedQuotes, NetworkError> {
network
.get_store_costs_from_network(
NetworkAddress::from_chunk_address(ChunkAddress::new(content_addr)),
vec![],
)
.await
}

/// Form to be executed payments and already executed payments from a cost map.
pub(crate) fn extract_quote_payments(
cost_map: &HashMap<XorName, SelectedQuotes>,
) -> (Vec<QuotePayment>, Vec<XorName>) {
let mut to_be_paid = vec![];
let mut already_paid = vec![];

for (chunk_address, (_, _, quote)) in cost_map.iter() {
if quote.cost.is_zero() {
already_paid.push(*chunk_address);
} else {
to_be_paid.push((quote.hash(), quote.rewards_address, quote.cost.as_atto()));
}
}

(to_be_paid, already_paid)
}

pub(crate) async fn process_tasks_with_max_concurrency<I, R>(tasks: I, batch_size: usize) -> Vec<R>
Expand Down
6 changes: 3 additions & 3 deletions evmlib/src/contract/payment_vault/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ where
}

/// Fetch a quote from the contract
pub async fn fetch_quote(
pub async fn get_quote<I: Into<IPaymentVault::QuotingMetrics>>(
&self,
metrics: IPaymentVault::QuotingMetrics,
metrics: I,
) -> Result<Amount, Error> {
let amount = self.contract.getQuote(metrics).call().await?.price;
let amount = self.contract.getQuote(metrics.into()).call().await?.price;
Ok(amount)
}

Expand Down
1 change: 1 addition & 0 deletions evmlib/src/contract/payment_vault/implementation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use alloy::network::{Network, ReceiptResponse, TransactionBuilder};
use alloy::providers::Provider;
use alloy::transports::Transport;

// Payment Vault contract byte code
const BYTE_CODE: &str = "0x60a060405230608052348015610013575f5ffd5b5061001c610021565b6100d3565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff16156100715760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146100d05780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b608051610ef76100f95f395f818161064d0152818161067601526107ba0152610ef75ff3fe6080604052600436106100bf575f3560e01c8063715018a61161007c578063ad3cb1cc11610057578063ad3cb1cc14610253578063b6c2141b14610290578063cd6dc687146102af578063f2fde38b146102ce575f5ffd5b8063715018a6146101d45780638da5cb5b146101e8578063a69bf4a314610224575f5ffd5b80630716326d146100c35780633c150bf214610132578063474740b1146101605780634ec42e8e146101745780634f1ef286146101ab57806352d1902d146101c0575b5f5ffd5b3480156100ce575f5ffd5b506101086100dd366004610bc4565b600260208190525f91825260409091208054600182015491909201546001600160a01b039092169183565b604080516001600160a01b0390941684526020840192909252908201526060015b60405180910390f35b34801561013d575f5ffd5b5061015261014c366004610bf1565b50600190565b604051908152602001610129565b34801561016b575f5ffd5b506101525f5481565b34801561017f575f5ffd5b50600154610193906001600160a01b031681565b6040516001600160a01b039091168152602001610129565b6101be6101b9366004610c33565b6102ed565b005b3480156101cb575f5ffd5b5061015261030c565b3480156101df575f5ffd5b506101be610327565b3480156101f3575f5ffd5b507f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b0316610193565b34801561022f575f5ffd5b5061024361023e366004610cf9565b61033a565b6040519015158152602001610129565b34801561025e575f5ffd5b50610283604051806040016040528060058152602001640352e302e360dc1b81525081565b6040516101299190610d37565b34801561029b575f5ffd5b506101be6102aa366004610d6c565b6103b6565b3480156102ba575f5ffd5b506101be6102c9366004610ddd565b6104a3565b3480156102d9575f5ffd5b506101be6102e8366004610e07565b610600565b6102f5610642565b6102fe826106e6565b61030882826106ee565b5050565b5f6103156107af565b505f516020610ea25f395f51905f5290565b61032f6107f8565b6103385f610853565b565b6040808201355f90815260026020818152838320845160608101865281546001600160a01b031681526001820154818401819052919093015494830194909452919290918401351480156103ae57506103966020840184610e07565b6001600160a01b0316815f01516001600160a01b0316145b949350505050565b5f5481908111156103da57604051630d67f41160e21b815260040160405180910390fd5b5f5b8181101561049d57368484838181106103f7576103f7610e22565b60600291909101915061042b9050336104136020840184610e07565b6001546001600160a01b0316919060208501356108c3565b6040808201355f90815260026020522081906104478282610e36565b505060408101356020820180359061045f9084610e07565b6001600160a01b03167ff998960b1c6f0e0e89b7bbe6b6fbf3e03e6f08eee5b8430877d8adb8e149d58060405160405180910390a4506001016103dc565b50505050565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a008054600160401b810460ff16159067ffffffffffffffff165f811580156104e85750825b90505f8267ffffffffffffffff1660011480156105045750303b155b905081158015610512575080155b156105305760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff19166001178555831561055a57845460ff60401b1916600160401b1785555b6001600160a01b03871661058157604051632d06160b60e21b815260040160405180910390fd5b600180546001600160a01b0319166001600160a01b0389161790555f8690556105a93361091d565b6105b161092e565b83156105f757845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50505050505050565b6106086107f8565b6001600160a01b03811661063657604051631e4fbdf760e01b81525f60048201526024015b60405180910390fd5b61063f81610853565b50565b306001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614806106c857507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166106bc5f516020610ea25f395f51905f52546001600160a01b031690565b6001600160a01b031614155b156103385760405163703e46dd60e11b815260040160405180910390fd5b61063f6107f8565b816001600160a01b03166352d1902d6040518163ffffffff1660e01b8152600401602060405180830381865afa925050508015610748575060408051601f3d908101601f1916820190925261074591810190610e74565b60015b61077057604051634c9c8ce360e01b81526001600160a01b038316600482015260240161062d565b5f516020610ea25f395f51905f5281146107a057604051632a87526960e21b81526004810182905260240161062d565b6107aa8383610936565b505050565b306001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146103385760405163703e46dd60e11b815260040160405180910390fd5b3361082a7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b6001600160a01b0316146103385760405163118cdaa760e01b815233600482015260240161062d565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0905f90a3505050565b604080516001600160a01b0385811660248301528416604482015260648082018490528251808303909101815260849091019091526020810180516001600160e01b03166323b872dd60e01b17905261049d90859061098b565b6109256109f7565b61063f81610a40565b6103386109f7565b61093f82610a48565b6040516001600160a01b038316907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b905f90a2805115610983576107aa8282610aab565b610308610b1d565b5f5f60205f8451602086015f885af1806109aa576040513d5f823e3d81fd5b50505f513d915081156109c15780600114156109ce565b6001600160a01b0384163b155b1561049d57604051635274afe760e01b81526001600160a01b038516600482015260240161062d565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0054600160401b900460ff1661033857604051631afcd79f60e31b815260040160405180910390fd5b6106086109f7565b806001600160a01b03163b5f03610a7d57604051634c9c8ce360e01b81526001600160a01b038216600482015260240161062d565b5f516020610ea25f395f51905f5280546001600160a01b0319166001600160a01b0392909216919091179055565b60605f5f846001600160a01b031684604051610ac79190610e8b565b5f60405180830381855af49150503d805f8114610aff576040519150601f19603f3d011682016040523d82523d5f602084013e610b04565b606091505b5091509150610b14858383610b3c565b95945050505050565b34156103385760405163b398979f60e01b815260040160405180910390fd5b606082610b5157610b4c82610b9b565b610b94565b8151158015610b6857506001600160a01b0384163b155b15610b9157604051639996b31560e01b81526001600160a01b038516600482015260240161062d565b50805b9392505050565b805115610bab5780518082602001fd5b60405163d6bda27560e01b815260040160405180910390fd5b5f60208284031215610bd4575f5ffd5b5035919050565b5f60c08284031215610beb575f5ffd5b50919050565b5f60c08284031215610c01575f5ffd5b610b948383610bdb565b6001600160a01b038116811461063f575f5ffd5b634e487b7160e01b5f52604160045260245ffd5b5f5f60408385031215610c44575f5ffd5b8235610c4f81610c0b565b9150602083013567ffffffffffffffff811115610c6a575f5ffd5b8301601f81018513610c7a575f5ffd5b803567ffffffffffffffff811115610c9457610c94610c1f565b604051601f8201601f19908116603f0116810167ffffffffffffffff81118282101715610cc357610cc3610c1f565b604052818152828201602001871015610cda575f5ffd5b816020840160208301375f602083830101528093505050509250929050565b5f5f828403610120811215610d0c575f5ffd5b610d168585610bdb565b9250606060bf1982011215610d29575f5ffd5b5060c0830190509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f5f60208385031215610d7d575f5ffd5b823567ffffffffffffffff811115610d93575f5ffd5b8301601f81018513610da3575f5ffd5b803567ffffffffffffffff811115610db9575f5ffd5b856020606083028401011115610dcd575f5ffd5b6020919091019590945092505050565b5f5f60408385031215610dee575f5ffd5b8235610df981610c0b565b946020939093013593505050565b5f60208284031215610e17575f5ffd5b8135610b9481610c0b565b634e487b7160e01b5f52603260045260245ffd5b8135610e4181610c0b565b81546001600160a01b0319166001600160a01b039190911617815560208201356001820155604090910135600290910155565b5f60208284031215610e84575f5ffd5b5051919050565b5f82518060208501845e5f92019182525091905056fe360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca26469706673582212203894ca52be6e6323aa3d296efd566c7f21d1723d4c66c56aed8a5f75a96b579d64736f6c634300081c0033";

pub async fn deploy<T, P, N>(provider: &P) -> Address
Expand Down
Loading
Loading