diff --git a/cashu/core/base.py b/cashu/core/base.py index 147ab809..18ca4c8f 100644 --- a/cashu/core/base.py +++ b/cashu/core/base.py @@ -818,6 +818,12 @@ def generate_keys(self): assert self.seed, "seed not set" assert self.derivation_path, "derivation path not set" + # we compute the keyset id from the public keys only if it is not + # loaded from the database. This is to allow for backwards compatibility + # with old keysets with new id's and vice versa. This code can be removed + # if there are only new keysets in the mint (> 0.15.0) + id_in_db = self.id + if self.version_tuple < (0, 12): # WARNING: Broken key derivation for backwards compatibility with < 0.12 self.private_keys = derive_keys_backwards_compatible_insecure_pre_0_12( @@ -828,7 +834,8 @@ def generate_keys(self): f"WARNING: Using weak key derivation for keyset {self.id} (backwards" " compatibility < 0.12)" ) - self.id = derive_keyset_id_deprecated(self.public_keys) # type: ignore + # load from db or derive + self.id = id_in_db or derive_keyset_id_deprecated(self.public_keys) # type: ignore elif self.version_tuple < (0, 15): self.private_keys = derive_keys_sha256(self.seed, self.derivation_path) logger.trace( @@ -836,11 +843,13 @@ def generate_keys(self): " compatibility < 0.15)" ) self.public_keys = derive_pubkeys(self.private_keys) # type: ignore - self.id = derive_keyset_id_deprecated(self.public_keys) # type: ignore + # load from db or derive + self.id = id_in_db or derive_keyset_id_deprecated(self.public_keys) # type: ignore else: self.private_keys = derive_keys(self.seed, self.derivation_path) self.public_keys = derive_pubkeys(self.private_keys) # type: ignore - self.id = derive_keyset_id(self.public_keys) # type: ignore + # load from db or derive + self.id = id_in_db or derive_keyset_id(self.public_keys) # type: ignore # ------- TOKEN ------- diff --git a/cashu/core/settings.py b/cashu/core/settings.py index 0cf2e755..4020c098 100644 --- a/cashu/core/settings.py +++ b/cashu/core/settings.py @@ -58,14 +58,6 @@ class MintSettings(CashuSettings): mint_database: str = Field(default="data/mint") mint_test_database: str = Field(default="test_data/test_mint") - mint_duplicate_old_keysets: bool = Field( - default=True, - title="Duplicate keysets", - description=( - "Whether to duplicate keysets for backwards compatibility before v1 API" - " (Nutshell 0.15.0)." - ), - ) class MintBackends(MintSettings): diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index 10a5c839..735a1442 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -231,9 +231,7 @@ async def activate_keyset( logger.debug(f"Loaded keyset {keyset.id}") return keyset - async def init_keysets( - self, autosave: bool = True, duplicate_keysets: Optional[bool] = None - ) -> None: + async def init_keysets(self, autosave: bool = True) -> None: """Initializes all keysets of the mint from the db. Loads all past keysets from db and generate their keys. Then activate the current keyset set by self.derivation_path. @@ -241,9 +239,6 @@ async def init_keysets( autosave (bool, optional): Whether the current keyset should be saved if it is not in the database yet. Will be passed to `self.activate_keyset` where it is generated from `self.derivation_path`. Defaults to True. - duplicate_keysets (bool, optional): Whether to duplicate new keysets and compute - their old keyset id, and duplicate old keysets and compute their new keyset id. - Defaults to False. """ # load all past keysets from db, the keys will be generated at instantiation tmp_keysets: List[MintKeyset] = await self.crud.get_keyset(db=self.db) diff --git a/cashu/mint/migrations.py b/cashu/mint/migrations.py index 41c9ee12..664b80c4 100644 --- a/cashu/mint/migrations.py +++ b/cashu/mint/migrations.py @@ -736,10 +736,10 @@ async def m018_duplicate_deprecated_keyset_ids(db: Database): keyset_copy = copy.copy(keyset) if not keyset_copy.public_keys: raise Exception(f"keyset {keyset_copy.id} has no public keys") - if keyset.version_tuple >= (0, 15): - keyset_copy.id = derive_keyset_id_deprecated(keyset_copy.public_keys) - else: + if keyset.version_tuple < (0, 15): keyset_copy.id = derive_keyset_id(keyset_copy.public_keys) + else: + keyset_copy.id = derive_keyset_id_deprecated(keyset_copy.public_keys) duplicated_keysets.append(keyset_copy) for keyset in duplicated_keysets: diff --git a/tests/conftest.py b/tests/conftest.py index a8d02057..a3ea4f1d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -78,9 +78,9 @@ def run(self, *args, **kwargs): async def ledger(): async def start_mint_init(ledger: Ledger) -> Ledger: await migrate_databases(ledger.db, migrations_mint) - # add keysets - # await ledger.activate_keyset(derivation_path="old_derivation", version="0.3.3") - await ledger.activate_keyset(derivation_path="m/0'/0'/0'", version="0.15.0") + # add a new keyset (with a new ID) which will be duplicated with a keyset with an + # old ID by mint migration m018_duplicate_deprecated_keyset_ids + # await ledger.activate_keyset(derivation_path=settings.mint_derivation_path, version="0.15.0") await migrations_mint.m018_duplicate_deprecated_keyset_ids(ledger.db) ledger = Ledger( diff --git a/tests/test_mint.py b/tests/test_mint.py index 534fc051..0a46b0f3 100644 --- a/tests/test_mint.py +++ b/tests/test_mint.py @@ -58,17 +58,6 @@ async def test_keysets(ledger: Ledger): assert ledger.keyset.id == "009a1f293253e41e" -@pytest.mark.asyncio -async def test_keysets_backwards_compatibility_pre_v0_15(ledger: Ledger): - """Backwards compatibility test for keysets pre v0.15.0 - We expect two instances of the same keyset but with different IDs. - First one is the new hex ID, second one is the old base64 ID. - """ - assert len(ledger.keysets) == 2 - assert list(ledger.keysets.keys()) == ["009a1f293253e41e", "eGnEWtdJ0PIM"] - assert ledger.keyset.id == "009a1f293253e41e" - - @pytest.mark.asyncio async def test_get_keyset(ledger: Ledger): keyset = ledger.get_keyset() @@ -136,55 +125,6 @@ async def test_generate_promises(ledger: Ledger): assert promises[0].dleq.e -@pytest.mark.asyncio -async def test_generate_promises_deprecated_keyset_id(ledger: Ledger): - blinded_messages_mock = [ - BlindedMessage( - amount=8, - B_="02634a2c2b34bec9e8a4aba4361f6bf202d7fa2365379b0840afe249a7a9d71239", - id="eGnEWtdJ0PIM", - ) - ] - promises = await ledger._generate_promises(blinded_messages_mock) - assert ( - promises[0].C_ - == "031422eeffb25319e519c68de000effb294cb362ef713a7cf4832cea7b0452ba6e" - ) - assert promises[0].amount == 8 - assert promises[0].id == "eGnEWtdJ0PIM" - - # DLEQ proof present - assert promises[0].dleq - assert promises[0].dleq.s - assert promises[0].dleq.e - - -@pytest.mark.asyncio -async def test_generate_promises_keyset_backwards_compatibility_pre_v0_15( - ledger: Ledger, -): - """Backwards compatibility test for keysets pre v0.15.0 - We want to generate promises using the old keyset ID. - We expect the promise to have the old base64 ID. - """ - blinded_messages_mock = [ - BlindedMessage( - amount=8, - B_="02634a2c2b34bec9e8a4aba4361f6bf202d7fa2365379b0840afe249a7a9d71239", - id="eGnEWtdJ0PIM", - ) - ] - promises = await ledger._generate_promises( - blinded_messages_mock, keyset=ledger.keysets["eGnEWtdJ0PIM"] - ) - assert ( - promises[0].C_ - == "031422eeffb25319e519c68de000effb294cb362ef713a7cf4832cea7b0452ba6e" - ) - assert promises[0].amount == 8 - assert promises[0].id == "eGnEWtdJ0PIM" - - @pytest.mark.asyncio async def test_generate_change_promises(ledger: Ledger): # Example slightly adapted from NUT-08 because we want to ensure the dynamic change diff --git a/tests/test_mint_api.py b/tests/test_mint_api.py index 3a7acbd3..5b105fcc 100644 --- a/tests/test_mint_api.py +++ b/tests/test_mint_api.py @@ -90,13 +90,6 @@ async def test_api_keysets(ledger: Ledger): "unit": "sat", "active": True, }, - # for backwards compatibility of the new keyset ID format, - # we also return the same keyset with the old base64 ID - { - "id": "eGnEWtdJ0PIM", - "unit": "sat", - "active": True, - }, ] } assert response.json() == expected @@ -132,17 +125,17 @@ async def test_api_keyset_keys(ledger: Ledger): reason="settings.debug_mint_only_deprecated is set", ) async def test_api_keyset_keys_old_keyset_id(ledger: Ledger): - response = httpx.get(f"{BASE_URL}/v1/keys/eGnEWtdJ0PIM") + response = httpx.get(f"{BASE_URL}/v1/keys/009a1f293253e41e") assert response.status_code == 200, f"{response.url} {response.status_code}" assert ledger.keyset.public_keys expected = { "keysets": [ { - "id": "eGnEWtdJ0PIM", + "id": "009a1f293253e41e", "unit": "sat", "keys": { str(k): v.serialize().hex() - for k, v in ledger.keysets["eGnEWtdJ0PIM"].public_keys.items() # type: ignore + for k, v in ledger.keysets["009a1f293253e41e"].public_keys.items() # type: ignore }, } ] diff --git a/tests/test_mint_init.py b/tests/test_mint_init.py index 17263164..e5c0c0c0 100644 --- a/tests/test_mint_init.py +++ b/tests/test_mint_init.py @@ -58,29 +58,6 @@ async def wallet(ledger: Ledger): @pytest.mark.asyncio async def test_init_keysets_with_duplicates(ledger: Ledger): ledger.keysets = {} - await ledger.init_keysets(duplicate_keysets=True) - assert len(ledger.keysets) == 2 - - -@pytest.mark.asyncio -async def test_init_keysets_with_duplicates_via_settings(ledger: Ledger): - ledger.keysets = {} - settings.mint_duplicate_old_keysets = True - await ledger.init_keysets() - assert len(ledger.keysets) == 2 - - -@pytest.mark.asyncio -async def test_init_keysets_without_duplicates(ledger: Ledger): - ledger.keysets = {} - await ledger.init_keysets(duplicate_keysets=False) - assert len(ledger.keysets) == 1 - - -@pytest.mark.asyncio -async def test_init_keysets_without_duplicates_via_settings(ledger: Ledger): - ledger.keysets = {} - settings.mint_duplicate_old_keysets = False await ledger.init_keysets() assert len(ledger.keysets) == 1 diff --git a/tests/test_wallet.py b/tests/test_wallet.py index 16d59c8d..efe96984 100644 --- a/tests/test_wallet.py +++ b/tests/test_wallet.py @@ -441,14 +441,10 @@ async def test_token_state(wallet1: Wallet): @pytest.mark.asyncio async def test_load_mint_keys_specific_keyset(wallet1: Wallet): await wallet1._load_mint_keys() - if settings.debug_mint_only_deprecated: - assert list(wallet1.keysets.keys()) == ["eGnEWtdJ0PIM"] - else: - assert list(wallet1.keysets.keys()) == ["009a1f293253e41e", "eGnEWtdJ0PIM"] + assert list(wallet1.keysets.keys()) == ["009a1f293253e41e"] await wallet1._load_mint_keys(keyset_id=wallet1.keyset_id) await wallet1._load_mint_keys(keyset_id="009a1f293253e41e") # expect deprecated keyset id to be present - await wallet1._load_mint_keys(keyset_id="eGnEWtdJ0PIM") await assert_err( wallet1._load_mint_keys(keyset_id="nonexistent"), KeysetNotFoundError(), diff --git a/tests/test_wallet_restore.py b/tests/test_wallet_restore.py index 9064235d..136425b3 100644 --- a/tests/test_wallet_restore.py +++ b/tests/test_wallet_restore.py @@ -8,7 +8,6 @@ from cashu.core.base import Proof from cashu.core.crypto.secp import PrivateKey from cashu.core.errors import CashuError -from cashu.core.settings import settings from cashu.wallet.wallet import Wallet from cashu.wallet.wallet import Wallet as Wallet1 from cashu.wallet.wallet import Wallet as Wallet2 @@ -86,10 +85,6 @@ async def wallet3(): @pytest.mark.asyncio -@pytest.mark.skipif( - settings.debug_mint_only_deprecated, - reason="settings.debug_mint_only_deprecated is set", -) async def test_bump_secret_derivation(wallet3: Wallet): await wallet3._init_private_key( "half depart obvious quality work element tank gorilla view sugar picture"