[Mint] Fix key rotation (#177)

* rotate keys every 5 seconds

* every 10 seconds

* do not regenerate all past keys for each epoch cycle

* remove automatic rotation

* make format

* print to logger

* rephrase print
This commit is contained in:
calle
2023-04-26 20:20:17 +02:00
committed by GitHub
parent 28812919ac
commit 87f9241de1
3 changed files with 39 additions and 7 deletions

View File

@@ -14,6 +14,8 @@ from .base import (
Wallet, Wallet,
) )
BRR = True
class FakeWallet(Wallet): class FakeWallet(Wallet):
"""https://github.com/lnbits/lnbits""" """https://github.com/lnbits/lnbits"""
@@ -77,7 +79,7 @@ class FakeWallet(Wallet):
async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse: async def pay_invoice(self, bolt11: str, fee_limit_msat: int) -> PaymentResponse:
invoice = decode(bolt11) invoice = decode(bolt11)
if invoice.payment_hash[:6] == self.privkey[:6]: if invoice.payment_hash[:6] == self.privkey[:6] or BRR:
await self.queue.put(invoice) await self.queue.put(invoice)
self.paid_invoices.add(invoice.payment_hash) self.paid_invoices.add(invoice.payment_hash)
return PaymentResponse(True, invoice.payment_hash, 0) return PaymentResponse(True, invoice.payment_hash, 0)
@@ -87,8 +89,7 @@ class FakeWallet(Wallet):
) )
async def get_invoice_status(self, checking_id: str) -> PaymentStatus: async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
paid = checking_id in self.paid_invoices or BRR
paid = checking_id in self.paid_invoices
return PaymentStatus(paid or None) return PaymentStatus(paid or None)
async def get_payment_status(self, _: str) -> PaymentStatus: async def get_payment_status(self, _: str) -> PaymentStatus:

View File

@@ -42,6 +42,7 @@ class Ledger:
self.crud = crud self.crud = crud
self.lightning = lightning self.lightning = lightning
self.pubkey = derive_pubkey(self.master_key) self.pubkey = derive_pubkey(self.master_key)
self.keysets = MintKeysets([])
async def load_used_proofs(self): async def load_used_proofs(self):
"""Load all used proofs from database.""" """Load all used proofs from database."""
@@ -86,11 +87,21 @@ class Ledger:
""" """
# load all past keysets from db # load all past keysets from db
tmp_keysets: List[MintKeyset] = await self.crud.get_keyset(db=self.db) tmp_keysets: List[MintKeyset] = await self.crud.get_keyset(db=self.db)
self.keysets = MintKeysets(tmp_keysets) # add keysets from db to current keysets
logger.trace(f"Loading {len(self.keysets.keysets)} keysets form db.") for k in tmp_keysets:
# generate all derived keys from stored derivation paths of past keysets if k.id and k.id not in self.keysets.keysets:
self.keysets.keysets[k.id] = k
logger.debug(
f"Currently, there are {len(self.keysets.keysets)} active keysets."
)
# generate all private keys, public keys, and keyset id from the derivation path for all keysets that are not yet generated
for _, v in self.keysets.keysets.items(): for _, v in self.keysets.keysets.items():
logger.trace(f"Generating keys for keyset {v.id}") # we already generated the keys for this keyset
if v.id and v.public_keys and len(v.public_keys):
continue
logger.debug(f"Generating keys for keyset {v.id}")
v.generate_keys(self.master_key) v.generate_keys(self.master_key)
# load the current keyset # load the current keyset
self.keyset = await self.load_keyset(self.derivation_path, autosave) self.keyset = await self.load_keyset(self.derivation_path, autosave)
@@ -128,6 +139,7 @@ class Ledger:
BlindedSignature: Generated promise. BlindedSignature: Generated promise.
""" """
keyset = keyset if keyset else self.keyset keyset = keyset if keyset else self.keyset
logger.trace(f"Generating promise with keyset {keyset.id}.")
private_key_amount = keyset.private_keys[amount] private_key_amount = keyset.private_keys[amount]
C_ = b_dhke.step2_bob(B_, private_key_amount) C_ = b_dhke.step2_bob(B_, private_key_amount)
await self.crud.store_promise( await self.crud.store_promise(
@@ -155,6 +167,9 @@ class Ledger:
if not proof.id: if not proof.id:
private_key_amount = self.keyset.private_keys[proof.amount] private_key_amount = self.keyset.private_keys[proof.amount]
else: else:
logger.trace(
f"Validating proof with keyset {self.keysets.keysets[proof.id].id}."
)
# use the appropriate active keyset for this proof.id # use the appropriate active keyset for this proof.id
private_key_amount = self.keysets.keysets[proof.id].private_keys[ private_key_amount = self.keysets.keysets[proof.id].private_keys[
proof.amount proof.amount

View File

@@ -1,6 +1,7 @@
# startup routine of the standalone app. These are the steps that need # startup routine of the standalone app. These are the steps that need
# to be taken by external apps importing the cashu mint. # to be taken by external apps importing the cashu mint.
import asyncio
import importlib import importlib
from loguru import logger from loguru import logger
@@ -28,6 +29,20 @@ ledger = Ledger(
) )
async def rotate_keys(n_seconds=10):
"""Rotate keyset epoch every n_seconds.
Note: This is just a helper function for testing purposes.
"""
i = 0
while True:
i += 1
logger.info("Rotating keys.")
ledger.derivation_path = f"0/0/0/{i}"
await ledger.init_keysets()
logger.info(f"Current keyset: {ledger.keyset.id}")
await asyncio.sleep(n_seconds)
async def start_mint_init(): async def start_mint_init():
await migrate_databases(ledger.db, migrations) await migrate_databases(ledger.db, migrations)
await ledger.load_used_proofs() await ledger.load_used_proofs()
@@ -45,3 +60,4 @@ async def start_mint_init():
logger.info(f"Data dir: {settings.cashu_dir}") logger.info(f"Data dir: {settings.cashu_dir}")
logger.info("Mint started.") logger.info("Mint started.")
# asyncio.create_task(rotate_keys())