Skip to content

Commit e0bf7c8

Browse files
Merge #91
91: feat: only renew if we hit the renewal date r=mfontanini a=mfontanini This adds the new `renewable_at` attribute to the nilauth subscription response and also changes the `pay_subscription` function to verify that you can renew before doing so, as you otherwise lose your payment. Co-authored-by: Matias Fontanini <[email protected]>
2 parents 2bf2ed7 + 70573b1 commit e0bf7c8

File tree

4 files changed

+29
-25
lines changed

4 files changed

+29
-25
lines changed

libs/nilauth-client/examples/mint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
1010
let mut payer = NillionChainClient::new("http://localhost:26648".to_string(), payment_key).await?;
1111
let client = DefaultNilauthClient::new("http://127.0.0.1:30921")?;
1212
let key = SecretKey::random(&mut rand::thread_rng());
13-
client.pay_subscription(&mut payer, &key.public_key()).await?;
13+
client.pay_subscription(&mut payer, &key).await?;
1414
let token = client.request_token(&key).await?;
1515
println!("{token}");
1616
Ok(())

libs/nilauth-client/src/client.rs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use nillion_nucs::{
77
k256::{
88
ecdsa::{signature::Signer, Signature, SigningKey},
99
sha2::{Digest, Sha256},
10-
PublicKey, SecretKey,
10+
SecretKey,
1111
},
1212
token::{Did, ProofHash, TokenBody},
1313
};
@@ -44,7 +44,7 @@ pub trait NilauthClient {
4444
async fn pay_subscription(
4545
&self,
4646
payments_client: &mut NillionChainClient,
47-
key: &PublicKey,
47+
key: &SecretKey,
4848
) -> Result<TxHash, PaySubscriptionError>;
4949

5050
/// Get our subscription status.
@@ -88,6 +88,9 @@ pub enum PaySubscriptionError {
8888
#[error("fetching subscription cost: {0}")]
8989
Cost(#[from] SubscriptionCostError),
9090

91+
#[error("fetching subscription status: {0}")]
92+
Status(#[from] SubscriptionStatusError),
93+
9194
#[error("serde: {0}")]
9295
Serde(#[from] serde_json::Error),
9396

@@ -103,6 +106,9 @@ pub enum PaySubscriptionError {
103106
#[error("server could not validate payment: {tx_hash}")]
104107
PaymentValidation { tx_hash: TxHash, payload: String },
105108

109+
#[error("cannot renew subscription before {0}")]
110+
CannotRenewYet(DateTime<Utc>),
111+
106112
#[error("request: {0:?}")]
107113
Request(RequestError),
108114
}
@@ -279,8 +285,15 @@ impl NilauthClient for DefaultNilauthClient {
279285
async fn pay_subscription(
280286
&self,
281287
payments_client: &mut NillionChainClient,
282-
key: &PublicKey,
288+
key: &SecretKey,
283289
) -> Result<TxHash, PaySubscriptionError> {
290+
let subscription = self.subscription_status(key).await?;
291+
match subscription.details {
292+
Some(details) if details.renewable_at > Utc::now() => {
293+
return Err(PaySubscriptionError::CannotRenewYet(details.renewable_at));
294+
}
295+
_ => (),
296+
};
284297
let about = self.about().await?;
285298
let cost = self.subscription_cost().await?;
286299
let payload = ValidatePaymentRequestPayload { nonce: rand::random(), service_public_key: about.public_key };
@@ -291,7 +304,8 @@ impl NilauthClient for DefaultNilauthClient {
291304
.await
292305
.map_err(|e| PaySubscriptionError::Payment(e.to_string()))?;
293306

294-
let public_key = key.to_sec1_bytes().as_ref().try_into().map_err(|_| PaySubscriptionError::InvalidPublicKey)?;
307+
let public_key =
308+
key.public_key().to_sec1_bytes().as_ref().try_into().map_err(|_| PaySubscriptionError::InvalidPublicKey)?;
295309
let url = self.make_url("/api/v1/payments/validate");
296310
let request =
297311
ValidatePaymentRequest { tx_hash: tx_hash.clone(), payload: payload.as_bytes().to_vec(), public_key };
@@ -511,4 +525,8 @@ pub struct SubscriptionDetails {
511525
/// The timestamp at which the subscription expires.
512526
#[serde(with = "chrono::serde::ts_seconds")]
513527
pub expires_at: DateTime<Utc>,
528+
529+
/// The timestamp at which the subscription can be renewed.
530+
#[serde(with = "chrono::serde::ts_seconds")]
531+
pub renewable_at: DateTime<Utc>,
514532
}

tools/nillion/src/runner.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,7 +755,7 @@ impl Runner {
755755
nilchain_client.set_gas_price(gas_price);
756756
}
757757

758-
let tx_hash = nilauth_client.pay_subscription(&mut nilchain_client, &key.public_key()).await?;
758+
let tx_hash = nilauth_client.pay_subscription(&mut nilchain_client, &key).await?;
759759
Ok(Box::new(Output { tx_hash: tx_hash.to_string() }))
760760
}
761761

tools/nillion/src/serialize.rs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ pub struct NoOutput;
1515
#[derive(Serialize)]
1616
pub struct ErrorOutput {
1717
error: String,
18-
#[serde(skip_serializing_if = "Option::is_none")]
19-
cause: Option<Vec<String>>,
18+
#[serde(skip_serializing_if = "Vec::is_empty")]
19+
causes: Vec<String>,
2020
}
2121

2222
pub fn serialize_output(format: &CommandOutputFormat, data: &dyn SerializeAsAny) -> Result<String> {
@@ -37,22 +37,8 @@ pub fn serialize_output(format: &CommandOutputFormat, data: &dyn SerializeAsAny)
3737
}
3838

3939
pub fn serialize_error(format: &CommandOutputFormat, e: &anyhow::Error) -> String {
40-
let main_error = e.to_string();
41-
let mut causes: Vec<String> = e.chain().skip(1).map(|cause| cause.to_string()).collect();
42-
43-
let error = if causes.is_empty() {
44-
if let Some((first_part, second_part)) = main_error.split_once(':') {
45-
causes.push(second_part.trim().to_string());
46-
first_part.trim().to_string()
47-
} else {
48-
main_error
49-
}
50-
} else {
51-
main_error
52-
};
53-
54-
let cause = (!causes.is_empty()).then_some(causes);
55-
56-
let error_response = ErrorOutput { error, cause };
40+
let error = e.to_string();
41+
let causes: Vec<String> = e.chain().skip(1).map(|cause| cause.to_string()).collect();
42+
let error_response = ErrorOutput { error, causes };
5743
serialize_output(format, &error_response).unwrap_or_else(|_| format!("{e:#}"))
5844
}

0 commit comments

Comments
 (0)