diff --git a/cashu/core/settings.py b/cashu/core/settings.py index 7606497..fc05442 100644 --- a/cashu/core/settings.py +++ b/cashu/core/settings.py @@ -56,11 +56,37 @@ class MintSettings(CashuSettings): mint_listen_port: int = Field(default=3338) mint_lightning_backend: str = Field(default="LNbitsWallet") mint_database: str = Field(default="data/mint") - mint_peg_out_only: bool = Field(default=False) - mint_max_peg_in: int = Field(default=None) - mint_max_peg_out: int = Field(default=None) - mint_max_request_length: int = Field(default=1000) - mint_max_balance: int = Field(default=None) + mint_peg_out_only: bool = Field( + default=False, + title="Peg-out only", + description="Mint allows no mint operations.", + ) + mint_max_peg_in: int = Field( + default=None, + title="Maximum peg-in", + description="Maximum amount for a mint operation.", + ) + mint_max_peg_out: int = Field( + default=None, + title="Maximum peg-out", + description="Maximum amount for a melt operation.", + ) + mint_max_request_length: int = Field( + default=1000, + title="Maximum request length", + description="Maximum length of REST API request arrays.", + ) + mint_max_balance: int = Field( + default=None, title="Maximum mint balance", description="Maximum mint balance." + ) + mint_duplicate_keysets: bool = Field( + default=True, + title="Duplicate keysets", + description=( + "Whether to duplicate keysets for backwards compatibility before v1 API" + " (Nutshell 0.15.0)." + ), + ) mint_lnbits_endpoint: str = Field(default=None) mint_lnbits_key: str = Field(default=None) @@ -85,7 +111,7 @@ class MintInformation(CashuSettings): class WalletSettings(CashuSettings): - tor: bool = Field(default=True) + tor: bool = Field(default=False) socks_host: str = Field(default=None) # deprecated socks_port: int = Field(default=9050) # deprecated socks_proxy: str = Field(default=None) diff --git a/cashu/mint/ledger.py b/cashu/mint/ledger.py index 24f11e0..116835c 100644 --- a/cashu/mint/ledger.py +++ b/cashu/mint/ledger.py @@ -156,14 +156,19 @@ class Ledger(LedgerVerification, LedgerSpendingConditions): logger.debug(f"Loaded keyset {keyset.id}") return keyset - async def init_keysets(self, autosave=True) -> None: + async def init_keysets( + self, autosave: bool = True, duplicate_keysets: Optional[bool] = None + ) -> 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. Args: 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. + 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) @@ -190,17 +195,22 @@ class Ledger(LedgerVerification, LedgerSpendingConditions): # BEGIN BACKWARDS COMPATIBILITY < 0.15.0 # we duplicate new keysets and compute their old keyset id, and # we duplicate old keysets and compute their new keyset id - for _, keyset in copy.copy(self.keysets).items(): - keyset_copy = copy.copy(keyset) - assert keyset_copy.public_keys - if keyset.version_tuple >= (0, 15): - keyset_copy.id = derive_keyset_id_deprecated(keyset_copy.public_keys) - else: - keyset_copy.id = derive_keyset_id(keyset_copy.public_keys) - keyset_copy.duplicate_keyset_id = keyset.id - self.keysets[keyset_copy.id] = keyset_copy - # remember which keyset this keyset was duplicated from - logger.debug(f"Duplicated keyset id {keyset.id} -> {keyset_copy.id}") + if ( + duplicate_keysets is None and settings.mint_duplicate_keysets + ) or duplicate_keysets: + for _, keyset in copy.copy(self.keysets).items(): + keyset_copy = copy.copy(keyset) + assert keyset_copy.public_keys + if keyset.version_tuple >= (0, 15): + keyset_copy.id = derive_keyset_id_deprecated( + keyset_copy.public_keys + ) + else: + keyset_copy.id = derive_keyset_id(keyset_copy.public_keys) + keyset_copy.duplicate_keyset_id = keyset.id + self.keysets[keyset_copy.id] = keyset_copy + # remember which keyset this keyset was duplicated from + logger.debug(f"Duplicated keyset id {keyset.id} -> {keyset_copy.id}") # END BACKWARDS COMPATIBILITY < 0.15.0 def get_keyset(self, keyset_id: Optional[str] = None) -> Dict[int, str]: diff --git a/tests/test_mint_init.py b/tests/test_mint_init.py index 029a546..77f111b 100644 --- a/tests/test_mint_init.py +++ b/tests/test_mint_init.py @@ -30,6 +30,36 @@ def assert_amt(proofs: List[Proof], expected: int): assert [p.amount for p in proofs] == expected +@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_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_keysets = False + await ledger.init_keysets() + assert len(ledger.keysets) == 1 + + @pytest.mark.asyncio async def test_ledger_encrypt(): aes = AESCipher(DECRYPTON_KEY)