@unlink-xyz/core 0.1.2 → 0.1.3-canary.0877bfe
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/dist/account/{zkAccount.d.ts → account.d.ts} +7 -5
- package/dist/account/account.d.ts.map +1 -0
- package/dist/account/{zkAccount.js → account.js} +57 -43
- package/dist/browser/index.js +108202 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/circuits.json +74 -0
- package/dist/clients/broadcaster.d.ts +7 -2
- package/dist/clients/broadcaster.d.ts.map +1 -1
- package/dist/clients/broadcaster.js +9 -1
- package/dist/clients/http.d.ts +6 -0
- package/dist/clients/http.d.ts.map +1 -1
- package/dist/clients/http.js +24 -9
- package/dist/clients/indexer.d.ts +11 -0
- package/dist/clients/indexer.d.ts.map +1 -1
- package/dist/clients/indexer.js +40 -11
- package/dist/config.d.ts +28 -9
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +33 -26
- package/dist/constants.d.ts +6 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +5 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +5 -2
- package/dist/crypto-adapters/auto-init.d.ts +2 -0
- package/dist/crypto-adapters/auto-init.d.ts.map +1 -0
- package/dist/crypto-adapters/auto-init.js +7 -0
- package/dist/crypto-adapters/index.d.ts +22 -0
- package/dist/crypto-adapters/index.d.ts.map +1 -0
- package/dist/crypto-adapters/index.js +47 -0
- package/dist/crypto-adapters/polyfills.d.ts +5 -0
- package/dist/crypto-adapters/polyfills.d.ts.map +1 -0
- package/dist/crypto-adapters/polyfills.js +8 -0
- package/dist/errors.d.ts +9 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +18 -0
- package/dist/history/index.d.ts +3 -0
- package/dist/history/index.d.ts.map +1 -0
- package/dist/history/index.js +2 -0
- package/dist/history/service.d.ts +46 -0
- package/dist/history/service.d.ts.map +1 -0
- package/dist/history/service.js +354 -0
- package/dist/history/types.d.ts +21 -0
- package/dist/history/types.d.ts.map +1 -0
- package/dist/index.d.ts +12 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -4
- package/dist/keys/address.d.ts +13 -0
- package/dist/keys/address.d.ts.map +1 -0
- package/dist/keys/address.js +55 -0
- package/dist/keys/derive.d.ts +37 -0
- package/dist/keys/derive.d.ts.map +1 -0
- package/dist/keys/derive.js +112 -0
- package/dist/keys/hex.d.ts +17 -0
- package/dist/keys/hex.d.ts.map +1 -0
- package/dist/keys/hex.js +66 -0
- package/dist/keys/index.d.ts +5 -0
- package/dist/keys/index.d.ts.map +1 -0
- package/dist/keys/index.js +4 -0
- package/dist/keys/mnemonic.d.ts +8 -0
- package/dist/keys/mnemonic.d.ts.map +1 -0
- package/dist/keys/mnemonic.js +23 -0
- package/dist/keys.d.ts +4 -1
- package/dist/keys.d.ts.map +1 -1
- package/dist/keys.js +4 -0
- package/dist/prover/config.d.ts +1 -15
- package/dist/prover/config.d.ts.map +1 -1
- package/dist/prover/config.js +1 -11
- package/dist/prover/prover.d.ts +15 -4
- package/dist/prover/prover.d.ts.map +1 -1
- package/dist/prover/prover.js +115 -98
- package/dist/prover/registry.d.ts +3 -30
- package/dist/prover/registry.d.ts.map +1 -1
- package/dist/prover/registry.js +12 -51
- package/dist/state/merkle/hydrator.d.ts.map +1 -1
- package/dist/state/merkle/hydrator.js +3 -2
- package/dist/state/merkle/index.d.ts +1 -1
- package/dist/state/merkle/index.d.ts.map +1 -1
- package/dist/state/merkle/index.js +1 -1
- package/dist/state/merkle/merkle-tree.d.ts +8 -0
- package/dist/state/merkle/merkle-tree.d.ts.map +1 -1
- package/dist/state/merkle/merkle-tree.js +16 -7
- package/dist/state/store/ciphertext-store.d.ts +4 -0
- package/dist/state/store/ciphertext-store.d.ts.map +1 -1
- package/dist/state/store/ciphertext-store.js +12 -0
- package/dist/state/store/history-store.d.ts +24 -0
- package/dist/state/store/history-store.d.ts.map +1 -0
- package/dist/state/store/history-store.js +53 -0
- package/dist/state/store/index.d.ts +3 -2
- package/dist/state/store/index.d.ts.map +1 -1
- package/dist/state/store/index.js +1 -0
- package/dist/state/store/job-store.d.ts +7 -7
- package/dist/state/store/job-store.d.ts.map +1 -1
- package/dist/state/store/job-store.js +65 -39
- package/dist/state/store/jobs.d.ts +65 -18
- package/dist/state/store/jobs.d.ts.map +1 -1
- package/dist/state/store/leaf-store.d.ts.map +1 -1
- package/dist/state/store/leaf-store.js +0 -3
- package/dist/state/store/note-store.d.ts +7 -7
- package/dist/state/store/note-store.d.ts.map +1 -1
- package/dist/state/store/note-store.js +38 -34
- package/dist/state/store/nullifier-store.d.ts +9 -0
- package/dist/state/store/nullifier-store.d.ts.map +1 -1
- package/dist/state/store/nullifier-store.js +32 -2
- package/dist/state/store/records.d.ts +31 -2
- package/dist/state/store/records.d.ts.map +1 -1
- package/dist/state/store/root-store.d.ts.map +1 -1
- package/dist/state/store/root-store.js +0 -4
- package/dist/state/store/store.d.ts +61 -27
- package/dist/state/store/store.d.ts.map +1 -1
- package/dist/state/store/store.js +92 -1
- package/dist/storage/indexeddb.js +1 -1
- package/dist/storage/memory.d.ts.map +1 -1
- package/dist/storage/memory.js +5 -1
- package/dist/transactions/deposit.d.ts +12 -15
- package/dist/transactions/deposit.d.ts.map +1 -1
- package/dist/transactions/deposit.js +203 -152
- package/dist/transactions/index.d.ts +7 -4
- package/dist/transactions/index.d.ts.map +1 -1
- package/dist/transactions/index.js +7 -2
- package/dist/transactions/note-selection.d.ts +17 -0
- package/dist/transactions/note-selection.d.ts.map +1 -0
- package/dist/transactions/note-selection.js +201 -0
- package/dist/transactions/note-sync.d.ts +5 -33
- package/dist/transactions/note-sync.d.ts.map +1 -1
- package/dist/transactions/note-sync.js +320 -155
- package/dist/transactions/reconcile.d.ts +10 -12
- package/dist/transactions/reconcile.d.ts.map +1 -1
- package/dist/transactions/reconcile.js +53 -7
- package/dist/transactions/transact.d.ts +13 -24
- package/dist/transactions/transact.d.ts.map +1 -1
- package/dist/transactions/transact.js +393 -507
- package/dist/transactions/transaction-planner.d.ts +34 -0
- package/dist/transactions/transaction-planner.d.ts.map +1 -0
- package/dist/transactions/transaction-planner.js +116 -0
- package/dist/transactions/transfer-planner.d.ts +36 -0
- package/dist/transactions/transfer-planner.d.ts.map +1 -0
- package/dist/transactions/transfer-planner.js +85 -0
- package/dist/transactions/types/deposit.d.ts +67 -0
- package/dist/transactions/types/deposit.d.ts.map +1 -0
- package/dist/transactions/types/domain.d.ts +67 -0
- package/dist/transactions/types/domain.d.ts.map +1 -0
- package/dist/transactions/types/domain.js +4 -0
- package/dist/transactions/types/index.d.ts +18 -0
- package/dist/transactions/types/index.d.ts.map +1 -0
- package/dist/transactions/types/index.js +17 -0
- package/dist/transactions/types/options.d.ts +45 -0
- package/dist/transactions/types/options.d.ts.map +1 -0
- package/dist/transactions/types/options.js +1 -0
- package/dist/transactions/types/planning.d.ts +80 -0
- package/dist/transactions/types/planning.d.ts.map +1 -0
- package/dist/transactions/types/planning.js +1 -0
- package/dist/transactions/types/state-stores.d.ts +103 -0
- package/dist/transactions/types/state-stores.d.ts.map +1 -0
- package/dist/transactions/types/state-stores.js +1 -0
- package/dist/transactions/types/transact.d.ts +76 -0
- package/dist/transactions/types/transact.d.ts.map +1 -0
- package/dist/transactions/types/transact.js +1 -0
- package/dist/transactions/withdrawal-planner.d.ts +58 -0
- package/dist/transactions/withdrawal-planner.d.ts.map +1 -0
- package/dist/transactions/withdrawal-planner.js +128 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/tsup.browser.config.d.ts +7 -0
- package/dist/tsup.browser.config.d.ts.map +1 -0
- package/dist/tsup.browser.config.js +34 -0
- package/dist/utils/amounts.d.ts +39 -0
- package/dist/utils/amounts.d.ts.map +1 -0
- package/dist/utils/amounts.js +89 -0
- package/dist/utils/async.d.ts +9 -0
- package/dist/utils/async.d.ts.map +1 -1
- package/dist/utils/async.js +24 -0
- package/dist/utils/bigint.js +7 -7
- package/dist/utils/crypto.d.ts +11 -5
- package/dist/utils/crypto.d.ts.map +1 -1
- package/dist/utils/crypto.js +12 -6
- package/dist/utils/format.d.ts +25 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +33 -0
- package/dist/utils/json-codec.js +1 -1
- package/dist/utils/notes.d.ts +15 -0
- package/dist/utils/notes.d.ts.map +1 -0
- package/dist/utils/notes.js +14 -0
- package/dist/utils/polling.d.ts +5 -0
- package/dist/utils/polling.d.ts.map +1 -1
- package/dist/utils/polling.js +5 -0
- package/dist/utils/random.d.ts +13 -0
- package/dist/utils/random.d.ts.map +1 -0
- package/dist/utils/random.js +27 -0
- package/dist/utils/secure-memory.d.ts +25 -0
- package/dist/utils/secure-memory.d.ts.map +1 -0
- package/dist/utils/secure-memory.js +28 -0
- package/dist/utils/signature.d.ts +6 -0
- package/dist/utils/signature.d.ts.map +1 -1
- package/dist/utils/signature.js +8 -6
- package/dist/utils/validators.d.ts +21 -10
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/utils/validators.js +37 -11
- package/dist/vitest.config.d.ts +3 -0
- package/dist/vitest.config.d.ts.map +1 -0
- package/dist/vitest.config.js +13 -0
- package/package.json +28 -11
- package/.eslintrc.json +0 -4
- package/account/zkAccount.test.ts +0 -316
- package/account/zkAccount.ts +0 -222
- package/clients/broadcaster.ts +0 -67
- package/clients/http.ts +0 -94
- package/clients/indexer.ts +0 -150
- package/config.ts +0 -39
- package/core.ts +0 -17
- package/dist/account/railgun-imports-prototype.d.ts +0 -12
- package/dist/account/railgun-imports-prototype.d.ts.map +0 -1
- package/dist/account/railgun-imports-prototype.js +0 -30
- package/dist/account/zkAccount.d.ts.map +0 -1
- package/dist/key-derivation/babyjubjub.d.ts +0 -9
- package/dist/key-derivation/babyjubjub.d.ts.map +0 -1
- package/dist/key-derivation/babyjubjub.js +0 -9
- package/dist/key-derivation/bech32.d.ts +0 -22
- package/dist/key-derivation/bech32.d.ts.map +0 -1
- package/dist/key-derivation/bech32.js +0 -86
- package/dist/key-derivation/bip32.d.ts +0 -17
- package/dist/key-derivation/bip32.d.ts.map +0 -1
- package/dist/key-derivation/bip32.js +0 -41
- package/dist/key-derivation/bip39.d.ts +0 -22
- package/dist/key-derivation/bip39.d.ts.map +0 -1
- package/dist/key-derivation/bip39.js +0 -56
- package/dist/key-derivation/bytes.d.ts +0 -19
- package/dist/key-derivation/bytes.d.ts.map +0 -1
- package/dist/key-derivation/bytes.js +0 -92
- package/dist/key-derivation/hash.d.ts +0 -3
- package/dist/key-derivation/hash.d.ts.map +0 -1
- package/dist/key-derivation/hash.js +0 -10
- package/dist/key-derivation/index.d.ts +0 -8
- package/dist/key-derivation/index.d.ts.map +0 -1
- package/dist/key-derivation/index.js +0 -7
- package/dist/key-derivation/wallet-node.d.ts +0 -45
- package/dist/key-derivation/wallet-node.d.ts.map +0 -1
- package/dist/key-derivation/wallet-node.js +0 -109
- package/dist/state/ciphertext-store.d.ts +0 -12
- package/dist/state/ciphertext-store.d.ts.map +0 -1
- package/dist/state/ciphertext-store.js +0 -25
- package/dist/state/hydrator.d.ts +0 -16
- package/dist/state/hydrator.d.ts.map +0 -1
- package/dist/state/hydrator.js +0 -18
- package/dist/state/job-store.d.ts +0 -12
- package/dist/state/job-store.d.ts.map +0 -1
- package/dist/state/job-store.js +0 -118
- package/dist/state/jobs.d.ts +0 -50
- package/dist/state/jobs.d.ts.map +0 -1
- package/dist/state/jobs.js +0 -1
- package/dist/state/leaf-store.d.ts +0 -17
- package/dist/state/leaf-store.d.ts.map +0 -1
- package/dist/state/leaf-store.js +0 -35
- package/dist/state/merkle-tree.d.ts +0 -34
- package/dist/state/merkle-tree.d.ts.map +0 -1
- package/dist/state/merkle-tree.js +0 -104
- package/dist/state/note-store.d.ts +0 -37
- package/dist/state/note-store.d.ts.map +0 -1
- package/dist/state/note-store.js +0 -133
- package/dist/state/nullifier-store.d.ts +0 -13
- package/dist/state/nullifier-store.d.ts.map +0 -1
- package/dist/state/nullifier-store.js +0 -21
- package/dist/state/records.d.ts +0 -57
- package/dist/state/records.d.ts.map +0 -1
- package/dist/state/root-store.d.ts +0 -13
- package/dist/state/root-store.d.ts.map +0 -1
- package/dist/state/root-store.js +0 -30
- package/dist/state/store.d.ts +0 -26
- package/dist/state/store.d.ts.map +0 -1
- package/dist/state/store.js +0 -19
- package/dist/state.d.ts +0 -83
- package/dist/state.d.ts.map +0 -1
- package/dist/state.js +0 -171
- package/dist/transactions/shield.d.ts +0 -5
- package/dist/transactions/shield.d.ts.map +0 -1
- package/dist/transactions/shield.js +0 -93
- package/dist/transactions/types.d.ts +0 -114
- package/dist/transactions/types.d.ts.map +0 -1
- package/dist/transactions/utils.d.ts +0 -10
- package/dist/transactions/utils.d.ts.map +0 -1
- package/dist/transactions/utils.js +0 -17
- package/dist/utils/time.d.ts +0 -2
- package/dist/utils/time.d.ts.map +0 -1
- package/dist/utils/time.js +0 -3
- package/dist/utils/witness.d.ts +0 -11
- package/dist/utils/witness.d.ts.map +0 -1
- package/dist/utils/witness.js +0 -19
- package/errors.ts +0 -20
- package/index.ts +0 -17
- package/key-derivation/babyjubjub.ts +0 -11
- package/key-derivation/bech32.test.ts +0 -90
- package/key-derivation/bech32.ts +0 -124
- package/key-derivation/bip32.ts +0 -56
- package/key-derivation/bip39.ts +0 -76
- package/key-derivation/bytes.ts +0 -118
- package/key-derivation/hash.ts +0 -13
- package/key-derivation/index.ts +0 -7
- package/key-derivation/wallet-node.ts +0 -155
- package/keys.ts +0 -47
- package/prover/config.ts +0 -104
- package/prover/index.ts +0 -1
- package/prover/prover.integration.test.ts +0 -162
- package/prover/prover.test.ts +0 -309
- package/prover/prover.ts +0 -405
- package/prover/registry.test.ts +0 -90
- package/prover/registry.ts +0 -82
- package/schema.ts +0 -17
- package/setup-artifacts.sh +0 -57
- package/state/index.ts +0 -2
- package/state/merkle/hydrator.ts +0 -69
- package/state/merkle/index.ts +0 -12
- package/state/merkle/merkle-tree.test.ts +0 -50
- package/state/merkle/merkle-tree.ts +0 -163
- package/state/store/ciphertext-store.ts +0 -28
- package/state/store/index.ts +0 -24
- package/state/store/job-store.ts +0 -162
- package/state/store/jobs.ts +0 -64
- package/state/store/leaf-store.ts +0 -39
- package/state/store/note-store.ts +0 -177
- package/state/store/nullifier-store.ts +0 -39
- package/state/store/records.ts +0 -61
- package/state/store/root-store.ts +0 -34
- package/state/store/store.ts +0 -25
- package/state.test.ts +0 -235
- package/storage/index.ts +0 -3
- package/storage/indexeddb.test.ts +0 -99
- package/storage/indexeddb.ts +0 -235
- package/storage/memory.test.ts +0 -59
- package/storage/memory.ts +0 -93
- package/transactions/deposit.test.ts +0 -160
- package/transactions/deposit.ts +0 -227
- package/transactions/index.ts +0 -20
- package/transactions/note-sync.test.ts +0 -155
- package/transactions/note-sync.ts +0 -452
- package/transactions/reconcile.ts +0 -73
- package/transactions/transact.test.ts +0 -451
- package/transactions/transact.ts +0 -811
- package/transactions/types.ts +0 -141
- package/tsconfig.json +0 -14
- package/types/global.d.ts +0 -15
- package/types.ts +0 -24
- package/utils/async.ts +0 -15
- package/utils/bigint.ts +0 -34
- package/utils/crypto.test.ts +0 -69
- package/utils/crypto.ts +0 -58
- package/utils/json-codec.ts +0 -38
- package/utils/polling.ts +0 -6
- package/utils/signature.ts +0 -16
- package/utils/validators.test.ts +0 -64
- package/utils/validators.ts +0 -86
- /package/dist/{transactions → history}/types.js +0 -0
- /package/dist/{state/records.js → transactions/types/deposit.js} +0 -0
|
@@ -1,46 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
|
|
4
|
-
import { type LeafRecord, type LocalMerkleTrees, type NoteRecord, type RootRecord } from "../state/index.js";
|
|
5
|
-
export type NoteSyncStateStore = {
|
|
6
|
-
putLeaf(record: LeafRecord): Promise<void>;
|
|
7
|
-
getLeaf(chainId: number, index: number): Promise<LeafRecord | null>;
|
|
8
|
-
clearLeaves(chainId: number): Promise<void>;
|
|
9
|
-
putRoot(record: RootRecord): Promise<void>;
|
|
10
|
-
putNote(record: NoteRecord): Promise<void>;
|
|
11
|
-
getNote(chainId: number, index: number): Promise<NoteRecord | null>;
|
|
12
|
-
markNoteSpent(chainId: number, index: number, spentAt?: number): Promise<NoteRecord>;
|
|
13
|
-
putCiphertext(chainId: number, index: number, payload: Uint8Array): Promise<void>;
|
|
14
|
-
countNullifiers(chainId: number): Promise<number>;
|
|
15
|
-
putNullifier(record: {
|
|
16
|
-
chainId: number;
|
|
17
|
-
nullifier: string;
|
|
18
|
-
noteIndex?: number;
|
|
19
|
-
}): Promise<void>;
|
|
20
|
-
};
|
|
21
|
-
export type NoteSyncOptions = {
|
|
22
|
-
merkleTrees?: LocalMerkleTrees;
|
|
23
|
-
indexerClient?: ReturnType<typeof createIndexerClient>;
|
|
24
|
-
fetch?: FetchLike;
|
|
25
|
-
limit?: number;
|
|
26
|
-
};
|
|
1
|
+
import type { Account } from "../account/account.js";
|
|
2
|
+
import type { NoteSyncOptions, NoteSyncStateStore } from "./types/index.js";
|
|
3
|
+
export type { NoteSyncOptions, NoteSyncStateStore };
|
|
27
4
|
type ChainSyncStatus = {
|
|
28
5
|
inFlight: boolean;
|
|
29
6
|
lastSuccess: number | null;
|
|
30
7
|
lastError?: string;
|
|
31
8
|
};
|
|
32
9
|
export declare function createNoteSyncService(stateStore: NoteSyncStateStore, options?: NoteSyncOptions): {
|
|
33
|
-
|
|
34
|
-
start?: number;
|
|
35
|
-
forceFullScan?: boolean;
|
|
36
|
-
}) => Promise<NoteRecord[]>;
|
|
37
|
-
syncChain: (chainId: number, account: ZkAccount, opts?: {
|
|
10
|
+
syncChain: (chainId: number, account: Account, opts?: {
|
|
38
11
|
forceFullResync?: boolean;
|
|
39
12
|
}) => Promise<void>;
|
|
40
|
-
syncChains: (chainIds: number[], account:
|
|
13
|
+
syncChains: (chainIds: number[], account: Account, opts?: {
|
|
41
14
|
forceFullResync?: boolean;
|
|
42
15
|
}) => Promise<void>;
|
|
43
16
|
getStatus: () => Map<number, ChainSyncStatus>;
|
|
44
17
|
};
|
|
45
|
-
export {};
|
|
46
18
|
//# sourceMappingURL=note-sync.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"note-sync.d.ts","sourceRoot":"","sources":["../../transactions/note-sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"note-sync.d.ts","sourceRoot":"","sources":["../../transactions/note-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAkBrD,OAAO,KAAK,EAEV,eAAe,EACf,kBAAkB,EACnB,MAAM,kBAAkB,CAAC;AAI1B,YAAY,EAAE,eAAe,EAAE,kBAAkB,EAAE,CAAC;AAEpD,KAAK,eAAe,GAAG;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAqBF,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,kBAAkB,EAC9B,OAAO,GAAE,eAAoB;yBA8elB,MAAM,WACN,OAAO,SACV;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,KAClC,OAAO,CAAC,IAAI,CAAC;2BA6FJ,MAAM,EAAE,WACT,OAAO,SACT;QAAE,eAAe,CAAC,EAAE,OAAO,CAAA;KAAE,KACnC,OAAO,CAAC,IAAI,CAAC;;EAejB"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { poseidon } from "@railgun-community/circomlibjs";
|
|
2
1
|
import { createIndexerClient } from "../clients/indexer.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { createServiceConfig } from "../config.js";
|
|
3
|
+
import { poseidon } from "../crypto-adapters/index.js";
|
|
4
|
+
import { CoreError, InitializationError } from "../errors.js";
|
|
5
|
+
import { FieldSize, Hex } from "../keys/hex.js";
|
|
6
6
|
import { createMerkleTrees, rebuildTreeFromStore, } from "../state/index.js";
|
|
7
7
|
import { formatUint256, parseHexToBigInt } from "../utils/bigint.js";
|
|
8
8
|
import { decryptNote } from "../utils/crypto.js";
|
|
@@ -18,10 +18,10 @@ function buildCiphertext(bytes) {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
function encodeCiphertext(ciphertext) {
|
|
21
|
-
const payload = new Uint8Array(
|
|
21
|
+
const payload = new Uint8Array(FieldSize.SCALAR * ciphertext.data.length);
|
|
22
22
|
ciphertext.data.forEach((value, index) => {
|
|
23
|
-
const start = index *
|
|
24
|
-
payload.set(
|
|
23
|
+
const start = index * FieldSize.SCALAR;
|
|
24
|
+
payload.set(Hex.toBytes(formatUint256(value)), start);
|
|
25
25
|
});
|
|
26
26
|
return payload;
|
|
27
27
|
}
|
|
@@ -34,22 +34,18 @@ export function createNoteSyncService(stateStore, options = {}) {
|
|
|
34
34
|
if (!indexerClient) {
|
|
35
35
|
const fetchImpl = options.fetch ?? (typeof fetch === "function" ? fetch : undefined);
|
|
36
36
|
if (!fetchImpl) {
|
|
37
|
-
throw new
|
|
37
|
+
throw new InitializationError("fetch dependency is required to sync indexer commitments");
|
|
38
38
|
}
|
|
39
|
+
if (!options.rpcUrl) {
|
|
40
|
+
throw new InitializationError("rpcUrl is required to sync indexer commitments");
|
|
41
|
+
}
|
|
42
|
+
const serviceConfig = createServiceConfig(options.rpcUrl);
|
|
39
43
|
indexerClient = createIndexerClient(serviceConfig.indexerBaseUrl, {
|
|
40
44
|
fetch: fetchImpl,
|
|
41
45
|
});
|
|
42
46
|
}
|
|
43
|
-
// Count-based optimization: avoid per-nullifier lookups when counts are unchanged
|
|
44
|
-
async function shouldQueryNullifiers(chainId) {
|
|
45
|
-
const [onChainCount, localCount] = await Promise.all([
|
|
46
|
-
indexerClient.getNullifierCount(chainId),
|
|
47
|
-
stateStore.countNullifiers(chainId),
|
|
48
|
-
]);
|
|
49
|
-
return onChainCount !== localCount;
|
|
50
|
-
}
|
|
51
47
|
function createNoteRecord(params) {
|
|
52
|
-
const { chainId, index, commitment, token, amount, npk, mpk, random, nullifier, spentAt } = params;
|
|
48
|
+
const { chainId, index, commitment, token, amount, npk, mpk, random, nullifier, createdTxHash, createdEventType, createdAt, spentAt, spentTxHash, } = params;
|
|
53
49
|
const base = {
|
|
54
50
|
chainId,
|
|
55
51
|
index,
|
|
@@ -60,26 +56,15 @@ export function createNoteSyncService(stateStore, options = {}) {
|
|
|
60
56
|
mpk: formatUint256(mpk),
|
|
61
57
|
random: formatUint256(random),
|
|
62
58
|
nullifier,
|
|
59
|
+
createdTxHash,
|
|
60
|
+
createdEventType,
|
|
61
|
+
createdAt,
|
|
62
|
+
spentTxHash,
|
|
63
63
|
};
|
|
64
64
|
return spentAt === undefined ? base : { ...base, spentAt };
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
const currentLeafCount = trees.getLeafCount(chainId);
|
|
69
|
-
if (record.index >= currentLeafCount) {
|
|
70
|
-
const { index } = trees.addLeaf(chainId, value);
|
|
71
|
-
if (index !== record.index && !allowRelaxedOrder) {
|
|
72
|
-
throw new CoreError("indexed commitments out of order");
|
|
73
|
-
}
|
|
74
|
-
await stateStore.putLeaf({
|
|
75
|
-
chainId,
|
|
76
|
-
index: record.index,
|
|
77
|
-
commitment: record.commitment,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
await stateStore.putRoot({ chainId, root: record.root });
|
|
81
|
-
}
|
|
82
|
-
async function tryStoreNote(chainId, record, account, shouldCheckNullifiers) {
|
|
66
|
+
// Try to decrypt a note. Returns the note record if successful, null otherwise.
|
|
67
|
+
function tryDecryptNoteRecord(chainId, record, account) {
|
|
83
68
|
const ciphertext = buildCiphertext(record.ciphertext);
|
|
84
69
|
let note;
|
|
85
70
|
try {
|
|
@@ -101,9 +86,7 @@ export function createNoteSyncService(stateStore, options = {}) {
|
|
|
101
86
|
}
|
|
102
87
|
const nullifier = poseidon([account.nullifyingKey, BigInt(record.index)]);
|
|
103
88
|
const nullifierHex = formatUint256(nullifier);
|
|
104
|
-
|
|
105
|
-
await stateStore.putCiphertext(chainId, record.index, ciphertextBytes);
|
|
106
|
-
const baseNoteParams = {
|
|
89
|
+
return createNoteRecord({
|
|
107
90
|
chainId,
|
|
108
91
|
index: record.index,
|
|
109
92
|
commitment: record.commitment,
|
|
@@ -113,65 +96,14 @@ export function createNoteSyncService(stateStore, options = {}) {
|
|
|
113
96
|
mpk: account.masterPublicKey,
|
|
114
97
|
random,
|
|
115
98
|
nullifier: nullifierHex,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// If note is already marked as spent locally, don't query indexer
|
|
120
|
-
// to ask for nullifier because we already know it's spent
|
|
121
|
-
if (existingNote?.spentAt !== undefined) {
|
|
122
|
-
// Ensure nullifier is stored for count optimization (idempotent)
|
|
123
|
-
await stateStore.putNullifier({
|
|
124
|
-
chainId,
|
|
125
|
-
nullifier: nullifierHex,
|
|
126
|
-
noteIndex: record.index,
|
|
127
|
-
});
|
|
128
|
-
return existingNote;
|
|
129
|
-
}
|
|
130
|
-
// Skip indexer nullifier query if nullifier counts match
|
|
131
|
-
if (!shouldCheckNullifiers) {
|
|
132
|
-
if (existingNote) {
|
|
133
|
-
return existingNote;
|
|
134
|
-
}
|
|
135
|
-
const stored = createNoteRecord(baseNoteParams);
|
|
136
|
-
await stateStore.putNote(stored);
|
|
137
|
-
return stored;
|
|
138
|
-
}
|
|
139
|
-
// Counts mismatched: query individual nullifier to check if this note was spent
|
|
140
|
-
const onChainNullifier = await indexerClient.getNullifier({
|
|
141
|
-
chainId,
|
|
142
|
-
nullifier: nullifierHex,
|
|
99
|
+
createdTxHash: record.txHash,
|
|
100
|
+
createdEventType: record.eventType,
|
|
101
|
+
createdAt: record.insertedAt != null ? record.insertedAt * 1000 : undefined,
|
|
143
102
|
});
|
|
144
|
-
if (onChainNullifier) {
|
|
145
|
-
const spentAtMs = onChainNullifier.spentAt * 1000;
|
|
146
|
-
// Store nullifier
|
|
147
|
-
await stateStore.putNullifier({
|
|
148
|
-
chainId,
|
|
149
|
-
nullifier: nullifierHex,
|
|
150
|
-
noteIndex: record.index,
|
|
151
|
-
});
|
|
152
|
-
if (existingNote) {
|
|
153
|
-
// Update existing unspent note to mark as spent
|
|
154
|
-
await stateStore.markNoteSpent(chainId, record.index, spentAtMs);
|
|
155
|
-
return existingNote;
|
|
156
|
-
}
|
|
157
|
-
const stored = createNoteRecord({
|
|
158
|
-
...baseNoteParams,
|
|
159
|
-
spentAt: spentAtMs,
|
|
160
|
-
});
|
|
161
|
-
await stateStore.putNote(stored);
|
|
162
|
-
return stored;
|
|
163
|
-
}
|
|
164
|
-
// Skip re-storing unspent notes that already exist
|
|
165
|
-
if (existingNote) {
|
|
166
|
-
return existingNote;
|
|
167
|
-
}
|
|
168
|
-
const stored = createNoteRecord(baseNoteParams);
|
|
169
|
-
await stateStore.putNote(stored);
|
|
170
|
-
return stored;
|
|
171
103
|
}
|
|
172
|
-
// Pulls commitments from the indexer
|
|
104
|
+
// Pulls commitments from the indexer, updating local tree and notes atomically.
|
|
105
|
+
// Uses batch nullifier check to avoid individual 404-generating queries.
|
|
173
106
|
async function ingestFrom(chainId, start, account) {
|
|
174
|
-
const shouldCheckNullifiers = await shouldQueryNullifiers(chainId);
|
|
175
107
|
let cursor = start;
|
|
176
108
|
for (;;) {
|
|
177
109
|
const batch = await indexerClient.fetchCommitmentBatch({
|
|
@@ -182,40 +114,276 @@ export function createNoteSyncService(stateStore, options = {}) {
|
|
|
182
114
|
if (batch.commitments.length === 0) {
|
|
183
115
|
break;
|
|
184
116
|
}
|
|
117
|
+
// Phase 1: Ingest commitments into tree + store
|
|
118
|
+
const decryptedNotes = [];
|
|
185
119
|
for (const record of batch.commitments) {
|
|
186
120
|
const expectedIndex = trees.getLeafCount(chainId);
|
|
187
121
|
if (record.index !== expectedIndex) {
|
|
188
|
-
throw new
|
|
122
|
+
throw new CoreError(`indexed commitments out of order: expected index ${expectedIndex}, got ${record.index} (cursor=${cursor})`);
|
|
189
123
|
}
|
|
190
|
-
const value =
|
|
124
|
+
const value = Hex.toBigInt(record.commitment);
|
|
191
125
|
const { index } = trees.addLeaf(chainId, value);
|
|
192
126
|
if (index !== record.index) {
|
|
193
|
-
throw new
|
|
127
|
+
throw new CoreError("local merkle tree desynchronized");
|
|
194
128
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
129
|
+
const noteRecord = tryDecryptNoteRecord(chainId, record, account);
|
|
130
|
+
const ciphertext = buildCiphertext(record.ciphertext);
|
|
131
|
+
const ciphertextBytes = encodeCiphertext(ciphertext);
|
|
132
|
+
await stateStore.syncCommitment({
|
|
133
|
+
leaf: {
|
|
134
|
+
chainId,
|
|
135
|
+
index: record.index,
|
|
136
|
+
commitment: record.commitment,
|
|
137
|
+
txHash: record.txHash,
|
|
138
|
+
eventType: record.eventType,
|
|
139
|
+
insertedAt: record.insertedAt,
|
|
140
|
+
},
|
|
141
|
+
ciphertext: {
|
|
142
|
+
chainId,
|
|
143
|
+
index: record.index,
|
|
144
|
+
payload: ciphertextBytes,
|
|
145
|
+
},
|
|
146
|
+
root: { chainId, root: record.root },
|
|
147
|
+
note: noteRecord ?? undefined,
|
|
199
148
|
});
|
|
200
|
-
|
|
201
|
-
|
|
149
|
+
if (noteRecord) {
|
|
150
|
+
decryptedNotes.push(noteRecord);
|
|
151
|
+
}
|
|
202
152
|
cursor = record.index + 1;
|
|
203
153
|
}
|
|
204
|
-
|
|
205
|
-
|
|
154
|
+
// Phase 2: Batch nullifier check for decrypted notes
|
|
155
|
+
if (decryptedNotes.length > 0) {
|
|
156
|
+
const notesToCheck = [];
|
|
157
|
+
for (const note of decryptedNotes) {
|
|
158
|
+
const existing = await stateStore.getNote(chainId, note.index);
|
|
159
|
+
if (existing?.spentAt !== undefined) {
|
|
160
|
+
await stateStore.putNullifier({
|
|
161
|
+
chainId,
|
|
162
|
+
nullifier: note.nullifier,
|
|
163
|
+
noteIndex: note.index,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
notesToCheck.push(note);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (notesToCheck.length > 0) {
|
|
171
|
+
const spentNullifiers = await indexerClient.checkNullifiers({
|
|
172
|
+
chainId,
|
|
173
|
+
nullifiers: notesToCheck.map((n) => n.nullifier),
|
|
174
|
+
});
|
|
175
|
+
const spentMap = new Map(spentNullifiers.map((n) => [n.nullifier, n]));
|
|
176
|
+
for (const note of notesToCheck) {
|
|
177
|
+
const spent = spentMap.get(note.nullifier);
|
|
178
|
+
if (spent) {
|
|
179
|
+
const spentAtMs = spent.spentAt * 1000;
|
|
180
|
+
await stateStore.putNullifier({
|
|
181
|
+
chainId,
|
|
182
|
+
nullifier: note.nullifier,
|
|
183
|
+
noteIndex: note.index,
|
|
184
|
+
});
|
|
185
|
+
await stateStore.markNoteSpent(chainId, note.index, spentAtMs, spent.txHash);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
async function diagnoseChainState(chainId, localCount) {
|
|
193
|
+
// Tier 1: compare first commitment
|
|
194
|
+
const firstBatch = await indexerClient.fetchCommitmentBatch({
|
|
195
|
+
chainId,
|
|
196
|
+
start: 0,
|
|
197
|
+
limit: 1,
|
|
198
|
+
});
|
|
199
|
+
const localFirst = await stateStore.getLeaf(chainId, 0);
|
|
200
|
+
if (firstBatch.commitments.length === 0 || !localFirst) {
|
|
201
|
+
return { kind: "full-divergence" };
|
|
202
|
+
}
|
|
203
|
+
if (firstBatch.commitments[0].commitment !== localFirst.commitment) {
|
|
204
|
+
return { kind: "full-divergence" };
|
|
205
|
+
}
|
|
206
|
+
// Single-leaf shortcut: first matches and there's only one local leaf.
|
|
207
|
+
if (localCount === 1) {
|
|
208
|
+
return { kind: "consistent" };
|
|
209
|
+
}
|
|
210
|
+
// Compare last local commitment
|
|
211
|
+
const lastBatch = await indexerClient.fetchCommitmentBatch({
|
|
212
|
+
chainId,
|
|
213
|
+
start: localCount - 1,
|
|
214
|
+
limit: 1,
|
|
215
|
+
});
|
|
216
|
+
const localLast = await stateStore.getLeaf(chainId, localCount - 1);
|
|
217
|
+
if (lastBatch.commitments.length > 0 &&
|
|
218
|
+
localLast &&
|
|
219
|
+
lastBatch.commitments[0].commitment === localLast.commitment) {
|
|
220
|
+
return { kind: "consistent" };
|
|
221
|
+
}
|
|
222
|
+
// Tier 2: binary search for divergence point
|
|
223
|
+
const divergePoint = await findDivergencePoint(chainId, 1, localCount - 1);
|
|
224
|
+
return { kind: "partial-divergence", validPrefix: divergePoint };
|
|
225
|
+
}
|
|
226
|
+
async function findDivergencePoint(chainId, low, high) {
|
|
227
|
+
while (low < high) {
|
|
228
|
+
const mid = Math.floor((low + high) / 2);
|
|
229
|
+
const batch = await indexerClient.fetchCommitmentBatch({
|
|
230
|
+
chainId,
|
|
231
|
+
start: mid,
|
|
232
|
+
limit: 1,
|
|
233
|
+
});
|
|
234
|
+
const localLeaf = await stateStore.getLeaf(chainId, mid);
|
|
235
|
+
if (batch.commitments.length > 0 &&
|
|
236
|
+
localLeaf &&
|
|
237
|
+
batch.commitments[0].commitment === localLeaf.commitment) {
|
|
238
|
+
low = mid + 1;
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
high = mid;
|
|
206
242
|
}
|
|
207
243
|
}
|
|
244
|
+
return low;
|
|
245
|
+
}
|
|
246
|
+
// Clears stale tail data and re-ingests from the divergence point.
|
|
247
|
+
async function partialResync(chainId, fromIndex, account) {
|
|
248
|
+
await Promise.all([
|
|
249
|
+
stateStore.clearChainDataFromIndex(chainId, fromIndex),
|
|
250
|
+
stateStore.clearNullifiersFromIndex(chainId, fromIndex),
|
|
251
|
+
]);
|
|
252
|
+
trees.reset(chainId);
|
|
253
|
+
await rebuildTreeFromStore({
|
|
254
|
+
chainId,
|
|
255
|
+
trees,
|
|
256
|
+
loadLeaf: stateStore.getLeaf.bind(stateStore),
|
|
257
|
+
});
|
|
258
|
+
await ingestFrom(chainId, fromIndex, account);
|
|
208
259
|
}
|
|
209
260
|
// Clears local state for a chain and rehydrates fully from the indexer.
|
|
210
261
|
async function fullResync(chainId, account) {
|
|
211
262
|
trees.reset(chainId);
|
|
212
|
-
await
|
|
263
|
+
await Promise.all([
|
|
264
|
+
stateStore.clearLeaves(chainId),
|
|
265
|
+
stateStore.clearNotes(chainId),
|
|
266
|
+
stateStore.clearCiphertexts(chainId),
|
|
267
|
+
stateStore.clearNullifiers(chainId),
|
|
268
|
+
]);
|
|
213
269
|
await ingestFrom(chainId, 0, account);
|
|
214
270
|
}
|
|
271
|
+
// Decode a stored ciphertext (3 x 32-byte values) into a Ciphertext object
|
|
272
|
+
function decodeCiphertext(payload) {
|
|
273
|
+
const data = [];
|
|
274
|
+
for (let i = 0; i < 3; i++) {
|
|
275
|
+
const start = i * FieldSize.SCALAR;
|
|
276
|
+
const end = start + FieldSize.SCALAR;
|
|
277
|
+
const slice = payload.slice(start, end);
|
|
278
|
+
data.push(Hex.toBigInt(Hex.fromBytes(slice)));
|
|
279
|
+
}
|
|
280
|
+
return { data: data };
|
|
281
|
+
}
|
|
282
|
+
// Re-scan stored ciphertexts for a new account, using batch nullifier check.
|
|
283
|
+
async function rescanCiphertextsForAccount(chainId, account, leafCount) {
|
|
284
|
+
const accountMpk = formatUint256(account.masterPublicKey);
|
|
285
|
+
const pendingNotes = [];
|
|
286
|
+
for (let index = 0; index < leafCount; index++) {
|
|
287
|
+
const existingNote = await stateStore.getNote(chainId, index);
|
|
288
|
+
if (existingNote && existingNote.mpk === accountMpk) {
|
|
289
|
+
continue;
|
|
290
|
+
}
|
|
291
|
+
const ciphertextBytes = await stateStore.getCiphertext(chainId, index);
|
|
292
|
+
if (!ciphertextBytes)
|
|
293
|
+
continue;
|
|
294
|
+
const leaf = await stateStore.getLeaf(chainId, index);
|
|
295
|
+
if (!leaf)
|
|
296
|
+
continue;
|
|
297
|
+
const ciphertext = decodeCiphertext(ciphertextBytes);
|
|
298
|
+
let note;
|
|
299
|
+
try {
|
|
300
|
+
note = decryptNote(ciphertext, account.masterPublicKey);
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
if (err instanceof CoreError)
|
|
304
|
+
continue;
|
|
305
|
+
throw err;
|
|
306
|
+
}
|
|
307
|
+
const npk = poseidon([account.masterPublicKey, note.random]);
|
|
308
|
+
const commitment = poseidon([npk, BigInt(note.token), note.amount]);
|
|
309
|
+
if (commitment !== parseHexToBigInt(leaf.commitment))
|
|
310
|
+
continue;
|
|
311
|
+
const nullifier = poseidon([account.nullifyingKey, BigInt(index)]);
|
|
312
|
+
const nullifierHex = formatUint256(nullifier);
|
|
313
|
+
const baseNoteParams = {
|
|
314
|
+
chainId,
|
|
315
|
+
index,
|
|
316
|
+
commitment: leaf.commitment,
|
|
317
|
+
token: note.token,
|
|
318
|
+
amount: note.amount,
|
|
319
|
+
npk,
|
|
320
|
+
mpk: account.masterPublicKey,
|
|
321
|
+
random: note.random,
|
|
322
|
+
nullifier: nullifierHex,
|
|
323
|
+
createdTxHash: leaf.txHash,
|
|
324
|
+
createdEventType: leaf.eventType,
|
|
325
|
+
createdAt: leaf.insertedAt != null ? leaf.insertedAt * 1000 : undefined,
|
|
326
|
+
};
|
|
327
|
+
pendingNotes.push({
|
|
328
|
+
note: createNoteRecord(baseNoteParams),
|
|
329
|
+
baseParams: baseNoteParams,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
if (pendingNotes.length > 0) {
|
|
333
|
+
const spentNullifiers = await indexerClient.checkNullifiers({
|
|
334
|
+
chainId,
|
|
335
|
+
nullifiers: pendingNotes.map((p) => p.note.nullifier),
|
|
336
|
+
});
|
|
337
|
+
const spentMap = new Map(spentNullifiers.map((n) => [n.nullifier, n]));
|
|
338
|
+
for (const { note, baseParams } of pendingNotes) {
|
|
339
|
+
const spent = spentMap.get(note.nullifier);
|
|
340
|
+
if (spent) {
|
|
341
|
+
await stateStore.putNullifier({
|
|
342
|
+
chainId,
|
|
343
|
+
nullifier: note.nullifier,
|
|
344
|
+
noteIndex: note.index,
|
|
345
|
+
});
|
|
346
|
+
await stateStore.putNote(createNoteRecord({
|
|
347
|
+
...baseParams,
|
|
348
|
+
spentAt: spent.spentAt * 1000,
|
|
349
|
+
spentTxHash: spent.txHash,
|
|
350
|
+
}));
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
await stateStore.putNote(note);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
// Check existing unspent notes for nullification using batch check.
|
|
359
|
+
async function checkExistingNotesForNullification(chainId, account) {
|
|
360
|
+
const accountMpk = formatUint256(account.masterPublicKey);
|
|
361
|
+
const unspentNotes = await stateStore.listNotes({
|
|
362
|
+
chainId,
|
|
363
|
+
mpk: accountMpk,
|
|
364
|
+
includeSpent: false,
|
|
365
|
+
});
|
|
366
|
+
if (unspentNotes.length === 0)
|
|
367
|
+
return;
|
|
368
|
+
const spentNullifiers = await indexerClient.checkNullifiers({
|
|
369
|
+
chainId,
|
|
370
|
+
nullifiers: unspentNotes.map((n) => n.nullifier),
|
|
371
|
+
});
|
|
372
|
+
const spentMap = new Map(spentNullifiers.map((n) => [n.nullifier, n]));
|
|
373
|
+
for (const note of unspentNotes) {
|
|
374
|
+
const spent = spentMap.get(note.nullifier);
|
|
375
|
+
if (spent) {
|
|
376
|
+
await stateStore.putNullifier({
|
|
377
|
+
chainId,
|
|
378
|
+
nullifier: note.nullifier,
|
|
379
|
+
noteIndex: note.index,
|
|
380
|
+
});
|
|
381
|
+
await stateStore.markNoteSpent(chainId, note.index, spent.spentAt * 1000, spent.txHash);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
215
385
|
/**
|
|
216
386
|
* Syncs a single chain into local state, optionally forcing a full rebuild.
|
|
217
|
-
* Skips overlapping runs via `inFlight` and falls back to full resync on
|
|
218
|
-
* ordering/root inconsistencies.
|
|
219
387
|
*/
|
|
220
388
|
async function syncChain(chainId, account, opts = {}) {
|
|
221
389
|
ensureChainId(chainId);
|
|
@@ -223,9 +391,8 @@ export function createNoteSyncService(stateStore, options = {}) {
|
|
|
223
391
|
inFlight: false,
|
|
224
392
|
lastSuccess: null,
|
|
225
393
|
};
|
|
226
|
-
if (current.inFlight)
|
|
394
|
+
if (current.inFlight)
|
|
227
395
|
return;
|
|
228
|
-
}
|
|
229
396
|
status.set(chainId, { ...current, inFlight: true, lastError: undefined });
|
|
230
397
|
try {
|
|
231
398
|
const start = opts.forceFullResync
|
|
@@ -238,19 +405,57 @@ export function createNoteSyncService(stateStore, options = {}) {
|
|
|
238
405
|
if (opts.forceFullResync) {
|
|
239
406
|
await fullResync(chainId, account);
|
|
240
407
|
}
|
|
408
|
+
else if (start > 0) {
|
|
409
|
+
try {
|
|
410
|
+
const diagnosis = await diagnoseChainState(chainId, start);
|
|
411
|
+
switch (diagnosis.kind) {
|
|
412
|
+
case "consistent":
|
|
413
|
+
try {
|
|
414
|
+
await ingestFrom(chainId, start, account);
|
|
415
|
+
}
|
|
416
|
+
catch (err) {
|
|
417
|
+
console.warn(`[note-sync] incremental ingest failed for chain ${chainId}, falling back to full resync:`, err);
|
|
418
|
+
await fullResync(chainId, account);
|
|
419
|
+
}
|
|
420
|
+
break;
|
|
421
|
+
case "partial-divergence":
|
|
422
|
+
await partialResync(chainId, diagnosis.validPrefix, account);
|
|
423
|
+
break;
|
|
424
|
+
case "full-divergence":
|
|
425
|
+
await fullResync(chainId, account);
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
catch (err) {
|
|
430
|
+
console.warn(`[note-sync] chain diagnosis failed for chain ${chainId}, falling back to full resync:`, err);
|
|
431
|
+
await fullResync(chainId, account);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
241
434
|
else {
|
|
435
|
+
// start === 0, fresh first sync
|
|
242
436
|
try {
|
|
243
|
-
await ingestFrom(chainId,
|
|
437
|
+
await ingestFrom(chainId, 0, account);
|
|
244
438
|
}
|
|
245
439
|
catch (err) {
|
|
246
|
-
|
|
440
|
+
console.warn(`[note-sync] initial ingest failed for chain ${chainId}, falling back to full resync:`, err);
|
|
247
441
|
await fullResync(chainId, account);
|
|
248
442
|
}
|
|
249
443
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
444
|
+
// Rescan ciphertexts for multi-account support
|
|
445
|
+
const accountMpk = formatUint256(account.masterPublicKey);
|
|
446
|
+
const leafCount = trees.getLeafCount(chainId);
|
|
447
|
+
if (leafCount > 0 && !opts.forceFullResync) {
|
|
448
|
+
const accountNotes = await stateStore.listNotes({
|
|
449
|
+
chainId,
|
|
450
|
+
mpk: accountMpk,
|
|
451
|
+
});
|
|
452
|
+
if (accountNotes.length < leafCount) {
|
|
453
|
+
await rescanCiphertextsForAccount(chainId, account, leafCount);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
// Check if any existing unspent notes have been nullified
|
|
457
|
+
await checkExistingNotesForNullification(chainId, account);
|
|
458
|
+
status.set(chainId, { inFlight: false, lastSuccess: Date.now() });
|
|
254
459
|
}
|
|
255
460
|
catch (err) {
|
|
256
461
|
status.set(chainId, {
|
|
@@ -269,50 +474,10 @@ export function createNoteSyncService(stateStore, options = {}) {
|
|
|
269
474
|
await syncChain(chainId, account, opts);
|
|
270
475
|
}
|
|
271
476
|
}
|
|
272
|
-
/**
|
|
273
|
-
* Legacy sync method that returns synced notes.
|
|
274
|
-
* Kept for backward compatibility.
|
|
275
|
-
*/
|
|
276
|
-
async function sync(chainId, account, opts) {
|
|
277
|
-
ensureChainId(chainId);
|
|
278
|
-
await rebuildTreeFromStore({
|
|
279
|
-
chainId,
|
|
280
|
-
trees,
|
|
281
|
-
loadLeaf: stateStore.getLeaf.bind(stateStore),
|
|
282
|
-
});
|
|
283
|
-
const synced = [];
|
|
284
|
-
let start = opts?.start ?? 0;
|
|
285
|
-
const shouldCheckNullifiers = await shouldQueryNullifiers(chainId);
|
|
286
|
-
let keepFetching = true;
|
|
287
|
-
while (keepFetching) {
|
|
288
|
-
const batch = await indexerClient.fetchCommitmentBatch({
|
|
289
|
-
chainId,
|
|
290
|
-
start,
|
|
291
|
-
limit,
|
|
292
|
-
});
|
|
293
|
-
if (batch.commitments.length === 0) {
|
|
294
|
-
keepFetching = false;
|
|
295
|
-
continue;
|
|
296
|
-
}
|
|
297
|
-
for (const record of batch.commitments) {
|
|
298
|
-
await recordCommitment(chainId, record, !!opts?.forceFullScan);
|
|
299
|
-
const storedNote = await tryStoreNote(chainId, record, account, shouldCheckNullifiers);
|
|
300
|
-
if (storedNote) {
|
|
301
|
-
synced.push(storedNote);
|
|
302
|
-
}
|
|
303
|
-
start = record.index + 1;
|
|
304
|
-
}
|
|
305
|
-
if (batch.commitments.length < limit) {
|
|
306
|
-
keepFetching = false;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
return synced;
|
|
310
|
-
}
|
|
311
477
|
function getStatus() {
|
|
312
478
|
return status;
|
|
313
479
|
}
|
|
314
480
|
return {
|
|
315
|
-
sync,
|
|
316
481
|
syncChain,
|
|
317
482
|
syncChains,
|
|
318
483
|
getStatus,
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { BaseStateStore, DepositSyncResult, TransactSyncResult } from "./types.js";
|
|
3
|
-
type DepositClient = {
|
|
4
|
-
syncPendingDeposit(relayId: string): Promise<DepositSyncResult>;
|
|
5
|
-
};
|
|
6
|
-
type TransactService = {
|
|
7
|
-
syncPendingTransact(relayId: string): Promise<TransactSyncResult>;
|
|
8
|
-
};
|
|
1
|
+
import type { JobKind, JobStatus } from "../state/index.js";
|
|
2
|
+
import type { BaseStateStore, DepositSyncResult, TransactSyncResult } from "./types/index.js";
|
|
9
3
|
type ReconcilerDeps = {
|
|
10
4
|
stateStore: BaseStateStore;
|
|
11
|
-
depositClient:
|
|
12
|
-
|
|
5
|
+
depositClient: {
|
|
6
|
+
syncPendingDeposit: (relayId: string) => Promise<DepositSyncResult>;
|
|
7
|
+
};
|
|
8
|
+
transactService: {
|
|
9
|
+
syncPendingTransact: (relayId: string) => Promise<TransactSyncResult>;
|
|
10
|
+
};
|
|
13
11
|
};
|
|
14
12
|
export declare function createJobReconciler(deps: ReconcilerDeps): {
|
|
15
|
-
reconcileRelay: (relayId: string) => Promise<DepositSyncResult | TransactSyncResult>;
|
|
13
|
+
reconcileRelay: (relayId: string) => Promise<Error | DepositSyncResult | TransactSyncResult | null>;
|
|
16
14
|
reconcileAll: (filter?: {
|
|
17
|
-
kind?:
|
|
15
|
+
kind?: JobKind;
|
|
18
16
|
statuses?: JobStatus[];
|
|
19
17
|
}) => Promise<unknown[]>;
|
|
20
18
|
};
|