Fix/cashu update protocol (#1433)

* updates NOTE: fix pyproject and requirements

* revert GET to POST

* update cashu on pip and change name of models

* adjust client to spendable

* refactor spendable
This commit is contained in:
calle 2023-01-30 09:29:44 +01:00 committed by GitHub
parent bdfbbb779e
commit 80a94aa9ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 36 additions and 42 deletions

2
.gitignore vendored
View File

@ -40,6 +40,4 @@ docker
# Nix
*result*
# Ignore extensions (post installable extension PR)
extensions/
upgrades/

View File

@ -1,17 +1,11 @@
async function hashToCurve(secretMessage) {
console.log(
'### secretMessage',
nobleSecp256k1.utils.bytesToHex(secretMessage)
)
let point
while (!point) {
const hash = await nobleSecp256k1.utils.sha256(secretMessage)
const hashHex = nobleSecp256k1.utils.bytesToHex(hash)
const pointX = '02' + hashHex
console.log('### pointX', pointX)
try {
point = nobleSecp256k1.Point.fromHex(pointX)
console.log('### point', point.toHex())
} catch (error) {
secretMessage = await nobleSecp256k1.utils.sha256(secretMessage)
}
@ -20,19 +14,17 @@ async function hashToCurve(secretMessage) {
}
async function step1Alice(secretMessage) {
// todo: document & validate `secretMessage` format
secretMessage = uint8ToBase64.encode(secretMessage)
secretMessage = new TextEncoder().encode(secretMessage)
const Y = await hashToCurve(secretMessage)
const rpk = nobleSecp256k1.utils.randomPrivateKey()
const r = bytesToNumber(rpk)
const r_bytes = nobleSecp256k1.utils.randomPrivateKey()
const r = bytesToNumber(r_bytes)
const P = nobleSecp256k1.Point.fromPrivateKey(r)
const B_ = Y.add(P)
return {B_: B_.toHex(true), r: nobleSecp256k1.utils.bytesToHex(rpk)}
return {B_: B_.toHex(true), r: nobleSecp256k1.utils.bytesToHex(r_bytes)}
}
function step3Alice(C_, r, A) {
// const rInt = BigInt(r)
const rInt = bytesToNumber(r)
const C = C_.subtract(A.multiply(rInt))
return C

View File

@ -1690,8 +1690,6 @@ page_container %}
outputs
}
console.log('payload', JSON.stringify(payload))
const {data} = await LNbits.api.request(
'POST',
`/cashu/api/v1/${this.mintId}/split`,
@ -1885,7 +1883,7 @@ page_container %}
const payload = {
proofs: scndProofs.flat(),
amount,
invoice: this.payInvoiceData.data.request
pr: this.payInvoiceData.data.request
}
console.log('#### payload', JSON.stringify(payload))
try {
@ -1959,8 +1957,13 @@ page_container %}
checks with the mint whether an array of proofs is still
spendable or already invalidated
*/
if (proofs.length == 0) {
return
}
const payload = {
proofs: proofs.flat()
proofs: proofs.map(p => {
return {secret: p.secret}
})
}
console.log('#### payload', JSON.stringify(payload))
try {
@ -1972,7 +1975,7 @@ page_container %}
)
// delete proofs from database if it is spent
let spentProofs = proofs.filter((p, pidx) => !data[pidx])
let spentProofs = proofs.filter((p, pidx) => !data.spendable[pidx])
if (spentProofs.length) {
this.deleteProofs(spentProofs)
@ -1990,7 +1993,7 @@ page_container %}
}
}
return data
return data.spendable
} catch (error) {
console.error(error)
LNbits.utils.notifyApiError(error)
@ -2033,6 +2036,9 @@ page_container %}
JSON.stringify(data)
)
},
////////////// UI HELPERS //////////////
setInvoicePaid: async function (payment_hash) {
const invoice = this.invoicesCashu.find(i => i.hash === payment_hash)
invoice.status = 'paid'
@ -2077,15 +2083,11 @@ page_container %}
*/
const tokenJson = atob(token)
const proofs = JSON.parse(tokenJson)
let data = await this.checkProofsSpendable(proofs)
// iterate through response of form {0: true, 1: false, ...}
const spendable = await this.checkProofsSpendable(proofs)
let paid = false
for (const [key, spendable] of Object.entries(data)) {
if (!spendable) {
this.setTokenPaid(token)
paid = true
}
if (spendable.includes(true)) {
this.setTokenPaid(token)
paid = true
}
if (paid) {
console.log('### token paid')
@ -2126,6 +2128,7 @@ page_container %}
},
findTokenForAmount: function (amount) {
// unused coin selection
for (const token of this.proofs) {
const index = token.promises?.findIndex(p => p.amount === amount)
if (index >= 0) {

View File

@ -4,18 +4,18 @@ from typing import Dict, List, Union
# -------- cashu imports
from cashu.core.base import (
BlindedSignature,
CheckFeesRequest,
CheckFeesResponse,
CheckRequest,
CheckSpendableRequest,
CheckSpendableResponse,
GetMeltResponse,
GetMintResponse,
Invoice,
MeltRequest,
PostMeltRequest,
PostMintRequest,
PostMintResponse,
PostSplitRequest,
PostSplitResponse,
SplitRequest,
)
from fastapi import Depends, Query
from loguru import logger
@ -279,7 +279,7 @@ async def mint(
@cashu_ext.post("/api/v1/{cashu_id}/melt")
async def melt_coins(
payload: MeltRequest, cashu_id: str = Query(None)
payload: PostMeltRequest, cashu_id: str = Query(None)
) -> GetMeltResponse:
"""Invalidates proofs and pays a Lightning invoice."""
cashu: Union[None, Cashu] = await get_cashu(cashu_id)
@ -288,7 +288,7 @@ async def melt_coins(
status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist."
)
proofs = payload.proofs
invoice = payload.invoice
invoice = payload.pr
# !!!!!!! MAKE SURE THAT PROOFS ARE ONLY FROM THIS CASHU KEYSET ID
# THIS IS NECESSARY BECAUSE THE CASHU BACKEND WILL ACCEPT ANY VALID
@ -358,7 +358,7 @@ async def melt_coins(
@cashu_ext.post("/api/v1/{cashu_id}/check")
async def check_spendable(
payload: CheckRequest, cashu_id: str = Query(None)
payload: CheckSpendableRequest, cashu_id: str = Query(None)
) -> Dict[int, bool]:
"""Check whether a secret has been spent already or not."""
cashu: Union[None, Cashu] = await get_cashu(cashu_id)
@ -366,7 +366,8 @@ async def check_spendable(
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Mint does not exist."
)
return await ledger.check_spendable(payload.proofs)
spendableList = await ledger.check_spendable(payload.proofs)
return CheckSpendableResponse(spendable=spendableList)
@cashu_ext.post("/api/v1/{cashu_id}/checkfees")
@ -395,7 +396,7 @@ async def check_fees(
@cashu_ext.post("/api/v1/{cashu_id}/split")
async def split(
payload: SplitRequest, cashu_id: str = Query(None)
payload: PostSplitRequest, cashu_id: str = Query(None)
) -> PostSplitResponse:
"""
Requetst a set of tokens with amount "total" to be split into two

8
poetry.lock generated
View File

@ -195,14 +195,14 @@ websockets = ">=10"
[[package]]
name = "cashu"
version = "0.8.2"
version = "0.9.0"
description = "Ecash wallet and mint for Bitcoin Lightning"
category = "main"
optional = false
python-versions = ">=3.7"
files = [
{file = "cashu-0.8.2-py3-none-any.whl", hash = "sha256:53893911763c424255bc7112aaba356e0a265e850d770338c70b2d282f67bf99"},
{file = "cashu-0.8.2.tar.gz", hash = "sha256:4cdd34a50d14960d2dcc6f5b6120f462688090dd084387860f7a59d16aa102ff"},
{file = "cashu-0.9.0-py3-none-any.whl", hash = "sha256:73dde901c8ea75d223f0cb37ea214028c17b798f9189b88968884c4a9c2e32a8"},
{file = "cashu-0.9.0.tar.gz", hash = "sha256:5d5087b3b80ecd8350ea2b098605581a746fc377c0bf9f1e3a97fa5c6d06d9f2"},
]
[package.dependencies]
@ -2112,4 +2112,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
[metadata]
lock-version = "2.0"
python-versions = "^3.10 | ^3.9 | ^3.8 | ^3.7"
content-hash = "bbbe4d958160a1e5c596c09af3c402964a7e68d9da1491e787649cee278c5eac"
content-hash = "e3ac1dcb6e10cc8fd7ee1ae88698ca6d2d412efe353578d9f2134adc512a523b"

View File

@ -62,8 +62,8 @@ protobuf = "4.21.12"
Cerberus = "1.3.4"
async-timeout = "4.0.2"
pyln-client = "0.11.1"
cashu = "0.8.2"
boltz-client = "0.1.3"
cashu = "0.9.0"
[tool.poetry.dev-dependencies]

View File

@ -8,7 +8,7 @@ base58==2.1.1 ; python_version >= "3.7" and python_version < "4.0"
bech32==1.2.0 ; python_version >= "3.7" and python_version < "4.0"
bitstring==3.1.9 ; python_version >= "3.7" and python_version < "4.0"
boltz-client==0.1.3 ; python_version >= "3.7" and python_version < "4.0"
cashu==0.8.2 ; python_version >= "3.7" and python_version < "4.0"
cashu==0.9.0 ; python_version >= "3.7" and python_version < "4.0"
cerberus==1.3.4 ; python_version >= "3.7" and python_version < "4.0"
certifi==2022.12.7 ; python_version >= "3.7" and python_version < "4.0"
cffi==1.15.1 ; python_version >= "3.7" and python_version < "4.0"