Skip to content

Commit

Permalink
Merge branch 'dleq' of github.com:callebtc/cashu into dleq
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Sep 19, 2023
2 parents 5b5b8fa + 61b7ff4 commit 809c52f
Show file tree
Hide file tree
Showing 37 changed files with 921 additions and 806 deletions.
3 changes: 1 addition & 2 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ TOR=TRUE

# NOSTR
# nostr private key to which to receive tokens to
NOSTR_PRIVATE_KEY=nostr_privatekey_here_hex_or_bech32_nsec
# NOSTR_PRIVATE_KEY=nostr_privatekey_here_hex_or_bech32_nsec
# nostr relays (comma separated list)
NOSTR_RELAYS=["wss://nostr-pub.wellorder.net"]

Expand All @@ -38,7 +38,6 @@ MINT_INFO_CONTACT=[["email","[email protected]"], ["twitter","@me"], ["nostr", "np
MINT_INFO_MOTD="Message to users"

MINT_PRIVATE_KEY=supersecretprivatekey
MINT_DATABASE=data/mint
# increment derivation path to rotate to a new keyset
MINT_DERIVATION_PATH="0/0/0/0"

Expand Down
8 changes: 0 additions & 8 deletions .flake8

This file was deleted.

11 changes: 6 additions & 5 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ jobs:
run: poetry install
- name: Check black
run: make black-check
- name: Check isort
run: make isort-check
linting:
mypy:
runs-on: ubuntu-latest
strategy:
matrix:
Expand All @@ -49,5 +47,8 @@ jobs:
run: yes | poetry run mypy cashu --install-types || true
- name: Run mypy
run: poetry run mypy cashu --ignore-missing
- name: Run flake8
run: poetry run flake8
ruff:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: chartboost/ruff-action@v1
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ tor.pid

# Default data directory
/data
/test_data

# MacOS
.DS_Store
16 changes: 5 additions & 11 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
exclude: '^cashu/nostr/.*'

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
Expand All @@ -14,16 +13,11 @@ repos:
- id: mixed-line-ending
- id: check-case-conflict
- repo: https://github.com/psf/black
rev: 22.6.0
rev: 23.7.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
rev: 5.12.0
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.0.283
hooks:
- id: isort
args: ['--profile', 'black']
- repo: https://github.com/pycqa/flake8
rev: 6.0.0
hooks:
- id: flake8
entry: poetry run flake8
- id: ruff
args: [ --fix, --exit-non-zero-on-fix ]
17 changes: 6 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
isort:
poetry run isort --profile black . --skip cashu/nostr
ruff:
poetry run ruff check . --fix

isort-check:
poetry run isort --profile black --check-only . --skip cashu/nostr
ruff-check:
poetry run ruff check .

black:
poetry run black . --exclude cashu/nostr
Expand All @@ -13,12 +13,9 @@ black-check:
mypy:
poetry run mypy cashu tests --ignore-missing

flake8:
poetry run flake8 cashu tests
format: black ruff

format: isort black

check: isort-check black-check flake8 mypy
check: black-check ruff-check mypy

clean:
rm -r cashu.egg-info/ || true
Expand All @@ -32,8 +29,6 @@ package:
python setup.py sdist bdist_wheel

test:
LIGHTNING=false \
TOR=false \
poetry run pytest tests --cov-report xml --cov cashu

install:
Expand Down
37 changes: 18 additions & 19 deletions cashu/core/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ class SecretKind:


class SigFlags:
SIG_INPUTS = (
"SIG_INPUTS" # require signatures only on the inputs (default signature flag)
SIG_INPUTS = ( # require signatures only on the inputs (default signature flag)
"SIG_INPUTS"
)
SIG_ALL = "SIG_ALL" # require signatures on inputs and outputs

Expand Down Expand Up @@ -180,23 +180,19 @@ class Proof(BaseModel):
Value token
"""

id: Union[
None, str
] = "" # NOTE: None for backwards compatibility for old clients that do not include the keyset id < 0.3

# NOTE: None for backwards compatibility for old clients that do not include the keyset id < 0.3
id: Union[None, str] = ""
amount: int = 0
secret: str = "" # secret or message to be blinded and signed
C: str = "" # signature on secret, unblinded by wallet
dleq: Union[DLEQWallet, None] = None # DLEQ proof

p2pksigs: Union[List[str], None] = [] # P2PK signature
p2shscript: Union[P2SHScript, None] = None # P2SH spending condition
reserved: Union[
None, bool
] = False # whether this proof is reserved for sending, used for coin management in the wallet
send_id: Union[
None, str
] = "" # unique ID of send attempt, used for grouping pending tokens in the wallet
# whether this proof is reserved for sending, used for coin management in the wallet
reserved: Union[None, bool] = False
# unique ID of send attempt, used for grouping pending tokens in the wallet
send_id: Union[None, str] = ""
time_created: Union[None, str] = ""
time_reserved: Union[None, str] = ""
derivation_path: Union[None, str] = "" # derivation path of the proof
Expand Down Expand Up @@ -377,9 +373,9 @@ class CheckSpendableRequest(BaseModel):

class CheckSpendableResponse(BaseModel):
spendable: List[bool]
pending: Optional[
List[bool]
] = None # TODO: Uncomment when all mints are updated to 0.12.3 and support /check
pending: Optional[List[bool]] = (
None # TODO: Uncomment when all mints are updated to 0.12.3 and support /check
)
# with pending tokens (kept for backwards compatibility of new wallets with old mints)


Expand Down Expand Up @@ -460,9 +456,11 @@ def deserialize(serialized: str):

return cls(
id=row["id"],
public_keys=deserialize(str(row["public_keys"]))
if dict(row).get("public_keys")
else {},
public_keys=(
deserialize(str(row["public_keys"]))
if dict(row).get("public_keys")
else {}
),
mint_url=row["mint_url"],
valid_from=row["valid_from"],
valid_to=row["valid_to"],
Expand Down Expand Up @@ -528,7 +526,8 @@ def generate_keys(self, seed):
self.id = derive_keyset_id(self.public_keys) # type: ignore
if backwards_compatibility_pre_0_12:
logger.warning(
f"WARNING: Using weak key derivation for keyset {self.id} (backwards compatibility < 0.12)"
f"WARNING: Using weak key derivation for keyset {self.id} (backwards"
" compatibility < 0.12)"
)


Expand Down
1 change: 0 additions & 1 deletion cashu/core/bolt11.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ def lnencode(addr, privkey):
tags_set = set()

for k, v in addr.tags:

# BOLT #11:
#
# A writer MUST NOT include more than one `d`, `h`, `n` or `x` fields,
Expand Down
2 changes: 1 addition & 1 deletion cashu/core/crypto/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,5 @@ def derive_keyset_id(keys: Dict[int, PublicKey]):
def random_hash() -> str:
"""Returns a base64-urlsafe encoded random hash."""
return base64.urlsafe_b64encode(
bytes([random.getrandbits(8) for i in range(32)])
bytes([random.getrandbits(8) for i in range(30)])
).decode()
6 changes: 3 additions & 3 deletions cashu/core/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ def _parse_timestamp(value, _):
psycopg2.extensions.new_type( # type: ignore
(1082, 1083, 1266),
"DATE2INT",
lambda value, curs: time.mktime(value.timetuple())
if value is not None
else None,
lambda value, curs: (
time.mktime(value.timetuple()) if value is not None else None
),
)
)

Expand Down
6 changes: 4 additions & 2 deletions cashu/core/migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,13 @@ async def run_migration(db, migrations_module):
exists = None
if conn.type == SQLITE:
exists = await conn.fetchone(
f"SELECT * FROM sqlite_master WHERE type='table' AND name='{table_with_schema(db, 'dbversions')}'"
"SELECT * FROM sqlite_master WHERE type='table' AND"
f" name='{table_with_schema(db, 'dbversions')}'"
)
elif conn.type in {POSTGRES, COCKROACH}:
exists = await conn.fetchone(
f"SELECT * FROM information_schema.tables WHERE table_name = '{table_with_schema(db, 'dbversions')}'"
"SELECT * FROM information_schema.tables WHERE table_name ="
f" '{table_with_schema(db, 'dbversions')}'"
)

if not exists:
Expand Down
6 changes: 4 additions & 2 deletions cashu/core/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ def verify_bitcoin_script(txin_redeemScript_b64, txin_signature_b64):
txin_redeemScript_b64 = base64.urlsafe_b64encode(txin_redeemScript).decode()
txin_signature_b64 = base64.urlsafe_b64encode(txin_signature).decode()
print(
f"Carol to Bob:\nscript: {txin_redeemScript.__repr__()}\nscript: {txin_redeemScript_b64}\nsignature: {txin_signature_b64}\n"
f"Carol to Bob:\nscript: {txin_redeemScript.__repr__()}\nscript:"
f" {txin_redeemScript_b64}\nsignature: {txin_signature_b64}\n"
)
print("")
# ---------
Expand All @@ -155,7 +156,8 @@ def verify_bitcoin_script(txin_redeemScript_b64, txin_signature_b64):
tx, _ = step1_bob_carol_create_tx(txin_p2sh_address)

print(
f"Bob verifies:\nscript: {txin_redeemScript_b64}\nsignature: {txin_signature_b64}\n"
f"Bob verifies:\nscript: {txin_redeemScript_b64}\nsignature:"
f" {txin_signature_b64}\n"
)
script_valid = step3_bob_verify_script(txin_signature, txin_redeemScript, tx)
# MINT redeems tokens and stores P2SH:txin_p2sh_address
Expand Down
51 changes: 44 additions & 7 deletions cashu/mint/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from traceback import print_exception

from fastapi import FastAPI, status
from fastapi.exception_handlers import (
request_validation_exception_handler as _request_validation_exception_handler,
)
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse

# from fastapi_profiler import PyInstrumentProfilerMiddleware
Expand Down Expand Up @@ -36,14 +40,19 @@ def configure_logger() -> None:
class Formatter:
def __init__(self):
self.padding = 0
self.minimal_fmt: str = "<green>{time:YYYY-MM-DD HH:mm:ss.SS}</green> | <level>{level}</level> | <level>{message}</level>\n"
self.minimal_fmt = (
"<green>{time:YYYY-MM-DD HH:mm:ss.SS}</green> |"
" <level>{level}</level> | <level>{message}</level>\n"
)
if settings.debug:
self.fmt: str = (
"<green>{time:YYYY-MM-DD HH:mm:ss.SS}</green> | <level>{level: <4}</level> | <cyan>{name}</cyan>:<cyan>"
"{function}</cyan>:<cyan>{line}</cyan> | <level>{message}</level>\n"
self.fmt = (
"<green>{time:YYYY-MM-DD HH:mm:ss.SS}</green> | <level>{level:"
" <4}</level> |"
" <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan>"
" | <level>{message}</level>\n"
)
else:
self.fmt: str = self.minimal_fmt
self.fmt = self.minimal_fmt

def format(self, record):
function = "{function}".format(**record)
Expand Down Expand Up @@ -109,6 +118,12 @@ def emit(self, record):

@app.middleware("http")
async def catch_exceptions(request: Request, call_next):
CORS_HEADERS = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "*",
"Access-Control-Allow-Headers": "*",
"Access-Control-Allow-Credentials": "true",
}
try:
return await call_next(request)
except Exception as e:
Expand All @@ -119,22 +134,44 @@ async def catch_exceptions(request: Request, call_next):

if isinstance(e, CashuError):
logger.error(f"CashuError: {err_message}")
# return with cors headers
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": err_message, "code": e.code},
headers=CORS_HEADERS,
)
logger.error(f"Exception: {err_message}")
if settings.debug:
print_exception(*sys.exc_info())
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
status_code=status.HTTP_400_BAD_REQUEST,
content={"detail": err_message, "code": 0},
headers=CORS_HEADERS,
)


async def request_validation_exception_handler(
request: Request, exc: RequestValidationError
) -> JSONResponse:
"""
This is a wrapper to the default RequestValidationException handler of FastAPI.
This function will be called when client input is not valid.
"""
query_params = request.query_params._dict
detail = {
"errors": exc.errors(),
"query_params": query_params,
}
# log the error
logger.error(detail)
# pass on
return await _request_validation_exception_handler(request, exc)


@app.on_event("startup")
async def startup_mint():
await start_mint_init()


app.include_router(router=router)
app.add_exception_handler(RequestValidationError, request_validation_exception_handler)
12 changes: 4 additions & 8 deletions cashu/mint/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,9 @@ async def get_proofs_used(
db: Database,
conn: Optional[Connection] = None,
):
rows = await (conn or db).fetchall(
f"""
rows = await (conn or db).fetchall(f"""
SELECT secret from {table_with_schema(db, 'proofs_used')}
"""
)
""")
return [row[0] for row in rows]


Expand Down Expand Up @@ -128,11 +126,9 @@ async def get_proofs_pending(
db: Database,
conn: Optional[Connection] = None,
):
rows = await (conn or db).fetchall(
f"""
rows = await (conn or db).fetchall(f"""
SELECT * from {table_with_schema(db, 'proofs_pending')}
"""
)
""")
return [Proof(**r) for r in rows]


Expand Down
Loading

0 comments on commit 809c52f

Please sign in to comment.