Formatting

This commit is contained in:
2026-09-05 18:30:35 +02:00
parent 454a9db1d5
commit 4caa075052
133 changed files with 8260 additions and 8181 deletions
+67 -71
View File
@@ -1,8 +1,8 @@
import {describe, expect, it} from 'vitest'
import {noteK1, noteSignature} from 'lnurlcash-kit'
import { describe, expect, it } from 'vitest';
import { noteK1, noteSignature } from 'lnurlcash-kit';
import {ensureExactAmount} from './ops'
import {requiredValue} from './test-utils'
import { ensureExactAmount } from './ops';
import { requiredValue } from './test-utils';
import {
allocateOutputSecrets,
makeBearer,
@@ -10,8 +10,8 @@ import {
noteUrl,
secret,
signatureKeysFor,
} from './ops.testHarness'
import {fetchNoteInfo} from 'lnurlcash-kit'
} from './ops.testHarness';
import { fetchNoteInfo } from 'lnurlcash-kit';
// Landed split/merge outputs carry the mint's signature in their URL (sig
// param), and earn verified:true only when that signature checks against a
@@ -21,38 +21,38 @@ import {fetchNoteInfo} from 'lnurlcash-kit'
// exist at the mint), only the offline-verifiable badge is withheld.
describe('landed mutation signature verification', () => {
it('verifies a landed split against the current key and preserves its signature', async () => {
const instance = await mint()
const bearer = await makeBearer(instance, secret('a0'), 21_000)
const instance = await mint();
const bearer = await makeBearer(instance, secret('a0'), 21_000);
const result = await ensureExactAmount([bearer], 5_000, {
onCarve: () => undefined,
allocateOutputSecrets,
mintSignatureKeys: signatureKeysFor(instance),
})
});
expect(result.note.verified).toBe(true)
const signature = noteSignature(result.note.url)
expect(signature).not.toBeNull()
expect(noteSignature(requiredValue(result.change).url)).not.toBeNull()
expect(result.note.verified).toBe(true);
const signature = noteSignature(result.note.url);
expect(signature).not.toBeNull();
expect(noteSignature(requiredValue(result.change).url)).not.toBeNull();
// change stays unverified (its true post-fee value is unknown until a
// refresh) even though its signature is preserved
expect(result.change?.verified).toBe(false)
})
expect(result.change?.verified).toBe(false);
});
it('verifies a landed merge against the current key and preserves its signature', async () => {
const instance = await mint()
const first = await makeBearer(instance, secret('a1'), 3_000)
const second = await makeBearer(instance, secret('a2'), 4_000)
const instance = await mint();
const first = await makeBearer(instance, secret('a1'), 3_000);
const second = await makeBearer(instance, secret('a2'), 4_000);
const result = await ensureExactAmount([first, second], 7_000, {
onCarve: () => undefined,
allocateOutputSecrets,
mintSignatureKeys: signatureKeysFor(instance),
})
});
expect(result.note.verified).toBe(true)
expect(noteSignature(result.note.url)).not.toBeNull()
})
expect(result.note.verified).toBe(true);
expect(noteSignature(result.note.url)).not.toBeNull();
});
it('verifies against the previous key after the mint rotated its signing key', async () => {
// the mint signs every output under its RETIRED key while advertising
@@ -60,26 +60,26 @@ describe('landed mutation signature verification', () => {
const instance = await mint({
previousPrivateKey: '22'.repeat(32),
signWithPreviousKey: true,
})
const bearer = await makeBearer(instance, secret('a3'), 21_000)
});
const bearer = await makeBearer(instance, secret('a3'), 21_000);
const result = await ensureExactAmount([bearer], 5_000, {
onCarve: () => undefined,
allocateOutputSecrets,
mintSignatureKeys: signatureKeysFor(instance),
})
});
expect(instance.state.previousPubkeys).toHaveLength(1)
expect(result.note.verified).toBe(true)
expect(noteSignature(result.note.url)).not.toBeNull()
})
expect(instance.state.previousPubkeys).toHaveLength(1);
expect(result.note.verified).toBe(true);
expect(noteSignature(result.note.url)).not.toBeNull();
});
it('rejects verification when the previous key is not trusted', async () => {
const instance = await mint({
previousPrivateKey: '22'.repeat(32),
signWithPreviousKey: true,
})
const bearer = await makeBearer(instance, secret('a4'), 21_000)
});
const bearer = await makeBearer(instance, secret('a4'), 21_000);
const result = await ensureExactAmount([bearer], 5_000, {
onCarve: () => undefined,
@@ -87,73 +87,69 @@ describe('landed mutation signature verification', () => {
// only the current key is trusted - the signature under the retired
// key must not verify
mintSignatureKeys: () => [instance.state.pubkey],
})
});
expect(result.note.verified).toBe(false)
expect(result.note.verified).toBe(false);
// the note and its signature are still tracked, recoverable by refresh
expect(noteSignature(result.note.url)).not.toBeNull()
const partK1 = requiredValue(noteK1(result.note.url))
expect(instance.state.noteState(partK1)).toBe('outstanding')
expect(instance.state.noteState(secret('a4'))).toBe('burned')
})
expect(noteSignature(result.note.url)).not.toBeNull();
const partK1 = requiredValue(noteK1(result.note.url));
expect(instance.state.noteState(partK1)).toBe('outstanding');
expect(instance.state.noteState(secret('a4'))).toBe('burned');
});
it('keeps a wrong-key signature staged unverified', async () => {
const instance = await mint()
const bearer = await makeBearer(instance, secret('a5'), 21_000)
const stranger = await mint({privateKey: '33'.repeat(32)})
const instance = await mint();
const bearer = await makeBearer(instance, secret('a5'), 21_000);
const stranger = await mint({ privateKey: '33'.repeat(32) });
const result = await ensureExactAmount([bearer], 5_000, {
onCarve: () => undefined,
allocateOutputSecrets,
// the only trusted key on file belongs to a DIFFERENT mint
mintSignatureKeys: () => [stranger.state.pubkey],
})
});
expect(result.note.verified).toBe(false)
expect(noteSignature(result.note.url)).not.toBeNull()
expect(instance.state.noteState(secret('a5'))).toBe('burned')
expect(
instance.state.noteState(requiredValue(noteK1(result.note.url))),
).toBe('outstanding')
})
expect(result.note.verified).toBe(false);
expect(noteSignature(result.note.url)).not.toBeNull();
expect(instance.state.noteState(secret('a5'))).toBe('burned');
expect(instance.state.noteState(requiredValue(noteK1(result.note.url)))).toBe('outstanding');
});
it('keeps a landed split unsigned by the mint staged unverified and consumed', async () => {
const instance = await mint({signatures: false})
const k1 = secret('a6')
const bearer = await makeBearer(instance, k1, 21_000)
const instance = await mint({ signatures: false });
const k1 = secret('a6');
const bearer = await makeBearer(instance, k1, 21_000);
const result = await ensureExactAmount([bearer], 5_000, {
onCarve: () => undefined,
allocateOutputSecrets,
mintSignatureKeys: signatureKeysFor(instance),
})
});
// the mutation landed (the kit refused the missing signature, the
// rescue probe proved the burn): the inputs are retired, the staged
// outputs are tracked at exactly their staged secrets, unverified
expect(result.consumed.map((entry) => entry.id)).toEqual([bearer.id])
expect(result.note.verified).toBe(false)
expect(noteSignature(result.note.url)).toBeNull()
expect(instance.state.noteState(k1)).toBe('burned')
const partK1 = requiredValue(noteK1(result.note.url))
expect(instance.state.noteState(partK1)).toBe('outstanding')
expect((await fetchNoteInfo(noteUrl(instance, partK1))).maxWithdrawable).toBe(5_000)
})
expect(result.consumed.map((entry) => entry.id)).toEqual([bearer.id]);
expect(result.note.verified).toBe(false);
expect(noteSignature(result.note.url)).toBeNull();
expect(instance.state.noteState(k1)).toBe('burned');
const partK1 = requiredValue(noteK1(result.note.url));
expect(instance.state.noteState(partK1)).toBe('outstanding');
expect((await fetchNoteInfo(noteUrl(instance, partK1))).maxWithdrawable).toBe(5_000);
});
it('never verifies a landed mutation without any trusted keys on file', async () => {
const instance = await mint()
const bearer = await makeBearer(instance, secret('a7'), 21_000)
const instance = await mint();
const bearer = await makeBearer(instance, secret('a7'), 21_000);
const result = await ensureExactAmount([bearer], 5_000, {
onCarve: () => undefined,
allocateOutputSecrets,
// no key source at all: nothing may be trusted blindly
})
});
expect(result.note.verified).toBe(false)
expect(noteSignature(result.note.url)).not.toBeNull()
expect(
instance.state.noteState(requiredValue(noteK1(result.note.url))),
).toBe('outstanding')
})
})
expect(result.note.verified).toBe(false);
expect(noteSignature(result.note.url)).not.toBeNull();
expect(instance.state.noteState(requiredValue(noteK1(result.note.url)))).toBe('outstanding');
});
});