@openzeppelin/miden-multisig-client 0.17.0-rc.2 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +172 -47
- package/dist/account/builder.d.ts +2 -2
- package/dist/account/builder.d.ts.map +1 -1
- package/dist/account/builder.js +49 -24
- package/dist/account/builder.js.map +1 -1
- package/dist/connectivity.d.ts +2 -0
- package/dist/connectivity.d.ts.map +1 -1
- package/dist/connectivity.js +7 -4
- package/dist/connectivity.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/multisig/authArgErrors.d.ts +59 -0
- package/dist/multisig/authArgErrors.d.ts.map +1 -0
- package/dist/multisig/authArgErrors.js +115 -0
- package/dist/multisig/authArgErrors.js.map +1 -0
- package/dist/multisig/helpers.d.ts +5 -0
- package/dist/multisig/helpers.d.ts.map +1 -1
- package/dist/multisig/helpers.js +7 -2
- package/dist/multisig/helpers.js.map +1 -1
- package/dist/multisig.d.ts +140 -0
- package/dist/multisig.d.ts.map +1 -1
- package/dist/multisig.js +419 -12
- package/dist/multisig.js.map +1 -1
- package/dist/procedures.d.ts +1 -1
- package/dist/procedures.js +1 -1
- package/dist/recovery/proposalNoteImport.d.ts +173 -0
- package/dist/recovery/proposalNoteImport.d.ts.map +1 -0
- package/dist/recovery/proposalNoteImport.js +411 -0
- package/dist/recovery/proposalNoteImport.js.map +1 -0
- package/dist/recovery/publicNoteBackfill.d.ts +168 -0
- package/dist/recovery/publicNoteBackfill.d.ts.map +1 -0
- package/dist/recovery/publicNoteBackfill.js +368 -0
- package/dist/recovery/publicNoteBackfill.js.map +1 -0
- package/dist/recovery/recoverNotes.d.ts +147 -0
- package/dist/recovery/recoverNotes.d.ts.map +1 -0
- package/dist/recovery/recoverNotes.js +163 -0
- package/dist/recovery/recoverNotes.js.map +1 -0
- package/dist/recovery/transportDrain.d.ts +124 -0
- package/dist/recovery/transportDrain.d.ts.map +1 -0
- package/dist/recovery/transportDrain.js +262 -0
- package/dist/recovery/transportDrain.js.map +1 -0
- package/dist/transaction/consumeNotes.d.ts.map +1 -1
- package/dist/transaction/consumeNotes.js +4 -1
- package/dist/transaction/consumeNotes.js.map +1 -1
- package/dist/transaction/p2id.d.ts.map +1 -1
- package/dist/transaction/p2id.js +4 -1
- package/dist/transaction/p2id.js.map +1 -1
- package/dist/transaction/summary.d.ts +10 -4
- package/dist/transaction/summary.d.ts.map +1 -1
- package/dist/transaction/summary.js +13 -7
- package/dist/transaction/summary.js.map +1 -1
- package/dist/transaction/updateGuardian.js +4 -1
- package/dist/transaction/updateGuardian.js.map +1 -1
- package/dist/transaction/updateProcedureThreshold.js +4 -1
- package/dist/transaction/updateProcedureThreshold.js.map +1 -1
- package/dist/transaction/updateSigners.js +4 -1
- package/dist/transaction/updateSigners.js.map +1 -1
- package/dist/transaction.d.ts +1 -1
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +1 -1
- package/dist/transaction.js.map +1 -1
- package/package.json +14 -10
- package/src/account/builder.ts +87 -35
- package/src/connectivity.ts +9 -4
- package/src/index.ts +34 -1
- package/src/multisig/authArgErrors.ts +138 -0
- package/src/multisig/helpers.ts +7 -2
- package/src/multisig.ts +513 -20
- package/src/procedures.ts +1 -1
- package/src/recovery/proposalNoteImport.ts +548 -0
- package/src/recovery/publicNoteBackfill.ts +502 -0
- package/src/recovery/recoverNotes.ts +288 -0
- package/src/recovery/transportDrain.ts +330 -0
- package/src/transaction/consumeNotes.ts +4 -1
- package/src/transaction/p2id.ts +4 -1
- package/src/transaction/summary.ts +13 -7
- package/src/transaction/updateGuardian.ts +4 -1
- package/src/transaction/updateProcedureThreshold.ts +4 -1
- package/src/transaction/updateSigners.ts +4 -1
- package/src/transaction.ts +1 -1
- package/dist/account/builder.test.d.ts +0 -2
- package/dist/account/builder.test.d.ts.map +0 -1
- package/dist/account/builder.test.js +0 -166
- package/dist/account/builder.test.js.map +0 -1
- package/dist/account/masm/account-components/auth.d.ts +0 -2
- package/dist/account/masm/account-components/auth.d.ts.map +0 -1
- package/dist/account/masm/account-components/auth.js +0 -46
- package/dist/account/masm/account-components/auth.js.map +0 -1
- package/dist/account/masm/index.d.ts +0 -2
- package/dist/account/masm/index.d.ts.map +0 -1
- package/dist/account/masm/index.js +0 -4
- package/dist/account/masm/index.js.map +0 -1
- package/dist/account/masm.d.ts +0 -2
- package/dist/account/masm.d.ts.map +0 -1
- package/dist/account/masm.js +0 -4
- package/dist/account/masm.js.map +0 -1
- package/dist/account/storage.test.d.ts +0 -2
- package/dist/account/storage.test.d.ts.map +0 -1
- package/dist/account/storage.test.js +0 -73
- package/dist/account/storage.test.js.map +0 -1
- package/dist/client.test.d.ts +0 -2
- package/dist/client.test.d.ts.map +0 -1
- package/dist/client.test.js +0 -380
- package/dist/client.test.js.map +0 -1
- package/dist/connectivity.test.d.ts +0 -2
- package/dist/connectivity.test.d.ts.map +0 -1
- package/dist/connectivity.test.js +0 -61
- package/dist/connectivity.test.js.map +0 -1
- package/dist/inspector.test.d.ts +0 -2
- package/dist/inspector.test.d.ts.map +0 -1
- package/dist/inspector.test.js +0 -425
- package/dist/inspector.test.js.map +0 -1
- package/dist/lookupAuth.test.d.ts +0 -2
- package/dist/lookupAuth.test.d.ts.map +0 -1
- package/dist/lookupAuth.test.js +0 -138
- package/dist/lookupAuth.test.js.map +0 -1
- package/dist/multisig/consumeNotesErrors.test.d.ts +0 -2
- package/dist/multisig/consumeNotesErrors.test.d.ts.map +0 -1
- package/dist/multisig/consumeNotesErrors.test.js +0 -28
- package/dist/multisig/consumeNotesErrors.test.js.map +0 -1
- package/dist/multisig/helpers.test.d.ts +0 -2
- package/dist/multisig/helpers.test.d.ts.map +0 -1
- package/dist/multisig/helpers.test.js +0 -94
- package/dist/multisig/helpers.test.js.map +0 -1
- package/dist/multisig.test.d.ts +0 -2
- package/dist/multisig.test.d.ts.map +0 -1
- package/dist/multisig.test.js +0 -4112
- package/dist/multisig.test.js.map +0 -1
- package/dist/proposal/factory.test.d.ts +0 -2
- package/dist/proposal/factory.test.d.ts.map +0 -1
- package/dist/proposal/factory.test.js +0 -32
- package/dist/proposal/factory.test.js.map +0 -1
- package/dist/proposal/metadata.test.d.ts +0 -2
- package/dist/proposal/metadata.test.d.ts.map +0 -1
- package/dist/proposal/metadata.test.js +0 -193
- package/dist/proposal/metadata.test.js.map +0 -1
- package/dist/prover/config.test.d.ts +0 -2
- package/dist/prover/config.test.d.ts.map +0 -1
- package/dist/prover/config.test.js +0 -54
- package/dist/prover/config.test.js.map +0 -1
- package/dist/prover/errors.test.d.ts +0 -2
- package/dist/prover/errors.test.d.ts.map +0 -1
- package/dist/prover/errors.test.js +0 -29
- package/dist/prover/errors.test.js.map +0 -1
- package/dist/prover/retry.test.d.ts +0 -2
- package/dist/prover/retry.test.d.ts.map +0 -1
- package/dist/prover/retry.test.js +0 -20
- package/dist/prover/retry.test.js.map +0 -1
- package/dist/prover/workflow.test.d.ts +0 -2
- package/dist/prover/workflow.test.d.ts.map +0 -1
- package/dist/prover/workflow.test.js +0 -105
- package/dist/prover/workflow.test.js.map +0 -1
- package/dist/raw-client.test.d.ts +0 -2
- package/dist/raw-client.test.d.ts.map +0 -1
- package/dist/raw-client.test.js +0 -111
- package/dist/raw-client.test.js.map +0 -1
- package/dist/rpc/config.test.d.ts +0 -2
- package/dist/rpc/config.test.d.ts.map +0 -1
- package/dist/rpc/config.test.js +0 -24
- package/dist/rpc/config.test.js.map +0 -1
- package/dist/rpc/errors.test.d.ts +0 -2
- package/dist/rpc/errors.test.d.ts.map +0 -1
- package/dist/rpc/errors.test.js +0 -34
- package/dist/rpc/errors.test.js.map +0 -1
- package/dist/rpc/retry.test.d.ts +0 -2
- package/dist/rpc/retry.test.d.ts.map +0 -1
- package/dist/rpc/retry.test.js +0 -98
- package/dist/rpc/retry.test.js.map +0 -1
- package/dist/signers/ecdsa.test.d.ts +0 -2
- package/dist/signers/ecdsa.test.d.ts.map +0 -1
- package/dist/signers/ecdsa.test.js +0 -88
- package/dist/signers/ecdsa.test.js.map +0 -1
- package/dist/signers/falcon.test.d.ts +0 -2
- package/dist/signers/falcon.test.d.ts.map +0 -1
- package/dist/signers/falcon.test.js +0 -161
- package/dist/signers/falcon.test.js.map +0 -1
- package/dist/signers/miden-wallet.ecdsa-recovery.test.d.ts +0 -2
- package/dist/signers/miden-wallet.ecdsa-recovery.test.d.ts.map +0 -1
- package/dist/signers/miden-wallet.ecdsa-recovery.test.js +0 -148
- package/dist/signers/miden-wallet.ecdsa-recovery.test.js.map +0 -1
- package/dist/signers/miden-wallet.test.d.ts +0 -2
- package/dist/signers/miden-wallet.test.d.ts.map +0 -1
- package/dist/signers/miden-wallet.test.js +0 -164
- package/dist/signers/miden-wallet.test.js.map +0 -1
- package/dist/signers/para.test.d.ts +0 -2
- package/dist/signers/para.test.d.ts.map +0 -1
- package/dist/signers/para.test.js +0 -146
- package/dist/signers/para.test.js.map +0 -1
- package/dist/transaction/index.d.ts +0 -8
- package/dist/transaction/index.d.ts.map +0 -1
- package/dist/transaction/index.js +0 -7
- package/dist/transaction/index.js.map +0 -1
- package/dist/transaction/p2id.test.d.ts +0 -2
- package/dist/transaction/p2id.test.d.ts.map +0 -1
- package/dist/transaction/p2id.test.js +0 -246
- package/dist/transaction/p2id.test.js.map +0 -1
- package/dist/transaction/rpoRandomCoin.test.d.ts +0 -2
- package/dist/transaction/rpoRandomCoin.test.d.ts.map +0 -1
- package/dist/transaction/rpoRandomCoin.test.js +0 -52
- package/dist/transaction/rpoRandomCoin.test.js.map +0 -1
- package/dist/transaction/summary.test.d.ts +0 -2
- package/dist/transaction/summary.test.d.ts.map +0 -1
- package/dist/transaction/summary.test.js +0 -26
- package/dist/transaction/summary.test.js.map +0 -1
- package/dist/transaction.test.d.ts +0 -2
- package/dist/transaction.test.d.ts.map +0 -1
- package/dist/transaction.test.js +0 -122
- package/dist/transaction.test.js.map +0 -1
- package/dist/types/proposal.test.d.ts +0 -2
- package/dist/types/proposal.test.d.ts.map +0 -1
- package/dist/types/proposal.test.js +0 -56
- package/dist/types/proposal.test.js.map +0 -1
- package/dist/utils/digest.test.d.ts +0 -2
- package/dist/utils/digest.test.d.ts.map +0 -1
- package/dist/utils/digest.test.js +0 -48
- package/dist/utils/digest.test.js.map +0 -1
- package/dist/utils/ecdsa.test.d.ts +0 -2
- package/dist/utils/ecdsa.test.d.ts.map +0 -1
- package/dist/utils/ecdsa.test.js +0 -131
- package/dist/utils/ecdsa.test.js.map +0 -1
- package/dist/utils/encoding.test.d.ts +0 -2
- package/dist/utils/encoding.test.d.ts.map +0 -1
- package/dist/utils/encoding.test.js +0 -185
- package/dist/utils/encoding.test.js.map +0 -1
- package/dist/utils/key.test.d.ts +0 -2
- package/dist/utils/key.test.d.ts.map +0 -1
- package/dist/utils/key.test.js +0 -82
- package/dist/utils/key.test.js.map +0 -1
- package/dist/utils/signature.test.d.ts +0 -2
- package/dist/utils/signature.test.d.ts.map +0 -1
- package/dist/utils/signature.test.js +0 -164
- package/dist/utils/signature.test.js.map +0 -1
- package/dist/utils/word.test.d.ts +0 -2
- package/dist/utils/word.test.d.ts.map +0 -1
- package/dist/utils/word.test.js +0 -54
- package/dist/utils/word.test.js.map +0 -1
- package/masm/account_components/auth/guarded_multisig.masm +0 -42
- package/src/account/builder.test.ts +0 -238
- package/src/account/masm/account-components/auth.ts +0 -46
- package/src/account/masm/index.ts +0 -4
- package/src/account/masm.ts +0 -4
- package/src/account/storage.test.ts +0 -90
- package/src/client.test.ts +0 -473
- package/src/connectivity.test.ts +0 -67
- package/src/inspector.test.ts +0 -542
- package/src/lookupAuth.test.ts +0 -185
- package/src/multisig/consumeNotesErrors.test.ts +0 -43
- package/src/multisig/helpers.test.ts +0 -114
- package/src/multisig.test.ts +0 -5008
- package/src/proposal/factory.test.ts +0 -40
- package/src/proposal/metadata.test.ts +0 -235
- package/src/prover/config.test.ts +0 -90
- package/src/prover/errors.test.ts +0 -61
- package/src/prover/retry.test.ts +0 -38
- package/src/prover/workflow.test.ts +0 -145
- package/src/raw-client.test.ts +0 -171
- package/src/rpc/config.test.ts +0 -45
- package/src/rpc/errors.test.ts +0 -69
- package/src/rpc/retry.test.ts +0 -144
- package/src/signers/ecdsa.test.ts +0 -111
- package/src/signers/falcon.test.ts +0 -197
- package/src/signers/miden-wallet.ecdsa-recovery.test.ts +0 -201
- package/src/signers/miden-wallet.test.ts +0 -206
- package/src/signers/para.test.ts +0 -186
- package/src/transaction/index.ts +0 -13
- package/src/transaction/p2id.test.ts +0 -371
- package/src/transaction/rpoRandomCoin.test.ts +0 -64
- package/src/transaction/summary.test.ts +0 -32
- package/src/transaction.test.ts +0 -142
- package/src/types/proposal.test.ts +0 -68
- package/src/utils/digest.test.ts +0 -55
- package/src/utils/ecdsa.test.ts +0 -164
- package/src/utils/encoding.test.ts +0 -233
- package/src/utils/key.test.ts +0 -91
- package/src/utils/signature.test.ts +0 -210
- package/src/utils/word.test.ts +0 -64
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recovery primitives.
|
|
3
|
+
*
|
|
4
|
+
* After key-based recovery the local Miden store starts empty, so notes the
|
|
5
|
+
* account was in the middle of consuming are gone. v2 `consume_notes`
|
|
6
|
+
* proposals embed the serialized notes they consume, which makes
|
|
7
|
+
* pending proposals opportunistic recovery material: this module rebuilds
|
|
8
|
+
* importable notes from those embedded bytes plus a node-fetched inclusion
|
|
9
|
+
* proof, without needing the node to hold the note body — so it works for
|
|
10
|
+
* private notes too.
|
|
11
|
+
*/
|
|
12
|
+
import { Endpoint, InputNote, InputNoteState, Note, NoteDetails, NoteFile, NoteFilter, NoteFilterTypes, RpcClient, } from '@miden-sdk/miden-sdk';
|
|
13
|
+
import { getRawMidenClient, requireMidenRpcEndpoint } from '../raw-client.js';
|
|
14
|
+
import { resolveRpcConfig } from '../rpc/config.js';
|
|
15
|
+
import { isTransientRpcError } from '../rpc/errors.js';
|
|
16
|
+
import { retryRpcRead } from '../rpc/retry.js';
|
|
17
|
+
import { isConsumeNotesV2 } from '../types/proposal.js';
|
|
18
|
+
import { noteFromBase64, normalizeHexWord } from '../utils/encoding.js';
|
|
19
|
+
/**
|
|
20
|
+
* Thrown by the recovery cancellation checkpoints; `runNoteRecovery` stops
|
|
21
|
+
* on it instead of misreporting a step failure. The message avoids
|
|
22
|
+
* 'cancelled'/'timeout' wording on purpose — the RPC retry classifier
|
|
23
|
+
* treats those fragments as transient, and cancellation must not retry.
|
|
24
|
+
*/
|
|
25
|
+
export class RecoveryCancelledError extends Error {
|
|
26
|
+
constructor() {
|
|
27
|
+
super('note recovery stopped before completion by its caller');
|
|
28
|
+
this.name = 'RecoveryCancelledError';
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/** Throws {@link RecoveryCancelledError} when the token reports cancelled. */
|
|
32
|
+
export function throwIfCancelled(cancelled) {
|
|
33
|
+
if (cancelled?.()) {
|
|
34
|
+
throw new RecoveryCancelledError();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** Shared by the recovery primitives (proposal import and backfill). */
|
|
38
|
+
export function errorDetail(error) {
|
|
39
|
+
return error instanceof Error ? error.message : String(error);
|
|
40
|
+
}
|
|
41
|
+
/** Details key: recipient digest + canonical FUNGIBLE asset list. This
|
|
42
|
+
* approximates the details commitment — which the WASM record surface does
|
|
43
|
+
* not expose — as closely as the surface allows: `fungibleAssets()` silently
|
|
44
|
+
* omits non-fungible assets and no complete accessor or commitment exists,
|
|
45
|
+
* so two notes sharing a recipient digest and fungible assets but differing
|
|
46
|
+
* only in non-fungible assets collide (the Rust SDK, keyed on the real
|
|
47
|
+
* `NoteDetailsCommitment`, does not). Latent until NFA-bearing notes reach
|
|
48
|
+
* these flows; closing it needs an upstream `NoteAssets` commitment/NFA
|
|
49
|
+
* accessor. Recipient digest alone would be worse: distinct notes can share
|
|
50
|
+
* a recipient while carrying different fungible assets. */
|
|
51
|
+
export function detailsKeyOf(recipientDigestHex, assets) {
|
|
52
|
+
const fingerprint = assets
|
|
53
|
+
.fungibleAssets()
|
|
54
|
+
.map((asset) => `${normalizeHexWord(asset.faucetId().toString())}:${asset.amount()}`)
|
|
55
|
+
.sort()
|
|
56
|
+
.join(',');
|
|
57
|
+
return `${recipientDigestHex}|${fingerprint}`;
|
|
58
|
+
}
|
|
59
|
+
function recordKeys(record) {
|
|
60
|
+
const keys = [];
|
|
61
|
+
const recordId = record.id();
|
|
62
|
+
if (recordId) {
|
|
63
|
+
keys.push(normalizeHexWord(recordId.toString()));
|
|
64
|
+
}
|
|
65
|
+
const details = record.details();
|
|
66
|
+
keys.push(detailsKeyOf(normalizeHexWord(details.recipient().digest().toHex()), details.assets()));
|
|
67
|
+
return keys;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Scans the store once and keys every record by note ID *and* details key:
|
|
71
|
+
* records the store keeps without metadata (a note details import in
|
|
72
|
+
* expected state, or a note observed as consumed on chain) expose neither a
|
|
73
|
+
* note ID nor a nullifier, and an ID-only lookup would keep re-importing
|
|
74
|
+
* them forever. (The WASM NoteFilter has no details-commitment variant,
|
|
75
|
+
* unlike the Rust SDK, so the store is scanned once and keyed both ways.)
|
|
76
|
+
* Shared by the recovery primitives (proposal import and backfill).
|
|
77
|
+
*/
|
|
78
|
+
export async function collectExistingRecords(webClient) {
|
|
79
|
+
const existing = new Map();
|
|
80
|
+
const records = await webClient.getInputNotes(new NoteFilter(NoteFilterTypes.All));
|
|
81
|
+
for (const record of records) {
|
|
82
|
+
for (const key of recordKeys(record)) {
|
|
83
|
+
existing.set(key, record);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return existing;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Imports one note with its inclusion proof and classifies the result.
|
|
90
|
+
* Upstream note-import batches are atomic, which is why callers import
|
|
91
|
+
* individually — one bad note must not sink the rest. Returns the outcome
|
|
92
|
+
* and whether the import succeeded (input for the batched consumed-state
|
|
93
|
+
* re-check).
|
|
94
|
+
*/
|
|
95
|
+
export async function importNoteWithProof(webClient, source, idHex, note, proof) {
|
|
96
|
+
try {
|
|
97
|
+
const inputNote = InputNote.authenticated(note, proof);
|
|
98
|
+
await webClient.importNoteFile(NoteFile.fromInputNote(inputNote));
|
|
99
|
+
return {
|
|
100
|
+
outcome: { identifier: idHex, source, status: 'imported' },
|
|
101
|
+
wasImported: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
return {
|
|
106
|
+
outcome: {
|
|
107
|
+
identifier: idHex,
|
|
108
|
+
source,
|
|
109
|
+
status: 'failed',
|
|
110
|
+
retryable: isTransientRpcError(error),
|
|
111
|
+
reason: `failed to import note: ${errorDetail(error)}`,
|
|
112
|
+
},
|
|
113
|
+
wasImported: false,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Re-classifies provisionally `imported` outcomes from the records the
|
|
119
|
+
* import actually left behind. A note the chain had already nullified is
|
|
120
|
+
* stored as consumption history, not as a consumable note — reported as
|
|
121
|
+
* `already-consumed`. A note whose inclusion proof failed verification
|
|
122
|
+
* against the authenticated block header is stored in `Invalid` state by
|
|
123
|
+
* upstream while the import still resolves — reported as `failed`, because
|
|
124
|
+
* "recovered" notes that can never be consumed must not count as recovered.
|
|
125
|
+
* Records are matched by note ID when they expose one, and by the (lossy,
|
|
126
|
+
* fungible-assets-only) details key otherwise — a chain-consumed record is
|
|
127
|
+
* stored without metadata, so the approximation is the only join available;
|
|
128
|
+
* it can only misstate the status here, never skip an import. One batched
|
|
129
|
+
* store read covers every imported note. A failed check downgrades nothing;
|
|
130
|
+
* it flags the outcome's classification as unconfirmed instead.
|
|
131
|
+
*/
|
|
132
|
+
export async function reclassifyConsumedImports(webClient, imported, outcomes) {
|
|
133
|
+
if (imported.length === 0) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
const records = await webClient.getInputNotes(new NoteFilter(NoteFilterTypes.All));
|
|
138
|
+
const byId = new Map();
|
|
139
|
+
const byDetailsKey = new Map();
|
|
140
|
+
for (const record of records) {
|
|
141
|
+
const recordId = record.id();
|
|
142
|
+
if (recordId) {
|
|
143
|
+
byId.set(normalizeHexWord(recordId.toString()), record);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const details = record.details();
|
|
147
|
+
byDetailsKey.set(detailsKeyOf(normalizeHexWord(details.recipient().digest().toHex()), details.assets()), record);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
for (const entry of imported) {
|
|
151
|
+
const record = byId.get(entry.idHex) ?? byDetailsKey.get(entry.detailsKey);
|
|
152
|
+
if (!record) {
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (record.isConsumed()) {
|
|
156
|
+
outcomes[entry.index] = {
|
|
157
|
+
...outcomes[entry.index],
|
|
158
|
+
status: 'already-consumed',
|
|
159
|
+
reason: 'note was already consumed on chain; recorded as consumption history',
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
else if (record.state() === InputNoteState.Invalid) {
|
|
163
|
+
outcomes[entry.index] = {
|
|
164
|
+
...outcomes[entry.index],
|
|
165
|
+
status: 'failed',
|
|
166
|
+
retryable: false,
|
|
167
|
+
reason: "the note's inclusion proof failed verification against the authenticated block header; the record is stored as invalid and the note is not consumable",
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
// The imports themselves succeeded; stay `imported` but flag that the
|
|
174
|
+
// post-import state check is unknown.
|
|
175
|
+
for (const entry of imported) {
|
|
176
|
+
outcomes[entry.index] = {
|
|
177
|
+
...outcomes[entry.index],
|
|
178
|
+
reason: `imported, but the post-import state check failed (${errorDetail(error)}); run sync to confirm the note's status`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Imports the notes embedded in v2 `consume_notes` proposals into the local
|
|
185
|
+
* Miden store, typically after key-based recovery rebuilt the
|
|
186
|
+
* proposal list (`syncProposals`) but left the note store empty.
|
|
187
|
+
*
|
|
188
|
+
* Proposals are opportunistic recovery material, not a backup: v1 proposals
|
|
189
|
+
* carry no note bytes, and proposals disappear once canonicalized, so only
|
|
190
|
+
* notes still mid-consumption are recoverable this way.
|
|
191
|
+
*
|
|
192
|
+
* Per note: decode the embedded bytes, skip notes the store already tracks,
|
|
193
|
+
* fetch the on-chain inclusion proof, and import the note individually
|
|
194
|
+
* (upstream note-import batches are atomic, so one bad note must not sink the
|
|
195
|
+
* rest). A note the chain does not know yet is recorded as expected with its
|
|
196
|
+
* tag tracked so a later sync picks it up, and is reported as
|
|
197
|
+
* `not-committed`/retryable. A note the chain has already nullified is
|
|
198
|
+
* recorded as consumption history and reported `already-consumed`.
|
|
199
|
+
*
|
|
200
|
+
* The returned outcomes cover every unique embedded note — a note embedded by
|
|
201
|
+
* several proposals yields one outcome, not one per embedding — and this
|
|
202
|
+
* function does not throw for per-note problems.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* const proposals = await multisig.syncProposals();
|
|
207
|
+
* const outcomes = await importNotesFromProposals(midenClient, proposals, {
|
|
208
|
+
* midenRpcEndpoint: 'https://rpc.testnet.miden.io',
|
|
209
|
+
* });
|
|
210
|
+
* await multisig.syncState();
|
|
211
|
+
* ```
|
|
212
|
+
*/
|
|
213
|
+
export async function importNotesFromProposals(midenClient, proposals, options) {
|
|
214
|
+
const midenRpcEndpoint = requireMidenRpcEndpoint(options.midenRpcEndpoint);
|
|
215
|
+
const rpcConfig = resolveRpcConfig(options.rpc);
|
|
216
|
+
throwIfCancelled(options.cancelled);
|
|
217
|
+
const webClient = await getRawMidenClient(midenClient, midenRpcEndpoint);
|
|
218
|
+
const outcomes = [];
|
|
219
|
+
// Decode, validate, and deduplicate embedded notes (the same note may be
|
|
220
|
+
// embedded by several proposals). Undecodable entries, embeddings past the
|
|
221
|
+
// declared note-id list, and embeddings whose decoded ID disagrees with
|
|
222
|
+
// the declared one become isolated `invalid` outcomes with a positional
|
|
223
|
+
// identifier: recovery runs automatically over synced proposals, so the
|
|
224
|
+
// per-index ID binding is what keeps a malformed or adversarial proposal
|
|
225
|
+
// from smuggling arbitrary notes (and, for uncommitted ones, persistent
|
|
226
|
+
// expected records and tag registrations) into the local store.
|
|
227
|
+
const decoded = [];
|
|
228
|
+
const seen = new Set();
|
|
229
|
+
for (const proposal of proposals) {
|
|
230
|
+
const metadata = proposal.metadata;
|
|
231
|
+
if (metadata.proposalType !== 'consume_notes' || !isConsumeNotesV2(metadata)) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const embedded = metadata.notes ?? [];
|
|
235
|
+
const declaredIds = metadata.noteIds ?? [];
|
|
236
|
+
for (let index = 0; index < embedded.length; index += 1) {
|
|
237
|
+
const identifier = `proposal ${proposal.id} notes[${index}]`;
|
|
238
|
+
const declaredId = declaredIds[index];
|
|
239
|
+
if (declaredId === undefined) {
|
|
240
|
+
outcomes.push({
|
|
241
|
+
identifier,
|
|
242
|
+
source: 'proposal',
|
|
243
|
+
status: 'invalid',
|
|
244
|
+
reason: "embedded note has no matching entry in the proposal's declared note ids",
|
|
245
|
+
});
|
|
246
|
+
continue;
|
|
247
|
+
}
|
|
248
|
+
// The try covers every per-note WASM accessor, so a payload that
|
|
249
|
+
// deserializes but traps on use is isolated like any other bad note.
|
|
250
|
+
let candidate;
|
|
251
|
+
try {
|
|
252
|
+
const note = noteFromBase64(embedded[index], Note);
|
|
253
|
+
candidate = {
|
|
254
|
+
note,
|
|
255
|
+
idHex: normalizeHexWord(note.id().toString()),
|
|
256
|
+
detailsKey: detailsKeyOf(normalizeHexWord(note.recipient().digest().toHex()), note.assets()),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
catch (error) {
|
|
260
|
+
outcomes.push({
|
|
261
|
+
identifier,
|
|
262
|
+
source: 'proposal',
|
|
263
|
+
status: 'invalid',
|
|
264
|
+
reason: `failed to decode embedded note: ${errorDetail(error)}`,
|
|
265
|
+
});
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (candidate.idHex !== normalizeHexWord(declaredId)) {
|
|
269
|
+
outcomes.push({
|
|
270
|
+
identifier,
|
|
271
|
+
source: 'proposal',
|
|
272
|
+
status: 'invalid',
|
|
273
|
+
reason: `embedded note decodes to ${candidate.idHex} but the proposal declares ${declaredId}`,
|
|
274
|
+
});
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (seen.has(candidate.idHex)) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
seen.add(candidate.idHex);
|
|
281
|
+
decoded.push(candidate);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
if (decoded.length === 0) {
|
|
285
|
+
return outcomes;
|
|
286
|
+
}
|
|
287
|
+
let existing;
|
|
288
|
+
try {
|
|
289
|
+
existing = await collectExistingRecords(webClient);
|
|
290
|
+
}
|
|
291
|
+
catch (error) {
|
|
292
|
+
const reason = `failed to read local store: ${errorDetail(error)}`;
|
|
293
|
+
for (const candidate of decoded) {
|
|
294
|
+
outcomes.push({
|
|
295
|
+
identifier: candidate.idHex,
|
|
296
|
+
source: 'proposal',
|
|
297
|
+
status: 'failed',
|
|
298
|
+
reason,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
return outcomes;
|
|
302
|
+
}
|
|
303
|
+
// Skip notes the store already tracks — but only on an exact note-ID
|
|
304
|
+
// match. A details-key match is a lossy approximation (see
|
|
305
|
+
// {@link detailsKeyOf}), so a candidate that only matches a metadata-less
|
|
306
|
+
// record proceeds to import: the upstream import dedupes exactly by the
|
|
307
|
+
// real details commitment, upgrading or no-oping in place, so importing
|
|
308
|
+
// "again" is safe while pre-skipping on the approximation could silently
|
|
309
|
+
// drop a genuinely new note.
|
|
310
|
+
const pending = [];
|
|
311
|
+
for (const candidate of decoded) {
|
|
312
|
+
const record = existing.get(candidate.idHex);
|
|
313
|
+
if (record) {
|
|
314
|
+
outcomes.push({
|
|
315
|
+
identifier: candidate.idHex,
|
|
316
|
+
source: 'proposal',
|
|
317
|
+
status: record.isConsumed() ? 'already-consumed' : 'already-present',
|
|
318
|
+
});
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
pending.push(candidate);
|
|
322
|
+
}
|
|
323
|
+
if (pending.length === 0) {
|
|
324
|
+
return outcomes;
|
|
325
|
+
}
|
|
326
|
+
// One round trip for all missing notes; only the import itself is per-note.
|
|
327
|
+
// The node returns proofs for private notes too, so the locally-held bytes
|
|
328
|
+
// are the only body this path ever needs.
|
|
329
|
+
const proofs = new Map();
|
|
330
|
+
throwIfCancelled(options.cancelled);
|
|
331
|
+
try {
|
|
332
|
+
const rpcClient = new RpcClient(new Endpoint(midenRpcEndpoint));
|
|
333
|
+
// Inside the retried closure, so a token flip between attempts stops
|
|
334
|
+
// the retry loop instead of letting backoff attempts outlive the
|
|
335
|
+
// deadline.
|
|
336
|
+
const fetchedNotes = await retryRpcRead(() => {
|
|
337
|
+
throwIfCancelled(options.cancelled);
|
|
338
|
+
return rpcClient.getNotesById(pending.map((candidate) => candidate.note.id()));
|
|
339
|
+
}, rpcConfig);
|
|
340
|
+
for (const fetched of fetchedNotes) {
|
|
341
|
+
proofs.set(normalizeHexWord(fetched.noteId.toString()), fetched.inclusionProof);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
if (error instanceof RecoveryCancelledError) {
|
|
346
|
+
throw error;
|
|
347
|
+
}
|
|
348
|
+
const retryable = isTransientRpcError(error);
|
|
349
|
+
const reason = `failed to fetch inclusion proofs: ${errorDetail(error)}`;
|
|
350
|
+
for (const candidate of pending) {
|
|
351
|
+
outcomes.push({
|
|
352
|
+
identifier: candidate.idHex,
|
|
353
|
+
source: 'proposal',
|
|
354
|
+
status: 'failed',
|
|
355
|
+
retryable,
|
|
356
|
+
reason,
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
return outcomes;
|
|
360
|
+
}
|
|
361
|
+
// Provisionally `imported` outcomes, re-classified in one batched
|
|
362
|
+
// post-import state check below.
|
|
363
|
+
const imported = [];
|
|
364
|
+
for (const candidate of pending) {
|
|
365
|
+
throwIfCancelled(options.cancelled);
|
|
366
|
+
const proof = proofs.get(candidate.idHex);
|
|
367
|
+
if (proof) {
|
|
368
|
+
const { outcome, wasImported } = await importNoteWithProof(webClient, 'proposal', candidate.idHex, candidate.note, proof);
|
|
369
|
+
if (wasImported) {
|
|
370
|
+
imported.push({
|
|
371
|
+
index: outcomes.length,
|
|
372
|
+
idHex: candidate.idHex,
|
|
373
|
+
detailsKey: candidate.detailsKey,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
outcomes.push(outcome);
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
try {
|
|
380
|
+
// Mirror the Rust SDK's `NoteFile::ExpectedNote` + sync-hint import:
|
|
381
|
+
// the tag rides in the note file itself, so upstream registers a
|
|
382
|
+
// note-source tag that sync uses to discover the commitment and
|
|
383
|
+
// removes once the note commits. (An explicit `addTag` would instead
|
|
384
|
+
// create a permanent user-source tag that the transport backfill
|
|
385
|
+
// also re-drains, and that would outlive even a failed import.)
|
|
386
|
+
const details = new NoteDetails(candidate.note.assets(), candidate.note.recipient());
|
|
387
|
+
await webClient.importNoteFile(NoteFile.fromExpectedNote(details, candidate.note.metadata().tag(), 0));
|
|
388
|
+
outcomes.push({
|
|
389
|
+
identifier: candidate.idHex,
|
|
390
|
+
source: 'proposal',
|
|
391
|
+
status: 'not-committed',
|
|
392
|
+
retryable: true,
|
|
393
|
+
reason: 'note not yet committed on chain; recorded as expected so a later sync picks it up',
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
catch (error) {
|
|
397
|
+
outcomes.push({
|
|
398
|
+
identifier: candidate.idHex,
|
|
399
|
+
source: 'proposal',
|
|
400
|
+
status: 'failed',
|
|
401
|
+
retryable: isTransientRpcError(error),
|
|
402
|
+
reason: `failed to record expected note: ${errorDetail(error)}`,
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
throwIfCancelled(options.cancelled);
|
|
408
|
+
await reclassifyConsumedImports(webClient, imported, outcomes);
|
|
409
|
+
return outcomes;
|
|
410
|
+
}
|
|
411
|
+
//# sourceMappingURL=proposalNoteImport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposalNoteImport.js","sourceRoot":"","sources":["../../src/recovery/proposalNoteImport.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Historical public-note backfill by tag.
|
|
3
|
+
*
|
|
4
|
+
* Public notes addressed to an account are on chain, but normal forward sync
|
|
5
|
+
* starts from the store's **global** cursor: in a shared dirty store the
|
|
6
|
+
* cursor may already be past blocks containing a recovered account's notes,
|
|
7
|
+
* and a fresh store has no efficient path to them at all. This module
|
|
8
|
+
* rescans a historical block range with the account's standard note tag and
|
|
9
|
+
* imports what it finds with on-chain inclusion proofs, without ever
|
|
10
|
+
* touching the global sync height.
|
|
11
|
+
*/
|
|
12
|
+
import { AccountId, type Note } from '@miden-sdk/miden-sdk';
|
|
13
|
+
import { type NoteImportOutcome } from './proposalNoteImport.js';
|
|
14
|
+
import { type RawClientSource } from '../raw-client.js';
|
|
15
|
+
import { type RpcConfig } from '../rpc/config.js';
|
|
16
|
+
/**
|
|
17
|
+
* `RpcError::PaginationError`'s Display prefix in the WASM error chain: the
|
|
18
|
+
* node caps internal pagination per `syncNotes` request, and the scan splits
|
|
19
|
+
* the range client-side when it trips. Exported for the drift-guard test,
|
|
20
|
+
* which pins it against the shipped WASM binary.
|
|
21
|
+
*/
|
|
22
|
+
export declare const RPC_PAGINATION_FRAGMENT = "rpc pagination error";
|
|
23
|
+
/**
|
|
24
|
+
* The requested scan range is invalid (out-of-range bound, or inverted
|
|
25
|
+
* against the resolved chain tip) — a caller error that retrying cannot fix,
|
|
26
|
+
* as opposed to the transient chain-tip-lookup failures this function also
|
|
27
|
+
* throws. `Multisig.recoverNotes` keys its problem retryability on this,
|
|
28
|
+
* mirroring the Rust orchestrator's `InvalidConfig` check.
|
|
29
|
+
*/
|
|
30
|
+
export declare class BackfillRangeError extends Error {
|
|
31
|
+
}
|
|
32
|
+
/** Verdict of the static relevance screen. */
|
|
33
|
+
export type ScreenVerdict = 'relevant' | 'irrelevant' | 'unscreenable';
|
|
34
|
+
/**
|
|
35
|
+
* Static relevance screen for a discovered public note. The Rust SDK screens
|
|
36
|
+
* with the execution-based `NoteScreener` normal sync uses; the WASM surface
|
|
37
|
+
* does not expose it, so this mirrors its verdict for the well-known note
|
|
38
|
+
* scripts: a note is `relevant` when it is a P2ID/P2IDE note whose target
|
|
39
|
+
* (or P2IDE reclaimer) is the scanned account, and `irrelevant` when it is
|
|
40
|
+
* one of those scripts addressed at someone else. Notes with other scripts
|
|
41
|
+
* are `unscreenable` — this screen cannot judge them, and they are
|
|
42
|
+
* conservatively not imported (tags are shared, truncated filters, and
|
|
43
|
+
* importing unscreened tag matches would let anyone pollute the store), but
|
|
44
|
+
* the report counts them separately so "screened out" and "not screenable"
|
|
45
|
+
* stay distinguishable. Exported for the drift-guard test, which pins the
|
|
46
|
+
* root and storage-layout assumptions against real WASM-built notes.
|
|
47
|
+
*/
|
|
48
|
+
export declare function screenNoteForAccount(note: Note, account: AccountId): ScreenVerdict;
|
|
49
|
+
/** A contiguous block range, inclusive on both ends. */
|
|
50
|
+
export interface BlockRange {
|
|
51
|
+
/** First block of the range. */
|
|
52
|
+
from: number;
|
|
53
|
+
/** Last block of the range. */
|
|
54
|
+
to: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Result of {@link backfillPublicNotesByTag}.
|
|
58
|
+
*
|
|
59
|
+
* Scan problems are reported here rather than thrown so a partially failing
|
|
60
|
+
* scan never aborts the rest of a recovery flow: notes discovered in the
|
|
61
|
+
* covered ranges are imported regardless.
|
|
62
|
+
*/
|
|
63
|
+
export interface PublicBackfillReport {
|
|
64
|
+
/** First block of the requested scan range. */
|
|
65
|
+
scannedFrom: number;
|
|
66
|
+
/** Last block of the requested scan range. */
|
|
67
|
+
scannedTo: number;
|
|
68
|
+
/** Unique tag-matching notes the scan discovered, of every visibility. */
|
|
69
|
+
discovered: number;
|
|
70
|
+
/** Unique non-public matches skipped: the chain does not hold their
|
|
71
|
+
* bodies, so they cannot be rebuilt from a scan. Private notes are covered
|
|
72
|
+
* by the transport drain and proposal-import primitives instead. */
|
|
73
|
+
skippedPrivate: number;
|
|
74
|
+
/** Unique public matches the relevance screen rejected: tags are
|
|
75
|
+
* best-effort, truncated filters, so unrelated notes can carry this
|
|
76
|
+
* account's tag. Like normal sync, only notes the account could actually
|
|
77
|
+
* consume are imported; the rest are counted here. (This SDK screens
|
|
78
|
+
* statically against the well-known P2ID/P2IDE scripts; the Rust SDK uses
|
|
79
|
+
* the execution-based screener.) */
|
|
80
|
+
skippedIrrelevant: number;
|
|
81
|
+
/** Unique public matches this SDK's static screen could not judge (custom
|
|
82
|
+
* note scripts). They are conservatively not imported, but counted apart
|
|
83
|
+
* from `skippedIrrelevant` so callers can tell "screened out" from "not
|
|
84
|
+
* screenable". Always `0` in the Rust SDK, whose execution-based screener
|
|
85
|
+
* judges every note. */
|
|
86
|
+
skippedUnscreenable: number;
|
|
87
|
+
/** One outcome per unique public note that passed the relevance screen —
|
|
88
|
+
* `outcomes.length === discovered - skippedPrivate - skippedIrrelevant -
|
|
89
|
+
* skippedUnscreenable`. Screened-out, unscreenable, and private matches
|
|
90
|
+
* get no outcome, only their counters. */
|
|
91
|
+
outcomes: NoteImportOutcome[];
|
|
92
|
+
/** Sub-ranges of `[scannedFrom, scannedTo]` the scan could not cover (RPC
|
|
93
|
+
* failures, or the scan budget ran out while splitting around the node's
|
|
94
|
+
* pagination cap). Empty when the whole range was scanned. Notes committed
|
|
95
|
+
* in these ranges may be missing from `outcomes`. */
|
|
96
|
+
uncovered: BlockRange[];
|
|
97
|
+
/** Whether rerunning the backfill can plausibly improve the result: cover
|
|
98
|
+
* `uncovered` ranges, or retry outcomes whose own `retryable` flag is set.
|
|
99
|
+
* Always `false` when the scan fully covered the range and no outcome is
|
|
100
|
+
* retryable. */
|
|
101
|
+
retryable: boolean;
|
|
102
|
+
/** Human-readable cause when the scan did not cover the whole range. */
|
|
103
|
+
reason?: string;
|
|
104
|
+
}
|
|
105
|
+
export interface BackfillPublicNotesOptions {
|
|
106
|
+
/** Hex ID of the account whose standard note tag should be scanned. */
|
|
107
|
+
accountId: string;
|
|
108
|
+
/** Miden node RPC endpoint used for the scan and body fetches. Must point
|
|
109
|
+
* at the same network as the injected Miden client. */
|
|
110
|
+
midenRpcEndpoint: string;
|
|
111
|
+
/** First block of the scan range (default: genesis). */
|
|
112
|
+
fromBlock?: number;
|
|
113
|
+
/** Last block of the scan range (default: the current chain tip). */
|
|
114
|
+
toBlock?: number;
|
|
115
|
+
/** Node RPC read-retry configuration (defaults match the rest of the SDK). */
|
|
116
|
+
rpc?: RpcConfig;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Scans a historical block range for public notes addressed at an account's
|
|
120
|
+
* standard note tag and imports what it finds with their on-chain inclusion
|
|
121
|
+
* proofs. Counterpart of
|
|
122
|
+
* `MultisigClient::backfill_public_notes_by_tag` in the Rust SDK.
|
|
123
|
+
*
|
|
124
|
+
* Use after account recovery: normal forward sync starts from the store's
|
|
125
|
+
* **global** cursor, so in a shared dirty store the cursor may already be
|
|
126
|
+
* past blocks containing the recovered account's notes, and a fresh store
|
|
127
|
+
* would need to replay the whole chain state to see them. The scan is
|
|
128
|
+
* tag-scoped and its cost grows with the number of matching notes, not the
|
|
129
|
+
* range length, which makes genesis an acceptable default lower
|
|
130
|
+
* bound. The global sync height is never touched — run normal sync
|
|
131
|
+
* afterwards to verify the imported notes. The store must have synced at
|
|
132
|
+
* least once (`Multisig.recoverNotes` syncs the chain before this strategy
|
|
133
|
+
* runs): importing a proof into a store that has never seen the chain
|
|
134
|
+
* fails, and such failures surface as `failed` outcomes.
|
|
135
|
+
*
|
|
136
|
+
* Notes are discovered by tag only — a best-effort filter: notes sent with
|
|
137
|
+
* unrelated custom tags are outside this scan's guarantee, and, like normal
|
|
138
|
+
* sync, every new discovery is screened for relevance before import —
|
|
139
|
+
* tag-colliding notes the account cannot consume are counted as
|
|
140
|
+
* `skippedIrrelevant` instead of polluting the store. This SDK screens
|
|
141
|
+
* statically against the well-known P2ID/P2IDE scripts (the WASM surface
|
|
142
|
+
* does not expose the execution-based screener the Rust SDK uses), so notes
|
|
143
|
+
* with custom scripts are conservatively not imported and counted as
|
|
144
|
+
* `skippedUnscreenable`. Only public notes can be
|
|
145
|
+
* rebuilt from chain data; private matches are counted as `skippedPrivate`
|
|
146
|
+
* and are covered by the transport drain and proposal-import primitives
|
|
147
|
+
* instead.
|
|
148
|
+
*
|
|
149
|
+
* A range dense enough to trip the node's internal pagination cap is split
|
|
150
|
+
* client-side and rescanned as narrower requests; ranges that still cannot
|
|
151
|
+
* be covered are reported in {@link PublicBackfillReport.uncovered} rather
|
|
152
|
+
* than failing the recovery flow. This function throws only when the scan
|
|
153
|
+
* range itself cannot be established (chain-tip lookup failed, an invalid
|
|
154
|
+
* account ID, a block bound that is not a u32 integer, or
|
|
155
|
+
* `fromBlock > toBlock`).
|
|
156
|
+
*
|
|
157
|
+
* Prefer the `Multisig.backfillPublicNotesByTag` convenience method, which
|
|
158
|
+
* reuses the client's endpoint and retry configuration.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const report = await multisig.backfillPublicNotesByTag();
|
|
163
|
+
* console.log(report.discovered, 'discovered,', report.outcomes.length, 'public');
|
|
164
|
+
* await multisig.syncState(); // verifies the imported notes
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
export declare function backfillPublicNotesByTag(midenClient: RawClientSource, options: BackfillPublicNotesOptions): Promise<PublicBackfillReport>;
|
|
168
|
+
//# sourceMappingURL=publicNoteBackfill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publicNoteBackfill.d.ts","sourceRoot":"","sources":["../../src/recovery/publicNoteBackfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EACL,SAAS,EAIT,KAAK,IAAI,EAMV,MAAM,sBAAsB,CAAC;AAG9B,OAAO,EAKL,KAAK,iBAAiB,EAEvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAA8C,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACpG,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAKpE;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,yBAAyB,CAAC;AAc9D;;;;;;GAMG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;CAAG;AAUhD,8CAA8C;AAC9C,MAAM,MAAM,aAAa,GAAG,UAAU,GAAG,YAAY,GAAG,cAAc,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,GAAG,aAAa,CAmBlF;AAED,wDAAwD;AACxD,MAAM,WAAW,UAAU;IACzB,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,EAAE,EAAE,MAAM,CAAC;CACZ;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC;IACnB;;wEAEoE;IACpE,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;wCAKoC;IACpC,iBAAiB,EAAE,MAAM,CAAC;IAC1B;;;;4BAIwB;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B;;;8CAG0C;IAC1C,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B;;;yDAGqD;IACrD,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB;;;oBAGgB;IAChB,SAAS,EAAE,OAAO,CAAC;IACnB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB;2DACuD;IACvD,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,GAAG,CAAC,EAAE,SAAS,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,wBAAsB,wBAAwB,CAC5C,WAAW,EAAE,eAAe,EAC5B,OAAO,EAAE,0BAA0B,GAClC,OAAO,CAAC,oBAAoB,CAAC,CAsQ/B"}
|