Skip to main content

worgl_sdk/
holder.rs

1//! A holder's notes, the keys it has handed out, and the transfers it has
2//! signed but not seen land.
3
4use std::cmp::Reverse;
5use std::collections::{HashSet, VecDeque};
6
7use serde::{Deserialize, Serialize};
8use worgl::{Denominations, HolderKey, Note, Output, PolicyError, PublicKey, TransferRequest};
9
10use crate::mint::{MintView, NoteState};
11use crate::payment::{Payment, PaymentRequest, ScheduledTransfer, Spacing};
12use crate::random;
13
14/// Most notes one payment request may ask for.
15pub const MAX_REQUESTED_NOTES: usize = 256;
16
17/// How many of the keys it paid last a holder remembers, so as to refuse
18/// paying one of them again: the notes of four requests of the most notes a
19/// request may ask for, or of hundreds of usual ones, for about 67 KiB of
20/// the saved store. A key paid by a transfer still outgoing, or by a payment
21/// the holder still keeps, is refused however long ago it was paid.
22pub const PAID_KEYS_KEPT: usize = 4 * MAX_REQUESTED_NOTES;
23
24/// Version of the format [`Holder::to_json`] writes for a store that holds
25/// unconfirmed change or notes owed to payees. A reader of format 1 skips
26/// fields it does not know, so it would drop those unseen and lose their
27/// value. A store without them is still written as format 1, which such a
28/// reader opens, missing only the payments kept and the keys paid last.
29const FORMAT: u32 = 2;
30
31/// Seconds before a scheduled rotation by which the transfers that
32/// [`Holder::refresh`] and [`Holder::due_resends`] plan are due, or half the
33/// time left when that is shorter. A plan made at or past the rotation's
34/// time, which the mint has not made yet as far as its info says, has them
35/// all due at once. A payer should settle a payment this long before the
36/// rotation that drops a note it spends.
37pub const REFRESH_MARGIN_SECS: u64 = 300;
38
39/// Seconds over which refreshes are spread when the mint has no schedule.
40const UNSCHEDULED_REFRESH_SECS: u64 = 60;
41
42/// The notes one holder owns, with the one-time key of each, plus the keys
43/// it has handed out, the transfers it has signed but not yet seen land, and
44/// the payments it made until it is done with them.
45///
46/// It keeps the privacy rules without being told: a fresh key for every
47/// note it expects, never two notes in one transfer, transfers of one
48/// payment and refreshes spread out in time, and outputs in random order.
49/// It does no networking: submit the transfers it makes to the mint, and
50/// give it the mint's answers.
51///
52/// Notes are bearer: whoever holds this store holds the money. Save it with
53/// [`to_json`](Self::to_json), encrypted at rest, after every change.
54#[derive(Debug, Clone, Default)]
55pub struct Holder {
56    notes: Vec<Held>,
57    expected: Vec<Expected>,
58    outgoing: Vec<Outgoing>,
59    unconfirmed: Vec<Unconfirmed>,
60    payments: Vec<MadePayment>,
61    /// The keys this holder paid last, oldest first.
62    paid: VecDeque<PublicKey>,
63}
64
65/// A note and the key that spends it.
66#[derive(Debug, Clone, Serialize, Deserialize)]
67struct Held {
68    note: Note,
69    #[serde(with = "secret")]
70    key: HolderKey,
71}
72
73/// A key handed out for a note of `amount` from `mint`, not yet received.
74#[derive(Debug, Clone, Serialize, Deserialize)]
75struct Expected {
76    mint: PublicKey,
77    amount: u64,
78    #[serde(with = "secret")]
79    key: HolderKey,
80}
81
82/// A transfer this holder signed and has not yet seen answered, with the
83/// note it spends.
84#[derive(Debug, Clone, Serialize, Deserialize)]
85struct Outgoing {
86    request: TransferRequest,
87    spends: Held,
88}
89
90/// The key for a note of change from a transfer this holder dropped or
91/// cancelled. The note comes only if the counterparty hands it over, and it
92/// would sit in `generation`, so it is worthless once that is dropped.
93#[derive(Debug, Clone, Serialize, Deserialize)]
94struct Unconfirmed {
95    change: Expected,
96    generation: u64,
97}
98
99/// A payment this holder made, kept while one of its transfers is
100/// [outgoing](Holder::outgoing) or the holder keeps notes owed to the payee
101/// for it.
102#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
103pub struct MadePayment {
104    /// The request it answers.
105    pub request: PaymentRequest,
106    /// The payment as [`Holder::pay`] returned it, to send again to a payee
107    /// who lost it. A transfer [cancelled](Holder::cancel) or
108    /// [forgotten](Holder::forget) leaves it, so it is never handed out
109    /// again; the payment then no longer pays the whole request, which
110    /// [`PaymentRequest::check`] tells, and the payee would refuse it.
111    pub payment: Payment,
112    /// The payee's notes from the mint's answers this holder got itself:
113    /// each time it [settles](Holder::settle) one of the payment's
114    /// transfers, whether a resend or its own submission of the payment got
115    /// the answer. It cannot tell whether the payee submitted the payment
116    /// and has them already, so it keeps them for the payee until they are
117    /// handed over ([`forget_owed`](Holder::forget_owed)) or their layer is
118    /// dropped ([`prune`](Holder::prune)).
119    pub owed: Vec<Note>,
120}
121
122/// Value a holder has at one mint, by what it can do now.
123#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
124pub struct Balance {
125    /// Can be spent now.
126    pub spendable: u128,
127    /// In the last layer: spendable after the next rotation.
128    pub frozen: u128,
129    /// Part of the above that dies at the next rotation unless refreshed.
130    pub expiring: u128,
131    /// In notes the view cannot place: read the mint's info again.
132    pub unknown: u128,
133    /// In notes spent by transfers not yet answered.
134    pub outgoing: u128,
135    /// Expected from keys handed out and not yet paid.
136    pub expected: u128,
137    /// Change of transfers dropped or cancelled, which comes only if the
138    /// counterparty hands it over: see [`Holder::forget`].
139    #[serde(default)]
140    pub unconfirmed: u128,
141}
142
143/// A payment request cannot be made.
144#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
145pub enum RequestError {
146    /// The amount is zero.
147    #[error("the amount must be positive")]
148    Zero,
149    /// The amount cannot be split into the mint's denominations.
150    #[error("{0} cannot be split into the mint's denominations")]
151    Denominations(u64),
152    /// It would take more than [`MAX_REQUESTED_NOTES`] notes.
153    #[error("the request would need more than {MAX_REQUESTED_NOTES} notes")]
154    TooManyNotes,
155}
156
157/// A payment cannot be made.
158#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
159pub enum PayError {
160    /// The request is for another mint than the view.
161    #[error("the request is for another mint")]
162    WrongMint,
163    /// The request asks for nothing.
164    #[error("the request asks for nothing")]
165    Empty,
166    /// The request asks for a note of an amount that is not one of the
167    /// mint's denominations, such as 0. The mint would refuse the transfer.
168    #[error("the request asks for a note of {0}, which is not one of the mint's denominations")]
169    Denomination(u64),
170    /// The request asks for a note to a key this holder has paid already: by
171    /// a transfer still outgoing, by a payment it keeps, among the last
172    /// [`PAID_KEYS_KEPT`] keys it paid, or twice in the request. The payee
173    /// would keep only one of two notes to one key, and the mint would see
174    /// the key twice. Paying again takes a new request.
175    #[error("the request asks for a note to {0}, which this holder has paid already")]
176    Paid(PublicKey),
177    /// Not enough value is spendable now. Frozen notes become spendable at
178    /// the next rotation.
179    #[error("{spendable} is spendable now and {needed} is needed")]
180    Unaffordable {
181        /// Value spendable now.
182        spendable: u128,
183        /// Value asked for.
184        needed: u128,
185    },
186    /// Enough value is spendable, but in notes too small for the notes the
187    /// request asks for. Ask the payee for a request with smaller notes; see
188    /// [`Holder::request_at_most`].
189    #[error(
190        "the requested notes do not fit the spendable notes; the largest spendable note is {largest}"
191    )]
192    Fragmented {
193        /// The largest spendable note.
194        largest: u64,
195    },
196    /// The change would take more notes than one transfer may create.
197    #[error("the change does not fit in {max_outputs} notes per transfer")]
198    TooManyOutputs {
199        /// The mint's limit.
200        max_outputs: u8,
201    },
202    /// A planned transfer breaks the mint's policy. Plans follow the policy,
203    /// so this means a bug.
204    #[error("a planned transfer breaks the mint's policy: {0}")]
205    Policy(PolicyError),
206    /// Signing failed. The library refuses only malformed inputs, so this
207    /// means the store is corrupt.
208    #[error(transparent)]
209    Sign(#[from] worgl::Error),
210}
211
212/// A saved store cannot be read.
213#[derive(Debug, thiserror::Error)]
214pub enum LoadError {
215    /// It is not a saved store.
216    #[error("not a saved note store: {0}")]
217    Json(#[from] serde_json::Error),
218    /// It was written by a newer SDK.
219    #[error("saved in format {0}, which this SDK does not read")]
220    Format(u32),
221}
222
223#[derive(Serialize, Deserialize)]
224struct Saved {
225    format: u32,
226    notes: Vec<Held>,
227    expected: Vec<Expected>,
228    outgoing: Vec<Outgoing>,
229    // Missing from stores of format 1 written before format 2 existed.
230    #[serde(default)]
231    unconfirmed: Vec<Unconfirmed>,
232    #[serde(default)]
233    payments: Vec<MadePayment>,
234    #[serde(default)]
235    paid: VecDeque<PublicKey>,
236}
237
238impl Holder {
239    /// An empty store.
240    pub fn new() -> Self {
241        Self::default()
242    }
243
244    /// Asks for `amount` from `mint`, as the fewest notes its denominations
245    /// allow, each to a fresh key.
246    pub fn request(
247        &mut self,
248        mint: &MintView,
249        amount: u64,
250    ) -> Result<PaymentRequest, RequestError> {
251        self.request_notes(mint, amount, None)
252    }
253
254    /// Asks for `amount` from `mint` in notes of at most `largest` each. A
255    /// payer whose notes are small answers [`PayError::Fragmented`] to a
256    /// plain [`request`](Self::request); this request it can pay.
257    pub fn request_at_most(
258        &mut self,
259        mint: &MintView,
260        amount: u64,
261        largest: u64,
262    ) -> Result<PaymentRequest, RequestError> {
263        self.request_notes(mint, amount, Some(largest))
264    }
265
266    fn request_notes(
267        &mut self,
268        mint: &MintView,
269        amount: u64,
270        largest: Option<u64>,
271    ) -> Result<PaymentRequest, RequestError> {
272        if amount == 0 {
273            return Err(RequestError::Zero);
274        }
275        let amounts = match split(
276            &mint.policy.denominations,
277            amount,
278            largest,
279            MAX_REQUESTED_NOTES,
280        ) {
281            Ok(amounts) => amounts,
282            Err(Split::Inexact) => return Err(RequestError::Denominations(amount)),
283            Err(Split::TooMany) => return Err(RequestError::TooManyNotes),
284        };
285        let mut outputs = Vec::with_capacity(amounts.len());
286        for amount in amounts {
287            let key = HolderKey::generate();
288            outputs.push(Output {
289                amount,
290                holder: key.public_key(),
291            });
292            self.expected.push(Expected {
293                mint: mint.issuer,
294                amount,
295                key,
296            });
297        }
298        random::shuffle(&mut outputs);
299        Ok(PaymentRequest {
300            mint: mint.issuer,
301            outputs,
302        })
303    }
304
305    /// Stops expecting the notes a request asked for, for a request that
306    /// will not be paid.
307    pub fn withdraw(&mut self, request: &PaymentRequest) {
308        self.expected.retain(|e| {
309            !request
310                .outputs
311                .iter()
312                .any(|o| o.holder == e.key.public_key())
313        });
314    }
315
316    /// Answers a payment request with signed transfers.
317    ///
318    /// It prefers one note that covers everything, paid in one transfer
319    /// with the change back to fresh keys. Otherwise it spends several
320    /// notes, one per transfer, largest first, and spaces the transfers by
321    /// `spacing`. Only notes [spendable](NoteState::Spendable) under `mint`
322    /// are used. The notes spent leave the store and wait among the
323    /// [outgoing](Self::outgoing) transfers until [`settle`](Self::settle)
324    /// or [`take_answers`](Self::take_answers) sees them answered, and the
325    /// payment is kept among the [payments](Self::payments).
326    ///
327    /// Before signing anything, it refuses a request for a note the mint
328    /// would not make, of an amount outside its denominations
329    /// ([`PayError::Denomination`]), and a request for a note to a key it
330    /// has paid already ([`PayError::Paid`]), such as the same request
331    /// twice. Each planned transfer is checked against the mint's policy as
332    /// well.
333    pub fn pay(
334        &mut self,
335        mint: &MintView,
336        request: &PaymentRequest,
337        spacing: Spacing,
338    ) -> Result<Payment, PayError> {
339        if request.mint != mint.issuer {
340            return Err(PayError::WrongMint);
341        }
342        if request.outputs.is_empty() {
343            return Err(PayError::Empty);
344        }
345        let mut asked = HashSet::new();
346        for output in &request.outputs {
347            if !mint.policy.denominations.contains(output.amount) {
348                return Err(PayError::Denomination(output.amount));
349            }
350            if !asked.insert(output.holder) || self.has_paid(&output.holder) {
351                return Err(PayError::Paid(output.holder));
352            }
353        }
354        let plan = self.plan(mint, request)?;
355        for part in &plan {
356            let outputs: Vec<u64> = part
357                .paid
358                .iter()
359                .map(|o| o.amount)
360                .chain(part.change.iter().copied())
361                .collect();
362            mint.policy
363                .check_transfer(&[self.notes[part.note].note.amount()], &outputs)
364                .map_err(PayError::Policy)?;
365        }
366        let mut transfers = Vec::with_capacity(plan.len());
367        let mut expected = Vec::new();
368        let mut after_secs = 0u64;
369        for (n, part) in plan.iter().enumerate() {
370            let held = &self.notes[part.note];
371            let mut outputs = part.paid.clone();
372            for &amount in &part.change {
373                let key = HolderKey::generate();
374                outputs.push(Output {
375                    amount,
376                    holder: key.public_key(),
377                });
378                expected.push(Expected {
379                    mint: mint.issuer,
380                    amount,
381                    key,
382                });
383            }
384            random::shuffle(&mut outputs);
385            let request = TransferRequest::sign(&[(held.note, &held.key)], outputs)?;
386            if n > 0 {
387                after_secs = after_secs.saturating_add(spacing.gap());
388            }
389            transfers.push(ScheduledTransfer {
390                after_secs,
391                request,
392            });
393        }
394        // Nothing failed: move the spent notes out.
395        for (part, scheduled) in plan.iter().zip(&transfers) {
396            self.outgoing.push(Outgoing {
397                request: scheduled.request.clone(),
398                spends: self.notes[part.note].clone(),
399            });
400        }
401        let mut used: Vec<usize> = plan.iter().map(|part| part.note).collect();
402        used.sort_unstable_by_key(|&i| Reverse(i));
403        for i in used {
404            self.notes.remove(i);
405        }
406        self.expected.extend(expected);
407        let payment = Payment {
408            mint: mint.issuer,
409            transfers,
410        };
411        self.payments.push(MadePayment {
412            request: request.clone(),
413            payment: payment.clone(),
414            owed: Vec::new(),
415        });
416        self.remember_paid(request.outputs.iter().map(|o| o.holder));
417        Ok(payment)
418    }
419
420    /// Whether this holder has paid a note to `key`: by an outgoing
421    /// transfer, by a payment it keeps, or among the last keys it paid.
422    fn has_paid(&self, key: &PublicKey) -> bool {
423        self.paid.contains(key)
424            || self
425                .outgoing
426                .iter()
427                .any(|o| o.request.outputs.iter().any(|out| out.holder == *key))
428            || self
429                .payments
430                .iter()
431                .any(|p| p.request.outputs.iter().any(|out| out.holder == *key))
432    }
433
434    /// Adds `keys` to the keys paid last, forgetting the oldest beyond
435    /// [`PAID_KEYS_KEPT`].
436    fn remember_paid(&mut self, keys: impl IntoIterator<Item = PublicKey>) {
437        self.paid.extend(keys);
438        let excess = self.paid.len().saturating_sub(PAID_KEYS_KEPT);
439        self.paid.drain(..excess);
440    }
441
442    /// Chooses which note pays which requested outputs.
443    fn plan(&self, mint: &MintView, request: &PaymentRequest) -> Result<Vec<Part>, PayError> {
444        let max_outputs = usize::from(mint.policy.max_outputs.max(1));
445        let denominations = &mint.policy.denominations;
446        let change_of = |room: u64| split(denominations, room, None, max_outputs).ok();
447        let needed = request.amount();
448        let mut spendable: Vec<usize> = (0..self.notes.len())
449            .filter(|&i| matches!(mint.state(&self.notes[i].note), NoteState::Spendable { .. }))
450            .collect();
451        spendable.sort_by_key(|&i| self.notes[i].note.amount());
452        let amount = |i: usize| self.notes[i].note.amount();
453        let total: u128 = spendable.iter().map(|&i| u128::from(amount(i))).sum();
454        if total < needed {
455            return Err(PayError::Unaffordable {
456                spendable: total,
457                needed,
458            });
459        }
460
461        // The smallest single note that covers everything, change included.
462        for &i in &spendable {
463            if u128::from(amount(i)) < needed {
464                continue;
465            }
466            let room = (u128::from(amount(i)) - needed) as u64;
467            if let Some(change) = change_of(room)
468                && request.outputs.len() + change.len() <= max_outputs
469            {
470                return Ok(vec![Part {
471                    note: i,
472                    paid: request.outputs.clone(),
473                    change,
474                }]);
475            }
476        }
477
478        // Otherwise the largest notes first, each paying the largest
479        // requested outputs it can hold.
480        let mut wanted = request.outputs.clone();
481        wanted.sort_by_key(|o| Reverse(o.amount));
482        let mut notes = spendable.clone();
483        let mut plan = Vec::new();
484        let mut change_limited = false;
485        while !wanted.is_empty() {
486            let Some(i) = notes.pop() else { break };
487            let mut room = amount(i);
488            let mut paid = Vec::new();
489            let mut k = 0;
490            while k < wanted.len() && paid.len() < max_outputs {
491                if wanted[k].amount <= room {
492                    room -= wanted[k].amount;
493                    paid.push(wanted.remove(k));
494                } else {
495                    k += 1;
496                }
497            }
498            // Give back the smallest outputs until the change fits.
499            let change = loop {
500                match change_of(room) {
501                    Some(change) if paid.len() + change.len() <= max_outputs => break Some(change),
502                    _ if paid.is_empty() => break None,
503                    _ => {
504                        change_limited = true;
505                        let out: Output = paid.pop().expect("paid is not empty");
506                        room += out.amount;
507                        wanted.push(out);
508                    }
509                }
510            };
511            wanted.sort_by_key(|o| Reverse(o.amount));
512            if let Some(change) = change
513                && !paid.is_empty()
514            {
515                plan.push(Part {
516                    note: i,
517                    paid,
518                    change,
519                });
520            }
521        }
522        if !wanted.is_empty() {
523            let max_outputs = mint.policy.max_outputs;
524            let largest = spendable.last().map_or(0, |&i| amount(i));
525            return Err(if change_limited {
526                PayError::TooManyOutputs { max_outputs }
527            } else {
528                PayError::Fragmented { largest }
529            });
530        }
531        Ok(plan)
532    }
533
534    /// Takes in the notes of a mint's answer that were made for this
535    /// holder's keys: from a payment it received, its own change, unconfirmed
536    /// change included, or a refresh. Notes for other keys are ignored, and a
537    /// note already held is not taken twice. Returns the value taken in.
538    ///
539    /// Give it notes from the mint's own answer, or check them first with
540    /// [`Note::verify`]: the store does not check signatures.
541    pub fn absorb(&mut self, notes: &[Note]) -> u128 {
542        let mut taken = 0;
543        for note in notes {
544            if self.notes.iter().any(|h| h.note == *note) {
545                continue;
546            }
547            let pays = |e: &Expected| {
548                e.mint == *note.issuer()
549                    && e.amount == note.amount()
550                    && e.key.public_key() == *note.holder()
551            };
552            let key = if let Some(i) = self.expected.iter().position(pays) {
553                self.expected.swap_remove(i).key
554            } else if let Some(i) = self.unconfirmed.iter().position(|u| pays(&u.change)) {
555                self.unconfirmed.swap_remove(i).change.key
556            } else {
557                continue;
558            };
559            self.notes.push(Held { note: *note, key });
560            taken += u128::from(note.amount());
561        }
562        taken
563    }
564
565    /// The notes of a mint's answers made for neither a note this holder
566    /// holds nor a key it expects, unconfirmed change included: the
567    /// counterparty's. A payee hands them back to the payer, whose change
568    /// they are, and a payer that submitted a payment hands them to the
569    /// payee. They tell the counterparty nothing about this holder's notes:
570    /// they are bound to the counterparty's own keys.
571    pub fn theirs(&self, notes: &[Note]) -> Vec<Note> {
572        notes
573            .iter()
574            .filter(|note| {
575                let holder = note.holder();
576                !self.notes.iter().any(|h| h.note.holder() == holder)
577                    && !self.expected.iter().any(|e| e.key.public_key() == *holder)
578                    && !self
579                        .unconfirmed
580                        .iter()
581                        .any(|u| u.change.key.public_key() == *holder)
582            })
583            .copied()
584            .collect()
585    }
586
587    /// Records the mint's answer to one of this holder's transfers: the
588    /// transfer stops being outgoing and its notes for this holder are taken
589    /// in. Returns the value taken in.
590    ///
591    /// When the transfer was outgoing and is part of a payment this holder
592    /// made, the answer's notes for the payee are kept for it, among the
593    /// payment's [owed](MadePayment::owed) notes: a resend may be what
594    /// carried out the payment.
595    pub fn settle(&mut self, request: &TransferRequest, answer: &[Note]) -> u128 {
596        let before = self.outgoing.len();
597        self.outgoing.retain(|o| o.request != *request);
598        if self.outgoing.len() < before
599            && let Some(made) = self
600                .payments
601                .iter_mut()
602                .find(|p| p.payment.transfers.iter().any(|t| t.request == *request))
603        {
604            for note in answer {
605                let payee = note.issuer() == &made.payment.mint
606                    && made
607                        .request
608                        .outputs
609                        .iter()
610                        .any(|o| o.holder == *note.holder() && o.amount == note.amount());
611                if payee && !made.owed.contains(note) {
612                    made.owed.push(*note);
613                }
614            }
615        }
616        let taken = self.absorb(answer);
617        self.tidy();
618        taken
619    }
620
621    /// Takes in notes the counterparty handed over from the mint's answers,
622    /// as [`absorb`](Self::absorb) does, then settles each outgoing transfer
623    /// that pays this holder notes, once it holds every one of them with the
624    /// transfer's mint, amount and key. Returns the value taken in.
625    ///
626    /// A transfer that pays this holder nothing, such as a payment that
627    /// needs no change, stays outgoing: only [resending](Self::resend) it
628    /// shows it was applied.
629    ///
630    /// Give it notes from the mint's own answer, or check them first with
631    /// [`Note::verify`]: the store does not check signatures, and a forged
632    /// note would settle a transfer as surely as a real one.
633    ///
634    /// A signature shows that the mint issued a note, not which transfer it
635    /// answers. A counterparty holding the transfer can pay the same keys
636    /// from notes of its own and leave the transfer unsubmitted: it then
637    /// stops being outgoing though the mint never applied it, and nothing
638    /// resends it before its note dies. A hand-back settles a transfer only
639    /// as surely as the counterparty submitted it; to be sure, ask the mint
640    /// (`POST /v1/verify`) whether the note the transfer spends is spent
641    /// before taking the notes in.
642    pub fn take_answers(&mut self, notes: &[Note]) -> u128 {
643        let taken = self.absorb(notes);
644        let (held, expected) = (&self.notes, &self.expected);
645        self.outgoing.retain(|o| {
646            let mint = o.spends.note.issuer();
647            let mut own = o
648                .request
649                .outputs
650                .iter()
651                .filter(|out| {
652                    held.iter().any(|h| h.note.holder() == &out.holder)
653                        || expected.iter().any(|e| e.key.public_key() == out.holder)
654                })
655                .peekable();
656            let answered = own.peek().is_some()
657                && own.all(|out| {
658                    held.iter().any(|h| {
659                        h.note.issuer() == mint
660                            && h.note.amount() == out.amount
661                            && h.note.holder() == &out.holder
662                    })
663                });
664            !answered
665        });
666        self.tidy();
667        taken
668    }
669
670    /// Drops an outgoing transfer whose note is gone, such as one the mint
671    /// refused because its note was already spent or had expired: had the
672    /// mint applied this transfer and still kept its answer, it would have
673    /// answered with the notes (see [`resend`](Self::resend)). Returns
674    /// whether the transfer was outgoing.
675    ///
676    /// The mint may have applied it all the same, so the keys of its change
677    /// stay, as unconfirmed change: change the counterparty hands over later
678    /// is still taken in by [`take_answers`](Self::take_answers) or
679    /// [`absorb`](Self::absorb), until the layer it would sit in is dropped
680    /// ([`prune`](Self::prune)). The transfer leaves its
681    /// [payment](MadePayment::payment).
682    pub fn forget(&mut self, request: &TransferRequest) -> bool {
683        self.end(request).is_some()
684    }
685
686    /// Takes back the note of an outgoing transfer, for one the mint never
687    /// applied, such as one nobody else holds that will never be submitted.
688    /// The keys of its change stay, as unconfirmed change, and the transfer
689    /// leaves its payment, as for [`forget`](Self::forget). Returns whether
690    /// the transfer was outgoing.
691    ///
692    /// A refusal does not always show that the mint never applied it: the
693    /// mint checks its policy before its record of answers, so a transfer it
694    /// applied under a looser policy is refused as `policy` too. Once a payee
695    /// holds the transfer, they can still submit it. If the mint applies it,
696    /// or already had, the payee's notes and the note taken back claim the
697    /// same value, and the mint refuses whichever is spent second.
698    pub fn cancel(&mut self, request: &TransferRequest) -> bool {
699        let Some(spends) = self.end(request) else {
700            return false;
701        };
702        self.notes.push(spends);
703        true
704    }
705
706    /// Ends an outgoing transfer and returns the note it spends. The keys of
707    /// its change move from the keys expected to the unconfirmed change, and
708    /// it leaves the [payment](MadePayment::payment) that holds it, so that
709    /// payment is never handed out again with it.
710    fn end(&mut self, request: &TransferRequest) -> Option<Held> {
711        let i = self.outgoing.iter().position(|o| o.request == *request)?;
712        let outgoing = self.outgoing.remove(i);
713        // A transfer's notes sit one layer past the note it spends.
714        let generation = outgoing.spends.note.serial().generation.saturating_add(1);
715        let mut i = 0;
716        while i < self.expected.len() {
717            let key = self.expected[i].key.public_key();
718            if request.outputs.iter().any(|o| o.holder == key) {
719                let change = self.expected.swap_remove(i);
720                self.unconfirmed.push(Unconfirmed { change, generation });
721            } else {
722                i += 1;
723            }
724        }
725        for made in &mut self.payments {
726            made.payment.transfers.retain(|t| t.request != *request);
727        }
728        self.tidy();
729        Some(outgoing.spends)
730    }
731
732    /// The payments this holder made and keeps: each while one of its
733    /// transfers is [outgoing](Self::outgoing), or while it keeps notes
734    /// [owed](MadePayment::owed) to the payee.
735    pub fn payments(&self) -> impl Iterator<Item = &MadePayment> {
736        self.payments.iter()
737    }
738
739    /// Stops keeping `notes` for payees, once they are handed over: they
740    /// leave the [owed](MadePayment::owed) notes of the payments that keep
741    /// them, and a payment with nothing else kept leaves the
742    /// [payments](Self::payments). Returns the value it stopped keeping.
743    ///
744    /// The payee checks their signatures and takes them in, as notes from
745    /// the mint's answers: with [`take_answers`](Self::take_answers), or
746    /// [`absorb`](Self::absorb).
747    pub fn forget_owed(&mut self, notes: &[Note]) -> u128 {
748        let mut value = 0;
749        for made in &mut self.payments {
750            made.owed.retain(|note| {
751                let handed = notes.contains(note);
752                if handed {
753                    value += u128::from(note.amount());
754                }
755                !handed
756            });
757        }
758        self.tidy();
759        value
760    }
761
762    /// Drops the payments with no transfer outgoing and no notes owed.
763    fn tidy(&mut self) {
764        let outgoing = &self.outgoing;
765        self.payments.retain(|p| {
766            !p.owed.is_empty()
767                || p.payment
768                    .transfers
769                    .iter()
770                    .any(|t| outgoing.iter().any(|o| o.request == t.request))
771        });
772    }
773
774    /// Transfers not yet answered. Resend them after a crash or a timeout,
775    /// with [`resend`](Self::resend): the mint answers an identical request
776    /// with the identical notes, before or after a rotation, for as long as
777    /// it remembers the transfer.
778    pub fn outgoing(&self) -> impl Iterator<Item = &TransferRequest> {
779        self.outgoing.iter().map(|o| &o.request)
780    }
781
782    /// What this holder may lose on `request` if the mint applied it and its
783    /// answer is lost: the value it pays to keys this holder still expects,
784    /// unconfirmed change included. `Some` when the transfer is outgoing or
785    /// pays such a key, even if the value is 0; `None` when nothing of this
786    /// holder's rides on it.
787    ///
788    /// A transfer refused as spent or expired may have been applied after
789    /// all, by the counterparty or by an earlier try whose answer was lost.
790    /// A counterparty that submitted it holds the answer and can hand the
791    /// notes over, for [`take_answers`](Self::take_answers).
792    pub fn at_stake(&self, request: &TransferRequest) -> Option<u128> {
793        let mint = request.inputs.first().map(|spend| spend.note.issuer());
794        let expected: u128 = request
795            .outputs
796            .iter()
797            .filter(|o| {
798                let pays = |e: &Expected| {
799                    Some(&e.mint) == mint && e.amount == o.amount && e.key.public_key() == o.holder
800                };
801                self.expected.iter().any(pays) || self.unconfirmed.iter().any(|u| pays(&u.change))
802            })
803            .map(|o| u128::from(o.amount))
804            .sum();
805        let outgoing = self.outgoing.iter().any(|o| o.request == *request);
806        (outgoing || expected > 0).then_some(expected)
807    }
808
809    /// The [outgoing](Self::outgoing) transfers in random order, each with a
810    /// time to resend it, spaced by `spacing`. Resent together, they would
811    /// tell the mint their notes had one owner.
812    ///
813    /// The mint answers a resent transfer with the same notes only while it
814    /// keeps its answer, and at the latest until the notes it issued expire
815    /// (see [Error codes]). After that, a transfer already applied is
816    /// refused as spent or expired, and its change can only come from the
817    /// counterparty, for [`take_answers`](Self::take_answers).
818    /// [`due_resends`](Self::due_resends) gives the transfers to resend
819    /// before a rotation ends their chance.
820    ///
821    /// [Error codes]: https://github.com/zhangheqi/worgl/blob/main/site/src/content/docs/docs/error-codes.md#sending-a-request-again
822    pub fn resend(&self, spacing: Spacing) -> Vec<ScheduledTransfer> {
823        let mut requests: Vec<TransferRequest> = self.outgoing().cloned().collect();
824        random::shuffle(&mut requests);
825        let mut after_secs = 0u64;
826        requests
827            .into_iter()
828            .enumerate()
829            .map(|(n, request)| {
830                if n > 0 {
831                    after_secs = after_secs.saturating_add(spacing.gap());
832                }
833                ScheduledTransfer {
834                    after_secs,
835                    request,
836                }
837            })
838            .collect()
839    }
840
841    /// The [outgoing](Self::outgoing) transfers at `mint` to resend before
842    /// its next rotation, each at its own random moment before it, as
843    /// [`refresh`](Self::refresh) spreads its transfers from the same `now`.
844    /// Nothing in the store changes.
845    ///
846    /// A transfer is due when the note it spends dies at that rotation:
847    /// after it, a transfer the mint never applied can no longer be
848    /// applied. It is still due when that note was dropped at the last
849    /// rotation, since the mint may keep an applied transfer's answer until
850    /// the notes it issued die, at the next. Call it before
851    /// [`refresh`](Self::refresh), whose transfers it would list too, submit
852    /// them with the refreshes and [`settle`](Self::settle) the answers.
853    /// Resending a payment the payee has not submitted yet carries it out;
854    /// the payee still gets the same notes by submitting it while the mint
855    /// keeps its answer, and settling the answer keeps them for the payee
856    /// too (see [`MadePayment::owed`]).
857    pub fn due_resends(&self, mint: &MintView, now: u64) -> Vec<ScheduledTransfer> {
858        let window = refresh_window(mint, now);
859        let mut transfers: Vec<ScheduledTransfer> = self
860            .outgoing
861            .iter()
862            .filter(|o| {
863                let note = &o.spends.note;
864                let dropped_last = note.issuer() == &mint.issuer
865                    && note.serial().generation.checked_add(1) == Some(mint.oldest);
866                dropped_last
867                    || matches!(
868                        mint.state(note),
869                        NoteState::Spendable {
870                            expires_after_rotations: 1
871                        } | NoteState::Frozen {
872                            expires_after_rotations: 1
873                        }
874                    )
875            })
876            .map(|o| ScheduledTransfer {
877                after_secs: random::between(0, window),
878                request: o.request.clone(),
879            })
880            .collect();
881        transfers.sort_by_key(|t| t.after_secs);
882        transfers
883    }
884
885    /// Pays each of `mint`'s notes that dies at the next rotation to a fresh
886    /// key of this holder, each at its own random moment before the
887    /// rotation, so the mint cannot group one holder's notes by when they
888    /// moved. The refreshed note lands one layer later and lives as long as
889    /// a received note.
890    ///
891    /// Call it once per rotation period, after reading the mint's info.
892    /// Submit each transfer at its time and [`settle`](Self::settle) the
893    /// answer.
894    ///
895    /// `mint` alone says which notes are due: those in its first layer.
896    /// `now`, the Unix time by the mint's clock, says only when: the
897    /// transfers are spread over the time left before the next rotation,
898    /// less [`REFRESH_MARGIN_SECS`], and are all due at once when `now` is at
899    /// or past it, since the mint has not made it yet as far as `mint` knows.
900    /// A clock behind the mint's by more than that margin can spread them
901    /// past the rotation, where they fail, so take `now` from the mint, such
902    /// as from the `Date` of its answer.
903    pub fn refresh(&mut self, mint: &MintView, now: u64) -> Vec<ScheduledTransfer> {
904        let window = refresh_window(mint, now);
905        let mut transfers = Vec::new();
906        let mut i = 0;
907        while i < self.notes.len() {
908            let due = matches!(
909                mint.state(&self.notes[i].note),
910                NoteState::Spendable {
911                    expires_after_rotations: 1
912                }
913            );
914            if !due {
915                i += 1;
916                continue;
917            }
918            let held = self.notes.remove(i);
919            let key = HolderKey::generate();
920            let output = Output {
921                amount: held.note.amount(),
922                holder: key.public_key(),
923            };
924            let request = TransferRequest::single(held.note, &held.key, output)
925                .expect("a held note is signed with its own key");
926            self.expected.push(Expected {
927                mint: mint.issuer,
928                amount: output.amount,
929                key,
930            });
931            self.outgoing.push(Outgoing {
932                request: request.clone(),
933                spends: held,
934            });
935            transfers.push(ScheduledTransfer {
936                after_secs: random::between(0, window),
937                request,
938            });
939        }
940        transfers.sort_by_key(|t| t.after_secs);
941        transfers
942    }
943
944    /// Removes `mint`'s notes whose layer was dropped and returns the value
945    /// lost. It also stops waiting for unconfirmed change of `mint` that
946    /// would sit in a dropped layer, and stops keeping notes owed to payees
947    /// once their layer is dropped; neither counts as lost.
948    ///
949    /// It goes by `mint` alone, with no clock: with a view of the mint's
950    /// info, it removes a note, and its key for good, only once the mint has
951    /// dropped the note's layer.
952    pub fn prune(&mut self, mint: &MintView) -> u128 {
953        let mut lost = 0;
954        self.notes.retain(|h| {
955            let expired = mint.state(&h.note) == NoteState::Expired;
956            if expired {
957                lost += u128::from(h.note.amount());
958            }
959            !expired
960        });
961        self.unconfirmed
962            .retain(|u| u.change.mint != mint.issuer || u.generation >= mint.oldest);
963        for made in &mut self.payments {
964            made.owed
965                .retain(|note| mint.state(note) != NoteState::Expired);
966        }
967        self.tidy();
968        lost
969    }
970
971    /// Value held at `mint`, by what it can do now.
972    pub fn balance(&self, mint: &MintView) -> Balance {
973        let mut balance = Balance::default();
974        for held in &self.notes {
975            let value = u128::from(held.note.amount());
976            match mint.state(&held.note) {
977                NoteState::Spendable {
978                    expires_after_rotations,
979                } => {
980                    balance.spendable += value;
981                    if expires_after_rotations == 1 {
982                        balance.expiring += value;
983                    }
984                }
985                NoteState::Frozen {
986                    expires_after_rotations,
987                } => {
988                    balance.frozen += value;
989                    if expires_after_rotations == 1 {
990                        balance.expiring += value;
991                    }
992                }
993                NoteState::Unknown => balance.unknown += value,
994                NoteState::Expired | NoteState::OtherMint => {}
995            }
996        }
997        for outgoing in &self.outgoing {
998            if outgoing.spends.note.issuer() == &mint.issuer {
999                balance.outgoing += u128::from(outgoing.spends.note.amount());
1000            }
1001        }
1002        for expected in &self.expected {
1003            if expected.mint == mint.issuer {
1004                balance.expected += u128::from(expected.amount);
1005            }
1006        }
1007        for unconfirmed in &self.unconfirmed {
1008            if unconfirmed.change.mint == mint.issuer {
1009                balance.unconfirmed += u128::from(unconfirmed.change.amount);
1010            }
1011        }
1012        balance
1013    }
1014
1015    /// The notes held, of every mint.
1016    pub fn notes(&self) -> impl Iterator<Item = &Note> {
1017        self.notes.iter().map(|h| &h.note)
1018    }
1019
1020    /// The whole store as JSON, secret keys included.
1021    ///
1022    /// A store with unconfirmed change or notes owed to payees is written in
1023    /// format 2, which an SDK that reads only format 1 refuses rather than
1024    /// open without them; any other store is written in format 1.
1025    pub fn to_json(&self) -> String {
1026        let plain = self.unconfirmed.is_empty() && self.payments.iter().all(|p| p.owed.is_empty());
1027        serde_json::to_string(&Saved {
1028            format: if plain { 1 } else { FORMAT },
1029            notes: self.notes.clone(),
1030            expected: self.expected.clone(),
1031            outgoing: self.outgoing.clone(),
1032            unconfirmed: self.unconfirmed.clone(),
1033            payments: self.payments.clone(),
1034            paid: self.paid.clone(),
1035        })
1036        .expect("a store always serializes")
1037    }
1038
1039    /// Reads a store written by [`to_json`](Self::to_json), by this SDK or
1040    /// an earlier one.
1041    pub fn from_json(json: &str) -> Result<Self, LoadError> {
1042        let saved: Saved = serde_json::from_str(json)?;
1043        if !(1..=FORMAT).contains(&saved.format) {
1044            return Err(LoadError::Format(saved.format));
1045        }
1046        Ok(Self {
1047            notes: saved.notes,
1048            expected: saved.expected,
1049            outgoing: saved.outgoing,
1050            unconfirmed: saved.unconfirmed,
1051            payments: saved.payments,
1052            paid: saved.paid,
1053        })
1054    }
1055}
1056
1057/// Seconds from `now` over which to spread transfers that must land before
1058/// `mint`'s next rotation: none once that rotation is due.
1059fn refresh_window(mint: &MintView, now: u64) -> u64 {
1060    match mint.until_rotation(now) {
1061        Some(left) => left.saturating_sub(REFRESH_MARGIN_SECS.min(left / 2)),
1062        None => UNSCHEDULED_REFRESH_SECS,
1063    }
1064}
1065
1066/// One transfer of a payment: the note it spends, the requested outputs it
1067/// pays and the change it returns.
1068struct Part {
1069    note: usize,
1070    paid: Vec<Output>,
1071    change: Vec<u64>,
1072}
1073
1074enum Split {
1075    Inexact,
1076    TooMany,
1077}
1078
1079/// Splits `amount` into allowed denominations no larger than `largest`,
1080/// largest first, as at most `limit` notes.
1081fn split(
1082    denominations: &Denominations,
1083    amount: u64,
1084    largest: Option<u64>,
1085    limit: usize,
1086) -> Result<Vec<u64>, Split> {
1087    if amount == 0 {
1088        return Ok(Vec::new());
1089    }
1090    let pieces = match (denominations, largest) {
1091        (_, Some(0)) => return Err(Split::Inexact),
1092        (denominations, None) => denominations.decompose(amount),
1093        (Denominations::Any, Some(cap)) => {
1094            let mut pieces = vec![(cap, amount / cap)];
1095            if !amount.is_multiple_of(cap) {
1096                pieces.push((amount % cap, 1));
1097            }
1098            Some(pieces)
1099        }
1100        (Denominations::PowersOfTwo, Some(cap)) => {
1101            let top = 1u64 << (63 - cap.leading_zeros());
1102            let mut pieces = vec![(top, amount / top)];
1103            pieces.extend(
1104                Denominations::PowersOfTwo
1105                    .decompose(amount % top)
1106                    .unwrap_or_default(),
1107            );
1108            Some(pieces)
1109        }
1110        (Denominations::List(values), Some(cap)) => {
1111            let allowed = values.iter().copied().filter(|&v| v <= cap);
1112            Denominations::list(allowed)
1113                .ok()
1114                .and_then(|d| d.decompose(amount))
1115        }
1116    };
1117    let pieces = pieces.ok_or(Split::Inexact)?;
1118    let count: u128 = pieces.iter().map(|&(_, n)| u128::from(n)).sum();
1119    if count > limit as u128 {
1120        return Err(Split::TooMany);
1121    }
1122    Ok(pieces
1123        .into_iter()
1124        .filter(|&(_, n)| n > 0)
1125        .flat_map(|(value, n)| std::iter::repeat_n(value, n as usize))
1126        .collect())
1127}
1128
1129/// Holder keys saved as their 32-byte secrets in hex.
1130mod secret {
1131    use serde::{Deserialize, Deserializer, Serializer, de};
1132    use worgl::HolderKey;
1133
1134    pub(super) fn serialize<S: Serializer>(key: &HolderKey, s: S) -> Result<S::Ok, S::Error> {
1135        s.serialize_str(&hex::encode(key.to_secret_bytes()))
1136    }
1137
1138    pub(super) fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<HolderKey, D::Error> {
1139        let text = String::deserialize(d)?;
1140        let mut secret = [0u8; 32];
1141        hex::decode_to_slice(text, &mut secret).map_err(de::Error::custom)?;
1142        Ok(HolderKey::from_secret_bytes(&secret))
1143    }
1144}
1145
1146#[cfg(test)]
1147mod tests {
1148    use super::*;
1149
1150    #[test]
1151    fn splits_follow_the_denominations_and_the_cap() {
1152        let p2 = Denominations::PowersOfTwo;
1153        assert_eq!(split(&p2, 13, None, 16).ok(), Some(vec![8, 4, 1]));
1154        assert_eq!(split(&p2, 13, Some(4), 16).ok(), Some(vec![4, 4, 4, 1]));
1155        assert_eq!(split(&p2, 13, Some(5), 16).ok(), Some(vec![4, 4, 4, 1]));
1156        assert!(matches!(
1157            split(&p2, 1 << 20, Some(1), 256),
1158            Err(Split::TooMany)
1159        ));
1160        assert_eq!(split(&p2, 0, None, 0).ok(), Some(vec![]));
1161
1162        let any = Denominations::Any;
1163        assert_eq!(split(&any, 7, None, 16).ok(), Some(vec![7]));
1164        assert_eq!(split(&any, 7, Some(3), 16).ok(), Some(vec![3, 3, 1]));
1165
1166        let list = Denominations::list([1, 2, 5]).unwrap();
1167        assert_eq!(split(&list, 9, None, 16).ok(), Some(vec![5, 2, 2]));
1168        assert_eq!(split(&list, 9, Some(2), 16).ok(), Some(vec![2, 2, 2, 2, 1]));
1169        let fives = Denominations::list([5]).unwrap();
1170        assert!(matches!(split(&fives, 7, None, 16), Err(Split::Inexact)));
1171        assert!(matches!(split(&fives, 5, Some(4), 16), Err(Split::Inexact)));
1172    }
1173
1174    #[test]
1175    fn the_keys_paid_last_are_kept_up_to_the_bound_and_saved() {
1176        let mut holder = Holder::new();
1177        let keys: Vec<PublicKey> = (0..=PAID_KEYS_KEPT)
1178            .map(|_| HolderKey::generate().public_key())
1179            .collect();
1180        holder.remember_paid(keys.iter().copied());
1181        assert_eq!(holder.paid.len(), PAID_KEYS_KEPT);
1182        let holder = Holder::from_json(&holder.to_json()).unwrap();
1183        assert!(!holder.has_paid(&keys[0]), "the oldest is forgotten");
1184        assert!(keys[1..].iter().all(|key| holder.has_paid(key)));
1185    }
1186}