@aztec/validator-client 3.0.0-nightly.20251024 → 3.0.0-nightly.20251026
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_proposal_handler.d.ts +23 -18
- package/dest/block_proposal_handler.d.ts.map +1 -1
- package/dest/block_proposal_handler.js +81 -56
- package/dest/duties/validation_service.d.ts +1 -2
- package/dest/duties/validation_service.d.ts.map +1 -1
- package/dest/duties/validation_service.js +4 -5
- package/dest/validator.d.ts +1 -1
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +6 -6
- package/package.json +11 -11
- package/src/block_proposal_handler.ts +110 -84
- package/src/duties/validation_service.ts +2 -5
- package/src/validator.ts +10 -6
|
@@ -3,24 +3,32 @@ import { DateProvider } from '@aztec/foundation/timer';
|
|
|
3
3
|
import type { P2P, PeerId } from '@aztec/p2p';
|
|
4
4
|
import { TxProvider } from '@aztec/p2p';
|
|
5
5
|
import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
|
|
6
|
-
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
6
|
+
import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
7
7
|
import type { IFullNodeBlockBuilder, ValidatorClientFullConfig } from '@aztec/stdlib/interfaces/server';
|
|
8
8
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
9
9
|
import { type BlockProposal } from '@aztec/stdlib/p2p';
|
|
10
10
|
import { type FailedTx, type Tx } from '@aztec/stdlib/tx';
|
|
11
11
|
import { type TelemetryClient, type Tracer } from '@aztec/telemetry-client';
|
|
12
12
|
import type { ValidatorMetrics } from './metrics.js';
|
|
13
|
-
export type BlockProposalValidationFailureReason = 'invalid_proposal' | 'parent_block_not_found' | '
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
export type BlockProposalValidationFailureReason = 'invalid_proposal' | 'parent_block_not_found' | 'parent_block_wrong_slot' | 'in_hash_mismatch' | 'block_number_already_exists' | 'txs_not_available' | 'state_mismatch' | 'failed_txs' | 'timeout' | 'unknown_error';
|
|
14
|
+
type ReexecuteTransactionsResult = {
|
|
15
|
+
block: L2Block;
|
|
16
|
+
failedTxs: FailedTx[];
|
|
17
|
+
reexecutionTimeMs: number;
|
|
18
|
+
totalManaUsed: number;
|
|
19
|
+
};
|
|
20
|
+
export type BlockProposalValidationSuccessResult = {
|
|
21
|
+
isValid: true;
|
|
22
|
+
blockNumber: number;
|
|
23
|
+
reexecutionResult?: ReexecuteTransactionsResult;
|
|
24
|
+
};
|
|
25
|
+
export type BlockProposalValidationFailureResult = {
|
|
26
|
+
isValid: false;
|
|
27
|
+
reason: BlockProposalValidationFailureReason;
|
|
28
|
+
blockNumber?: number;
|
|
29
|
+
reexecutionResult?: ReexecuteTransactionsResult;
|
|
30
|
+
};
|
|
31
|
+
export type BlockProposalValidationResult = BlockProposalValidationSuccessResult | BlockProposalValidationFailureResult;
|
|
24
32
|
export declare class BlockProposalHandler {
|
|
25
33
|
private blockBuilder;
|
|
26
34
|
private blockSource;
|
|
@@ -35,13 +43,10 @@ export declare class BlockProposalHandler {
|
|
|
35
43
|
constructor(blockBuilder: IFullNodeBlockBuilder, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, blockProposalValidator: BlockProposalValidator, config: ValidatorClientFullConfig, metrics?: ValidatorMetrics | undefined, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
|
|
36
44
|
registerForReexecution(p2pClient: P2P): BlockProposalHandler;
|
|
37
45
|
handleBlockProposal(proposal: BlockProposal, proposalSender: PeerId, shouldReexecute: boolean): Promise<BlockProposalValidationResult>;
|
|
46
|
+
private getParentBlock;
|
|
38
47
|
private getReexecutionDeadline;
|
|
39
48
|
private getReexecuteFailureReason;
|
|
40
|
-
reexecuteTransactions(proposal: BlockProposal, txs: Tx[], l1ToL2Messages: Fr[]): Promise<
|
|
41
|
-
block: any;
|
|
42
|
-
failedTxs: FailedTx[];
|
|
43
|
-
reexecutionTimeMs: number;
|
|
44
|
-
totalManaUsed: number;
|
|
45
|
-
}>;
|
|
49
|
+
reexecuteTransactions(proposal: BlockProposal, blockNumber: number, txs: Tx[], l1ToL2Messages: Fr[]): Promise<ReexecuteTransactionsResult>;
|
|
46
50
|
}
|
|
51
|
+
export {};
|
|
47
52
|
//# sourceMappingURL=block_proposal_handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"block_proposal_handler.d.ts","sourceRoot":"","sources":["../src/block_proposal_handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"block_proposal_handler.d.ts","sourceRoot":"","sources":["../src/block_proposal_handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
+
import { TimeoutError } from '@aztec/foundation/error';
|
|
2
3
|
import { Fr } from '@aztec/foundation/fields';
|
|
3
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
5
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
@@ -36,16 +37,16 @@ export class BlockProposalHandler {
|
|
|
36
37
|
const handler = async (proposal, proposalSender)=>{
|
|
37
38
|
try {
|
|
38
39
|
const result = await this.handleBlockProposal(proposal, proposalSender, true);
|
|
39
|
-
if (result.isValid
|
|
40
|
+
if (result.isValid) {
|
|
40
41
|
this.log.info(`Non-validator reexecution completed for slot ${proposal.slotNumber.toBigInt()}`, {
|
|
41
|
-
blockNumber:
|
|
42
|
-
reexecutionTimeMs: result.reexecutionResult
|
|
43
|
-
totalManaUsed: result.reexecutionResult
|
|
44
|
-
numTxs: result.reexecutionResult
|
|
42
|
+
blockNumber: result.blockNumber,
|
|
43
|
+
reexecutionTimeMs: result.reexecutionResult?.reexecutionTimeMs,
|
|
44
|
+
totalManaUsed: result.reexecutionResult?.totalManaUsed,
|
|
45
|
+
numTxs: result.reexecutionResult?.block?.body?.txEffects?.length ?? 0
|
|
45
46
|
});
|
|
46
47
|
} else {
|
|
47
48
|
this.log.warn(`Non-validator reexecution failed for slot ${proposal.slotNumber.toBigInt()}`, {
|
|
48
|
-
blockNumber:
|
|
49
|
+
blockNumber: result.blockNumber,
|
|
49
50
|
reason: result.reason
|
|
50
51
|
});
|
|
51
52
|
}
|
|
@@ -59,8 +60,8 @@ export class BlockProposalHandler {
|
|
|
59
60
|
}
|
|
60
61
|
async handleBlockProposal(proposal, proposalSender, shouldReexecute) {
|
|
61
62
|
const slotNumber = proposal.slotNumber.toBigInt();
|
|
62
|
-
const blockNumber = proposal.blockNumber;
|
|
63
63
|
const proposer = proposal.getSender();
|
|
64
|
+
const config = this.blockBuilder.getConfig();
|
|
64
65
|
// Reject proposals with invalid signatures
|
|
65
66
|
if (!proposer) {
|
|
66
67
|
this.log.warn(`Received proposal with invalid signature for slot ${slotNumber}`);
|
|
@@ -87,42 +88,45 @@ export class BlockProposalHandler {
|
|
|
87
88
|
reason: 'invalid_proposal'
|
|
88
89
|
};
|
|
89
90
|
}
|
|
91
|
+
// Check that the parent proposal is a block we know, otherwise reexecution would fail
|
|
92
|
+
const parentBlockHeader = await this.getParentBlock(proposal);
|
|
93
|
+
if (parentBlockHeader === undefined) {
|
|
94
|
+
this.log.warn(`Parent block for proposal not found, skipping processing`, proposalInfo);
|
|
95
|
+
return {
|
|
96
|
+
isValid: false,
|
|
97
|
+
reason: 'parent_block_not_found'
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// Check that the parent block's slot is less than the proposal's slot (should not happen, but we check anyway)
|
|
101
|
+
if (parentBlockHeader !== 'genesis' && parentBlockHeader.getSlot() >= slotNumber) {
|
|
102
|
+
this.log.warn(`Parent block slot is greater than or equal to proposal slot, skipping processing`, {
|
|
103
|
+
parentBlockSlot: parentBlockHeader.getSlot().toString(),
|
|
104
|
+
proposalSlot: slotNumber.toString(),
|
|
105
|
+
...proposalInfo
|
|
106
|
+
});
|
|
107
|
+
return {
|
|
108
|
+
isValid: false,
|
|
109
|
+
reason: 'parent_block_wrong_slot'
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// Compute the block number based on the parent block
|
|
113
|
+
const blockNumber = parentBlockHeader === 'genesis' ? INITIAL_L2_BLOCK_NUM : parentBlockHeader.getBlockNumber() + 1;
|
|
114
|
+
// Check that this block number does not exist already
|
|
115
|
+
const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
|
|
116
|
+
if (existingBlock) {
|
|
117
|
+
this.log.warn(`Block number ${blockNumber} already exists, skipping processing`, proposalInfo);
|
|
118
|
+
return {
|
|
119
|
+
isValid: false,
|
|
120
|
+
blockNumber,
|
|
121
|
+
reason: 'block_number_already_exists'
|
|
122
|
+
};
|
|
123
|
+
}
|
|
90
124
|
// Collect txs from the proposal. We start doing this as early as possible,
|
|
91
|
-
// and we do it even if we don't plan to re-execute the txs, so that we have them
|
|
92
|
-
|
|
93
|
-
const config = this.blockBuilder.getConfig();
|
|
94
|
-
const { txs, missingTxs } = await this.txProvider.getTxsForBlockProposal(proposal, {
|
|
125
|
+
// and we do it even if we don't plan to re-execute the txs, so that we have them if another node needs them.
|
|
126
|
+
const { txs, missingTxs } = await this.txProvider.getTxsForBlockProposal(proposal, blockNumber, {
|
|
95
127
|
pinnedPeer: proposalSender,
|
|
96
|
-
deadline: this.getReexecutionDeadline(
|
|
128
|
+
deadline: this.getReexecutionDeadline(slotNumber, config)
|
|
97
129
|
});
|
|
98
|
-
// Check that the parent proposal is a block we know, otherwise reexecution would fail
|
|
99
|
-
if (blockNumber > INITIAL_L2_BLOCK_NUM) {
|
|
100
|
-
const deadline = this.getReexecutionDeadline(proposal, config);
|
|
101
|
-
const currentTime = this.dateProvider.now();
|
|
102
|
-
const timeoutDurationMs = deadline.getTime() - currentTime;
|
|
103
|
-
const parentBlock = await this.blockSource.getBlock(blockNumber - 1) ?? (timeoutDurationMs <= 0 ? undefined : await retryUntil(async ()=>{
|
|
104
|
-
await this.blockSource.syncImmediate();
|
|
105
|
-
return await this.blockSource.getBlock(blockNumber - 1);
|
|
106
|
-
}, 'Force Archiver Sync', timeoutDurationMs / 1000, 0.5));
|
|
107
|
-
if (parentBlock === undefined) {
|
|
108
|
-
this.log.warn(`Parent block for ${blockNumber} not found, skipping processing`, proposalInfo);
|
|
109
|
-
return {
|
|
110
|
-
isValid: false,
|
|
111
|
-
reason: 'parent_block_not_found'
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
if (!proposal.payload.header.lastArchiveRoot.equals(parentBlock.archive.root)) {
|
|
115
|
-
this.log.warn(`Parent block archive root for proposal does not match, skipping processing`, {
|
|
116
|
-
proposalLastArchiveRoot: proposal.payload.header.lastArchiveRoot.toString(),
|
|
117
|
-
parentBlockArchiveRoot: parentBlock.archive.root.toString(),
|
|
118
|
-
...proposalInfo
|
|
119
|
-
});
|
|
120
|
-
return {
|
|
121
|
-
isValid: false,
|
|
122
|
-
reason: 'parent_block_does_not_match'
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
130
|
// Check that I have the same set of l1ToL2Messages as the proposal
|
|
127
131
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
|
|
128
132
|
const computedInHash = await computeInHashFromL1ToL2Messages(l1ToL2Messages);
|
|
@@ -135,18 +139,10 @@ export class BlockProposalHandler {
|
|
|
135
139
|
});
|
|
136
140
|
return {
|
|
137
141
|
isValid: false,
|
|
142
|
+
blockNumber,
|
|
138
143
|
reason: 'in_hash_mismatch'
|
|
139
144
|
};
|
|
140
145
|
}
|
|
141
|
-
// Check that this block number does not exist already
|
|
142
|
-
const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
|
|
143
|
-
if (existingBlock) {
|
|
144
|
-
this.log.warn(`Block number ${blockNumber} already exists, skipping processing`, proposalInfo);
|
|
145
|
-
return {
|
|
146
|
-
isValid: false,
|
|
147
|
-
reason: 'block_number_already_exists'
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
146
|
// Check that all of the transactions in the proposal are available
|
|
151
147
|
if (missingTxs.length > 0) {
|
|
152
148
|
this.log.warn(`Missing ${missingTxs.length} txs to process proposal`, {
|
|
@@ -155,6 +151,7 @@ export class BlockProposalHandler {
|
|
|
155
151
|
});
|
|
156
152
|
return {
|
|
157
153
|
isValid: false,
|
|
154
|
+
blockNumber,
|
|
158
155
|
reason: 'txs_not_available'
|
|
159
156
|
};
|
|
160
157
|
}
|
|
@@ -163,12 +160,13 @@ export class BlockProposalHandler {
|
|
|
163
160
|
if (shouldReexecute) {
|
|
164
161
|
try {
|
|
165
162
|
this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
|
|
166
|
-
reexecutionResult = await this.reexecuteTransactions(proposal, txs, l1ToL2Messages);
|
|
163
|
+
reexecutionResult = await this.reexecuteTransactions(proposal, blockNumber, txs, l1ToL2Messages);
|
|
167
164
|
} catch (error) {
|
|
168
165
|
this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
|
|
169
166
|
const reason = this.getReexecuteFailureReason(error);
|
|
170
167
|
return {
|
|
171
168
|
isValid: false,
|
|
169
|
+
blockNumber,
|
|
172
170
|
reason,
|
|
173
171
|
reexecutionResult
|
|
174
172
|
};
|
|
@@ -177,11 +175,38 @@ export class BlockProposalHandler {
|
|
|
177
175
|
this.log.info(`Successfully processed proposal for slot ${slotNumber}`, proposalInfo);
|
|
178
176
|
return {
|
|
179
177
|
isValid: true,
|
|
178
|
+
blockNumber,
|
|
180
179
|
reexecutionResult
|
|
181
180
|
};
|
|
182
181
|
}
|
|
183
|
-
|
|
184
|
-
const
|
|
182
|
+
async getParentBlock(proposal) {
|
|
183
|
+
const parentArchive = proposal.payload.header.lastArchiveRoot;
|
|
184
|
+
const slot = proposal.slotNumber.toBigInt();
|
|
185
|
+
const config = this.blockBuilder.getConfig();
|
|
186
|
+
const { genesisArchiveRoot } = await this.blockSource.getGenesisValues();
|
|
187
|
+
if (parentArchive.equals(genesisArchiveRoot)) {
|
|
188
|
+
return 'genesis';
|
|
189
|
+
}
|
|
190
|
+
const deadline = this.getReexecutionDeadline(slot, config);
|
|
191
|
+
const currentTime = this.dateProvider.now();
|
|
192
|
+
const timeoutDurationMs = deadline.getTime() - currentTime;
|
|
193
|
+
try {
|
|
194
|
+
return await this.blockSource.getBlockHeaderByArchive(parentArchive) ?? (timeoutDurationMs <= 0 ? undefined : await retryUntil(()=>this.blockSource.syncImmediate().then(()=>this.blockSource.getBlockHeaderByArchive(parentArchive)), 'force archiver sync', timeoutDurationMs / 1000, 0.5));
|
|
195
|
+
} catch (err) {
|
|
196
|
+
if (err instanceof TimeoutError) {
|
|
197
|
+
this.log.debug(`Timed out getting parent block by archive root`, {
|
|
198
|
+
parentArchive
|
|
199
|
+
});
|
|
200
|
+
} else {
|
|
201
|
+
this.log.error('Error getting parent block by archive root', err, {
|
|
202
|
+
parentArchive
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
getReexecutionDeadline(slot, config) {
|
|
209
|
+
const nextSlotTimestampSeconds = Number(getTimestampForSlot(slot + 1n, config));
|
|
185
210
|
const msNeededForPropagationAndPublishing = this.config.validatorReexecuteDeadlineMs;
|
|
186
211
|
return new Date(nextSlotTimestampSeconds * 1000 - msNeededForPropagationAndPublishing);
|
|
187
212
|
}
|
|
@@ -192,11 +217,11 @@ export class BlockProposalHandler {
|
|
|
192
217
|
return 'failed_txs';
|
|
193
218
|
} else if (err instanceof ReExTimeoutError) {
|
|
194
219
|
return 'timeout';
|
|
195
|
-
} else
|
|
220
|
+
} else {
|
|
196
221
|
return 'unknown_error';
|
|
197
222
|
}
|
|
198
223
|
}
|
|
199
|
-
async reexecuteTransactions(proposal, txs, l1ToL2Messages) {
|
|
224
|
+
async reexecuteTransactions(proposal, blockNumber, txs, l1ToL2Messages) {
|
|
200
225
|
const { header } = proposal.payload;
|
|
201
226
|
const { txHashes } = proposal;
|
|
202
227
|
// If we do not have all of the transactions, then we should fail
|
|
@@ -214,13 +239,13 @@ export class BlockProposalHandler {
|
|
|
214
239
|
coinbase: proposal.payload.header.coinbase,
|
|
215
240
|
feeRecipient: proposal.payload.header.feeRecipient,
|
|
216
241
|
gasFees: proposal.payload.header.gasFees,
|
|
217
|
-
blockNumber
|
|
242
|
+
blockNumber,
|
|
218
243
|
timestamp: header.timestamp,
|
|
219
244
|
chainId: new Fr(config.l1ChainId),
|
|
220
245
|
version: new Fr(config.rollupVersion)
|
|
221
246
|
});
|
|
222
247
|
const { block, failedTxs } = await this.blockBuilder.buildBlock(txs, l1ToL2Messages, globalVariables, {
|
|
223
|
-
deadline: this.getReexecutionDeadline(proposal, config)
|
|
248
|
+
deadline: this.getReexecutionDeadline(proposal.payload.header.slotNumber.toBigInt(), config)
|
|
224
249
|
});
|
|
225
250
|
const numFailedTxs = failedTxs.length;
|
|
226
251
|
const slot = proposal.slotNumber.toBigInt();
|
|
@@ -13,7 +13,6 @@ export declare class ValidationService {
|
|
|
13
13
|
/**
|
|
14
14
|
* Create a block proposal with the given header, archive, and transactions
|
|
15
15
|
*
|
|
16
|
-
* @param blockNumber - The block number this proposal is for
|
|
17
16
|
* @param header - The block header
|
|
18
17
|
* @param archive - The archive of the current block
|
|
19
18
|
* @param txs - TxHash[] ordered list of transactions
|
|
@@ -21,7 +20,7 @@ export declare class ValidationService {
|
|
|
21
20
|
*
|
|
22
21
|
* @returns A block proposal signing the above information (not the current implementation!!!)
|
|
23
22
|
*/
|
|
24
|
-
createBlockProposal(
|
|
23
|
+
createBlockProposal(header: CheckpointHeader, archive: Fr, stateReference: StateReference, txs: Tx[], proposerAttesterAddress: EthAddress | undefined, options: BlockProposalOptions): Promise<BlockProposal>;
|
|
25
24
|
/**
|
|
26
25
|
* Attest with selection of validators to the given block proposal, constructed by the current sequencer
|
|
27
26
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation_service.d.ts","sourceRoot":"","sources":["../../src/duties/validation_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAG9C,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,KAAK,oBAAoB,EAG1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,GAAG;gBADH,QAAQ,EAAE,iBAAiB,EAC3B,GAAG,yCAA+C;IAG5D
|
|
1
|
+
{"version":3,"file":"validation_service.d.ts","sourceRoot":"","sources":["../../src/duties/validation_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AACjE,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAG9C,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,KAAK,oBAAoB,EAG1B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,qBAAa,iBAAiB;IAE1B,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,GAAG;gBADH,QAAQ,EAAE,iBAAiB,EAC3B,GAAG,yCAA+C;IAG5D;;;;;;;;;OASG;IACG,mBAAmB,CACvB,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,EAAE,EACX,cAAc,EAAE,cAAc,EAC9B,GAAG,EAAE,EAAE,EAAE,EACT,uBAAuB,EAAE,UAAU,GAAG,SAAS,EAC/C,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,aAAa,CAAC;IA0BzB;;;;;;;;;OASG;IACG,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAU/F,0BAA0B,CAC9B,sBAAsB,EAAE,+BAA+B,EACvD,QAAQ,EAAE,UAAU,GACnB,OAAO,CAAC,SAAS,CAAC;CAMtB"}
|
|
@@ -14,14 +14,13 @@ export class ValidationService {
|
|
|
14
14
|
/**
|
|
15
15
|
* Create a block proposal with the given header, archive, and transactions
|
|
16
16
|
*
|
|
17
|
-
* @param blockNumber - The block number this proposal is for
|
|
18
17
|
* @param header - The block header
|
|
19
18
|
* @param archive - The archive of the current block
|
|
20
19
|
* @param txs - TxHash[] ordered list of transactions
|
|
21
20
|
* @param options - Block proposal options (including broadcastInvalidBlockProposal for testing)
|
|
22
21
|
*
|
|
23
22
|
* @returns A block proposal signing the above information (not the current implementation!!!)
|
|
24
|
-
*/ async createBlockProposal(
|
|
23
|
+
*/ async createBlockProposal(header, archive, stateReference, txs, proposerAttesterAddress, options) {
|
|
25
24
|
let payloadSigner;
|
|
26
25
|
if (proposerAttesterAddress !== undefined) {
|
|
27
26
|
payloadSigner = (payload)=>this.keyStore.signMessageWithAddress(proposerAttesterAddress, payload);
|
|
@@ -35,9 +34,9 @@ export class ValidationService {
|
|
|
35
34
|
// For testing: corrupt the state reference to trigger state_mismatch validation failure
|
|
36
35
|
if (options.broadcastInvalidBlockProposal) {
|
|
37
36
|
unfreeze(stateReference.partial).noteHashTree = AppendOnlyTreeSnapshot.random();
|
|
38
|
-
this.log.warn(`Creating INVALID block proposal for
|
|
37
|
+
this.log.warn(`Creating INVALID block proposal for slot ${header.slotNumber.toBigInt()}`);
|
|
39
38
|
}
|
|
40
|
-
return BlockProposal.createProposalFromSigner(
|
|
39
|
+
return BlockProposal.createProposalFromSigner(new ConsensusPayload(header, archive, stateReference), txHashes, options.publishFullTxs ? txs : undefined, payloadSigner);
|
|
41
40
|
}
|
|
42
41
|
/**
|
|
43
42
|
* Attest with selection of validators to the given block proposal, constructed by the current sequencer
|
|
@@ -51,7 +50,7 @@ export class ValidationService {
|
|
|
51
50
|
*/ async attestToProposal(proposal, attestors) {
|
|
52
51
|
const buf = Buffer32.fromBuffer(keccak256(proposal.payload.getPayloadToSign(SignatureDomainSeparator.blockAttestation)));
|
|
53
52
|
const signatures = await Promise.all(attestors.map((attestor)=>this.keyStore.signMessageWithAddress(attestor, buf)));
|
|
54
|
-
return signatures.map((sig)=>new BlockAttestation(proposal.
|
|
53
|
+
return signatures.map((sig)=>new BlockAttestation(proposal.payload, sig, proposal.signature));
|
|
55
54
|
}
|
|
56
55
|
async signAttestationsAndSigners(attestationsAndSigners, proposer) {
|
|
57
56
|
const buf = Buffer32.fromBuffer(keccak256(attestationsAndSigners.getPayloadToSign(SignatureDomainSeparator.attestationsAndSigners)));
|
package/dest/validator.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ export declare class ValidatorClient extends ValidatorClient_base implements Val
|
|
|
44
44
|
static new(config: ValidatorClientFullConfig, blockBuilder: IFullNodeBlockBuilder, epochCache: EpochCache, p2pClient: P2P, blockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: TxProvider, keyStoreManager: KeystoreManager, dateProvider?: DateProvider, telemetry?: TelemetryClient): ValidatorClient;
|
|
45
45
|
getValidatorAddresses(): EthAddress[];
|
|
46
46
|
getBlockProposalHandler(): BlockProposalHandler;
|
|
47
|
-
reExecuteTransactions(proposal: BlockProposal, txs: any[], l1ToL2Messages: Fr[]): Promise<any>;
|
|
47
|
+
reExecuteTransactions(proposal: BlockProposal, blockNumber: number, txs: any[], l1ToL2Messages: Fr[]): Promise<any>;
|
|
48
48
|
signWithAddress(addr: EthAddress, msg: TypedDataDefinition): Promise<Signature>;
|
|
49
49
|
getCoinbaseForAttestor(attestor: EthAddress): EthAddress;
|
|
50
50
|
getFeeRecipientForAttestor(attestor: EthAddress): AztecAddress;
|
package/dest/validator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../src/validator.ts"],"names":[],"mappings":"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"}
|
package/dest/validator.js
CHANGED
|
@@ -108,8 +108,8 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
108
108
|
return this.blockProposalHandler;
|
|
109
109
|
}
|
|
110
110
|
// Proxy method for backwards compatibility with tests
|
|
111
|
-
reExecuteTransactions(proposal, txs, l1ToL2Messages) {
|
|
112
|
-
return this.blockProposalHandler.reexecuteTransactions(proposal, txs, l1ToL2Messages);
|
|
111
|
+
reExecuteTransactions(proposal, blockNumber, txs, l1ToL2Messages) {
|
|
112
|
+
return this.blockProposalHandler.reexecuteTransactions(proposal, blockNumber, txs, l1ToL2Messages);
|
|
113
113
|
}
|
|
114
114
|
signWithAddress(addr, msg) {
|
|
115
115
|
return this.keyStore.signTypedDataWithAddress(addr, msg);
|
|
@@ -174,7 +174,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
174
174
|
...proposal.toBlockInfo(),
|
|
175
175
|
proposer: proposer.toString()
|
|
176
176
|
};
|
|
177
|
-
this.log.info(`Received proposal for
|
|
177
|
+
this.log.info(`Received proposal for slot ${slotNumber}`, {
|
|
178
178
|
...proposalInfo,
|
|
179
179
|
txHashes: proposal.txHashes.map((t)=>t.toString())
|
|
180
180
|
});
|
|
@@ -194,7 +194,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
194
194
|
'state_mismatch',
|
|
195
195
|
'failed_txs',
|
|
196
196
|
'in_hash_mismatch',
|
|
197
|
-
'
|
|
197
|
+
'parent_block_wrong_slot'
|
|
198
198
|
];
|
|
199
199
|
if (badProposalReasons.includes(reason)) {
|
|
200
200
|
this.metrics.incFailedAttestationsBadProposal(1, reason);
|
|
@@ -216,7 +216,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
216
216
|
return undefined;
|
|
217
217
|
}
|
|
218
218
|
// Provided all of the above checks pass, we can attest to the proposal
|
|
219
|
-
this.log.info(`Attesting to proposal for
|
|
219
|
+
this.log.info(`Attesting to proposal for slot ${slotNumber}`, proposalInfo);
|
|
220
220
|
this.metrics.incSuccessfulAttestations(inCommittee.length);
|
|
221
221
|
// If the above function does not throw an error, then we can attest to the proposal
|
|
222
222
|
return this.createBlockAttestationsFromProposal(proposal, inCommittee);
|
|
@@ -248,7 +248,7 @@ const SLASHABLE_BLOCK_PROPOSAL_VALIDATION_RESULT = [
|
|
|
248
248
|
this.log.verbose(`Already made a proposal for the same slot, skipping proposal`);
|
|
249
249
|
return Promise.resolve(undefined);
|
|
250
250
|
}
|
|
251
|
-
const newProposal = await this.validationService.createBlockProposal(
|
|
251
|
+
const newProposal = await this.validationService.createBlockProposal(header, archive, stateReference, txs, proposerAddress, {
|
|
252
252
|
...options,
|
|
253
253
|
broadcastInvalidBlockProposal: this.config.broadcastInvalidBlockProposal
|
|
254
254
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/validator-client",
|
|
3
|
-
"version": "3.0.0-nightly.
|
|
3
|
+
"version": "3.0.0-nightly.20251026",
|
|
4
4
|
"main": "dest/index.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -64,16 +64,16 @@
|
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@aztec/constants": "3.0.0-nightly.
|
|
68
|
-
"@aztec/epoch-cache": "3.0.0-nightly.
|
|
69
|
-
"@aztec/ethereum": "3.0.0-nightly.
|
|
70
|
-
"@aztec/foundation": "3.0.0-nightly.
|
|
71
|
-
"@aztec/node-keystore": "3.0.0-nightly.
|
|
72
|
-
"@aztec/p2p": "3.0.0-nightly.
|
|
73
|
-
"@aztec/prover-client": "3.0.0-nightly.
|
|
74
|
-
"@aztec/slasher": "3.0.0-nightly.
|
|
75
|
-
"@aztec/stdlib": "3.0.0-nightly.
|
|
76
|
-
"@aztec/telemetry-client": "3.0.0-nightly.
|
|
67
|
+
"@aztec/constants": "3.0.0-nightly.20251026",
|
|
68
|
+
"@aztec/epoch-cache": "3.0.0-nightly.20251026",
|
|
69
|
+
"@aztec/ethereum": "3.0.0-nightly.20251026",
|
|
70
|
+
"@aztec/foundation": "3.0.0-nightly.20251026",
|
|
71
|
+
"@aztec/node-keystore": "3.0.0-nightly.20251026",
|
|
72
|
+
"@aztec/p2p": "3.0.0-nightly.20251026",
|
|
73
|
+
"@aztec/prover-client": "3.0.0-nightly.20251026",
|
|
74
|
+
"@aztec/slasher": "3.0.0-nightly.20251026",
|
|
75
|
+
"@aztec/stdlib": "3.0.0-nightly.20251026",
|
|
76
|
+
"@aztec/telemetry-client": "3.0.0-nightly.20251026",
|
|
77
77
|
"koa": "^2.16.1",
|
|
78
78
|
"koa-router": "^13.1.1",
|
|
79
79
|
"tslib": "^2.4.0",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
2
|
+
import { TimeoutError } from '@aztec/foundation/error';
|
|
2
3
|
import { Fr } from '@aztec/foundation/fields';
|
|
3
4
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
5
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
@@ -7,12 +8,12 @@ import type { P2P, PeerId } from '@aztec/p2p';
|
|
|
7
8
|
import { TxProvider } from '@aztec/p2p';
|
|
8
9
|
import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
|
|
9
10
|
import { computeInHashFromL1ToL2Messages } from '@aztec/prover-client/helpers';
|
|
10
|
-
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
11
|
+
import type { L2Block, L2BlockSource } from '@aztec/stdlib/block';
|
|
11
12
|
import { getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
12
13
|
import type { IFullNodeBlockBuilder, ValidatorClientFullConfig } from '@aztec/stdlib/interfaces/server';
|
|
13
14
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
14
15
|
import { type BlockProposal, ConsensusPayload } from '@aztec/stdlib/p2p';
|
|
15
|
-
import { type FailedTx, GlobalVariables, type Tx } from '@aztec/stdlib/tx';
|
|
16
|
+
import { BlockHeader, type FailedTx, GlobalVariables, type Tx } from '@aztec/stdlib/tx';
|
|
16
17
|
import {
|
|
17
18
|
ReExFailedTxsError,
|
|
18
19
|
ReExStateMismatchError,
|
|
@@ -26,7 +27,7 @@ import type { ValidatorMetrics } from './metrics.js';
|
|
|
26
27
|
export type BlockProposalValidationFailureReason =
|
|
27
28
|
| 'invalid_proposal'
|
|
28
29
|
| 'parent_block_not_found'
|
|
29
|
-
| '
|
|
30
|
+
| 'parent_block_wrong_slot'
|
|
30
31
|
| 'in_hash_mismatch'
|
|
31
32
|
| 'block_number_already_exists'
|
|
32
33
|
| 'txs_not_available'
|
|
@@ -35,16 +36,27 @@ export type BlockProposalValidationFailureReason =
|
|
|
35
36
|
| 'timeout'
|
|
36
37
|
| 'unknown_error';
|
|
37
38
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
type ReexecuteTransactionsResult = {
|
|
40
|
+
block: L2Block;
|
|
41
|
+
failedTxs: FailedTx[];
|
|
42
|
+
reexecutionTimeMs: number;
|
|
43
|
+
totalManaUsed: number;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type BlockProposalValidationSuccessResult = {
|
|
47
|
+
isValid: true;
|
|
48
|
+
blockNumber: number;
|
|
49
|
+
reexecutionResult?: ReexecuteTransactionsResult;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export type BlockProposalValidationFailureResult = {
|
|
53
|
+
isValid: false;
|
|
54
|
+
reason: BlockProposalValidationFailureReason;
|
|
55
|
+
blockNumber?: number;
|
|
56
|
+
reexecutionResult?: ReexecuteTransactionsResult;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type BlockProposalValidationResult = BlockProposalValidationSuccessResult | BlockProposalValidationFailureResult;
|
|
48
60
|
|
|
49
61
|
export class BlockProposalHandler {
|
|
50
62
|
public readonly tracer: Tracer;
|
|
@@ -68,16 +80,16 @@ export class BlockProposalHandler {
|
|
|
68
80
|
const handler = async (proposal: BlockProposal, proposalSender: PeerId) => {
|
|
69
81
|
try {
|
|
70
82
|
const result = await this.handleBlockProposal(proposal, proposalSender, true);
|
|
71
|
-
if (result.isValid
|
|
83
|
+
if (result.isValid) {
|
|
72
84
|
this.log.info(`Non-validator reexecution completed for slot ${proposal.slotNumber.toBigInt()}`, {
|
|
73
|
-
blockNumber:
|
|
74
|
-
reexecutionTimeMs: result.reexecutionResult
|
|
75
|
-
totalManaUsed: result.reexecutionResult
|
|
76
|
-
numTxs: result.reexecutionResult
|
|
85
|
+
blockNumber: result.blockNumber,
|
|
86
|
+
reexecutionTimeMs: result.reexecutionResult?.reexecutionTimeMs,
|
|
87
|
+
totalManaUsed: result.reexecutionResult?.totalManaUsed,
|
|
88
|
+
numTxs: result.reexecutionResult?.block?.body?.txEffects?.length ?? 0,
|
|
77
89
|
});
|
|
78
90
|
} else {
|
|
79
91
|
this.log.warn(`Non-validator reexecution failed for slot ${proposal.slotNumber.toBigInt()}`, {
|
|
80
|
-
blockNumber:
|
|
92
|
+
blockNumber: result.blockNumber,
|
|
81
93
|
reason: result.reason,
|
|
82
94
|
});
|
|
83
95
|
}
|
|
@@ -97,8 +109,8 @@ export class BlockProposalHandler {
|
|
|
97
109
|
shouldReexecute: boolean,
|
|
98
110
|
): Promise<BlockProposalValidationResult> {
|
|
99
111
|
const slotNumber = proposal.slotNumber.toBigInt();
|
|
100
|
-
const blockNumber = proposal.blockNumber;
|
|
101
112
|
const proposer = proposal.getSender();
|
|
113
|
+
const config = this.blockBuilder.getConfig();
|
|
102
114
|
|
|
103
115
|
// Reject proposals with invalid signatures
|
|
104
116
|
if (!proposer) {
|
|
@@ -120,49 +132,40 @@ export class BlockProposalHandler {
|
|
|
120
132
|
return { isValid: false, reason: 'invalid_proposal' };
|
|
121
133
|
}
|
|
122
134
|
|
|
123
|
-
// Collect txs from the proposal. We start doing this as early as possible,
|
|
124
|
-
// and we do it even if we don't plan to re-execute the txs, so that we have them
|
|
125
|
-
// if another node needs them.
|
|
126
|
-
const config = this.blockBuilder.getConfig();
|
|
127
|
-
const { txs, missingTxs } = await this.txProvider.getTxsForBlockProposal(proposal, {
|
|
128
|
-
pinnedPeer: proposalSender,
|
|
129
|
-
deadline: this.getReexecutionDeadline(proposal, config),
|
|
130
|
-
});
|
|
131
|
-
|
|
132
135
|
// Check that the parent proposal is a block we know, otherwise reexecution would fail
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
(await this.blockSource.getBlock(blockNumber - 1)) ??
|
|
139
|
-
(timeoutDurationMs <= 0
|
|
140
|
-
? undefined
|
|
141
|
-
: await retryUntil(
|
|
142
|
-
async () => {
|
|
143
|
-
await this.blockSource.syncImmediate();
|
|
144
|
-
return await this.blockSource.getBlock(blockNumber - 1);
|
|
145
|
-
},
|
|
146
|
-
'Force Archiver Sync',
|
|
147
|
-
timeoutDurationMs / 1000,
|
|
148
|
-
0.5,
|
|
149
|
-
));
|
|
136
|
+
const parentBlockHeader = await this.getParentBlock(proposal);
|
|
137
|
+
if (parentBlockHeader === undefined) {
|
|
138
|
+
this.log.warn(`Parent block for proposal not found, skipping processing`, proposalInfo);
|
|
139
|
+
return { isValid: false, reason: 'parent_block_not_found' };
|
|
140
|
+
}
|
|
150
141
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
142
|
+
// Check that the parent block's slot is less than the proposal's slot (should not happen, but we check anyway)
|
|
143
|
+
if (parentBlockHeader !== 'genesis' && parentBlockHeader.getSlot() >= slotNumber) {
|
|
144
|
+
this.log.warn(`Parent block slot is greater than or equal to proposal slot, skipping processing`, {
|
|
145
|
+
parentBlockSlot: parentBlockHeader.getSlot().toString(),
|
|
146
|
+
proposalSlot: slotNumber.toString(),
|
|
147
|
+
...proposalInfo,
|
|
148
|
+
});
|
|
149
|
+
return { isValid: false, reason: 'parent_block_wrong_slot' };
|
|
150
|
+
}
|
|
155
151
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
152
|
+
// Compute the block number based on the parent block
|
|
153
|
+
const blockNumber = parentBlockHeader === 'genesis' ? INITIAL_L2_BLOCK_NUM : parentBlockHeader.getBlockNumber() + 1;
|
|
154
|
+
|
|
155
|
+
// Check that this block number does not exist already
|
|
156
|
+
const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
|
|
157
|
+
if (existingBlock) {
|
|
158
|
+
this.log.warn(`Block number ${blockNumber} already exists, skipping processing`, proposalInfo);
|
|
159
|
+
return { isValid: false, blockNumber, reason: 'block_number_already_exists' };
|
|
164
160
|
}
|
|
165
161
|
|
|
162
|
+
// Collect txs from the proposal. We start doing this as early as possible,
|
|
163
|
+
// and we do it even if we don't plan to re-execute the txs, so that we have them if another node needs them.
|
|
164
|
+
const { txs, missingTxs } = await this.txProvider.getTxsForBlockProposal(proposal, blockNumber, {
|
|
165
|
+
pinnedPeer: proposalSender,
|
|
166
|
+
deadline: this.getReexecutionDeadline(slotNumber, config),
|
|
167
|
+
});
|
|
168
|
+
|
|
166
169
|
// Check that I have the same set of l1ToL2Messages as the proposal
|
|
167
170
|
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(blockNumber);
|
|
168
171
|
const computedInHash = await computeInHashFromL1ToL2Messages(l1ToL2Messages);
|
|
@@ -173,20 +176,13 @@ export class BlockProposalHandler {
|
|
|
173
176
|
computedInHash: computedInHash.toString(),
|
|
174
177
|
...proposalInfo,
|
|
175
178
|
});
|
|
176
|
-
return { isValid: false, reason: 'in_hash_mismatch' };
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// Check that this block number does not exist already
|
|
180
|
-
const existingBlock = await this.blockSource.getBlockHeader(blockNumber);
|
|
181
|
-
if (existingBlock) {
|
|
182
|
-
this.log.warn(`Block number ${blockNumber} already exists, skipping processing`, proposalInfo);
|
|
183
|
-
return { isValid: false, reason: 'block_number_already_exists' };
|
|
179
|
+
return { isValid: false, blockNumber, reason: 'in_hash_mismatch' };
|
|
184
180
|
}
|
|
185
181
|
|
|
186
182
|
// Check that all of the transactions in the proposal are available
|
|
187
183
|
if (missingTxs.length > 0) {
|
|
188
184
|
this.log.warn(`Missing ${missingTxs.length} txs to process proposal`, { ...proposalInfo, missingTxs });
|
|
189
|
-
return { isValid: false, reason: 'txs_not_available' };
|
|
185
|
+
return { isValid: false, blockNumber, reason: 'txs_not_available' };
|
|
190
186
|
}
|
|
191
187
|
|
|
192
188
|
// Try re-executing the transactions in the proposal if needed
|
|
@@ -194,23 +190,57 @@ export class BlockProposalHandler {
|
|
|
194
190
|
if (shouldReexecute) {
|
|
195
191
|
try {
|
|
196
192
|
this.log.verbose(`Re-executing transactions in the proposal`, proposalInfo);
|
|
197
|
-
reexecutionResult = await this.reexecuteTransactions(proposal, txs, l1ToL2Messages);
|
|
193
|
+
reexecutionResult = await this.reexecuteTransactions(proposal, blockNumber, txs, l1ToL2Messages);
|
|
198
194
|
} catch (error) {
|
|
199
195
|
this.log.error(`Error reexecuting txs while processing block proposal`, error, proposalInfo);
|
|
200
196
|
const reason = this.getReexecuteFailureReason(error);
|
|
201
|
-
return { isValid: false, reason, reexecutionResult };
|
|
197
|
+
return { isValid: false, blockNumber, reason, reexecutionResult };
|
|
202
198
|
}
|
|
203
199
|
}
|
|
204
200
|
|
|
205
201
|
this.log.info(`Successfully processed proposal for slot ${slotNumber}`, proposalInfo);
|
|
206
|
-
return { isValid: true, reexecutionResult };
|
|
202
|
+
return { isValid: true, blockNumber, reexecutionResult };
|
|
207
203
|
}
|
|
208
204
|
|
|
209
|
-
private
|
|
210
|
-
proposal
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const
|
|
205
|
+
private async getParentBlock(proposal: BlockProposal): Promise<'genesis' | BlockHeader | undefined> {
|
|
206
|
+
const parentArchive = proposal.payload.header.lastArchiveRoot;
|
|
207
|
+
const slot = proposal.slotNumber.toBigInt();
|
|
208
|
+
const config = this.blockBuilder.getConfig();
|
|
209
|
+
const { genesisArchiveRoot } = await this.blockSource.getGenesisValues();
|
|
210
|
+
|
|
211
|
+
if (parentArchive.equals(genesisArchiveRoot)) {
|
|
212
|
+
return 'genesis';
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const deadline = this.getReexecutionDeadline(slot, config);
|
|
216
|
+
const currentTime = this.dateProvider.now();
|
|
217
|
+
const timeoutDurationMs = deadline.getTime() - currentTime;
|
|
218
|
+
|
|
219
|
+
try {
|
|
220
|
+
return (
|
|
221
|
+
(await this.blockSource.getBlockHeaderByArchive(parentArchive)) ??
|
|
222
|
+
(timeoutDurationMs <= 0
|
|
223
|
+
? undefined
|
|
224
|
+
: await retryUntil(
|
|
225
|
+
() =>
|
|
226
|
+
this.blockSource.syncImmediate().then(() => this.blockSource.getBlockHeaderByArchive(parentArchive)),
|
|
227
|
+
'force archiver sync',
|
|
228
|
+
timeoutDurationMs / 1000,
|
|
229
|
+
0.5,
|
|
230
|
+
))
|
|
231
|
+
);
|
|
232
|
+
} catch (err) {
|
|
233
|
+
if (err instanceof TimeoutError) {
|
|
234
|
+
this.log.debug(`Timed out getting parent block by archive root`, { parentArchive });
|
|
235
|
+
} else {
|
|
236
|
+
this.log.error('Error getting parent block by archive root', err, { parentArchive });
|
|
237
|
+
}
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
private getReexecutionDeadline(slot: bigint, config: { l1GenesisTime: bigint; slotDuration: number }): Date {
|
|
243
|
+
const nextSlotTimestampSeconds = Number(getTimestampForSlot(slot + 1n, config));
|
|
214
244
|
const msNeededForPropagationAndPublishing = this.config.validatorReexecuteDeadlineMs;
|
|
215
245
|
return new Date(nextSlotTimestampSeconds * 1000 - msNeededForPropagationAndPublishing);
|
|
216
246
|
}
|
|
@@ -222,21 +252,17 @@ export class BlockProposalHandler {
|
|
|
222
252
|
return 'failed_txs';
|
|
223
253
|
} else if (err instanceof ReExTimeoutError) {
|
|
224
254
|
return 'timeout';
|
|
225
|
-
} else
|
|
255
|
+
} else {
|
|
226
256
|
return 'unknown_error';
|
|
227
257
|
}
|
|
228
258
|
}
|
|
229
259
|
|
|
230
260
|
async reexecuteTransactions(
|
|
231
261
|
proposal: BlockProposal,
|
|
262
|
+
blockNumber: number,
|
|
232
263
|
txs: Tx[],
|
|
233
264
|
l1ToL2Messages: Fr[],
|
|
234
|
-
): Promise<{
|
|
235
|
-
block: any;
|
|
236
|
-
failedTxs: FailedTx[];
|
|
237
|
-
reexecutionTimeMs: number;
|
|
238
|
-
totalManaUsed: number;
|
|
239
|
-
}> {
|
|
265
|
+
): Promise<ReexecuteTransactionsResult> {
|
|
240
266
|
const { header } = proposal.payload;
|
|
241
267
|
const { txHashes } = proposal;
|
|
242
268
|
|
|
@@ -257,14 +283,14 @@ export class BlockProposalHandler {
|
|
|
257
283
|
coinbase: proposal.payload.header.coinbase, // set arbitrarily by the proposer
|
|
258
284
|
feeRecipient: proposal.payload.header.feeRecipient, // set arbitrarily by the proposer
|
|
259
285
|
gasFees: proposal.payload.header.gasFees, // validated by the rollup contract
|
|
260
|
-
blockNumber
|
|
286
|
+
blockNumber, // computed from the parent block and checked it does not exist in archiver
|
|
261
287
|
timestamp: header.timestamp, // checked in the rollup contract against the slot number
|
|
262
288
|
chainId: new Fr(config.l1ChainId),
|
|
263
289
|
version: new Fr(config.rollupVersion),
|
|
264
290
|
});
|
|
265
291
|
|
|
266
292
|
const { block, failedTxs } = await this.blockBuilder.buildBlock(txs, l1ToL2Messages, globalVariables, {
|
|
267
|
-
deadline: this.getReexecutionDeadline(proposal, config),
|
|
293
|
+
deadline: this.getReexecutionDeadline(proposal.payload.header.slotNumber.toBigInt(), config),
|
|
268
294
|
});
|
|
269
295
|
|
|
270
296
|
const numFailedTxs = failedTxs.length;
|
|
@@ -28,7 +28,6 @@ export class ValidationService {
|
|
|
28
28
|
/**
|
|
29
29
|
* Create a block proposal with the given header, archive, and transactions
|
|
30
30
|
*
|
|
31
|
-
* @param blockNumber - The block number this proposal is for
|
|
32
31
|
* @param header - The block header
|
|
33
32
|
* @param archive - The archive of the current block
|
|
34
33
|
* @param txs - TxHash[] ordered list of transactions
|
|
@@ -37,7 +36,6 @@ export class ValidationService {
|
|
|
37
36
|
* @returns A block proposal signing the above information (not the current implementation!!!)
|
|
38
37
|
*/
|
|
39
38
|
async createBlockProposal(
|
|
40
|
-
blockNumber: number,
|
|
41
39
|
header: CheckpointHeader,
|
|
42
40
|
archive: Fr,
|
|
43
41
|
stateReference: StateReference,
|
|
@@ -59,11 +57,10 @@ export class ValidationService {
|
|
|
59
57
|
// For testing: corrupt the state reference to trigger state_mismatch validation failure
|
|
60
58
|
if (options.broadcastInvalidBlockProposal) {
|
|
61
59
|
unfreeze(stateReference.partial).noteHashTree = AppendOnlyTreeSnapshot.random();
|
|
62
|
-
this.log.warn(`Creating INVALID block proposal for
|
|
60
|
+
this.log.warn(`Creating INVALID block proposal for slot ${header.slotNumber.toBigInt()}`);
|
|
63
61
|
}
|
|
64
62
|
|
|
65
63
|
return BlockProposal.createProposalFromSigner(
|
|
66
|
-
blockNumber,
|
|
67
64
|
new ConsensusPayload(header, archive, stateReference),
|
|
68
65
|
txHashes,
|
|
69
66
|
options.publishFullTxs ? txs : undefined,
|
|
@@ -88,7 +85,7 @@ export class ValidationService {
|
|
|
88
85
|
const signatures = await Promise.all(
|
|
89
86
|
attestors.map(attestor => this.keyStore.signMessageWithAddress(attestor, buf)),
|
|
90
87
|
);
|
|
91
|
-
return signatures.map(sig => new BlockAttestation(proposal.
|
|
88
|
+
return signatures.map(sig => new BlockAttestation(proposal.payload, sig, proposal.signature));
|
|
92
89
|
}
|
|
93
90
|
|
|
94
91
|
async signAttestationsAndSigners(
|
package/src/validator.ts
CHANGED
|
@@ -184,8 +184,13 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
184
184
|
}
|
|
185
185
|
|
|
186
186
|
// Proxy method for backwards compatibility with tests
|
|
187
|
-
public reExecuteTransactions(
|
|
188
|
-
|
|
187
|
+
public reExecuteTransactions(
|
|
188
|
+
proposal: BlockProposal,
|
|
189
|
+
blockNumber: number,
|
|
190
|
+
txs: any[],
|
|
191
|
+
l1ToL2Messages: Fr[],
|
|
192
|
+
): Promise<any> {
|
|
193
|
+
return this.blockProposalHandler.reexecuteTransactions(proposal, blockNumber, txs, l1ToL2Messages);
|
|
189
194
|
}
|
|
190
195
|
|
|
191
196
|
public signWithAddress(addr: EthAddress, msg: TypedDataDefinition) {
|
|
@@ -268,7 +273,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
268
273
|
const partOfCommittee = inCommittee.length > 0;
|
|
269
274
|
|
|
270
275
|
const proposalInfo = { ...proposal.toBlockInfo(), proposer: proposer.toString() };
|
|
271
|
-
this.log.info(`Received proposal for
|
|
276
|
+
this.log.info(`Received proposal for slot ${slotNumber}`, {
|
|
272
277
|
...proposalInfo,
|
|
273
278
|
txHashes: proposal.txHashes.map(t => t.toString()),
|
|
274
279
|
});
|
|
@@ -299,7 +304,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
299
304
|
'state_mismatch',
|
|
300
305
|
'failed_txs',
|
|
301
306
|
'in_hash_mismatch',
|
|
302
|
-
'
|
|
307
|
+
'parent_block_wrong_slot',
|
|
303
308
|
];
|
|
304
309
|
|
|
305
310
|
if (badProposalReasons.includes(reason as BlockProposalValidationFailureReason)) {
|
|
@@ -329,7 +334,7 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
329
334
|
}
|
|
330
335
|
|
|
331
336
|
// Provided all of the above checks pass, we can attest to the proposal
|
|
332
|
-
this.log.info(`Attesting to proposal for
|
|
337
|
+
this.log.info(`Attesting to proposal for slot ${slotNumber}`, proposalInfo);
|
|
333
338
|
this.metrics.incSuccessfulAttestations(inCommittee.length);
|
|
334
339
|
|
|
335
340
|
// If the above function does not throw an error, then we can attest to the proposal
|
|
@@ -378,7 +383,6 @@ export class ValidatorClient extends (EventEmitter as new () => WatcherEmitter)
|
|
|
378
383
|
}
|
|
379
384
|
|
|
380
385
|
const newProposal = await this.validationService.createBlockProposal(
|
|
381
|
-
blockNumber,
|
|
382
386
|
header,
|
|
383
387
|
archive,
|
|
384
388
|
stateReference,
|