Skip to content

Commit

Permalink
Global mutex + output already signed healer + tokenv4 base64 keyset i…
Browse files Browse the repository at this point in the history
…d fix (#224)

* global mutex wip

* fix outputs already signed healer

* fix mutex and animate

* fix animations

* update cashu-ts-rc3 self healing on mint

* async mutex lock

* remove unneded code

* fix counter for pay invoice and mutex lock on mint activation

* counter for send
  • Loading branch information
callebtc authored Aug 31, 2024
1 parent 13882b9 commit 3d2f829
Show file tree
Hide file tree
Showing 13 changed files with 160 additions and 57 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
"@capacitor/clipboard": "^6.0.0",
"@capacitor/core": "^6.0.0",
"@capacitor/ios": "^6.0.0",
"@cashu/cashu-ts": "^1.1.0-2",
"@cashu/cashu-ts": "^1.1.0-3",
"@cashu/crypto": "^0.2.7",
"@chenfengyuan/vue-qrcode": "^2.0.0",
"@gandlaf21/bc-ur": "^1.1.12",
Expand Down
22 changes: 20 additions & 2 deletions src/components/BalanceView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,25 @@
<!-- <q-card class="q-my-md q-py-sm">
<q-card-section class="q-mt-sm q-py-xs"> -->
<div class="q-pt-xl q-pb-md">
<div class="row justify-center q-pb-lg">
<ToggleUnit class="q-mt-lg q-mb-none" :balanceView="true" />
<div class="row justify-center q-pb-lg" style="height:80px">
<div v-if="globalMutexLock">
<transition
appear
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
>
<q-spinner-hourglass class="q-mt-lg q-mb-none" size="lg" color="primary" />
</transition>
</div>
<div v-else >
<transition
appear
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut"
>
<ToggleUnit class="q-mt-lg q-mb-none" :balanceView="true" />
</transition>
</div>
</div>
<transition
appear
Expand Down Expand Up @@ -142,6 +159,7 @@ export default defineComponent({
]),
...mapState(useTokensStore, ["historyTokens"]),
...mapState(useSettingsStore, ["getBitcoinPrice"]),
...mapState(useUiStore, ["globalMutexLock"]),
...mapWritableState(useMintsStore, ["activeUnit"]),
...mapWritableState(useUiStore, ["hideBalance"]),
pendingBalance: function () {
Expand Down
14 changes: 8 additions & 6 deletions src/components/InvoiceDetailDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@
? 'Creating invoice...'
: 'Create Invoice'
"
><q-spinner-hourglass
v-if="createInvoiceButtonBlocked"
color="white"
size="1em"
/></q-btn>
:loading="globalMutexLock"
>
<template v-slot:loading>
<q-spinner-hourglass />
Creating
</template>
</q-btn>
<q-btn v-close-popup rounded flat color="grey" class="q-ml-auto"
>Close</q-btn
>
Expand Down Expand Up @@ -173,7 +175,7 @@ export default defineComponent({
...mapState(useWalletStore, ["invoiceData"]),
...mapState(useMintsStore, ["activeUnit", "activeUnitLabel"]),
...mapState(useWorkersStore, ["invoiceWorkerRunning"]),
...mapWritableState(useUiStore, ["showInvoiceDetails", "tickerShort"]),
...mapWritableState(useUiStore, ["showInvoiceDetails", "tickerShort", "globalMutexLock"]),
displayUnit: function () {
let display = this.formatCurrency(
this.invoiceData.amount,
Expand Down
4 changes: 4 additions & 0 deletions src/components/MintSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,10 @@ export default defineComponent({
}
},
sanitizeMintUrlAndShowAddDialog: function () {
// if no protocol is given, add https
if (!this.addMintData.url.match(/^[a-zA-Z]+:\/\//)) {
this.addMintData.url = "https://" + this.addMintData.url;
}
if (!this.validateMintUrl(this.addMintData.url)) {
notifyError("Invalid URL");
return;
Expand Down
16 changes: 9 additions & 7 deletions src/components/PayInvoiceDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,14 @@
payInvoiceData.blocking || payInvoiceData.meltQuote.error != ''
"
@click="melt"
:label="!payInvoiceData.blocking ? 'Pay' : 'Processing...'"
><q-spinner-hourglass
v-if="payInvoiceData.blocking"
color="primary"
size="1em"
/></q-btn>
:label="payInvoiceData.meltQuote.error != '' ? 'Error' : !payInvoiceData.blocking ? 'Pay' : 'Processing...'"
:loading="globalMutexLock && !payInvoiceData.blocking"
class="q-px-lg"
>
<template v-slot:loading >
<q-spinner-hourglass />
</template>
</q-btn>
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Close</q-btn>
</div>
<div v-else class="row q-mt-lg">
Expand Down Expand Up @@ -248,7 +250,7 @@ export default defineComponent({
},
},
computed: {
...mapState(useUiStore, ["tickerShort"]),
...mapState(useUiStore, ["tickerShort", "globalMutexLock"]),
...mapWritableState(useCameraStore, ["camera", "hasCamera"]),
...mapState(useWalletStore, ["payInvoiceData"]),
...mapState(useMintsStore, [
Expand Down
2 changes: 1 addition & 1 deletion src/components/ReceiveTokenDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
/>
</div>
</div>
<div class="row q-mt-lg">
<div class="row q-mt-lg q-pl-xs">
<q-btn
@click="receveIfDecodes"
color="primary"
Expand Down
17 changes: 13 additions & 4 deletions src/components/SendTokenDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,12 @@
color="primary"
rounded
type="submit"
>Send</q-btn
:loading="globalMutexLock"
>Send
<template v-slot:loading>
<q-spinner-hourglass />
</template>
</q-btn
>
<div
v-if="sendData.p2pkPubkey && isValidPubkey(sendData.p2pkPubkey)"
Expand Down Expand Up @@ -398,7 +403,7 @@ export default defineComponent({
]),
...mapWritableState(useSendTokensStore, ["sendData"]),
...mapWritableState(useCameraStore, ["camera", "hasCamera"]),
...mapState(useUiStore, ["tickerShort", "canPasteFromClipboard"]),
...mapState(useUiStore, ["tickerShort", "canPasteFromClipboard", "globalMutexLock"]),
...mapState(useMintsStore, [
"activeProofs",
"activeUnit",
Expand Down Expand Up @@ -590,14 +595,18 @@ export default defineComponent({
// if the token starts with 'cashuA', it is a v3 token
// if it starts with 'cashuB', it is a v4 token
if (this.sendData.tokensBase64.startsWith("cashuA")) {
this.sendData.tokensBase64 = getEncodedTokenV4(
try {
this.sendData.tokensBase64 = getEncodedTokenV4(decodedToken)
} catch {
console.log("### Could not encode token to V4");
this.sendData.tokensBase64 = getEncodedToken(
decodedToken
);
}
} else {
this.sendData.tokensBase64 = getEncodedToken(
decodedToken
);
}
},
deleteThisToken: function () {
Expand Down
4 changes: 2 additions & 2 deletions src/components/TokenInformation.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<template>
<div class="row text-left q-py-none q-my-none">
<div class="col-12 q-px-none">
<q-chip v-if="showAmount" outline class="q-mr-md q-pa-md">
<q-chip v-if="showAmount" outline class="q-pa-md" style="border-width: 2px;">
<q-icon name="toll" size="xs" class="q-mr-sm" />
<strong>{{ displayUnit }} </strong>
</q-chip>
<q-chip outline class="q-pa-md q-ml-md">
<q-chip outline class="q-pa-md">
<q-icon name="account_balance" size="xs" class="q-mr-xs" />
{{ tokenMintUrl }}
<q-spinner-hourglass v-if="addMintBlocking" size="sm" class="q-ml-sm" />
Expand Down
7 changes: 6 additions & 1 deletion src/stores/mints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useLocalStorage } from "@vueuse/core";
import { useWorkersStore } from "./workers";
import { notifyApiError, notifyError, notifySuccess } from "src/js/notify";
import { CashuMint, MintKeys, MintAllKeysets, Proof, SerializedBlindedSignature, MintKeyset } from "@cashu/cashu-ts";

import { useUiStore } from "./ui";
export type Mint = {
url: string;
keys: MintKeys[];
Expand Down Expand Up @@ -282,6 +282,7 @@ export const useMintsStore = defineStore("mints", {
},
activateMint: async function (mint: Mint, verbose = false, force = false) {
const workers = useWorkersStore();
const uIStore = useUiStore();
if (mint.url === this.activeMintUrl && !force) {
// return here because this function is called repeatedly by the
// invoice check and token spendable check workers and would otherwise
Expand All @@ -293,6 +294,7 @@ export const useMintsStore = defineStore("mints", {

// create new mint.api instance because we can't store it in local storage
let previousUrl = this.activeMintUrl;
await uIStore.lockMutex();
try {
this.activeMintUrl = mint.url;
console.log("### this.activeMintUrl", this.activeMintUrl);
Expand All @@ -316,6 +318,8 @@ export const useMintsStore = defineStore("mints", {
}
await notifyError(err_msg, "Mint activation failed");
throw error;
} finally {
await uIStore.unlockMutex();
}
},
fetchMintInfo: async function (mint: Mint) {
Expand All @@ -332,6 +336,7 @@ export const useMintsStore = defineStore("mints", {
}
},
fetchMintKeys: async function (mint: Mint) {

try {
const mintClass = new MintClass(mint);
const keysets = await this.fetchMintKeysets(mint);
Expand Down
8 changes: 7 additions & 1 deletion src/stores/proofs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ export const useProofsStore = defineStore("proofs", {
token: [{ proofs: proofs, mint: mints[0].url }],
unit: unit,
} as Token;
return getEncodedTokenV4(token);
try {
return getEncodedTokenV4(token);
} catch (e) {
console.log("Could not encode TokenV4, defaulting to TokenV3", e);
return getEncodedToken(token);
}


// // what we put into the JSON
// let mintsJson = mints.map((m) => [{ url: m.url, ids: m.keysets }][0]);
Expand Down
21 changes: 21 additions & 0 deletions src/stores/ui.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { defineStore } from "pinia";
import { useMintsStore } from "./mints";
import { useLocalStorage } from "@vueuse/core";
import { notifyApiError, notifyError, notifySuccess, notifyWarning, notify } from "../js/notify";

const unitTickerShortMap = {
sat: "sats",
Expand All @@ -19,8 +20,28 @@ export const useUiStore = defineStore("ui", {
tab: useLocalStorage("cashu.ui.tab", "history" as string),
expandHistory:
useLocalStorage("cashu.ui.expandHistory", true as boolean),
globalMutexLock: false,
}),
actions: {
async lockMutex() {
const nRetries = 10;
const retryInterval = 500;
let retries = 0;

while (this.globalMutexLock) {
if (retries >= nRetries) {
notify("Please try again.")
throw new Error("Failed to acquire global mutex lock");
}
retries++;
await new Promise(resolve => setTimeout(resolve, retryInterval));
}

this.globalMutexLock = true;
},
unlockMutex() {
this.globalMutexLock = false;
},
setTab(tab: string) {
this.tab = tab;
},
Expand Down
Loading

0 comments on commit 3d2f829

Please sign in to comment.