@aztec/pxe 5.0.0 → 5.0.1
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/contract_function_simulator/oracle/oracle_registry.d.ts +2 -1
- package/dest/contract_function_simulator/oracle/oracle_registry.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/oracle_registry.js +9 -0
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts +5 -2
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.d.ts.map +1 -1
- package/dest/contract_function_simulator/oracle/utility_execution_oracle.js +39 -15
- 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 +28 -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 +5 -1
- 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 +2 -2
- package/dest/pxe.d.ts +1 -1
- package/dest/pxe.d.ts.map +1 -1
- package/dest/pxe.js +8 -5
- 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/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/package.json +17 -17
- package/src/contract_function_simulator/oracle/oracle_registry.ts +5 -0
- package/src/contract_function_simulator/oracle/utility_execution_oracle.ts +47 -14
- 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 +38 -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 +4 -0
- package/src/notes/note_service.ts +1 -1
- package/src/oracle_version.ts +2 -2
- package/src/pxe.ts +8 -5
- package/src/storage/store_identity.ts +72 -0
- package/src/storage/tagging_store/sender_tagging_store.ts +62 -15
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/pxe",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"typedocOptions": {
|
|
6
6
|
"entryPoints": [
|
|
@@ -71,20 +71,20 @@
|
|
|
71
71
|
]
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@aztec/bb-prover": "5.0.
|
|
75
|
-
"@aztec/bb.js": "5.0.
|
|
76
|
-
"@aztec/builder": "5.0.
|
|
77
|
-
"@aztec/constants": "5.0.
|
|
78
|
-
"@aztec/ethereum": "5.0.
|
|
79
|
-
"@aztec/foundation": "5.0.
|
|
80
|
-
"@aztec/key-store": "5.0.
|
|
81
|
-
"@aztec/kv-store": "5.0.
|
|
82
|
-
"@aztec/noir-protocol-circuits-types": "5.0.
|
|
83
|
-
"@aztec/noir-types": "5.0.
|
|
84
|
-
"@aztec/protocol-contracts": "5.0.
|
|
85
|
-
"@aztec/simulator": "5.0.
|
|
86
|
-
"@aztec/standard-contracts": "5.0.
|
|
87
|
-
"@aztec/stdlib": "5.0.
|
|
74
|
+
"@aztec/bb-prover": "5.0.1",
|
|
75
|
+
"@aztec/bb.js": "5.0.1",
|
|
76
|
+
"@aztec/builder": "5.0.1",
|
|
77
|
+
"@aztec/constants": "5.0.1",
|
|
78
|
+
"@aztec/ethereum": "5.0.1",
|
|
79
|
+
"@aztec/foundation": "5.0.1",
|
|
80
|
+
"@aztec/key-store": "5.0.1",
|
|
81
|
+
"@aztec/kv-store": "5.0.1",
|
|
82
|
+
"@aztec/noir-protocol-circuits-types": "5.0.1",
|
|
83
|
+
"@aztec/noir-types": "5.0.1",
|
|
84
|
+
"@aztec/protocol-contracts": "5.0.1",
|
|
85
|
+
"@aztec/simulator": "5.0.1",
|
|
86
|
+
"@aztec/standard-contracts": "5.0.1",
|
|
87
|
+
"@aztec/stdlib": "5.0.1",
|
|
88
88
|
"koa": "^2.16.1",
|
|
89
89
|
"koa-router": "^13.1.1",
|
|
90
90
|
"lodash.omit": "^4.5.0",
|
|
@@ -93,8 +93,8 @@
|
|
|
93
93
|
"viem": "npm:@aztec/viem@2.38.2"
|
|
94
94
|
},
|
|
95
95
|
"devDependencies": {
|
|
96
|
-
"@aztec/noir-test-contracts.js": "5.0.
|
|
97
|
-
"@aztec/world-state": "5.0.
|
|
96
|
+
"@aztec/noir-test-contracts.js": "5.0.1",
|
|
97
|
+
"@aztec/world-state": "5.0.1",
|
|
98
98
|
"@jest/globals": "^30.0.0",
|
|
99
99
|
"@types/jest": "^30.0.0",
|
|
100
100
|
"@types/lodash.omit": "^4.5.7",
|
|
@@ -273,6 +273,11 @@ export const ORACLE_REGISTRY = {
|
|
|
273
273
|
returnType: OPTION(TX_EFFECT),
|
|
274
274
|
}),
|
|
275
275
|
|
|
276
|
+
aztec_utl_getTxEffects: makeEntry({
|
|
277
|
+
params: [{ name: 'txHashes', type: EPHEMERAL_ARRAY(TX_HASH) }],
|
|
278
|
+
returnType: EPHEMERAL_ARRAY(OPTION(TX_EFFECT)),
|
|
279
|
+
}),
|
|
280
|
+
|
|
276
281
|
aztec_utl_setCapsule: makeEntry({
|
|
277
282
|
params: [
|
|
278
283
|
{ name: 'contractAddress', type: AZTEC_ADDRESS },
|
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
type Capsule,
|
|
36
36
|
type IndexedTxEffect,
|
|
37
37
|
type OffchainEffect,
|
|
38
|
+
type TxEffect,
|
|
38
39
|
type TxHash,
|
|
39
40
|
} from '@aztec/stdlib/tx';
|
|
40
41
|
|
|
@@ -48,6 +49,7 @@ import { TxResolverService } from '../../messages/tx_resolver_service.js';
|
|
|
48
49
|
import { NoteService } from '../../notes/note_service.js';
|
|
49
50
|
import { ORACLE_VERSION_MAJOR } from '../../oracle_version.js';
|
|
50
51
|
import type { AddressStore } from '../../storage/address_store/address_store.js';
|
|
52
|
+
import { assertAllowedScope } from '../../storage/allowed_scopes.js';
|
|
51
53
|
import type { CapsuleService } from '../../storage/capsule_store/capsule_service.js';
|
|
52
54
|
import { FactCollectionKey, FactCollectionTypeKey, anchoredTipBlockNumbers } from '../../storage/fact_store/index.js';
|
|
53
55
|
import type { FactService, OriginBlock } from '../../storage/fact_store/index.js';
|
|
@@ -612,6 +614,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
612
614
|
this.recipientTaggingStore,
|
|
613
615
|
this.taggingSecretSourcesStore,
|
|
614
616
|
this.addressStore,
|
|
617
|
+
this.scopes,
|
|
615
618
|
this.jobId,
|
|
616
619
|
this.logger.getBindings(),
|
|
617
620
|
);
|
|
@@ -683,21 +686,25 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
683
686
|
throw new Error('Invalid tx hash passed into aztec_utl_getTxEffect oracle handler');
|
|
684
687
|
}
|
|
685
688
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
+
return await this.#getTxEffectOption(txHash);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/** Fetches transaction effects for all hashes, preserving request order. */
|
|
693
|
+
public async getTxEffects(txHashes: EphemeralArray<TxHash>): Promise<EphemeralArray<Option<TxEffectData>>> {
|
|
694
|
+
const hashes = txHashes.readAll(this.ephemeralArrayService);
|
|
695
|
+
const invalidHash = hashes.find(txHash => txHash.hash.isZero());
|
|
696
|
+
if (invalidHash) {
|
|
697
|
+
throw new Error('Invalid tx hash passed into aztec_utl_getTxEffects oracle handler');
|
|
689
698
|
}
|
|
690
699
|
|
|
691
|
-
const
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
})),
|
|
700
|
-
});
|
|
700
|
+
const uniqueTxHashes = uniqueBy(hashes, h => h.toString());
|
|
701
|
+
const options = await Promise.all(uniqueTxHashes.map(txHash => this.#getTxEffectOption(txHash)));
|
|
702
|
+
const optionsByHash = new Map(uniqueTxHashes.map((txHash, i) => [txHash.toString(), options[i]]));
|
|
703
|
+
|
|
704
|
+
return EphemeralArray.fromValues(
|
|
705
|
+
this.ephemeralArrayService,
|
|
706
|
+
hashes.map(txHash => optionsByHash.get(txHash.toString())!),
|
|
707
|
+
);
|
|
701
708
|
}
|
|
702
709
|
|
|
703
710
|
public setCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[], scope: AztecAddress): void {
|
|
@@ -871,7 +878,8 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
871
878
|
* @param ephPks - Ephemeral array containing the serialized Points.
|
|
872
879
|
* @param contractAddress - The contract address for app-siloing (validated against execution context).
|
|
873
880
|
* @returns A new ephemeral array containing the computed shared secrets, or an empty array when the PXE does not
|
|
874
|
-
* hold the keys for `address
|
|
881
|
+
* hold the keys for `address`.
|
|
882
|
+
* @throws If `address` is not in the execution's allowed scopes.
|
|
875
883
|
*/
|
|
876
884
|
public async getSharedSecrets(
|
|
877
885
|
address: AztecAddress,
|
|
@@ -883,6 +891,11 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
883
891
|
`getSharedSecrets called with contract address ${contractAddress}, expected ${this.contractAddress}`,
|
|
884
892
|
);
|
|
885
893
|
}
|
|
894
|
+
|
|
895
|
+
assertAllowedScope(address, this.scopes);
|
|
896
|
+
|
|
897
|
+
// An address can be in scope without the PXE holding its keys (e.g. syncing a registered but non-owned account),
|
|
898
|
+
// in which case no secrets can be derived and we return an empty array rather than failing.
|
|
886
899
|
const recipientCompleteAddress = await this.addressStore.getCompleteAddress(address);
|
|
887
900
|
if (!recipientCompleteAddress) {
|
|
888
901
|
this.logger.warn(
|
|
@@ -1119,6 +1132,26 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
|
|
|
1119
1132
|
);
|
|
1120
1133
|
}
|
|
1121
1134
|
|
|
1135
|
+
async #getTxEffectOption(txHash: TxHash): Promise<Option<TxEffectData>> {
|
|
1136
|
+
const receipt = await this.aztecNodeReadCache.getTxReceiptWithEffect(txHash);
|
|
1137
|
+
if (!receipt.isMined() || !receipt.txEffect || receipt.blockNumber > this.anchorBlockHeader.getBlockNumber()) {
|
|
1138
|
+
return Option.none();
|
|
1139
|
+
}
|
|
1140
|
+
return Option.some(this.#toTxEffectData(receipt.txEffect));
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
#toTxEffectData(txEffect: TxEffect): TxEffectData {
|
|
1144
|
+
return {
|
|
1145
|
+
...txEffect,
|
|
1146
|
+
publicLogs: FlatPublicLogs.fromLogs(txEffect.publicLogs),
|
|
1147
|
+
contractClassLogs: txEffect.contractClassLogs.map(log => ({
|
|
1148
|
+
contractAddress: log.contractAddress,
|
|
1149
|
+
fields: log.fields.toFields(),
|
|
1150
|
+
emittedLength: log.emittedLength,
|
|
1151
|
+
})),
|
|
1152
|
+
};
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1122
1155
|
/** Runs a query concurrently with a validation that the block hash is not ahead of the anchor block. */
|
|
1123
1156
|
async #queryWithBlockHashNotAfterAnchor<T>(blockHash: BlockHash, query: () => Promise<T>): Promise<T> {
|
|
1124
1157
|
// Most contracts query state at the "current" block, which is the anchor. Skip the validation when we can.
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { BBBundlePrivateKernelProver } from '@aztec/bb-prover/client/bundle';
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import { createStore } from '@aztec/kv-store/sqlite-opfs';
|
|
4
3
|
import { BundledProtocolContractsProvider } from '@aztec/protocol-contracts/providers/bundle';
|
|
5
4
|
import { WASMSimulator } from '@aztec/simulator/client';
|
|
6
5
|
import { getStandardAuthRegistry } from '@aztec/standard-contracts/auth-registry';
|
|
@@ -12,6 +11,7 @@ import type { PXEConfig } from '../../../config/index.js';
|
|
|
12
11
|
import { PXE } from '../../../pxe.js';
|
|
13
12
|
import { PXE_DATA_SCHEMA_VERSION } from '../../../storage/metadata.js';
|
|
14
13
|
import { type PXECreationOptions, isPrivateKernelProver } from '../../pxe_creation_options.js';
|
|
14
|
+
import { openBrowserStore } from '../store.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Create and start an PXE instance with the given AztecNode.
|
|
@@ -31,16 +31,28 @@ export async function createPXE(
|
|
|
31
31
|
const actor = options.loggerActorLabel;
|
|
32
32
|
const loggers = options.loggers ?? {};
|
|
33
33
|
|
|
34
|
-
const l1ContractAddresses = await aztecNode.
|
|
34
|
+
const { l1ChainId, l1ContractAddresses, rollupVersion } = await aztecNode.getNodeInfo();
|
|
35
35
|
const configWithContracts = {
|
|
36
36
|
...config,
|
|
37
37
|
...l1ContractAddresses,
|
|
38
|
+
l1ChainId,
|
|
39
|
+
rollupVersion,
|
|
38
40
|
} as PXEConfig;
|
|
39
41
|
|
|
40
42
|
const storeLogger = loggers.store ?? createLogger('pxe:data', { actor });
|
|
41
43
|
|
|
42
44
|
const store =
|
|
43
|
-
options.store ??
|
|
45
|
+
options.store ??
|
|
46
|
+
(await openBrowserStore(
|
|
47
|
+
'pxe_data',
|
|
48
|
+
PXE_DATA_SCHEMA_VERSION,
|
|
49
|
+
{
|
|
50
|
+
l1ChainId,
|
|
51
|
+
rollupAddress: l1ContractAddresses.rollupAddress,
|
|
52
|
+
dataStoreMapSizeKb: configWithContracts.dataStoreMapSizeKb,
|
|
53
|
+
},
|
|
54
|
+
storeLogger,
|
|
55
|
+
));
|
|
44
56
|
|
|
45
57
|
const simulator = options.simulator ?? new WASMSimulator();
|
|
46
58
|
const proverLogger = loggers.prover ?? createLogger('pxe:bb:wasm:bundle', { actor });
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { BBLazyPrivateKernelProver } from '@aztec/bb-prover/client/lazy';
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
|
-
import { createStore } from '@aztec/kv-store/sqlite-opfs';
|
|
4
3
|
import { LazyProtocolContractsProvider } from '@aztec/protocol-contracts/providers/lazy';
|
|
5
4
|
import { WASMSimulator } from '@aztec/simulator/client';
|
|
6
5
|
import { getStandardAuthRegistry } from '@aztec/standard-contracts/auth-registry/lazy';
|
|
@@ -12,6 +11,7 @@ import type { PXEConfig } from '../../../config/index.js';
|
|
|
12
11
|
import { PXE } from '../../../pxe.js';
|
|
13
12
|
import { PXE_DATA_SCHEMA_VERSION } from '../../../storage/metadata.js';
|
|
14
13
|
import { type PXECreationOptions, isPrivateKernelProver } from '../../pxe_creation_options.js';
|
|
14
|
+
import { openBrowserStore } from '../store.js';
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* Create and start an PXE instance with the given AztecNode.
|
|
@@ -29,10 +29,12 @@ export async function createPXE(
|
|
|
29
29
|
) {
|
|
30
30
|
const actor = options.loggerActorLabel;
|
|
31
31
|
|
|
32
|
-
const l1ContractAddresses = await aztecNode.
|
|
32
|
+
const { l1ChainId, l1ContractAddresses, rollupVersion } = await aztecNode.getNodeInfo();
|
|
33
33
|
const configWithContracts = {
|
|
34
34
|
...config,
|
|
35
35
|
...l1ContractAddresses,
|
|
36
|
+
l1ChainId,
|
|
37
|
+
rollupVersion,
|
|
36
38
|
} as PXEConfig;
|
|
37
39
|
|
|
38
40
|
const loggers = options.loggers ?? {};
|
|
@@ -40,7 +42,17 @@ export async function createPXE(
|
|
|
40
42
|
const storeLogger = loggers.store ?? createLogger('pxe:data', { actor });
|
|
41
43
|
|
|
42
44
|
const store =
|
|
43
|
-
options.store ??
|
|
45
|
+
options.store ??
|
|
46
|
+
(await openBrowserStore(
|
|
47
|
+
'pxe_data',
|
|
48
|
+
PXE_DATA_SCHEMA_VERSION,
|
|
49
|
+
{
|
|
50
|
+
l1ChainId,
|
|
51
|
+
rollupAddress: l1ContractAddresses.rollupAddress,
|
|
52
|
+
dataStoreMapSizeKb: configWithContracts.dataStoreMapSizeKb,
|
|
53
|
+
},
|
|
54
|
+
storeLogger,
|
|
55
|
+
));
|
|
44
56
|
|
|
45
57
|
const simulator = options.simulator ?? new WASMSimulator();
|
|
46
58
|
const proverLogger = loggers.prover ?? createLogger('pxe:bb:wasm:bundle', { actor });
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { AztecSQLiteOPFSStore, storePoolDirectory } from '@aztec/kv-store/sqlite-opfs';
|
|
4
|
+
|
|
5
|
+
import { assertStoreIdentity, effectiveStoreName } from '../../storage/store_identity.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Opens the persistent browser (sqlite-opfs) store selected by `name` and identity `(config.l1ChainId,
|
|
9
|
+
* config.rollupAddress, schemaVersion)` triple. A store exists per identity: reopening with the same identity returns
|
|
10
|
+
* the same data, a different identity selects a different (possibly fresh) store.
|
|
11
|
+
*/
|
|
12
|
+
export async function openBrowserStore(
|
|
13
|
+
name: string,
|
|
14
|
+
schemaVersion: number,
|
|
15
|
+
config: { l1ChainId: number; rollupAddress: EthAddress; dataStoreMapSizeKb?: number },
|
|
16
|
+
log: Logger = createLogger('pxe:data'),
|
|
17
|
+
): Promise<AztecSQLiteOPFSStore> {
|
|
18
|
+
const identity = { l1ChainId: config.l1ChainId, rollupAddress: config.rollupAddress, schemaVersion };
|
|
19
|
+
const storeName = effectiveStoreName(name, identity);
|
|
20
|
+
log.info(`Creating ${storeName} SQLite-OPFS data store`, {
|
|
21
|
+
storeName,
|
|
22
|
+
dataStoreMapSizeKb: config.dataStoreMapSizeKb,
|
|
23
|
+
});
|
|
24
|
+
const store = await AztecSQLiteOPFSStore.open(
|
|
25
|
+
createLogger('kv-store:sqlite-opfs'),
|
|
26
|
+
storeName,
|
|
27
|
+
false,
|
|
28
|
+
storePoolDirectory(storeName),
|
|
29
|
+
);
|
|
30
|
+
try {
|
|
31
|
+
await assertStoreIdentity(store, storeName, identity);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
// The store handle owns a worker and OPFS locks; release them before surfacing the refusal.
|
|
34
|
+
await store.close().catch(() => {});
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
return store;
|
|
38
|
+
}
|
|
@@ -6,6 +6,7 @@ export * from '../../config/index.js';
|
|
|
6
6
|
export * from '../../error_enriching.js';
|
|
7
7
|
export * from '../../storage/index.js';
|
|
8
8
|
export * from './utils.js';
|
|
9
|
+
export * from './store.js';
|
|
9
10
|
export { NoteService } from '../../notes/note_service.js';
|
|
10
11
|
export { ORACLE_VERSION_MAJOR, ORACLE_VERSION_MINOR } from '../../oracle_version.js';
|
|
11
12
|
export { type PXECreationOptions } from '../pxe_creation_options.js';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import { type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
3
|
+
import { type AztecLMDBStoreV2, openStoreAt } from '@aztec/kv-store/lmdb-v2';
|
|
4
|
+
|
|
5
|
+
import { mkdir } from 'fs/promises';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
|
|
8
|
+
import { storeIdentitySlug } from '../../storage/store_identity.js';
|
|
9
|
+
|
|
10
|
+
/** Location and identity inputs for opening an identity-partitioned PXE-side store. */
|
|
11
|
+
export type IdentityStoreConfig = {
|
|
12
|
+
dataDirectory: string;
|
|
13
|
+
/** Maximum LMDB map size in KB. When omitted, the kv-store default map size applies. */
|
|
14
|
+
dataStoreMapSizeKb?: number;
|
|
15
|
+
l1ChainId: number;
|
|
16
|
+
rollupAddress: EthAddress;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Opens the persistent LMDB store selected by `name` and identity triple `(l1ChainId, rollupAddress, schemaVersion)`.
|
|
21
|
+
* A store exists per identity: reopening with the same identity returns the same data, a different identity selects
|
|
22
|
+
* a different (possibly fresh) store. Callers wanting an ephemeral store use `openTmpStore` explicitly instead.
|
|
23
|
+
*/
|
|
24
|
+
export async function openStore(
|
|
25
|
+
name: string,
|
|
26
|
+
schemaVersion: number,
|
|
27
|
+
config: IdentityStoreConfig,
|
|
28
|
+
bindings?: LoggerBindings,
|
|
29
|
+
): Promise<AztecLMDBStoreV2> {
|
|
30
|
+
// Stores live under `<dataDirectory>/<name>-stores/<l1ChainId>-<rollupAddress>-v<schemaVersion>`, a sibling of the
|
|
31
|
+
// legacy `<dataDirectory>/<name>` directory: older binaries reset the legacy directory on a rollup mismatch, so
|
|
32
|
+
// per-identity stores must not nest inside it.
|
|
33
|
+
const subDir = join(
|
|
34
|
+
config.dataDirectory,
|
|
35
|
+
`${name}-stores`,
|
|
36
|
+
storeIdentitySlug({ l1ChainId: config.l1ChainId, rollupAddress: config.rollupAddress, schemaVersion }),
|
|
37
|
+
);
|
|
38
|
+
await mkdir(subDir, { recursive: true });
|
|
39
|
+
|
|
40
|
+
createLogger(`pxe:data:${name}`, bindings).info(`Opening ${name} data store (LMDB v2)`, {
|
|
41
|
+
storeName: name,
|
|
42
|
+
subDir,
|
|
43
|
+
dataStoreMapSizeKb: config.dataStoreMapSizeKb,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return openStoreAt(subDir, config.dataStoreMapSizeKb, undefined, bindings);
|
|
47
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BBBundlePrivateKernelProver } from '@aztec/bb-prover/client/bundle';
|
|
2
2
|
import type { L1ContractAddresses } from '@aztec/ethereum/l1-contract-addresses';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
|
-
import {
|
|
4
|
+
import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
|
|
5
5
|
import { BundledProtocolContractsProvider } from '@aztec/protocol-contracts/providers/bundle';
|
|
6
6
|
import { WASMSimulator } from '@aztec/simulator/client';
|
|
7
7
|
import { MemoryCircuitRecorder, SimulatorRecorderWrapper } from '@aztec/simulator/server';
|
|
@@ -15,6 +15,7 @@ import type { PXEConfig } from '../../config/index.js';
|
|
|
15
15
|
import { PXE } from '../../pxe.js';
|
|
16
16
|
import { PXE_DATA_SCHEMA_VERSION } from '../../storage/index.js';
|
|
17
17
|
import { type PXECreationOptions, isPrivateKernelProver } from '../pxe_creation_options.js';
|
|
18
|
+
import { openStore } from './store.js';
|
|
18
19
|
|
|
19
20
|
type PXEConfigWithoutDefaults = Omit<
|
|
20
21
|
PXEConfig,
|
|
@@ -46,12 +47,25 @@ export async function createPXE(
|
|
|
46
47
|
|
|
47
48
|
if (!options.store) {
|
|
48
49
|
const storeLogger = loggers.store ?? createLogger('pxe:data:lmdb', { actor });
|
|
49
|
-
options.store =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
options.store = configWithContracts.dataDirectory
|
|
51
|
+
? await openStore(
|
|
52
|
+
'pxe_data',
|
|
53
|
+
PXE_DATA_SCHEMA_VERSION,
|
|
54
|
+
{
|
|
55
|
+
dataDirectory: configWithContracts.dataDirectory,
|
|
56
|
+
dataStoreMapSizeKb: configWithContracts.dataStoreMapSizeKb,
|
|
57
|
+
l1ChainId,
|
|
58
|
+
rollupAddress: l1ContractAddresses.rollupAddress,
|
|
59
|
+
},
|
|
60
|
+
storeLogger.getBindings(),
|
|
61
|
+
)
|
|
62
|
+
: await openTmpStore(
|
|
63
|
+
'pxe_data',
|
|
64
|
+
true,
|
|
65
|
+
configWithContracts.dataStoreMapSizeKb,
|
|
66
|
+
undefined,
|
|
67
|
+
storeLogger.getBindings(),
|
|
68
|
+
);
|
|
55
69
|
}
|
|
56
70
|
const proverLogger = loggers.prover ?? createLogger('pxe:bb:native', { actor });
|
|
57
71
|
|
package/src/logs/log_service.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type { LogRetrievalResponse } from '../contract_function_simulator/noir-s
|
|
|
24
24
|
import type { PendingTaggedLog } from '../contract_function_simulator/noir-structs/pending_tagged_log.js';
|
|
25
25
|
import { ResolvedTx } from '../contract_function_simulator/noir-structs/resolved_tx.js';
|
|
26
26
|
import { AddressStore } from '../storage/address_store/address_store.js';
|
|
27
|
+
import { assertAllowedScope } from '../storage/allowed_scopes.js';
|
|
27
28
|
import type { RecipientTaggingStore } from '../storage/tagging_store/recipient_tagging_store.js';
|
|
28
29
|
import type { TaggingSecretSourcesStore } from '../storage/tagging_store/tagging_secret_sources_store.js';
|
|
29
30
|
import {
|
|
@@ -47,6 +48,7 @@ export class LogService {
|
|
|
47
48
|
private readonly recipientTaggingStore: RecipientTaggingStore,
|
|
48
49
|
private readonly taggingSecretSourcesStore: TaggingSecretSourcesStore,
|
|
49
50
|
private readonly addressStore: AddressStore,
|
|
51
|
+
private readonly scopes: AztecAddress[],
|
|
50
52
|
private readonly jobId: string,
|
|
51
53
|
bindings?: LoggerBindings,
|
|
52
54
|
) {
|
|
@@ -189,6 +191,8 @@ export class LogService {
|
|
|
189
191
|
recipient: AztecAddress,
|
|
190
192
|
providedSecrets: AppTaggingSecret[],
|
|
191
193
|
): Promise<PendingTaggedLog[]> {
|
|
194
|
+
assertAllowedScope(recipient, this.scopes);
|
|
195
|
+
|
|
192
196
|
this.log.verbose(
|
|
193
197
|
`Fetching tagged logs for contract ${contractAddress.toString()} and recipient ${recipient.toString()}`,
|
|
194
198
|
);
|
|
@@ -26,7 +26,7 @@ export class NoteService {
|
|
|
26
26
|
*
|
|
27
27
|
* @param owner - The owner of the notes. If undefined, returns notes for all known owners.
|
|
28
28
|
* @param status - The status of notes to fetch.
|
|
29
|
-
* @param scopes - The accounts whose notes we can access in this call.
|
|
29
|
+
* @param scopes - The accounts whose notes we can access in this call. An empty list matches no notes.
|
|
30
30
|
*/
|
|
31
31
|
public async getNotes(
|
|
32
32
|
contractAddress: AztecAddress,
|
package/src/oracle_version.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/// if AZTEC_NR_MINOR > PXE_MINOR because if a contract is updated to use a newer Aztec.nr dependency without actually
|
|
12
12
|
/// using any of the new oracles then there is no reason to throw.
|
|
13
13
|
export const ORACLE_VERSION_MAJOR = 30;
|
|
14
|
-
export const ORACLE_VERSION_MINOR =
|
|
14
|
+
export const ORACLE_VERSION_MINOR = 8;
|
|
15
15
|
|
|
16
16
|
/// This hash is computed from the `ORACLE_REGISTRY` declaration (each oracle's name, ordered parameter names and
|
|
17
17
|
/// types, and return type) and is used to detect when the oracle interface changes. When it does, you need to either:
|
|
@@ -19,4 +19,4 @@ export const ORACLE_VERSION_MINOR = 7;
|
|
|
19
19
|
/// - increment only `ORACLE_VERSION_MINOR` if the change is additive (a new oracle was added).
|
|
20
20
|
///
|
|
21
21
|
/// These constants must be kept in sync between this file and `noir-projects/aztec-nr/aztec/src/oracle/version.nr`.
|
|
22
|
-
export const ORACLE_INTERFACE_HASH = '
|
|
22
|
+
export const ORACLE_INTERFACE_HASH = 'b302a8e65d37043c0a0dc08a39895603122dce334843f0442462edb3f56e32e2';
|
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. */
|
|
@@ -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
|
+
}
|