prepare new api endpoint

This commit is contained in:
Simon Wicky
2023-11-23 09:08:53 +01:00
committed by durch
parent 338613362d
commit 2bb130c204
8 changed files with 167 additions and 23 deletions
@@ -9,8 +9,8 @@ use crate::{
ReqwestRpcClient, ValidatorClientError,
};
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, EcashParametersResponse, VerifyCredentialBody,
VerifyCredentialResponse,
BlindSignRequestBody, BlindedSignatureResponse, EcashParametersResponse,
OfflineVerifyCredentialBody, OnlineVerifyCredentialBody, VerifyCredentialResponse,
};
use nym_api_requests::models::{DescribedGateway, MixNodeBondAnnotated};
use nym_api_requests::models::{
@@ -334,11 +334,18 @@ impl NymApiClient {
pub async fn verify_offline_credential(
&self,
request_body: &VerifyCredentialBody,
request_body: &OfflineVerifyCredentialBody,
) -> Result<VerifyCredentialResponse, ValidatorClientError> {
Ok(self.nym_api.verify_offline_credential(request_body).await?)
}
pub async fn verify_online_credential(
&self,
request_body: &OnlineVerifyCredentialBody,
) -> Result<VerifyCredentialResponse, ValidatorClientError> {
Ok(self.nym_api.verify_online_credential(request_body).await?)
}
pub async fn ecash_parameters(&self) -> Result<EcashParametersResponse, ValidatorClientError> {
Ok(self.nym_api.ecash_parameters().await?)
}
@@ -6,8 +6,8 @@ use crate::nym_api::routes::{CORE_STATUS_COUNT, SINCE_ARG};
use async_trait::async_trait;
use http_api_client::{ApiClient, NO_PARAMS};
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, EcashParametersResponse, VerifyCredentialBody,
VerifyCredentialResponse,
BlindSignRequestBody, BlindedSignatureResponse, EcashParametersResponse,
OfflineVerifyCredentialBody, OnlineVerifyCredentialBody, VerifyCredentialResponse,
};
use nym_api_requests::models::{
ComputeRewardEstParam, DescribedGateway, GatewayBondAnnotated, GatewayCoreStatusResponse,
@@ -385,7 +385,7 @@ pub trait NymApiClientExt: ApiClient {
async fn verify_offline_credential(
&self,
request_body: &VerifyCredentialBody,
request_body: &OfflineVerifyCredentialBody,
) -> Result<VerifyCredentialResponse, NymAPIError> {
self.post_json(
&[
@@ -400,6 +400,23 @@ pub trait NymApiClientExt: ApiClient {
.await
}
async fn verify_online_credential(
&self,
request_body: &OnlineVerifyCredentialBody,
) -> Result<VerifyCredentialResponse, NymAPIError> {
self.post_json(
&[
routes::API_VERSION,
routes::COCONUT_ROUTES,
routes::BANDWIDTH,
routes::ECASH_VERIFY_ONLINE_CREDENTIAL,
],
NO_PARAMS,
request_body,
)
.await
}
async fn ecash_parameters(&self) -> Result<EcashParametersResponse, NymAPIError> {
self.get_json(
&[
@@ -17,6 +17,7 @@ pub const BANDWIDTH: &str = "bandwidth";
pub const COCONUT_BLIND_SIGN: &str = "blind-sign";
pub const ECASH_VERIFY_OFFLINE_CREDENTIAL: &str = "verify-offline-credential";
pub const ECASH_VERIFY_ONLINE_CREDENTIAL: &str = "verify-online-credential";
pub const ECASH_PARAMETERS: &str = "ecash-parameters";
pub const STATUS_ROUTES: &str = "status";
+28 -8
View File
@@ -12,24 +12,44 @@ use nym_compact_ecash::{
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Getters, CopyGetters, Clone)]
pub struct VerifyCredentialBody {
pub struct OfflineVerifyCredentialBody {
#[getset(get = "pub")]
credential: EcashCredential,
//#[getset(get = "pub")]
//proposal_id: u64,
#[getset(get = "pub")]
gateway_cosmos_addr: AccountId,
}
impl VerifyCredentialBody {
impl OfflineVerifyCredentialBody {
pub fn new(
credential: EcashCredential,
//proposal_id: u64,
gateway_cosmos_addr: AccountId,
) -> VerifyCredentialBody {
VerifyCredentialBody {
) -> OfflineVerifyCredentialBody {
OfflineVerifyCredentialBody {
credential,
//proposal_id,
gateway_cosmos_addr,
}
}
}
#[derive(Serialize, Deserialize, Getters, CopyGetters, Clone)]
pub struct OnlineVerifyCredentialBody {
#[getset(get = "pub")]
credential: EcashCredential,
#[getset(get = "pub")]
proposal_id: u64,
#[getset(get = "pub")]
gateway_cosmos_addr: AccountId,
}
impl OnlineVerifyCredentialBody {
pub fn new(
credential: EcashCredential,
proposal_id: u64,
gateway_cosmos_addr: AccountId,
) -> OnlineVerifyCredentialBody {
OnlineVerifyCredentialBody {
credential,
proposal_id,
gateway_cosmos_addr,
}
}
+6
View File
@@ -83,6 +83,12 @@ pub enum CoconutError {
#[error("Credentials error - {0}")]
CredentialsError(#[from] nym_credentials::error::Error),
#[error("Incorrect credential proposal description: {reason}")]
IncorrectProposal { reason: String },
#[error("Invalid status of credential: {status}")]
InvalidCredentialStatus { status: String },
#[error("DKG error: {0}")]
DkgError(#[from] DkgError),
+93 -5
View File
@@ -9,11 +9,15 @@ use crate::support::storage::NymApiStorage;
use getset::{CopyGetters, Getters};
use keypair::KeyPair;
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, EcashParametersResponse, VerifyCredentialBody,
VerifyCredentialResponse,
BlindSignRequestBody, BlindedSignatureResponse, EcashParametersResponse,
OfflineVerifyCredentialBody, OnlineVerifyCredentialBody, VerifyCredentialResponse,
};
use nym_coconut_bandwidth_contract_common::spend_credential::{
funds_from_cosmos_msgs, SpendCredentialStatus,
};
use nym_coconut_dkg_common::types::EpochId;
use crate::coconut::helpers::accepted_vote_err;
use nym_compact_ecash::error::CompactEcashError;
use nym_compact_ecash::scheme::keygen::KeyPairAuth;
use nym_compact_ecash::scheme::withdrawal::WithdrawalRequest;
@@ -30,6 +34,7 @@ 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::AccountId;
use nym_validator_client::nyxd::{Coin, Fee};
use rand_07::rngs::OsRng;
use rocket::fairing::AdHoc;
use rocket::serde::json::Json;
@@ -50,6 +55,7 @@ pub(crate) mod tests;
pub struct State {
client: Arc<dyn LocalClient + Send + Sync>,
mix_denom: String,
key_pair: KeyPair,
ecash_params: Parameters,
comm_channel: Arc<dyn APICommunicationChannel + Send + Sync>,
@@ -60,6 +66,7 @@ pub struct State {
impl State {
pub(crate) fn new<C, D>(
client: C,
mix_denom: String,
key_pair: KeyPair,
comm_channel: D,
storage: NymApiStorage,
@@ -76,6 +83,7 @@ impl State {
let ecash_params = Parameters::try_from_bs58(params_base58).unwrap(); //SW Waiting for an actual parameters generation scheme.
Self {
client,
mix_denom,
key_pair,
ecash_params,
comm_channel,
@@ -178,6 +186,7 @@ impl InternalSignRequest {
pub fn stage<C, D>(
client: C,
mix_denom: String,
key_pair: KeyPair,
comm_channel: D,
storage: NymApiStorage,
@@ -186,12 +195,16 @@ impl InternalSignRequest {
C: LocalClient + Send + Sync + 'static,
D: APICommunicationChannel + Send + Sync + 'static,
{
let state = State::new(client, key_pair, comm_channel, storage);
let state = State::new(client, mix_denom, key_pair, comm_channel, storage);
AdHoc::on_ignite("Internal Sign Request Stage", |rocket| async {
rocket.manage(state).mount(
// this format! is so ugly...
format!("/{}/{}/{}", NYM_API_VERSION, COCONUT_ROUTES, BANDWIDTH),
routes![post_blind_sign, verify_offline_credential],
routes![
post_blind_sign,
verify_offline_credential,
verify_online_credential
],
)
})
}
@@ -248,7 +261,7 @@ pub async fn post_blind_sign(
#[post("/verify-offline-credential", data = "<verify_credential_body>")]
pub async fn verify_offline_credential(
verify_credential_body: Json<VerifyCredentialBody>,
verify_credential_body: Json<OfflineVerifyCredentialBody>,
state: &RocketState<State>,
) -> Result<Json<VerifyCredentialResponse>> {
let verification_key = state
@@ -281,6 +294,81 @@ pub async fn verify_offline_credential(
Ok(Json(VerifyCredentialResponse::new(true)))
}
#[post("/verify-online-credential", data = "<verify_credential_body>")]
pub async fn verify_online_credential(
verify_credential_body: Json<OnlineVerifyCredentialBody>,
state: &RocketState<State>,
) -> Result<Json<VerifyCredentialResponse>> {
let proposal_id = *verify_credential_body.proposal_id();
let proposal = state.client.get_proposal(proposal_id).await?;
// Proposal description is the blinded serial number
if !verify_credential_body
.credential()
.has_blinded_serial_number(&proposal.description)?
{
return Err(CoconutError::IncorrectProposal {
reason: String::from("incorrect blinded serial number in description"),
});
}
let proposed_release_funds =
funds_from_cosmos_msgs(proposal.msgs).ok_or(CoconutError::IncorrectProposal {
reason: String::from("action is not to release funds"),
})?;
// 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())
.await?
.spend_credential
.ok_or(CoconutError::InvalidCredentialStatus {
status: String::from("Inexistent"),
})?
.status();
if credential_status != SpendCredentialStatus::InProgress {
return Err(CoconutError::InvalidCredentialStatus {
status: format!("{:?}", credential_status),
});
}
let verification_key = state
.verification_key(*verify_credential_body.credential().epoch_id())
.await?;
let mut vote_yes = verify_credential_body
.credential()
.payment()
.spend_verify(
&state.ecash_params,
&verification_key,
verify_credential_body.credential().pay_info(),
)
.map_err(|_| {
CoconutError::CompactEcashInternalError(CompactEcashError::PaymentVerification)
})?;
//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,
state.mix_denom.clone(),
);
// Vote yes or no on the proposal based on the verification result
let ret = state
.client
.vote_proposal(
proposal_id,
vote_yes,
Some(Fee::new_payer_granter_auto(
None,
None,
Some(verify_credential_body.gateway_cosmos_addr().to_owned()),
)),
)
.await;
accepted_vote_err(ret)?;
Ok(Json(VerifyCredentialResponse::new(vote_yes)))
}
#[derive(Getters, CopyGetters)]
pub struct EcashParameters {
#[getset(get = "pub")]
+8 -4
View File
@@ -5,7 +5,8 @@ use super::InternalSignRequest;
use crate::coconut::error::{CoconutError, Result};
use cosmwasm_std::{to_binary, Addr, CosmosMsg, Decimal, WasmMsg};
use nym_api_requests::coconut::{
BlindSignRequestBody, BlindedSignatureResponse, VerifyCredentialBody, VerifyCredentialResponse,
BlindSignRequestBody, BlindedSignatureResponse, OnlineVerifyCredentialBody,
VerifyCredentialResponse,
};
use nym_coconut::tests::helpers::theta_from_keys_and_attributes;
use nym_coconut::{prepare_blind_sign, ttp_keygen, Base58, BlindedSignature, Parameters};
@@ -880,8 +881,11 @@ async fn verification_of_bandwidth_credential() {
let proposal_id = 42;
// The address is not used, so we can use a duplicate
let gateway_cosmos_addr = validator_address.clone();
let req =
VerifyCredentialBody::new(credential.clone(), proposal_id, gateway_cosmos_addr.clone());
let req = OnlineVerifyCredentialBody::new(
credential.clone(),
proposal_id,
gateway_cosmos_addr.clone(),
);
// Test endpoint with not proposal for the proposal id
let response = client
@@ -1032,7 +1036,7 @@ async fn verification_of_bandwidth_credential() {
0,
);
let bad_req =
VerifyCredentialBody::new(bad_credential, proposal_id, gateway_cosmos_addr.clone());
OnlineVerifyCredentialBody::new(bad_credential, proposal_id, gateway_cosmos_addr.clone());
let response = client
.post(format!(
"/{}/{}/{}/{}",
+1
View File
@@ -70,6 +70,7 @@ pub(crate) async fn setup_rocket(
let comm_channel = QueryCommunicationChannel::new(_nyxd_client.clone());
rocket.attach(InternalSignRequest::stage(
_nyxd_client.clone(),
mix_denom,
coconut_keypair,
comm_channel,
storage.clone().unwrap(),