Wallet/fix_nostr_timeout (#376)

* fix nostr receive

* split with amount pre 0.13

* drop 0.13.0 amount with split compatibility
This commit is contained in:
callebtc
2023-12-03 01:56:58 +01:00
committed by GitHub
parent 74c9317277
commit 6c8b1a858f
9 changed files with 62 additions and 61 deletions

View File

@@ -119,15 +119,7 @@ MINT_URL=https://8333.space:3338
```bash
cashu info
```
Returns:
```bash
Version: 0.14.0
Debug: False
Cashu dir: /home/user/.cashu
Wallet: wallet
Mint URL: https://8333.space:3338
```
This command shows information about your wallet.
#### Check balance
```bash
@@ -159,21 +151,11 @@ You should see the encoded token. Copy the token and send it to another user suc
cashuAeyJwcm9vZnMiOiBbey...
```
You can now see that your available balance has dropped by the amount that you reserved for sending if you enter `cashu balance`:
```bash
Balance: 420 sat
```
#### Receive tokens
To receive tokens, another user enters:
```bash
cashu receive cashuAeyJwcm9vZnMiOiBbey...
```
You should see the balance increase:
```bash
Balance: 0 sat
Balance: 69 sat
```
# Starting the wallet API daemon
Nutshell wallet can be used in daemon mode that can be controlled through a REST API:

View File

@@ -532,6 +532,9 @@ class TokenV3(BaseModel):
def get_keysets(self):
return list(set([p.id for p in self.get_proofs()]))
def get_mints(self):
return list(set([t.mint for t in self.token if t.mint]))
@classmethod
def deserialize(cls, tokenv3_serialized: str) -> "TokenV3":
"""
@@ -542,6 +545,9 @@ class TokenV3(BaseModel):
f"Token prefix not valid. Expected {prefix}."
)
token_base64 = tokenv3_serialized[len(prefix) :]
# if base64 string is not a multiple of 4, pad it with "="
token_base64 += "=" * (4 - len(token_base64) % 4)
token = json.loads(base64.urlsafe_b64decode(token_base64))
return cls.parse_obj(token)

View File

@@ -8,7 +8,7 @@ from pydantic import BaseSettings, Extra, Field
env = Env()
VERSION = "0.14.0"
VERSION = "0.14.1"
def find_env_file():

View File

@@ -122,7 +122,7 @@ class NostrClient:
message = json.dumps(request)
self.relay_manager.publish_message(message)
while True:
while any([r.connected for r in self.relay_manager.relays.values()]):
while self.relay_manager.message_pool.has_events():
event_msg = self.relay_manager.message_pool.get_event()
if "?iv=" in event_msg.event.content:
@@ -143,7 +143,7 @@ class NostrClient:
time.sleep(0.1)
def subscribe(self, callback_func=None):
while True:
while any([r.connected for r in self.relay_manager.relays.values()]):
while self.relay_manager.message_pool.has_events():
event_msg = self.relay_manager.message_pool.get_event()
if callback_func:

View File

@@ -107,17 +107,14 @@ def deserialize_token_from_string(token: str) -> TokenV3:
except Exception:
pass
# ----- receive token -----
# deserialize token
# dtoken = json.loads(base64.urlsafe_b64decode(token))
if token.startswith("cashu"):
tokenObj = TokenV3.deserialize(token)
# tokenObj = TokenV2.parse_obj(dtoken)
assert len(tokenObj.token), Exception("no proofs in token")
assert len(tokenObj.token[0].proofs), Exception("no proofs in token")
return tokenObj
raise Exception("Invalid token")
async def receive(
wallet: Wallet,

View File

@@ -139,24 +139,24 @@ async def m007_nostr(db: Database):
"""
Stores timestamps of nostr operations.
"""
# async with db.connect() as conn:
# await conn.execute("""
# CREATE TABLE IF NOT EXISTS nostr (
# type TEXT NOT NULL,
# last TIMESTAMP DEFAULT NULL
# )
# """)
# await conn.execute(
# """
# INSERT INTO nostr
# (type, last)
# VALUES (?, ?)
# """,
# (
# "dm",
# None,
# ),
# )
async with db.connect() as conn:
await conn.execute("""
CREATE TABLE IF NOT EXISTS nostr (
type TEXT NOT NULL,
last TIMESTAMP DEFAULT NULL
)
""")
await conn.execute(
"""
INSERT INTO nostr
(type, last)
VALUES (?, ?)
""",
(
"dm",
None,
),
)
async def m008_keysets_add_public_keys(db: Database):

View File

@@ -1,10 +1,13 @@
import asyncio
import datetime
import threading
import click
from httpx import ConnectError
from loguru import logger
from cashu.core.base import TokenV3
from ..core.settings import settings
from ..nostr.client.client import NostrClient
from ..nostr.event import Event
@@ -97,7 +100,7 @@ async def send_nostr(
async def receive_nostr(
wallet: Wallet,
):
) -> NostrClient:
if settings.nostr_private_key is None:
print(
"Warning: No nostr private key set! You don't have NOSTR_PRIVATE_KEY set in"
@@ -113,18 +116,28 @@ async def receive_nostr(
await asyncio.sleep(2)
def get_token_callback(event: Event, decrypted_content: str):
date_str = datetime.datetime.fromtimestamp(event.created_at).strftime(
"%Y-%m-%d %H:%M:%S"
)
logger.debug(
f"From {event.public_key[:3]}..{event.public_key[-3:]}: {decrypted_content}"
f"From {event.public_key[:3]}..{event.public_key[-3:]} on {date_str}:"
f" {decrypted_content}"
)
# split the content into words
words = decrypted_content.split(" ")
for w in words:
try:
logger.trace(
f"Nostr: setting last check timestamp to {event.created_at}"
"Nostr: setting last check timestamp to"
f" {event.created_at} ({date_str})"
)
# call the receive method
tokenObj = deserialize_token_from_string(w)
tokenObj: TokenV3 = deserialize_token_from_string(w)
print(
f"Receiving {tokenObj.get_amount()} sat on mint"
f" {tokenObj.get_mints()[0]} from nostr user {event.public_key} at"
f" {date_str}"
)
asyncio.run(
receive(
wallet,
@@ -143,8 +156,11 @@ async def receive_nostr(
# determine timestamp of last check so we don't scan all historical DMs
last_check = await get_nostr_last_check_timestamp(db=wallet.db)
logger.debug(f"Last check: {last_check}")
if last_check:
date_str = datetime.datetime.fromtimestamp(last_check).strftime(
"%Y-%m-%d %H:%M:%S"
)
logger.debug(f"Last check: {date_str}")
last_check -= 60 * 60 # 1 hour tolerance
logger.debug("Starting Nostr DM thread")
@@ -154,3 +170,4 @@ async def receive_nostr(
name="Nostr DM",
)
t.start()
return client

View File

@@ -94,7 +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,
timeout=5,
)
return await func(self, *args, **kwargs)
@@ -198,9 +198,9 @@ class LedgerAPI(object):
if keyset_id and keyset_id != keyset.id:
# NOTE: Because of the upcoming change of how to calculate keyset ids
# with version 0.14.0, we overwrite the calculated keyset id with the
# with version 0.15.0, we overwrite the calculated keyset id with the
# requested one. This is a temporary fix and should be removed once all
# ecash is transitioned to 0.14.0.
# ecash is transitioned to 0.15.0.
logger.debug(
f"Keyset ID mismatch: {keyset_id} != {keyset.id}. This can happen due"
" to a version upgrade."
@@ -732,9 +732,7 @@ class Wallet(LedgerAPI, WalletP2PK, WalletHTLC, WalletSecrets):
proofs (List[Proof]): Proofs to be redeemed.
"""
# verify DLEQ of incoming proofs
logger.debug("Verifying DLEQ of incoming proofs.")
self.verify_proofs_dleq(proofs)
logger.debug("DLEQ verified.")
return await self.split(proofs, sum_proofs(proofs))
async def split(
@@ -928,7 +926,8 @@ class Wallet(LedgerAPI, WalletP2PK, WalletHTLC, WalletSecrets):
):
raise Exception("DLEQ proof invalid.")
else:
logger.debug("DLEQ proof valid.")
logger.trace("DLEQ proof valid.")
logger.debug("Verified incoming DLEQ proofs.")
async def _construct_proofs(
self,

View File

@@ -13,7 +13,7 @@ entry_points = {"console_scripts": ["cashu = cashu.wallet.cli.cli:cli"]}
setuptools.setup(
name="cashu",
version="0.14.0",
version="0.14.1",
description="Ecash wallet and mint for Bitcoin Lightning",
long_description=long_description,
long_description_content_type="text/markdown",