online mode on gateway
This commit is contained in:
@@ -671,6 +671,18 @@ impl EcashCredential {
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
pub fn value(&self) -> u64 {
|
||||
todo!() //SW todo
|
||||
}
|
||||
|
||||
pub fn blinded_serial_number(&self) -> String {
|
||||
todo!() //SW todo
|
||||
}
|
||||
|
||||
pub fn has_blinded_serial_number(&self, _blinded_serial_number_bs58: &str) -> Result<bool> {
|
||||
todo!() //SW todo
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for EcashCredential {
|
||||
|
||||
@@ -66,6 +66,12 @@ pub(crate) enum RequestHandlingError {
|
||||
#[error("Not enough nym API endpoints provided. Needed {needed}, received {received}")]
|
||||
NotEnoughNymAPIs { received: usize, needed: usize },
|
||||
|
||||
#[error("There was a problem with the proposal id: {reason}")]
|
||||
ProposalIdError { reason: String },
|
||||
|
||||
#[error("Compact ecash error - {0}")]
|
||||
CompactEcashError(#[from] nym_compact_ecash::error::CompactEcashError),
|
||||
|
||||
#[error("Coconut interface error - {0}")]
|
||||
CoconutInterfaceError(#[from] nym_coconut_interface::error::CoconutInterfaceError),
|
||||
|
||||
@@ -251,11 +257,18 @@ where
|
||||
.check_payment(&credential, &aggregated_verification_key)
|
||||
.await?;
|
||||
|
||||
self.inner
|
||||
.ecash_verifier
|
||||
.post_credential(current_api_clients, credential.clone())?;
|
||||
if self.inner.offline_credential_verification {
|
||||
self.inner
|
||||
.ecash_verifier
|
||||
.post_credential(current_api_clients, credential.clone())?;
|
||||
|
||||
self.inner.storage.insert_credential(credential).await?;
|
||||
self.inner.storage.insert_credential(credential).await?;
|
||||
} else {
|
||||
self.inner
|
||||
.ecash_verifier
|
||||
.release_funds(current_api_clients, &credential)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let bandwidth_value = 100000000; //SW MAKE A GLOBAL PARAMETER
|
||||
|
||||
|
||||
@@ -7,25 +7,36 @@ use super::authenticated::RequestHandlingError;
|
||||
use chrono::Utc;
|
||||
use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
|
||||
use futures::StreamExt;
|
||||
use nym_api_requests::coconut::VerifyCredentialBody;
|
||||
use log::*;
|
||||
use nym_api_requests::coconut::OfflineVerifyCredentialBody;
|
||||
use nym_compact_ecash::scheme::EcashCredential;
|
||||
use nym_compact_ecash::setup::Parameters;
|
||||
use nym_compact_ecash::{PayInfo, VerificationKeyAuth};
|
||||
use nym_validator_client::coconut::all_ecash_api_clients;
|
||||
use nym_validator_client::nyxd::AccountId;
|
||||
use nym_validator_client::nyxd::{AccountId, Coin, Fee};
|
||||
use nym_validator_client::{
|
||||
nyxd::contract_traits::DkgQueryClient, CoconutApiClient, DirectSigningHttpRpcNyxdClient,
|
||||
NymApiClient,
|
||||
nyxd::{
|
||||
contract_traits::{
|
||||
CoconutBandwidthSigningClient, DkgQueryClient, MultisigQueryClient,
|
||||
MultisigSigningClient,
|
||||
},
|
||||
cosmwasm_client::logs::{find_attribute, BANDWIDTH_PROPOSAL_ID},
|
||||
},
|
||||
CoconutApiClient, DirectSigningHttpRpcNyxdClient, NymApiClient,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use std::sync::Mutex;
|
||||
use std::time::SystemTime;
|
||||
use tokio::time::{interval, Duration};
|
||||
|
||||
const TIME_RANGE_SEC: i64 = 30;
|
||||
const CRED_SENDING_INTERVAL: u64 = 300;
|
||||
const ONE_HOUR_SEC: u64 = 3600;
|
||||
const MAX_FEEGRANT_UNYM: u128 = 10000;
|
||||
|
||||
pub(crate) struct EcashVerifier {
|
||||
nyxd_client: DirectSigningHttpRpcNyxdClient,
|
||||
mix_denom_base: String,
|
||||
ecash_parameters: Parameters,
|
||||
pk_bytes: [u8; 32], //bytes represenation of a pub key representing the verifier
|
||||
pay_infos: Arc<Mutex<Vec<PayInfo>>>,
|
||||
@@ -39,13 +50,19 @@ impl EcashVerifier {
|
||||
pk_bytes: [u8; 32],
|
||||
shutdown: nym_task::TaskClient,
|
||||
storage: St,
|
||||
offline_verification: bool,
|
||||
) -> Self {
|
||||
let mix_denom_base = nyxd_client.current_chain_details().mix_denom.base.clone();
|
||||
let (cred_sender, cred_receiver) = mpsc::unbounded();
|
||||
let cs = CredentialSender::new(cred_receiver, storage);
|
||||
cs.start(shutdown);
|
||||
//SW do not initialize unused elements
|
||||
if offline_verification {
|
||||
let cs = CredentialSender::new(cred_receiver, storage);
|
||||
cs.start(shutdown);
|
||||
}
|
||||
|
||||
EcashVerifier {
|
||||
nyxd_client,
|
||||
mix_denom_base,
|
||||
ecash_parameters,
|
||||
pk_bytes,
|
||||
pay_infos: Arc::new(Mutex::new(Vec::new())),
|
||||
@@ -199,6 +216,87 @@ impl EcashVerifier {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn release_funds(
|
||||
&self,
|
||||
api_clients: Vec<CoconutApiClient>,
|
||||
credential: &EcashCredential,
|
||||
) -> Result<(), RequestHandlingError> {
|
||||
// Use a custom multiplier for revoke, as the default one (1.3)
|
||||
// isn't enough
|
||||
let revoke_fee = Some(Fee::Auto(Some(1.5)));
|
||||
|
||||
let res = self
|
||||
.nyxd_client
|
||||
.spend_credential(
|
||||
Coin::new(
|
||||
credential.value().into(), //SW THIS WILL BE A FIXED VALUE?
|
||||
self.mix_denom_base.clone(),
|
||||
),
|
||||
credential.blinded_serial_number(), //SW what will this be?
|
||||
self.nyxd_client.address().to_string(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let proposal_id = find_attribute(&res.logs, "wasm", BANDWIDTH_PROPOSAL_ID)
|
||||
.ok_or(RequestHandlingError::ProposalIdError {
|
||||
reason: String::from("proposal id not found"),
|
||||
})?
|
||||
.value
|
||||
.parse::<u64>()
|
||||
.map_err(|_| RequestHandlingError::ProposalIdError {
|
||||
reason: String::from("proposal id could not be parsed to u64"),
|
||||
})?;
|
||||
|
||||
let proposal = self.nyxd_client.query_proposal(proposal_id).await?;
|
||||
if !credential.has_blinded_serial_number(&proposal.description)? {
|
||||
//SW serial number issue
|
||||
return Err(RequestHandlingError::ProposalIdError {
|
||||
reason: String::from("proposal has different serial number"),
|
||||
});
|
||||
}
|
||||
|
||||
let req = nym_api_requests::coconut::OnlineVerifyCredentialBody::new(
|
||||
credential.clone(),
|
||||
proposal_id,
|
||||
self.nyxd_client.address(),
|
||||
);
|
||||
for client in api_clients {
|
||||
self.nyxd_client
|
||||
.grant_allowance(
|
||||
&client.cosmos_address,
|
||||
vec![Coin::new(MAX_FEEGRANT_UNYM, self.mix_denom_base.clone())],
|
||||
SystemTime::now().checked_add(Duration::from_secs(ONE_HOUR_SEC)),
|
||||
// It would be nice to be able to filter deeper, but for now only the msg type filter is avaialable
|
||||
vec![String::from("/cosmwasm.wasm.v1.MsgExecuteContract")],
|
||||
"Create allowance to vote the release of funds".to_string(),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let ret = client.api_client.verify_online_credential(&req).await;
|
||||
self.nyxd_client
|
||||
.revoke_allowance(
|
||||
&client.cosmos_address,
|
||||
"Cleanup the previous allowance for releasing funds".to_string(),
|
||||
revoke_fee.clone(),
|
||||
)
|
||||
.await?;
|
||||
match ret {
|
||||
Ok(res) => {
|
||||
if !res.verification_result {
|
||||
debug!("Validator {} didn't accept the credential. It will probably vote No on the spending proposal", 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.nyxd_client.execute_proposal(proposal_id, None).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -226,7 +324,7 @@ where
|
||||
|
||||
async fn send_credential(pending: &PendingCredential) -> bool {
|
||||
let request =
|
||||
VerifyCredentialBody::new(pending.credential.clone(), pending.address.clone());
|
||||
OfflineVerifyCredentialBody::new(pending.credential.clone(), pending.address.clone());
|
||||
match pending.client.verify_offline_credential(&request).await {
|
||||
Ok(res) => {
|
||||
if !res.verification_result {
|
||||
|
||||
@@ -90,6 +90,7 @@ pub(crate) struct FreshHandler<R, S, St> {
|
||||
rng: R,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
pub(crate) only_coconut_credentials: bool,
|
||||
pub(crate) offline_credential_verification: bool,
|
||||
pub(crate) active_clients_store: ActiveClientsStore,
|
||||
pub(crate) outbound_mix_sender: MixForwardingSender,
|
||||
pub(crate) socket_connection: SocketStream<S>,
|
||||
@@ -111,6 +112,7 @@ where
|
||||
rng: R,
|
||||
conn: S,
|
||||
only_coconut_credentials: bool,
|
||||
offline_credential_verification: bool,
|
||||
outbound_mix_sender: MixForwardingSender,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
storage: St,
|
||||
@@ -121,6 +123,7 @@ where
|
||||
rng,
|
||||
active_clients_store,
|
||||
only_coconut_credentials,
|
||||
offline_credential_verification,
|
||||
outbound_mix_sender,
|
||||
socket_connection: SocketStream::RawTcp(conn),
|
||||
local_identity,
|
||||
|
||||
@@ -18,6 +18,7 @@ pub(crate) struct Listener {
|
||||
address: SocketAddr,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
only_coconut_credentials: bool,
|
||||
offline_credential_verification: bool,
|
||||
pub(crate) ecash_verifier: Arc<EcashVerifier>,
|
||||
}
|
||||
|
||||
@@ -26,12 +27,14 @@ impl Listener {
|
||||
address: SocketAddr,
|
||||
local_identity: Arc<identity::KeyPair>,
|
||||
only_coconut_credentials: bool,
|
||||
offline_credential_verification: bool,
|
||||
ecash_verifier: Arc<EcashVerifier>,
|
||||
) -> Self {
|
||||
Listener {
|
||||
address,
|
||||
local_identity,
|
||||
only_coconut_credentials,
|
||||
offline_credential_verification,
|
||||
ecash_verifier,
|
||||
}
|
||||
}
|
||||
@@ -72,6 +75,7 @@ impl Listener {
|
||||
OsRng,
|
||||
socket,
|
||||
self.only_coconut_credentials,
|
||||
self.offline_credential_verification,
|
||||
outbound_mix_sender.clone(),
|
||||
Arc::clone(&self.local_identity),
|
||||
storage.clone(),
|
||||
|
||||
@@ -231,6 +231,7 @@ impl<St> Gateway<St> {
|
||||
listening_address,
|
||||
Arc::clone(&self.identity_keypair),
|
||||
self.config.gateway.only_coconut_credentials,
|
||||
self.config.gateway.offline_credential_verification,
|
||||
ecash_verifier,
|
||||
)
|
||||
.start(
|
||||
@@ -472,6 +473,7 @@ impl<St> Gateway<St> {
|
||||
self.identity_keypair.public_key().to_bytes(),
|
||||
shutdown.subscribe().named("EcashVerifier"),
|
||||
self.storage.clone(),
|
||||
self.config.gateway.offline_credential_verification,
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -347,7 +347,7 @@ pub async fn verify_online_credential(
|
||||
//SW THIS WILL HAVE TO CHANGE AS WELL
|
||||
vote_yes &= Coin::from(proposed_release_funds)
|
||||
== Coin::new(
|
||||
verify_credential_body.credential().voucher_value() as u128,
|
||||
verify_credential_body.credential().value() as u128,
|
||||
state.mix_denom.clone(),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user