This commit is contained in:
callebtc
2022-10-10 21:17:53 +02:00
parent bdd1b90aeb
commit 080ae4b224
6 changed files with 65 additions and 10 deletions

View File

@@ -2,13 +2,19 @@ import asyncio
import logging import logging
import sys import sys
from fastapi import FastAPI from fastapi import FastAPI, Request
from loguru import logger from loguru import logger
from cashu.core.settings import DEBUG, VERSION from cashu.core.settings import DEBUG, VERSION
from cashu.lightning import WALLET from cashu.lightning import WALLET
from cashu.mint.migrations import m001_initial from cashu.mint.migrations import m001_initial
from starlette_context.middleware import RawContextMiddleware
from starlette_context import context
from starlette.middleware import Middleware
from starlette.requests import Request as StarletteRequest
from . import ledger from . import ledger
from .router import router from .router import router
from .startup import load_ledger from .startup import load_ledger
@@ -49,6 +55,15 @@ def create_app(config_object="core.settings") -> FastAPI:
configure_logger() configure_logger()
middleware = [
Middleware(
RawContextMiddleware,
),
Middleware(
RawContextMiddleware,
),
]
app = FastAPI( app = FastAPI(
title="Cashu Mint", title="Cashu Mint",
description="Ecash wallet and mint with Bitcoin Lightning support.", description="Ecash wallet and mint with Bitcoin Lightning support.",
@@ -57,8 +72,8 @@ def create_app(config_object="core.settings") -> FastAPI:
"name": "MIT License", "name": "MIT License",
"url": "https://raw.githubusercontent.com/callebtc/cashu/main/LICENSE", "url": "https://raw.githubusercontent.com/callebtc/cashu/main/LICENSE",
}, },
middleware=middleware,
) )
return app return app

View File

@@ -7,6 +7,7 @@ from typing import Dict, List, Set
from loguru import logger from loguru import logger
import cashu.core.legacy as legacy
import cashu.core.b_dhke as b_dhke import cashu.core.b_dhke as b_dhke
import cashu.core.bolt11 as bolt11 import cashu.core.bolt11 as bolt11
from cashu.core.base import ( from cashu.core.base import (
@@ -36,6 +37,8 @@ from cashu.mint.crud import (
update_lightning_invoice, update_lightning_invoice,
) )
from starlette_context import context
class Ledger: class Ledger:
def __init__(self, secret_key: str, db: str, derivation_path=""): def __init__(self, secret_key: str, db: str, derivation_path=""):
@@ -113,6 +116,9 @@ class Ledger:
C = PublicKey(bytes.fromhex(proof.C), raw=True) C = PublicKey(bytes.fromhex(proof.C), raw=True)
# backwards compatibility with old hash_to_curve
if not context.get("version"):
return legacy.verify_pre_0_3_3(secret_key, C, proof.secret)
return b_dhke.verify(secret_key, C, proof.secret) return b_dhke.verify(secret_key, C, proof.secret)
def _verify_script(self, idx: int, proof: Proof): def _verify_script(self, idx: int, proof: Proof):

View File

@@ -20,6 +20,10 @@ from cashu.mint import ledger
router: APIRouter = APIRouter() router: APIRouter = APIRouter()
from starlette.requests import Request
from starlette_context import context
@router.get("/keys") @router.get("/keys")
def keys(): def keys():
"""Get the public keys of the mint""" """Get the public keys of the mint"""
@@ -49,7 +53,6 @@ async def request_mint(amount: int = 0):
@router.post("/mint") @router.post("/mint")
async def mint( async def mint(
payloads: MintRequest, payloads: MintRequest,
bolt11: Union[str, None] = None,
payment_hash: Union[str, None] = None, payment_hash: Union[str, None] = None,
): ):
""" """
@@ -70,10 +73,12 @@ async def mint(
@router.post("/melt") @router.post("/melt")
async def melt(payload: MeltRequest): async def melt(request: Request, payload: MeltRequest):
""" """
Requests tokens to be destroyed and sent out via Lightning. Requests tokens to be destroyed and sent out via Lightning.
""" """
context["version"] = request.headers.get("Client-version")
print(context["version"])
ok, preimage = await ledger.melt(payload.proofs, payload.invoice) ok, preimage = await ledger.melt(payload.proofs, payload.invoice)
resp = GetMeltResponse(paid=ok, preimage=preimage) resp = GetMeltResponse(paid=ok, preimage=preimage)
return resp return resp
@@ -97,11 +102,13 @@ async def check_fees(payload: CheckFeesRequest):
@router.post("/split") @router.post("/split")
async def split(payload: SplitRequest): async def split(request: Request, payload: SplitRequest):
""" """
Requetst a set of tokens with amount "total" to be split into two Requetst a set of tokens with amount "total" to be split into two
newly minted sets with amount "split" and "total-split". newly minted sets with amount "split" and "total-split".
""" """
context["version"] = request.headers.get("Client-version")
print(context["version"])
proofs = payload.proofs proofs = payload.proofs
amount = payload.amount amount = payload.amount
outputs = payload.outputs.blinded_messages if payload.outputs else None outputs = payload.outputs.blinded_messages if payload.outputs else None

View File

@@ -30,7 +30,7 @@ from cashu.core.script import (
step2_carol_sign_tx, step2_carol_sign_tx,
) )
from cashu.core.secp import PublicKey from cashu.core.secp import PublicKey
from cashu.core.settings import DEBUG from cashu.core.settings import DEBUG, VERSION
from cashu.core.split import amount_split from cashu.core.split import amount_split
from cashu.wallet.crud import ( from cashu.wallet.crud import (
get_keyset, get_keyset,
@@ -52,7 +52,10 @@ class LedgerAPI:
self.url = url self.url = url
async def _get_keys(self, url): async def _get_keys(self, url):
resp = requests.get(url + "/keys").json() resp = requests.get(
url + "/keys",
headers={"Client-version": VERSION},
).json()
keys = resp keys = resp
assert len(keys), Exception("did not receive any keys") assert len(keys), Exception("did not receive any keys")
keyset_keys = { keyset_keys = {
@@ -63,7 +66,10 @@ class LedgerAPI:
return keyset return keyset
async def _get_keysets(self, url): async def _get_keysets(self, url):
keysets = requests.get(url + "/keysets").json() keysets = requests.get(
url + "/keysets",
headers={"Client-version": VERSION},
).json()
assert len(keysets), Exception("did not receive any keysets") assert len(keysets), Exception("did not receive any keysets")
return keysets return keysets
@@ -177,6 +183,7 @@ class LedgerAPI:
self.url + "/mint", self.url + "/mint",
json=payloads.dict(), json=payloads.dict(),
params={"payment_hash": payment_hash}, params={"payment_hash": payment_hash},
headers={"Client-version": VERSION},
) )
resp.raise_for_status() resp.raise_for_status()
try: try:
@@ -235,6 +242,7 @@ class LedgerAPI:
resp = requests.post( resp = requests.post(
self.url + "/split", self.url + "/split",
json=split_payload.dict(include=_splitrequest_include_fields(proofs)), json=split_payload.dict(include=_splitrequest_include_fields(proofs)),
headers={"Client-version": VERSION},
) )
resp.raise_for_status() resp.raise_for_status()
try: try:
@@ -260,6 +268,7 @@ class LedgerAPI:
resp = requests.post( resp = requests.post(
self.url + "/check", self.url + "/check",
json=payload.dict(), json=payload.dict(),
headers={"Client-version": VERSION},
) )
resp.raise_for_status() resp.raise_for_status()
return_dict = resp.json() return_dict = resp.json()
@@ -272,6 +281,7 @@ class LedgerAPI:
resp = requests.post( resp = requests.post(
self.url + "/checkfees", self.url + "/checkfees",
json=payload.dict(), json=payload.dict(),
headers={"Client-version": VERSION},
) )
resp.raise_for_status() resp.raise_for_status()
@@ -293,6 +303,7 @@ class LedgerAPI:
resp = requests.post( resp = requests.post(
self.url + "/melt", self.url + "/melt",
json=payload.dict(include=_meltequest_include_fields(proofs)), json=payload.dict(include=_meltequest_include_fields(proofs)),
headers={"Client-version": VERSION},
) )
resp.raise_for_status() resp.raise_for_status()

19
poetry.lock generated
View File

@@ -167,7 +167,7 @@ starlette = "0.19.1"
[package.extras] [package.extras]
all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"]
dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"]
doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.2)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.5.0)"] doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.5.0)"]
test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"]
[[package]] [[package]]
@@ -553,6 +553,17 @@ typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""
[package.extras] [package.extras]
full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"]
[[package]]
name = "starlette-context"
version = "0.3.4"
description = "Access context in Starlette"
category = "main"
optional = false
python-versions = ">=3.7"
[package.dependencies]
starlette = "*"
[[package]] [[package]]
name = "tomli" name = "tomli"
version = "2.0.1" version = "2.0.1"
@@ -632,7 +643,7 @@ testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=
[metadata] [metadata]
lock-version = "1.1" lock-version = "1.1"
python-versions = "^3.7" python-versions = "^3.7"
content-hash = "b4e980ee90226bab07750b1becc8c69df7752f6d168d200a79c782aa1efe61da" content-hash = "14ff9c57ca971c645f1a075b5c6fa0a84a38eaf6399d14afa724136728a3da03"
[metadata.files] [metadata.files]
anyio = [ anyio = [
@@ -999,6 +1010,10 @@ starlette = [
{file = "starlette-0.19.1-py3-none-any.whl", hash = "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf"}, {file = "starlette-0.19.1-py3-none-any.whl", hash = "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf"},
{file = "starlette-0.19.1.tar.gz", hash = "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7"}, {file = "starlette-0.19.1.tar.gz", hash = "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7"},
] ]
starlette-context = [
{file = "starlette_context-0.3.4-py37-none-any.whl", hash = "sha256:b16bf17bd3ead7ded2f458aebf7f913744b9cf28305e16c69b435a6c6ddf1135"},
{file = "starlette_context-0.3.4.tar.gz", hash = "sha256:2d28e1838302fb5d5adacadc10fb73fb2d5cca1f0aa1e279698701cc96f1567c"},
]
tomli = [ tomli = [
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},

View File

@@ -22,6 +22,7 @@ bitstring = "^3.1.9"
secp256k1 = "^0.14.0" secp256k1 = "^0.14.0"
sqlalchemy-aio = "^0.17.0" sqlalchemy-aio = "^0.17.0"
python-bitcoinlib = "^0.11.2" python-bitcoinlib = "^0.11.2"
starlette-context = "^0.3.4"
[tool.poetry.dev-dependencies] [tool.poetry.dev-dependencies]
black = {version = "^22.8.0", allow-prereleases = true} black = {version = "^22.8.0", allow-prereleases = true}