@aztec/pxe 0.0.1-commit.3100065 → 0.0.1-commit.321f6a9
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/dest/bin/check_oracle_version.js +3 -8
- package/dest/bin/index.d.ts +2 -2
- package/dest/bin/index.d.ts.map +1 -1
- package/dest/bin/index.js +1 -1
- package/dest/bin/oracle_version_helpers.d.ts +8 -25
- package/dest/bin/oracle_version_helpers.d.ts.map +1 -1
- package/dest/bin/oracle_version_helpers.js +11 -219
- package/dest/config/package_info.js +1 -1
- package/dest/contract/helpers.d.ts +1 -1
- package/dest/contract/helpers.d.ts.map +1 -1
- package/dest/contract/helpers.js +3 -3
- package/dest/contract/skip_sync_contracts.d.ts +11 -0
- package/dest/contract/skip_sync_contracts.d.ts.map +1 -0
- package/dest/contract/skip_sync_contracts.js +18 -0
- package/dest/contract_function_simulator/contract_function_simulator.d.ts +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.d.ts.map +1 -1
- package/dest/contract_function_simulator/contract_function_simulator.js +5 -3
- package/dest/contract_function_simulator/index.d.ts +3 -3
- package/dest/contract_function_simulator/index.d.ts.map +1 -1
- package/dest/contract_function_simulator/index.js +1 -2
- package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts +7 -9
- package/dest/contract_function_simulator/noir-structs/resolved_tx.d.ts.map +1 -1
- package/dest/contract_function_simulator/noir-structs/resolved_tx.js +3 -44
- package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts +5 -4
- package/dest/contract_function_simulator/noir-structs/tx_effect_data.d.ts.map +1 -1
- package/dest/contract_function_simulator/noir-structs/tx_effect_data.js +2 -2
- package/dest/contract_function_simulator/oracle/oracle_registry.d.ts +4 -3
- package/dest/contract_function_simulator/oracle/oracle_registry.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/oracle_registry.js +15 -6
- package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts +87 -35
- package/dest/contract_function_simulator/oracle/oracle_type_mappings.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/oracle_type_mappings.js +286 -286
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/private_execution_oracle.js +5 -6
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +6 -3
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +41 -16
- package/dest/entrypoints/client/bundle/index.d.ts +2 -1
- package/dest/entrypoints/client/bundle/index.d.ts.map +1 -1
- package/dest/entrypoints/client/bundle/index.js +1 -0
- package/dest/entrypoints/client/bundle/utils.d.ts +1 -1
- package/dest/entrypoints/client/bundle/utils.d.ts.map +1 -1
- package/dest/entrypoints/client/bundle/utils.js +10 -4
- package/dest/entrypoints/client/lazy/index.d.ts +2 -1
- package/dest/entrypoints/client/lazy/index.d.ts.map +1 -1
- package/dest/entrypoints/client/lazy/index.js +1 -0
- package/dest/entrypoints/client/lazy/utils.d.ts +1 -1
- package/dest/entrypoints/client/lazy/utils.d.ts.map +1 -1
- package/dest/entrypoints/client/lazy/utils.js +10 -4
- package/dest/entrypoints/client/store.d.ts +14 -0
- package/dest/entrypoints/client/store.d.ts.map +1 -0
- package/dest/entrypoints/client/store.js +42 -0
- package/dest/entrypoints/server/index.d.ts +2 -1
- package/dest/entrypoints/server/index.d.ts.map +1 -1
- package/dest/entrypoints/server/index.js +1 -0
- package/dest/entrypoints/server/store.d.ts +18 -0
- package/dest/entrypoints/server/store.d.ts.map +1 -0
- package/dest/entrypoints/server/store.js +28 -0
- package/dest/entrypoints/server/utils.d.ts +1 -1
- package/dest/entrypoints/server/utils.d.ts.map +1 -1
- package/dest/entrypoints/server/utils.js +8 -2
- package/dest/logs/log_service.d.ts +3 -2
- package/dest/logs/log_service.d.ts.map +1 -1
- package/dest/logs/log_service.js +12 -3
- package/dest/messages/tx_resolver_service.d.ts +2 -2
- package/dest/messages/tx_resolver_service.d.ts.map +1 -1
- package/dest/messages/tx_resolver_service.js +7 -2
- package/dest/notes/note_service.d.ts +1 -1
- package/dest/notes/note_service.js +1 -1
- package/dest/oracle_version.d.ts +2 -2
- package/dest/oracle_version.js +3 -3
- package/dest/private_kernel/batch_planner.d.ts +1 -1
- package/dest/private_kernel/batch_planner.d.ts.map +1 -1
- package/dest/private_kernel/batch_planner.js +1 -1
- package/dest/private_kernel/private_kernel_execution_prover.d.ts +1 -1
- package/dest/private_kernel/private_kernel_execution_prover.d.ts.map +1 -1
- package/dest/private_kernel/private_kernel_execution_prover.js +45 -5
- package/dest/pxe.d.ts +1 -1
- package/dest/pxe.d.ts.map +1 -1
- package/dest/pxe.js +8 -5
- package/dest/storage/fact_store/fact_store.d.ts +1 -1
- package/dest/storage/fact_store/fact_store.js +1 -1
- package/dest/storage/fact_store/index.d.ts +2 -2
- package/dest/storage/fact_store/index.d.ts.map +1 -1
- package/dest/storage/fact_store/index.js +1 -1
- package/dest/storage/fact_store/origin_state.d.ts +3 -1
- package/dest/storage/fact_store/origin_state.d.ts.map +1 -1
- package/dest/storage/fact_store/origin_state.js +7 -0
- package/dest/storage/store_identity.d.ts +35 -0
- package/dest/storage/store_identity.d.ts.map +1 -0
- package/dest/storage/store_identity.js +44 -0
- package/dest/storage/tagging_store/sender_tagging_store.d.ts +19 -3
- package/dest/storage/tagging_store/sender_tagging_store.d.ts.map +1 -1
- package/dest/storage/tagging_store/sender_tagging_store.js +48 -11
- package/dest/tagging/constants.d.ts +2 -1
- package/dest/tagging/constants.d.ts.map +1 -1
- package/dest/tagging/constants.js +9 -0
- package/dest/tagging/index.d.ts +2 -2
- package/dest/tagging/index.d.ts.map +1 -1
- package/dest/tagging/index.js +1 -1
- package/dest/tagging/recipient_sync/sync_tagged_private_logs.d.ts +9 -4
- package/dest/tagging/recipient_sync/sync_tagged_private_logs.d.ts.map +1 -1
- package/dest/tagging/recipient_sync/sync_tagged_private_logs.js +60 -25
- package/dest/tagging/sender_sync/sync_sender_tagging_indexes.js +1 -1
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts +1 -1
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.d.ts.map +1 -1
- package/dest/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.js +6 -2
- package/dest/tagging/testing/tag_query_test_utils.d.ts +6 -0
- package/dest/tagging/testing/tag_query_test_utils.d.ts.map +1 -0
- package/dest/tagging/testing/tag_query_test_utils.js +10 -0
- package/package.json +17 -17
- package/src/bin/check_oracle_version.ts +3 -10
- package/src/bin/index.ts +1 -5
- package/src/bin/oracle_version_helpers.ts +11 -268
- package/src/config/package_info.ts +1 -1
- package/src/contract/helpers.ts +3 -3
- package/src/contract/skip_sync_contracts.ts +23 -0
- package/src/contract_function_simulator/contract_function_simulator.ts +5 -3
- package/src/contract_function_simulator/index.ts +23 -3
- package/src/contract_function_simulator/noir-structs/resolved_tx.ts +11 -45
- package/src/contract_function_simulator/noir-structs/tx_effect_data.ts +4 -3
- package/src/contract_function_simulator/oracle/oracle_registry.ts +12 -8
- package/src/contract_function_simulator/oracle/oracle_type_mappings.ts +285 -197
- package/src/contract_function_simulator/oracle/private_execution_oracle.ts +12 -7
- package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +55 -17
- package/src/entrypoints/client/bundle/index.ts +1 -0
- package/src/entrypoints/client/bundle/utils.ts +15 -3
- package/src/entrypoints/client/lazy/index.ts +1 -0
- package/src/entrypoints/client/lazy/utils.ts +15 -3
- package/src/entrypoints/client/store.ts +54 -0
- package/src/entrypoints/server/index.ts +1 -0
- package/src/entrypoints/server/store.ts +47 -0
- package/src/entrypoints/server/utils.ts +21 -7
- package/src/logs/log_service.ts +11 -2
- package/src/messages/tx_resolver_service.ts +8 -8
- package/src/notes/note_service.ts +1 -1
- package/src/oracle_version.ts +3 -3
- package/src/private_kernel/batch_planner.ts +0 -1
- package/src/private_kernel/private_kernel_execution_prover.ts +90 -4
- package/src/pxe.ts +8 -5
- package/src/storage/fact_store/fact_store.ts +1 -1
- package/src/storage/fact_store/index.ts +1 -0
- package/src/storage/fact_store/origin_state.ts +9 -0
- package/src/storage/store_identity.ts +72 -0
- package/src/storage/tagging_store/sender_tagging_store.ts +62 -15
- package/src/tagging/constants.ts +10 -0
- package/src/tagging/index.ts +1 -1
- package/src/tagging/recipient_sync/sync_tagged_private_logs.ts +103 -46
- package/src/tagging/sender_sync/sync_sender_tagging_indexes.ts +1 -1
- package/src/tagging/sender_sync/utils/load_and_store_new_tagging_indexes.ts +6 -2
- package/src/tagging/testing/tag_query_test_utils.ts +11 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { CircuitKind } from '@aztec/bb.js';
|
|
1
2
|
import { MAX_APPS_PER_KERNEL } from '@aztec/constants';
|
|
2
3
|
import { uniqueBy } from '@aztec/foundation/collection';
|
|
3
|
-
import {
|
|
4
|
+
import { vkAsFields } from '@aztec/foundation/crypto/keys';
|
|
4
5
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
6
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
6
7
|
import { pushTestData } from '@aztec/foundation/testing';
|
|
@@ -20,9 +21,13 @@ import {
|
|
|
20
21
|
type PrivateKernelExecutionProofOutput,
|
|
21
22
|
PrivateKernelInit2CircuitPrivateInputs,
|
|
22
23
|
PrivateKernelInit3CircuitPrivateInputs,
|
|
24
|
+
PrivateKernelInit4CircuitPrivateInputs,
|
|
25
|
+
PrivateKernelInit5CircuitPrivateInputs,
|
|
23
26
|
PrivateKernelInitCircuitPrivateInputs,
|
|
24
27
|
PrivateKernelInner2CircuitPrivateInputs,
|
|
25
28
|
PrivateKernelInner3CircuitPrivateInputs,
|
|
29
|
+
PrivateKernelInner4CircuitPrivateInputs,
|
|
30
|
+
PrivateKernelInner5CircuitPrivateInputs,
|
|
26
31
|
PrivateKernelInnerCircuitPrivateInputs,
|
|
27
32
|
PrivateKernelResetTailCircuitPrivateInputs,
|
|
28
33
|
type PrivateKernelSimulateOutput,
|
|
@@ -145,6 +150,7 @@ export class PrivateKernelExecutionProver {
|
|
|
145
150
|
bytecode: output.bytecode,
|
|
146
151
|
witness: output.outputWitness,
|
|
147
152
|
vk: output.verificationKey.keyAsBytes,
|
|
153
|
+
kind: CircuitKind.Kernel,
|
|
148
154
|
timings: {
|
|
149
155
|
witgen: witgenTimer.ms(),
|
|
150
156
|
},
|
|
@@ -230,6 +236,7 @@ export class PrivateKernelExecutionProver {
|
|
|
230
236
|
bytecode: tailOutput.bytecode,
|
|
231
237
|
witness: tailOutput.outputWitness,
|
|
232
238
|
vk: tailOutput.verificationKey.keyAsBytes,
|
|
239
|
+
kind: CircuitKind.Kernel,
|
|
233
240
|
timings: {
|
|
234
241
|
witgen: witgenTimer.ms(),
|
|
235
242
|
},
|
|
@@ -261,6 +268,7 @@ export class PrivateKernelExecutionProver {
|
|
|
261
268
|
bytecode: hidingOutput.bytecode,
|
|
262
269
|
witness: hidingOutput.outputWitness,
|
|
263
270
|
vk: hidingOutput.verificationKey.keyAsBytes,
|
|
271
|
+
kind: CircuitKind.HidingKernel,
|
|
264
272
|
timings: {
|
|
265
273
|
witgen: witgenTimer.ms(),
|
|
266
274
|
},
|
|
@@ -270,7 +278,11 @@ export class PrivateKernelExecutionProver {
|
|
|
270
278
|
if (profileMode == 'gates' || profileMode == 'full') {
|
|
271
279
|
for (const entry of executionSteps) {
|
|
272
280
|
const gateCountTimer = new Timer();
|
|
273
|
-
const gateCount = await this.proofCreator.computeGateCountForCircuit(
|
|
281
|
+
const gateCount = await this.proofCreator.computeGateCountForCircuit(
|
|
282
|
+
entry.bytecode,
|
|
283
|
+
entry.functionName,
|
|
284
|
+
entry.kind,
|
|
285
|
+
);
|
|
274
286
|
entry.gateCount = gateCount;
|
|
275
287
|
entry.timings.gateCount = gateCountTimer.ms();
|
|
276
288
|
}
|
|
@@ -366,6 +378,7 @@ export class PrivateKernelExecutionProver {
|
|
|
366
378
|
bytecode: next.acir,
|
|
367
379
|
witness: next.partialWitness,
|
|
368
380
|
vk: next.vk,
|
|
381
|
+
kind: CircuitKind.App,
|
|
369
382
|
timings: {
|
|
370
383
|
witgen: next.profileResult?.timings.witgen ?? 0,
|
|
371
384
|
oracles: next.profileResult?.timings.oracles,
|
|
@@ -399,8 +412,8 @@ export class PrivateKernelExecutionProver {
|
|
|
399
412
|
) {
|
|
400
413
|
const { contractAddress, functionSelector } = publicInputs.callContext;
|
|
401
414
|
|
|
402
|
-
const
|
|
403
|
-
const vk = await VerificationKeyAsFields.fromKey(
|
|
415
|
+
const vkFields = await vkAsFields(vkAsBuffer, CircuitKind.App);
|
|
416
|
+
const vk = await VerificationKeyAsFields.fromKey(vkFields);
|
|
404
417
|
|
|
405
418
|
const { currentContractClassId, publicKeys, saltedInitializationHash } =
|
|
406
419
|
await this.oracle.getContractAddressPreimage(contractAddress);
|
|
@@ -514,6 +527,47 @@ export class PrivateKernelExecutionProver {
|
|
|
514
527
|
functionName = 'private_kernel_init_3';
|
|
515
528
|
break;
|
|
516
529
|
}
|
|
530
|
+
case 4: {
|
|
531
|
+
const proofInput = new PrivateKernelInit4CircuitPrivateInputs(
|
|
532
|
+
txRequest,
|
|
533
|
+
vkTreeRoot,
|
|
534
|
+
ProtocolContractsList,
|
|
535
|
+
apps[0],
|
|
536
|
+
apps[1],
|
|
537
|
+
apps[2],
|
|
538
|
+
apps[3],
|
|
539
|
+
isPrivateOnlyTx,
|
|
540
|
+
minRevertibleSideEffectCounter,
|
|
541
|
+
);
|
|
542
|
+
this.log.debug(`Calling private kernel init_4 with isPrivateOnly ${isPrivateOnlyTx}`);
|
|
543
|
+
pushTestData('private-kernel-inputs-init-4', proofInput);
|
|
544
|
+
output = generateWitnesses
|
|
545
|
+
? await this.proofCreator.generateInit4Output(proofInput)
|
|
546
|
+
: await this.proofCreator.simulateInit4(proofInput);
|
|
547
|
+
functionName = 'private_kernel_init_4';
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
case 5: {
|
|
551
|
+
const proofInput = new PrivateKernelInit5CircuitPrivateInputs(
|
|
552
|
+
txRequest,
|
|
553
|
+
vkTreeRoot,
|
|
554
|
+
ProtocolContractsList,
|
|
555
|
+
apps[0],
|
|
556
|
+
apps[1],
|
|
557
|
+
apps[2],
|
|
558
|
+
apps[3],
|
|
559
|
+
apps[4],
|
|
560
|
+
isPrivateOnlyTx,
|
|
561
|
+
minRevertibleSideEffectCounter,
|
|
562
|
+
);
|
|
563
|
+
this.log.debug(`Calling private kernel init_5 with isPrivateOnly ${isPrivateOnlyTx}`);
|
|
564
|
+
pushTestData('private-kernel-inputs-init-5', proofInput);
|
|
565
|
+
output = generateWitnesses
|
|
566
|
+
? await this.proofCreator.generateInit5Output(proofInput)
|
|
567
|
+
: await this.proofCreator.simulateInit5(proofInput);
|
|
568
|
+
functionName = 'private_kernel_init_5';
|
|
569
|
+
break;
|
|
570
|
+
}
|
|
517
571
|
default:
|
|
518
572
|
throw new Error(`Unsupported init kernel batch size: ${apps.length}`);
|
|
519
573
|
}
|
|
@@ -548,6 +602,37 @@ export class PrivateKernelExecutionProver {
|
|
|
548
602
|
functionName = 'private_kernel_inner_3';
|
|
549
603
|
break;
|
|
550
604
|
}
|
|
605
|
+
case 4: {
|
|
606
|
+
const proofInput = new PrivateKernelInner4CircuitPrivateInputs(
|
|
607
|
+
previousKernelData,
|
|
608
|
+
apps[0],
|
|
609
|
+
apps[1],
|
|
610
|
+
apps[2],
|
|
611
|
+
apps[3],
|
|
612
|
+
);
|
|
613
|
+
pushTestData('private-kernel-inputs-inner-4', proofInput);
|
|
614
|
+
output = generateWitnesses
|
|
615
|
+
? await this.proofCreator.generateInner4Output(proofInput)
|
|
616
|
+
: await this.proofCreator.simulateInner4(proofInput);
|
|
617
|
+
functionName = 'private_kernel_inner_4';
|
|
618
|
+
break;
|
|
619
|
+
}
|
|
620
|
+
case 5: {
|
|
621
|
+
const proofInput = new PrivateKernelInner5CircuitPrivateInputs(
|
|
622
|
+
previousKernelData,
|
|
623
|
+
apps[0],
|
|
624
|
+
apps[1],
|
|
625
|
+
apps[2],
|
|
626
|
+
apps[3],
|
|
627
|
+
apps[4],
|
|
628
|
+
);
|
|
629
|
+
pushTestData('private-kernel-inputs-inner-5', proofInput);
|
|
630
|
+
output = generateWitnesses
|
|
631
|
+
? await this.proofCreator.generateInner5Output(proofInput)
|
|
632
|
+
: await this.proofCreator.simulateInner5(proofInput);
|
|
633
|
+
functionName = 'private_kernel_inner_5';
|
|
634
|
+
break;
|
|
635
|
+
}
|
|
551
636
|
default:
|
|
552
637
|
throw new Error(`Unsupported inner kernel batch size: ${apps.length}`);
|
|
553
638
|
}
|
|
@@ -558,6 +643,7 @@ export class PrivateKernelExecutionProver {
|
|
|
558
643
|
bytecode: output.bytecode,
|
|
559
644
|
witness: output.outputWitness,
|
|
560
645
|
vk: output.verificationKey.keyAsBytes,
|
|
646
|
+
kind: CircuitKind.Kernel,
|
|
561
647
|
timings: {
|
|
562
648
|
witgen: witgenTimer.ms(),
|
|
563
649
|
},
|
package/src/pxe.ts
CHANGED
|
@@ -37,7 +37,7 @@ import type {
|
|
|
37
37
|
PrivateKernelTailCircuitPublicInputs,
|
|
38
38
|
} from '@aztec/stdlib/kernel';
|
|
39
39
|
import { computeAddressSecret } from '@aztec/stdlib/keys';
|
|
40
|
-
import { deriveEcdhSharedSecretPoint } from '@aztec/stdlib/logs';
|
|
40
|
+
import { deriveEcdhSharedSecretPoint, protectFromForgery } from '@aztec/stdlib/logs';
|
|
41
41
|
import {
|
|
42
42
|
BlockHeader,
|
|
43
43
|
type ContractOverrides,
|
|
@@ -890,9 +890,11 @@ export class PXE {
|
|
|
890
890
|
}
|
|
891
891
|
|
|
892
892
|
/**
|
|
893
|
-
* Derives the shared secret of a handshake from its ephemeral public key:
|
|
894
|
-
*
|
|
895
|
-
*
|
|
893
|
+
* Derives the shared secret of a handshake from its ephemeral public key: the raw ECDH secret
|
|
894
|
+
* `S = addressSecret(recipient) * ephPk` with the forgery protection applied,
|
|
895
|
+
* matching the protected secret the registry stores and the derivation the recipient-side scan uses for
|
|
896
|
+
* handshakes discovered onchain. The ephemeral key is reconstructed from its x-coordinate with a positive y,
|
|
897
|
+
* matching how the protocol generates it.
|
|
896
898
|
*
|
|
897
899
|
* @throws If `ephPk` is not the x-coordinate of a Grumpkin curve point, or if `recipient` is not an account of
|
|
898
900
|
* this PXE, since the derivation needs its keys.
|
|
@@ -914,7 +916,8 @@ export class PXE {
|
|
|
914
916
|
|
|
915
917
|
const ivskM = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
|
|
916
918
|
const addressSecret = await computeAddressSecret(await completeAddress.getPreaddress(), ivskM);
|
|
917
|
-
|
|
919
|
+
const rawSecret = await deriveEcdhSharedSecretPoint(addressSecret, ephPkPoint);
|
|
920
|
+
return protectFromForgery(rawSecret, ephPkPoint, await recipient.toAddressPoint());
|
|
918
921
|
}
|
|
919
922
|
|
|
920
923
|
/** Registers a resolved shared secret scoped to a recipient. Returns whether it was newly added. */
|
|
@@ -82,7 +82,7 @@ export class FactStore implements StagedStore {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
/**
|
|
85
|
-
* Records a fact in a collection
|
|
85
|
+
* Records a fact in a collection.
|
|
86
86
|
*
|
|
87
87
|
* The collection is created implicitly on the first fact recorded for its key: recording into an existing collection
|
|
88
88
|
* just adds to it.
|
|
@@ -21,6 +21,15 @@ export enum OriginBlockState {
|
|
|
21
21
|
Finalized = 3,
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
/** Parses a numeric origin-block-state discriminant, rejecting unknown values. */
|
|
25
|
+
export function originBlockStateFromNumber(value: number): OriginBlockState {
|
|
26
|
+
if (!(value in OriginBlockState)) {
|
|
27
|
+
const validNames = Object.keys(OriginBlockState).filter(k => isNaN(Number(k)));
|
|
28
|
+
throw new Error(`Invalid OriginBlockState value ${value}, expected one of ${validNames.join(', ')}`);
|
|
29
|
+
}
|
|
30
|
+
return value as OriginBlockState;
|
|
31
|
+
}
|
|
32
|
+
|
|
24
33
|
/** The two chain-tip block numbers needed to classify an origin block (`finalized <= proven` always holds). */
|
|
25
34
|
export type TipBlockNumbers = { provenBlockNumber: number; finalizedBlockNumber: number };
|
|
26
35
|
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
3
|
+
import { DatabaseVersion } from '@aztec/stdlib/database-version/version';
|
|
4
|
+
|
|
5
|
+
/** The triple that determine which physical store a logical store name maps to. */
|
|
6
|
+
export type StoreIdentity = {
|
|
7
|
+
/** Chain ID of the L1 the rollup is deployed to. */
|
|
8
|
+
l1ChainId: number;
|
|
9
|
+
/** Address of the rollup contract the store's data pertains to. */
|
|
10
|
+
rollupAddress: EthAddress;
|
|
11
|
+
/** Schema version of the data held in the store. */
|
|
12
|
+
schemaVersion: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Composes the store-name discriminator for a store identity. Two identities map to the same physical store iff
|
|
17
|
+
* their slugs are equal, so the format must stay stable: `<l1ChainId>-<rollupAddress>-v<schemaVersion>` — changing
|
|
18
|
+
* it orphans every existing store.
|
|
19
|
+
*/
|
|
20
|
+
export function storeIdentitySlug({ l1ChainId, rollupAddress, schemaVersion }: StoreIdentity): string {
|
|
21
|
+
return `${l1ChainId}-${rollupAddress.toString()}-v${schemaVersion}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Composes the physical store name for a logical store name and identity. */
|
|
25
|
+
export function effectiveStoreName(name: string, identity: StoreIdentity): string {
|
|
26
|
+
return `${name}_${storeIdentitySlug(identity)}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Invariant check for stores whose physical name carries their identity: the recorded version can
|
|
31
|
+
* only disagree with the expected one if there is a store-naming bug.
|
|
32
|
+
*/
|
|
33
|
+
export async function assertStoreIdentity(
|
|
34
|
+
store: AztecAsyncKVStore,
|
|
35
|
+
storeName: string,
|
|
36
|
+
identity: StoreIdentity,
|
|
37
|
+
): Promise<void> {
|
|
38
|
+
const expected = new DatabaseVersion(identity.schemaVersion, identity.rollupAddress);
|
|
39
|
+
const singleton = store.openSingleton<string>('dbVersion');
|
|
40
|
+
const stored = await singleton.getAsync();
|
|
41
|
+
if (stored === undefined) {
|
|
42
|
+
await singleton.set(expected.toBuffer().toString('utf-8'));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
let storedVersion: DatabaseVersion;
|
|
46
|
+
try {
|
|
47
|
+
storedVersion = DatabaseVersion.fromBuffer(Buffer.from(stored, 'utf-8'));
|
|
48
|
+
} catch {
|
|
49
|
+
throw new StoreIdentityMismatchError(storeName, expected.toString(), stored);
|
|
50
|
+
}
|
|
51
|
+
if (!storedVersion.equals(expected)) {
|
|
52
|
+
throw new StoreIdentityMismatchError(storeName, expected.toString(), storedVersion.toString());
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Thrown when a store's recorded identity does not match the identity it was opened under. Since the identity is
|
|
58
|
+
* part of the physical store name, this can only indicate a store-naming bug; the store is left untouched.
|
|
59
|
+
*/
|
|
60
|
+
export class StoreIdentityMismatchError extends Error {
|
|
61
|
+
constructor(
|
|
62
|
+
public readonly storeName: string,
|
|
63
|
+
public readonly expected: string,
|
|
64
|
+
public readonly actual: string,
|
|
65
|
+
) {
|
|
66
|
+
super(
|
|
67
|
+
`Store '${storeName}' records identity ${actual} but was opened as ${expected}. ` +
|
|
68
|
+
`Refusing to open; data was NOT modified.`,
|
|
69
|
+
);
|
|
70
|
+
this.name = 'StoreIdentityMismatchError';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -128,10 +128,11 @@ export class SenderTaggingStore implements StagedStore {
|
|
|
128
128
|
}
|
|
129
129
|
|
|
130
130
|
/**
|
|
131
|
-
* Stores pending index ranges.
|
|
131
|
+
* Stores pending index ranges, rejecting any range that disagrees with an already-stored one.
|
|
132
132
|
* @remarks If the same (secret, txHash) pair already exists in the db with an equal range, it's a no-op. This is
|
|
133
133
|
* expected to happen because whenever we start sync we start from the last finalized index and we can have pending
|
|
134
|
-
* ranges already stored from previous syncs. If the ranges differ, it throws an error as that indicates a bug
|
|
134
|
+
* ranges already stored from previous syncs. If the ranges differ, it throws an error as that indicates a bug in
|
|
135
|
+
* callers that record indexes at prove time. Discovery from onchain logs must use `mergePendingIndexes` instead.
|
|
135
136
|
* @param ranges - The tagging index ranges containing the directional app tagging secrets and the index ranges that are
|
|
136
137
|
* to be stored in the db.
|
|
137
138
|
* @param txHash - The tx in which the tagging indexes were used in private logs.
|
|
@@ -141,6 +142,33 @@ export class SenderTaggingStore implements StagedStore {
|
|
|
141
142
|
* @throws If a different range already exists for the same (secret, txHash) pair.
|
|
142
143
|
*/
|
|
143
144
|
storePendingIndexes(ranges: TaggingIndexRange[], txHash: TxHash, jobId: string): Promise<void> {
|
|
145
|
+
return this.#storePendingIndexes(ranges, txHash, jobId, false);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Stores pending index ranges, widening an existing entry for the same (secret, txHash) pair to the union of the
|
|
150
|
+
* stored and incoming ranges instead of throwing on a mismatch. Discovery from onchain logs needs this: it may see
|
|
151
|
+
* only the surviving (non-revertible phase) sub-range of a partially reverted tx recorded at prove time (the
|
|
152
|
+
* finalized receipt step of the sync resolves that difference), or indexes beyond a partially discovered entry
|
|
153
|
+
* when a tx from another PXE straddles a sync window boundary. Callers that record indexes at prove time must use
|
|
154
|
+
* `storePendingIndexes` instead, so that a range disagreement surfaces as a bug rather than being absorbed.
|
|
155
|
+
* @param ranges - The tagging index ranges containing the directional app tagging secrets and the index ranges that are
|
|
156
|
+
* to be stored in the db.
|
|
157
|
+
* @param txHash - The tx in which the tagging indexes were used in private logs.
|
|
158
|
+
* @param jobId - job context for staged writes to this store. See `JobCoordinator` for more details.
|
|
159
|
+
* @throws If the highestIndex is further than window length from the highest finalized index for the same secret.
|
|
160
|
+
* @throws If the lowestIndex is lower than or equal to the last finalized index for the same secret.
|
|
161
|
+
*/
|
|
162
|
+
mergePendingIndexes(ranges: TaggingIndexRange[], txHash: TxHash, jobId: string): Promise<void> {
|
|
163
|
+
return this.#storePendingIndexes(ranges, txHash, jobId, true);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
#storePendingIndexes(
|
|
167
|
+
ranges: TaggingIndexRange[],
|
|
168
|
+
txHash: TxHash,
|
|
169
|
+
jobId: string,
|
|
170
|
+
mergeExisting: boolean,
|
|
171
|
+
): Promise<void> {
|
|
144
172
|
if (ranges.length === 0) {
|
|
145
173
|
return Promise.resolve();
|
|
146
174
|
}
|
|
@@ -187,21 +215,40 @@ export class SenderTaggingStore implements StagedStore {
|
|
|
187
215
|
// Check if an entry with the same txHash already exists
|
|
188
216
|
const existingEntry = pendingData.find(entry => entry.txHash === txHashStr);
|
|
189
217
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
throw new Error(
|
|
194
|
-
`Conflicting range for secret ${secretStr} and txHash ${txHashStr}: ` +
|
|
195
|
-
`existing [${existingEntry.lowestIndex}, ${existingEntry.highestIndex}] vs ` +
|
|
196
|
-
`new [${range.lowestIndex}, ${range.highestIndex}]`,
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
// Exact duplicate — skip
|
|
200
|
-
} else {
|
|
201
|
-
this.#writePendingIndexes(jobId, secretStr, [
|
|
218
|
+
let updatedPending: PendingIndexesEntry[] | undefined;
|
|
219
|
+
if (!existingEntry) {
|
|
220
|
+
updatedPending = [
|
|
202
221
|
...pendingData,
|
|
203
222
|
{ lowestIndex: range.lowestIndex, highestIndex: range.highestIndex, txHash: txHashStr },
|
|
204
|
-
]
|
|
223
|
+
];
|
|
224
|
+
} else if (mergeExisting) {
|
|
225
|
+
// Widen the entry to the union of both ranges, never shrink it: replacing would drop prove-time
|
|
226
|
+
// indexes the chain doesn't show (partially reverted tx), and skipping would drop onchain indexes
|
|
227
|
+
// discovered in a later sync window (tx straddling the window boundary).
|
|
228
|
+
const lowestIndex = Math.min(existingEntry.lowestIndex, range.lowestIndex);
|
|
229
|
+
const highestIndex = Math.max(existingEntry.highestIndex, range.highestIndex);
|
|
230
|
+
if (lowestIndex !== existingEntry.lowestIndex || highestIndex !== existingEntry.highestIndex) {
|
|
231
|
+
updatedPending = pendingData.map(entry =>
|
|
232
|
+
entry === existingEntry ? { lowestIndex, highestIndex, txHash: entry.txHash } : entry,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
} else if (
|
|
236
|
+
existingEntry.lowestIndex !== range.lowestIndex ||
|
|
237
|
+
existingEntry.highestIndex !== range.highestIndex
|
|
238
|
+
) {
|
|
239
|
+
// Different ranges for the same (secret, txHash) indicate a bug in callers that record indexes at prove
|
|
240
|
+
// time.
|
|
241
|
+
throw new Error(
|
|
242
|
+
`Conflicting range for secret ${secretStr} and txHash ${txHashStr}: ` +
|
|
243
|
+
`existing [${existingEntry.lowestIndex}, ${existingEntry.highestIndex}] vs ` +
|
|
244
|
+
`new [${range.lowestIndex}, ${range.highestIndex}]`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
// Remaining cases (a merge whose union equals the stored range, or an identical range without
|
|
248
|
+
// mergeExisting): duplicate evidence, nothing to write.
|
|
249
|
+
|
|
250
|
+
if (updatedPending) {
|
|
251
|
+
this.#writePendingIndexes(jobId, secretStr, updatedPending);
|
|
205
252
|
}
|
|
206
253
|
}
|
|
207
254
|
});
|
package/src/tagging/constants.ts
CHANGED
|
@@ -18,3 +18,13 @@ import { MAX_PRIVATE_LOGS_PER_TX } from '@aztec/constants';
|
|
|
18
18
|
// reserved at log emission time, before squashing is decided, and the kernel's reset/squash loop is not bounded by
|
|
19
19
|
// MAX_PRIVATE_LOGS_PER_TX. No fixed window value closes that gap.
|
|
20
20
|
export const UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN = MAX_PRIVATE_LOGS_PER_TX + 20;
|
|
21
|
+
|
|
22
|
+
// The number of tags probed per constrained secret in the first round.
|
|
23
|
+
//
|
|
24
|
+
// The probe doubles each round (2, 4, 8, ..., capped at UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN) while every probed
|
|
25
|
+
// index is a hit, stopping at the first missing tag. Constrained delivery is gapless, so a single missing tag proves
|
|
26
|
+
// the stream has ended: at steady state this turns a full WINDOW_LEN probe into two tags. A secret K logs behind
|
|
27
|
+
// catches up in ~log2(K) round-trips while the probe is still doubling (2, 4, 8, 16, 32), but once it saturates the cap
|
|
28
|
+
// and advances WINDOW_LEN tags per round, deeper catch-up is linear at ~K/WINDOW_LEN rounds. Either way it beats both
|
|
29
|
+
// the full window every round and one round per log.
|
|
30
|
+
export const INITIAL_CONSTRAINED_PROBE_LEN = 2;
|
package/src/tagging/index.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
export { syncTaggedPrivateLogs } from './recipient_sync/sync_tagged_private_logs.js';
|
|
13
13
|
export { syncSenderTaggingIndexes } from './sender_sync/sync_sender_tagging_indexes.js';
|
|
14
14
|
export { persistSenderTaggingIndexRangesForTx } from './persist_sender_tagging_index_ranges.js';
|
|
15
|
-
export { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN } from './constants.js';
|
|
15
|
+
export { UNFINALIZED_TAGGING_INDEXES_WINDOW_LEN, INITIAL_CONSTRAINED_PROBE_LEN } from './constants.js';
|
|
16
16
|
export { getAllPrivateLogsByTags, getAllPublicLogsByTagsFromContract } from './get_all_logs_by_tags.js';
|
|
17
17
|
|
|
18
18
|
// Re-export tagging-related types from stdlib
|