locally marking credentials as spent
This commit is contained in:
@@ -49,7 +49,11 @@ impl Credential {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn blinded_serial_number(&self) -> String {
|
||||
pub fn blinded_serial_number(&self) -> &BlindedSerialNumber {
|
||||
&self.theta.blinded_serial_number
|
||||
}
|
||||
|
||||
pub fn blinded_serial_number_bs58(&self) -> String {
|
||||
self.theta.blinded_serial_number_bs58()
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@ use thiserror::Error;
|
||||
use tokio::io::{AsyncRead, AsyncWrite};
|
||||
use tokio_tungstenite::tungstenite::{protocol::Message, Error as WsError};
|
||||
|
||||
use std::cmp::max;
|
||||
use std::{convert::TryFrom, process, time::Duration};
|
||||
|
||||
use crate::node::client_handling::websocket::connection_handler::coconut::BANDWIDTH_PER_CREDENTIAL;
|
||||
use crate::node::{
|
||||
client_handling::{
|
||||
bandwidth::Bandwidth,
|
||||
@@ -58,6 +60,9 @@ pub(crate) enum RequestHandlingError {
|
||||
#[error("Provided bandwidth credential did not verify correctly on {0}")]
|
||||
InvalidBandwidthCredential(String),
|
||||
|
||||
#[error("the provided bandwidth credential has already been spent before at this gateway")]
|
||||
BandwidthCredentialAlreadySpent,
|
||||
|
||||
#[error("This gateway is only accepting coconut credentials for bandwidth")]
|
||||
OnlyCoconutCredentials,
|
||||
|
||||
@@ -229,6 +234,17 @@ where
|
||||
iv,
|
||||
)?;
|
||||
|
||||
// check if the credential hasn't been spent before
|
||||
let already_spent = self
|
||||
.inner
|
||||
.storage
|
||||
.contains_credential(credential.blinded_serial_number())
|
||||
.await?;
|
||||
if already_spent {
|
||||
return Err(RequestHandlingError::BandwidthCredentialAlreadySpent);
|
||||
}
|
||||
|
||||
// locally verify the credential
|
||||
let aggregated_verification_key = self
|
||||
.inner
|
||||
.coconut_verifier
|
||||
@@ -241,19 +257,36 @@ where
|
||||
));
|
||||
}
|
||||
|
||||
let api_clients = self
|
||||
.inner
|
||||
.coconut_verifier
|
||||
.api_clients(*credential.epoch_id())
|
||||
// technically this is not atomic, i.e. checking for the spending and then marking as spent,
|
||||
// but because we have the `UNIQUE` constraint on the database table
|
||||
// if somebody attempts to spend the same credential in another, parallel request,
|
||||
// one of them will fail
|
||||
//
|
||||
// mark the credential as spent
|
||||
// TODO: technically this should be done under a storage transaction so that if we experience any
|
||||
// failures later on, it'd get reverted
|
||||
self.inner
|
||||
.storage
|
||||
.insert_spent_credential(*credential.blinded_serial_number(), self.client.address)
|
||||
.await?;
|
||||
|
||||
self.inner
|
||||
.coconut_verifier
|
||||
.release_funds(&api_clients, &credential)
|
||||
.await?;
|
||||
// OLD CODE FOR RELEASING FUNDS
|
||||
// let api_clients = self
|
||||
// .inner
|
||||
// .coconut_verifier
|
||||
// .api_clients(*credential.epoch_id())
|
||||
// .await?;
|
||||
//
|
||||
// self.inner
|
||||
// .coconut_verifier
|
||||
// .release_funds(&api_clients, &credential)
|
||||
// .await?;
|
||||
|
||||
let bandwidth = Bandwidth::from(credential);
|
||||
let bandwidth_value = bandwidth.value();
|
||||
|
||||
// if somebody decided to use a credential with bunch of tokens in it, sure, grant them that bandwidth
|
||||
// otherwise use the default value
|
||||
let bandwidth_value = max(bandwidth.value(), BANDWIDTH_PER_CREDENTIAL);
|
||||
|
||||
if bandwidth_value > i64::MAX as u64 {
|
||||
// note that this would have represented more than 1 exabyte,
|
||||
|
||||
@@ -20,6 +20,8 @@ use std::collections::HashMap;
|
||||
use std::ops::Deref;
|
||||
use tokio::sync::{RwLock, RwLockReadGuard};
|
||||
|
||||
pub(crate) const BANDWIDTH_PER_CREDENTIAL: u64 = 1024 * 1024 * 1024; // 1GB
|
||||
|
||||
pub(crate) struct CoconutVerifier {
|
||||
address: AccountId,
|
||||
nyxd_client: RwLock<DirectSigningHttpRpcNyxdClient>,
|
||||
@@ -165,7 +167,7 @@ impl CoconutVerifier {
|
||||
credential.voucher_value().into(),
|
||||
self.mix_denom_base.clone(),
|
||||
),
|
||||
credential.blinded_serial_number(),
|
||||
credential.blinded_serial_number_bs58(),
|
||||
self.address.to_string(),
|
||||
None,
|
||||
)
|
||||
|
||||
@@ -110,7 +110,11 @@ pub async fn verify_bandwidth_credential(
|
||||
// Credential has not been spent before, and is on its way of being spent
|
||||
let credential_status = state
|
||||
.client
|
||||
.get_spent_credential(verify_credential_body.credential.blinded_serial_number())
|
||||
.get_spent_credential(
|
||||
verify_credential_body
|
||||
.credential
|
||||
.blinded_serial_number_bs58(),
|
||||
)
|
||||
.await?
|
||||
.spend_credential
|
||||
.ok_or(CoconutError::InvalidCredentialStatus {
|
||||
|
||||
@@ -1062,7 +1062,7 @@ async fn verification_of_bandwidth_credential() {
|
||||
);
|
||||
|
||||
// Test the endpoint with no msg in the proposal action
|
||||
proposal.description = credential.blinded_serial_number();
|
||||
proposal.description = credential.blinded_serial_number_bs58();
|
||||
proposal_db
|
||||
.write()
|
||||
.unwrap()
|
||||
@@ -1117,7 +1117,7 @@ async fn verification_of_bandwidth_credential() {
|
||||
);
|
||||
|
||||
spent_credential_db.write().unwrap().insert(
|
||||
credential.blinded_serial_number(),
|
||||
credential.blinded_serial_number_bs58(),
|
||||
SpendCredentialResponse::new(None),
|
||||
);
|
||||
let response = client
|
||||
@@ -1140,11 +1140,11 @@ async fn verification_of_bandwidth_credential() {
|
||||
// Test the endpoint with a credential that doesn't verify correctly
|
||||
let mut spent_credential = SpendCredential::new(
|
||||
funds.clone().into(),
|
||||
credential.blinded_serial_number(),
|
||||
credential.blinded_serial_number_bs58(),
|
||||
Addr::unchecked("unimportant"),
|
||||
);
|
||||
spent_credential_db.write().unwrap().insert(
|
||||
credential.blinded_serial_number(),
|
||||
credential.blinded_serial_number_bs58(),
|
||||
SpendCredentialResponse::new(Some(spent_credential.clone())),
|
||||
);
|
||||
let bad_credential = Credential::new(
|
||||
@@ -1259,7 +1259,7 @@ async fn verification_of_bandwidth_credential() {
|
||||
// Test the endpoint with the credential marked as Spent in the Coconut Bandwidth Contract
|
||||
spent_credential.mark_as_spent();
|
||||
spent_credential_db.write().unwrap().insert(
|
||||
credential.blinded_serial_number(),
|
||||
credential.blinded_serial_number_bs58(),
|
||||
SpendCredentialResponse::new(Some(spent_credential)),
|
||||
);
|
||||
let response = client
|
||||
|
||||
Reference in New Issue
Block a user