mirror of
https://github.com/aljazceru/nutshell.git
synced 2025-12-20 02:24:20 +01:00
index on db and read spent proofs from db (#370)
* index on db and read spent proofs from db * add benchmark for testing * remove benchmark * add option to disable cached secrets * disable python 3.9 tests
This commit is contained in:
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@@ -12,8 +12,9 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
python-version: ["3.9", "3.10"]
|
||||
python-version: ["3.10"]
|
||||
poetry-version: ["1.5.1"]
|
||||
mint-cache-secrets: ["true", "false"]
|
||||
# db-url: ["", "postgres://cashu:cashu@localhost:5432/test"] # TODO: Postgres test not working
|
||||
db-url: [""]
|
||||
backend-wallet-class: ["FakeWallet"]
|
||||
@@ -21,6 +22,7 @@ jobs:
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
poetry-version: ${{ matrix.poetry-version }}
|
||||
mint-cache-secrets: ${{ matrix.mint-cache-secrets }}
|
||||
regtest:
|
||||
uses: ./.github/workflows/regtest.yml
|
||||
strategy:
|
||||
|
||||
4
.github/workflows/tests.yml
vendored
4
.github/workflows/tests.yml
vendored
@@ -15,6 +15,9 @@ on:
|
||||
os:
|
||||
default: "ubuntu-latest"
|
||||
type: string
|
||||
mint-cache-secrets:
|
||||
default: "false"
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
poetry:
|
||||
@@ -47,6 +50,7 @@ jobs:
|
||||
MINT_HOST: localhost
|
||||
MINT_PORT: 3337
|
||||
MINT_DATABASE: ${{ inputs.db-url }}
|
||||
MINT_CACHE_SECRETS: ${{ inputs.mint-cache-secrets }}
|
||||
TOR: false
|
||||
run: |
|
||||
make test
|
||||
|
||||
@@ -5,6 +5,7 @@ import time
|
||||
from contextlib import asynccontextmanager
|
||||
from typing import Optional, Union
|
||||
|
||||
from loguru import logger
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy_aio.base import AsyncConnection
|
||||
from sqlalchemy_aio.strategy import ASYNCIO_STRATEGY # type: ignore
|
||||
@@ -130,7 +131,7 @@ class Database(Compat):
|
||||
# )
|
||||
else:
|
||||
if not os.path.exists(self.db_location):
|
||||
print(f"Creating database directory: {self.db_location}")
|
||||
logger.info(f"Creating database directory: {self.db_location}")
|
||||
os.makedirs(self.db_location)
|
||||
self.path = os.path.join(self.db_location, f"{self.name}.sqlite3")
|
||||
database_uri = f"sqlite:///{self.path}"
|
||||
|
||||
@@ -44,6 +44,7 @@ class EnvSettings(CashuSettings):
|
||||
debug: bool = Field(default=False)
|
||||
log_level: str = Field(default="INFO")
|
||||
cashu_dir: str = Field(default=os.path.join(str(Path.home()), ".cashu"))
|
||||
debug_profiling: bool = Field(default=False)
|
||||
|
||||
|
||||
class MintSettings(CashuSettings):
|
||||
@@ -61,6 +62,8 @@ class MintSettings(CashuSettings):
|
||||
mint_lnbits_endpoint: str = Field(default=None)
|
||||
mint_lnbits_key: str = Field(default=None)
|
||||
|
||||
mint_cache_secrets: bool = Field(default=True)
|
||||
|
||||
|
||||
class MintInformation(CashuSettings):
|
||||
mint_info_name: str = Field(default="Cashu mint")
|
||||
|
||||
@@ -8,8 +8,6 @@ from fastapi.exception_handlers import (
|
||||
)
|
||||
from fastapi.exceptions import RequestValidationError
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
# from fastapi_profiler import PyInstrumentProfilerMiddleware
|
||||
from loguru import logger
|
||||
from starlette.middleware import Middleware
|
||||
from starlette.middleware.cors import CORSMiddleware
|
||||
@@ -20,6 +18,9 @@ from ..core.settings import settings
|
||||
from .router import router
|
||||
from .startup import start_mint_init
|
||||
|
||||
if settings.debug_profiling:
|
||||
from fastapi_profiler import PyInstrumentProfilerMiddleware
|
||||
|
||||
# from starlette_context import context
|
||||
# from starlette_context.middleware import RawContextMiddleware
|
||||
|
||||
@@ -108,7 +109,9 @@ def create_app(config_object="core.settings") -> FastAPI:
|
||||
middleware=middleware,
|
||||
)
|
||||
|
||||
# app.add_middleware(PyInstrumentProfilerMiddleware)
|
||||
if settings.debug_profiling:
|
||||
assert PyInstrumentProfilerMiddleware is not None
|
||||
app.add_middleware(PyInstrumentProfilerMiddleware)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ class LedgerCrud:
|
||||
db: Database,
|
||||
id: str,
|
||||
conn: Optional[Connection] = None,
|
||||
):
|
||||
) -> Optional[Invoice]:
|
||||
return await get_lightning_invoice(
|
||||
db=db,
|
||||
id=id,
|
||||
@@ -42,8 +42,23 @@ class LedgerCrud:
|
||||
self,
|
||||
db: Database,
|
||||
conn: Optional[Connection] = None,
|
||||
):
|
||||
return await get_secrets_used(db=db, conn=conn)
|
||||
) -> List[str]:
|
||||
return await get_secrets_used(
|
||||
db=db,
|
||||
conn=conn,
|
||||
)
|
||||
|
||||
async def get_proof_used(
|
||||
self,
|
||||
db: Database,
|
||||
proof: Proof,
|
||||
conn: Optional[Connection] = None,
|
||||
) -> Optional[Proof]:
|
||||
return await get_proof_used(
|
||||
db=db,
|
||||
proof=proof,
|
||||
conn=conn,
|
||||
)
|
||||
|
||||
async def invalidate_proof(
|
||||
self,
|
||||
@@ -215,7 +230,7 @@ async def get_promise(
|
||||
async def get_secrets_used(
|
||||
db: Database,
|
||||
conn: Optional[Connection] = None,
|
||||
):
|
||||
) -> List[str]:
|
||||
rows = await (conn or db).fetchall(f"""
|
||||
SELECT secret from {table_with_schema(db, 'proofs_used')}
|
||||
""")
|
||||
@@ -253,6 +268,21 @@ async def get_proofs_pending(
|
||||
return [Proof(**r) for r in rows]
|
||||
|
||||
|
||||
async def get_proof_used(
|
||||
db: Database,
|
||||
proof: Proof,
|
||||
conn: Optional[Connection] = None,
|
||||
) -> Optional[Proof]:
|
||||
row = await (conn or db).fetchone(
|
||||
f"""
|
||||
SELECT 1 from {table_with_schema(db, 'proofs_used')}
|
||||
WHERE secret = ?
|
||||
""",
|
||||
(str(proof.secret),),
|
||||
)
|
||||
return Proof(**row) if row else None
|
||||
|
||||
|
||||
async def set_proof_pending(
|
||||
db: Database,
|
||||
proof: Proof,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import asyncio
|
||||
import math
|
||||
from typing import Dict, List, Optional, Set, Tuple
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
import bolt11
|
||||
from loguru import logger
|
||||
@@ -49,7 +49,6 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerLightning):
|
||||
crud: LedgerCrud,
|
||||
derivation_path="",
|
||||
):
|
||||
self.secrets_used: Set[str] = set()
|
||||
self.master_key = seed
|
||||
self.derivation_path = derivation_path
|
||||
|
||||
@@ -162,9 +161,10 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerLightning):
|
||||
# Mark proofs as used and prepare new promises
|
||||
secrets = set([p.secret for p in proofs])
|
||||
self.secrets_used |= secrets
|
||||
async with self.db.connect() as conn:
|
||||
# store in db
|
||||
for p in proofs:
|
||||
await self.crud.invalidate_proof(proof=p, db=self.db)
|
||||
await self.crud.invalidate_proof(proof=p, db=self.db, conn=conn)
|
||||
|
||||
async def _generate_change_promises(
|
||||
self,
|
||||
@@ -538,70 +538,59 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerLightning):
|
||||
async def _generate_promises(
|
||||
self, B_s: List[BlindedMessage], keyset: Optional[MintKeyset] = None
|
||||
) -> list[BlindedSignature]:
|
||||
"""Generates promises that sum to the given amount.
|
||||
"""Generates a promises (Blind signatures) for given amount and returns a pair (amount, C').
|
||||
|
||||
Args:
|
||||
B_s (List[BlindedMessage]): _description_
|
||||
keyset (Optional[MintKeyset], optional): _description_. Defaults to None.
|
||||
|
||||
Returns:
|
||||
list[BlindedSignature]: _description_
|
||||
"""
|
||||
return [
|
||||
await self._generate_promise(
|
||||
b.amount, PublicKey(bytes.fromhex(b.B_), raw=True), keyset
|
||||
)
|
||||
for b in B_s
|
||||
]
|
||||
|
||||
async def _generate_promise(
|
||||
self, amount: int, B_: PublicKey, keyset: Optional[MintKeyset] = None
|
||||
) -> BlindedSignature:
|
||||
"""Generates a promise (Blind signature) for given amount and returns a pair (amount, C').
|
||||
|
||||
Args:
|
||||
amount (int): Amount of the promise.
|
||||
B_ (PublicKey): Blinded secret (point on curve)
|
||||
B_s (List[BlindedMessage]): Blinded secret (point on curve)
|
||||
keyset (Optional[MintKeyset], optional): Which keyset to use. Private keys will be taken from this keyset. Defaults to None.
|
||||
|
||||
Returns:
|
||||
BlindedSignature: Generated promise.
|
||||
list[BlindedSignature]: Generated BlindedSignatures.
|
||||
"""
|
||||
keyset = keyset if keyset else self.keyset
|
||||
promises = []
|
||||
for b in B_s:
|
||||
amount = b.amount
|
||||
B_ = PublicKey(bytes.fromhex(b.B_), raw=True)
|
||||
logger.trace(f"Generating promise with keyset {keyset.id}.")
|
||||
private_key_amount = keyset.private_keys[amount]
|
||||
C_, e, s = b_dhke.step2_bob(B_, private_key_amount)
|
||||
promises.append((B_, amount, C_, e, s))
|
||||
|
||||
signatures = []
|
||||
async with self.db.connect() as conn:
|
||||
for promise in promises:
|
||||
B_, amount, C_, e, s = promise
|
||||
logger.trace(f"crud: _generate_promise storing promise for {amount}")
|
||||
await self.crud.store_promise(
|
||||
amount=amount,
|
||||
id=keyset.id,
|
||||
B_=B_.serialize().hex(),
|
||||
C_=C_.serialize().hex(),
|
||||
e=e.serialize(),
|
||||
s=s.serialize(),
|
||||
db=self.db,
|
||||
id=keyset.id,
|
||||
conn=conn,
|
||||
)
|
||||
logger.trace(f"crud: _generate_promise stored promise for {amount}")
|
||||
return BlindedSignature(
|
||||
signature = BlindedSignature(
|
||||
id=keyset.id,
|
||||
amount=amount,
|
||||
C_=C_.serialize().hex(),
|
||||
dleq=DLEQ(e=e.serialize(), s=s.serialize()),
|
||||
)
|
||||
signatures.append(signature)
|
||||
return signatures
|
||||
|
||||
# ------- PROOFS -------
|
||||
|
||||
async def load_used_proofs(self) -> None:
|
||||
"""Load all used proofs from database."""
|
||||
logger.trace("crud: loading used proofs")
|
||||
logger.debug("Loading used proofs into memory")
|
||||
secrets_used = await self.crud.get_secrets_used(db=self.db)
|
||||
logger.trace(f"crud: loaded {len(secrets_used)} used proofs")
|
||||
logger.debug(f"Loaded {len(secrets_used)} used proofs")
|
||||
self.secrets_used = set(secrets_used)
|
||||
|
||||
def _check_spendable(self, proof: Proof) -> bool:
|
||||
"""Checks whether the proof was already spent."""
|
||||
return proof.secret not in self.secrets_used
|
||||
|
||||
async def _check_pending(self, proofs: List[Proof]) -> List[bool]:
|
||||
"""Checks whether the proof is still pending."""
|
||||
proofs_pending = await self.crud.get_proofs_pending(db=self.db)
|
||||
@@ -628,13 +617,12 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerLightning):
|
||||
List[bool]: List of which proof is still spendable (True if still spendable, else False)
|
||||
List[bool]: List of which proof are pending (True if pending, else False)
|
||||
"""
|
||||
spendable = [self._check_spendable(p) for p in proofs]
|
||||
|
||||
spendable = await self._check_proofs_spendable(proofs)
|
||||
pending = await self._check_pending(proofs)
|
||||
return spendable, pending
|
||||
|
||||
async def _set_proofs_pending(
|
||||
self, proofs: List[Proof], conn: Optional[Connection] = None
|
||||
) -> None:
|
||||
async def _set_proofs_pending(self, proofs: List[Proof]) -> None:
|
||||
"""If none of the proofs is in the pending table (_validate_proofs_pending), adds proofs to
|
||||
the list of pending proofs or removes them. Used as a mutex for proofs.
|
||||
|
||||
@@ -646,22 +634,24 @@ class Ledger(LedgerVerification, LedgerSpendingConditions, LedgerLightning):
|
||||
"""
|
||||
# first we check whether these proofs are pending already
|
||||
async with self.proofs_pending_lock:
|
||||
async with self.db.connect() as conn:
|
||||
await self._validate_proofs_pending(proofs, conn)
|
||||
for p in proofs:
|
||||
try:
|
||||
await self.crud.set_proof_pending(proof=p, db=self.db, conn=conn)
|
||||
await self.crud.set_proof_pending(
|
||||
proof=p, db=self.db, conn=conn
|
||||
)
|
||||
except Exception:
|
||||
raise TransactionError("proofs already pending.")
|
||||
|
||||
async def _unset_proofs_pending(
|
||||
self, proofs: List[Proof], conn: Optional[Connection] = None
|
||||
) -> None:
|
||||
async def _unset_proofs_pending(self, proofs: List[Proof]) -> None:
|
||||
"""Deletes proofs from pending table.
|
||||
|
||||
Args:
|
||||
proofs (List[Proof]): Proofs to delete.
|
||||
"""
|
||||
async with self.proofs_pending_lock:
|
||||
async with self.db.connect() as conn:
|
||||
for p in proofs:
|
||||
await self.crud.unset_proof_pending(proof=p, db=self.db, conn=conn)
|
||||
|
||||
|
||||
@@ -204,3 +204,13 @@ async def m009_add_out_to_invoices(db: Database):
|
||||
await conn.execute(
|
||||
f"ALTER TABLE {table_with_schema(db, 'invoices')} ADD COLUMN out BOOL"
|
||||
)
|
||||
|
||||
|
||||
async def m010_add_index_to_proofs_used(db: Database):
|
||||
# create index on proofs_used table for secret
|
||||
async with db.connect() as conn:
|
||||
await conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS"
|
||||
f" {table_with_schema(db, 'proofs_used')}_secret_idx ON"
|
||||
f" {table_with_schema(db, 'proofs_used')} (secret)"
|
||||
)
|
||||
|
||||
@@ -47,6 +47,7 @@ async def rotate_keys(n_seconds=10):
|
||||
|
||||
async def start_mint_init():
|
||||
await migrate_databases(ledger.db, migrations)
|
||||
if settings.mint_cache_secrets:
|
||||
await ledger.load_used_proofs()
|
||||
await ledger.init_keysets()
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from ..core.base import (
|
||||
)
|
||||
from ..core.crypto import b_dhke
|
||||
from ..core.crypto.secp import PublicKey
|
||||
from ..core.db import Database
|
||||
from ..core.errors import (
|
||||
NoSecretInProofsError,
|
||||
NotAllowedError,
|
||||
@@ -19,16 +20,19 @@ from ..core.errors import (
|
||||
TransactionError,
|
||||
)
|
||||
from ..core.settings import settings
|
||||
from ..mint.crud import LedgerCrud
|
||||
from .conditions import LedgerSpendingConditions
|
||||
from .protocols import SupportsKeysets
|
||||
from .protocols import SupportsDb, SupportsKeysets
|
||||
|
||||
|
||||
class LedgerVerification(LedgerSpendingConditions, SupportsKeysets):
|
||||
class LedgerVerification(LedgerSpendingConditions, SupportsKeysets, SupportsDb):
|
||||
"""Verification functions for the ledger."""
|
||||
|
||||
keyset: MintKeyset
|
||||
keysets: MintKeysets
|
||||
secrets_used: Set[str]
|
||||
secrets_used: Set[str] = set()
|
||||
crud: LedgerCrud
|
||||
db: Database
|
||||
|
||||
async def verify_inputs_and_outputs(
|
||||
self, proofs: List[Proof], outputs: Optional[List[BlindedMessage]] = None
|
||||
@@ -48,7 +52,9 @@ class LedgerVerification(LedgerSpendingConditions, SupportsKeysets):
|
||||
"""
|
||||
# Verify inputs
|
||||
# Verify proofs are spendable
|
||||
self._check_proofs_spendable(proofs)
|
||||
spendable = await self._check_proofs_spendable(proofs)
|
||||
if not all(spendable):
|
||||
raise TokenAlreadySpentError()
|
||||
# Verify amounts of inputs
|
||||
if not all([self._verify_amount(p.amount) for p in proofs]):
|
||||
raise TransactionError("invalid amount.")
|
||||
@@ -87,10 +93,24 @@ class LedgerVerification(LedgerSpendingConditions, SupportsKeysets):
|
||||
if not self._verify_no_duplicate_outputs(outputs):
|
||||
raise TransactionError("duplicate outputs.")
|
||||
|
||||
def _check_proofs_spendable(self, proofs: List[Proof]):
|
||||
"""Checks whether the proofs were already spent."""
|
||||
if not all([p.secret not in self.secrets_used for p in proofs]):
|
||||
raise TokenAlreadySpentError()
|
||||
async def _check_proofs_spendable(self, proofs: List[Proof]) -> List[bool]:
|
||||
"""Checks whether the proof was already spent."""
|
||||
spendable_states = []
|
||||
if settings.mint_cache_secrets:
|
||||
# check used secrets in memory
|
||||
for p in proofs:
|
||||
spendable_state = p.secret not in self.secrets_used
|
||||
spendable_states.append(spendable_state)
|
||||
else:
|
||||
# check used secrets in database
|
||||
async with self.db.connect() as conn:
|
||||
for p in proofs:
|
||||
spendable_state = (
|
||||
await self.crud.get_proof_used(db=self.db, proof=p, conn=conn)
|
||||
is None
|
||||
)
|
||||
spendable_states.append(spendable_state)
|
||||
return spendable_states
|
||||
|
||||
def _verify_secret_criteria(self, proof: Proof) -> Literal[True]:
|
||||
"""Verifies that a secret is present and is not too long (DOS prevention)."""
|
||||
|
||||
@@ -94,6 +94,7 @@ def async_set_httpx_client(func):
|
||||
proxies=proxies_dict, # type: ignore
|
||||
headers=headers_dict,
|
||||
base_url=self.url,
|
||||
timeout=None if settings.debug else 5,
|
||||
)
|
||||
return await func(self, *args, **kwargs)
|
||||
|
||||
|
||||
173
poetry.lock
generated
173
poetry.lock
generated
@@ -1,10 +1,9 @@
|
||||
# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "anyio"
|
||||
version = "4.0.0"
|
||||
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -26,7 +25,6 @@ trio = ["trio (>=0.22)"]
|
||||
name = "asn1crypto"
|
||||
version = "1.5.1"
|
||||
description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@@ -38,7 +36,6 @@ files = [
|
||||
name = "attrs"
|
||||
version = "23.1.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -57,7 +54,6 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte
|
||||
name = "base58"
|
||||
version = "2.1.1"
|
||||
description = "Base58 and Base58Check implementation."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@@ -72,7 +68,6 @@ tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", "
|
||||
name = "bech32"
|
||||
version = "1.2.0"
|
||||
description = "Reference implementation for Bech32 and segwit addresses."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@@ -84,7 +79,6 @@ files = [
|
||||
name = "bip32"
|
||||
version = "3.4"
|
||||
description = "Minimalistic implementation of the BIP32 key derivation scheme"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@@ -100,7 +94,6 @@ coincurve = ">=15.0,<19"
|
||||
name = "bitstring"
|
||||
version = "3.1.9"
|
||||
description = "Simple construction, analysis and modification of binary data."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@@ -113,7 +106,6 @@ files = [
|
||||
name = "black"
|
||||
version = "23.9.1"
|
||||
description = "The uncompromising code formatter."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -160,7 +152,6 @@ uvloop = ["uvloop (>=0.15.2)"]
|
||||
name = "bolt11"
|
||||
version = "2.0.5"
|
||||
description = "A library for encoding and decoding BOLT11 payment requests."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8.1"
|
||||
files = [
|
||||
@@ -180,7 +171,6 @@ secp256k1 = "*"
|
||||
name = "certifi"
|
||||
version = "2023.7.22"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@@ -192,7 +182,6 @@ files = [
|
||||
name = "cffi"
|
||||
version = "1.16.0"
|
||||
description = "Foreign Function Interface for Python calling C code."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -257,7 +246,6 @@ pycparser = "*"
|
||||
name = "cfgv"
|
||||
version = "3.4.0"
|
||||
description = "Validate configuration and produce human readable error messages."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -269,7 +257,6 @@ files = [
|
||||
name = "click"
|
||||
version = "8.1.7"
|
||||
description = "Composable command line interface toolkit"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -284,7 +271,6 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
name = "coincurve"
|
||||
version = "18.0.0"
|
||||
description = "Cross-platform Python CFFI bindings for libsecp256k1"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -340,7 +326,6 @@ cffi = ">=1.3.0"
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
@@ -352,7 +337,6 @@ files = [
|
||||
name = "coverage"
|
||||
version = "7.3.2"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -420,7 +404,6 @@ toml = ["tomli"]
|
||||
name = "cryptography"
|
||||
version = "41.0.4"
|
||||
description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -466,7 +449,6 @@ test-randomorder = ["pytest-randomly"]
|
||||
name = "distlib"
|
||||
version = "0.3.7"
|
||||
description = "Distribution utilities"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@@ -478,7 +460,6 @@ files = [
|
||||
name = "ecdsa"
|
||||
version = "0.18.0"
|
||||
description = "ECDSA cryptographic signature library (pure python)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
files = [
|
||||
@@ -497,7 +478,6 @@ gmpy2 = ["gmpy2"]
|
||||
name = "environs"
|
||||
version = "9.5.0"
|
||||
description = "simplified environment variable parsing"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@@ -519,7 +499,6 @@ tests = ["dj-database-url", "dj-email-url", "django-cache-url", "pytest"]
|
||||
name = "exceptiongroup"
|
||||
version = "1.1.3"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -534,7 +513,6 @@ test = ["pytest (>=6)"]
|
||||
name = "fastapi"
|
||||
version = "0.103.0"
|
||||
description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -550,11 +528,24 @@ typing-extensions = ">=4.5.0"
|
||||
[package.extras]
|
||||
all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.5)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "fastapi-profiler"
|
||||
version = "1.2.0"
|
||||
description = "A FastAPI Middleware of pyinstrument to check your service performance."
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "fastapi_profiler-1.2.0-py3-none-any.whl", hash = "sha256:71615f815c5ff4fe193c14b1ecf6bfc250502c6adfca64a219340df5eb0a7a9b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
fastapi = "*"
|
||||
pyinstrument = ">=4.4.0"
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
version = "3.12.4"
|
||||
description = "A platform independent file lock."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -571,7 +562,6 @@ typing = ["typing-extensions (>=4.7.1)"]
|
||||
name = "h11"
|
||||
version = "0.14.0"
|
||||
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -583,7 +573,6 @@ files = [
|
||||
name = "httpcore"
|
||||
version = "0.18.0"
|
||||
description = "A minimal low-level HTTP client."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -595,17 +584,16 @@ files = [
|
||||
anyio = ">=3.0,<5.0"
|
||||
certifi = "*"
|
||||
h11 = ">=0.13,<0.15"
|
||||
sniffio = ">=1.0.0,<2.0.0"
|
||||
sniffio = "==1.*"
|
||||
|
||||
[package.extras]
|
||||
http2 = ["h2 (>=3,<5)"]
|
||||
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
||||
socks = ["socksio (==1.*)"]
|
||||
|
||||
[[package]]
|
||||
name = "httpx"
|
||||
version = "0.25.1"
|
||||
description = "The next generation HTTP client."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -619,19 +607,18 @@ certifi = "*"
|
||||
httpcore = "*"
|
||||
idna = "*"
|
||||
sniffio = "*"
|
||||
socksio = {version = ">=1.0.0,<2.0.0", optional = true, markers = "extra == \"socks\""}
|
||||
socksio = {version = "==1.*", optional = true, markers = "extra == \"socks\""}
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli", "brotlicffi"]
|
||||
cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<14)"]
|
||||
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
|
||||
http2 = ["h2 (>=3,<5)"]
|
||||
socks = ["socksio (>=1.0.0,<2.0.0)"]
|
||||
socks = ["socksio (==1.*)"]
|
||||
|
||||
[[package]]
|
||||
name = "identify"
|
||||
version = "2.5.30"
|
||||
description = "File identification library for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -646,7 +633,6 @@ license = ["ukkonen"]
|
||||
name = "idna"
|
||||
version = "3.4"
|
||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@@ -658,7 +644,6 @@ files = [
|
||||
name = "importlib-metadata"
|
||||
version = "6.8.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -678,7 +663,6 @@ testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
description = "brain-dead simple config-ini parsing"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -690,7 +674,6 @@ files = [
|
||||
name = "loguru"
|
||||
version = "0.7.2"
|
||||
description = "Python logging made (stupidly) simple"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@@ -709,7 +692,6 @@ dev = ["Sphinx (==7.2.5)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptio
|
||||
name = "marshmallow"
|
||||
version = "3.20.1"
|
||||
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -730,7 +712,6 @@ tests = ["pytest", "pytz", "simplejson"]
|
||||
name = "mnemonic"
|
||||
version = "0.20"
|
||||
description = "Implementation of Bitcoin BIP-0039"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@@ -742,7 +723,6 @@ files = [
|
||||
name = "mypy"
|
||||
version = "1.6.0"
|
||||
description = "Optional static typing for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -789,7 +769,6 @@ reports = ["lxml"]
|
||||
name = "mypy-extensions"
|
||||
version = "1.0.0"
|
||||
description = "Type system extensions for programs checked with the mypy type checker."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@@ -801,7 +780,6 @@ files = [
|
||||
name = "nodeenv"
|
||||
version = "1.8.0"
|
||||
description = "Node.js virtual environment builder"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
|
||||
files = [
|
||||
@@ -816,7 +794,6 @@ setuptools = "*"
|
||||
name = "outcome"
|
||||
version = "1.2.0"
|
||||
description = "Capture the outcome of Python function calls."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -831,7 +808,6 @@ attrs = ">=19.2.0"
|
||||
name = "packaging"
|
||||
version = "23.2"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -843,7 +819,6 @@ files = [
|
||||
name = "pathspec"
|
||||
version = "0.11.2"
|
||||
description = "Utility library for gitignore style pattern matching of file paths."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -855,7 +830,6 @@ files = [
|
||||
name = "platformdirs"
|
||||
version = "3.11.0"
|
||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -871,7 +845,6 @@ test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-co
|
||||
name = "pluggy"
|
||||
version = "1.3.0"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -887,7 +860,6 @@ testing = ["pytest", "pytest-benchmark"]
|
||||
name = "pre-commit"
|
||||
version = "3.5.0"
|
||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -906,7 +878,6 @@ virtualenv = ">=20.10.0"
|
||||
name = "psycopg2-binary"
|
||||
version = "2.9.9"
|
||||
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
||||
category = "main"
|
||||
optional = true
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -985,7 +956,6 @@ files = [
|
||||
name = "pycparser"
|
||||
version = "2.21"
|
||||
description = "C parser in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
@@ -997,7 +967,6 @@ files = [
|
||||
name = "pycryptodomex"
|
||||
version = "3.19.0"
|
||||
description = "Cryptographic library for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
@@ -1039,7 +1008,6 @@ files = [
|
||||
name = "pydantic"
|
||||
version = "1.10.13"
|
||||
description = "Data validation and settings management using python type hints"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1088,11 +1056,86 @@ typing-extensions = ">=4.2.0"
|
||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||
email = ["email-validator (>=1.0.3)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyinstrument"
|
||||
version = "4.6.1"
|
||||
description = "Call stack profiler for Python. Shows you why your code is slow!"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:73476e4bc6e467ac1b2c3c0dd1f0b71c9061d4de14626676adfdfbb14aa342b4"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4d1da8efd974cf9df52ee03edaee2d3875105ddd00de35aa542760f7c612bdf7"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:507be1ee2f2b0c9fba74d622a272640dd6d1b0c9ec3388b2cdeb97ad1e77125f"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cee6de08eb45754ef4f602ce52b640d1c535d934a6a8733a974daa095def37"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7873e8cec92321251fdf894a72b3c78f4c5c20afdd1fef0baf9042ec843bb04"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:a242f6cac40bc83e1f3002b6b53681846dfba007f366971db0bf21e02dbb1903"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:97c9660cdb4bd2a43cf4f3ab52cffd22f3ac9a748d913b750178fb34e5e39e64"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e304cd0723e2b18ada5e63c187abf6d777949454c734f5974d64a0865859f0f4"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-win32.whl", hash = "sha256:cee21a2d78187dd8a80f72f5d0f1ddb767b2d9800f8bb4d94b6d11f217c22cdb"},
|
||||
{file = "pyinstrument-4.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:2000712f71d693fed2f8a1c1638d37b7919124f367b37976d07128d49f1445eb"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a366c6f3dfb11f1739bdc1dee75a01c1563ad0bf4047071e5e77598087df457f"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c6be327be65d934796558aa9cb0f75ce62ebd207d49ad1854610c97b0579ad47"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e160d9c5d20d3e4ef82269e4e8b246ff09bdf37af5fb8cb8ccca97936d95ad6"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ffbf56605ef21c2fcb60de2fa74ff81f417d8be0c5002a407e414d6ef6dee43"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c92cc4924596d6e8f30a16182bbe90893b1572d847ae12652f72b34a9a17c24a"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f4b48a94d938cae981f6948d9ec603bab2087b178d2095d042d5a48aabaecaab"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7a386392275bdef4a1849712dc5b74f0023483fca14ef93d0ca27d453548982"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:871b131b83e9b1122f2325061c68ed1e861eebcb568c934d2fb193652f077f77"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-win32.whl", hash = "sha256:8d8515156dd91f5652d13b5fcc87e634f8fe1c07b68d1d0840348cdd50bf5ace"},
|
||||
{file = "pyinstrument-4.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:fb868fbe089036e9f32525a249f4c78b8dc46967612393f204b8234f439c9cc4"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a18cd234cce4f230f1733807f17a134e64a1f1acabf74a14d27f583cf2b183df"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:574cfca69150be4ce4461fb224712fbc0722a49b0dc02fa204d02807adf6b5a0"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e02cf505e932eb8ccf561b7527550a67ec14fcae1fe0e25319b09c9c166e914"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:832fb2acef9d53701c1ab546564c45fb70a8770c816374f8dd11420d399103c9"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13cb57e9607545623ebe462345b3d0c4caee0125d2d02267043ece8aca8f4ea0"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9be89e7419bcfe8dd6abb0d959d6d9c439c613a4a873514c43d16b48dae697c9"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:476785cfbc44e8e1b1ad447398aa3deae81a8df4d37eb2d8bbb0c404eff979cd"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e9cebd90128a3d2fee36d3ccb665c1b9dce75261061b2046203e45c4a8012d54"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-win32.whl", hash = "sha256:1d0b76683df2ad5c40eff73607dc5c13828c92fbca36aff1ddf869a3c5a55fa6"},
|
||||
{file = "pyinstrument-4.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:c4b7af1d9d6a523cfbfedebcb69202242d5bd0cb89c4e094cc73d5d6e38279bd"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:79ae152f8c6a680a188fb3be5e0f360ac05db5bbf410169a6c40851dfaebcce9"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07cad2745964c174c65aa75f1bf68a4394d1b4d28f33894837cfd315d1e836f0"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb81f66f7f94045d723069cf317453d42375de9ff3c69089cf6466b078ac1db4"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab30ae75969da99e9a529e21ff497c18fdf958e822753db4ae7ed1e67094040"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f36cb5b644762fb3c86289324bbef17e95f91cd710603ac19444a47f638e8e96"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8b45075d9dbbc977dbc7007fb22bb0054c6990fbe91bf48dd80c0b96c6307ba7"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:475ac31477f6302e092463896d6a2055f3e6abcd293bad16ff94fc9185308a88"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-win32.whl", hash = "sha256:29172ab3d8609fdf821c3f2562dc61e14f1a8ff5306607c32ca743582d3a760e"},
|
||||
{file = "pyinstrument-4.6.1-cp37-cp37m-win_amd64.whl", hash = "sha256:bd176f297c99035127b264369d2bb97a65255f65f8d4e843836baf55ebb3cee4"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:23e9b4526978432e9999021da9a545992cf2ac3df5ee82db7beb6908fc4c978c"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2dbcaccc9f456ef95557ec501caeb292119c24446d768cb4fb43578b0f3d572c"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2097f63c66c2bc9678c826b9ff0c25acde3ed455590d9dcac21220673fe74fbf"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:205ac2e76bd65d61b9611a9ce03d5f6393e34ec5b41dd38808f25d54e6b3e067"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f414ddf1161976a40fc0a333000e6a4ad612719eac0b8c9bb73f47153187148"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:65e62ebfa2cd8fb57eda90006f4505ac4c70da00fc2f05b6d8337d776ea76d41"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d96309df4df10be7b4885797c5f69bb3a89414680ebaec0722d8156fde5268c3"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f3d1ad3bc8ebb4db925afa706aa865c4bfb40d52509f143491ac0df2440ee5d2"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-win32.whl", hash = "sha256:dc37cb988c8854eb42bda2e438aaf553536566657d157c4473cc8aad5692a779"},
|
||||
{file = "pyinstrument-4.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:2cd4ce750c34a0318fc2d6c727cc255e9658d12a5cf3f2d0473f1c27157bdaeb"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ca95b21f022e995e062b371d1f42d901452bcbedd2c02f036de677119503355"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ac1e1d7e1f1b64054c4eb04eb4869a7a5eef2261440e73943cc1b1bc3c828c18"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0711845e953fce6ab781221aacffa2a66dbc3289f8343e5babd7b2ea34da6c90"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5b7d28582017de35cb64eb4e4fa603e753095108ca03745f5d17295970ee631f"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7be57db08bd366a37db3aa3a6187941ee21196e8b14975db337ddc7d1490649d"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9a0ac0f56860398d2628ce389826ce83fb3a557d0c9a2351e8a2eac6eb869983"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a9045186ff13bc826fef16be53736a85029aae3c6adfe52e666cad00d7ca623b"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6c4c56b6eab9004e92ad8a48bb54913fdd71fc8a748ae42a27b9e26041646f8b"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-win32.whl", hash = "sha256:37e989c44b51839d0c97466fa2b623638b9470d56d79e329f359f0e8fa6d83db"},
|
||||
{file = "pyinstrument-4.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:5494c5a84fee4309d7d973366ca6b8b9f8ba1d6b254e93b7c506264ef74f2cef"},
|
||||
{file = "pyinstrument-4.6.1.tar.gz", hash = "sha256:f4731b27121350f5a983d358d2272fe3df2f538aed058f57217eef7801a89288"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
bin = ["click", "nox"]
|
||||
docs = ["furo (==2021.6.18b36)", "myst-parser (==0.15.1)", "sphinx (==4.2.0)", "sphinxcontrib-programoutput (==0.17)"]
|
||||
examples = ["django", "numpy"]
|
||||
test = ["flaky", "greenlet (>=3.0.0a1)", "ipython", "pytest", "pytest-asyncio (==0.12.0)", "sphinx-autobuild (==2021.3.14)", "trio"]
|
||||
types = ["typing-extensions"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.4.2"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1115,7 +1158,6 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no
|
||||
name = "pytest-asyncio"
|
||||
version = "0.21.1"
|
||||
description = "Pytest support for asyncio"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1134,7 +1176,6 @@ testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy
|
||||
name = "pytest-cov"
|
||||
version = "4.1.0"
|
||||
description = "Pytest plugin for measuring coverage."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1153,7 +1194,6 @@ testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtuale
|
||||
name = "python-dotenv"
|
||||
version = "1.0.0"
|
||||
description = "Read key-value pairs from a .env file and set them as environment variables"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -1168,7 +1208,6 @@ cli = ["click (>=5.0)"]
|
||||
name = "pyyaml"
|
||||
version = "6.0.1"
|
||||
description = "YAML parser and emitter for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@@ -1218,7 +1257,6 @@ files = [
|
||||
name = "represent"
|
||||
version = "1.6.0.post0"
|
||||
description = "Create __repr__ automatically or declaratively."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
@@ -1236,7 +1274,6 @@ test = ["ipython", "mock", "pytest (>=3.0.5)"]
|
||||
name = "ruff"
|
||||
version = "0.0.284"
|
||||
description = "An extremely fast Python linter, written in Rust."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1263,7 +1300,6 @@ files = [
|
||||
name = "secp256k1"
|
||||
version = "0.14.0"
|
||||
description = "FFI bindings to libsecp256k1"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
@@ -1299,7 +1335,6 @@ cffi = ">=1.3.0"
|
||||
name = "setuptools"
|
||||
version = "68.2.2"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -1316,7 +1351,6 @@ testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jar
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
description = "Python 2 and 3 compatibility utilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
files = [
|
||||
@@ -1328,7 +1362,6 @@ files = [
|
||||
name = "sniffio"
|
||||
version = "1.3.0"
|
||||
description = "Sniff out which async library your code is running under"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1340,7 +1373,6 @@ files = [
|
||||
name = "socksio"
|
||||
version = "1.0.0"
|
||||
description = "Sans-I/O implementation of SOCKS4, SOCKS4A, and SOCKS5."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@@ -1352,7 +1384,6 @@ files = [
|
||||
name = "sqlalchemy"
|
||||
version = "1.3.24"
|
||||
description = "Database Abstraction Library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
files = [
|
||||
@@ -1408,7 +1439,6 @@ pymysql = ["pymysql", "pymysql (<1)"]
|
||||
name = "sqlalchemy-aio"
|
||||
version = "0.17.0"
|
||||
description = "Async support for SQLAlchemy."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@@ -1430,7 +1460,6 @@ trio = ["trio (>=0.15)"]
|
||||
name = "starlette"
|
||||
version = "0.27.0"
|
||||
description = "The little ASGI library that shines."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1449,7 +1478,6 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart", "pyyam
|
||||
name = "tomli"
|
||||
version = "2.0.1"
|
||||
description = "A lil' TOML parser"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1461,7 +1489,6 @@ files = [
|
||||
name = "typing-extensions"
|
||||
version = "4.8.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -1473,7 +1500,6 @@ files = [
|
||||
name = "uvicorn"
|
||||
version = "0.23.2"
|
||||
description = "The lightning-fast ASGI server."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -1493,7 +1519,6 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
|
||||
name = "virtualenv"
|
||||
version = "20.24.5"
|
||||
description = "Virtual Python Environment builder"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1514,7 +1539,6 @@ test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess
|
||||
name = "websocket-client"
|
||||
version = "1.6.4"
|
||||
description = "WebSocket client for Python with low level API options"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -1531,7 +1555,6 @@ test = ["websockets"]
|
||||
name = "wheel"
|
||||
version = "0.41.2"
|
||||
description = "A built-package format for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@@ -1546,7 +1569,6 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"]
|
||||
name = "win32-setctime"
|
||||
version = "1.1.0"
|
||||
description = "A small Python utility to set file creation time on Windows"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
files = [
|
||||
@@ -1561,7 +1583,6 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
|
||||
name = "zipp"
|
||||
version = "3.17.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@@ -1579,4 +1600,4 @@ pgsql = ["psycopg2-binary"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8.1"
|
||||
content-hash = "fd3495f7158b86ad25037517a1dfe033cfd367d75857b4db5c9db10f233bb842"
|
||||
content-hash = "b2c312fd906aa18a26712039f700322c2c20889a95e1cd9af787df54d700b2ca"
|
||||
|
||||
@@ -43,6 +43,7 @@ pytest-cov = "^4.0.0"
|
||||
pytest = "^7.4.0"
|
||||
ruff = "^0.0.284"
|
||||
pre-commit = "^3.3.3"
|
||||
fastapi-profiler = "^1.2.0"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
|
||||
@@ -20,6 +20,7 @@ from cashu.mint.ledger import Ledger
|
||||
SERVER_PORT = 3337
|
||||
SERVER_ENDPOINT = f"http://localhost:{SERVER_PORT}"
|
||||
|
||||
settings.debug = True
|
||||
settings.cashu_dir = "./test_data/"
|
||||
settings.mint_host = "localhost"
|
||||
settings.mint_port = SERVER_PORT
|
||||
@@ -55,6 +56,7 @@ class UvicornServer(multiprocessing.Process):
|
||||
async def ledger():
|
||||
async def start_mint_init(ledger: Ledger):
|
||||
await migrate_databases(ledger.db, migrations_mint)
|
||||
if settings.mint_cache_secrets:
|
||||
await ledger.load_used_proofs()
|
||||
await ledger.init_keysets()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user