@provablehq/sdk 0.10.2-rc.1 → 0.10.3
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/dynamic/browser.cjs +12 -0
- package/dist/dynamic/browser.d.cts +8 -0
- package/dist/dynamic/browser.d.ts +2 -2
- package/dist/dynamic/node.cjs +12 -0
- package/dist/dynamic/node.d.cts +8 -0
- package/dist/dynamic/node.d.ts +2 -2
- package/dist/mainnet/account.d.cts +347 -0
- package/dist/mainnet/browser.cjs +8507 -0
- package/dist/mainnet/browser.cjs.map +1 -0
- package/dist/mainnet/browser.d.cts +72 -0
- package/dist/mainnet/browser.d.ts +4 -5
- package/dist/mainnet/browser.js +332 -855
- package/dist/mainnet/browser.js.map +1 -1
- package/dist/mainnet/constants.d.cts +40 -0
- package/dist/mainnet/external-signing.d.cts +76 -0
- package/dist/mainnet/integrations/sealance/merkle-tree.d.cts +192 -0
- package/dist/mainnet/keys/keystore/error.d.cts +24 -0
- package/dist/mainnet/keys/keystore/file.d.cts +177 -0
- package/dist/mainnet/keys/keystore/interface.d.cts +161 -0
- package/dist/mainnet/keys/provider/interface.d.cts +170 -0
- package/dist/mainnet/keys/provider/memory.d.cts +213 -0
- package/dist/mainnet/keys/provider/memory.d.ts +6 -2
- package/dist/mainnet/keys/provider/offline.d.cts +365 -0
- package/dist/mainnet/keys/verifier/interface.d.cts +70 -0
- package/dist/mainnet/keys/verifier/memory.d.cts +37 -0
- package/dist/mainnet/keys/verifier/memory.d.ts +1 -1
- package/dist/mainnet/models/authorization.d.cts +6 -0
- package/dist/mainnet/models/authorization.d.ts +2 -2
- package/dist/mainnet/models/blockJSON.d.cts +33 -0
- package/dist/mainnet/models/confirmed_transaction.d.cts +9 -0
- package/dist/mainnet/models/cryptoBoxPubkey.d.cts +4 -0
- package/dist/mainnet/models/deployment/deploymentJSON.d.cts +6 -0
- package/dist/mainnet/models/deployment/deploymentObject.d.cts +6 -0
- package/dist/mainnet/models/encryptedProvingRequest.d.cts +4 -0
- package/dist/mainnet/models/execution/executionJSON.d.cts +11 -0
- package/dist/mainnet/models/execution/executionObject.d.cts +11 -0
- package/dist/mainnet/models/external-signing.d.cts +123 -0
- package/dist/mainnet/models/finalizeJSON.d.cts +6 -0
- package/dist/mainnet/models/functionInput.d.cts +7 -0
- package/dist/mainnet/models/functionObject.d.cts +8 -0
- package/dist/mainnet/models/imports.d.cts +7 -0
- package/dist/mainnet/models/input/inputJSON.d.cts +10 -0
- package/dist/mainnet/models/input/inputObject.d.cts +15 -0
- package/dist/mainnet/models/inputID.d.cts +4 -0
- package/dist/mainnet/models/keyPair.d.cts +4 -0
- package/dist/mainnet/models/output/outputJSON.d.cts +7 -0
- package/dist/mainnet/models/output/outputObject.d.cts +18 -0
- package/dist/mainnet/models/owner/ownerJSON.d.cts +4 -0
- package/dist/mainnet/models/owner/ownerObject.d.cts +5 -0
- package/dist/mainnet/models/plaintext/array.d.cts +3 -0
- package/dist/mainnet/models/plaintext/literal.d.cts +1 -0
- package/dist/mainnet/models/plaintext/plaintext.d.cts +5 -0
- package/dist/mainnet/models/plaintext/struct.d.cts +5 -0
- package/dist/mainnet/models/provingRequest.d.cts +6 -0
- package/dist/mainnet/models/provingRequest.d.ts +1 -1
- package/dist/mainnet/models/provingResponse.d.cts +51 -0
- package/dist/mainnet/models/ratification.d.cts +4 -0
- package/dist/mainnet/models/record-provider/encryptedRecord.d.cts +58 -0
- package/dist/mainnet/models/record-provider/ownedRecord.d.cts +60 -0
- package/dist/mainnet/models/record-provider/recordSearchParams.d.cts +19 -0
- package/dist/mainnet/models/record-scanner/encryptedRecordsResult.d.cts +7 -0
- package/dist/mainnet/models/record-scanner/encryptedRegistrationRequest.d.cts +8 -0
- package/dist/mainnet/models/record-scanner/error.d.cts +47 -0
- package/dist/mainnet/models/record-scanner/error.d.ts +1 -1
- package/dist/mainnet/models/record-scanner/ownedFilter.d.cts +22 -0
- package/dist/mainnet/models/record-scanner/ownedFilter.d.ts +3 -3
- package/dist/mainnet/models/record-scanner/ownedRecordsResponseFilter.d.cts +42 -0
- package/dist/mainnet/models/record-scanner/ownedRecordsResult.d.cts +13 -0
- package/dist/mainnet/models/record-scanner/recordsFilter.d.cts +35 -0
- package/dist/mainnet/models/record-scanner/recordsFilter.d.ts +2 -2
- package/dist/mainnet/models/record-scanner/recordsResponseFilter.d.cts +42 -0
- package/dist/mainnet/models/record-scanner/registrationRequest.d.cts +13 -0
- package/dist/mainnet/models/record-scanner/registrationResponse.d.cts +13 -0
- package/dist/mainnet/models/record-scanner/registrationResult.d.cts +9 -0
- package/dist/mainnet/models/record-scanner/revokeResult.d.cts +17 -0
- package/dist/mainnet/models/record-scanner/serialNumbersResult.d.cts +15 -0
- package/dist/mainnet/models/record-scanner/statusResponse.d.cts +13 -0
- package/dist/mainnet/models/record-scanner/statusResult.d.cts +13 -0
- package/dist/mainnet/models/record-scanner/tagsResult.d.cts +12 -0
- package/dist/mainnet/models/request.d.cts +14 -0
- package/dist/mainnet/models/request.d.ts +1 -1
- package/dist/mainnet/models/solution.d.cts +14 -0
- package/dist/mainnet/models/transaction/transactionJSON.d.cts +11 -0
- package/dist/mainnet/models/transaction/transactionObject.d.cts +14 -0
- package/dist/mainnet/models/transition/transitionJSON.d.cts +13 -0
- package/dist/mainnet/models/transition/transitionObject.d.cts +15 -0
- package/dist/mainnet/network-client.d.cts +850 -0
- package/dist/mainnet/network-client.d.ts +3 -16
- package/dist/mainnet/node-polyfill.cjs +238 -0
- package/dist/mainnet/node-polyfill.cjs.map +1 -0
- package/dist/mainnet/node-polyfill.d.cts +5 -0
- package/dist/mainnet/node-polyfill.js +1 -1
- package/dist/mainnet/node-polyfill.js.map +1 -1
- package/dist/mainnet/node.cjs +685 -0
- package/dist/mainnet/node.cjs.map +1 -0
- package/dist/mainnet/node.d.cts +3 -0
- package/dist/mainnet/node.js +3 -3
- package/dist/mainnet/polyfill/crypto.d.cts +1 -0
- package/dist/mainnet/polyfill/fetch.d.cts +1 -0
- package/dist/mainnet/polyfill/shared.d.cts +1 -0
- package/dist/mainnet/polyfill/worker.d.cts +1 -0
- package/dist/mainnet/polyfill/xmlhttprequest.d.cts +1 -0
- package/dist/mainnet/program-manager.d.cts +1588 -0
- package/dist/mainnet/program-manager.d.ts +1 -62
- package/dist/mainnet/record-provider.d.cts +274 -0
- package/dist/mainnet/record-scanner.d.cts +371 -0
- package/dist/mainnet/record-scanner.d.ts +9 -6
- package/dist/mainnet/security.d.cts +62 -0
- package/dist/mainnet/security.d.ts +5 -5
- package/dist/mainnet/utils.d.cts +23 -0
- package/dist/mainnet/utils.d.ts +10 -2
- package/dist/mainnet/wasm.d.cts +1 -0
- package/dist/mainnet/wasm.d.ts +1 -1
- package/dist/testnet/account.d.cts +347 -0
- package/dist/testnet/browser.cjs +8507 -0
- package/dist/testnet/browser.cjs.map +1 -0
- package/dist/testnet/browser.d.cts +72 -0
- package/dist/testnet/browser.d.ts +4 -5
- package/dist/testnet/browser.js +332 -855
- package/dist/testnet/browser.js.map +1 -1
- package/dist/testnet/constants.d.cts +40 -0
- package/dist/testnet/external-signing.d.cts +76 -0
- package/dist/testnet/integrations/sealance/merkle-tree.d.cts +192 -0
- package/dist/testnet/keys/keystore/error.d.cts +24 -0
- package/dist/testnet/keys/keystore/file.d.cts +177 -0
- package/dist/testnet/keys/keystore/interface.d.cts +161 -0
- package/dist/testnet/keys/provider/interface.d.cts +170 -0
- package/dist/testnet/keys/provider/memory.d.cts +213 -0
- package/dist/testnet/keys/provider/memory.d.ts +6 -2
- package/dist/testnet/keys/provider/offline.d.cts +365 -0
- package/dist/testnet/keys/verifier/interface.d.cts +70 -0
- package/dist/testnet/keys/verifier/memory.d.cts +37 -0
- package/dist/testnet/keys/verifier/memory.d.ts +1 -1
- package/dist/testnet/models/authorization.d.cts +6 -0
- package/dist/testnet/models/authorization.d.ts +2 -2
- package/dist/testnet/models/blockJSON.d.cts +33 -0
- package/dist/testnet/models/confirmed_transaction.d.cts +9 -0
- package/dist/testnet/models/cryptoBoxPubkey.d.cts +4 -0
- package/dist/testnet/models/deployment/deploymentJSON.d.cts +6 -0
- package/dist/testnet/models/deployment/deploymentObject.d.cts +6 -0
- package/dist/testnet/models/encryptedProvingRequest.d.cts +4 -0
- package/dist/testnet/models/execution/executionJSON.d.cts +11 -0
- package/dist/testnet/models/execution/executionObject.d.cts +11 -0
- package/dist/testnet/models/external-signing.d.cts +123 -0
- package/dist/testnet/models/finalizeJSON.d.cts +6 -0
- package/dist/testnet/models/functionInput.d.cts +7 -0
- package/dist/testnet/models/functionObject.d.cts +8 -0
- package/dist/testnet/models/imports.d.cts +7 -0
- package/dist/testnet/models/input/inputJSON.d.cts +10 -0
- package/dist/testnet/models/input/inputObject.d.cts +15 -0
- package/dist/testnet/models/inputID.d.cts +4 -0
- package/dist/testnet/models/keyPair.d.cts +4 -0
- package/dist/testnet/models/output/outputJSON.d.cts +7 -0
- package/dist/testnet/models/output/outputObject.d.cts +18 -0
- package/dist/testnet/models/owner/ownerJSON.d.cts +4 -0
- package/dist/testnet/models/owner/ownerObject.d.cts +5 -0
- package/dist/testnet/models/plaintext/array.d.cts +3 -0
- package/dist/testnet/models/plaintext/literal.d.cts +1 -0
- package/dist/testnet/models/plaintext/plaintext.d.cts +5 -0
- package/dist/testnet/models/plaintext/struct.d.cts +5 -0
- package/dist/testnet/models/provingRequest.d.cts +6 -0
- package/dist/testnet/models/provingRequest.d.ts +1 -1
- package/dist/testnet/models/provingResponse.d.cts +51 -0
- package/dist/testnet/models/ratification.d.cts +4 -0
- package/dist/testnet/models/record-provider/encryptedRecord.d.cts +58 -0
- package/dist/testnet/models/record-provider/ownedRecord.d.cts +60 -0
- package/dist/testnet/models/record-provider/recordSearchParams.d.cts +19 -0
- package/dist/testnet/models/record-scanner/encryptedRecordsResult.d.cts +7 -0
- package/dist/testnet/models/record-scanner/encryptedRegistrationRequest.d.cts +8 -0
- package/dist/testnet/models/record-scanner/error.d.cts +47 -0
- package/dist/testnet/models/record-scanner/error.d.ts +1 -1
- package/dist/testnet/models/record-scanner/ownedFilter.d.cts +22 -0
- package/dist/testnet/models/record-scanner/ownedFilter.d.ts +3 -3
- package/dist/testnet/models/record-scanner/ownedRecordsResponseFilter.d.cts +42 -0
- package/dist/testnet/models/record-scanner/ownedRecordsResult.d.cts +13 -0
- package/dist/testnet/models/record-scanner/recordsFilter.d.cts +35 -0
- package/dist/testnet/models/record-scanner/recordsFilter.d.ts +2 -2
- package/dist/testnet/models/record-scanner/recordsResponseFilter.d.cts +42 -0
- package/dist/testnet/models/record-scanner/registrationRequest.d.cts +13 -0
- package/dist/testnet/models/record-scanner/registrationResponse.d.cts +13 -0
- package/dist/testnet/models/record-scanner/registrationResult.d.cts +9 -0
- package/dist/testnet/models/record-scanner/revokeResult.d.cts +17 -0
- package/dist/testnet/models/record-scanner/serialNumbersResult.d.cts +15 -0
- package/dist/testnet/models/record-scanner/statusResponse.d.cts +13 -0
- package/dist/testnet/models/record-scanner/statusResult.d.cts +13 -0
- package/dist/testnet/models/record-scanner/tagsResult.d.cts +12 -0
- package/dist/testnet/models/request.d.cts +14 -0
- package/dist/testnet/models/request.d.ts +1 -1
- package/dist/testnet/models/solution.d.cts +14 -0
- package/dist/testnet/models/transaction/transactionJSON.d.cts +11 -0
- package/dist/testnet/models/transaction/transactionObject.d.cts +14 -0
- package/dist/testnet/models/transition/transitionJSON.d.cts +13 -0
- package/dist/testnet/models/transition/transitionObject.d.cts +15 -0
- package/dist/testnet/network-client.d.cts +850 -0
- package/dist/testnet/network-client.d.ts +3 -16
- package/dist/testnet/node-polyfill.cjs +238 -0
- package/dist/testnet/node-polyfill.cjs.map +1 -0
- package/dist/testnet/node-polyfill.d.cts +5 -0
- package/dist/testnet/node-polyfill.js +1 -1
- package/dist/testnet/node-polyfill.js.map +1 -1
- package/dist/testnet/node.cjs +685 -0
- package/dist/testnet/node.cjs.map +1 -0
- package/dist/testnet/node.d.cts +3 -0
- package/dist/testnet/node.js +3 -3
- package/dist/testnet/polyfill/crypto.d.cts +1 -0
- package/dist/testnet/polyfill/fetch.d.cts +1 -0
- package/dist/testnet/polyfill/shared.d.cts +1 -0
- package/dist/testnet/polyfill/worker.d.cts +1 -0
- package/dist/testnet/polyfill/xmlhttprequest.d.cts +1 -0
- package/dist/testnet/program-manager.d.cts +1588 -0
- package/dist/testnet/program-manager.d.ts +1 -62
- package/dist/testnet/record-provider.d.cts +274 -0
- package/dist/testnet/record-scanner.d.cts +371 -0
- package/dist/testnet/record-scanner.d.ts +9 -6
- package/dist/testnet/security.d.cts +62 -0
- package/dist/testnet/security.d.ts +5 -5
- package/dist/testnet/utils.d.cts +23 -0
- package/dist/testnet/utils.d.ts +10 -2
- package/dist/testnet/wasm.d.cts +1 -0
- package/dist/testnet/wasm.d.ts +1 -1
- package/package.json +51 -13
- package/dist/mainnet/keys/keystore/indexeddb.d.ts +0 -49
- package/dist/testnet/keys/keystore/indexeddb.d.ts +0 -49
package/dist/mainnet/browser.js
CHANGED
|
@@ -1,363 +1,11 @@
|
|
|
1
1
|
import 'core-js/proposals/json-parse-with-source.js';
|
|
2
|
-
import {
|
|
3
|
-
export { Address, Authorization, BHP1024, BHP256, BHP512, BHP768, Boolean, Ciphertext, ComputeKey, DynamicRecord, EncryptionToolkit, ExecutionRequest, ExecutionResponse, Field, Execution as FunctionExecution, GraphKey, Group, I128, I16, I32, I64, I8, OfflineQuery, Pedersen128, Pedersen64, Plaintext, Poseidon2, Poseidon4, Poseidon8, PrivateKey, PrivateKeyCiphertext, Program,
|
|
4
|
-
import
|
|
5
|
-
import { bech32m } from '@scure/base';
|
|
2
|
+
import { ViewKey, ComputeKey, Address, PrivateKeyCiphertext, PrivateKey, RecordCiphertext, EncryptionToolkit, Group, Metadata, VerifyingKey, Program, Plaintext, Transaction, ProvingRequest, ProvingKey, RecordPlaintext, Field, Poseidon4, ProgramManager as ProgramManager$1, ExecutionRequest, stringToField, verifyFunctionExecution, Value, Proof, Signature } from '@provablehq/wasm/mainnet.js';
|
|
3
|
+
export { Address, Authorization, BHP1024, BHP256, BHP512, BHP768, Boolean, Ciphertext, ComputeKey, DynamicRecord, EncryptionToolkit, ExecutionRequest, ExecutionResponse, Field, Execution as FunctionExecution, GraphKey, Group, I128, I16, I32, I64, I8, OfflineQuery, Pedersen128, Pedersen64, Plaintext, Poseidon2, Poseidon4, Poseidon8, PrivateKey, PrivateKeyCiphertext, Program, ProgramManager as ProgramManagerBase, Proof, ProvingKey, ProvingRequest, RecordCiphertext, RecordPlaintext, Scalar, Signature, Transaction, Transition, U128, U16, U32, U64, U8, Value, VerifyingKey, ViewKey, getOrInitConsensusVersionTestHeights, initThreadPool, snarkVerify, snarkVerifyBatch, stringToField, verifyFunctionExecution } from '@provablehq/wasm/mainnet.js';
|
|
4
|
+
import { cryptoBoxSeal } from '@serenity-kit/noble-sodium';
|
|
5
|
+
import { base64, bech32m } from '@scure/base';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
* Used to prevent path traversal and other filesystem injection when deriving paths from locators.
|
|
10
|
-
*
|
|
11
|
-
* @extends Error
|
|
12
|
-
*/
|
|
13
|
-
class InvalidLocatorError extends Error {
|
|
14
|
-
locator;
|
|
15
|
-
reason;
|
|
16
|
-
/**
|
|
17
|
-
* @param message - Human-readable description of the validation failure.
|
|
18
|
-
* @param locator - The invalid locator string that failed validation.
|
|
19
|
-
* @param reason - Machine-readable reason code for the failure.
|
|
20
|
-
*/
|
|
21
|
-
constructor(message, locator, reason) {
|
|
22
|
-
super(message);
|
|
23
|
-
this.locator = locator;
|
|
24
|
-
this.reason = reason;
|
|
25
|
-
this.name = "InvalidLocatorError";
|
|
26
|
-
Object.setPrototypeOf(this, InvalidLocatorError.prototype);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Error thrown when there is a mismatch between expected and actual key metadata.
|
|
32
|
-
* This can occur during verification of either the checksum or size of a key.
|
|
33
|
-
*
|
|
34
|
-
* @extends Error
|
|
35
|
-
*/
|
|
36
|
-
class KeyVerificationError extends Error {
|
|
37
|
-
locator;
|
|
38
|
-
field;
|
|
39
|
-
expected;
|
|
40
|
-
actual;
|
|
41
|
-
/**
|
|
42
|
-
* Creates a new KeyVerificationError instance (error.name is "ChecksumMismatchError").
|
|
43
|
-
*
|
|
44
|
-
* @param {string} locator - The key locator where the mismatch occurred.
|
|
45
|
-
* @param {"checksum" | "size"} field - The field that failed verification (either "checksum" or "size").
|
|
46
|
-
* @param {string} expected - The expected value of the field.
|
|
47
|
-
* @param {string} actual - The actual value encountered.
|
|
48
|
-
*/
|
|
49
|
-
constructor(locator, field, expected, actual) {
|
|
50
|
-
super(`Key verification ${locator} ${field} mismatch: expected ${expected}, got ${actual}`);
|
|
51
|
-
this.locator = locator;
|
|
52
|
-
this.field = field;
|
|
53
|
-
this.expected = expected;
|
|
54
|
-
this.actual = actual;
|
|
55
|
-
this.name = "ChecksumMismatchError";
|
|
56
|
-
Object.setPrototypeOf(this, KeyVerificationError.prototype);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Computes the SHA-256 checksum of a given set of bytes.
|
|
61
|
-
*
|
|
62
|
-
* @param {Uint8Array} bytes - The bytes to compute the checksum of.
|
|
63
|
-
*/
|
|
64
|
-
async function sha256Hex(bytes) {
|
|
65
|
-
const hash = await crypto.subtle.digest("SHA-256", bytes);
|
|
66
|
-
return Array.from(new Uint8Array(hash))
|
|
67
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
68
|
-
.join("");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* In-memory implementation of KeyVerifier that stores and verifies key fingerprints.
|
|
73
|
-
* Provides functionality to compute and verify cryptographic checksums of keys, storing them
|
|
74
|
-
* in memory for subsequent verification. This implementation is primarily used for testing
|
|
75
|
-
* and development purposes where persistence is not required.
|
|
76
|
-
*
|
|
77
|
-
* Key features:
|
|
78
|
-
* - Computes SHA-256 checksums and sizes for key bytes.
|
|
79
|
-
* - Stores key fingerprints in memory using string locators.
|
|
80
|
-
* - Verifies key bytes against stored or provided fingerprints.
|
|
81
|
-
*
|
|
82
|
-
* @implements {KeyVerifier}
|
|
83
|
-
*/
|
|
84
|
-
class MemKeyVerifier {
|
|
85
|
-
keyStore = {};
|
|
86
|
-
/**
|
|
87
|
-
* Computes and optionally stores key metadata. If a keyFingerprint is provided, this function will verify the computed checksum against it before storing it.
|
|
88
|
-
*
|
|
89
|
-
* @param {KeyMetadata} keyMetadata - Object containing key bytes and optional verification data.
|
|
90
|
-
* @throws {KeyVerificationError} When provided keyFingerprint doesn't match computed values.
|
|
91
|
-
* @returns {Promise<KeyFingerprint>} Computed key metadata.
|
|
92
|
-
*/
|
|
93
|
-
async computeKeyMetadata(keyMetadata) {
|
|
94
|
-
// Compute the metadata from the key bytes
|
|
95
|
-
const computedFingerprint = {
|
|
96
|
-
checksum: await sha256Hex(keyMetadata.keyBytes),
|
|
97
|
-
size: keyMetadata.keyBytes.length
|
|
98
|
-
};
|
|
99
|
-
// If a KeyFingerprint is provided, verify it matches computed values.
|
|
100
|
-
if (keyMetadata.fingerprint) {
|
|
101
|
-
if (keyMetadata.fingerprint.size !== computedFingerprint.size) {
|
|
102
|
-
throw new KeyVerificationError(keyMetadata.locator ? keyMetadata.locator : "", "size", String(keyMetadata.fingerprint.size), String(computedFingerprint.size));
|
|
103
|
-
}
|
|
104
|
-
if (keyMetadata.fingerprint.checksum !== computedFingerprint.checksum) {
|
|
105
|
-
throw new KeyVerificationError(keyMetadata.locator ? keyMetadata.locator : "", "checksum", keyMetadata.fingerprint.checksum, computedFingerprint.checksum);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
// If locator is provided, store only the fingerprint
|
|
109
|
-
if (keyMetadata.locator) {
|
|
110
|
-
this.keyStore[keyMetadata.locator] = computedFingerprint;
|
|
111
|
-
}
|
|
112
|
-
return computedFingerprint;
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Verifies key bytes against stored or provided metadata. Follows a priority verification scheme:
|
|
116
|
-
* 1. If KeyFingerprint is provided in the metadata, this method verifies against that first.
|
|
117
|
-
* 2. If a locator is provided, attempts to verify against stored fingerprint.
|
|
118
|
-
* 3. If neither is available, throws an error.
|
|
119
|
-
*
|
|
120
|
-
* @param {KeyMetadata} keyMetadata - Object containing the key bytes and optional verification metadata.
|
|
121
|
-
* @throws {Error} When neither fingerprint nor valid locator is provided for verification.
|
|
122
|
-
* @throws {KeyVerificationError} When size or checksum verification fails.
|
|
123
|
-
* @returns {Promise<void>} Promise that resolves when verification succeeds.
|
|
124
|
-
*/
|
|
125
|
-
async verifyKeyBytes(keyMetadata) {
|
|
126
|
-
if (!keyMetadata.keyBytes) {
|
|
127
|
-
throw new Error("Key bytes must be provided for verification.");
|
|
128
|
-
}
|
|
129
|
-
// Compute the fingerprint for the provided bytes.
|
|
130
|
-
const computedFingerprint = await this.computeKeyMetadata({
|
|
131
|
-
keyBytes: keyMetadata.keyBytes
|
|
132
|
-
});
|
|
133
|
-
// Determine which fingerprint to verify against.
|
|
134
|
-
let fingerprintToVerify;
|
|
135
|
-
if (keyMetadata.fingerprint) {
|
|
136
|
-
// If a key fingerprint is provided, use it.
|
|
137
|
-
fingerprintToVerify = keyMetadata.fingerprint;
|
|
138
|
-
}
|
|
139
|
-
else if (keyMetadata.locator) {
|
|
140
|
-
// Otherwise try to get stored fingerprint by locator.
|
|
141
|
-
fingerprintToVerify = this.keyStore[keyMetadata.locator];
|
|
142
|
-
}
|
|
143
|
-
if (!fingerprintToVerify) {
|
|
144
|
-
throw new Error("Either fingerprint or a valid locator must be provided for verification.");
|
|
145
|
-
}
|
|
146
|
-
// Verify the key size.
|
|
147
|
-
if (fingerprintToVerify.size !== computedFingerprint.size) {
|
|
148
|
-
throw new KeyVerificationError(keyMetadata.locator || "", "size", String(fingerprintToVerify.size), String(computedFingerprint.size));
|
|
149
|
-
}
|
|
150
|
-
// Verify the key checksum.
|
|
151
|
-
if (fingerprintToVerify.checksum !== computedFingerprint.checksum) {
|
|
152
|
-
throw new KeyVerificationError(keyMetadata.locator || "", "checksum", fingerprintToVerify.checksum, computedFingerprint.checksum);
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Browser-compatible {@link KeyStore} backed by IndexedDB.
|
|
159
|
-
*
|
|
160
|
-
* This is the browser counterpart to {@link LocalFileKeyStore} (which requires Node.js `fs`).
|
|
161
|
-
* It persists proving and verifying keys across page reloads and browser sessions using the
|
|
162
|
-
* IndexedDB API available in all modern browsers and Web Workers.
|
|
163
|
-
*
|
|
164
|
-
* @example
|
|
165
|
-
* ```ts
|
|
166
|
-
* import { IndexedDBKeyStore, ProgramManager } from "@provablehq/sdk";
|
|
167
|
-
*
|
|
168
|
-
* const keyStore = new IndexedDBKeyStore();
|
|
169
|
-
* const pm = new ProgramManager();
|
|
170
|
-
* pm.setKeyStore(keyStore);
|
|
171
|
-
* // Keys synthesized during execution are now cached in IndexedDB
|
|
172
|
-
* // and reloaded automatically on subsequent runs.
|
|
173
|
-
* ```
|
|
174
|
-
*/
|
|
175
|
-
class IndexedDBKeyStore {
|
|
176
|
-
dbName;
|
|
177
|
-
storeName = "keys";
|
|
178
|
-
keyVerifier = new MemKeyVerifier();
|
|
179
|
-
dbPromise = null;
|
|
180
|
-
/**
|
|
181
|
-
* @param dbName IndexedDB database name. Defaults to `"aleo-keystore"`.
|
|
182
|
-
*/
|
|
183
|
-
constructor(dbName = "aleo-keystore") {
|
|
184
|
-
this.dbName = dbName;
|
|
185
|
-
}
|
|
186
|
-
// -------------------------------------------------------
|
|
187
|
-
// IndexedDB helpers
|
|
188
|
-
// -------------------------------------------------------
|
|
189
|
-
/** Opens (or creates) the database, returning a cached promise. */
|
|
190
|
-
openDB() {
|
|
191
|
-
if (this.dbPromise)
|
|
192
|
-
return this.dbPromise;
|
|
193
|
-
this.dbPromise = new Promise((resolve, reject) => {
|
|
194
|
-
const request = indexedDB.open(this.dbName, 1);
|
|
195
|
-
request.onupgradeneeded = () => {
|
|
196
|
-
const db = request.result;
|
|
197
|
-
if (!db.objectStoreNames.contains(this.storeName)) {
|
|
198
|
-
db.createObjectStore(this.storeName, { keyPath: "locator" });
|
|
199
|
-
}
|
|
200
|
-
};
|
|
201
|
-
request.onsuccess = () => resolve(request.result);
|
|
202
|
-
request.onerror = () => {
|
|
203
|
-
this.dbPromise = null;
|
|
204
|
-
reject(request.error);
|
|
205
|
-
};
|
|
206
|
-
request.onblocked = () => {
|
|
207
|
-
this.dbPromise = null;
|
|
208
|
-
reject(new DOMException("Database open blocked", "AbortError"));
|
|
209
|
-
};
|
|
210
|
-
});
|
|
211
|
-
return this.dbPromise;
|
|
212
|
-
}
|
|
213
|
-
/** Runs a single read-write transaction and returns the request result. */
|
|
214
|
-
async tx(mode, fn) {
|
|
215
|
-
const db = await this.openDB();
|
|
216
|
-
return new Promise((resolve, reject) => {
|
|
217
|
-
const txn = db.transaction(this.storeName, mode);
|
|
218
|
-
const store = txn.objectStore(this.storeName);
|
|
219
|
-
const req = fn(store);
|
|
220
|
-
let result;
|
|
221
|
-
req.onsuccess = () => { result = req.result; };
|
|
222
|
-
txn.oncomplete = () => resolve(result);
|
|
223
|
-
txn.onerror = () => reject(txn.error);
|
|
224
|
-
txn.onabort = () => reject(txn.error ?? new DOMException("Transaction aborted", "AbortError"));
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
// -------------------------------------------------------
|
|
228
|
-
// Locator serialization (mirrors LocalFileKeyStore)
|
|
229
|
-
// -------------------------------------------------------
|
|
230
|
-
validateComponent(value, label) {
|
|
231
|
-
if (value === "" || value === ".") {
|
|
232
|
-
throw new InvalidLocatorError(`KeyLocator ${label} must not be empty or "." (got "${value}")`, value, "reserved_name");
|
|
233
|
-
}
|
|
234
|
-
if (value.includes("..")) {
|
|
235
|
-
throw new InvalidLocatorError(`KeyLocator ${label} must not contain ".." (got "${value}")`, value, "path_traversal");
|
|
236
|
-
}
|
|
237
|
-
if (value.includes("/") || value.includes("\\") || value.includes("\0")) {
|
|
238
|
-
throw new InvalidLocatorError(`KeyLocator ${label} must not contain path separators or null bytes (got "${value}")`, value, "path_separator");
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
validateNonNegative(value, label) {
|
|
242
|
-
if (!Number.isInteger(value) || value < 0) {
|
|
243
|
-
throw new InvalidLocatorError(`KeyLocator ${label} must be a non-negative integer (got ${value})`, String(value), "negative_value");
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
serializeLocator(locator) {
|
|
247
|
-
this.validateComponent(locator.program, "program");
|
|
248
|
-
this.validateComponent(locator.functionName, "functionName");
|
|
249
|
-
this.validateComponent(locator.network, "network");
|
|
250
|
-
this.validateNonNegative(locator.edition, "edition");
|
|
251
|
-
this.validateNonNegative(locator.amendment, "amendment");
|
|
252
|
-
const base = `${locator.program}.${locator.functionName}.e${locator.edition}.a${locator.amendment}.${locator.network}.${locator.keyType}`;
|
|
253
|
-
if (locator.keyType === "translation") {
|
|
254
|
-
this.validateComponent(locator.recordName, "recordName");
|
|
255
|
-
this.validateNonNegative(locator.recordInputPosition, "recordInputPosition");
|
|
256
|
-
return `${base}.${locator.recordName}.${locator.recordInputPosition}`;
|
|
257
|
-
}
|
|
258
|
-
return base;
|
|
259
|
-
}
|
|
260
|
-
checksumToFingerprint(checksum, keyBytes) {
|
|
261
|
-
if (!checksum)
|
|
262
|
-
return undefined;
|
|
263
|
-
return { checksum, size: keyBytes.length };
|
|
264
|
-
}
|
|
265
|
-
// -------------------------------------------------------
|
|
266
|
-
// KeyStore interface
|
|
267
|
-
// -------------------------------------------------------
|
|
268
|
-
async getKeyBytes(locator) {
|
|
269
|
-
const key = this.serializeLocator(locator);
|
|
270
|
-
const record = await this.tx("readonly", (store) => store.get(key));
|
|
271
|
-
if (!record)
|
|
272
|
-
return null;
|
|
273
|
-
const fingerprint = this.checksumToFingerprint(locator.checksum, record.bytes) ?? record.metadata;
|
|
274
|
-
if (fingerprint) {
|
|
275
|
-
await this.keyVerifier.verifyKeyBytes({
|
|
276
|
-
keyBytes: record.bytes,
|
|
277
|
-
locator: key,
|
|
278
|
-
fingerprint,
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
return record.bytes;
|
|
282
|
-
}
|
|
283
|
-
async getProvingKey(locator) {
|
|
284
|
-
const bytes = await this.getKeyBytes(locator);
|
|
285
|
-
if (!bytes)
|
|
286
|
-
return null;
|
|
287
|
-
return ProvingKey.fromBytes(bytes);
|
|
288
|
-
}
|
|
289
|
-
async getVerifyingKey(locator) {
|
|
290
|
-
const bytes = await this.getKeyBytes(locator);
|
|
291
|
-
if (!bytes)
|
|
292
|
-
return null;
|
|
293
|
-
return VerifyingKey.fromBytes(bytes);
|
|
294
|
-
}
|
|
295
|
-
async setKeys(proverLocator, verifierLocator, keys) {
|
|
296
|
-
const proverKey = this.serializeLocator(proverLocator);
|
|
297
|
-
const verifierKey = this.serializeLocator(verifierLocator);
|
|
298
|
-
const [provingKey, verifyingKey] = keys;
|
|
299
|
-
const [provingKeyBytes, verifyingKeyBytes] = [
|
|
300
|
-
provingKey.toBytes(),
|
|
301
|
-
verifyingKey.toBytes(),
|
|
302
|
-
];
|
|
303
|
-
const [proverFingerprint, verifierFingerprint] = await Promise.all([
|
|
304
|
-
this.keyVerifier.computeKeyMetadata({
|
|
305
|
-
keyBytes: provingKeyBytes,
|
|
306
|
-
locator: proverKey,
|
|
307
|
-
fingerprint: this.checksumToFingerprint(proverLocator.checksum, provingKeyBytes),
|
|
308
|
-
}),
|
|
309
|
-
this.keyVerifier.computeKeyMetadata({
|
|
310
|
-
keyBytes: verifyingKeyBytes,
|
|
311
|
-
locator: verifierKey,
|
|
312
|
-
fingerprint: this.checksumToFingerprint(verifierLocator.checksum, verifyingKeyBytes),
|
|
313
|
-
}),
|
|
314
|
-
]);
|
|
315
|
-
const proverRecord = { locator: proverKey, bytes: provingKeyBytes, metadata: proverFingerprint };
|
|
316
|
-
const verifierRecord = { locator: verifierKey, bytes: verifyingKeyBytes, metadata: verifierFingerprint };
|
|
317
|
-
// Write both in a single transaction for atomicity.
|
|
318
|
-
const db = await this.openDB();
|
|
319
|
-
await new Promise((resolve, reject) => {
|
|
320
|
-
const txn = db.transaction(this.storeName, "readwrite");
|
|
321
|
-
const store = txn.objectStore(this.storeName);
|
|
322
|
-
store.put(proverRecord);
|
|
323
|
-
store.put(verifierRecord);
|
|
324
|
-
txn.oncomplete = () => resolve();
|
|
325
|
-
txn.onerror = () => reject(txn.error);
|
|
326
|
-
txn.onabort = () => reject(txn.error ?? new DOMException("Transaction aborted", "AbortError"));
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
async setKeyBytes(keyBytes, locator) {
|
|
330
|
-
const key = this.serializeLocator(locator);
|
|
331
|
-
const computedMetadata = await this.keyVerifier.computeKeyMetadata({
|
|
332
|
-
keyBytes,
|
|
333
|
-
locator: key,
|
|
334
|
-
fingerprint: this.checksumToFingerprint(locator.checksum, keyBytes),
|
|
335
|
-
});
|
|
336
|
-
const record = { locator: key, bytes: keyBytes, metadata: computedMetadata };
|
|
337
|
-
await this.tx("readwrite", (store) => store.put(record));
|
|
338
|
-
}
|
|
339
|
-
async getKeyMetadata(locator) {
|
|
340
|
-
const key = this.serializeLocator(locator);
|
|
341
|
-
const record = await this.tx("readonly", (store) => store.get(key));
|
|
342
|
-
return record?.metadata ?? null;
|
|
343
|
-
}
|
|
344
|
-
async has(locator) {
|
|
345
|
-
const key = this.serializeLocator(locator);
|
|
346
|
-
const count = await this.tx("readonly", (store) => store.count(IDBKeyRange.only(key)));
|
|
347
|
-
return count > 0;
|
|
348
|
-
}
|
|
349
|
-
async delete(locator) {
|
|
350
|
-
const key = this.serializeLocator(locator);
|
|
351
|
-
await this.tx("readwrite", (store) => store.delete(key));
|
|
352
|
-
}
|
|
353
|
-
async clear() {
|
|
354
|
-
await this.tx("readwrite", (store) => store.clear());
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
await sodium.ready;
|
|
359
|
-
/**
|
|
360
|
-
* Encrypt an authorization with a libsodium cryptobox public key.
|
|
8
|
+
* Encrypt an authorization with a cryptobox X25519 public key (libsodium-compatible wire format).
|
|
361
9
|
*
|
|
362
10
|
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
363
11
|
* @param {Authorization} authorization the authorization to encrypt.
|
|
@@ -365,14 +13,13 @@ await sodium.ready;
|
|
|
365
13
|
* @returns {string} the encrypted authorization in RFC 4648 standard Base64.
|
|
366
14
|
*/
|
|
367
15
|
function encryptAuthorization(publicKey, authorization) {
|
|
368
|
-
// Ready the cryptobox lib.
|
|
369
16
|
return encryptMessage(publicKey, authorization.toBytesLe());
|
|
370
17
|
}
|
|
371
18
|
/**
|
|
372
|
-
* Encrypt a ProvingRequest with a
|
|
19
|
+
* Encrypt a ProvingRequest with a cryptobox X25519 public key (libsodium-compatible wire format).
|
|
373
20
|
*
|
|
374
21
|
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
375
|
-
* @param {
|
|
22
|
+
* @param {ProvingRequest} provingRequest the ProvingRequest to encrypt.
|
|
376
23
|
*
|
|
377
24
|
* @returns {string} the encrypted ProvingRequest in RFC 4648 standard Base64.
|
|
378
25
|
*/
|
|
@@ -380,7 +27,7 @@ function encryptProvingRequest(publicKey, provingRequest) {
|
|
|
380
27
|
return encryptMessage(publicKey, provingRequest.toBytesLe());
|
|
381
28
|
}
|
|
382
29
|
/**
|
|
383
|
-
* Encrypt a view key with a
|
|
30
|
+
* Encrypt a view key with a cryptobox X25519 public key (libsodium-compatible wire format).
|
|
384
31
|
*
|
|
385
32
|
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
386
33
|
* @param {ViewKey} viewKey the view key to encrypt.
|
|
@@ -446,7 +93,17 @@ function zeroizeBytes(bytes) {
|
|
|
446
93
|
bytes.fill(0);
|
|
447
94
|
}
|
|
448
95
|
/**
|
|
449
|
-
* Encrypt arbitrary bytes with a
|
|
96
|
+
* Encrypt arbitrary bytes with a cryptobox public key using the libsodium
|
|
97
|
+
* `crypto_box_seal` wire format.
|
|
98
|
+
*
|
|
99
|
+
* The implementation is delegated to `@serenity-kit/noble-sodium`, which
|
|
100
|
+
* composes the primitive steps of `crypto_box_seal` — ephemeral X25519
|
|
101
|
+
* keypair, blake2b-24 nonce derivation over `epk || rpk`, HSalsa20 key
|
|
102
|
+
* derivation from the ECDH shared secret, and XSalsa20-Poly1305 AEAD — on
|
|
103
|
+
* top of the audited `@noble/*` primitives. Output is byte-identical to
|
|
104
|
+
* libsodium's `crypto_box_seal` for any given ephemeral key, so ciphertexts
|
|
105
|
+
* are decryptable by any libsodium-compatible backend (e.g. `sodiumoxide`,
|
|
106
|
+
* `libsodium-sys`) with no changes.
|
|
450
107
|
*
|
|
451
108
|
* @param {string} publicKey The cryptobox X25519 public key to encrypt with (encoded in RFC 4648 standard Base64).
|
|
452
109
|
* @param {Uint8Array} message the bytes to encrypt.
|
|
@@ -454,8 +111,9 @@ function zeroizeBytes(bytes) {
|
|
|
454
111
|
* @returns {string} the encrypted bytes in RFC 4648 standard Base64.
|
|
455
112
|
*/
|
|
456
113
|
function encryptMessage(publicKey, message) {
|
|
457
|
-
const publicKeyBytes =
|
|
458
|
-
|
|
114
|
+
const publicKeyBytes = base64.decode(publicKey);
|
|
115
|
+
const ciphertext = cryptoBoxSeal({ message, publicKey: publicKeyBytes });
|
|
116
|
+
return base64.encode(ciphertext);
|
|
459
117
|
}
|
|
460
118
|
|
|
461
119
|
/**
|
|
@@ -979,6 +637,8 @@ function logAndThrow(message) {
|
|
|
979
637
|
console.error(message);
|
|
980
638
|
throw new Error(message);
|
|
981
639
|
}
|
|
640
|
+
/** Default transport — wraps global fetch to avoid illegal-invocation errors in browsers. */
|
|
641
|
+
const defaultTransport = (...args) => fetch(...args);
|
|
982
642
|
function parseJSON(json) {
|
|
983
643
|
function revive(key, value, context) {
|
|
984
644
|
if (Number.isInteger(value)) {
|
|
@@ -990,16 +650,16 @@ function parseJSON(json) {
|
|
|
990
650
|
}
|
|
991
651
|
return JSON.parse(json, revive);
|
|
992
652
|
}
|
|
993
|
-
async function get(url, options) {
|
|
994
|
-
const response = await
|
|
653
|
+
async function get(url, options, transport = defaultTransport) {
|
|
654
|
+
const response = await transport(url, options);
|
|
995
655
|
if (!response.ok) {
|
|
996
656
|
throw new Error(response.status + " could not get URL " + url);
|
|
997
657
|
}
|
|
998
658
|
return response;
|
|
999
659
|
}
|
|
1000
|
-
async function post(url, options) {
|
|
660
|
+
async function post(url, options, transport = defaultTransport) {
|
|
1001
661
|
options.method = "POST";
|
|
1002
|
-
const response = await
|
|
662
|
+
const response = await transport(url, options);
|
|
1003
663
|
if (!response.ok) {
|
|
1004
664
|
const error = await response.text();
|
|
1005
665
|
let message = `${response.status} error received from ${url}`;
|
|
@@ -1180,6 +840,7 @@ class AleoNetworkClient {
|
|
|
1180
840
|
ctx;
|
|
1181
841
|
verboseErrors;
|
|
1182
842
|
network;
|
|
843
|
+
transport;
|
|
1183
844
|
apiKey;
|
|
1184
845
|
consumerId;
|
|
1185
846
|
jwtData;
|
|
@@ -1193,6 +854,7 @@ class AleoNetworkClient {
|
|
|
1193
854
|
this.network = "mainnet";
|
|
1194
855
|
this.ctx = {};
|
|
1195
856
|
this.verboseErrors = true;
|
|
857
|
+
this.transport = options?.transport ?? defaultTransport;
|
|
1196
858
|
if (options) {
|
|
1197
859
|
if (options.headers) {
|
|
1198
860
|
this.headers = options.headers;
|
|
@@ -1200,7 +862,7 @@ class AleoNetworkClient {
|
|
|
1200
862
|
else {
|
|
1201
863
|
this.headers = {
|
|
1202
864
|
// This is replaced by the actual version by a Rollup plugin
|
|
1203
|
-
"X-Aleo-SDK-Version": "0.10.
|
|
865
|
+
"X-Aleo-SDK-Version": "0.10.3",
|
|
1204
866
|
"X-Aleo-environment": environment(),
|
|
1205
867
|
};
|
|
1206
868
|
}
|
|
@@ -1216,7 +878,7 @@ class AleoNetworkClient {
|
|
|
1216
878
|
else {
|
|
1217
879
|
this.headers = {
|
|
1218
880
|
// This is replaced by the actual version by a Rollup plugin
|
|
1219
|
-
"X-Aleo-SDK-Version": "0.10.
|
|
881
|
+
"X-Aleo-SDK-Version": "0.10.3",
|
|
1220
882
|
"X-Aleo-environment": environment(),
|
|
1221
883
|
};
|
|
1222
884
|
}
|
|
@@ -1363,7 +1025,7 @@ class AleoNetworkClient {
|
|
|
1363
1025
|
...this.headers,
|
|
1364
1026
|
...ctx,
|
|
1365
1027
|
},
|
|
1366
|
-
});
|
|
1028
|
+
}, this.transport);
|
|
1367
1029
|
return await response.text();
|
|
1368
1030
|
});
|
|
1369
1031
|
}
|
|
@@ -1379,7 +1041,7 @@ class AleoNetworkClient {
|
|
|
1379
1041
|
* @returns The Response object from the POST request.
|
|
1380
1042
|
*/
|
|
1381
1043
|
async _sendPost(url, options) {
|
|
1382
|
-
return post(url, options);
|
|
1044
|
+
return post(url, options, this.transport);
|
|
1383
1045
|
}
|
|
1384
1046
|
/**
|
|
1385
1047
|
* Attempt to find records in the Aleo blockchain.
|
|
@@ -2030,30 +1692,6 @@ class AleoNetworkClient {
|
|
|
2030
1692
|
this.ctx = {};
|
|
2031
1693
|
}
|
|
2032
1694
|
}
|
|
2033
|
-
/**
|
|
2034
|
-
* Returns the current edition and amendment count for a program.
|
|
2035
|
-
*
|
|
2036
|
-
* @param {string} programId - The program ID (e.g. "hello_hello.aleo")
|
|
2037
|
-
* @returns {{ program_id: string, edition: number, amendment_count: number }}
|
|
2038
|
-
*
|
|
2039
|
-
* @example
|
|
2040
|
-
* const networkClient = new AleoNetworkClient("https://api.provable.com/v2");
|
|
2041
|
-
* const info = await networkClient.getProgramAmendmentCount("hello_hello.aleo");
|
|
2042
|
-
* console.log(info.edition, info.amendment_count);
|
|
2043
|
-
*/
|
|
2044
|
-
async getProgramAmendmentCount(programId) {
|
|
2045
|
-
try {
|
|
2046
|
-
this.ctx = { "X-ALEO-METHOD": "getProgramAmendmentCount" };
|
|
2047
|
-
const raw = await this.fetchRaw("/programs/" + programId + "/amendment_count");
|
|
2048
|
-
return JSON.parse(raw);
|
|
2049
|
-
}
|
|
2050
|
-
catch (error) {
|
|
2051
|
-
throw new Error(`Error fetching amendment count for ${programId}: ${error}`);
|
|
2052
|
-
}
|
|
2053
|
-
finally {
|
|
2054
|
-
this.ctx = {};
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
1695
|
/**
|
|
2058
1696
|
* Returns a program object from a program ID or program source code.
|
|
2059
1697
|
*
|
|
@@ -2604,7 +2242,7 @@ class AleoNetworkClient {
|
|
|
2604
2242
|
headers: Object.assign({}, { ...this.headers, "X-ALEO-METHOD": "submitSolution" }, {
|
|
2605
2243
|
"Content-Type": "application/json",
|
|
2606
2244
|
}),
|
|
2607
|
-
}));
|
|
2245
|
+
}, this.transport));
|
|
2608
2246
|
try {
|
|
2609
2247
|
const text = await response.text();
|
|
2610
2248
|
return parseJSON(text);
|
|
@@ -2632,7 +2270,7 @@ class AleoNetworkClient {
|
|
|
2632
2270
|
headers: {
|
|
2633
2271
|
'X-Provable-API-Key': apiKey
|
|
2634
2272
|
}
|
|
2635
|
-
});
|
|
2273
|
+
}, this.transport);
|
|
2636
2274
|
const authHeader = response.headers.get('authorization');
|
|
2637
2275
|
if (!authHeader) {
|
|
2638
2276
|
throw new Error('No authorization header in JWT refresh response');
|
|
@@ -2741,7 +2379,7 @@ class AleoNetworkClient {
|
|
|
2741
2379
|
const pubKeyResponse = await get(proverUri + "/pubkey", {
|
|
2742
2380
|
headers,
|
|
2743
2381
|
credentials: "include",
|
|
2744
|
-
});
|
|
2382
|
+
}, this.transport);
|
|
2745
2383
|
// Encrypt the provingRequest.
|
|
2746
2384
|
const pubkey = parseJSON(await pubKeyResponse.text());
|
|
2747
2385
|
const ciphertext = encryptProvingRequest(pubkey.public_key, ProvingRequest.fromString(provingRequestString));
|
|
@@ -2753,7 +2391,7 @@ class AleoNetworkClient {
|
|
|
2753
2391
|
// We're in node, attempt to set the cookie manually.
|
|
2754
2392
|
const cookie = isNode() ? pubKeyResponse.headers.get("set-cookie") : undefined;
|
|
2755
2393
|
// Send the encrypted proving request to the DPS service.
|
|
2756
|
-
const res = await
|
|
2394
|
+
const res = await this.transport(`${proverUri}/prove/encrypted`, {
|
|
2757
2395
|
method: "POST",
|
|
2758
2396
|
body: JSON.stringify(payload),
|
|
2759
2397
|
headers: {
|
|
@@ -2769,7 +2407,7 @@ class AleoNetworkClient {
|
|
|
2769
2407
|
const proveEndpoint = proverUri.endsWith("/prove")
|
|
2770
2408
|
? proverUri
|
|
2771
2409
|
: proverUri + "/prove";
|
|
2772
|
-
const res = await
|
|
2410
|
+
const res = await this.transport(proveEndpoint, {
|
|
2773
2411
|
method: "POST",
|
|
2774
2412
|
body: provingRequestString,
|
|
2775
2413
|
headers,
|
|
@@ -2841,7 +2479,7 @@ class AleoNetworkClient {
|
|
|
2841
2479
|
return reject(new Error(`Transaction ${transactionId} did not appear after the timeout period of ${interval}ms - consider resubmitting the transaction`));
|
|
2842
2480
|
}
|
|
2843
2481
|
try {
|
|
2844
|
-
const res = await
|
|
2482
|
+
const res = await this.transport(`${this.host}/transaction/confirmed/${transactionId}`, {
|
|
2845
2483
|
headers: {
|
|
2846
2484
|
...this.headers,
|
|
2847
2485
|
"X-ALEO-METHOD": "waitForTransactionConfirmation",
|
|
@@ -2977,9 +2615,10 @@ class AleoKeyProvider {
|
|
|
2977
2615
|
cache;
|
|
2978
2616
|
cacheOption;
|
|
2979
2617
|
keyUris;
|
|
2618
|
+
transport;
|
|
2980
2619
|
async fetchBytes(url = "/") {
|
|
2981
2620
|
try {
|
|
2982
|
-
const response = await get(url);
|
|
2621
|
+
const response = await get(url, undefined, this.transport);
|
|
2983
2622
|
const data = await response.arrayBuffer();
|
|
2984
2623
|
return new Uint8Array(data);
|
|
2985
2624
|
}
|
|
@@ -2987,10 +2626,11 @@ class AleoKeyProvider {
|
|
|
2987
2626
|
throw new Error("Error fetching data." + error.message);
|
|
2988
2627
|
}
|
|
2989
2628
|
}
|
|
2990
|
-
constructor() {
|
|
2629
|
+
constructor(options) {
|
|
2991
2630
|
this.keyUris = KEY_STORE;
|
|
2992
2631
|
this.cache = new Map();
|
|
2993
2632
|
this.cacheOption = false;
|
|
2633
|
+
this.transport = options?.transport ?? defaultTransport;
|
|
2994
2634
|
}
|
|
2995
2635
|
async keyStore() {
|
|
2996
2636
|
return undefined;
|
|
@@ -3360,7 +3000,7 @@ class AleoKeyProvider {
|
|
|
3360
3000
|
default:
|
|
3361
3001
|
try {
|
|
3362
3002
|
/// Try to fetch the verifying key from the network as a string
|
|
3363
|
-
const response = await get(verifierUri);
|
|
3003
|
+
const response = await get(verifierUri, undefined, this.transport);
|
|
3364
3004
|
const text = await response.text();
|
|
3365
3005
|
return VerifyingKey.fromString(text);
|
|
3366
3006
|
}
|
|
@@ -3375,8 +3015,158 @@ class AleoKeyProvider {
|
|
|
3375
3015
|
}
|
|
3376
3016
|
}
|
|
3377
3017
|
}
|
|
3378
|
-
unBondPublicKeys() {
|
|
3379
|
-
return this.fetchCreditsKeys(CREDITS_PROGRAM_KEYS.unbond_public);
|
|
3018
|
+
unBondPublicKeys() {
|
|
3019
|
+
return this.fetchCreditsKeys(CREDITS_PROGRAM_KEYS.unbond_public);
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
/**
|
|
3024
|
+
* Error thrown when there is a mismatch between expected and actual key metadata.
|
|
3025
|
+
* This can occur during verification of either the checksum or size of a key.
|
|
3026
|
+
*
|
|
3027
|
+
* @extends Error
|
|
3028
|
+
*/
|
|
3029
|
+
class KeyVerificationError extends Error {
|
|
3030
|
+
locator;
|
|
3031
|
+
field;
|
|
3032
|
+
expected;
|
|
3033
|
+
actual;
|
|
3034
|
+
/**
|
|
3035
|
+
* Creates a new KeyVerificationError instance (error.name is "ChecksumMismatchError").
|
|
3036
|
+
*
|
|
3037
|
+
* @param {string} locator - The key locator where the mismatch occurred.
|
|
3038
|
+
* @param {"checksum" | "size"} field - The field that failed verification (either "checksum" or "size").
|
|
3039
|
+
* @param {string} expected - The expected value of the field.
|
|
3040
|
+
* @param {string} actual - The actual value encountered.
|
|
3041
|
+
*/
|
|
3042
|
+
constructor(locator, field, expected, actual) {
|
|
3043
|
+
super(`Key verification ${locator} ${field} mismatch: expected ${expected}, got ${actual}`);
|
|
3044
|
+
this.locator = locator;
|
|
3045
|
+
this.field = field;
|
|
3046
|
+
this.expected = expected;
|
|
3047
|
+
this.actual = actual;
|
|
3048
|
+
this.name = "ChecksumMismatchError";
|
|
3049
|
+
Object.setPrototypeOf(this, KeyVerificationError.prototype);
|
|
3050
|
+
}
|
|
3051
|
+
}
|
|
3052
|
+
/**
|
|
3053
|
+
* Computes the SHA-256 checksum of a given set of bytes.
|
|
3054
|
+
*
|
|
3055
|
+
* @param {Uint8Array} bytes - The bytes to compute the checksum of.
|
|
3056
|
+
*/
|
|
3057
|
+
async function sha256Hex(bytes) {
|
|
3058
|
+
const hash = await crypto.subtle.digest("SHA-256", bytes);
|
|
3059
|
+
return Array.from(new Uint8Array(hash))
|
|
3060
|
+
.map((b) => b.toString(16).padStart(2, "0"))
|
|
3061
|
+
.join("");
|
|
3062
|
+
}
|
|
3063
|
+
|
|
3064
|
+
/**
|
|
3065
|
+
* In-memory implementation of KeyVerifier that stores and verifies key fingerprints.
|
|
3066
|
+
* Provides functionality to compute and verify cryptographic checksums of keys, storing them
|
|
3067
|
+
* in memory for subsequent verification. This implementation is primarily used for testing
|
|
3068
|
+
* and development purposes where persistence is not required.
|
|
3069
|
+
*
|
|
3070
|
+
* Key features:
|
|
3071
|
+
* - Computes SHA-256 checksums and sizes for key bytes.
|
|
3072
|
+
* - Stores key fingerprints in memory using string locators.
|
|
3073
|
+
* - Verifies key bytes against stored or provided fingerprints.
|
|
3074
|
+
*
|
|
3075
|
+
* @implements {KeyVerifier}
|
|
3076
|
+
*/
|
|
3077
|
+
class MemKeyVerifier {
|
|
3078
|
+
keyStore = {};
|
|
3079
|
+
/**
|
|
3080
|
+
* Computes and optionally stores key metadata. If a keyFingerprint is provided, this function will verify the computed checksum against it before storing it.
|
|
3081
|
+
*
|
|
3082
|
+
* @param {KeyMetadata} keyMetadata - Object containing key bytes and optional verification data.
|
|
3083
|
+
* @throws {KeyVerificationError} When provided keyFingerprint doesn't match computed values.
|
|
3084
|
+
* @returns {Promise<KeyFingerprint>} Computed key metadata.
|
|
3085
|
+
*/
|
|
3086
|
+
async computeKeyMetadata(keyMetadata) {
|
|
3087
|
+
// Compute the metadata from the key bytes
|
|
3088
|
+
const computedFingerprint = {
|
|
3089
|
+
checksum: await sha256Hex(keyMetadata.keyBytes),
|
|
3090
|
+
size: keyMetadata.keyBytes.length
|
|
3091
|
+
};
|
|
3092
|
+
// If a KeyFingerprint is provided, verify it matches computed values.
|
|
3093
|
+
if (keyMetadata.fingerprint) {
|
|
3094
|
+
if (keyMetadata.fingerprint.size !== computedFingerprint.size) {
|
|
3095
|
+
throw new KeyVerificationError(keyMetadata.locator ? keyMetadata.locator : "", "size", String(keyMetadata.fingerprint.size), String(computedFingerprint.size));
|
|
3096
|
+
}
|
|
3097
|
+
if (keyMetadata.fingerprint.checksum !== computedFingerprint.checksum) {
|
|
3098
|
+
throw new KeyVerificationError(keyMetadata.locator ? keyMetadata.locator : "", "checksum", keyMetadata.fingerprint.checksum, computedFingerprint.checksum);
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
// If locator is provided, store only the fingerprint
|
|
3102
|
+
if (keyMetadata.locator) {
|
|
3103
|
+
this.keyStore[keyMetadata.locator] = computedFingerprint;
|
|
3104
|
+
}
|
|
3105
|
+
return computedFingerprint;
|
|
3106
|
+
}
|
|
3107
|
+
/**
|
|
3108
|
+
* Verifies key bytes against stored or provided metadata. Follows a priority verification scheme:
|
|
3109
|
+
* 1. If KeyFingerprint is provided in the metadata, this method verifies against that first.
|
|
3110
|
+
* 2. If a locator is provided, attempts to verify against stored fingerprint.
|
|
3111
|
+
* 3. If neither is available, throws an error.
|
|
3112
|
+
*
|
|
3113
|
+
* @param {KeyMetadata} keyMetadata - Object containing the key bytes and optional verification metadata.
|
|
3114
|
+
* @throws {Error} When neither fingerprint nor valid locator is provided for verification.
|
|
3115
|
+
* @throws {KeyVerificationError} When size or checksum verification fails.
|
|
3116
|
+
* @returns {Promise<void>} Promise that resolves when verification succeeds.
|
|
3117
|
+
*/
|
|
3118
|
+
async verifyKeyBytes(keyMetadata) {
|
|
3119
|
+
if (!keyMetadata.keyBytes) {
|
|
3120
|
+
throw new Error("Key bytes must be provided for verification.");
|
|
3121
|
+
}
|
|
3122
|
+
// Compute the fingerprint for the provided bytes.
|
|
3123
|
+
const computedFingerprint = await this.computeKeyMetadata({
|
|
3124
|
+
keyBytes: keyMetadata.keyBytes
|
|
3125
|
+
});
|
|
3126
|
+
// Determine which fingerprint to verify against.
|
|
3127
|
+
let fingerprintToVerify;
|
|
3128
|
+
if (keyMetadata.fingerprint) {
|
|
3129
|
+
// If a key fingerprint is provided, use it.
|
|
3130
|
+
fingerprintToVerify = keyMetadata.fingerprint;
|
|
3131
|
+
}
|
|
3132
|
+
else if (keyMetadata.locator) {
|
|
3133
|
+
// Otherwise try to get stored fingerprint by locator.
|
|
3134
|
+
fingerprintToVerify = this.keyStore[keyMetadata.locator];
|
|
3135
|
+
}
|
|
3136
|
+
if (!fingerprintToVerify) {
|
|
3137
|
+
throw new Error("Either fingerprint or a valid locator must be provided for verification.");
|
|
3138
|
+
}
|
|
3139
|
+
// Verify the key size.
|
|
3140
|
+
if (fingerprintToVerify.size !== computedFingerprint.size) {
|
|
3141
|
+
throw new KeyVerificationError(keyMetadata.locator || "", "size", String(fingerprintToVerify.size), String(computedFingerprint.size));
|
|
3142
|
+
}
|
|
3143
|
+
// Verify the key checksum.
|
|
3144
|
+
if (fingerprintToVerify.checksum !== computedFingerprint.checksum) {
|
|
3145
|
+
throw new KeyVerificationError(keyMetadata.locator || "", "checksum", fingerprintToVerify.checksum, computedFingerprint.checksum);
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
|
|
3150
|
+
/**
|
|
3151
|
+
* Error thrown when a key locator is invalid for filesystem use.
|
|
3152
|
+
* Used to prevent path traversal and other filesystem injection when deriving paths from locators.
|
|
3153
|
+
*
|
|
3154
|
+
* @extends Error
|
|
3155
|
+
*/
|
|
3156
|
+
class InvalidLocatorError extends Error {
|
|
3157
|
+
locator;
|
|
3158
|
+
reason;
|
|
3159
|
+
/**
|
|
3160
|
+
* @param message - Human-readable description of the validation failure.
|
|
3161
|
+
* @param locator - The invalid locator string that failed validation.
|
|
3162
|
+
* @param reason - Machine-readable reason code for the failure.
|
|
3163
|
+
*/
|
|
3164
|
+
constructor(message, locator, reason) {
|
|
3165
|
+
super(message);
|
|
3166
|
+
this.locator = locator;
|
|
3167
|
+
this.reason = reason;
|
|
3168
|
+
this.name = "InvalidLocatorError";
|
|
3169
|
+
Object.setPrototypeOf(this, InvalidLocatorError.prototype);
|
|
3380
3170
|
}
|
|
3381
3171
|
}
|
|
3382
3172
|
|
|
@@ -4294,6 +4084,7 @@ class RecordScanner {
|
|
|
4294
4084
|
viewKeys;
|
|
4295
4085
|
autoReRegister;
|
|
4296
4086
|
decryptEnabled;
|
|
4087
|
+
transport;
|
|
4297
4088
|
account;
|
|
4298
4089
|
/**
|
|
4299
4090
|
* @param {RecordScannerOptions} options Configuration for the record scanner.
|
|
@@ -4301,6 +4092,7 @@ class RecordScanner {
|
|
|
4301
4092
|
constructor(options) {
|
|
4302
4093
|
// Set the network by detecting which version of the SDK is being used.
|
|
4303
4094
|
const network = "/mainnet";
|
|
4095
|
+
this.transport = options.transport ?? defaultTransport;
|
|
4304
4096
|
// If the user has configured a network in their uri, throw.
|
|
4305
4097
|
if (options.url.endsWith("/mainnet") || options.url.endsWith("/testnet")) {
|
|
4306
4098
|
throw new Error("The record scanning url should not include the specific network, this is automatically configured by the Provable SDK.");
|
|
@@ -4441,7 +4233,7 @@ class RecordScanner {
|
|
|
4441
4233
|
headers: {
|
|
4442
4234
|
"X-Provable-API-Key": apiKey,
|
|
4443
4235
|
},
|
|
4444
|
-
});
|
|
4236
|
+
}, this.transport);
|
|
4445
4237
|
const authHeader = response.headers.get("authorization");
|
|
4446
4238
|
if (!authHeader) {
|
|
4447
4239
|
throw new Error("No authorization header in JWT refresh response");
|
|
@@ -5010,7 +4802,14 @@ class RecordScanner {
|
|
|
5010
4802
|
if (this.apiKey) {
|
|
5011
4803
|
req.headers.set(this.apiKey.header, this.apiKey.value);
|
|
5012
4804
|
}
|
|
5013
|
-
const
|
|
4805
|
+
const body = req.body ? await req.text() : undefined;
|
|
4806
|
+
const plainHeaders = {};
|
|
4807
|
+
req.headers.forEach((value, key) => { plainHeaders[key] = value; });
|
|
4808
|
+
const response = await this.transport(req.url, {
|
|
4809
|
+
method: req.method,
|
|
4810
|
+
headers: plainHeaders,
|
|
4811
|
+
body,
|
|
4812
|
+
});
|
|
5014
4813
|
// Non-2xx: throw so callers can handleRequestError or re-register on 422 if autoReRegister is enabled.
|
|
5015
4814
|
if (!response.ok) {
|
|
5016
4815
|
const text = await response.text();
|
|
@@ -5376,19 +5175,17 @@ class ProgramManager {
|
|
|
5376
5175
|
networkClient;
|
|
5377
5176
|
recordProvider;
|
|
5378
5177
|
inclusionKeysLoaded = false;
|
|
5379
|
-
_keyStore;
|
|
5380
5178
|
/** Create a new instance of the ProgramManager
|
|
5381
5179
|
*
|
|
5382
5180
|
* @param { string | undefined } host A host uri running the official Aleo API
|
|
5383
5181
|
* @param { FunctionKeyProvider | undefined } keyProvider A key provider that implements {@link FunctionKeyProvider} interface
|
|
5384
5182
|
* @param { RecordProvider | undefined } recordProvider A record provider that implements {@link RecordProvider} interface
|
|
5385
5183
|
*/
|
|
5386
|
-
constructor(host, keyProvider, recordProvider, networkClientOptions
|
|
5184
|
+
constructor(host, keyProvider, recordProvider, networkClientOptions) {
|
|
5387
5185
|
this.host = host ? host : "https://api.provable.com/v2";
|
|
5388
5186
|
this.networkClient = new AleoNetworkClient(this.host, networkClientOptions);
|
|
5389
|
-
this.keyProvider = keyProvider ? keyProvider : new AleoKeyProvider();
|
|
5187
|
+
this.keyProvider = keyProvider ? keyProvider : new AleoKeyProvider({ transport: networkClientOptions?.transport });
|
|
5390
5188
|
this.recordProvider = recordProvider;
|
|
5391
|
-
this._keyStore = keyStore;
|
|
5392
5189
|
}
|
|
5393
5190
|
/**
|
|
5394
5191
|
* Check if the fee is sufficient to pay for the transaction
|
|
@@ -5432,320 +5229,6 @@ class ProgramManager {
|
|
|
5432
5229
|
setRecordProvider(recordProvider) {
|
|
5433
5230
|
this.recordProvider = recordProvider;
|
|
5434
5231
|
}
|
|
5435
|
-
/**
|
|
5436
|
-
* Set the key store for automatic key caching across executions.
|
|
5437
|
-
*
|
|
5438
|
-
* @param {KeyStore} keyStore
|
|
5439
|
-
*/
|
|
5440
|
-
setKeyStore(keyStore) {
|
|
5441
|
-
this._keyStore = keyStore;
|
|
5442
|
-
}
|
|
5443
|
-
/**
|
|
5444
|
-
* Build a ProgramImportsBuilder from a program and its imports.
|
|
5445
|
-
* Fetches imports from the network if not provided, resolves transitive
|
|
5446
|
-
* dependencies, and optionally pre-loads cached keys from the KeyStore.
|
|
5447
|
-
*
|
|
5448
|
-
* @param loadKeys When true (default), loads cached proving/verifying keys
|
|
5449
|
-
* from the KeyStore into the builder. Set to false for authorization and
|
|
5450
|
-
* proving request paths where keys are not synthesized.
|
|
5451
|
-
*/
|
|
5452
|
-
async buildProgramImports(program, imports, loadKeys = true) {
|
|
5453
|
-
const builder = new ProgramImports();
|
|
5454
|
-
const programSource = typeof program === "string" ? program : program.toString();
|
|
5455
|
-
const programObj = Program.fromString(programSource);
|
|
5456
|
-
const importNames = programObj.getImports();
|
|
5457
|
-
if (importNames.length === 0 && (!imports || Object.keys(imports).length === 0)) {
|
|
5458
|
-
return { builder, importEditions: new Map() };
|
|
5459
|
-
}
|
|
5460
|
-
let resolvedImports = {};
|
|
5461
|
-
if (importNames.length > 0) {
|
|
5462
|
-
try {
|
|
5463
|
-
resolvedImports = await this.networkClient.getProgramImports(programSource);
|
|
5464
|
-
}
|
|
5465
|
-
catch (e) {
|
|
5466
|
-
console.warn(`Failed to resolve program imports from network: ${e}. Falling back to user-provided imports.`);
|
|
5467
|
-
}
|
|
5468
|
-
}
|
|
5469
|
-
if (imports) {
|
|
5470
|
-
resolvedImports = { ...resolvedImports, ...imports };
|
|
5471
|
-
}
|
|
5472
|
-
// Build a map of which functions each import actually calls,
|
|
5473
|
-
// so we only load keys for functions in the call chain.
|
|
5474
|
-
const calledFunctions = ProgramManager.getCalledFunctions(programSource);
|
|
5475
|
-
// Phase 1: Collect all programs via BFS, discovering transitive imports.
|
|
5476
|
-
// The initial getProgramImports call above already resolves the full
|
|
5477
|
-
// transitive closure via recursive DFS. The BFS loop here only needs
|
|
5478
|
-
// to handle user-provided imports whose transitive deps may not yet be
|
|
5479
|
-
// known. For each unknown import we issue a single getProgram() call
|
|
5480
|
-
// (not a full recursive getProgramImports) and fetch siblings in
|
|
5481
|
-
// parallel to minimize round-trips.
|
|
5482
|
-
const collected = new Map();
|
|
5483
|
-
const collectQueue = Object.entries(resolvedImports).map(([name, src]) => [name, typeof src === "string" ? src : src.toString()]);
|
|
5484
|
-
while (collectQueue.length > 0) {
|
|
5485
|
-
const [name, source] = collectQueue.shift();
|
|
5486
|
-
if (collected.has(name))
|
|
5487
|
-
continue;
|
|
5488
|
-
collected.set(name, source);
|
|
5489
|
-
// Discover transitive imports and collect called functions.
|
|
5490
|
-
// Use regex instead of Program.fromString to avoid a WASM
|
|
5491
|
-
// round-trip per import — we only need import names here.
|
|
5492
|
-
try {
|
|
5493
|
-
const subImports = ProgramManager.getImportNames(source);
|
|
5494
|
-
if (subImports.length > 0) {
|
|
5495
|
-
const transitiveCalls = ProgramManager.getCalledFunctions(source);
|
|
5496
|
-
for (const [tProgram, tFns] of transitiveCalls) {
|
|
5497
|
-
if (!calledFunctions.has(tProgram)) {
|
|
5498
|
-
calledFunctions.set(tProgram, tFns);
|
|
5499
|
-
}
|
|
5500
|
-
else {
|
|
5501
|
-
for (const fn of tFns)
|
|
5502
|
-
calledFunctions.get(tProgram).add(fn);
|
|
5503
|
-
}
|
|
5504
|
-
}
|
|
5505
|
-
// Fetch only unknown transitive imports — the source for
|
|
5506
|
-
// programs already in collected/resolvedImports is known, so
|
|
5507
|
-
// we skip them. Fetches within a BFS level run in parallel.
|
|
5508
|
-
const unknownImports = subImports.filter((id) => !collected.has(id) && !(id in resolvedImports));
|
|
5509
|
-
if (unknownImports.length > 0) {
|
|
5510
|
-
const fetched = await Promise.all(unknownImports.map(async (id) => {
|
|
5511
|
-
try {
|
|
5512
|
-
const src = await this.networkClient.getProgram(id);
|
|
5513
|
-
return [id, src];
|
|
5514
|
-
}
|
|
5515
|
-
catch {
|
|
5516
|
-
return null;
|
|
5517
|
-
}
|
|
5518
|
-
}));
|
|
5519
|
-
for (const entry of fetched) {
|
|
5520
|
-
if (entry && !collected.has(entry[0])) {
|
|
5521
|
-
collectQueue.push(entry);
|
|
5522
|
-
}
|
|
5523
|
-
}
|
|
5524
|
-
}
|
|
5525
|
-
}
|
|
5526
|
-
}
|
|
5527
|
-
catch {
|
|
5528
|
-
// Non-blocking — transitive resolution is best-effort
|
|
5529
|
-
}
|
|
5530
|
-
}
|
|
5531
|
-
// Phase 2: Add programs in topological order (leaves first).
|
|
5532
|
-
// A simple DFS post-order ensures dependencies are added before
|
|
5533
|
-
// dependents, regardless of the order collected entries arrived.
|
|
5534
|
-
const sorted = [];
|
|
5535
|
-
const visited = new Set();
|
|
5536
|
-
const visit = (name) => {
|
|
5537
|
-
if (visited.has(name))
|
|
5538
|
-
return;
|
|
5539
|
-
visited.add(name);
|
|
5540
|
-
const source = collected.get(name);
|
|
5541
|
-
if (!source)
|
|
5542
|
-
return;
|
|
5543
|
-
for (const dep of ProgramManager.getImportNames(source)) {
|
|
5544
|
-
if (collected.has(dep))
|
|
5545
|
-
visit(dep);
|
|
5546
|
-
}
|
|
5547
|
-
sorted.push([name, source]);
|
|
5548
|
-
};
|
|
5549
|
-
for (const [name] of collected)
|
|
5550
|
-
visit(name);
|
|
5551
|
-
// Resolve editions for all imports in parallel (each import may have
|
|
5552
|
-
// a different edition than the top-level program).
|
|
5553
|
-
const importEditions = new Map();
|
|
5554
|
-
await Promise.all(sorted.map(async ([name]) => {
|
|
5555
|
-
importEditions.set(name, await this.resolveEditionAndAmendment(name));
|
|
5556
|
-
}));
|
|
5557
|
-
for (const [name, source] of sorted) {
|
|
5558
|
-
if (builder.contains(name))
|
|
5559
|
-
continue;
|
|
5560
|
-
const { edition: importEdition, amendment: importAmendment } = importEditions.get(name);
|
|
5561
|
-
try {
|
|
5562
|
-
builder.addProgram(name, source, importEdition);
|
|
5563
|
-
}
|
|
5564
|
-
catch (e) {
|
|
5565
|
-
console.warn(`Failed to add import ${name} to builder: ${e}`);
|
|
5566
|
-
continue;
|
|
5567
|
-
}
|
|
5568
|
-
if (loadKeys) {
|
|
5569
|
-
const calledFns = calledFunctions.get(name);
|
|
5570
|
-
await this.loadKeysFromStore(builder, name, calledFns ? [...calledFns] : [], importEdition, importAmendment);
|
|
5571
|
-
}
|
|
5572
|
-
}
|
|
5573
|
-
return { builder, importEditions };
|
|
5574
|
-
}
|
|
5575
|
-
/**
|
|
5576
|
-
* Extract `import program_name.aleo;` names from program source via regex.
|
|
5577
|
-
* Avoids a WASM round-trip compared to Program.fromString + getImports.
|
|
5578
|
-
*/
|
|
5579
|
-
static getImportNames(programSource) {
|
|
5580
|
-
const result = [];
|
|
5581
|
-
const importPattern = /^\s*import\s+([a-zA-Z_][a-zA-Z0-9_]*\.aleo)\s*;/gm;
|
|
5582
|
-
let match;
|
|
5583
|
-
while ((match = importPattern.exec(programSource)) !== null) {
|
|
5584
|
-
result.push(match[1]);
|
|
5585
|
-
}
|
|
5586
|
-
return result;
|
|
5587
|
-
}
|
|
5588
|
-
/**
|
|
5589
|
-
* Parse `call program.aleo/function` instructions from program source
|
|
5590
|
-
* to determine which functions of each import are actually in the call chain.
|
|
5591
|
-
* Returns a map of program name -> set of called function names.
|
|
5592
|
-
*/
|
|
5593
|
-
static getCalledFunctions(programSource) {
|
|
5594
|
-
const result = new Map();
|
|
5595
|
-
const callPattern = /call\s+([a-zA-Z_][a-zA-Z0-9_]*\.aleo)\/([a-zA-Z_][a-zA-Z0-9_]*)/g;
|
|
5596
|
-
let match;
|
|
5597
|
-
while ((match = callPattern.exec(programSource)) !== null) {
|
|
5598
|
-
const programName = match[1];
|
|
5599
|
-
const functionName = match[2];
|
|
5600
|
-
if (!result.has(programName)) {
|
|
5601
|
-
result.set(programName, new Set());
|
|
5602
|
-
}
|
|
5603
|
-
result.get(programName).add(functionName);
|
|
5604
|
-
}
|
|
5605
|
-
return result;
|
|
5606
|
-
}
|
|
5607
|
-
/**
|
|
5608
|
-
* Resolve the active KeyStore, preferring the directly-set _keyStore
|
|
5609
|
-
* over the KeyProvider's keyStore().
|
|
5610
|
-
*/
|
|
5611
|
-
async resolveKeyStore() {
|
|
5612
|
-
if (this._keyStore)
|
|
5613
|
-
return this._keyStore;
|
|
5614
|
-
try {
|
|
5615
|
-
return await this.keyProvider?.keyStore?.();
|
|
5616
|
-
}
|
|
5617
|
-
catch {
|
|
5618
|
-
return undefined;
|
|
5619
|
-
}
|
|
5620
|
-
}
|
|
5621
|
-
/**
|
|
5622
|
-
* Resolve the edition and amendment count for a program from the network.
|
|
5623
|
-
* Returns `{ edition, amendment }` or falls back to `{ edition: 1, amendment: 0 }`.
|
|
5624
|
-
*/
|
|
5625
|
-
async resolveEditionAndAmendment(programName, fallbackEdition) {
|
|
5626
|
-
try {
|
|
5627
|
-
const info = await this.networkClient.getProgramAmendmentCount(programName);
|
|
5628
|
-
return { edition: info.edition, amendment: info.amendment_count };
|
|
5629
|
-
}
|
|
5630
|
-
catch (e) {
|
|
5631
|
-
console.warn(`Error finding edition/amendment for ${programName}. Network response: '${e.message}'. Defaulting to edition ${fallbackEdition ?? 1}, amendment 0.`);
|
|
5632
|
-
return { edition: fallbackEdition ?? 1, amendment: 0 };
|
|
5633
|
-
}
|
|
5634
|
-
}
|
|
5635
|
-
/**
|
|
5636
|
-
* Load cached proving/verifying keys from the KeyStore into a ProgramImportsBuilder.
|
|
5637
|
-
* Only loads keys for the specified functions — returns immediately if
|
|
5638
|
-
* functionNames is empty or undefined.
|
|
5639
|
-
* Resolves edition and amendment from the network for accurate key locator
|
|
5640
|
-
* construction when not explicitly provided.
|
|
5641
|
-
*/
|
|
5642
|
-
async loadKeysFromStore(builder, programName, functionNames, edition, amendment) {
|
|
5643
|
-
if (!functionNames || functionNames.length === 0)
|
|
5644
|
-
return;
|
|
5645
|
-
const keyStore = await this.resolveKeyStore();
|
|
5646
|
-
if (!keyStore)
|
|
5647
|
-
return;
|
|
5648
|
-
// Resolve edition and amendment from the network if not fully provided.
|
|
5649
|
-
if (edition === undefined || amendment === undefined) {
|
|
5650
|
-
const resolved = await this.resolveEditionAndAmendment(programName, edition);
|
|
5651
|
-
edition = edition ?? resolved.edition;
|
|
5652
|
-
amendment = amendment ?? resolved.amendment;
|
|
5653
|
-
}
|
|
5654
|
-
for (const fnName of functionNames) {
|
|
5655
|
-
const pkLocator = provingKeyLocator(programName, fnName, edition, amendment);
|
|
5656
|
-
const vkLocator = verifyingKeyLocator(programName, fnName, edition, amendment);
|
|
5657
|
-
try {
|
|
5658
|
-
const pk = await keyStore.getProvingKey(pkLocator);
|
|
5659
|
-
if (pk)
|
|
5660
|
-
builder.addProvingKey(programName, fnName, pk);
|
|
5661
|
-
const vk = await keyStore.getVerifyingKey(vkLocator);
|
|
5662
|
-
if (vk)
|
|
5663
|
-
builder.addVerifyingKey(programName, fnName, vk);
|
|
5664
|
-
}
|
|
5665
|
-
catch (e) {
|
|
5666
|
-
console.debug(`Failed to load keys for ${programName}/${fnName}: ${e}`);
|
|
5667
|
-
}
|
|
5668
|
-
}
|
|
5669
|
-
}
|
|
5670
|
-
/**
|
|
5671
|
-
* Persist newly synthesized keys from the returned ProgramImportsBuilder
|
|
5672
|
-
* into the KeyStore. Only writes keys that are not already in the store,
|
|
5673
|
-
* avoiding unnecessary writes of large proving keys.
|
|
5674
|
-
* Fetches each program's current edition and amendment count from the network
|
|
5675
|
-
* for accurate key locator construction.
|
|
5676
|
-
*/
|
|
5677
|
-
async persistExtractedKeys(builder, importEditions) {
|
|
5678
|
-
const keyStore = await this.resolveKeyStore();
|
|
5679
|
-
if (!keyStore)
|
|
5680
|
-
return;
|
|
5681
|
-
const programNames = Array.from(builder.programNames());
|
|
5682
|
-
// Reuse editions resolved during buildProgramImports when available,
|
|
5683
|
-
// falling back to parallel network resolution for any missing programs.
|
|
5684
|
-
const editionMap = importEditions ?? new Map();
|
|
5685
|
-
const missing = programNames.filter((name) => !editionMap.has(name));
|
|
5686
|
-
if (missing.length > 0) {
|
|
5687
|
-
await Promise.all(missing.map(async (name) => {
|
|
5688
|
-
editionMap.set(name, await this.resolveEditionAndAmendment(name));
|
|
5689
|
-
}));
|
|
5690
|
-
}
|
|
5691
|
-
for (const programName of programNames) {
|
|
5692
|
-
const { edition, amendment } = editionMap.get(programName);
|
|
5693
|
-
let fns;
|
|
5694
|
-
try {
|
|
5695
|
-
fns = Array.from(builder.functionKeysAvailable(programName));
|
|
5696
|
-
}
|
|
5697
|
-
catch (e) {
|
|
5698
|
-
console.debug(`Failed to query keys for ${programName}: ${e}`);
|
|
5699
|
-
continue;
|
|
5700
|
-
}
|
|
5701
|
-
for (const fnName of fns) {
|
|
5702
|
-
try {
|
|
5703
|
-
const pkLocator = provingKeyLocator(programName, fnName, edition, amendment);
|
|
5704
|
-
const vkLocator = verifyingKeyLocator(programName, fnName, edition, amendment);
|
|
5705
|
-
// Skip keys already in the store.
|
|
5706
|
-
if (await keyStore.has(pkLocator) && await keyStore.has(vkLocator)) {
|
|
5707
|
-
continue;
|
|
5708
|
-
}
|
|
5709
|
-
const pk = builder.getProvingKey(programName, fnName);
|
|
5710
|
-
const vk = builder.getVerifyingKey(programName, fnName);
|
|
5711
|
-
if (pk && vk) {
|
|
5712
|
-
await keyStore.setKeys(pkLocator, vkLocator, [pk, vk]);
|
|
5713
|
-
}
|
|
5714
|
-
}
|
|
5715
|
-
catch (e) {
|
|
5716
|
-
console.debug(`Failed to persist key for ${programName}/${fnName}: ${e}`);
|
|
5717
|
-
}
|
|
5718
|
-
}
|
|
5719
|
-
}
|
|
5720
|
-
}
|
|
5721
|
-
/**
|
|
5722
|
-
* Resolve top-level function keys, checking the KeyStore first and
|
|
5723
|
-
* falling back to the KeyProvider.
|
|
5724
|
-
*/
|
|
5725
|
-
async resolveTopLevelKeys(programName, functionName, keySearchParams, edition, amendment) {
|
|
5726
|
-
const keyStore = await this.resolveKeyStore();
|
|
5727
|
-
if (keyStore) {
|
|
5728
|
-
try {
|
|
5729
|
-
const pkLocator = provingKeyLocator(programName, functionName, edition, amendment);
|
|
5730
|
-
const vkLocator = verifyingKeyLocator(programName, functionName, edition, amendment);
|
|
5731
|
-
if (await keyStore.has(pkLocator) && await keyStore.has(vkLocator)) {
|
|
5732
|
-
const pk = await keyStore.getProvingKey(pkLocator);
|
|
5733
|
-
const vk = await keyStore.getVerifyingKey(vkLocator);
|
|
5734
|
-
if (pk && vk)
|
|
5735
|
-
return [pk, vk];
|
|
5736
|
-
}
|
|
5737
|
-
}
|
|
5738
|
-
catch {
|
|
5739
|
-
// Fall through to KeyProvider
|
|
5740
|
-
}
|
|
5741
|
-
}
|
|
5742
|
-
try {
|
|
5743
|
-
return (await this.keyProvider.functionKeys(keySearchParams));
|
|
5744
|
-
}
|
|
5745
|
-
catch {
|
|
5746
|
-
return undefined;
|
|
5747
|
-
}
|
|
5748
|
-
}
|
|
5749
5232
|
/**
|
|
5750
5233
|
* Set a header in the `AleoNetworkClient`s header map
|
|
5751
5234
|
*
|
|
@@ -6180,9 +5663,15 @@ class ProgramManager {
|
|
|
6180
5663
|
if (programName === undefined) {
|
|
6181
5664
|
programName = programObject.id();
|
|
6182
5665
|
}
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
5666
|
+
if (edition == undefined) {
|
|
5667
|
+
try {
|
|
5668
|
+
edition = await this.networkClient.getLatestProgramEdition(programName);
|
|
5669
|
+
}
|
|
5670
|
+
catch (e) {
|
|
5671
|
+
console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
|
|
5672
|
+
edition = 0;
|
|
5673
|
+
}
|
|
5674
|
+
}
|
|
6186
5675
|
// Get the private key from the account if it is not provided in the parameters
|
|
6187
5676
|
let executionPrivateKey = privateKey;
|
|
6188
5677
|
if (typeof privateKey === "undefined" &&
|
|
@@ -6203,19 +5692,23 @@ class ProgramManager {
|
|
|
6203
5692
|
logAndThrow(`Error finding fee keys. Key finder response: '${e.message}'. Please ensure your key provider is configured correctly.`);
|
|
6204
5693
|
}
|
|
6205
5694
|
const [feeProvingKey, feeVerifyingKey] = feeKeys;
|
|
6206
|
-
//
|
|
6207
|
-
const { builder: programImportsBuilder, importEditions } = await this.buildProgramImports(program, imports);
|
|
6208
|
-
// Include the top-level program's already-resolved edition so
|
|
6209
|
-
// persistExtractedKeys doesn't make a redundant network call for it.
|
|
6210
|
-
importEditions.set(programName, { edition: edition, amendment });
|
|
6211
|
-
// If the function proving and verifying keys are not provided, attempt to find them
|
|
5695
|
+
// If the function proving and verifying keys are not provided, attempt to find them using the key provider
|
|
6212
5696
|
if (!provingKey || !verifyingKey) {
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
[provingKey, verifyingKey] = keys;
|
|
5697
|
+
try {
|
|
5698
|
+
[provingKey, verifyingKey] = (await this.keyProvider.functionKeys(keySearchParams));
|
|
6216
5699
|
}
|
|
6217
|
-
|
|
6218
|
-
console.log(
|
|
5700
|
+
catch (e) {
|
|
5701
|
+
console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`);
|
|
5702
|
+
}
|
|
5703
|
+
}
|
|
5704
|
+
// Resolve the program imports if they exist
|
|
5705
|
+
const numberOfImports = programObject.getImports().length;
|
|
5706
|
+
if (numberOfImports > 0 && !imports) {
|
|
5707
|
+
try {
|
|
5708
|
+
imports = (await this.networkClient.getProgramImports(programName));
|
|
5709
|
+
}
|
|
5710
|
+
catch (e) {
|
|
5711
|
+
logAndThrow(`Error finding program imports. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`);
|
|
6219
5712
|
}
|
|
6220
5713
|
}
|
|
6221
5714
|
// Get the fee record from the account if it is not provided in the parameters
|
|
@@ -6251,20 +5744,8 @@ class ProgramManager {
|
|
|
6251
5744
|
}
|
|
6252
5745
|
// Auto-convert bare string inputs to field elements where the function expects field type.
|
|
6253
5746
|
const preparedInputs = this.prepareInputs(program, functionName, inputs);
|
|
6254
|
-
// Build an execution transaction
|
|
6255
|
-
|
|
6256
|
-
// interior mutability and can be persisted to the KeyStore.
|
|
6257
|
-
const result = await ProgramManager$1.buildExecutionTransaction(executionPrivateKey, program, functionName, preparedInputs, priorityFee, feeRecord, this.host, undefined, // imports (legacy Object path — builder handles resolution)
|
|
6258
|
-
provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery, edition, programImportsBuilder?.clone());
|
|
6259
|
-
// The clone passed to WASM shares state with the original via
|
|
6260
|
-
// Rc<RefCell<>> — synthesized keys are already visible.
|
|
6261
|
-
try {
|
|
6262
|
-
await this.persistExtractedKeys(programImportsBuilder, importEditions);
|
|
6263
|
-
}
|
|
6264
|
-
catch (e) {
|
|
6265
|
-
console.debug(`Failed to persist extracted keys: ${e}`);
|
|
6266
|
-
}
|
|
6267
|
-
return result;
|
|
5747
|
+
// Build an execution transaction
|
|
5748
|
+
return await ProgramManager$1.buildExecutionTransaction(executionPrivateKey, program, functionName, preparedInputs, priorityFee, feeRecord, this.host, imports, provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, offlineQuery, edition);
|
|
6268
5749
|
}
|
|
6269
5750
|
/**
|
|
6270
5751
|
* Builds an execution transaction for submission to the Aleo network from an Authorization and Fee Authorization.
|
|
@@ -6342,10 +5823,6 @@ class ProgramManager {
|
|
|
6342
5823
|
const feeAuthorization = options.feeAuthorization;
|
|
6343
5824
|
const keySearchParams = options.keySearchParams;
|
|
6344
5825
|
const offlineQuery = options.offlineQuery;
|
|
6345
|
-
let edition = options.edition;
|
|
6346
|
-
const resolved = await this.resolveEditionAndAmendment(programName, edition);
|
|
6347
|
-
edition = edition ?? resolved.edition;
|
|
6348
|
-
const { amendment } = resolved;
|
|
6349
5826
|
let provingKey = options.provingKey;
|
|
6350
5827
|
let verifyingKey = options.verifyingKey;
|
|
6351
5828
|
let program = options.program;
|
|
@@ -6374,17 +5851,24 @@ class ProgramManager {
|
|
|
6374
5851
|
logAndThrow(`Error finding fee keys. Key finder response: '${e.message}'. Please ensure your key provider is configured correctly.`);
|
|
6375
5852
|
}
|
|
6376
5853
|
const [feeProvingKey, feeVerifyingKey] = feeKeys;
|
|
6377
|
-
//
|
|
6378
|
-
const { builder: programImportsBuilder, importEditions } = await this.buildProgramImports(program, imports);
|
|
6379
|
-
importEditions.set(programName, { edition: edition, amendment });
|
|
6380
|
-
// If the function proving and verifying keys are not provided, attempt to find them.
|
|
5854
|
+
// If the function proving and verifying keys are not provided, attempt to find them using the key provider.
|
|
6381
5855
|
if (!provingKey || !verifyingKey) {
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
[provingKey, verifyingKey] = keys;
|
|
5856
|
+
try {
|
|
5857
|
+
[provingKey, verifyingKey] = (await this.keyProvider.functionKeys(keySearchParams));
|
|
6385
5858
|
}
|
|
6386
|
-
|
|
6387
|
-
console.log(
|
|
5859
|
+
catch (e) {
|
|
5860
|
+
console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`);
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
// Resolve the program imports if they exist.
|
|
5864
|
+
console.log("Resolving program imports");
|
|
5865
|
+
const numberOfImports = Program.fromString(program).getImports().length;
|
|
5866
|
+
if (numberOfImports > 0 && !imports) {
|
|
5867
|
+
try {
|
|
5868
|
+
imports = (await this.networkClient.getProgramImports(programName));
|
|
5869
|
+
}
|
|
5870
|
+
catch (e) {
|
|
5871
|
+
logAndThrow(`Error finding program imports. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`);
|
|
6388
5872
|
}
|
|
6389
5873
|
}
|
|
6390
5874
|
// If the offline query exists, add the inclusion key.
|
|
@@ -6400,20 +5884,9 @@ class ProgramManager {
|
|
|
6400
5884
|
logAndThrow(`Inclusion key bytes not loaded, please ensure the program manager is initialized with a KeyProvider that includes the inclusion key.`);
|
|
6401
5885
|
}
|
|
6402
5886
|
}
|
|
6403
|
-
// Build an execution transaction from the authorization.
|
|
6404
|
-
|
|
6405
|
-
|
|
6406
|
-
const result = await ProgramManager$1.executeAuthorization(authorization, feeAuthorization, program, provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, undefined, // imports (legacy Object path — builder handles resolution)
|
|
6407
|
-
this.host, offlineQuery, programImportsBuilder?.clone(), edition);
|
|
6408
|
-
// The builder uses interior mutability (Rc<RefCell<>>) — synthesized
|
|
6409
|
-
// keys are already visible through the caller's reference.
|
|
6410
|
-
try {
|
|
6411
|
-
await this.persistExtractedKeys(programImportsBuilder, importEditions);
|
|
6412
|
-
}
|
|
6413
|
-
catch (e) {
|
|
6414
|
-
console.debug(`Failed to persist extracted keys: ${e}`);
|
|
6415
|
-
}
|
|
6416
|
-
return result;
|
|
5887
|
+
// Build an execution transaction from the authorization.
|
|
5888
|
+
console.log("Executing authorizations");
|
|
5889
|
+
return await ProgramManager$1.executeAuthorization(authorization, feeAuthorization, program, provingKey, verifyingKey, feeProvingKey, feeVerifyingKey, imports, this.host, offlineQuery);
|
|
6417
5890
|
}
|
|
6418
5891
|
/**
|
|
6419
5892
|
* Builds a SnarkVM `Authorization` for a specific function.
|
|
@@ -6476,17 +5949,29 @@ class ProgramManager {
|
|
|
6476
5949
|
if (typeof executionPrivateKey === "undefined") {
|
|
6477
5950
|
throw "No private key provided and no private key set in the ProgramManager";
|
|
6478
5951
|
}
|
|
6479
|
-
|
|
6480
|
-
|
|
5952
|
+
if (edition == undefined) {
|
|
5953
|
+
try {
|
|
5954
|
+
edition = await this.networkClient.getLatestProgramEdition(programName);
|
|
5955
|
+
}
|
|
5956
|
+
catch (e) {
|
|
5957
|
+
console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
|
|
5958
|
+
edition = 0;
|
|
5959
|
+
}
|
|
5960
|
+
}
|
|
5961
|
+
// Resolve the program imports if they exist.
|
|
5962
|
+
const numberOfImports = Program.fromString(program).getImports().length;
|
|
5963
|
+
if (numberOfImports > 0 && !imports) {
|
|
5964
|
+
try {
|
|
5965
|
+
imports = (await this.networkClient.getProgramImports(programName));
|
|
5966
|
+
}
|
|
5967
|
+
catch (e) {
|
|
5968
|
+
logAndThrow(`Error finding program imports. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`);
|
|
5969
|
+
}
|
|
5970
|
+
}
|
|
6481
5971
|
// Auto-convert bare string inputs to field elements where the function expects field type.
|
|
6482
5972
|
const preparedInputs = this.prepareInputs(program, functionName, inputs);
|
|
6483
|
-
// Build ProgramImportsBuilder for import resolution (no key loading —
|
|
6484
|
-
// authorizations don't synthesize keys).
|
|
6485
|
-
const { builder } = await this.buildProgramImports(program, imports, false);
|
|
6486
|
-
const hasImports = !builder.isEmpty();
|
|
6487
5973
|
// Build and return an `Authorization` for the desired function.
|
|
6488
|
-
|
|
6489
|
-
return authorization;
|
|
5974
|
+
return await ProgramManager$1.authorize(executionPrivateKey, program, functionName, preparedInputs, imports, edition);
|
|
6490
5975
|
}
|
|
6491
5976
|
/**
|
|
6492
5977
|
* Builds a SnarkVM `Authorization` for a specific function without building a circuit first. This should be used when fast authorization generation is needed and the invoker is confident inputs are coorect.
|
|
@@ -6549,17 +6034,29 @@ class ProgramManager {
|
|
|
6549
6034
|
if (typeof executionPrivateKey === "undefined") {
|
|
6550
6035
|
throw "No private key provided and no private key set in the ProgramManager";
|
|
6551
6036
|
}
|
|
6552
|
-
|
|
6553
|
-
|
|
6037
|
+
// Resolve the program imports if they exist.
|
|
6038
|
+
const numberOfImports = Program.fromString(program).getImports().length;
|
|
6039
|
+
if (numberOfImports > 0 && !imports) {
|
|
6040
|
+
try {
|
|
6041
|
+
imports = (await this.networkClient.getProgramImports(programName));
|
|
6042
|
+
}
|
|
6043
|
+
catch (e) {
|
|
6044
|
+
logAndThrow(`Error finding program imports. Network response: '${e.message}'. Please ensure you're connected to a valid Aleo network and the program is deployed to the network.`);
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
if (edition == undefined) {
|
|
6048
|
+
try {
|
|
6049
|
+
edition = await this.networkClient.getLatestProgramEdition(programName);
|
|
6050
|
+
}
|
|
6051
|
+
catch (e) {
|
|
6052
|
+
console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
|
|
6053
|
+
edition = 0;
|
|
6054
|
+
}
|
|
6055
|
+
}
|
|
6554
6056
|
// Auto-convert bare string inputs to field elements where the function expects field type.
|
|
6555
6057
|
const preparedInputs = this.prepareInputs(program, functionName, inputs);
|
|
6556
|
-
// Build ProgramImportsBuilder for import resolution (no key loading —
|
|
6557
|
-
// authorizations don't synthesize keys).
|
|
6558
|
-
const { builder } = await this.buildProgramImports(program, imports, false);
|
|
6559
|
-
const hasImports = !builder.isEmpty();
|
|
6560
6058
|
// Build and return an `Authorization` for the desired function.
|
|
6561
|
-
|
|
6562
|
-
return authorization;
|
|
6059
|
+
return await ProgramManager$1.buildAuthorizationUnchecked(executionPrivateKey, program, functionName, preparedInputs, imports, edition);
|
|
6563
6060
|
}
|
|
6564
6061
|
/**
|
|
6565
6062
|
* Builds a `ProvingRequest` for submission to a prover for execution. If building a proving request with an ExecutionRequest, a private key must be explicitly provided.
|
|
@@ -6622,8 +6119,15 @@ class ProgramManager {
|
|
|
6622
6119
|
if (programName === undefined) {
|
|
6623
6120
|
programName = Program.fromString(program).id();
|
|
6624
6121
|
}
|
|
6625
|
-
|
|
6626
|
-
|
|
6122
|
+
if (edition == undefined) {
|
|
6123
|
+
try {
|
|
6124
|
+
edition = await this.networkClient.getLatestProgramEdition(programName);
|
|
6125
|
+
}
|
|
6126
|
+
catch (e) {
|
|
6127
|
+
console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
|
|
6128
|
+
edition = 0;
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6627
6131
|
// Get the private key from the account if it is not provided in the parameters.
|
|
6628
6132
|
let executionPrivateKey = privateKey;
|
|
6629
6133
|
if (typeof privateKey === "undefined" &&
|
|
@@ -6661,30 +6165,8 @@ class ProgramManager {
|
|
|
6661
6165
|
catch (e) {
|
|
6662
6166
|
logAndThrow(`Error finding fee record. Record finder response: '${e.message}'. Please ensure you're connected to a valid Aleo network and a record with enough balance exists.`);
|
|
6663
6167
|
}
|
|
6664
|
-
// Build ProgramImportsBuilder for import resolution (no key loading —
|
|
6665
|
-
// proving requests don't synthesize keys).
|
|
6666
|
-
// Note: imports is kept for the Rust-side fee estimation fallback
|
|
6667
|
-
// (estimate_fee_for_authorization uses the legacy imports Object to avoid
|
|
6668
|
-
// a RefCell double-borrow — see proving_request.rs).
|
|
6669
|
-
const { builder } = await this.buildProgramImports(program, imports, false);
|
|
6670
|
-
const hasImports = !builder.isEmpty();
|
|
6671
|
-
// Normalize imports to the full merged set from the builder so the
|
|
6672
|
-
// Rust fee estimator sees all transitive imports, not just the
|
|
6673
|
-
// caller's partial set. Use programNames + getProgram to avoid
|
|
6674
|
-
// serializing key bytes (toObject would serialize all proving/
|
|
6675
|
-
// verifying keys, which can be tens of MB).
|
|
6676
|
-
if (hasImports) {
|
|
6677
|
-
const merged = {};
|
|
6678
|
-
for (const name of Array.from(builder.programNames())) {
|
|
6679
|
-
const src = builder.getProgram(name);
|
|
6680
|
-
if (src)
|
|
6681
|
-
merged[name] = src;
|
|
6682
|
-
}
|
|
6683
|
-
imports = merged;
|
|
6684
|
-
}
|
|
6685
6168
|
if (options.executionRequest instanceof ExecutionRequest) {
|
|
6686
|
-
return await ProgramManager$1.buildProvingRequestFromExecutionRequest(options.executionRequest, program, unchecked, broadcast, edition, imports,
|
|
6687
|
-
executionPrivateKey, hasImports ? builder?.clone() : undefined);
|
|
6169
|
+
return await ProgramManager$1.buildProvingRequestFromExecutionRequest(options.executionRequest, program, unchecked, broadcast, edition, imports, executionPrivateKey);
|
|
6688
6170
|
}
|
|
6689
6171
|
else {
|
|
6690
6172
|
// Ensure the private key exists.
|
|
@@ -6698,8 +6180,7 @@ class ProgramManager {
|
|
|
6698
6180
|
// Auto-convert bare string inputs to field elements where the function expects field type.
|
|
6699
6181
|
const preparedInputs = this.prepareInputs(program, functionName, inputs);
|
|
6700
6182
|
// Build and return the `ProvingRequest`.
|
|
6701
|
-
return await ProgramManager$1.buildProvingRequest(executionPrivateKey, program, functionName, preparedInputs, baseFee, priorityFee, feeRecord, imports,
|
|
6702
|
-
broadcast, unchecked, edition, useFeeMaster, hasImports ? builder?.clone() : undefined);
|
|
6183
|
+
return await ProgramManager$1.buildProvingRequest(executionPrivateKey, program, functionName, preparedInputs, baseFee, priorityFee, feeRecord, imports, broadcast, unchecked, edition, useFeeMaster);
|
|
6703
6184
|
}
|
|
6704
6185
|
}
|
|
6705
6186
|
/**
|
|
@@ -6872,10 +6353,6 @@ class ProgramManager {
|
|
|
6872
6353
|
* assert(result === ["10u32"]);
|
|
6873
6354
|
*/
|
|
6874
6355
|
async run(program, function_name, inputs, proveExecution, imports, keySearchParams, provingKey, verifyingKey, privateKey, offlineQuery, edition) {
|
|
6875
|
-
const programName = Program.fromString(program).id();
|
|
6876
|
-
const resolved = await this.resolveEditionAndAmendment(programName, edition);
|
|
6877
|
-
edition = edition ?? resolved.edition;
|
|
6878
|
-
const { amendment } = resolved;
|
|
6879
6356
|
// Get the private key from the account if it is not provided in the parameters
|
|
6880
6357
|
let executionPrivateKey = privateKey;
|
|
6881
6358
|
if (typeof privateKey === "undefined" &&
|
|
@@ -6885,33 +6362,22 @@ class ProgramManager {
|
|
|
6885
6362
|
if (typeof executionPrivateKey === "undefined") {
|
|
6886
6363
|
throw "No private key provided and no private key set in the ProgramManager";
|
|
6887
6364
|
}
|
|
6888
|
-
//
|
|
6889
|
-
const { builder, importEditions } = await this.buildProgramImports(program, imports);
|
|
6890
|
-
importEditions.set(programName, { edition: edition, amendment });
|
|
6365
|
+
// If the function proving and verifying keys are not provided, attempt to find them using the key provider
|
|
6891
6366
|
if (!provingKey || !verifyingKey) {
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
[provingKey, verifyingKey] = keys;
|
|
6367
|
+
try {
|
|
6368
|
+
[provingKey, verifyingKey] = (await this.keyProvider.functionKeys(keySearchParams));
|
|
6895
6369
|
}
|
|
6896
|
-
|
|
6897
|
-
console.log(
|
|
6370
|
+
catch (e) {
|
|
6371
|
+
console.log(`Function keys not found. Key finder response: '${e}'. The function keys will be synthesized`);
|
|
6898
6372
|
}
|
|
6899
6373
|
}
|
|
6900
6374
|
// Auto-convert bare string inputs to field elements where the function expects field type.
|
|
6901
6375
|
const preparedInputs = this.prepareInputs(program, function_name, inputs);
|
|
6902
|
-
// Run the program offline
|
|
6903
|
-
|
|
6904
|
-
|
|
6905
|
-
|
|
6906
|
-
|
|
6907
|
-
// Rc<RefCell<>> — synthesized keys are already visible.
|
|
6908
|
-
try {
|
|
6909
|
-
await this.persistExtractedKeys(builder, importEditions);
|
|
6910
|
-
}
|
|
6911
|
-
catch (e) {
|
|
6912
|
-
console.debug(`Failed to persist extracted keys: ${e}`);
|
|
6913
|
-
}
|
|
6914
|
-
return result;
|
|
6376
|
+
// Run the program offline and return the result
|
|
6377
|
+
console.log("Running program offline");
|
|
6378
|
+
console.log("Proving key: ", provingKey);
|
|
6379
|
+
console.log("Verifying key: ", verifyingKey);
|
|
6380
|
+
return ProgramManager$1.executeFunctionOffline(executionPrivateKey, program, function_name, preparedInputs, proveExecution, false, imports, provingKey, verifyingKey, this.host, offlineQuery, edition);
|
|
6915
6381
|
}
|
|
6916
6382
|
/**
|
|
6917
6383
|
* Join two credits records into a single credits record
|
|
@@ -8013,8 +7479,12 @@ class ProgramManager {
|
|
|
8013
7479
|
throw new Error("Authorization must be provided if estimating fee for Authorization.");
|
|
8014
7480
|
}
|
|
8015
7481
|
const programSource = program ? program.toString() : await this.networkClient.getProgram(programName, edition);
|
|
8016
|
-
const programImports = imports
|
|
8017
|
-
|
|
7482
|
+
const programImports = imports ? imports : await this.networkClient.getProgramImports(programSource);
|
|
7483
|
+
console.log(JSON.stringify(programImports));
|
|
7484
|
+
if (Object.keys(programImports)) {
|
|
7485
|
+
return ProgramManager$1.estimateFeeForAuthorization(authorization, programSource, programImports, edition);
|
|
7486
|
+
}
|
|
7487
|
+
return ProgramManager$1.estimateFeeForAuthorization(authorization, programSource, imports, edition);
|
|
8018
7488
|
}
|
|
8019
7489
|
/**
|
|
8020
7490
|
* Estimate the execution fee for an Aleo function.
|
|
@@ -8160,8 +7630,15 @@ class ProgramManager {
|
|
|
8160
7630
|
if (programName === undefined) {
|
|
8161
7631
|
programName = programObject.id();
|
|
8162
7632
|
}
|
|
8163
|
-
|
|
8164
|
-
|
|
7633
|
+
if (edition == undefined) {
|
|
7634
|
+
try {
|
|
7635
|
+
edition = await this.networkClient.getLatestProgramEdition(programName);
|
|
7636
|
+
}
|
|
7637
|
+
catch (e) {
|
|
7638
|
+
console.warn(`Error finding edition for ${programName}. Network response: '${e.message}'. Assuming edition 0.`);
|
|
7639
|
+
edition = 0;
|
|
7640
|
+
}
|
|
7641
|
+
}
|
|
8165
7642
|
// Get the private key from the account if it is not provided in the parameters.
|
|
8166
7643
|
let executionPrivateKey = privateKey;
|
|
8167
7644
|
if (typeof privateKey === "undefined" &&
|
|
@@ -8746,5 +8223,5 @@ async function initializeWasm() {
|
|
|
8746
8223
|
console.warn("initializeWasm is deprecated, you no longer need to use it");
|
|
8747
8224
|
}
|
|
8748
8225
|
|
|
8749
|
-
export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KeyVerificationError as ChecksumMismatchError, DecryptionNotEnabledError,
|
|
8226
|
+
export { Account, AleoKeyProvider, AleoKeyProviderParams, AleoNetworkClient, BlockHeightSearch, CREDITS_PROGRAM_KEYS, KeyVerificationError as ChecksumMismatchError, DecryptionNotEnabledError, InvalidLocatorError, KEY_STORE, KeyVerificationError, MemKeyVerifier, NetworkRecordProvider, OfflineKeyProvider, OfflineSearchParams, PRIVATE_TO_PUBLIC_TRANSFER, PRIVATE_TRANSFER, PRIVATE_TRANSFER_TYPES, PUBLIC_TO_PRIVATE_TRANSFER, PUBLIC_TRANSFER, PUBLIC_TRANSFER_AS_SIGNER, ProgramManager, RECORD_DOMAIN, RecordNotFoundError, RecordScanner, RecordScannerRequestError, SealanceMerkleTree, UUIDError, VALID_TRANSFER_TYPES, ViewKeyNotStoredError, buildExecutionRequestFromExternallySignedData, computeExternalSigningInputs, encryptAuthorization, encryptProvingRequest, encryptRegistrationRequest, encryptViewKey, initializeWasm, inputsToFields, isInputIdStrategy, isProveApiErrorBody, isProvingResponse, isRecordViewKeyStrategy, isViewKeyStrategy, logAndThrow, provingKeyLocator, sha256Hex, toAddress, toField, toGroup, toSignature, toViewKey, translationKeyLocator, verifyBatchProof, verifyProof, verifyingKeyLocator, zeroizeBytes };
|
|
8750
8227
|
//# sourceMappingURL=browser.js.map
|