diff --git a/tests/test_nip44_v2.py b/tests/test_nip44_v2.py index 2188f4f..34d9c3d 100644 --- a/tests/test_nip44_v2.py +++ b/tests/test_nip44_v2.py @@ -243,81 +243,77 @@ class TestPaddingFormula: # ----------------------------------------------------------------------------- -# Bitspire-side fixture, posted to ~/dev/coordination/log.md at 2026-05-30T13:15Z. -# Throwaway keypairs (one-shot, never sign anything else) — safe to embed verbatim. -# Generated by apps/machine/src/services/operator-config.ts-shape code path using -# the @bitSpire/nostr-client encryptContentV2 + createSignedEvent helpers (same -# code the production bootstrap publish uses). Round-tripped on bitspire side -# before posting. +# Bitspire-side v1.1 fixture, posted to ~/dev/coordination/log.md at +# 2026-05-30T19:00Z. Positions-keyed wire shape per the v1.1 redesign +# (18:30Z + 18:45Z); intentionally includes two positions sharing +# denomination=20 to exercise the multi-same-denom round-trip on our +# decrypt + payload-validate path. Throwaway keypairs (one-shot, never +# sign anything else) — safe to embed verbatim. +# Generated by apps/machine/src/services/operator-config.ts-shape code +# path using the @bitSpire/nostr-client encryptContentV2 + +# createSignedEvent helpers (same code the production bootstrap publish +# uses). Round-tripped on bitspire side via decryptContentV2 before posting. # ----------------------------------------------------------------------------- _BITSPIRE_FIXTURE = { "atm_keypair": { "privkey_hex": ( - "a1601b05967cb421056f197008eca1dfa61f0eb5b505c277a0d4ca6b053e91f2" + "814e6188d017102bbf301ba5b38fba95b2556dc79a60df4cd50605c4593578e6" ), "pubkey_hex": ( - "8db588b6431edbbc0c4f7517bc90447cec34c866b7110e63c88e20a4cccd0e5c" + "217bdc9a65b571c4d9b59da6227a7aa6ca5bbfd5280af791417c57a79d92852b" ), }, "operator_keypair": { "privkey_hex": ( - "216030bdda5aa47c37b74117bc29612bfc18d8122f70e80cb7a6d875c8699108" + "cca7dd9fe4874f6b9f3f3fae21648da686b7e714bfd4786e8fa8745933fd3185" ), "pubkey_hex": ( - "052f27837c3c46b5086825805b8d061ed64346e61cd0c3013725e544aa2a0b49" + "49bd8e615769f8b6a5aa8ce9617b919996abecf234599ba196789461cf239146" ), }, "expected_plaintext": { - "denominations": { - "20": {"position": 1, "count": 49}, - "50": {"position": 2, "count": 100}, + "positions": { + "1": {"denomination": 20, "count": 49}, + "2": {"denomination": 20, "count": 38}, + "3": {"denomination": 50, "count": 100}, }, }, "event": { "kind": 30078, "content": ( - "AgUSQOlYyF7JomOKqJSyAOF/O7yR1d2DYgXvXUS7sBMqRbKPM+ACmkT/R6owFd22nRf2" - "k+KEibEi+WcK6+acBwy1ThWP2NHUlrMp8qjUYrV1XXJXwRLOlLBe0LHmioFi6jTyJxSE" - "/Z+z79o7wki60CKDoNZqSRiScRN0lT7tzEgsFXo2vFzPdzEQwy/jk154DgBoCiRIRjtX" - "kBNGGlN9ABPPfw==" + "AqOHsCcjN2W8L/Cx0uH+n++VA13W+wy7z1EcuuNX49sSagelX2lI0HEKyd+ActOc" + "iaPsHrp9ecJTkEZOD86ioldbLbEVColJwK4g1uVZSbpDeqRe+97woxVDqPnzj507" + "tFaVLF/dRmda+oKHUzkVPhE4PHQJzp9Fqji38J3nU6N68qo7KOt3qg1nSy5eDfAu" + "zt7djRBx63+/veub0rWTMMQLBgci8+Ms6Y+Zb1mki3L6NWuIR0Or+8DhcD+ZJiOu" + "WTcx" ), "tags": [ [ "d", "bitspire-cassettes-state:" - "8db588b6431edbbc0c4f7517bc90447cec34c866b7110e63c88e20a4cccd0e5c", + "217bdc9a65b571c4d9b59da6227a7aa6ca5bbfd5280af791417c57a79d92852b", ], [ "p", - "052f27837c3c46b5086825805b8d061ed64346e61cd0c3013725e544aa2a0b49", + "49bd8e615769f8b6a5aa8ce9617b919996abecf234599ba196789461cf239146", ], ], - "created_at": 1780156459, + "created_at": 1780173222, "pubkey": ( - "8db588b6431edbbc0c4f7517bc90447cec34c866b7110e63c88e20a4cccd0e5c" + "217bdc9a65b571c4d9b59da6227a7aa6ca5bbfd5280af791417c57a79d92852b" ), "id": ( - "28e2bd428bca5b522c037d06e962f5c2ed2e40c398f7ecf84ed5f6272ab77ae4" + "72c09f333386dd4ad6125f8c69823824eea50d8091b694458bcd60701517eece" ), "sig": ( - "8bbde91fb39cfe7026384ca89843b3f9aaf5b9a9a90ddc20e09bc056721438b2" - "9d032435e71bb16a5ac211c951de02d8e2f5422d9ee110653f6e3df72238f6dd" + "07ecafacf0169f074e564a999ee1c31446930b43391d007c4a1f9ef7ad890d6c" + "2aa6e3ecc5318edeb5748fbd64c7ca33407099a97154e2ff7e0c626e48d71925" ), }, } -@pytest.mark.skip( - reason=( - "v1.1 wire-shape pivot (coord-log 2026-05-30T18:30Z + 18:45Z): the " - "13:15Z fixture above is encoded with the old `{denominations: ...}` " - "wire shape; the v1.1 wire shape is `{positions: {: " - "{denomination, count}}}`. Bitspire will post a fresh fixture against " - "the v1.1 shape; once posted, swap `_BITSPIRE_FIXTURE` for the new " - "JSON and drop this skip (v1.1 commit g on the PR)." - ) -) class TestBitspireCrossTest: """Byte-compat cross-test between our hand-rolled NIP-44 v2 (`nip44.py`) and the nostr-tools NIP-44 v2 impl that bitspire uses on the ATM side @@ -328,8 +324,9 @@ class TestBitspireCrossTest: def test_decrypts_bitspire_sample_event(self): """The load-bearing assertion: our `decrypt_from` recovers the - expected `{"denominations": {...}}` plaintext from bitspire's - encrypted event content.""" + expected `{"positions": {...}}` plaintext from bitspire's encrypted + event content. v1.1 fixture intentionally exercises the multi-same- + denomination round-trip (positions 1 + 2 both hold $20).""" import json event = _BITSPIRE_FIXTURE["event"] @@ -342,7 +339,16 @@ class TestBitspireCrossTest: operator_privkey, event["pubkey"], ) - assert json.loads(plaintext) == _BITSPIRE_FIXTURE["expected_plaintext"] + payload = json.loads(plaintext) + assert payload == _BITSPIRE_FIXTURE["expected_plaintext"] + + # v1.1 invariant: two positions can carry the same denomination. + # Pin it explicitly so a future "fix" that re-introduces denom- + # uniqueness validation surfaces here instead of as a runtime + # rejection on real machines. + assert payload["positions"]["1"]["denomination"] == 20 + assert payload["positions"]["2"]["denomination"] == 20 + assert payload["positions"]["1"]["count"] != payload["positions"]["2"]["count"] def test_signature_verifies_via_lnbits_helper(self): """Optional extra per bitspire's 13:15Z note (3). The consumer