mirror of
https://github.com/tompro/sattle.git
synced 2026-10-26 01:49:58 +00:00
feat(funds): recover staged mutations
This commit is contained in:
@@ -1,17 +1,10 @@
|
||||
import {describe, expect, it} from 'vitest'
|
||||
import {noteK1} from 'lnurlcash-kit'
|
||||
|
||||
import type {CarveResult} from './ops'
|
||||
import {ensureExactAmount, receiveBearer} from './ops'
|
||||
import {claimFromPreimage, prepareMint} from './ops/mint'
|
||||
import {requiredValue} from './test-utils'
|
||||
import {
|
||||
makeBearer,
|
||||
mint,
|
||||
noteUrl,
|
||||
retryingCbFetch,
|
||||
secret,
|
||||
settleLastInvoice,
|
||||
} from './ops.testHarness'
|
||||
import {makeBearer, mint, noteUrl, retryingCbFetch, secret} from './ops.testHarness'
|
||||
|
||||
// The redeem callback is a GET, and HTTP stacks retry GETs - so a mint
|
||||
// can execute the first attempt of a mutation and refuse the byte-identical
|
||||
@@ -24,7 +17,10 @@ describe('mutation retry refusals', () => {
|
||||
const instance = await mint()
|
||||
const k1 = secret('60')
|
||||
const bearer = await makeBearer(instance, k1, 50_000)
|
||||
const result = await ensureExactAmount([bearer], 25_000, {fetch: retryingCbFetch()})
|
||||
const result = await ensureExactAmount([bearer], 25_000, {
|
||||
fetch: retryingCbFetch(),
|
||||
onCarve: () => undefined,
|
||||
})
|
||||
// the split landed on the first (unseen) attempt: the input is burned
|
||||
// and both outputs are live under the secrets the wallet carried
|
||||
expect(instance.state.noteState(k1)).toBe('burned')
|
||||
@@ -41,7 +37,10 @@ describe('mutation retry refusals', () => {
|
||||
const instance = await mint()
|
||||
const a = await makeBearer(instance, secret('61'), 20_000)
|
||||
const b = await makeBearer(instance, secret('62'), 5_000)
|
||||
const result = await ensureExactAmount([a, b], 25_000, {fetch: retryingCbFetch()})
|
||||
const result = await ensureExactAmount([a, b], 25_000, {
|
||||
fetch: retryingCbFetch(),
|
||||
onCarve: () => undefined,
|
||||
})
|
||||
expect(result.consumed).toHaveLength(2)
|
||||
expect(instance.state.noteState(secret('61'))).toBe('burned')
|
||||
expect(instance.state.noteState(secret('62'))).toBe('burned')
|
||||
@@ -50,19 +49,6 @@ describe('mutation retry refusals', () => {
|
||||
expect(instance.state.noteState(mergedK1)).toBe('outstanding')
|
||||
})
|
||||
|
||||
it('adopts the fresh secret when the claim rotate answer is a retry refusal', async () => {
|
||||
const instance = await mint({testHooks: true})
|
||||
const prepared = await prepareMint(`mint@127.0.0.1:${instance.port}`, 21_000)
|
||||
const preimage = await settleLastInvoice(instance)
|
||||
const claimed = await claimFromPreimage(prepared, preimage, {fetch: retryingCbFetch()})
|
||||
expect(claimed.rotated).toBe(true)
|
||||
expect(claimed.note.verified).toBe(true)
|
||||
expect(instance.state.noteState(preimage)).toBe('burned')
|
||||
const k1 = requiredValue(noteK1(claimed.note.url))
|
||||
expect(k1).not.toBe(preimage)
|
||||
expect(instance.state.noteState(k1)).toBe('outstanding')
|
||||
})
|
||||
|
||||
it('adopts the fresh secret when the receive rotate answer is a retry refusal', async () => {
|
||||
const instance = await mint()
|
||||
const senderK1 = secret('63')
|
||||
@@ -83,8 +69,16 @@ describe('mutation retry refusals', () => {
|
||||
const k1 = secret('64')
|
||||
const bearer = await makeBearer(instance, k1, 50_000)
|
||||
instance.state.settleMelt(k1) // burned elsewhere, before we ever asked
|
||||
const checkpoints: CarveResult[] = []
|
||||
await expect(
|
||||
ensureExactAmount([bearer], 25_000, {fetch: retryingCbFetch()}),
|
||||
ensureExactAmount([bearer], 25_000, {
|
||||
fetch: retryingCbFetch(),
|
||||
onCarve: (carve) => {
|
||||
checkpoints.push(carve)
|
||||
},
|
||||
}),
|
||||
).rejects.toThrow(/spent/i)
|
||||
expect(checkpoints).toHaveLength(1)
|
||||
expect(checkpoints[0]?.consumed).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user