mintd: sort pks by amount in /v1/keys

This commit is contained in:
ok300
2024-10-14 17:08:40 +02:00
committed by thesimplekid
parent e0f5344e8f
commit 4efeb7d1c5
3 changed files with 67 additions and 13 deletions

View File

@@ -4,8 +4,9 @@
use std::cmp::Ordering;
use std::fmt;
use std::str::FromStr;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use thiserror::Error;
use crate::nuts::CurrencyUnit;
@@ -214,6 +215,54 @@ impl std::ops::Div for Amount {
}
}
/// String wrapper for an [Amount].
///
/// It ser-/deserializes the inner [Amount] to a string, while at the same time using the [u64]
/// value of the [Amount] for comparison and ordering. This helps automatically sort the keys of
/// a [BTreeMap] when [AmountStr] is used as key.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AmountStr(Amount);
impl AmountStr {
pub(crate) fn from(amt: Amount) -> Self {
Self(amt)
}
}
impl PartialOrd<Self> for AmountStr {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for AmountStr {
fn cmp(&self, other: &Self) -> Ordering {
self.0.cmp(&other.0)
}
}
impl<'de> Deserialize<'de> for AmountStr {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
u64::from_str(&s)
.map(Amount)
.map(Self)
.map_err(serde::de::Error::custom)
}
}
impl Serialize for AmountStr {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&self.0.to_string())
}
}
/// Kinds of targeting that are supported
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default, Serialize, Deserialize)]
pub enum SplitTarget {

View File

@@ -16,7 +16,7 @@ mod secret_key;
pub use self::public_key::PublicKey;
pub use self::secret_key::SecretKey;
use super::nut02::KeySet;
use crate::amount::Amount;
use crate::amount::{Amount, AmountStr};
/// Nut01 Error
#[derive(Debug, Error)]
@@ -37,16 +37,20 @@ pub enum Error {
},
}
/// Mint Keys [NUT-01]
/// Mint public keys per amount.
///
/// This is a variation of [MintKeys] that only exposes the public keys.
///
/// See [NUT-01]
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
pub struct Keys(BTreeMap<String, PublicKey>);
pub struct Keys(BTreeMap<AmountStr, PublicKey>);
impl From<MintKeys> for Keys {
fn from(keys: MintKeys) -> Self {
Self(
keys.0
.iter()
.map(|(amount, keypair)| (amount.to_string(), keypair.public_key))
.into_iter()
.map(|(amount, keypair)| (AmountStr::from(amount), keypair.public_key))
.collect(),
)
}
@@ -55,25 +59,25 @@ impl From<MintKeys> for Keys {
impl Keys {
/// Create new [`Keys`]
#[inline]
pub fn new(keys: BTreeMap<String, PublicKey>) -> Self {
pub fn new(keys: BTreeMap<AmountStr, PublicKey>) -> Self {
Self(keys)
}
/// Get [`Keys`]
#[inline]
pub fn keys(&self) -> &BTreeMap<String, PublicKey> {
pub fn keys(&self) -> &BTreeMap<AmountStr, PublicKey> {
&self.0
}
/// Get [`PublicKey`] for [`Amount`]
#[inline]
pub fn amount_key(&self, amount: Amount) -> Option<PublicKey> {
self.0.get(&amount.to_string()).copied()
self.0.get(&AmountStr::from(amount)).copied()
}
/// Iterate through the (`Amount`, `PublicKey`) entries in the Map
#[inline]
pub fn iter(&self) -> impl Iterator<Item = (&String, &PublicKey)> {
pub fn iter(&self) -> impl Iterator<Item = (&AmountStr, &PublicKey)> {
self.0.iter()
}
}
@@ -87,7 +91,7 @@ pub struct KeysResponse {
pub keysets: Vec<KeySet>,
}
/// Mint keys
/// Mint key pairs per amount
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct MintKeys(BTreeMap<Amount, MintKeyPair>);

View File

@@ -25,6 +25,7 @@ use thiserror::Error;
use super::nut01::Keys;
#[cfg(feature = "mint")]
use super::nut01::{MintKeyPair, MintKeys};
use crate::amount::AmountStr;
use crate::nuts::nut00::CurrencyUnit;
use crate::util::hex;
#[cfg(feature = "mint")]
@@ -197,9 +198,9 @@ impl From<&Keys> for Id {
5 - prefix it with a keyset ID version byte
*/
let mut keys: Vec<(&String, &super::PublicKey)> = map.iter().collect();
let mut keys: Vec<(&AmountStr, &super::PublicKey)> = map.iter().collect();
keys.sort_by_key(|(k, _v)| u64::from_str(k).unwrap());
keys.sort_by_key(|(amt, _v)| *amt);
let pubkeys_concat: Vec<u8> = keys
.iter()