fix(orders): a restored pending leaves the cancelled take's step start and range slice on a maker's row
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 78/100
Research direction
Start in rust/src/api/orders.rs at apply_restored_status, then read write_maker_step_end, clear_maker_step_start, and forget_range_slice in the same file, plus the two existing callers (resync_republished_maker_order, end_maker_waiting_step) to mirror their order of operations. Check is_maker_waiting_step and existing.order.is_mine guards in rust/src/api/invoice.rs. Done means the five test scenarios in the issue pass: step start reflects the second take (T3), range slice cleared, and non-pending/taker restores unchanged.
Written by the indexing model from the issue text.
Description
A restore that reports a maker's taken order as pending again moves the row to Pending, but leaves behind what the cancelled take recorded: the invoice step start and the range slice. The next take on that order then inherits both. Its pay or add-invoice countdown starts already expired, and a range order shows the old take's amount instead of the full range.
Found in the review of #630 (finding 4b). It predates that PR and is out of its scope.
Why
The other two paths that notice a maker's order is back on the book end the step through write_maker_step_end (rust/src/api/orders.rs):
- the daemon's
new-order, viaresync_republished_maker_order; - the sweep's
SyncPending, viaend_maker_waiting_step.
write_maker_step_end clears the step start first (clear_maker_step_start), then writes Pending, then forgets the range slice (forget_range_slice). Its doc says why that order matters, and clear_maker_step_start's doc says that anything that learns the order is back must clear the start.
apply_restored_status is a third such path, and does neither. It records the cursor, writes the restored status with update_trade_fields, and updates the book and the UI.
The step start matters because a maker keeps one trade key for the whole life of the order: mostrod's taker-cancel path clears only the counterparty's pubkeys (edit_pubkeys_order). So the next take's pay-invoice or add-invoice reaches the maker on the same index with the same status. next_step_start (rust/src/api/invoice.rs) then reads it as the same step and keeps the older timestamp: the stored start is WaitingPayment at T2 on the same index, and T3 ≥ T2. This is the maker's half of #567: that function's doc names resync_republished_maker_order as the one that opens the maker's new step, by deleting the key, and the restore was left out.
Scenario
- A sell maker's range order (10–1000 ARS) is taken at T2 for 250 ARS. The maker gets
pay-invoiceat T2: the row isWaitingPaymentwith the 250 ARS slice, and the step start isWaitingPayment:T2:<index>. - The taker cancels. mostrod republishes the order as
pending(cancel_order_by_taker:update_order_to_initial_state,edit_pubkeys_order) and sends the makernew-order, which this client never applies (lost). - The maker runs Account → Refresh. The restore's Orders reply lists the order as
pending, andapply_restored_statuswritesPending. The step startT2and the 250 ARS slice stay on the row. - A new taker takes the order at T3 and the maker gets
pay-invoiceat T3. Expected: the pay-invoice countdown starts at T3. Actual: it starts at T2 and may already be expired. Between steps 3 and 4, the maker's row also shows 250 ARS instead of the 10–1000 range.
The same happens after a fresh-device restore whose history replay rebuilt the row from pay-invoice at T2.
Only a taker's cancel triggers it. When the maker's own step times out (a sell maker at WaitingPayment, a buy maker at WaitingBuyerInvoice), mostrod cancels the order instead of republishing it (scheduler.rs), and there is no next take to inherit anything.
Direction
When the restored status is Pending and the row is a maker's (existing.order.is_mine) at a waiting step (is_maker_waiting_step, which does not look at the role), end the step through write_maker_step_end, as the other two paths do, instead of a bare update_trade_fields. Keep the book update and the emit. If write_maker_step_end returns false, return false without touching the book or emitting, as a failed update_trade_fields does today. Every other restored status keeps today's write.
Out of scope here, and declared as a residual risk in #630: apply_restored_status records the cursor (the restore's sent_at) before a row write that can fail.
Tests
- A maker whose order was taken via
pay-invoiceat T2, restored aspending, then taken again viapay-invoiceat T3: the step start is T3. - The same for
add-invoice: a buy maker asked for its payout invoice, whose taker (the seller) cancels after paying the hold invoice. mostrod allows that atWaitingBuyerInvoice, returns the escrow and republishes the order. - A range order restored as
pending: the row's slice is cleared and the range is back. - Regression: a restore that reports a non-
pendingstatus on a waiting row still writes it as today, and keeps the step start. - A taker's waiting row restored as
pendingkeeps today's write.
Not reproduced on a node yet. The mechanism is from the code above and from the review of #630, which reproduced it in a throwaway test (gap_restored_pending_leaves_the_makers_step_start).
Related: #567, #628, #630.
- Dominant language
- Dart
- Stars
- 11
- Forks
- 9
- Avg merge
- 1d 40m
- Merged PRs (30d)
- 219
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from MostroP2P/app
-
area: rust-core bug priority: low
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
area: ui
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
Similar issues
-
Standalone dash flashes as its own RSVP step (e.g. Russian dialogue)Possibly taken @bezig01 claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
daniel-pimenta-cc/ledor#53 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Iteration CounterOpenenhancement firebase
Difficulty 2/5 1-3 hours Newbie friendliness 65/100
brysonddelozier/scribbles#24 ·
-
bug good first issue P2-Medium
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
basictech01/uniun#305 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
daohoangson/flutter_widget_from_html#1657 ·
Maintainers usually reply within 3 days