pshenmic-dpp 2.0.0-dev.23 → 2.0.0-dev.25
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/binaries/bindingsTypes.d.ts +8 -8
- package/dist/binaries/memory.cjs +7 -0
- package/dist/binaries/memory.d.cts +2 -0
- package/dist/binaries/native/aarch64-apple-darwin/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/aarch64-unknown-linux-gnu/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/aarch64-unknown-linux-musl/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/x86_64-apple-darwin/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/x86_64-unknown-linux-gnu/pshenmic_dpp.node +0 -0
- package/dist/binaries/native/x86_64-unknown-linux-musl/pshenmic_dpp.node +0 -0
- package/dist/binaries/pshenmic_dpp.android.node/arm64-v8a/libpshenmic_dpp.so +0 -0
- package/dist/binaries/pshenmic_dpp.apple.node/ios-arm64-simulator/libpshenmic_dpp.framework/libpshenmic_dpp +0 -0
- package/dist/binaries/wasm/wasmBytes.cjs +2 -1
- package/dist/binaries/wasm/wasmBytes.d.cts +2 -1
- package/dist/binaries/wasm/workerBundle.cjs +6 -0
- package/dist/binaries/wasm/workerBundle.d.cts +2 -0
- package/dist/binaries/wasmCreation.cjs +119 -38
- package/dist/binaries/wasmCreation.d.cts +2 -0
- package/dist/src/dpp/structs/Orchard/OrchardProver.d.ts +7 -0
- package/dist/src/dpp/structs/Orchard/OrchardProver.js +17 -1
- package/dist/src/dpp/structs/Orchard/ShieldedBuilder.d.ts +13 -6
- package/dist/src/dpp/structs/Orchard/ShieldedBuilder.js +29 -13
- package/package.json +1 -1
- package/tests/unit/Shielded.spec.ts +8 -6
- package/tests/unit/WebAssembly.spec.ts +40 -1
|
@@ -1,46 +1,127 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const { WASI } = require('@tybys/wasm-util');
|
|
3
3
|
const { getDefaultContext } = require('@emnapi/runtime');
|
|
4
|
-
const { instantiateNapiModuleSync } = require('@emnapi/core');
|
|
5
|
-
const { bytes } = require('./wasm/wasmBytes.cjs');
|
|
6
|
-
const { decode } = require('../utils/base122.cjs');
|
|
7
|
-
const { decompressSync } = require('fflate');
|
|
8
|
-
const wasmBytes = new Uint8Array(decode(bytes));
|
|
9
|
-
const wasi = new WASI({
|
|
10
|
-
version: 'preview1',
|
|
11
|
-
print: function () {
|
|
12
|
-
console.log.apply(console, arguments);
|
|
13
|
-
},
|
|
14
|
-
printErr: function () {
|
|
15
|
-
console.error.apply(console, arguments);
|
|
16
|
-
}
|
|
17
|
-
});
|
|
4
|
+
const { instantiateNapiModuleSync, MessageHandler } = require('@emnapi/core');
|
|
18
5
|
const emnapiContext = getDefaultContext();
|
|
19
6
|
emnapiContext.feature.supportNewFunction = false;
|
|
20
7
|
emnapiContext.feature.supportBigInt = false;
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
8
|
+
const isNode = typeof process !== 'undefined' && process.versions != null && process.versions.node != null;
|
|
9
|
+
const nodeWorkerThreads = isNode ? require('worker_threads') : null;
|
|
10
|
+
const isWorker = isNode
|
|
11
|
+
? !nodeWorkerThreads.isMainThread
|
|
12
|
+
: (typeof self !== 'undefined' && !self.document);
|
|
13
|
+
if (isWorker) {
|
|
14
|
+
// wasi pthread worker: the main thread posts the compiled module + shared
|
|
15
|
+
// memory here and this instantiates a child-thread copy over them. Async
|
|
16
|
+
// `#[napi]` fns (the Halo 2 proving stack) run on these threads.
|
|
17
|
+
const postMsg = isNode
|
|
18
|
+
? (d) => nodeWorkerThreads.parentPort.postMessage(d)
|
|
19
|
+
: (d) => self.postMessage(d);
|
|
20
|
+
if (isNode) {
|
|
21
|
+
// emnapi's threadsafe-function dispatch calls the bare global
|
|
22
|
+
// `postMessage` from pthread contexts (a Web Worker global); Node
|
|
23
|
+
// worker_threads doesn't have it, so polyfill with parentPort.
|
|
24
|
+
globalThis.self = globalThis;
|
|
25
|
+
globalThis.postMessage = postMsg;
|
|
26
|
+
}
|
|
27
|
+
const handler = new MessageHandler({
|
|
28
|
+
postMessage: postMsg,
|
|
29
|
+
onLoad({ wasmModule, wasmMemory }) {
|
|
30
|
+
const wasi = new WASI({ version: 'preview1' });
|
|
31
|
+
return instantiateNapiModuleSync(wasmModule, {
|
|
32
|
+
childThread: true,
|
|
33
|
+
wasi,
|
|
34
|
+
context: emnapiContext,
|
|
35
|
+
postMessage: postMsg,
|
|
36
|
+
overwriteImports(importObject) {
|
|
37
|
+
importObject.env = {
|
|
38
|
+
...importObject.env,
|
|
39
|
+
...importObject.napi,
|
|
40
|
+
...importObject.emnapi,
|
|
41
|
+
memory: wasmMemory
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
42
45
|
}
|
|
46
|
+
});
|
|
47
|
+
if (isNode) {
|
|
48
|
+
nodeWorkerThreads.parentPort.on('message', (data) => handler.handle({ data }));
|
|
43
49
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
50
|
+
else {
|
|
51
|
+
self.onmessage = (e) => handler.handle({ data: e.data });
|
|
52
|
+
}
|
|
53
|
+
module.exports = null;
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
// Main thread only. This block must NEVER run in a worker: it decodes,
|
|
57
|
+
// decompresses and sync-compiles the whole 7.5MB module and allocates a
|
|
58
|
+
// fresh 64MB shared memory — workers receive the already-compiled module
|
|
59
|
+
// and the real memory via the 'load' message instead. Running it per
|
|
60
|
+
// worker multiplies init time by the core count (rayon spawns one thread
|
|
61
|
+
// per core while building the proving key).
|
|
62
|
+
const { bytes } = require('./wasm/wasmBytes.cjs');
|
|
63
|
+
const { decode } = require('../utils/base122.cjs');
|
|
64
|
+
const { decompressSync } = require('fflate');
|
|
65
|
+
const { default: sharedMemory } = require('./memory.cjs');
|
|
66
|
+
const wasmBytes = new Uint8Array(decode(bytes));
|
|
67
|
+
const wasi = new WASI({
|
|
68
|
+
version: 'preview1',
|
|
69
|
+
print: function () {
|
|
70
|
+
console.log.apply(console, arguments);
|
|
71
|
+
},
|
|
72
|
+
printErr: function () {
|
|
73
|
+
console.error.apply(console, arguments);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
let workerBlobUrl;
|
|
77
|
+
const wasm = instantiateNapiModuleSync(decompressSync(wasmBytes), {
|
|
78
|
+
context: emnapiContext,
|
|
79
|
+
wasi,
|
|
80
|
+
// Threads are spawned lazily (first async `#[napi]` call), so
|
|
81
|
+
// instantiation stays synchronous: emnapi only forbids sync loading
|
|
82
|
+
// with a PREloaded worker pool (`reuseWorker.size > 0`). `true` keeps
|
|
83
|
+
// size 0 but returns finished workers to a pool instead of
|
|
84
|
+
// terminating them, so repeated proving calls reuse them.
|
|
85
|
+
reuseWorker: true,
|
|
86
|
+
onCreateWorker() {
|
|
87
|
+
if (isNode) {
|
|
88
|
+
return new nodeWorkerThreads.Worker(__filename);
|
|
89
|
+
}
|
|
90
|
+
// Escape hatch for hosts that want to control worker creation
|
|
91
|
+
// (e.g. strict CSP environments where blob: workers are forbidden).
|
|
92
|
+
if (typeof globalThis.__PSHENMIC_DPP_CREATE_WORKER__ === 'function') {
|
|
93
|
+
return globalThis.__PSHENMIC_DPP_CREATE_WORKER__();
|
|
94
|
+
}
|
|
95
|
+
if (typeof Worker === 'undefined') {
|
|
96
|
+
throw new Error('Cannot create a wasm thread worker: no Worker constructor in this environment. ' +
|
|
97
|
+
'Provide globalThis.__PSHENMIC_DPP_CREATE_WORKER__ returning a Worker running workerBundle.cjs `source`.');
|
|
98
|
+
}
|
|
99
|
+
// Self-contained worker (all emnapi deps inlined) spawned from a Blob
|
|
100
|
+
// URL, so it survives being bundled into a single file: the worker
|
|
101
|
+
// receives the compiled module + shared memory via postMessage and
|
|
102
|
+
// needs no access to this script's URL or the wasm bytes.
|
|
103
|
+
if (workerBlobUrl === undefined) {
|
|
104
|
+
const { source } = require('./wasm/workerBundle.cjs');
|
|
105
|
+
workerBlobUrl = URL.createObjectURL(new Blob([source], { type: 'text/javascript' }));
|
|
106
|
+
}
|
|
107
|
+
return new Worker(workerBlobUrl, { name: 'pshenmic-dpp-wasm-thread' });
|
|
108
|
+
},
|
|
109
|
+
overwriteImports(importObject) {
|
|
110
|
+
importObject.env = {
|
|
111
|
+
...importObject.env,
|
|
112
|
+
...importObject.napi,
|
|
113
|
+
...importObject.emnapi,
|
|
114
|
+
memory: sharedMemory
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
beforeInit({ instance }) {
|
|
118
|
+
for (const name of Object.keys(instance.exports)) {
|
|
119
|
+
if (name.startsWith('__napi_register__')) {
|
|
120
|
+
instance.exports[name]();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
module.exports = wasm.napiModule.exports;
|
|
126
|
+
module.exports.default = wasm.napiModule.exports;
|
|
127
|
+
}
|
|
@@ -7,6 +7,13 @@ import type { OrchardProverNAPI } from '../../../../binaries/bindingsTypes.js';
|
|
|
7
7
|
export declare class OrchardProverWASM {
|
|
8
8
|
/** @private **/
|
|
9
9
|
_rawOrchardProver: OrchardProverNAPI;
|
|
10
|
+
/**
|
|
11
|
+
* The proving key is deterministic and expensive (~10s), so it's built
|
|
12
|
+
* once per process and shared by every prover instance. Cleared on
|
|
13
|
+
* failure so a failed init can be retried.
|
|
14
|
+
*/
|
|
15
|
+
private static _initPromise;
|
|
10
16
|
constructor();
|
|
17
|
+
init(): Promise<void>;
|
|
11
18
|
static createFromRawInstance(rawInstance: OrchardProverNAPI): OrchardProverWASM;
|
|
12
19
|
}
|
|
@@ -7,8 +7,24 @@ import { dppProvider } from '../../provider.js';
|
|
|
7
7
|
export class OrchardProverWASM {
|
|
8
8
|
/** @private **/
|
|
9
9
|
_rawOrchardProver;
|
|
10
|
+
/**
|
|
11
|
+
* The proving key is deterministic and expensive (~10s), so it's built
|
|
12
|
+
* once per process and shared by every prover instance. Cleared on
|
|
13
|
+
* failure so a failed init can be retried.
|
|
14
|
+
*/
|
|
15
|
+
static _initPromise = null;
|
|
10
16
|
constructor() {
|
|
11
|
-
|
|
17
|
+
// empty
|
|
18
|
+
}
|
|
19
|
+
async init() {
|
|
20
|
+
if (OrchardProverWASM._initPromise == null) {
|
|
21
|
+
OrchardProverWASM._initPromise = dppProvider.dpp.OrchardProverNAPI.init()
|
|
22
|
+
.catch((e) => {
|
|
23
|
+
OrchardProverWASM._initPromise = null;
|
|
24
|
+
throw e;
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
this._rawOrchardProver = await OrchardProverWASM._initPromise;
|
|
12
28
|
}
|
|
13
29
|
static createFromRawInstance(rawInstance) {
|
|
14
30
|
const instance = Object.create(OrchardProverWASM.prototype);
|
|
@@ -24,17 +24,24 @@ import { IdentityCreateFromShieldedPoolResultWASM } from './IdentityCreateFromSh
|
|
|
24
24
|
export declare class ShieldedBuilderWASM {
|
|
25
25
|
/** @private **/
|
|
26
26
|
_rawShieldedBuilder: ShieldedBuilderNAPI;
|
|
27
|
+
/**
|
|
28
|
+
* Building the Halo 2 proving key takes ~10s, and the key is deterministic,
|
|
29
|
+
* so it's built once per process: every builder instance shares the same
|
|
30
|
+
* raw builder. Cleared on failure so a failed init can be retried.
|
|
31
|
+
*/
|
|
32
|
+
private static _initPromise;
|
|
27
33
|
constructor();
|
|
34
|
+
init(): Promise<void>;
|
|
28
35
|
/** Asset lock -> pool (deposit). */
|
|
29
|
-
shieldFromAssetLock(recipient: OrchardAddressWASM, shieldAmount: bigint, assetLockProof: AssetLockProofWASM, privateKey: PrivateKeyWASM, memo: ShieldedMemoWASM, dummyOutputs: number, senderOvk?: Uint8Array, surplusOutput?: PlatformAddressLike, platformVersion?: PlatformVersionNAPI): StateTransitionWASM
|
|
36
|
+
shieldFromAssetLock(recipient: OrchardAddressWASM, shieldAmount: bigint, assetLockProof: AssetLockProofWASM, privateKey: PrivateKeyWASM, memo: ShieldedMemoWASM, dummyOutputs: number, senderOvk?: Uint8Array, surplusOutput?: PlatformAddressLike, platformVersion?: PlatformVersionNAPI): Promise<StateTransitionWASM>;
|
|
30
37
|
/** Transparent platform addresses -> pool (deposit). One private key per input. */
|
|
31
|
-
shield(recipient: OrchardAddressWASM, shieldAmount: bigint, inputs: InputAddressWASM[], privateKeys: PrivateKeyWASM[], feeStrategy: AddressFundsFeeStrategyStepWASM[], userFeeIncrease: number, memo: ShieldedMemoWASM, senderOvk?: Uint8Array, platformVersion?: PlatformVersionNAPI): StateTransitionWASM
|
|
38
|
+
shield(recipient: OrchardAddressWASM, shieldAmount: bigint, inputs: InputAddressWASM[], privateKeys: PrivateKeyWASM[], feeStrategy: AddressFundsFeeStrategyStepWASM[], userFeeIncrease: number, memo: ShieldedMemoWASM, senderOvk?: Uint8Array, platformVersion?: PlatformVersionNAPI): Promise<StateTransitionWASM>;
|
|
32
39
|
/** Pool -> core L1 (spend). */
|
|
33
|
-
shieldedWithdrawal(spends: SpendableNoteWASM[], withdrawalAmount: bigint, outputScript: CoreScriptWASM, coreFeePerByte: number, pooling: PoolingLike, changeAddress: OrchardAddressWASM, seed: Uint8Array, coinType: number, account: number, anchor: Uint8Array, memo: ShieldedMemoWASM, platformVersion?: PlatformVersionNAPI): ShieldedWithdrawalResultWASM
|
|
40
|
+
shieldedWithdrawal(spends: SpendableNoteWASM[], withdrawalAmount: bigint, outputScript: CoreScriptWASM, coreFeePerByte: number, pooling: PoolingLike, changeAddress: OrchardAddressWASM, seed: Uint8Array, coinType: number, account: number, anchor: Uint8Array, memo: ShieldedMemoWASM, platformVersion?: PlatformVersionNAPI): Promise<ShieldedWithdrawalResultWASM>;
|
|
34
41
|
/** Pool -> platform identity balance (spend). */
|
|
35
|
-
unshield(spends: SpendableNoteWASM[], outputAddress: PlatformAddressLike, unshieldAmount: bigint, changeAddress: OrchardAddressWASM, seed: Uint8Array, coinType: number, account: number, anchor: Uint8Array, memo: ShieldedMemoWASM, platformVersion?: PlatformVersionNAPI): ShieldedWithdrawalResultWASM
|
|
42
|
+
unshield(spends: SpendableNoteWASM[], outputAddress: PlatformAddressLike, unshieldAmount: bigint, changeAddress: OrchardAddressWASM, seed: Uint8Array, coinType: number, account: number, anchor: Uint8Array, memo: ShieldedMemoWASM, platformVersion?: PlatformVersionNAPI): Promise<ShieldedWithdrawalResultWASM>;
|
|
36
43
|
/** Pool -> pool (spend). */
|
|
37
|
-
shieldedTransfer(spends: SpendableNoteWASM[], recipient: OrchardAddressWASM, transferAmount: bigint, changeAddress: OrchardAddressWASM, seed: Uint8Array, coinType: number, account: number, anchor: Uint8Array, memo: ShieldedMemoWASM, platformVersion?: PlatformVersionNAPI): ShieldedWithdrawalResultWASM
|
|
44
|
+
shieldedTransfer(spends: SpendableNoteWASM[], recipient: OrchardAddressWASM, transferAmount: bigint, changeAddress: OrchardAddressWASM, seed: Uint8Array, coinType: number, account: number, anchor: Uint8Array, memo: ShieldedMemoWASM, platformVersion?: PlatformVersionNAPI): Promise<ShieldedWithdrawalResultWASM>;
|
|
38
45
|
/** Pool -> new identity (spend). One private key per public key, same order. */
|
|
39
|
-
identityCreateFromShieldedPool(publicKeys: IdentityPublicKeyInCreationWASM[], privateKeys: PrivateKeyWASM[], denomination: bigint, sendToAddressOnCreationFailure: PlatformAddressLike, spends: SpendableNoteWASM[], changeAddress: OrchardAddressWASM, seed: Uint8Array, coinType: number, account: number, anchor: Uint8Array, memo: ShieldedMemoWASM, platformVersion?: PlatformVersionNAPI): IdentityCreateFromShieldedPoolResultWASM
|
|
46
|
+
identityCreateFromShieldedPool(publicKeys: IdentityPublicKeyInCreationWASM[], privateKeys: PrivateKeyWASM[], denomination: bigint, sendToAddressOnCreationFailure: PlatformAddressLike, spends: SpendableNoteWASM[], changeAddress: OrchardAddressWASM, seed: Uint8Array, coinType: number, account: number, anchor: Uint8Array, memo: ShieldedMemoWASM, platformVersion?: PlatformVersionNAPI): Promise<IdentityCreateFromShieldedPoolResultWASM>;
|
|
40
47
|
}
|
|
@@ -15,31 +15,47 @@ import { IdentityCreateFromShieldedPoolResultWASM } from './IdentityCreateFromSh
|
|
|
15
15
|
export class ShieldedBuilderWASM {
|
|
16
16
|
/** @private **/
|
|
17
17
|
_rawShieldedBuilder;
|
|
18
|
+
/**
|
|
19
|
+
* Building the Halo 2 proving key takes ~10s, and the key is deterministic,
|
|
20
|
+
* so it's built once per process: every builder instance shares the same
|
|
21
|
+
* raw builder. Cleared on failure so a failed init can be retried.
|
|
22
|
+
*/
|
|
23
|
+
static _initPromise = null;
|
|
18
24
|
constructor() {
|
|
19
|
-
|
|
25
|
+
// empty
|
|
26
|
+
}
|
|
27
|
+
async init() {
|
|
28
|
+
if (ShieldedBuilderWASM._initPromise == null) {
|
|
29
|
+
ShieldedBuilderWASM._initPromise = dppProvider.dpp.ShieldedBuilderNAPI.init()
|
|
30
|
+
.catch((e) => {
|
|
31
|
+
ShieldedBuilderWASM._initPromise = null;
|
|
32
|
+
throw e;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
this._rawShieldedBuilder = await ShieldedBuilderWASM._initPromise;
|
|
20
36
|
}
|
|
21
37
|
/** Asset lock -> pool (deposit). */
|
|
22
|
-
shieldFromAssetLock(recipient, shieldAmount, assetLockProof, privateKey, memo, dummyOutputs, senderOvk, surplusOutput, platformVersion) {
|
|
23
|
-
return StateTransitionWASM.createFromRawInstance(this._rawShieldedBuilder.shieldFromAssetLock(recipient._rawOrchardAddress, shieldAmount.toString(), assetLockProof._rawAssetLockProof, privateKey._rawPrivateKey, memo._rawShieldedMemo, dummyOutputs, senderOvk, surplusOutput != null ? preparePlatformAddressValue(surplusOutput) : undefined, platformVersion));
|
|
38
|
+
async shieldFromAssetLock(recipient, shieldAmount, assetLockProof, privateKey, memo, dummyOutputs, senderOvk, surplusOutput, platformVersion) {
|
|
39
|
+
return StateTransitionWASM.createFromRawInstance(await this._rawShieldedBuilder.shieldFromAssetLock(recipient._rawOrchardAddress, shieldAmount.toString(), assetLockProof._rawAssetLockProof, privateKey._rawPrivateKey, memo._rawShieldedMemo, dummyOutputs, senderOvk, surplusOutput != null ? preparePlatformAddressValue(surplusOutput) : undefined, platformVersion));
|
|
24
40
|
}
|
|
25
41
|
/** Transparent platform addresses -> pool (deposit). One private key per input. */
|
|
26
|
-
shield(recipient, shieldAmount, inputs, privateKeys, feeStrategy, userFeeIncrease, memo, senderOvk, platformVersion) {
|
|
27
|
-
return StateTransitionWASM.createFromRawInstance(this._rawShieldedBuilder.shield(recipient._rawOrchardAddress, shieldAmount.toString(), inputs.map(i => i._rawInputAddress), privateKeys.map(k => k._rawPrivateKey), feeStrategy.map(s => s._rawAddressFundsFeeStrategyStep), userFeeIncrease, memo._rawShieldedMemo, senderOvk, platformVersion));
|
|
42
|
+
async shield(recipient, shieldAmount, inputs, privateKeys, feeStrategy, userFeeIncrease, memo, senderOvk, platformVersion) {
|
|
43
|
+
return StateTransitionWASM.createFromRawInstance(await this._rawShieldedBuilder.shield(recipient._rawOrchardAddress, shieldAmount.toString(), inputs.map(i => i._rawInputAddress), privateKeys.map(k => k._rawPrivateKey), feeStrategy.map(s => s._rawAddressFundsFeeStrategyStep), userFeeIncrease, memo._rawShieldedMemo, senderOvk, platformVersion));
|
|
28
44
|
}
|
|
29
45
|
/** Pool -> core L1 (spend). */
|
|
30
|
-
shieldedWithdrawal(spends, withdrawalAmount, outputScript, coreFeePerByte, pooling, changeAddress, seed, coinType, account, anchor, memo, platformVersion) {
|
|
31
|
-
return ShieldedWithdrawalResultWASM.createFromRawInstance(this._rawShieldedBuilder.shieldedWithdrawal(spends.map(s => s._rawSpendableNote), withdrawalAmount.toString(), outputScript._rawCoreScript, coreFeePerByte, valueToDynamicValue(pooling), changeAddress._rawOrchardAddress, seed, coinType, account, anchor, memo._rawShieldedMemo, platformVersion));
|
|
46
|
+
async shieldedWithdrawal(spends, withdrawalAmount, outputScript, coreFeePerByte, pooling, changeAddress, seed, coinType, account, anchor, memo, platformVersion) {
|
|
47
|
+
return ShieldedWithdrawalResultWASM.createFromRawInstance(await this._rawShieldedBuilder.shieldedWithdrawal(spends.map(s => s._rawSpendableNote), withdrawalAmount.toString(), outputScript._rawCoreScript, coreFeePerByte, valueToDynamicValue(pooling), changeAddress._rawOrchardAddress, seed, coinType, account, anchor, memo._rawShieldedMemo, platformVersion));
|
|
32
48
|
}
|
|
33
49
|
/** Pool -> platform identity balance (spend). */
|
|
34
|
-
unshield(spends, outputAddress, unshieldAmount, changeAddress, seed, coinType, account, anchor, memo, platformVersion) {
|
|
35
|
-
return ShieldedWithdrawalResultWASM.createFromRawInstance(this._rawShieldedBuilder.unshield(spends.map(s => s._rawSpendableNote), preparePlatformAddressValue(outputAddress), unshieldAmount.toString(), changeAddress._rawOrchardAddress, seed, coinType, account, anchor, memo._rawShieldedMemo, platformVersion));
|
|
50
|
+
async unshield(spends, outputAddress, unshieldAmount, changeAddress, seed, coinType, account, anchor, memo, platformVersion) {
|
|
51
|
+
return ShieldedWithdrawalResultWASM.createFromRawInstance(await this._rawShieldedBuilder.unshield(spends.map(s => s._rawSpendableNote), preparePlatformAddressValue(outputAddress), unshieldAmount.toString(), changeAddress._rawOrchardAddress, seed, coinType, account, anchor, memo._rawShieldedMemo, platformVersion));
|
|
36
52
|
}
|
|
37
53
|
/** Pool -> pool (spend). */
|
|
38
|
-
shieldedTransfer(spends, recipient, transferAmount, changeAddress, seed, coinType, account, anchor, memo, platformVersion) {
|
|
39
|
-
return ShieldedWithdrawalResultWASM.createFromRawInstance(this._rawShieldedBuilder.shieldedTransfer(spends.map(s => s._rawSpendableNote), recipient._rawOrchardAddress, transferAmount.toString(), changeAddress._rawOrchardAddress, seed, coinType, account, anchor, memo._rawShieldedMemo, platformVersion));
|
|
54
|
+
async shieldedTransfer(spends, recipient, transferAmount, changeAddress, seed, coinType, account, anchor, memo, platformVersion) {
|
|
55
|
+
return ShieldedWithdrawalResultWASM.createFromRawInstance(await this._rawShieldedBuilder.shieldedTransfer(spends.map(s => s._rawSpendableNote), recipient._rawOrchardAddress, transferAmount.toString(), changeAddress._rawOrchardAddress, seed, coinType, account, anchor, memo._rawShieldedMemo, platformVersion));
|
|
40
56
|
}
|
|
41
57
|
/** Pool -> new identity (spend). One private key per public key, same order. */
|
|
42
|
-
identityCreateFromShieldedPool(publicKeys, privateKeys, denomination, sendToAddressOnCreationFailure, spends, changeAddress, seed, coinType, account, anchor, memo, platformVersion) {
|
|
43
|
-
return IdentityCreateFromShieldedPoolResultWASM.createFromRawInstance(this._rawShieldedBuilder.identityCreateFromShieldedPool(publicKeys.map(k => k._rawKeyInCreation), privateKeys.map(k => k._rawPrivateKey), denomination.toString(), preparePlatformAddressValue(sendToAddressOnCreationFailure), spends.map(s => s._rawSpendableNote), changeAddress._rawOrchardAddress, seed, coinType, account, anchor, memo._rawShieldedMemo, platformVersion));
|
|
58
|
+
async identityCreateFromShieldedPool(publicKeys, privateKeys, denomination, sendToAddressOnCreationFailure, spends, changeAddress, seed, coinType, account, anchor, memo, platformVersion) {
|
|
59
|
+
return IdentityCreateFromShieldedPoolResultWASM.createFromRawInstance(await this._rawShieldedBuilder.identityCreateFromShieldedPool(publicKeys.map(k => k._rawKeyInCreation), privateKeys.map(k => k._rawPrivateKey), denomination.toString(), preparePlatformAddressValue(sendToAddressOnCreationFailure), spends.map(s => s._rawSpendableNote), changeAddress._rawOrchardAddress, seed, coinType, account, anchor, memo._rawShieldedMemo, platformVersion));
|
|
44
60
|
}
|
|
45
61
|
}
|
package/package.json
CHANGED
|
@@ -288,21 +288,23 @@ describe('SpendableNote', function () {
|
|
|
288
288
|
})
|
|
289
289
|
|
|
290
290
|
describe('OrchardProver', function () {
|
|
291
|
-
//
|
|
292
|
-
test('should construct a prover', function () {
|
|
291
|
+
// Initializing the prover builds the Halo 2 proving key (~seconds).
|
|
292
|
+
test('should construct a prover', async function () {
|
|
293
293
|
const prover = new OrchardProverWASM()
|
|
294
|
+
await prover.init()
|
|
294
295
|
|
|
295
296
|
expect(prover).toBeInstanceOf(OrchardProverWASM)
|
|
296
297
|
}, 30000)
|
|
297
298
|
})
|
|
298
299
|
|
|
299
300
|
describe('ShieldedBuilder', function () {
|
|
300
|
-
// The builder builds its own Halo 2 proving key on
|
|
301
|
+
// The builder builds its own Halo 2 proving key on init (~seconds),
|
|
301
302
|
// so build it once and reuse it across the deposit test.
|
|
302
303
|
let builder: ShieldedBuilderWASM
|
|
303
304
|
|
|
304
|
-
beforeAll(function () {
|
|
305
|
+
beforeAll(async function () {
|
|
305
306
|
builder = new ShieldedBuilderWASM()
|
|
307
|
+
await builder.init()
|
|
306
308
|
}, 30000)
|
|
307
309
|
|
|
308
310
|
describe('constructor', function () {
|
|
@@ -312,7 +314,7 @@ describe('ShieldedBuilder', function () {
|
|
|
312
314
|
})
|
|
313
315
|
|
|
314
316
|
describe('shield (transparent -> pool deposit)', function () {
|
|
315
|
-
test('should build and prove a shield transition', function () {
|
|
317
|
+
test('should build and prove a shield transition', async function () {
|
|
316
318
|
const recipient = OrchardAddressWASM.fromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
317
319
|
const senderOvk = orchardOvkFromSeed(SEED, COIN_TYPE, ACCOUNT)
|
|
318
320
|
|
|
@@ -321,7 +323,7 @@ describe('ShieldedBuilder', function () {
|
|
|
321
323
|
// address, nonce, balance — balance must cover amount + fee.
|
|
322
324
|
const input = new InputAddressWASM(inputAddress, 0, DASH / 2n)
|
|
323
325
|
|
|
324
|
-
const st = builder.shield(
|
|
326
|
+
const st = await builder.shield(
|
|
325
327
|
recipient,
|
|
326
328
|
(DASH * 4n) / 10n, // 0.4 DASH into the pool
|
|
327
329
|
[input],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as dpp from "pshenmic-dpp/wasm";
|
|
2
|
-
import {IdentifierWASM} from "pshenmic-dpp/wasm";
|
|
2
|
+
import {IdentifierWASM, ShieldedBuilderWASM} from "pshenmic-dpp/wasm";
|
|
3
3
|
|
|
4
4
|
let identifierBytes: Uint8Array;
|
|
5
5
|
|
|
@@ -46,4 +46,43 @@ describe("dpp", function () {
|
|
|
46
46
|
expect(identifier.bytes()).toEqual(identifierBytes);
|
|
47
47
|
});
|
|
48
48
|
})
|
|
49
|
+
|
|
50
|
+
describe('shielded init', function () {
|
|
51
|
+
test('should allow to use old instances after shielded init', async function () {
|
|
52
|
+
const identifier = IdentifierWASM.fromBytes(identifierBytes);
|
|
53
|
+
|
|
54
|
+
const builder = new ShieldedBuilderWASM()
|
|
55
|
+
|
|
56
|
+
await builder.init();
|
|
57
|
+
|
|
58
|
+
expect(identifier.bytes()).toEqual(identifierBytes);
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('should build a real Halo 2 proof with instances created before init', async function () {
|
|
62
|
+
const seed = new Uint8Array(64).fill(7);
|
|
63
|
+
|
|
64
|
+
// created BEFORE init — must stay usable by the proving call
|
|
65
|
+
const recipient = dpp.OrchardAddressWASM.fromSeed(seed, 1, 0);
|
|
66
|
+
const senderOvk = dpp.orchardOvkFromSeed(seed, 1, 0);
|
|
67
|
+
const privateKey = dpp.PrivateKeyWASM.fromWIF('cUy4wbim4y9NDwC24omx8oWY5WqfmjSU2gdcZtTXza2xDCAkQXRP');
|
|
68
|
+
const outPoint = new dpp.OutPointWASM('79af4b339ddfee8c9b6d08d74155373c6ef547cda5e65473a254b9b0f8533f0c', 0);
|
|
69
|
+
const assetLockProof = dpp.AssetLockProofWASM.createChainAssetLockProof(1499737, outPoint);
|
|
70
|
+
const memo = dpp.ShieldedMemoWASM.empty();
|
|
71
|
+
|
|
72
|
+
const builder = new ShieldedBuilderWASM();
|
|
73
|
+
await builder.init();
|
|
74
|
+
|
|
75
|
+
const st = await builder.shieldFromAssetLock(
|
|
76
|
+
recipient,
|
|
77
|
+
40_000_000_000n,
|
|
78
|
+
assetLockProof,
|
|
79
|
+
privateKey,
|
|
80
|
+
memo,
|
|
81
|
+
0,
|
|
82
|
+
senderOvk
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(st.hex().length).toBeGreaterThan(0);
|
|
86
|
+
}, 120000)
|
|
87
|
+
})
|
|
49
88
|
});
|