Skip to content

Commit

Permalink
Update mint 337456333eaaea41e3d03633188ed4379d723954 (#31)
Browse files Browse the repository at this point in the history
* add missing file

* update to 337456333eaaea41e3d03633188ed4379d723954

* black on everything

* unblack
  • Loading branch information
callebtc authored Jul 20, 2023
1 parent debd633 commit f8595eb
Show file tree
Hide file tree
Showing 7 changed files with 331 additions and 115 deletions.
10 changes: 5 additions & 5 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Cashu",
"short_description": "Ecash mint and wallet",
"tile": "/cashu/static/image/cashu.png",
"contributors": ["calle", "vlad", "arcbtc"],
"hidden": false
"name": "Cashu",
"short_description": "Ecash mint and wallet",
"tile": "/cashu/static/image/cashu.png",
"contributors": ["calle", "vlad", "arcbtc"],
"hidden": false
}
114 changes: 100 additions & 14 deletions lib/cashu/core/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import base64
import json
import time
from sqlite3 import Row
from typing import Any, Dict, List, Optional, Union

Expand All @@ -19,47 +20,127 @@ class SecretKind:
P2PK = "P2PK"


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


class Tags(BaseModel):
__root__: List[List[str]]
"""
Tags are used to encode additional information in the Secret of a Proof.
"""

__root__: List[List[str]] = []

def __init__(self, tags: Optional[List[List[str]]] = None, **kwargs):
super().__init__(**kwargs)
self.__root__ = tags or []

def __setitem__(self, key: str, value: str) -> None:
self.__root__.append([key, value])

def __getitem__(self, key: str) -> Union[str, None]:
return self.get_tag(key)

def get_tag(self, tag_name: str) -> Union[str, None]:
for tag in self.__root__:
if tag[0] == tag_name:
return tag[1]
return None

def get_tag_all(self, tag_name: str) -> List[str]:
all_tags = []
for tag in self.__root__:
if tag[0] == tag_name:
all_tags.append(tag[1])
return all_tags


class Secret(BaseModel):
"""Describes spending condition encoded in the secret field of a Proof."""

kind: str
data: str
nonce: Union[None, str] = None
timelock: Union[None, int] = None
tags: Union[None, Tags] = None

def serialize(self) -> str:
data_dict: Dict[str, Any] = {
"data": self.data,
"nonce": self.nonce or PrivateKey().serialize()[:32],
}
if self.timelock:
data_dict["timelock"] = self.timelock
if self.tags:
if self.tags and self.tags.__root__:
logger.debug(f"Serializing tags: {self.tags.__root__}")
data_dict["tags"] = self.tags.__root__
logger.debug(
json.dumps(
[self.kind, data_dict],
)
)
return json.dumps(
[self.kind, data_dict],
)

@classmethod
def deserialize(cls, data: str):
kind, kwargs = json.loads(data)
return cls(kind=kind, **kwargs)
def deserialize(cls, from_proof: str):
kind, kwargs = json.loads(from_proof)
data = kwargs.pop("data")
nonce = kwargs.pop("nonce")
tags_list = kwargs.pop("tags", None)
if tags_list:
tags = Tags(tags=tags_list)
else:
tags = None
logger.debug(f"Deserialized Secret: {kind}, {data}, {nonce}, {tags}")
return cls(kind=kind, data=data, nonce=nonce, tags=tags)

@property
def locktime(self) -> Union[None, int]:
if self.tags:
locktime = self.tags.get_tag("locktime")
if locktime:
return int(locktime)
return None

@property
def sigflag(self) -> Union[None, str]:
if self.tags:
sigflag = self.tags.get_tag("sigflag")
if sigflag:
return sigflag
return None

@property
def n_sigs(self) -> Union[None, int]:
if self.tags:
n_sigs = self.tags.get_tag("n_sigs")
if n_sigs:
return int(n_sigs)
return None

def get_p2pk_pubkey_from_secret(self) -> List[str]:
"""Gets the P2PK pubkey from a Secret depending on the locktime
Args:
secret (Secret): P2PK Secret in ecash token
Returns:
str: pubkey to use for P2PK, empty string if anyone can spend (locktime passed)
"""
pubkeys: List[str] = [self.data] # for now we only support one pubkey
# get all additional pubkeys from tags for multisig
if self.tags and self.tags.get_tag("pubkey"):
pubkeys += self.tags.get_tag_all("pubkey")

now = time.time()
if self.locktime and self.locktime < now:
logger.trace(f"p2pk locktime ran out ({self.locktime}<{now}).")
# check tags if a refund pubkey is present.
# If yes, we demand the signature to be from the refund pubkey
if self.tags:
refund_pubkey = self.tags.get_tag("refund")
if refund_pubkey:
pubkeys = [refund_pubkey]
return pubkeys
return []
return pubkeys


class P2SHScript(BaseModel):
Expand All @@ -83,7 +164,7 @@ class Proof(BaseModel):
amount: int = 0
secret: str = "" # secret or message to be blinded and signed
C: str = "" # signature on secret, unblinded by wallet
p2pksig: Optional[str] = None # P2PK signature
p2pksigs: Union[List[str], None] = [] # P2PK signature
p2shscript: Union[P2SHScript, None] = None # P2SH spending condition
reserved: Union[
None, bool
Expand Down Expand Up @@ -121,6 +202,7 @@ class BlindedMessage(BaseModel):

amount: int
B_: str # Hex-encoded blinded message
p2pksigs: Union[List[str], None] = None # signature for p2pk with SIG_ALL


class BlindedSignature(BaseModel):
Expand Down Expand Up @@ -253,6 +335,10 @@ 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
# with pending tokens (kept for backwards compatibility of new wallets with old mints)


class CheckFeesRequest(BaseModel):
Expand Down
4 changes: 2 additions & 2 deletions lib/cashu/core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

env = Env()

VERSION = "0.12.2"
VERSION = "0.12.3"


def find_env_file():
Expand Down Expand Up @@ -98,7 +98,7 @@ class WalletSettings(CashuSettings):
]
)

timelock_delta_seconds: int = Field(default=86400) # 1 day
locktime_delta_seconds: int = Field(default=86400) # 1 day


class Settings(
Expand Down
Loading

0 comments on commit f8595eb

Please sign in to comment.