@aztec/sequencer-client 0.26.5 → 0.26.6
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/block_builder/solo_block_builder.d.ts.map +1 -1
- package/dest/block_builder/solo_block_builder.js +8 -5
- package/dest/index.d.ts +7 -7
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +8 -8
- package/dest/sequencer/abstract_phase_manager.d.ts +12 -15
- package/dest/sequencer/abstract_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/abstract_phase_manager.js +32 -24
- package/dest/sequencer/app_logic_phase_manager.d.ts +1 -6
- package/dest/sequencer/app_logic_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/app_logic_phase_manager.js +11 -8
- package/dest/sequencer/hints_builder.d.ts +13 -0
- package/dest/sequencer/hints_builder.d.ts.map +1 -0
- package/dest/sequencer/hints_builder.js +21 -0
- package/dest/sequencer/index.d.ts +1 -1
- package/dest/sequencer/index.d.ts.map +1 -1
- package/dest/sequencer/index.js +2 -2
- package/dest/sequencer/phase_manager_factory.d.ts.map +1 -1
- package/dest/sequencer/phase_manager_factory.js +5 -1
- package/dest/sequencer/processed_tx.d.ts +37 -2
- package/dest/sequencer/processed_tx.d.ts.map +1 -1
- package/dest/sequencer/processed_tx.js +67 -9
- package/dest/sequencer/public_processor.d.ts.map +1 -1
- package/dest/sequencer/public_processor.js +15 -9
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +1 -2
- package/dest/sequencer/setup_phase_manager.d.ts +1 -6
- package/dest/sequencer/setup_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/setup_phase_manager.js +3 -5
- package/dest/sequencer/tail_phase_manager.d.ts +28 -0
- package/dest/sequencer/tail_phase_manager.d.ts.map +1 -0
- package/dest/sequencer/tail_phase_manager.js +32 -0
- package/dest/sequencer/teardown_phase_manager.d.ts +1 -6
- package/dest/sequencer/teardown_phase_manager.d.ts.map +1 -1
- package/dest/sequencer/teardown_phase_manager.js +3 -4
- package/dest/simulator/index.d.ts +7 -1
- package/dest/simulator/index.d.ts.map +1 -1
- package/dest/simulator/index.js +1 -1
- package/dest/simulator/public_kernel.d.ts +7 -1
- package/dest/simulator/public_kernel.d.ts.map +1 -1
- package/dest/simulator/public_kernel.js +22 -4
- package/package.json +13 -13
- package/src/block_builder/solo_block_builder.ts +6 -32
- package/src/index.ts +7 -7
- package/src/sequencer/abstract_phase_manager.ts +58 -48
- package/src/sequencer/app_logic_phase_manager.ts +12 -22
- package/src/sequencer/hints_builder.ts +56 -0
- package/src/sequencer/index.ts +1 -1
- package/src/sequencer/phase_manager_factory.ts +12 -0
- package/src/sequencer/processed_tx.ts +147 -17
- package/src/sequencer/public_processor.ts +25 -13
- package/src/sequencer/sequencer.ts +0 -1
- package/src/sequencer/setup_phase_manager.ts +5 -19
- package/src/sequencer/tail_phase_manager.ts +49 -0
- package/src/sequencer/teardown_phase_manager.ts +5 -18
- package/src/simulator/index.ts +7 -0
- package/src/simulator/public_kernel.ts +35 -5
|
@@ -27,42 +27,32 @@ export class AppLogicPhaseManager extends AbstractPhaseManager {
|
|
|
27
27
|
super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
async handle(
|
|
30
|
+
override async handle(
|
|
31
31
|
tx: Tx,
|
|
32
32
|
previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
|
|
33
33
|
previousPublicKernelProof: Proof,
|
|
34
|
-
)
|
|
35
|
-
/**
|
|
36
|
-
* the output of the public kernel circuit for this phase
|
|
37
|
-
*/
|
|
38
|
-
publicKernelOutput: PublicKernelCircuitPublicInputs;
|
|
39
|
-
/**
|
|
40
|
-
* the proof of the public kernel circuit for this phase
|
|
41
|
-
*/
|
|
42
|
-
publicKernelProof: Proof;
|
|
43
|
-
}> {
|
|
34
|
+
) {
|
|
44
35
|
// add new contracts to the contracts db so that their functions may be found and called
|
|
45
36
|
// TODO(#4073): This is catching only private deployments, when we add public ones, we'll
|
|
46
37
|
// have to capture contracts emitted in that phase as well.
|
|
47
38
|
// TODO(@spalladino): Should we allow emitting contracts in the fee preparation phase?
|
|
48
39
|
this.log(`Processing tx ${tx.getTxHash()}`);
|
|
49
40
|
await this.publicContractsDB.addNewContracts(tx);
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
tx,
|
|
53
|
-
previousPublicKernelOutput,
|
|
54
|
-
previousPublicKernelProof,
|
|
55
|
-
);
|
|
56
|
-
tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
|
|
41
|
+
const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
|
|
42
|
+
await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof);
|
|
57
43
|
|
|
58
|
-
|
|
59
|
-
|
|
44
|
+
if (revertReason) {
|
|
45
|
+
await this.rollback(tx, revertReason);
|
|
46
|
+
} else {
|
|
47
|
+
tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
|
|
48
|
+
await this.publicStateDB.commit();
|
|
49
|
+
}
|
|
60
50
|
|
|
61
|
-
return { publicKernelOutput, publicKernelProof };
|
|
51
|
+
return { publicKernelOutput, publicKernelProof, revertReason };
|
|
62
52
|
}
|
|
63
53
|
|
|
64
54
|
async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
|
|
65
|
-
this.log.warn(`
|
|
55
|
+
this.log.warn(`Rolling back changes from ${tx.getTxHash()}`);
|
|
66
56
|
// remove contracts on failure
|
|
67
57
|
await this.publicContractsDB.removeNewContracts(tx);
|
|
68
58
|
// rollback any state updates from this failed transaction
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { MerkleTreeId } from '@aztec/circuit-types';
|
|
2
|
+
import {
|
|
3
|
+
Fr,
|
|
4
|
+
MAX_NEW_NULLIFIERS_PER_TX,
|
|
5
|
+
MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX,
|
|
6
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
7
|
+
MAX_REVERTIBLE_NULLIFIERS_PER_TX,
|
|
8
|
+
MembershipWitness,
|
|
9
|
+
NULLIFIER_TREE_HEIGHT,
|
|
10
|
+
NullifierLeafPreimage,
|
|
11
|
+
ReadRequestContext,
|
|
12
|
+
SideEffectLinkedToNoteHash,
|
|
13
|
+
buildNullifierReadRequestResetHints,
|
|
14
|
+
concatAccumulatedData,
|
|
15
|
+
mergeAccumulatedData,
|
|
16
|
+
} from '@aztec/circuits.js';
|
|
17
|
+
import { Tuple } from '@aztec/foundation/serialize';
|
|
18
|
+
import { MerkleTreeOperations } from '@aztec/world-state';
|
|
19
|
+
|
|
20
|
+
export class HintsBuilder {
|
|
21
|
+
constructor(private db: MerkleTreeOperations) {}
|
|
22
|
+
|
|
23
|
+
getNullifierReadRequestResetHints(
|
|
24
|
+
nullifierReadRequestsNonRevertible: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>,
|
|
25
|
+
nullifierReadRequestsRevertible: Tuple<ReadRequestContext, typeof MAX_NULLIFIER_READ_REQUESTS_PER_TX>,
|
|
26
|
+
nullifiersNonRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_NON_REVERTIBLE_NULLIFIERS_PER_TX>,
|
|
27
|
+
nullifiersRevertible: Tuple<SideEffectLinkedToNoteHash, typeof MAX_REVERTIBLE_NULLIFIERS_PER_TX>,
|
|
28
|
+
) {
|
|
29
|
+
return buildNullifierReadRequestResetHints(
|
|
30
|
+
this,
|
|
31
|
+
mergeAccumulatedData(
|
|
32
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
33
|
+
nullifierReadRequestsNonRevertible,
|
|
34
|
+
nullifierReadRequestsRevertible,
|
|
35
|
+
),
|
|
36
|
+
concatAccumulatedData(MAX_NEW_NULLIFIERS_PER_TX, nullifiersNonRevertible, nullifiersRevertible),
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async getNullifierMembershipWitness(nullifier: Fr) {
|
|
41
|
+
const index = await this.db.findLeafIndex(MerkleTreeId.NULLIFIER_TREE, nullifier.toBuffer());
|
|
42
|
+
if (index === undefined) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const siblingPath = await this.db.getSiblingPath(MerkleTreeId.NULLIFIER_TREE, index);
|
|
47
|
+
const membershipWitness = new MembershipWitness(
|
|
48
|
+
NULLIFIER_TREE_HEIGHT,
|
|
49
|
+
index,
|
|
50
|
+
siblingPath.toTuple<typeof NULLIFIER_TREE_HEIGHT>(),
|
|
51
|
+
);
|
|
52
|
+
const leafPreimage = (await this.db.getLeafPreimage(MerkleTreeId.NULLIFIER_TREE, index))! as NullifierLeafPreimage;
|
|
53
|
+
|
|
54
|
+
return { membershipWitness, leafPreimage };
|
|
55
|
+
}
|
|
56
|
+
}
|
package/src/sequencer/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js';
|
|
|
9
9
|
import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
|
|
10
10
|
import { AppLogicPhaseManager } from './app_logic_phase_manager.js';
|
|
11
11
|
import { SetupPhaseManager } from './setup_phase_manager.js';
|
|
12
|
+
import { TailPhaseManager } from './tail_phase_manager.js';
|
|
12
13
|
import { TeardownPhaseManager } from './teardown_phase_manager.js';
|
|
13
14
|
|
|
14
15
|
export class PhaseDidNotChangeError extends Error {
|
|
@@ -115,6 +116,17 @@ export class PhaseManagerFactory {
|
|
|
115
116
|
publicContractsDB,
|
|
116
117
|
publicStateDB,
|
|
117
118
|
);
|
|
119
|
+
} else if (currentPhaseManager.phase !== PublicKernelPhase.TAIL) {
|
|
120
|
+
return new TailPhaseManager(
|
|
121
|
+
db,
|
|
122
|
+
publicExecutor,
|
|
123
|
+
publicKernel,
|
|
124
|
+
publicProver,
|
|
125
|
+
globalVariables,
|
|
126
|
+
historicalHeader,
|
|
127
|
+
publicContractsDB,
|
|
128
|
+
publicStateDB,
|
|
129
|
+
);
|
|
118
130
|
} else {
|
|
119
131
|
return undefined;
|
|
120
132
|
}
|
|
@@ -1,13 +1,29 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
ContractData,
|
|
3
|
+
ExtendedContractData,
|
|
4
|
+
PublicDataWrite,
|
|
5
|
+
SimulationError,
|
|
6
|
+
Tx,
|
|
7
|
+
TxEffect,
|
|
8
|
+
TxHash,
|
|
9
|
+
TxL2Logs,
|
|
10
|
+
} from '@aztec/circuit-types';
|
|
2
11
|
import {
|
|
3
12
|
Fr,
|
|
4
13
|
Header,
|
|
14
|
+
MAX_NEW_CONTRACTS_PER_TX,
|
|
15
|
+
MAX_NEW_NOTE_HASHES_PER_TX,
|
|
16
|
+
MAX_NEW_NULLIFIERS_PER_TX,
|
|
17
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
5
18
|
Proof,
|
|
6
19
|
PublicAccumulatedNonRevertibleData,
|
|
7
20
|
PublicAccumulatedRevertibleData,
|
|
8
21
|
PublicKernelCircuitPublicInputs,
|
|
22
|
+
SideEffect,
|
|
23
|
+
SideEffectLinkedToNoteHash,
|
|
9
24
|
makeEmptyProof,
|
|
10
25
|
} from '@aztec/circuits.js';
|
|
26
|
+
import { Tuple, fromFieldsTuple } from '@aztec/foundation/serialize';
|
|
11
27
|
|
|
12
28
|
/**
|
|
13
29
|
* Represents a tx that has been processed by the sequencer public processor,
|
|
@@ -26,8 +42,39 @@ export type ProcessedTx = Pick<Tx, 'proof' | 'encryptedLogs' | 'unencryptedLogs'
|
|
|
26
42
|
* Flag indicating the tx is 'empty' meaning it's a padding tx to take us to a power of 2.
|
|
27
43
|
*/
|
|
28
44
|
isEmpty: boolean;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Reason the tx was reverted.
|
|
48
|
+
*/
|
|
49
|
+
revertReason: SimulationError | undefined;
|
|
29
50
|
};
|
|
30
51
|
|
|
52
|
+
export type RevertedTx = ProcessedTx & {
|
|
53
|
+
data: PublicKernelCircuitPublicInputs & {
|
|
54
|
+
reverted: true;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
revertReason: SimulationError;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export function isRevertedTx(tx: ProcessedTx): tx is RevertedTx {
|
|
61
|
+
return tx.data.reverted;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function partitionReverts(txs: ProcessedTx[]): { reverted: RevertedTx[]; nonReverted: ProcessedTx[] } {
|
|
65
|
+
return txs.reduce(
|
|
66
|
+
({ reverted, nonReverted }, tx) => {
|
|
67
|
+
if (isRevertedTx(tx)) {
|
|
68
|
+
reverted.push(tx);
|
|
69
|
+
} else {
|
|
70
|
+
nonReverted.push(tx);
|
|
71
|
+
}
|
|
72
|
+
return { reverted, nonReverted };
|
|
73
|
+
},
|
|
74
|
+
{ reverted: [], nonReverted: [] } as ReturnType<typeof partitionReverts>,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
31
78
|
/**
|
|
32
79
|
* Represents a tx that failed to be processed by the sequencer public processor.
|
|
33
80
|
*/
|
|
@@ -42,31 +89,73 @@ export type FailedTx = {
|
|
|
42
89
|
error: Error;
|
|
43
90
|
};
|
|
44
91
|
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @param tx - the TX being procesed
|
|
95
|
+
* @param publicKernelPublicInput - the output of the public kernel circuit, unless we just came from private
|
|
96
|
+
* @param publicKernelProof - the proof of the public kernel circuit, unless we just came from private
|
|
97
|
+
* @returns PublicKernelCircuitPublicInputs, either passed through from the input or converted from the output of the TX,
|
|
98
|
+
* and Proof, either passed through from the input or the proof of the TX
|
|
99
|
+
*/
|
|
100
|
+
export function getPreviousOutputAndProof(
|
|
101
|
+
tx: Tx,
|
|
102
|
+
publicKernelPublicInput?: PublicKernelCircuitPublicInputs,
|
|
103
|
+
publicKernelProof?: Proof,
|
|
104
|
+
): {
|
|
105
|
+
/**
|
|
106
|
+
* the output of the public kernel circuit for this phase
|
|
107
|
+
*/
|
|
108
|
+
publicKernelPublicInput: PublicKernelCircuitPublicInputs;
|
|
109
|
+
/**
|
|
110
|
+
* the proof of the public kernel circuit for this phase
|
|
111
|
+
*/
|
|
112
|
+
previousProof: Proof;
|
|
113
|
+
} {
|
|
114
|
+
if (publicKernelPublicInput && publicKernelProof) {
|
|
115
|
+
return {
|
|
116
|
+
publicKernelPublicInput,
|
|
117
|
+
previousProof: publicKernelProof,
|
|
118
|
+
};
|
|
119
|
+
} else {
|
|
120
|
+
const publicKernelPublicInput = new PublicKernelCircuitPublicInputs(
|
|
121
|
+
tx.data.aggregationObject,
|
|
122
|
+
PublicAccumulatedNonRevertibleData.fromPrivateAccumulatedNonRevertibleData(tx.data.endNonRevertibleData),
|
|
123
|
+
PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end),
|
|
124
|
+
tx.data.constants,
|
|
125
|
+
tx.data.needsSetup,
|
|
126
|
+
tx.data.needsAppLogic,
|
|
127
|
+
tx.data.needsTeardown,
|
|
128
|
+
false, // reverted
|
|
129
|
+
);
|
|
130
|
+
return {
|
|
131
|
+
publicKernelPublicInput,
|
|
132
|
+
previousProof: publicKernelProof || tx.proof,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
45
137
|
/**
|
|
46
138
|
* Makes a processed tx out of source tx.
|
|
47
139
|
* @param tx - Source tx.
|
|
48
140
|
* @param kernelOutput - Output of the kernel circuit simulation for this tx.
|
|
49
141
|
* @param proof - Proof of the kernel circuit for this tx.
|
|
50
142
|
*/
|
|
51
|
-
export function makeProcessedTx(
|
|
143
|
+
export function makeProcessedTx(
|
|
144
|
+
tx: Tx,
|
|
145
|
+
kernelOutput?: PublicKernelCircuitPublicInputs,
|
|
146
|
+
proof?: Proof,
|
|
147
|
+
revertReason?: SimulationError,
|
|
148
|
+
): ProcessedTx {
|
|
149
|
+
const { publicKernelPublicInput, previousProof } = getPreviousOutputAndProof(tx, kernelOutput, proof);
|
|
52
150
|
return {
|
|
53
151
|
hash: tx.getTxHash(),
|
|
54
|
-
data:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
PublicAccumulatedRevertibleData.fromPrivateAccumulatedRevertibleData(tx.data.end),
|
|
60
|
-
tx.data.constants,
|
|
61
|
-
tx.data.needsSetup,
|
|
62
|
-
tx.data.needsAppLogic,
|
|
63
|
-
tx.data.needsTeardown,
|
|
64
|
-
),
|
|
65
|
-
proof: proof ?? tx.proof,
|
|
66
|
-
encryptedLogs: tx.encryptedLogs,
|
|
67
|
-
unencryptedLogs: tx.unencryptedLogs,
|
|
68
|
-
newContracts: tx.newContracts,
|
|
152
|
+
data: publicKernelPublicInput,
|
|
153
|
+
proof: previousProof,
|
|
154
|
+
encryptedLogs: revertReason ? new TxL2Logs([]) : tx.encryptedLogs,
|
|
155
|
+
unencryptedLogs: revertReason ? new TxL2Logs([]) : tx.unencryptedLogs,
|
|
156
|
+
newContracts: revertReason ? [ExtendedContractData.empty()] : tx.newContracts,
|
|
69
157
|
isEmpty: false,
|
|
158
|
+
revertReason,
|
|
70
159
|
};
|
|
71
160
|
}
|
|
72
161
|
|
|
@@ -90,5 +179,46 @@ export function makeEmptyProcessedTx(header: Header, chainId: Fr, version: Fr):
|
|
|
90
179
|
proof: emptyProof,
|
|
91
180
|
newContracts: [ExtendedContractData.empty()],
|
|
92
181
|
isEmpty: true,
|
|
182
|
+
revertReason: undefined,
|
|
93
183
|
};
|
|
94
184
|
}
|
|
185
|
+
|
|
186
|
+
export function toTxEffect(tx: ProcessedTx): TxEffect {
|
|
187
|
+
return new TxEffect(
|
|
188
|
+
tx.data.combinedData.newNoteHashes.map((c: SideEffect) => c.value) as Tuple<Fr, typeof MAX_NEW_NOTE_HASHES_PER_TX>,
|
|
189
|
+
tx.data.combinedData.newNullifiers.map((n: SideEffectLinkedToNoteHash) => n.value) as Tuple<
|
|
190
|
+
Fr,
|
|
191
|
+
typeof MAX_NEW_NULLIFIERS_PER_TX
|
|
192
|
+
>,
|
|
193
|
+
tx.data.combinedData.newL2ToL1Msgs,
|
|
194
|
+
tx.data.combinedData.publicDataUpdateRequests.map(t => new PublicDataWrite(t.leafSlot, t.newValue)) as Tuple<
|
|
195
|
+
PublicDataWrite,
|
|
196
|
+
typeof MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
|
|
197
|
+
>,
|
|
198
|
+
tx.data.combinedData.newContracts.map(cd => cd.hash()) as Tuple<Fr, typeof MAX_NEW_CONTRACTS_PER_TX>,
|
|
199
|
+
tx.data.combinedData.newContracts.map(
|
|
200
|
+
cd => new ContractData(cd.contractAddress, cd.portalContractAddress),
|
|
201
|
+
) as Tuple<ContractData, typeof MAX_NEW_CONTRACTS_PER_TX>,
|
|
202
|
+
tx.encryptedLogs || new TxL2Logs([]),
|
|
203
|
+
tx.unencryptedLogs || new TxL2Logs([]),
|
|
204
|
+
);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function validateProcessedTxLogs(tx: ProcessedTx): void {
|
|
208
|
+
const unencryptedLogs = tx.unencryptedLogs || new TxL2Logs([]);
|
|
209
|
+
const kernelUnencryptedLogsHash = fromFieldsTuple(tx.data.combinedData.unencryptedLogsHash);
|
|
210
|
+
if (!unencryptedLogs.hash().equals(kernelUnencryptedLogsHash)) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`Unencrypted logs hash mismatch. Expected ${unencryptedLogs
|
|
213
|
+
.hash()
|
|
214
|
+
.toString('hex')}, got ${kernelUnencryptedLogsHash.toString('hex')}.
|
|
215
|
+
Processed: ${JSON.stringify(unencryptedLogs.toJSON())}
|
|
216
|
+
Kernel Length: ${tx.data.combinedData.unencryptedLogPreimagesLength}`,
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function validateProcessedTx(tx: ProcessedTx): void {
|
|
222
|
+
validateProcessedTxLogs(tx);
|
|
223
|
+
// TODO: validate other fields
|
|
224
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContractDataSource, L1ToL2MessageSource, Tx } from '@aztec/circuit-types';
|
|
1
|
+
import { ContractDataSource, L1ToL2MessageSource, SimulationError, Tx } from '@aztec/circuit-types';
|
|
2
2
|
import { TxSequencerProcessingStats } from '@aztec/circuit-types/stats';
|
|
3
3
|
import { GlobalVariables, Header } from '@aztec/circuits.js';
|
|
4
4
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
@@ -14,7 +14,14 @@ import { RealPublicKernelCircuitSimulator } from '../simulator/public_kernel.js'
|
|
|
14
14
|
import { SimulationProvider } from '../simulator/simulation_provider.js';
|
|
15
15
|
import { AbstractPhaseManager } from './abstract_phase_manager.js';
|
|
16
16
|
import { PhaseManagerFactory } from './phase_manager_factory.js';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
FailedTx,
|
|
19
|
+
ProcessedTx,
|
|
20
|
+
getPreviousOutputAndProof,
|
|
21
|
+
makeEmptyProcessedTx,
|
|
22
|
+
makeProcessedTx,
|
|
23
|
+
validateProcessedTx,
|
|
24
|
+
} from './processed_tx.js';
|
|
18
25
|
|
|
19
26
|
/**
|
|
20
27
|
* Creates new instances of PublicProcessor given the provided merkle tree db and contract data source.
|
|
@@ -99,17 +106,15 @@ export class PublicProcessor {
|
|
|
99
106
|
this.publicStateDB,
|
|
100
107
|
);
|
|
101
108
|
this.log(`Beginning processing in phase ${phase?.phase} for tx ${tx.getTxHash()}`);
|
|
102
|
-
let { publicKernelPublicInput,
|
|
103
|
-
|
|
104
|
-
undefined,
|
|
105
|
-
undefined,
|
|
106
|
-
);
|
|
109
|
+
let { publicKernelPublicInput, previousProof: proof } = getPreviousOutputAndProof(tx, undefined, undefined);
|
|
110
|
+
let revertReason: SimulationError | undefined;
|
|
107
111
|
const timer = new Timer();
|
|
108
112
|
try {
|
|
109
113
|
while (phase) {
|
|
110
|
-
const output = await phase.handle(tx, publicKernelPublicInput,
|
|
114
|
+
const output = await phase.handle(tx, publicKernelPublicInput, proof);
|
|
111
115
|
publicKernelPublicInput = output.publicKernelOutput;
|
|
112
|
-
|
|
116
|
+
proof = output.publicKernelProof;
|
|
117
|
+
revertReason ??= output.revertReason;
|
|
113
118
|
phase = PhaseManagerFactory.phaseFromOutput(
|
|
114
119
|
publicKernelPublicInput,
|
|
115
120
|
phase,
|
|
@@ -124,7 +129,9 @@ export class PublicProcessor {
|
|
|
124
129
|
);
|
|
125
130
|
}
|
|
126
131
|
|
|
127
|
-
const processedTransaction = makeProcessedTx(tx, publicKernelPublicInput,
|
|
132
|
+
const processedTransaction = makeProcessedTx(tx, publicKernelPublicInput, proof, revertReason);
|
|
133
|
+
validateProcessedTx(processedTransaction);
|
|
134
|
+
|
|
128
135
|
result.push(processedTransaction);
|
|
129
136
|
|
|
130
137
|
this.log(`Processed public part of ${tx.data.endNonRevertibleData.newNullifiers[0].value}`, {
|
|
@@ -135,9 +142,14 @@ export class PublicProcessor {
|
|
|
135
142
|
0,
|
|
136
143
|
...tx.getStats(),
|
|
137
144
|
} satisfies TxSequencerProcessingStats);
|
|
138
|
-
} catch (err) {
|
|
139
|
-
const
|
|
140
|
-
|
|
145
|
+
} catch (err: any) {
|
|
146
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
|
|
147
|
+
this.log.warn(`Failed to process tx ${tx.getTxHash()}: ${errorMessage}`);
|
|
148
|
+
|
|
149
|
+
failed.push({
|
|
150
|
+
tx,
|
|
151
|
+
error: err instanceof Error ? err : new Error(errorMessage),
|
|
152
|
+
});
|
|
141
153
|
}
|
|
142
154
|
}
|
|
143
155
|
|
|
@@ -180,7 +180,6 @@ export class Sequencer {
|
|
|
180
180
|
this.log.info(`Building block ${newBlockNumber} with ${validTxs.length} transactions`);
|
|
181
181
|
this.state = SequencerState.CREATING_BLOCK;
|
|
182
182
|
|
|
183
|
-
// Process txs and drop the ones that fail processing
|
|
184
183
|
// We create a fresh processor each time to reset any cached state (eg storage writes)
|
|
185
184
|
const processor = await this.publicProcessorFactory.create(historicalHeader, newGlobalVariables);
|
|
186
185
|
const [publicProcessorDuration, [processedTxs, failedTxs]] = await elapsed(() => processor.process(validTxs));
|
|
@@ -27,34 +27,20 @@ export class SetupPhaseManager extends AbstractPhaseManager {
|
|
|
27
27
|
super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
async handle(
|
|
30
|
+
override async handle(
|
|
32
31
|
tx: Tx,
|
|
33
32
|
previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
|
|
34
33
|
previousPublicKernelProof: Proof,
|
|
35
|
-
)
|
|
36
|
-
/**
|
|
37
|
-
* the output of the public kernel circuit for this phase
|
|
38
|
-
*/
|
|
39
|
-
publicKernelOutput: PublicKernelCircuitPublicInputs;
|
|
40
|
-
/**
|
|
41
|
-
* the proof of the public kernel circuit for this phase
|
|
42
|
-
*/
|
|
43
|
-
publicKernelProof: Proof;
|
|
44
|
-
}> {
|
|
34
|
+
) {
|
|
45
35
|
this.log(`Processing tx ${tx.getTxHash()}`);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
tx,
|
|
49
|
-
previousPublicKernelOutput,
|
|
50
|
-
previousPublicKernelProof,
|
|
51
|
-
);
|
|
36
|
+
const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
|
|
37
|
+
await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof);
|
|
52
38
|
tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
|
|
53
39
|
|
|
54
40
|
// commit the state updates from this transaction
|
|
55
41
|
await this.publicStateDB.commit();
|
|
56
42
|
|
|
57
|
-
return { publicKernelOutput, publicKernelProof };
|
|
43
|
+
return { publicKernelOutput, publicKernelProof, revertReason };
|
|
58
44
|
}
|
|
59
45
|
|
|
60
46
|
async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Tx } from '@aztec/circuit-types';
|
|
2
|
+
import { GlobalVariables, Header, Proof, PublicKernelCircuitPublicInputs } from '@aztec/circuits.js';
|
|
3
|
+
import { PublicExecutor, PublicStateDB } from '@aztec/simulator';
|
|
4
|
+
import { MerkleTreeOperations } from '@aztec/world-state';
|
|
5
|
+
|
|
6
|
+
import { PublicProver } from '../prover/index.js';
|
|
7
|
+
import { PublicKernelCircuitSimulator } from '../simulator/index.js';
|
|
8
|
+
import { ContractsDataSourcePublicDB } from '../simulator/public_executor.js';
|
|
9
|
+
import { AbstractPhaseManager, PublicKernelPhase } from './abstract_phase_manager.js';
|
|
10
|
+
import { FailedTx } from './processed_tx.js';
|
|
11
|
+
|
|
12
|
+
export class TailPhaseManager extends AbstractPhaseManager {
|
|
13
|
+
constructor(
|
|
14
|
+
protected db: MerkleTreeOperations,
|
|
15
|
+
protected publicExecutor: PublicExecutor,
|
|
16
|
+
protected publicKernel: PublicKernelCircuitSimulator,
|
|
17
|
+
protected publicProver: PublicProver,
|
|
18
|
+
protected globalVariables: GlobalVariables,
|
|
19
|
+
protected historicalHeader: Header,
|
|
20
|
+
protected publicContractsDB: ContractsDataSourcePublicDB,
|
|
21
|
+
protected publicStateDB: PublicStateDB,
|
|
22
|
+
public readonly phase: PublicKernelPhase = PublicKernelPhase.TAIL,
|
|
23
|
+
) {
|
|
24
|
+
super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async handle(tx: Tx, previousPublicKernelOutput: PublicKernelCircuitPublicInputs, previousPublicKernelProof: Proof) {
|
|
28
|
+
this.log(`Processing tx ${tx.getTxHash()}`);
|
|
29
|
+
this.log(`Executing tail circuit for tx ${tx.getTxHash()}`);
|
|
30
|
+
const [publicKernelOutput, publicKernelProof] = await this.runKernelCircuit(
|
|
31
|
+
previousPublicKernelOutput,
|
|
32
|
+
previousPublicKernelProof,
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
// commit the state updates from this transaction
|
|
36
|
+
await this.publicStateDB.commit();
|
|
37
|
+
|
|
38
|
+
return { publicKernelOutput, publicKernelProof, revertReason: undefined };
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
|
|
42
|
+
this.log.warn(`Error processing tx ${tx.getTxHash()}: ${err}`);
|
|
43
|
+
await this.publicStateDB.rollback();
|
|
44
|
+
return {
|
|
45
|
+
tx,
|
|
46
|
+
error: err instanceof Error ? err : new Error('Unknown error'),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -27,33 +27,20 @@ export class TeardownPhaseManager extends AbstractPhaseManager {
|
|
|
27
27
|
super(db, publicExecutor, publicKernel, publicProver, globalVariables, historicalHeader, phase);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
async handle(
|
|
30
|
+
override async handle(
|
|
31
31
|
tx: Tx,
|
|
32
32
|
previousPublicKernelOutput: PublicKernelCircuitPublicInputs,
|
|
33
33
|
previousPublicKernelProof: Proof,
|
|
34
|
-
)
|
|
35
|
-
/**
|
|
36
|
-
* the output of the public kernel circuit for this phase
|
|
37
|
-
*/
|
|
38
|
-
publicKernelOutput: PublicKernelCircuitPublicInputs;
|
|
39
|
-
/**
|
|
40
|
-
* the proof of the public kernel circuit for this phase
|
|
41
|
-
*/
|
|
42
|
-
publicKernelProof: Proof;
|
|
43
|
-
}> {
|
|
34
|
+
) {
|
|
44
35
|
this.log(`Processing tx ${tx.getTxHash()}`);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
tx,
|
|
48
|
-
previousPublicKernelOutput,
|
|
49
|
-
previousPublicKernelProof,
|
|
50
|
-
);
|
|
36
|
+
const [publicKernelOutput, publicKernelProof, newUnencryptedFunctionLogs, revertReason] =
|
|
37
|
+
await this.processEnqueuedPublicCalls(tx, previousPublicKernelOutput, previousPublicKernelProof);
|
|
51
38
|
tx.unencryptedLogs.addFunctionLogs(newUnencryptedFunctionLogs);
|
|
52
39
|
|
|
53
40
|
// commit the state updates from this transaction
|
|
54
41
|
await this.publicStateDB.commit();
|
|
55
42
|
|
|
56
|
-
return { publicKernelOutput, publicKernelProof };
|
|
43
|
+
return { publicKernelOutput, publicKernelProof, revertReason };
|
|
57
44
|
}
|
|
58
45
|
|
|
59
46
|
async rollback(tx: Tx, err: unknown): Promise<FailedTx> {
|
package/src/simulator/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
MergeRollupInputs,
|
|
5
5
|
PublicKernelCircuitPrivateInputs,
|
|
6
6
|
PublicKernelCircuitPublicInputs,
|
|
7
|
+
PublicKernelTailCircuitPrivateInputs,
|
|
7
8
|
RootRollupInputs,
|
|
8
9
|
RootRollupPublicInputs,
|
|
9
10
|
} from '@aztec/circuits.js';
|
|
@@ -54,5 +55,11 @@ export interface PublicKernelCircuitSimulator {
|
|
|
54
55
|
* @returns The public inputs as outputs of the simulation.
|
|
55
56
|
*/
|
|
56
57
|
publicKernelCircuitTeardown(inputs: PublicKernelCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
|
|
58
|
+
/**
|
|
59
|
+
* Simulates the public kernel tail circuit from its inputs.
|
|
60
|
+
* @param inputs - Inputs to the circuit.
|
|
61
|
+
* @returns The public inputs as outputs of the simulation.
|
|
62
|
+
*/
|
|
63
|
+
publicKernelCircuitTail(inputs: PublicKernelTailCircuitPrivateInputs): Promise<PublicKernelCircuitPublicInputs>;
|
|
57
64
|
}
|
|
58
65
|
export * from './acvm_wasm.js';
|
|
@@ -1,17 +1,24 @@
|
|
|
1
1
|
import { CircuitSimulationStats } from '@aztec/circuit-types/stats';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
PublicKernelCircuitPrivateInputs,
|
|
4
|
+
PublicKernelCircuitPublicInputs,
|
|
5
|
+
PublicKernelTailCircuitPrivateInputs,
|
|
6
|
+
} from '@aztec/circuits.js';
|
|
3
7
|
import { createDebugLogger } from '@aztec/foundation/log';
|
|
4
8
|
import { elapsed } from '@aztec/foundation/timer';
|
|
5
9
|
import {
|
|
6
10
|
PublicKernelAppLogicArtifact,
|
|
7
11
|
PublicKernelSetupArtifact,
|
|
12
|
+
PublicKernelTailArtifact,
|
|
8
13
|
PublicKernelTeardownArtifact,
|
|
9
14
|
convertPublicInnerRollupInputsToWitnessMap,
|
|
10
15
|
convertPublicInnerRollupOutputFromWitnessMap,
|
|
11
16
|
convertPublicSetupRollupInputsToWitnessMap,
|
|
12
17
|
convertPublicSetupRollupOutputFromWitnessMap,
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
convertPublicTailInputsToWitnessMap,
|
|
19
|
+
convertPublicTailOutputFromWitnessMap,
|
|
20
|
+
convertPublicTeardownRollupInputsToWitnessMap,
|
|
21
|
+
convertPublicTeardownRollupOutputFromWitnessMap,
|
|
15
22
|
} from '@aztec/noir-protocol-circuits-types';
|
|
16
23
|
|
|
17
24
|
import { PublicKernelCircuitSimulator, WASMSimulator } from './index.js';
|
|
@@ -91,11 +98,11 @@ export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimu
|
|
|
91
98
|
if (!input.previousKernel.publicInputs.needsTeardown) {
|
|
92
99
|
throw new Error(`Expected previous kernel inputs to need teardown`);
|
|
93
100
|
}
|
|
94
|
-
const inputWitness =
|
|
101
|
+
const inputWitness = convertPublicTeardownRollupInputsToWitnessMap(input);
|
|
95
102
|
const [duration, witness] = await elapsed(() =>
|
|
96
103
|
this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelTeardownArtifact),
|
|
97
104
|
);
|
|
98
|
-
const result =
|
|
105
|
+
const result = convertPublicTeardownRollupOutputFromWitnessMap(witness);
|
|
99
106
|
this.log(`Simulated public kernel teardown circuit`, {
|
|
100
107
|
eventName: 'circuit-simulation',
|
|
101
108
|
circuitName: 'public-kernel-teardown',
|
|
@@ -105,4 +112,27 @@ export class RealPublicKernelCircuitSimulator implements PublicKernelCircuitSimu
|
|
|
105
112
|
} satisfies CircuitSimulationStats);
|
|
106
113
|
return result;
|
|
107
114
|
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Simulates the public kernel tail circuit from its inputs.
|
|
118
|
+
* @param input - Inputs to the circuit.
|
|
119
|
+
* @returns The public inputs as outputs of the simulation.
|
|
120
|
+
*/
|
|
121
|
+
public async publicKernelCircuitTail(
|
|
122
|
+
input: PublicKernelTailCircuitPrivateInputs,
|
|
123
|
+
): Promise<PublicKernelCircuitPublicInputs> {
|
|
124
|
+
const inputWitness = convertPublicTailInputsToWitnessMap(input);
|
|
125
|
+
const [duration, witness] = await elapsed(() =>
|
|
126
|
+
this.wasmSimulator.simulateCircuit(inputWitness, PublicKernelTailArtifact),
|
|
127
|
+
);
|
|
128
|
+
const result = convertPublicTailOutputFromWitnessMap(witness);
|
|
129
|
+
this.log(`Simulated public kernel tail circuit`, {
|
|
130
|
+
eventName: 'circuit-simulation',
|
|
131
|
+
circuitName: 'public-kernel-tail',
|
|
132
|
+
duration,
|
|
133
|
+
inputSize: input.toBuffer().length,
|
|
134
|
+
outputSize: result.toBuffer().length,
|
|
135
|
+
} satisfies CircuitSimulationStats);
|
|
136
|
+
return result;
|
|
137
|
+
}
|
|
108
138
|
}
|