@aztec/txe 0.86.0-starknet.1 → 0.87.0
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/oracle/txe_oracle.d.ts +10 -6
- package/dest/oracle/txe_oracle.d.ts.map +1 -1
- package/dest/oracle/txe_oracle.js +190 -13
- package/dest/state_machine/archiver.d.ts +6 -0
- package/dest/state_machine/archiver.d.ts.map +1 -1
- package/dest/state_machine/archiver.js +10 -3
- package/dest/state_machine/dummy_p2p_client.d.ts +4 -1
- package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
- package/dest/state_machine/dummy_p2p_client.js +9 -0
- package/dest/state_machine/index.d.ts.map +1 -1
- package/dest/state_machine/index.js +3 -1
- package/dest/state_machine/synchronizer.d.ts +2 -1
- package/dest/state_machine/synchronizer.d.ts.map +1 -1
- package/dest/state_machine/synchronizer.js +3 -0
- package/dest/txe_service/txe_service.d.ts +12 -3
- package/dest/txe_service/txe_service.d.ts.map +1 -1
- package/dest/txe_service/txe_service.js +221 -37
- package/dest/util/encoding.d.ts +11 -4
- package/dest/util/encoding.d.ts.map +1 -1
- package/dest/util/encoding.js +38 -2
- package/package.json +18 -18
- package/src/oracle/txe_oracle.ts +368 -15
- package/src/state_machine/archiver.ts +12 -3
- package/src/state_machine/dummy_p2p_client.ts +13 -1
- package/src/state_machine/index.ts +4 -1
- package/src/state_machine/synchronizer.ts +5 -1
- package/src/txe_service/txe_service.ts +427 -31
- package/src/util/encoding.ts +51 -2
package/dest/util/encoding.js
CHANGED
|
@@ -40,8 +40,20 @@ export function fromArray(obj) {
|
|
|
40
40
|
const boundedStorage = storage.slice(0, fromSingle(length).toNumber());
|
|
41
41
|
return Buffer.concat(boundedStorage.map((str)=>hexToBuffer(str).slice(-uintByteSize)));
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// Just like toACVMField in yarn-project/simulator/src/private/acvm/serialize.ts but returns a ForeignCallSingle
|
|
44
|
+
// instead of an ACVMField.
|
|
45
|
+
export function toSingle(value) {
|
|
46
|
+
let valueAsField;
|
|
47
|
+
if (Buffer.isBuffer(value)) {
|
|
48
|
+
valueAsField = Fr.fromBuffer(value);
|
|
49
|
+
} else if (typeof value === 'boolean' || typeof value === 'number' || typeof value === 'bigint') {
|
|
50
|
+
valueAsField = new Fr(value);
|
|
51
|
+
} else if (typeof value === 'string') {
|
|
52
|
+
valueAsField = Fr.fromHexString(value);
|
|
53
|
+
} else {
|
|
54
|
+
valueAsField = value;
|
|
55
|
+
}
|
|
56
|
+
return valueAsField.toString().slice(2);
|
|
45
57
|
}
|
|
46
58
|
export function toArray(objs) {
|
|
47
59
|
return objs.map((obj)=>obj.toString());
|
|
@@ -74,6 +86,30 @@ export function bufferToU8Array(buffer) {
|
|
|
74
86
|
len
|
|
75
87
|
];
|
|
76
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Converts an array of arrays representing Noir BoundedVec of nested arrays into its Noir serialized form.
|
|
91
|
+
* @param bVecStorage - The array underlying the BoundedVec.
|
|
92
|
+
* @param maxLen - The max length of the BoundedVec (max num of the nested arrays in the BoundedVec).
|
|
93
|
+
* @param nestedArrayLength - The length of the nested arrays (each nested array has to have the same length).
|
|
94
|
+
* @returns Serialized BoundedVec following Noir intrinsic serialization.
|
|
95
|
+
*/ export function arrayOfArraysToBoundedVecOfArrays(bVecStorage, maxLen, nestedArrayLength) {
|
|
96
|
+
if (bVecStorage.length > maxLen) {
|
|
97
|
+
throw new Error(`Array of length ${bVecStorage.length} larger than maxLen ${maxLen}`);
|
|
98
|
+
}
|
|
99
|
+
// Check that all nested arrays have length nestedArrayLength
|
|
100
|
+
if (!bVecStorage.every((nestedArray)=>nestedArray.length === nestedArrayLength)) {
|
|
101
|
+
throw new Error(`Nested array length passed in from Noir does not correspond to the length obtained in TS: ${nestedArrayLength} !== ${bVecStorage[0].length}`);
|
|
102
|
+
}
|
|
103
|
+
const flattenedStorage = bVecStorage.flat();
|
|
104
|
+
const numFieldsToPad = maxLen * nestedArrayLength - flattenedStorage.length;
|
|
105
|
+
const flattenedStorageWithPadding = flattenedStorage.concat(Array(numFieldsToPad).fill(new Fr(0)));
|
|
106
|
+
// At last we get the actual length of the BoundedVec and return the values.
|
|
107
|
+
const len = toSingle(new Fr(bVecStorage.length));
|
|
108
|
+
return [
|
|
109
|
+
flattenedStorageWithPadding,
|
|
110
|
+
len
|
|
111
|
+
];
|
|
112
|
+
}
|
|
77
113
|
export function toForeignCallResult(obj) {
|
|
78
114
|
return {
|
|
79
115
|
values: obj
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/txe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.87.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": "./dest/index.js",
|
|
6
6
|
"bin": "./dest/bin/index.js",
|
|
@@ -57,30 +57,30 @@
|
|
|
57
57
|
]
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@aztec/accounts": "0.
|
|
61
|
-
"@aztec/archiver": "0.
|
|
62
|
-
"@aztec/aztec-node": "0.
|
|
63
|
-
"@aztec/aztec.js": "0.
|
|
64
|
-
"@aztec/bb-prover": "0.
|
|
65
|
-
"@aztec/constants": "0.
|
|
66
|
-
"@aztec/foundation": "0.
|
|
67
|
-
"@aztec/key-store": "0.
|
|
68
|
-
"@aztec/kv-store": "0.
|
|
69
|
-
"@aztec/protocol-contracts": "0.
|
|
70
|
-
"@aztec/pxe": "0.
|
|
71
|
-
"@aztec/simulator": "0.
|
|
72
|
-
"@aztec/stdlib": "0.
|
|
73
|
-
"@aztec/world-state": "0.
|
|
60
|
+
"@aztec/accounts": "0.87.0",
|
|
61
|
+
"@aztec/archiver": "0.87.0",
|
|
62
|
+
"@aztec/aztec-node": "0.87.0",
|
|
63
|
+
"@aztec/aztec.js": "0.87.0",
|
|
64
|
+
"@aztec/bb-prover": "0.87.0",
|
|
65
|
+
"@aztec/constants": "0.87.0",
|
|
66
|
+
"@aztec/foundation": "0.87.0",
|
|
67
|
+
"@aztec/key-store": "0.87.0",
|
|
68
|
+
"@aztec/kv-store": "0.87.0",
|
|
69
|
+
"@aztec/protocol-contracts": "0.87.0",
|
|
70
|
+
"@aztec/pxe": "0.87.0",
|
|
71
|
+
"@aztec/simulator": "0.87.0",
|
|
72
|
+
"@aztec/stdlib": "0.87.0",
|
|
73
|
+
"@aztec/world-state": "0.87.0",
|
|
74
74
|
"zod": "^3.23.8"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@jest/globals": "^29.5.0",
|
|
78
78
|
"@types/jest": "^29.5.0",
|
|
79
|
-
"@types/node": "^
|
|
79
|
+
"@types/node": "^22.15.17",
|
|
80
80
|
"jest": "^29.5.0",
|
|
81
81
|
"jest-mock-extended": "^3.0.3",
|
|
82
82
|
"ts-node": "^10.9.1",
|
|
83
|
-
"typescript": "^5.
|
|
83
|
+
"typescript": "^5.3.3"
|
|
84
84
|
},
|
|
85
85
|
"files": [
|
|
86
86
|
"dest",
|
|
@@ -89,6 +89,6 @@
|
|
|
89
89
|
],
|
|
90
90
|
"types": "./dest/index.d.ts",
|
|
91
91
|
"engines": {
|
|
92
|
-
"node": ">=
|
|
92
|
+
"node": ">=20.10"
|
|
93
93
|
}
|
|
94
94
|
}
|
package/src/oracle/txe_oracle.ts
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { type AztecNode, Body, L2Block, Note } from '@aztec/aztec.js';
|
|
2
2
|
import {
|
|
3
|
+
DEFAULT_GAS_LIMIT,
|
|
4
|
+
DEFAULT_TEARDOWN_GAS_LIMIT,
|
|
3
5
|
type L1_TO_L2_MSG_TREE_HEIGHT,
|
|
6
|
+
MAX_CONTRACT_CLASS_LOGS_PER_TX,
|
|
7
|
+
MAX_ENQUEUED_CALLS_PER_TX,
|
|
8
|
+
MAX_L2_GAS_PER_TX_PUBLIC_PORTION,
|
|
9
|
+
MAX_L2_TO_L1_MSGS_PER_TX,
|
|
4
10
|
MAX_NOTE_HASHES_PER_TX,
|
|
5
11
|
MAX_NULLIFIERS_PER_TX,
|
|
12
|
+
MAX_PRIVATE_LOGS_PER_TX,
|
|
6
13
|
NULLIFIER_SUBTREE_HEIGHT,
|
|
7
14
|
type NULLIFIER_TREE_HEIGHT,
|
|
8
15
|
NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
|
|
@@ -13,7 +20,7 @@ import { padArrayEnd } from '@aztec/foundation/collection';
|
|
|
13
20
|
import { Aes128, Schnorr, poseidon2Hash } from '@aztec/foundation/crypto';
|
|
14
21
|
import { Fr, Point } from '@aztec/foundation/fields';
|
|
15
22
|
import { type Logger, applyStringFormatting } from '@aztec/foundation/log';
|
|
16
|
-
import { Timer } from '@aztec/foundation/timer';
|
|
23
|
+
import { TestDateProvider, Timer } from '@aztec/foundation/timer';
|
|
17
24
|
import { KeyStore } from '@aztec/key-store';
|
|
18
25
|
import type { AztecAsyncKVStore } from '@aztec/kv-store';
|
|
19
26
|
import type { ProtocolContract } from '@aztec/protocol-contracts';
|
|
@@ -34,8 +41,11 @@ import {
|
|
|
34
41
|
type MessageLoadOracleInputs,
|
|
35
42
|
type NoteData,
|
|
36
43
|
Oracle,
|
|
44
|
+
PrivateExecutionOracle,
|
|
37
45
|
type TypedOracle,
|
|
46
|
+
UtilityExecutionOracle,
|
|
38
47
|
WASMSimulator,
|
|
48
|
+
executePrivateFunction,
|
|
39
49
|
extractCallStack,
|
|
40
50
|
extractPrivateCircuitPublicInputs,
|
|
41
51
|
pickNotes,
|
|
@@ -46,6 +56,7 @@ import { createTxForPublicCalls } from '@aztec/simulator/public/fixtures';
|
|
|
46
56
|
import {
|
|
47
57
|
ExecutionError,
|
|
48
58
|
PublicContractsDB,
|
|
59
|
+
PublicProcessor,
|
|
49
60
|
type PublicTxResult,
|
|
50
61
|
PublicTxSimulator,
|
|
51
62
|
createSimulationError,
|
|
@@ -56,6 +67,7 @@ import {
|
|
|
56
67
|
EventSelector,
|
|
57
68
|
type FunctionAbi,
|
|
58
69
|
FunctionSelector,
|
|
70
|
+
FunctionType,
|
|
59
71
|
type NoteSelector,
|
|
60
72
|
countArgumentsSize,
|
|
61
73
|
} from '@aztec/stdlib/abi';
|
|
@@ -64,25 +76,33 @@ import { PublicDataWrite } from '@aztec/stdlib/avm';
|
|
|
64
76
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
65
77
|
import type { ContractInstance, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
66
78
|
import { SimulationError } from '@aztec/stdlib/errors';
|
|
67
|
-
import { Gas, GasFees } from '@aztec/stdlib/gas';
|
|
79
|
+
import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
|
|
68
80
|
import {
|
|
69
81
|
computeNoteHashNonce,
|
|
70
82
|
computePublicDataTreeLeafSlot,
|
|
71
83
|
computeUniqueNoteHash,
|
|
84
|
+
computeVarArgsHash,
|
|
72
85
|
siloNoteHash,
|
|
73
86
|
siloNullifier,
|
|
74
87
|
} from '@aztec/stdlib/hash';
|
|
75
88
|
import type { MerkleTreeReadOperations, MerkleTreeWriteOperations } from '@aztec/stdlib/interfaces/server';
|
|
76
|
-
import { type KeyValidationRequest, PrivateContextInputs, PublicCallRequest } from '@aztec/stdlib/kernel';
|
|
77
|
-
import { deriveKeys } from '@aztec/stdlib/keys';
|
|
78
89
|
import {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
type KeyValidationRequest,
|
|
91
|
+
PartialPrivateTailPublicInputsForPublic,
|
|
92
|
+
PartialPrivateTailPublicInputsForRollup,
|
|
93
|
+
PrivateContextInputs,
|
|
94
|
+
PrivateKernelTailCircuitPublicInputs,
|
|
95
|
+
PrivateToPublicAccumulatedData,
|
|
96
|
+
PrivateToRollupAccumulatedData,
|
|
97
|
+
PublicCallRequest,
|
|
98
|
+
RollupValidationRequests,
|
|
99
|
+
ScopedLogHash,
|
|
100
|
+
} from '@aztec/stdlib/kernel';
|
|
101
|
+
import { deriveKeys } from '@aztec/stdlib/keys';
|
|
102
|
+
import { ContractClassLog, IndexedTaggingSecret, LogWithTxData, PrivateLog, type PublicLog } from '@aztec/stdlib/logs';
|
|
103
|
+
import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
|
|
85
104
|
import type { NoteStatus } from '@aztec/stdlib/note';
|
|
105
|
+
import { ClientIvcProof } from '@aztec/stdlib/proofs';
|
|
86
106
|
import type { CircuitWitnessGenerationStats } from '@aztec/stdlib/stats';
|
|
87
107
|
import {
|
|
88
108
|
makeAppendOnlyTreeSnapshot,
|
|
@@ -103,9 +123,15 @@ import {
|
|
|
103
123
|
BlockHeader,
|
|
104
124
|
CallContext,
|
|
105
125
|
GlobalVariables,
|
|
126
|
+
HashedValues,
|
|
127
|
+
PrivateExecutionResult,
|
|
106
128
|
PublicCallRequestWithCalldata,
|
|
129
|
+
Tx,
|
|
130
|
+
TxConstantData,
|
|
131
|
+
TxContext,
|
|
107
132
|
TxEffect,
|
|
108
133
|
TxHash,
|
|
134
|
+
collectNested,
|
|
109
135
|
} from '@aztec/stdlib/tx';
|
|
110
136
|
import { ForkCheckpoint, NativeWorldStateService } from '@aztec/world-state/native';
|
|
111
137
|
|
|
@@ -140,7 +166,7 @@ export class TXE implements TypedOracle {
|
|
|
140
166
|
|
|
141
167
|
private simulationProvider = new WASMSimulator();
|
|
142
168
|
|
|
143
|
-
|
|
169
|
+
public noteCache: ExecutionNoteCache;
|
|
144
170
|
|
|
145
171
|
private authwits: Map<string, AuthWitness> = new Map();
|
|
146
172
|
|
|
@@ -385,9 +411,7 @@ export class TXE implements TypedOracle {
|
|
|
385
411
|
addPublicLogs(logs: PublicLog[]) {
|
|
386
412
|
logs.forEach(log => {
|
|
387
413
|
try {
|
|
388
|
-
|
|
389
|
-
const tag = log.log[1];
|
|
390
|
-
|
|
414
|
+
const tag = log.fields[0];
|
|
391
415
|
this.logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.blockNumber}`);
|
|
392
416
|
this.publicLogs.push(log);
|
|
393
417
|
} catch (err) {
|
|
@@ -623,7 +647,6 @@ export class TXE implements TypedOracle {
|
|
|
623
647
|
counter,
|
|
624
648
|
);
|
|
625
649
|
this.sideEffectCounter = counter + 1;
|
|
626
|
-
return Promise.resolve();
|
|
627
650
|
}
|
|
628
651
|
|
|
629
652
|
async notifyNullifiedNote(innerNullifier: Fr, noteHash: Fr, counter: number) {
|
|
@@ -729,6 +752,7 @@ export class TXE implements TypedOracle {
|
|
|
729
752
|
txEffect.noteHashes = [...uniqueNoteHashesFromPrivate, ...this.uniqueNoteHashesFromPublic];
|
|
730
753
|
|
|
731
754
|
txEffect.nullifiers = [...this.siloedNullifiersFromPublic, ...this.noteCache.getAllNullifiers()];
|
|
755
|
+
|
|
732
756
|
if (usedTxRequestHashForNonces) {
|
|
733
757
|
txEffect.nullifiers.unshift(this.getTxRequestHash());
|
|
734
758
|
}
|
|
@@ -812,6 +836,61 @@ export class TXE implements TypedOracle {
|
|
|
812
836
|
throw new Error('Method not implemented.');
|
|
813
837
|
}
|
|
814
838
|
|
|
839
|
+
async simulateUtilityFunction(targetContractAddress: AztecAddress, functionSelector: FunctionSelector, argsHash: Fr) {
|
|
840
|
+
const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
841
|
+
if (!artifact) {
|
|
842
|
+
throw new Error(`Cannot call ${functionSelector} as there is artifact found at ${targetContractAddress}.`);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const call = {
|
|
846
|
+
name: artifact.name,
|
|
847
|
+
selector: functionSelector,
|
|
848
|
+
to: targetContractAddress,
|
|
849
|
+
};
|
|
850
|
+
|
|
851
|
+
const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
|
|
852
|
+
|
|
853
|
+
if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
|
|
854
|
+
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface, undefined, undefined);
|
|
858
|
+
|
|
859
|
+
try {
|
|
860
|
+
this.logger.verbose(`Executing utility function ${entryPointArtifact.name}`, {
|
|
861
|
+
contract: call.to,
|
|
862
|
+
selector: call.selector,
|
|
863
|
+
});
|
|
864
|
+
|
|
865
|
+
const args = await this.loadFromExecutionCache(argsHash);
|
|
866
|
+
const initialWitness = toACVMWitness(0, args);
|
|
867
|
+
const acirExecutionResult = await this.simulationProvider
|
|
868
|
+
.executeUserCircuit(initialWitness, entryPointArtifact, new Oracle(oracle))
|
|
869
|
+
.catch((err: Error) => {
|
|
870
|
+
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
|
|
871
|
+
throw new ExecutionError(
|
|
872
|
+
err.message,
|
|
873
|
+
{
|
|
874
|
+
contractAddress: call.to,
|
|
875
|
+
functionSelector: call.selector,
|
|
876
|
+
},
|
|
877
|
+
extractCallStack(err, entryPointArtifact.debug),
|
|
878
|
+
{ cause: err },
|
|
879
|
+
);
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness);
|
|
883
|
+
this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
|
|
884
|
+
|
|
885
|
+
const returnHash = await computeVarArgsHash(returnWitness);
|
|
886
|
+
|
|
887
|
+
this.storeInExecutionCache(returnWitness, returnHash);
|
|
888
|
+
return returnHash;
|
|
889
|
+
} catch (err) {
|
|
890
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
|
|
815
894
|
async callPrivateFunction(
|
|
816
895
|
targetContractAddress: AztecAddress,
|
|
817
896
|
functionSelector: FunctionSelector,
|
|
@@ -944,6 +1023,8 @@ export class TXE implements TypedOracle {
|
|
|
944
1023
|
contractsDB,
|
|
945
1024
|
globalVariables,
|
|
946
1025
|
/*doMerkleOperations=*/ false,
|
|
1026
|
+
/*skipFeeEnforcement=*/ false,
|
|
1027
|
+
/*clientInitiatedSimulation=*/ true,
|
|
947
1028
|
);
|
|
948
1029
|
|
|
949
1030
|
const { usedTxRequestHashForNonces } = this.noteCache.finish();
|
|
@@ -1267,4 +1348,276 @@ export class TXE implements TypedOracle {
|
|
|
1267
1348
|
txIndexInBlock,
|
|
1268
1349
|
);
|
|
1269
1350
|
}
|
|
1351
|
+
|
|
1352
|
+
async privateCallNewFlow(
|
|
1353
|
+
from: AztecAddress,
|
|
1354
|
+
targetContractAddress: AztecAddress = AztecAddress.zero(),
|
|
1355
|
+
functionSelector: FunctionSelector = FunctionSelector.empty(),
|
|
1356
|
+
args: Fr[],
|
|
1357
|
+
argsHash: Fr = Fr.zero(),
|
|
1358
|
+
isStaticCall: boolean = false,
|
|
1359
|
+
) {
|
|
1360
|
+
this.logger.verbose(
|
|
1361
|
+
`Executing external function ${await this.getDebugFunctionName(
|
|
1362
|
+
targetContractAddress,
|
|
1363
|
+
functionSelector,
|
|
1364
|
+
)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
|
|
1365
|
+
);
|
|
1366
|
+
|
|
1367
|
+
const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
|
|
1368
|
+
|
|
1369
|
+
if (artifact === undefined) {
|
|
1370
|
+
throw new Error('Function Artifact does not exist');
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
|
|
1374
|
+
|
|
1375
|
+
const gasLimits = new Gas(DEFAULT_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
|
|
1376
|
+
|
|
1377
|
+
const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_GAS_LIMIT, MAX_L2_GAS_PER_TX_PUBLIC_PORTION);
|
|
1378
|
+
|
|
1379
|
+
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
|
|
1380
|
+
|
|
1381
|
+
const txContext = new TxContext(this.CHAIN_ID, this.ROLLUP_VERSION, gasSettings);
|
|
1382
|
+
|
|
1383
|
+
const blockHeader = await this.pxeOracleInterface.getBlockHeader();
|
|
1384
|
+
|
|
1385
|
+
const noteCache = new ExecutionNoteCache(this.getTxRequestHash());
|
|
1386
|
+
|
|
1387
|
+
const context = new PrivateExecutionOracle(
|
|
1388
|
+
argsHash,
|
|
1389
|
+
txContext,
|
|
1390
|
+
callContext,
|
|
1391
|
+
/** Header of a block whose state is used during private execution (not the block the transaction is included in). */
|
|
1392
|
+
blockHeader,
|
|
1393
|
+
/** List of transient auth witnesses to be used during this simulation */
|
|
1394
|
+
[],
|
|
1395
|
+
/** List of transient auth witnesses to be used during this simulation */
|
|
1396
|
+
[],
|
|
1397
|
+
HashedValuesCache.create(),
|
|
1398
|
+
noteCache,
|
|
1399
|
+
this.pxeOracleInterface,
|
|
1400
|
+
this.simulationProvider,
|
|
1401
|
+
0,
|
|
1402
|
+
1,
|
|
1403
|
+
);
|
|
1404
|
+
|
|
1405
|
+
context.storeInExecutionCache(args, argsHash);
|
|
1406
|
+
|
|
1407
|
+
// Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
|
|
1408
|
+
let result;
|
|
1409
|
+
try {
|
|
1410
|
+
const executionResult = await executePrivateFunction(
|
|
1411
|
+
this.simulationProvider,
|
|
1412
|
+
context,
|
|
1413
|
+
artifact,
|
|
1414
|
+
targetContractAddress,
|
|
1415
|
+
functionSelector,
|
|
1416
|
+
);
|
|
1417
|
+
const { usedTxRequestHashForNonces } = noteCache.finish();
|
|
1418
|
+
const firstNullifierHint = usedTxRequestHashForNonces ? Fr.ZERO : noteCache.getAllNullifiers()[0];
|
|
1419
|
+
|
|
1420
|
+
const publicCallRequests = collectNested([executionResult], r => [
|
|
1421
|
+
...r.publicInputs.publicCallRequests.map(r => r.inner),
|
|
1422
|
+
r.publicInputs.publicTeardownCallRequest,
|
|
1423
|
+
]).filter(r => !r.isEmpty());
|
|
1424
|
+
const publicFunctionsCalldata = await Promise.all(
|
|
1425
|
+
publicCallRequests.map(async r => {
|
|
1426
|
+
const calldata = await context.loadFromExecutionCache(r.calldataHash);
|
|
1427
|
+
return new HashedValues(calldata, r.calldataHash);
|
|
1428
|
+
}),
|
|
1429
|
+
);
|
|
1430
|
+
|
|
1431
|
+
result = new PrivateExecutionResult(executionResult, firstNullifierHint, publicFunctionsCalldata);
|
|
1432
|
+
} catch (err) {
|
|
1433
|
+
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
const uniqueNoteHashes: Fr[] = [];
|
|
1437
|
+
const taggedPrivateLogs: PrivateLog[] = [];
|
|
1438
|
+
const nullifiers: Fr[] = result.firstNullifier.equals(Fr.ZERO)
|
|
1439
|
+
? [this.getTxRequestHash()]
|
|
1440
|
+
: noteCache.getAllNullifiers();
|
|
1441
|
+
const l2ToL1Messages: ScopedL2ToL1Message[] = [];
|
|
1442
|
+
const contractClassLogsHashes: ScopedLogHash[] = [];
|
|
1443
|
+
const publicCallRequests: PublicCallRequest[] = [];
|
|
1444
|
+
|
|
1445
|
+
const nonceGenerator = nullifiers[0];
|
|
1446
|
+
|
|
1447
|
+
let publicTeardownCallRequest;
|
|
1448
|
+
|
|
1449
|
+
let noteHashIndexInTx = 0;
|
|
1450
|
+
const executions = [result.entrypoint];
|
|
1451
|
+
while (executions.length !== 0) {
|
|
1452
|
+
const execution = executions.shift()!;
|
|
1453
|
+
executions.unshift(...execution!.nestedExecutions);
|
|
1454
|
+
|
|
1455
|
+
const { contractAddress } = execution.publicInputs.callContext;
|
|
1456
|
+
|
|
1457
|
+
const noteHashesFromExecution = await Promise.all(
|
|
1458
|
+
execution.publicInputs.noteHashes
|
|
1459
|
+
.filter(noteHash => !noteHash.isEmpty())
|
|
1460
|
+
.map(async noteHash => {
|
|
1461
|
+
const nonce = await computeNoteHashNonce(nonceGenerator, noteHashIndexInTx++);
|
|
1462
|
+
const siloedNoteHash = await siloNoteHash(contractAddress, noteHash.value);
|
|
1463
|
+
|
|
1464
|
+
// We could defer this to the public processor, and pass this in as non-revertible.
|
|
1465
|
+
return computeUniqueNoteHash(nonce, siloedNoteHash);
|
|
1466
|
+
}),
|
|
1467
|
+
);
|
|
1468
|
+
|
|
1469
|
+
const privateLogsFromExecution = await Promise.all(
|
|
1470
|
+
execution.publicInputs.privateLogs
|
|
1471
|
+
.filter(privateLog => !privateLog.isEmpty())
|
|
1472
|
+
.map(async metadata => {
|
|
1473
|
+
metadata.log.fields[0] = await poseidon2Hash([contractAddress, metadata.log.fields[0]]);
|
|
1474
|
+
|
|
1475
|
+
return metadata.log;
|
|
1476
|
+
}),
|
|
1477
|
+
);
|
|
1478
|
+
|
|
1479
|
+
uniqueNoteHashes.push(...noteHashesFromExecution);
|
|
1480
|
+
taggedPrivateLogs.push(...privateLogsFromExecution);
|
|
1481
|
+
l2ToL1Messages.push(
|
|
1482
|
+
...execution.publicInputs.l2ToL1Msgs
|
|
1483
|
+
.filter(l2ToL1Message => !l2ToL1Message.isEmpty())
|
|
1484
|
+
.map(message => message.scope(contractAddress)),
|
|
1485
|
+
);
|
|
1486
|
+
contractClassLogsHashes.push(
|
|
1487
|
+
...execution.publicInputs.contractClassLogsHashes
|
|
1488
|
+
.filter(contractClassLogsHash => !contractClassLogsHash.isEmpty())
|
|
1489
|
+
.map(message => message.logHash.scope(contractAddress)),
|
|
1490
|
+
);
|
|
1491
|
+
publicCallRequests.push(
|
|
1492
|
+
...execution.publicInputs.publicCallRequests
|
|
1493
|
+
.filter(publicCallRequest => !publicCallRequest.isEmpty())
|
|
1494
|
+
.map(callRequest => callRequest.inner),
|
|
1495
|
+
);
|
|
1496
|
+
|
|
1497
|
+
if (publicTeardownCallRequest !== undefined && !execution.publicInputs.publicTeardownCallRequest.isEmpty()) {
|
|
1498
|
+
throw new Error('Trying to set multiple teardown requests');
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
publicTeardownCallRequest = execution.publicInputs.publicTeardownCallRequest.isEmpty()
|
|
1502
|
+
? publicTeardownCallRequest
|
|
1503
|
+
: execution.publicInputs.publicTeardownCallRequest;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
const globals = makeGlobalVariables();
|
|
1507
|
+
globals.blockNumber = new Fr(this.blockNumber);
|
|
1508
|
+
globals.gasFees = GasFees.empty();
|
|
1509
|
+
|
|
1510
|
+
const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(this));
|
|
1511
|
+
const simulator = new PublicTxSimulator(this.baseFork, contractsDB, globals, true, true);
|
|
1512
|
+
const processor = new PublicProcessor(globals, this.baseFork, contractsDB, simulator, new TestDateProvider());
|
|
1513
|
+
|
|
1514
|
+
const constantData = new TxConstantData(blockHeader, txContext, Fr.zero(), Fr.zero());
|
|
1515
|
+
|
|
1516
|
+
const hasPublicCalls = result.publicFunctionCalldata.length !== 0;
|
|
1517
|
+
let inputsForRollup;
|
|
1518
|
+
let inputsForPublic;
|
|
1519
|
+
|
|
1520
|
+
// Private only
|
|
1521
|
+
if (result.publicFunctionCalldata.length === 0) {
|
|
1522
|
+
const accumulatedDataForRollup = new PrivateToRollupAccumulatedData(
|
|
1523
|
+
padArrayEnd(uniqueNoteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
1524
|
+
padArrayEnd(nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
|
|
1525
|
+
padArrayEnd(l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
|
|
1526
|
+
padArrayEnd(taggedPrivateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
|
|
1527
|
+
padArrayEnd(contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
|
|
1528
|
+
);
|
|
1529
|
+
|
|
1530
|
+
inputsForRollup = new PartialPrivateTailPublicInputsForRollup(accumulatedDataForRollup);
|
|
1531
|
+
} else {
|
|
1532
|
+
const accumulatedDataForPublic = new PrivateToPublicAccumulatedData(
|
|
1533
|
+
padArrayEnd(uniqueNoteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
1534
|
+
padArrayEnd(nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
|
|
1535
|
+
padArrayEnd(l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
|
|
1536
|
+
padArrayEnd(taggedPrivateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
|
|
1537
|
+
padArrayEnd(contractClassLogsHashes, ScopedLogHash.empty(), MAX_CONTRACT_CLASS_LOGS_PER_TX),
|
|
1538
|
+
padArrayEnd(publicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX),
|
|
1539
|
+
);
|
|
1540
|
+
|
|
1541
|
+
inputsForPublic = new PartialPrivateTailPublicInputsForPublic(
|
|
1542
|
+
// We are using non-revertible because we set the first nullifier to be used as a nonce generator, otherwise the tx hash is manually calculated.
|
|
1543
|
+
// nonrevertible
|
|
1544
|
+
accumulatedDataForPublic,
|
|
1545
|
+
// revertible
|
|
1546
|
+
PrivateToPublicAccumulatedData.empty(),
|
|
1547
|
+
publicTeardownCallRequest ?? PublicCallRequest.empty(),
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
const txData = new PrivateKernelTailCircuitPublicInputs(
|
|
1552
|
+
constantData,
|
|
1553
|
+
RollupValidationRequests.empty(),
|
|
1554
|
+
/*gasUsed=*/ new Gas(0, 0),
|
|
1555
|
+
/*feePayer=*/ AztecAddress.zero(),
|
|
1556
|
+
hasPublicCalls ? inputsForPublic : undefined,
|
|
1557
|
+
!hasPublicCalls ? inputsForRollup : undefined,
|
|
1558
|
+
);
|
|
1559
|
+
|
|
1560
|
+
const tx = new Tx(txData, ClientIvcProof.empty(), [], result.publicFunctionCalldata);
|
|
1561
|
+
|
|
1562
|
+
const results = await processor.process([tx]);
|
|
1563
|
+
|
|
1564
|
+
const processedTxs = results[0];
|
|
1565
|
+
const failedTxs = results[1];
|
|
1566
|
+
|
|
1567
|
+
if (failedTxs.length !== 0) {
|
|
1568
|
+
throw new Error('Public execution has failed');
|
|
1569
|
+
}
|
|
1570
|
+
|
|
1571
|
+
const fork = this.baseFork;
|
|
1572
|
+
|
|
1573
|
+
const txEffect = TxEffect.empty();
|
|
1574
|
+
|
|
1575
|
+
txEffect.noteHashes = processedTxs[0]!.txEffect.noteHashes;
|
|
1576
|
+
txEffect.nullifiers = processedTxs[0]!.txEffect.nullifiers;
|
|
1577
|
+
txEffect.privateLogs = taggedPrivateLogs;
|
|
1578
|
+
txEffect.publicLogs = processedTxs[0]!.txEffect.publicLogs;
|
|
1579
|
+
txEffect.publicDataWrites = processedTxs[0]!.txEffect.publicDataWrites;
|
|
1580
|
+
|
|
1581
|
+
txEffect.txHash = new TxHash(new Fr(this.blockNumber));
|
|
1582
|
+
|
|
1583
|
+
const body = new Body([txEffect]);
|
|
1584
|
+
|
|
1585
|
+
const l2Block = new L2Block(
|
|
1586
|
+
makeAppendOnlyTreeSnapshot(this.blockNumber + 1),
|
|
1587
|
+
makeHeader(0, this.blockNumber, this.blockNumber),
|
|
1588
|
+
body,
|
|
1589
|
+
);
|
|
1590
|
+
|
|
1591
|
+
const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
|
|
1592
|
+
await fork.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
|
|
1593
|
+
|
|
1594
|
+
const stateReference = await fork.getStateReference();
|
|
1595
|
+
const archiveInfo = await fork.getTreeInfo(MerkleTreeId.ARCHIVE);
|
|
1596
|
+
|
|
1597
|
+
const header = new BlockHeader(
|
|
1598
|
+
new AppendOnlyTreeSnapshot(new Fr(archiveInfo.root), Number(archiveInfo.size)),
|
|
1599
|
+
makeContentCommitment(),
|
|
1600
|
+
stateReference,
|
|
1601
|
+
globals,
|
|
1602
|
+
Fr.ZERO,
|
|
1603
|
+
Fr.ZERO,
|
|
1604
|
+
);
|
|
1605
|
+
|
|
1606
|
+
header.globalVariables.blockNumber = new Fr(this.blockNumber);
|
|
1607
|
+
|
|
1608
|
+
l2Block.header = header;
|
|
1609
|
+
|
|
1610
|
+
await fork.updateArchive(l2Block.header);
|
|
1611
|
+
|
|
1612
|
+
await this.stateMachine.handleL2Block(l2Block);
|
|
1613
|
+
|
|
1614
|
+
const txRequestHash = this.getTxRequestHash();
|
|
1615
|
+
|
|
1616
|
+
this.setBlockNumber(this.blockNumber + 1);
|
|
1617
|
+
return {
|
|
1618
|
+
endSideEffectCounter: result.entrypoint.publicInputs.endSideEffectCounter,
|
|
1619
|
+
returnsHash: result.entrypoint.publicInputs.returnsHash,
|
|
1620
|
+
txHash: txRequestHash,
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1270
1623
|
}
|
|
@@ -41,11 +41,11 @@ export class TXEArchiver extends ArchiverStoreHelper {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* Gets
|
|
44
|
+
* Gets a published l2 block. If a negative number is passed, the block returned is the most recent.
|
|
45
45
|
* @param number - The block number to return (inclusive).
|
|
46
46
|
* @returns The requested L2 block.
|
|
47
47
|
*/
|
|
48
|
-
public async
|
|
48
|
+
public override async getPublishedBlock(number: number): Promise<PublishedL2Block | undefined> {
|
|
49
49
|
// If the number provided is -ve, then return the latest block.
|
|
50
50
|
if (number < 0) {
|
|
51
51
|
number = await this.store.getSynchedL2BlockNumber();
|
|
@@ -54,7 +54,16 @@ export class TXEArchiver extends ArchiverStoreHelper {
|
|
|
54
54
|
return undefined;
|
|
55
55
|
}
|
|
56
56
|
const blocks = await this.store.getPublishedBlocks(number, 1);
|
|
57
|
-
return blocks.length === 0 ? undefined : blocks[0]
|
|
57
|
+
return blocks.length === 0 ? undefined : blocks[0];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Gets an l2 block. If a negative number is passed, the block returned is the most recent.
|
|
62
|
+
* @param number - The block number to return (inclusive).
|
|
63
|
+
* @returns The requested L2 block.
|
|
64
|
+
*/
|
|
65
|
+
public getBlock(number: number): Promise<L2Block | undefined> {
|
|
66
|
+
return this.getPublishedBlock(number).then(block => block?.block);
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
/**
|
|
@@ -5,6 +5,14 @@ import type { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
|
|
|
5
5
|
import type { Tx, TxHash } from '@aztec/stdlib/tx';
|
|
6
6
|
|
|
7
7
|
export class DummyP2P implements P2P {
|
|
8
|
+
public validate(_txs: Tx[]): Promise<void> {
|
|
9
|
+
return Promise.resolve();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
public clear(): Promise<void> {
|
|
13
|
+
throw new Error('DummyP2P does not implement "clear".');
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
public getPendingTxs(): Promise<Tx[]> {
|
|
9
17
|
throw new Error('DummyP2P does not implement "getPendingTxs"');
|
|
10
18
|
}
|
|
@@ -17,7 +25,7 @@ export class DummyP2P implements P2P {
|
|
|
17
25
|
throw new Error('DummyP2P does not implement "getPeers"');
|
|
18
26
|
}
|
|
19
27
|
|
|
20
|
-
public broadcastProposal(_proposal: BlockProposal): void {
|
|
28
|
+
public broadcastProposal(_proposal: BlockProposal): Promise<void> {
|
|
21
29
|
throw new Error('DummyP2P does not implement "broadcastProposal"');
|
|
22
30
|
}
|
|
23
31
|
|
|
@@ -152,4 +160,8 @@ export class DummyP2P implements P2P {
|
|
|
152
160
|
public getSyncedLatestSlot(): Promise<bigint> {
|
|
153
161
|
throw new Error('DummyP2P does not implement "getSyncedLatestSlot"');
|
|
154
162
|
}
|
|
163
|
+
|
|
164
|
+
markTxsAsNonEvictable(_: TxHash[]): Promise<void> {
|
|
165
|
+
throw new Error('DummyP2P does not implement "markTxsAsNonEvictable".');
|
|
166
|
+
}
|
|
155
167
|
}
|