mirror of
https://github.com/lnbits/lnbits.git
synced 2025-06-16 11:51:25 +02:00
feat: stupid random tests
This commit is contained in:
parent
1f592604b4
commit
cf5ffe24ea
@ -1,6 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
|
|
||||||
from lnbits.db import Database
|
from lnbits.db import Database
|
||||||
from lnbits.helpers import template_renderer
|
from lnbits.helpers import template_renderer
|
||||||
@ -10,6 +11,14 @@ db = Database("ext_cashu")
|
|||||||
|
|
||||||
cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["cashu"])
|
cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["cashu"])
|
||||||
|
|
||||||
|
cashu_static_files = [
|
||||||
|
{
|
||||||
|
"path": "/cashu/static",
|
||||||
|
"app": StaticFiles(directory="lnbits/extensions/cashu/static"),
|
||||||
|
"name": "cashu_static",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def cashu_renderer():
|
def cashu_renderer():
|
||||||
return template_renderer(["lnbits/extensions/cashu/templates"])
|
return template_renderer(["lnbits/extensions/cashu/templates"])
|
||||||
|
31
lnbits/extensions/cashu/static/js/dhke.js
Normal file
31
lnbits/extensions/cashu/static/js/dhke.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
async function hashToCurve(secretMessage) {
|
||||||
|
let point
|
||||||
|
while (!point) {
|
||||||
|
const hash = await nobleSecp256k1.utils.sha256(secretMessage)
|
||||||
|
try {
|
||||||
|
point = nobleSecp256k1.Point.fromHex(hash)
|
||||||
|
} catch (error) {
|
||||||
|
// console.error(error)
|
||||||
|
// const x = bytesToNumber(hash) + ''
|
||||||
|
// const msg = await nobleSecp256k1.utils.sha256(x)
|
||||||
|
secretMessage = await nobleSecp256k1.utils.sha256(hash)
|
||||||
|
// secretMessage = nobleSecp256k1.utils.bytesToHex(msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return point
|
||||||
|
}
|
||||||
|
|
||||||
|
async function step1Bob(secretMessage) {
|
||||||
|
const Y = await hashToCurve(secretMessage)
|
||||||
|
const randomBlindingFactor = bytesToNumber(
|
||||||
|
nobleSecp256k1.utils.randomPrivateKey()
|
||||||
|
)
|
||||||
|
const P = nobleSecp256k1.Point.fromPrivateKey(randomBlindingFactor)
|
||||||
|
const B_ = Y.add(P)
|
||||||
|
return {B_, randomBlindingFactor}
|
||||||
|
}
|
||||||
|
|
||||||
|
function step3Bob(C_, r, A) {
|
||||||
|
const C = C_.subtract(A.multiply(r))
|
||||||
|
return C
|
||||||
|
}
|
1179
lnbits/extensions/cashu/static/js/noble-secp256k1.js
Normal file
1179
lnbits/extensions/cashu/static/js/noble-secp256k1.js
Normal file
File diff suppressed because it is too large
Load Diff
23
lnbits/extensions/cashu/static/js/utils.js
Normal file
23
lnbits/extensions/cashu/static/js/utils.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
function splitAmount(value) {
|
||||||
|
const chunks = []
|
||||||
|
for (let i = 0; i < 32; i++) {
|
||||||
|
const mask = 1 << i
|
||||||
|
if ((value & mask) !== 0) chunks.push(Math.pow(2, i))
|
||||||
|
}
|
||||||
|
return chunks
|
||||||
|
}
|
||||||
|
|
||||||
|
function bytesToNumber(bytes) {
|
||||||
|
return hexToNumber(nobleSecp256k1.utils.bytesToHex(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
function bigIntStringify(key, value) {
|
||||||
|
return typeof value === 'bigint' ? value.toString() : value
|
||||||
|
}
|
||||||
|
|
||||||
|
function hexToNumber(hex) {
|
||||||
|
if (typeof hex !== 'string') {
|
||||||
|
throw new TypeError('hexToNumber: expected string, got ' + typeof hex)
|
||||||
|
}
|
||||||
|
return BigInt(`0x${hex}`)
|
||||||
|
}
|
@ -81,6 +81,14 @@ page_container %}
|
|||||||
<q-icon name="settings_ethernet" color="grey">
|
<q-icon name="settings_ethernet" color="grey">
|
||||||
<q-tooltip>Pending</q-tooltip>
|
<q-tooltip>Pending</q-tooltip>
|
||||||
</q-icon>
|
</q-icon>
|
||||||
|
<q-badge
|
||||||
|
size="lg"
|
||||||
|
color="secondary"
|
||||||
|
class="q-mr-md cursor-pointer"
|
||||||
|
@click="recheckToken(props.row.hash)"
|
||||||
|
>
|
||||||
|
Recheck
|
||||||
|
</q-badge>
|
||||||
</div>
|
</div>
|
||||||
</q-td>
|
</q-td>
|
||||||
<q-td
|
<q-td
|
||||||
@ -491,6 +499,7 @@ page_container %}
|
|||||||
hash: ''
|
hash: ''
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
tokens: [],
|
||||||
|
|
||||||
receive: {
|
receive: {
|
||||||
show: false,
|
show: false,
|
||||||
@ -854,9 +863,122 @@ page_container %}
|
|||||||
'cashu.tokenBuys',
|
'cashu.tokenBuys',
|
||||||
JSON.stringify(this.tokenBuys)
|
JSON.stringify(this.tokenBuys)
|
||||||
)
|
)
|
||||||
|
const amounts = splitAmount(this.buyTokens.data.amount)
|
||||||
|
await this.requestTokens(amounts, this.buyTokens.data.hash)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
LNbits.utils.notifyApiError(error)
|
LNbits.utils.notifyApiError(error)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkXXXXXX: async function () {
|
||||||
|
for (const tokenBuy of this.tokenBuys) {
|
||||||
|
if (tokenBuy.status === 'pending') {
|
||||||
|
try {
|
||||||
|
const {data} = await LNbits.api.request(
|
||||||
|
'POST',
|
||||||
|
`/cashu/api/v1/cashu/${this.mintId}/mint?payment_hash=${tokenBuy.hash}`,
|
||||||
|
'',
|
||||||
|
{
|
||||||
|
blinded_messages: []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
console.log('### data', data)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
recheckToken: async function(hash) {
|
||||||
|
console.log('### recheckToken', hash)
|
||||||
|
const tokens = this.tokenBuys.find(bt => bt.hash = hash)
|
||||||
|
if (!tokens) {
|
||||||
|
console.error('####### no token for hash', hash)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const promises = await this.fetchPromisesFromMint(hash, tokens.blindedMessages)
|
||||||
|
if (promises && promises.length){
|
||||||
|
tokens.promises = promises
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchPromisesFromMint: async function (hash, blindedMessages) {
|
||||||
|
console.log('### fetchPromisesFromMint', hash, blindedMessages)
|
||||||
|
try {
|
||||||
|
const {data} = await LNbits.api.request(
|
||||||
|
'POST',
|
||||||
|
`/cashu/api/v1/cashu/${this.mintId}/mint?payment_hash=${hash}`,
|
||||||
|
'',
|
||||||
|
{
|
||||||
|
blinded_messages: blindedMessages
|
||||||
|
}
|
||||||
|
)
|
||||||
|
console.log('### fetchPromisesFromMint data', data)
|
||||||
|
return data
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
requestTokens: async function (amounts, paymentHash) {
|
||||||
|
const newTokens = await this.buildTokens(amounts, paymentHash)
|
||||||
|
this.tokens.push(newTokens)
|
||||||
|
localStorage.setItem(
|
||||||
|
'cashu.tokens',
|
||||||
|
JSON.stringify(this.tokens, bigIntStringify)
|
||||||
|
)
|
||||||
|
console.log('### this.tokens', this.tokens)
|
||||||
|
await this.fetchPromisesFromMint(paymentHash, newTokens.newTokens)
|
||||||
|
},
|
||||||
|
|
||||||
|
buildTokens: async function (amounts, paymentHash) {
|
||||||
|
const blindedMessages = []
|
||||||
|
const secrets = []
|
||||||
|
const randomBlindingFactors = []
|
||||||
|
for (let i = 0; i < amounts.length; i++) {
|
||||||
|
// const secret = bytesToNumber(nobleSecp256k1.utils.randomBytes(32)) + ''
|
||||||
|
const secret = nobleSecp256k1.utils.randomBytes(32)
|
||||||
|
secrets.push(secret)
|
||||||
|
const {B_, randomBlindingFactor} = await step1Bob(secret)
|
||||||
|
randomBlindingFactors.push(randomBlindingFactor)
|
||||||
|
blindedMessages.push({amount: amounts[i], B_: B_})
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTokens = {
|
||||||
|
hash: paymentHash,
|
||||||
|
blindedMessages,
|
||||||
|
randomBlindingFactors,
|
||||||
|
secrets,
|
||||||
|
status: 'pending'
|
||||||
|
}
|
||||||
|
return newTokens
|
||||||
|
// console.log('### payloadsJson.payloads', payloadsJson.payloads)
|
||||||
|
// const promises = await mintApi.mint(payloadsJson.payloads, paymentHash)
|
||||||
|
// if (promises.error) {
|
||||||
|
// throw new Error(promises.error)
|
||||||
|
// }
|
||||||
|
// return this._constructProofs(promises, randomBlindingFactors, secrets)
|
||||||
|
},
|
||||||
|
|
||||||
|
_constructProofs: function (promises, randomBlindingFactors, secrets) {
|
||||||
|
return promises.map((p, i) => {
|
||||||
|
const C_ = nobleSecp256k1.Point.fromHex(p['C_'])
|
||||||
|
const A = this.keys[p.amount]
|
||||||
|
const C = step3Bob(
|
||||||
|
C_,
|
||||||
|
randomBlindingFactors[i],
|
||||||
|
nobleSecp256k1.Point.fromHex(A)
|
||||||
|
).toHex()
|
||||||
|
return {
|
||||||
|
amount: p.amount,
|
||||||
|
C: {C, secret: secrets[i]}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -910,10 +1032,16 @@ page_container %}
|
|||||||
this.tokenBuys = JSON.parse(
|
this.tokenBuys = JSON.parse(
|
||||||
localStorage.getItem('cashu.tokenBuys') || '[]'
|
localStorage.getItem('cashu.tokenBuys') || '[]'
|
||||||
)
|
)
|
||||||
|
this.tokens = JSON.parse(localStorage.getItem('cashu.tokens') || '[]')
|
||||||
console.log('#### this.tokenBuys', this.tokenBuys)
|
console.log('#### this.tokenBuys', this.tokenBuys)
|
||||||
console.log('#### this.mintId', this.mintId)
|
console.log('#### this.mintId', this.mintId)
|
||||||
console.log('#### this.mintName', this.mintName)
|
console.log('#### this.mintName', this.mintName)
|
||||||
|
|
||||||
|
this.checkXXXXXX()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
<script src="{{ url_for('cashu_static', path='js/noble-secp256k1.js') }}"></script>
|
||||||
|
<script src="{{ url_for('cashu_static', path='js/utils.js') }}"></script>
|
||||||
|
<script src="{{ url_for('cashu_static', path='js/dhke.js') }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -285,10 +285,10 @@ async def mint_coins(
|
|||||||
|
|
||||||
status: PaymentStatus = await check_transaction_status(cashu.wallet, payment_hash)
|
status: PaymentStatus = await check_transaction_status(cashu.wallet, payment_hash)
|
||||||
# todo: revert to: status.paid != True:
|
# todo: revert to: status.paid != True:
|
||||||
# if status.paid != True:
|
if status.paid != True:
|
||||||
# raise HTTPException(
|
raise HTTPException(
|
||||||
# status_code=HTTPStatus.PAYMENT_REQUIRED, detail="Invoice not paid."
|
status_code=HTTPStatus.PAYMENT_REQUIRED, detail="Invoice not paid."
|
||||||
# )
|
)
|
||||||
try:
|
try:
|
||||||
await update_lightning_invoice(cashu_id, payment_hash, True)
|
await update_lightning_invoice(cashu_id, payment_hash, True)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user