Skip to content

Commit

Permalink
tests on register_dlc working
Browse files Browse the repository at this point in the history
  • Loading branch information
lollerfirst committed Jul 31, 2024
1 parent a01a77f commit 8dc0c71
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 7 deletions.
15 changes: 13 additions & 2 deletions cashu/mint/dlc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,23 @@
from ..core.errors import TransactionError
from .features import LedgerFeatures

from json.decoder import JSONDecodeError

from typing import List, Tuple, Dict
class LedgerDLC(LedgerFeatures):

async def filter_sct_proofs(self, proofs: List[Proof]) -> Tuple[List[Proof], List[Proof]]:
sct_proofs = list(filter(lambda p: Secret.deserialize(p.secret).kind == SecretKind.SCT.value, proofs))
non_sct_proofs = list(filter(lambda p: p not in sct_proofs, proofs))
deserializable = []
non_sct_proofs = []
for p in proofs:
try:
Secret.deserialize(p.secret)
deserializable.append(p)
except JSONDecodeError:
non_sct_proofs.append(p)

sct_proofs = list(filter(lambda p: Secret.deserialize(p.secret).kind == SecretKind.SCT.value, deserializable))
non_sct_proofs += list(filter(lambda p: p not in sct_proofs, deserializable))
return (sct_proofs, non_sct_proofs)

async def get_dlc_fees(self, fa_unit: str) -> Dict[str, int]:
Expand Down
5 changes: 3 additions & 2 deletions cashu/mint/verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,8 +347,9 @@ async def _verify_dlc_amount_threshold(self, funding_amount: int, proofs: List[P
the funding_amount
"""
sct_proofs, _ = await self.filter_sct_proofs(proofs)
sct_secrets = [Secret.deserialize(p.secret) for p in sct_proofs]
if not all([int(s.tags.get_tag('threshold')) <= funding_amount for s in sct_secrets]):
dlc_witnesses = [DLCWitness.from_witness(p.witness or "") for p in sct_proofs]
dlc_secrets = [Secret.deserialize(w.leaf_secret) for w in dlc_witnesses]
if not all([int(s.tags.get_tag('threshold')) <= funding_amount for s in dlc_secrets]):
raise TransactionError("Some inputs' funding thresholds were not met")

async def _verify_dlc_inputs(
Expand Down
96 changes: 93 additions & 3 deletions tests/test_dlc.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from cashu.wallet.wallet import Wallet
from cashu.core.secret import Secret, SecretKind
from cashu.core.errors import CashuError
from cashu.core.base import DLCWitness, Proof, TokenV4
from cashu.core.base import DLCWitness, Proof, TokenV4, Unit, DiscreteLogContract
from cashu.core.models import PostDlcRegistrationRequest, PostDlcRegistrationResponse
from cashu.mint.ledger import Ledger
from cashu.wallet.helpers import send
from tests.conftest import SERVER_ENDPOINT
from hashlib import sha256
Expand All @@ -17,7 +19,15 @@
from loguru import logger

from typing import Union, List
from cashu.core.crypto.dlc import merkle_root, merkle_verify, sorted_merkle_hash, list_hash
from secp256k1 import PrivateKey
from cashu.core.crypto.dlc import (
merkle_root,
merkle_verify,
sorted_merkle_hash,
list_hash,
sign_dlc,
verify_dlc_signature,
)

@pytest_asyncio.fixture(scope="function")
async def wallet():
Expand Down Expand Up @@ -79,6 +89,20 @@ async def test_merkle_verify():
root, branch_hashes = merkle_root(leafs, index)
assert merkle_verify(root, leafs[index], branch_hashes), "merkle_verify test fail"

@pytest.mark.asyncio
async def test_dlc_signatures():
dlc_root = sha256("TESTING".encode()).hexdigest()
funding_amount = 1000
privkey = PrivateKey()

# sign
signature = sign_dlc(dlc_root, funding_amount, privkey)
# verify
assert(
verify_dlc_signature(dlc_root, funding_amount, signature, privkey.pubkey),
"Could not verify funding proof signature"
)

@pytest.mark.asyncio
async def test_swap_for_dlc_locked(wallet: Wallet):
invoice = await wallet.request_mint(64)
Expand Down Expand Up @@ -245,4 +269,70 @@ async def test_send_funding_token(wallet: Wallet):
proofs = deserialized_token.proofs
assert all([Secret.deserialize(p.secret).kind == SecretKind.SCT.value for p in proofs])
witnesses = [DLCWitness.from_witness(p.witness) for p in proofs]
assert all([Secret.deserialize(w.leaf_secret).kind == SecretKind.DLC.value for w in witnesses])
assert all([Secret.deserialize(w.leaf_secret).kind == SecretKind.DLC.value for w in witnesses])

@pytest.mark.asyncio
async def test_registration_vanilla_proofs(wallet: Wallet, ledger: Ledger):
invoice = await wallet.request_mint(64)
await pay_if_regtest(invoice.bolt11)
minted = await wallet.mint(64, id=invoice.id)

# Get public key the mint uses to sign
keysets = await wallet._get_keys()
active_keyset_for_unit = next(filter(lambda k: k.active and k.unit == Unit["sat"], keysets))
pubkey = next(iter(active_keyset_for_unit.public_keys.values()))

dlc_root = sha256("TESTING".encode()).hexdigest()
dlc = DiscreteLogContract(
funding_amount=64,
unit="sat",
dlc_root=dlc_root,
inputs=minted,
)

request = PostDlcRegistrationRequest(registrations=[dlc])
response = await ledger.register_dlc(request)
assert len(response.funded) == 1, "Funding proofs len != 1"

funding_proof = response.funded[0]
assert (
verify_dlc_signature(dlc_root, 64, bytes.fromhex(funding_proof.signature), pubkey),
"Could not verify funding proof"
)

@pytest.mark.asyncio
async def test_registration_dlc_locked_proofs(wallet: Wallet, ledger: Ledger):
invoice = await wallet.request_mint(64)
await pay_if_regtest(invoice.bolt11)
minted = await wallet.mint(64, id=invoice.id)

# Get locked proofs
dlc_root = sha256("TESTING".encode()).hexdigest()
_, locked = await wallet.split(minted, 64, dlc_data=(dlc_root, 32))
assert len(_) == 0

# Add witnesses to proofs
locked = await wallet.add_sct_witnesses_to_proofs(locked)

# Get public key the mint uses to sign
keysets = await wallet._get_keys()
active_keyset_for_unit = next(filter(lambda k: k.active and k.unit == Unit["sat"], keysets))
pubkey = next(iter(active_keyset_for_unit.public_keys.values()))

dlc = DiscreteLogContract(
funding_amount=64,
unit="sat",
dlc_root=dlc_root,
inputs=locked,
)

request = PostDlcRegistrationRequest(registrations=[dlc])
response = await ledger.register_dlc(request)
assert response.errors is None, f"Funding proofs error: {response.errors[0].bad_inputs}"
assert len(response.funded) == 1, "Funding proofs len != 1"

funding_proof = response.funded[0]
assert (
verify_dlc_signature(dlc_root, 64, bytes.fromhex(funding_proof.signature), pubkey),
"Could not verify funding proof"
)

0 comments on commit 8dc0c71

Please sign in to comment.