Determinstic secrets / ecash restore (#131)

* first working version but some sats go missing

* back at it

* make format

* restore to main

* move mint database

* fix some tests

* make format

* remove old _construct_outputs we reintroduced in merge with main

* add type annotations

* add wallet private key to tests

* wallet: load proofs

* fix tests

* _generate_secrets with deterministic generation (temporary)

* allow wallet initialization with custom private key

* add pk to wallet api test

* mint scope=module

* remove private_key from test_wallet.py to see if it helps with the github tests

* readd private keys to tests

* workflow without env

* add more private key!

* readd env

* ledger scope session

* add default private key for testing

* generate private keys if not available

* testing

* its working!!!

* first iteration of bip32 working

* get mint info and add many type annotations

* tests

* fix tests with bip32

* restore from multiple mints

* disable profiler

* make format

* failed POST /mint do not increment secret counter

* store derivation path in each token

* fix tests

* refactor migrations so private keys can be generated by the wallet with .with_db() classmethod

* start fixing tests

* all tests passing except those that need to set a specific private key

* bip39 mnemonic to seed - with db but restore doesnt work yet with custom seed

* mnemonic restore works

* enter mnemonic in cli

* fix tests to use different mnemonic

* properly ask user for seed input

* tests: dont ask for inputs

* try to fix tests

* fix cashu -d

* fixing

* bump version and add more text to mnemonic enter

* add more comments

* add many more comments and type annotations in the wallet

* dont print generated mnemonic and dont wait for input

* fix test

* does this fix tests?

* sigh....

* make format

* do not restore from an initialized wallet

* fix mnemonics

* fix nitpicks

* print wallet name if nonstandard wallet

* fix merge error and remove comments

* poetry lock and requirements

* remove unused code

* fix tests

* mnemonic.lower() and add keyset id if not present for backwards compat

* edit comment
This commit is contained in:
callebtc
2023-07-24 13:42:56 +02:00
committed by GitHub
parent 337456333e
commit 0b2468914d
29 changed files with 1881 additions and 650 deletions

View File

@@ -1,6 +1,6 @@
import json
import time
from typing import Any, List, Optional
from typing import Any, List, Optional, Tuple
from ..core.base import Invoice, KeyBase, P2SHScript, Proof, WalletKeyset
from ..core.db import Connection, Database
@@ -14,10 +14,17 @@ async def store_proof(
await (conn or db).execute(
"""
INSERT INTO proofs
(id, amount, C, secret, time_created)
VALUES (?, ?, ?, ?, ?)
(id, amount, C, secret, time_created, derivation_path)
VALUES (?, ?, ?, ?, ?, ?)
""",
(proof.id, proof.amount, str(proof.C), str(proof.secret), int(time.time())),
(
proof.id,
proof.amount,
str(proof.C),
str(proof.secret),
int(time.time()),
proof.derivation_path,
),
)
@@ -62,10 +69,17 @@ async def invalidate_proof(
await (conn or db).execute(
"""
INSERT INTO proofs_used
(amount, C, secret, time_used, id)
VALUES (?, ?, ?, ?, ?)
(amount, C, secret, time_used, id, derivation_path)
VALUES (?, ?, ?, ?, ?, ?)
""",
(proof.amount, str(proof.C), str(proof.secret), int(time.time()), proof.id),
(
proof.amount,
str(proof.C),
str(proof.secret),
int(time.time()),
proof.id,
proof.derivation_path,
),
)
@@ -329,6 +343,52 @@ async def update_lightning_invoice(
)
async def bump_secret_derivation(
db: Database,
keyset_id: str,
by: int = 1,
skip: bool = False,
conn: Optional[Connection] = None,
):
rows = await (conn or db).fetchone(
"SELECT counter from keysets WHERE id = ?", (keyset_id,)
)
# if no counter for this keyset, create one
if not rows:
await (conn or db).execute(
"UPDATE keysets SET counter = ? WHERE id = ?",
(
0,
keyset_id,
),
)
counter = 0
else:
counter = int(rows[0])
if not skip:
await (conn or db).execute(
f"UPDATE keysets SET counter = counter + {by} WHERE id = ?",
(keyset_id,),
)
return counter
async def set_secret_derivation(
db: Database,
keyset_id: str,
counter: int,
conn: Optional[Connection] = None,
):
await (conn or db).execute(
"UPDATE keysets SET counter = ? WHERE id = ?",
(
counter,
keyset_id,
),
)
async def set_nostr_last_check_timestamp(
db: Database,
timestamp: int,
@@ -351,3 +411,41 @@ async def get_nostr_last_check_timestamp(
("dm",),
)
return row[0] if row else None
async def get_seed_and_mnemonic(
db: Database,
conn: Optional[Connection] = None,
) -> Optional[Tuple[str, str]]:
row = await (conn or db).fetchone(
f"""
SELECT seed, mnemonic from seed
""",
)
return (
(
row[0],
row[1],
)
if row
else None
)
async def store_seed_and_mnemonic(
db: Database,
seed: str,
mnemonic: str,
conn: Optional[Connection] = None,
):
await (conn or db).execute(
f"""
INSERT INTO seed
(seed, mnemonic)
VALUES (?, ?)
""",
(
seed,
mnemonic,
),
)