credentials storage on gateway and api

This commit is contained in:
Simon Wicky
2023-10-27 14:39:09 +02:00
committed by durch
parent 506693a8a5
commit 46c53eb1a5
11 changed files with 157 additions and 35 deletions
@@ -34,6 +34,9 @@ pub enum CompactEcashError {
#[error("Could not decode base 58 string - {0}")]
MalformedString(#[from] bs58::decode::Error),
#[error("Payment did not verify")]
PaymentVerification,
#[error(
"Deserailization error, expected at least {} bytes, got {}",
min,
@@ -22,4 +22,10 @@ CREATE TABLE available_bandwidth
available INTEGER NOT NULL
);
CREATE INDEX `message_store_index` ON `message_store` (`client_address_bs58`, `content`);
CREATE INDEX `message_store_index` ON `message_store` (`client_address_bs58`, `content`);
CREATE TABLE credentials
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
credentials TEXT NOT NULL
);
@@ -266,11 +266,14 @@ where
))
})?;
//SW PUT that in a new threads, ensuring it eventually gets sent
self.inner
.ecash_verifier
.post_and_store_credential(current_api_clients, credential)
.post_credential(current_api_clients, credential.clone())
.await?;
self.inner.storage.insert_credential(credential).await?;
let bandwidth_value = 500000;
self.increase_bandwidth(bandwidth_value as i64).await?;
@@ -24,17 +24,11 @@ const MAX_FEEGRANT_UNYM: u128 = 10000;
pub(crate) struct EcashVerifier {
nyxd_client: DirectSigningHttpRpcNyxdClient,
mix_denom_base: String,
}
impl EcashVerifier {
pub fn new(nyxd_client: DirectSigningHttpRpcNyxdClient) -> Self {
let mix_denom_base = nyxd_client.current_chain_details().mix_denom.base.clone();
EcashVerifier {
nyxd_client,
mix_denom_base,
}
EcashVerifier { nyxd_client }
}
pub async fn all_current_ecash_api_clients(
@@ -60,7 +54,7 @@ impl EcashVerifier {
Ok(())
}
pub async fn post_and_store_credential(
pub async fn post_credential(
&self,
api_clients: Vec<CoconutApiClient>,
credential: EcashCredential,
@@ -72,28 +66,22 @@ impl EcashVerifier {
);
for client in api_clients {
let ret = client.api_client.verify_bandwidth_credential(&req).await; //SW PUT that in a new threads, ensuring it eventually gets sent
warn!(
"Return from {} : {:?}",
client.api_client.nym_api.current_url(),
ret
);
// match ret {
// Ok(res) => {
// if !res.verification_result {
// debug!(
// "Validator {} didn't accept the credential.",
// client.api_client.nym_api.current_url()
// );
// }
// }
// Err(e) => {
// warn!("Validator {} could not be reached. There might be a problem with the coconut endpoint - {:?}", client.api_client.nym_api.current_url(), e);
// }
// }
}
let ret = client.api_client.verify_bandwidth_credential(&req).await;
//store credential
match ret {
Ok(res) => {
if !res.verification_result {
debug!(
"Validator {} didn't accept the credential.",
client.api_client.nym_api.current_url()
);
}
}
Err(e) => {
warn!("Validator {} could not be reached. There might be a problem with the coconut endpoint - {:?}", client.api_client.nym_api.current_url(), e);
}
}
}
Ok(())
}
+34
View File
@@ -0,0 +1,34 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
#[derive(Clone)]
pub(crate) struct CredentialManager {
connection_pool: sqlx::SqlitePool,
}
impl CredentialManager {
/// Creates new instance of the `CredentialManager` with the provided sqlite connection pool.
///
/// # Arguments
///
/// * `connection_pool`: database connection pool to use.
pub(crate) fn new(connection_pool: sqlx::SqlitePool) -> Self {
CredentialManager { connection_pool }
}
/// Inserts provided credential into the database.
/// If the credential previously existed for the provided client, they are overwritten with the new data.
///
/// # Arguments
///
/// * `credential`: base58 representation of an ecash credential
pub(crate) async fn insert_credential(&self, credential: String) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT OR REPLACE INTO credentials(credentials) VALUES (?)",
credential
)
.execute(&self.connection_pool)
.await?;
Ok(())
}
}
+21 -1
View File
@@ -2,18 +2,22 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::node::storage::bandwidth::BandwidthManager;
use crate::node::storage::credential::CredentialManager;
use crate::node::storage::error::StorageError;
use crate::node::storage::inboxes::InboxManager;
use crate::node::storage::models::{PersistedSharedKeys, StoredMessage};
use crate::node::storage::shared_keys::SharedKeysManager;
use async_trait::async_trait;
use log::{debug, error};
use nym_compact_ecash::scheme::EcashCredential;
use nym_compact_ecash::Base58;
use nym_gateway_requests::registration::handshake::SharedKeys;
use nym_sphinx::DestinationAddressBytes;
use sqlx::ConnectOptions;
use std::path::Path;
mod bandwidth;
mod credential;
pub(crate) mod error;
mod inboxes;
mod models;
@@ -134,6 +138,13 @@ pub(crate) trait Storage: Send + Sync {
client_address: DestinationAddressBytes,
amount: i64,
) -> Result<(), StorageError>;
/// Stored the accepted credential
///
/// # Arguments
///
/// * `credential`: credential to store
async fn insert_credential(&self, credential: EcashCredential) -> Result<(), StorageError>;
}
// note that clone here is fine as upon cloning the same underlying pool will be used
@@ -142,6 +153,7 @@ pub(crate) struct PersistentStorage {
shared_key_manager: SharedKeysManager,
inbox_manager: InboxManager,
bandwidth_manager: BandwidthManager,
credential_manager: CredentialManager,
}
impl PersistentStorage {
@@ -187,7 +199,8 @@ impl PersistentStorage {
Ok(PersistentStorage {
shared_key_manager: SharedKeysManager::new(connection_pool.clone()),
inbox_manager: InboxManager::new(connection_pool.clone(), message_retrieval_limit),
bandwidth_manager: BandwidthManager::new(connection_pool),
bandwidth_manager: BandwidthManager::new(connection_pool.clone()),
credential_manager: CredentialManager::new(connection_pool),
})
}
}
@@ -304,6 +317,13 @@ impl Storage for PersistentStorage {
.await?;
Ok(())
}
async fn insert_credential(&self, credential: EcashCredential) -> Result<(), StorageError> {
self.credential_manager
.insert_credential(credential.to_bs58())
.await?;
Ok(())
}
}
/// In-memory implementation of `Storage`. The intention is primarily in testing environments.
+4
View File
@@ -18,3 +18,7 @@ pub(crate) struct PersistedBandwidth {
pub(crate) client_address_bs58: String,
pub(crate) available: i64,
}
pub(crate) struct Credentials {
pub(crate) credential: String,
}
@@ -76,6 +76,14 @@ create table gateway_ipv6_status
FOREIGN KEY (gateway_details_id) REFERENCES gateway_details (id)
);
create table credentials
(
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
credential TEXT NOT NULL,
gateway_address TEXT NOT NULL
);
-- indices for faster lookups
CREATE
INDEX `mixnode_ipv4_status_index` ON `mixnode_ipv4_status` (`mixnode_details_id`, `timestamp` desc);
+24 -3
View File
@@ -18,8 +18,10 @@ use nym_coconut_bandwidth_contract_common::spend_credential::{
};
use nym_coconut_dkg_common::types::EpochId;
use nym_compact_ecash::error::CompactEcashError;
use nym_compact_ecash::scheme::keygen::{KeyPairAuth, SecretKeyAuth};
use nym_compact_ecash::scheme::withdrawal::WithdrawalRequest;
use nym_compact_ecash::scheme::EcashCredential;
use nym_compact_ecash::setup::GroupParameters;
use nym_compact_ecash::utils::BlindedSignature;
use nym_compact_ecash::{PublicKeyUser, VerificationKeyAuth};
@@ -31,7 +33,7 @@ use nym_crypto::asymmetric::encryption;
use nym_crypto::shared_key::new_ephemeral_shared_key;
use nym_crypto::symmetric::stream_cipher;
use nym_validator_client::nym_api::routes::{BANDWIDTH, COCONUT_ROUTES};
use nym_validator_client::nyxd::{Coin, Fee};
use nym_validator_client::nyxd::{AccountId, Coin, Fee};
use rand_07::rngs::OsRng;
use rocket::fairing::AdHoc;
use rocket::serde::json::Json;
@@ -143,6 +145,17 @@ impl State {
.aggregated_verification_key(epoch_id)
.await
}
pub async fn store_credential(
&self,
credential: &EcashCredential,
gateway_addr: &AccountId,
) -> Result<()> {
self.storage
.insert_credential(credential, gateway_addr)
.await
.map_err(|err| err.into())
}
}
#[derive(Getters, CopyGetters, Debug)]
@@ -250,15 +263,23 @@ pub async fn verify_bandwidth_credential(
.verification_key(*verify_credential_body.credential().epoch_id())
.await?;
if let Err(err) = verify_credential_body.credential().payment().spend_verify(
if let Err(_) = verify_credential_body.credential().payment().spend_verify(
verify_credential_body.credential().params(),
&verification_key,
verify_credential_body.credential().pay_info(),
) {
return Err(CoconutError::CompactEcashInternalError(err));
return Err(CoconutError::CompactEcashInternalError(
CompactEcashError::PaymentVerification,
));
}
//store credential
state
.store_credential(
verify_credential_body.credential(),
verify_credential_body.gateway_cosmos_addr(),
)
.await?;
Ok(Json(VerifyCredentialResponse::new(true)))
}
+21
View File
@@ -1013,4 +1013,25 @@ impl StorageManager {
Ok(blinded_signature_response)
}
/// Creates new credential entry for a given gateway addr.
///
/// # Arguments
///
/// * `credential`: base58 repr of a credential.
/// * `gateway_addr`: cosmos address of the gateway
pub(crate) async fn insert_credential(
&self,
credential: String,
gateway_addr: String,
) -> Result<(), sqlx::Error> {
sqlx::query!(
"INSERT INTO credentials(credential, gateway_address) VALUES (?, ?)",
credential,
gateway_addr
)
.execute(&self.connection_pool)
.await?;
Ok(())
}
}
+14
View File
@@ -10,7 +10,10 @@ use crate::node_status_api::models::{
use crate::node_status_api::{ONE_DAY, ONE_HOUR};
use crate::storage::manager::StorageManager;
use crate::storage::models::{NodeStatus, TestingRoute};
use nym_compact_ecash::scheme::EcashCredential;
use nym_compact_ecash::Base58;
use nym_mixnet_contract_common::MixId;
use nym_validator_client::nyxd::AccountId;
use rocket::fairing::AdHoc;
use sqlx::ConnectOptions;
use std::path::Path;
@@ -737,4 +740,15 @@ impl NymApiStorage {
.await
.map_err(|err| err.into())
}
pub(crate) async fn insert_credential(
&self,
credential: &EcashCredential,
gateway_addr: &AccountId,
) -> Result<(), NymApiStorageError> {
self.manager
.insert_credential(credential.to_bs58(), gateway_addr.to_string())
.await
.map_err(|err| err.into())
}
}