@aztec/validator-client 0.0.1-commit.9ee6fcc6 → 0.0.1-commit.9ef841308
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/README.md +0 -2
- package/dest/config.d.ts +1 -1
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +0 -5
- package/dest/factory.d.ts +5 -4
- package/dest/factory.d.ts.map +1 -1
- package/dest/factory.js +3 -3
- package/dest/index.d.ts +2 -2
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/metrics.d.ts +2 -2
- package/dest/metrics.d.ts.map +1 -1
- package/dest/proposal_handler.d.ts +94 -0
- package/dest/proposal_handler.d.ts.map +1 -0
- package/dest/{block_proposal_handler.js → proposal_handler.js} +249 -7
- package/dest/validator.d.ts +7 -20
- package/dest/validator.d.ts.map +1 -1
- package/dest/validator.js +16 -224
- package/package.json +19 -19
- package/src/config.ts +0 -5
- package/src/factory.ts +5 -3
- package/src/index.ts +1 -1
- package/src/metrics.ts +1 -1
- package/src/{block_proposal_handler.ts → proposal_handler.ts} +283 -8
- package/src/validator.ts +20 -247
- package/dest/block_proposal_handler.d.ts +0 -64
- package/dest/block_proposal_handler.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -158,13 +158,11 @@ Time | Proposer | Validator
|
|
|
158
158
|
|
|
159
159
|
| Flag | Purpose |
|
|
160
160
|
| ------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
161
|
-
| `validatorReexecute` | Re-execute transactions to verify proposals |
|
|
162
161
|
| `fishermanMode` | Validate proposals but don't broadcast attestations (monitoring only) |
|
|
163
162
|
| `alwaysReexecuteBlockProposals` | Force re-execution even when not in committee |
|
|
164
163
|
| `slashBroadcastedInvalidBlockPenalty` | Penalty amount for invalid proposals (0 = disabled) |
|
|
165
164
|
| `slashDuplicateProposalPenalty` | Penalty amount for duplicate proposals (0 = disabled) |
|
|
166
165
|
| `slashDuplicateAttestationPenalty` | Penalty amount for duplicate attestations (0 = disabled) |
|
|
167
|
-
| `validatorReexecuteDeadlineMs` | Time reserved at end of slot for propagation/publishing |
|
|
168
166
|
| `attestationPollingIntervalMs` | How often to poll for attestations when collecting |
|
|
169
167
|
| `disabledValidators` | Validator addresses to exclude from duties |
|
|
170
168
|
|
package/dest/config.d.ts
CHANGED
|
@@ -8,4 +8,4 @@ export declare const validatorClientConfigMappings: ConfigMappingsType<Validator
|
|
|
8
8
|
* @returns The validator configuration.
|
|
9
9
|
*/
|
|
10
10
|
export declare function getProverEnvVars(): ValidatorClientConfig;
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uZmlnLmQudHMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvY29uZmlnLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxLQUFLLGtCQUFrQixFQUt4QixNQUFNLDBCQUEwQixDQUFDO0FBR2xDLE9BQU8sS0FBSyxFQUFFLHFCQUFxQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFFN0UsWUFBWSxFQUFFLHFCQUFxQixFQUFFLENBQUM7QUFFdEMsZUFBTyxNQUFNLDZCQUE2QixFQUFFLGtCQUFrQixDQUFDLHFCQUFxQixDQW1GbkYsQ0FBQztBQUVGOzs7O0dBSUc7QUFDSCx3QkFBZ0IsZ0JBQWdCLElBQUkscUJBQXFCLENBRXhEIn0=
|
package/dest/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EAKxB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAEtC,eAAO,MAAM,6BAA6B,EAAE,kBAAkB,CAAC,qBAAqB,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,kBAAkB,EAKxB,MAAM,0BAA0B,CAAC;AAGlC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E,YAAY,EAAE,qBAAqB,EAAE,CAAC;AAEtC,eAAO,MAAM,6BAA6B,EAAE,kBAAkB,CAAC,qBAAqB,CAmFnF,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,qBAAqB,CAExD"}
|
package/dest/config.js
CHANGED
|
@@ -31,11 +31,6 @@ export const validatorClientConfigMappings = {
|
|
|
31
31
|
description: 'Interval between polling for new attestations',
|
|
32
32
|
...numberConfigHelper(200)
|
|
33
33
|
},
|
|
34
|
-
validatorReexecute: {
|
|
35
|
-
env: 'VALIDATOR_REEXECUTE',
|
|
36
|
-
description: 'Re-execute transactions before attesting',
|
|
37
|
-
...booleanConfigHelper(true)
|
|
38
|
-
},
|
|
39
34
|
alwaysReexecuteBlockProposals: {
|
|
40
35
|
description: 'Whether to always reexecute block proposals, even for non-validator nodes (useful for monitoring network status).',
|
|
41
36
|
defaultValue: true
|
package/dest/factory.d.ts
CHANGED
|
@@ -8,19 +8,20 @@ import type { ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/s
|
|
|
8
8
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
9
9
|
import type { TelemetryClient } from '@aztec/telemetry-client';
|
|
10
10
|
import type { SlashingProtectionDatabase } from '@aztec/validator-ha-signer/types';
|
|
11
|
-
import { BlockProposalHandler } from './block_proposal_handler.js';
|
|
12
11
|
import type { FullNodeCheckpointsBuilder } from './checkpoint_builder.js';
|
|
12
|
+
import { ProposalHandler } from './proposal_handler.js';
|
|
13
13
|
import { ValidatorClient } from './validator.js';
|
|
14
|
-
export declare function
|
|
14
|
+
export declare function createProposalHandler(config: ValidatorClientFullConfig, deps: {
|
|
15
15
|
checkpointsBuilder: FullNodeCheckpointsBuilder;
|
|
16
16
|
worldState: WorldStateSynchronizer;
|
|
17
17
|
blockSource: L2BlockSource & L2BlockSink;
|
|
18
18
|
l1ToL2MessageSource: L1ToL2MessageSource;
|
|
19
19
|
p2pClient: P2PClient;
|
|
20
20
|
epochCache: EpochCache;
|
|
21
|
+
blobClient: BlobClientInterface;
|
|
21
22
|
dateProvider: DateProvider;
|
|
22
23
|
telemetry: TelemetryClient;
|
|
23
|
-
}):
|
|
24
|
+
}): ProposalHandler;
|
|
24
25
|
export declare function createValidatorClient(config: ValidatorClientFullConfig, deps: {
|
|
25
26
|
checkpointsBuilder: FullNodeCheckpointsBuilder;
|
|
26
27
|
worldState: WorldStateSynchronizer;
|
|
@@ -34,4 +35,4 @@ export declare function createValidatorClient(config: ValidatorClientFullConfig,
|
|
|
34
35
|
blobClient: BlobClientInterface;
|
|
35
36
|
slashingProtectionDb?: SlashingProtectionDatabase;
|
|
36
37
|
}): Promise<ValidatorClient> | undefined;
|
|
37
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
38
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFjdG9yeS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2ZhY3RvcnkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNyRSxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNyRCxPQUFPLEtBQUssRUFBRSxZQUFZLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM1RCxPQUFPLEtBQUssRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUM1RCxPQUFPLEVBQTBCLEtBQUssU0FBUyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3BFLE9BQU8sS0FBSyxFQUFFLFdBQVcsRUFBRSxhQUFhLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN0RSxPQUFPLEtBQUssRUFBRSx5QkFBeUIsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3pHLE9BQU8sS0FBSyxFQUFFLG1CQUFtQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDbkUsT0FBTyxLQUFLLEVBQUUsZUFBZSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDL0QsT0FBTyxLQUFLLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxrQ0FBa0MsQ0FBQztBQUVuRixPQUFPLEtBQUssRUFBRSwwQkFBMEIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBRTFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFakQsd0JBQWdCLHFCQUFxQixDQUNuQyxNQUFNLEVBQUUseUJBQXlCLEVBQ2pDLElBQUksRUFBRTtJQUNKLGtCQUFrQixFQUFFLDBCQUEwQixDQUFDO0lBQy9DLFVBQVUsRUFBRSxzQkFBc0IsQ0FBQztJQUNuQyxXQUFXLEVBQUUsYUFBYSxHQUFHLFdBQVcsQ0FBQztJQUN6QyxtQkFBbUIsRUFBRSxtQkFBbUIsQ0FBQztJQUN6QyxTQUFTLEVBQUUsU0FBUyxDQUFDO0lBQ3JCLFVBQVUsRUFBRSxVQUFVLENBQUM7SUFDdkIsVUFBVSxFQUFFLG1CQUFtQixDQUFDO0lBQ2hDLFlBQVksRUFBRSxZQUFZLENBQUM7SUFDM0IsU0FBUyxFQUFFLGVBQWUsQ0FBQztDQUM1QixtQkFxQkY7QUFFRCx3QkFBZ0IscUJBQXFCLENBQ25DLE1BQU0sRUFBRSx5QkFBeUIsRUFDakMsSUFBSSxFQUFFO0lBQ0osa0JBQWtCLEVBQUUsMEJBQTBCLENBQUM7SUFDL0MsVUFBVSxFQUFFLHNCQUFzQixDQUFDO0lBQ25DLFNBQVMsRUFBRSxTQUFTLENBQUM7SUFDckIsV0FBVyxFQUFFLGFBQWEsR0FBRyxXQUFXLENBQUM7SUFDekMsbUJBQW1CLEVBQUUsbUJBQW1CLENBQUM7SUFDekMsU0FBUyxFQUFFLGVBQWUsQ0FBQztJQUMzQixZQUFZLEVBQUUsWUFBWSxDQUFDO0lBQzNCLFVBQVUsRUFBRSxVQUFVLENBQUM7SUFDdkIsZUFBZSxFQUFFLGVBQWUsR0FBRyxTQUFTLENBQUM7SUFDN0MsVUFBVSxFQUFFLG1CQUFtQixDQUFDO0lBQ2hDLG9CQUFvQixDQUFDLEVBQUUsMEJBQTBCLENBQUM7Q0FDbkQsd0NBc0JGIn0=
|
package/dest/factory.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAEnF,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,KAAK,EAAE,yBAAyB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAEnF,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,yBAAyB,EACjC,IAAI,EAAE;IACJ,kBAAkB,EAAE,0BAA0B,CAAC;IAC/C,UAAU,EAAE,sBAAsB,CAAC;IACnC,WAAW,EAAE,aAAa,GAAG,WAAW,CAAC;IACzC,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,EAAE,mBAAmB,CAAC;IAChC,YAAY,EAAE,YAAY,CAAC;IAC3B,SAAS,EAAE,eAAe,CAAC;CAC5B,mBAqBF;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,yBAAyB,EACjC,IAAI,EAAE;IACJ,kBAAkB,EAAE,0BAA0B,CAAC;IAC/C,UAAU,EAAE,sBAAsB,CAAC;IACnC,SAAS,EAAE,SAAS,CAAC;IACrB,WAAW,EAAE,aAAa,GAAG,WAAW,CAAC;IACzC,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,SAAS,EAAE,eAAe,CAAC;IAC3B,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,eAAe,EAAE,eAAe,GAAG,SAAS,CAAC;IAC7C,UAAU,EAAE,mBAAmB,CAAC;IAChC,oBAAoB,CAAC,EAAE,0BAA0B,CAAC;CACnD,wCAsBF"}
|
package/dest/factory.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { BlockProposalValidator } from '@aztec/p2p';
|
|
2
|
-
import { BlockProposalHandler } from './block_proposal_handler.js';
|
|
3
2
|
import { ValidatorMetrics } from './metrics.js';
|
|
3
|
+
import { ProposalHandler } from './proposal_handler.js';
|
|
4
4
|
import { ValidatorClient } from './validator.js';
|
|
5
|
-
export function
|
|
5
|
+
export function createProposalHandler(config, deps) {
|
|
6
6
|
const metrics = new ValidatorMetrics(deps.telemetry);
|
|
7
7
|
const blockProposalValidator = new BlockProposalValidator(deps.epochCache, {
|
|
8
8
|
txsPermitted: !config.disableTransactions,
|
|
9
9
|
maxTxsPerBlock: config.validateMaxTxsPerBlock ?? config.validateMaxTxsPerCheckpoint
|
|
10
10
|
});
|
|
11
|
-
return new
|
|
11
|
+
return new ProposalHandler(deps.checkpointsBuilder, deps.worldState, deps.blockSource, deps.l1ToL2MessageSource, deps.p2pClient.getTxProvider(), blockProposalValidator, deps.epochCache, config, deps.blobClient, metrics, deps.dateProvider, deps.telemetry);
|
|
12
12
|
}
|
|
13
13
|
export function createValidatorClient(config, deps) {
|
|
14
14
|
if (config.disableValidator || !deps.keyStoreManager) {
|
package/dest/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './proposal_handler.js';
|
|
2
2
|
export * from './checkpoint_builder.js';
|
|
3
3
|
export * from './config.js';
|
|
4
4
|
export * from './factory.js';
|
|
5
5
|
export * from './validator.js';
|
|
6
6
|
export * from './key_store/index.js';
|
|
7
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
7
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLHVCQUF1QixDQUFDO0FBQ3RDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyxhQUFhLENBQUM7QUFDNUIsY0FBYyxjQUFjLENBQUM7QUFDN0IsY0FBYyxnQkFBZ0IsQ0FBQztBQUMvQixjQUFjLHNCQUFzQixDQUFDIn0=
|
package/dest/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC"}
|
package/dest/index.js
CHANGED
package/dest/metrics.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { EpochNumber } from '@aztec/foundation/branded-types';
|
|
|
2
2
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
3
|
import type { BlockProposal } from '@aztec/stdlib/p2p';
|
|
4
4
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
5
|
-
import type { BlockProposalValidationFailureReason } from './
|
|
5
|
+
import type { BlockProposalValidationFailureReason } from './proposal_handler.js';
|
|
6
6
|
export declare class ValidatorMetrics {
|
|
7
7
|
private failedReexecutionCounter;
|
|
8
8
|
private successfulAttestationsCount;
|
|
@@ -24,4 +24,4 @@ export declare class ValidatorMetrics {
|
|
|
24
24
|
/** Increment the count of epochs in which the given attester submitted at least one attestation. */
|
|
25
25
|
incAttestedEpochCount(attester: EthAddress): void;
|
|
26
26
|
}
|
|
27
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0cmljcy5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL21ldHJpY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsV0FBVyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDbkUsT0FBTyxLQUFLLEVBQUUsVUFBVSxFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDaEUsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDdkQsT0FBTyxFQUtMLEtBQUssZUFBZSxFQUdyQixNQUFNLHlCQUF5QixDQUFDO0FBRWpDLE9BQU8sS0FBSyxFQUFFLG9DQUFvQyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFbEYscUJBQWEsZ0JBQWdCO0lBQzNCLE9BQU8sQ0FBQyx3QkFBd0IsQ0FBZ0I7SUFDaEQsT0FBTyxDQUFDLDJCQUEyQixDQUFnQjtJQUNuRCxPQUFPLENBQUMsa0NBQWtDLENBQWdCO0lBQzFELE9BQU8sQ0FBQyxnQ0FBZ0MsQ0FBZ0I7SUFDeEQsT0FBTyxDQUFDLFlBQVksQ0FBUTtJQUM1QixPQUFPLENBQUMsa0JBQWtCLENBQWdCO0lBRTFDLE9BQU8sQ0FBQyxRQUFRLENBQVk7SUFDNUIsT0FBTyxDQUFDLE1BQU0sQ0FBWTtJQUMxQixPQUFPLENBQUMsWUFBWSxDQUFRO0lBRTVCLFlBQVksZUFBZSxFQUFFLGVBQWUsRUFvRDNDO0lBRU0sVUFBVSxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxRQUk5RDtJQUVNLHVCQUF1QixDQUFDLFFBQVEsRUFBRSxhQUFhLFFBTXJEO0lBRU0seUJBQXlCLENBQUMsR0FBRyxFQUFFLE1BQU0sUUFFM0M7SUFFTSxnQ0FBZ0MsQ0FDckMsR0FBRyxFQUFFLE1BQU0sRUFDWCxNQUFNLEVBQUUsb0NBQW9DLEVBQzVDLFdBQVcsRUFBRSxPQUFPLFFBTXJCO0lBRU0sOEJBQThCLENBQ25DLEdBQUcsRUFBRSxNQUFNLEVBQ1gsTUFBTSxFQUFFLG9DQUFvQyxFQUM1QyxXQUFXLEVBQUUsT0FBTyxRQU1yQjtJQUVELDJGQUEyRjtJQUNwRixlQUFlLENBQUMsS0FBSyxFQUFFLFdBQVcsUUFFeEM7SUFFRCxvR0FBb0c7SUFDN0YscUJBQXFCLENBQUMsUUFBUSxFQUFFLFVBQVUsUUFFaEQ7Q0FDRiJ9
|
package/dest/metrics.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAKL,KAAK,eAAe,EAGrB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAKL,KAAK,eAAe,EAGrB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,oCAAoC,EAAE,MAAM,uBAAuB,CAAC;AAElF,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,wBAAwB,CAAgB;IAChD,OAAO,CAAC,2BAA2B,CAAgB;IACnD,OAAO,CAAC,kCAAkC,CAAgB;IAC1D,OAAO,CAAC,gCAAgC,CAAgB;IACxD,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,kBAAkB,CAAgB;IAE1C,OAAO,CAAC,QAAQ,CAAY;IAC5B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,YAAY,CAAQ;IAE5B,YAAY,eAAe,EAAE,eAAe,EAoD3C;IAEM,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAI9D;IAEM,uBAAuB,CAAC,QAAQ,EAAE,aAAa,QAMrD;IAEM,yBAAyB,CAAC,GAAG,EAAE,MAAM,QAE3C;IAEM,gCAAgC,CACrC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,oCAAoC,EAC5C,WAAW,EAAE,OAAO,QAMrB;IAEM,8BAA8B,CACnC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,oCAAoC,EAC5C,WAAW,EAAE,OAAO,QAMrB;IAED,2FAA2F;IACpF,eAAe,CAAC,KAAK,EAAE,WAAW,QAExC;IAED,oGAAoG;IAC7F,qBAAqB,CAAC,QAAQ,EAAE,UAAU,QAEhD;CACF"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { BlobClientInterface } from '@aztec/blob-client/client';
|
|
2
|
+
import type { EpochCache } from '@aztec/epoch-cache';
|
|
3
|
+
import { BlockNumber, CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
|
+
import type { LogData } from '@aztec/foundation/log';
|
|
6
|
+
import { DateProvider } from '@aztec/foundation/timer';
|
|
7
|
+
import type { P2P, PeerId } from '@aztec/p2p';
|
|
8
|
+
import { BlockProposalValidator } from '@aztec/p2p/msg_validators';
|
|
9
|
+
import type { L2Block, L2BlockSink, L2BlockSource } from '@aztec/stdlib/block';
|
|
10
|
+
import type { ITxProvider, ValidatorClientFullConfig, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
11
|
+
import { type L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
12
|
+
import type { BlockProposal, CheckpointProposalCore } from '@aztec/stdlib/p2p';
|
|
13
|
+
import type { FailedTx, Tx } from '@aztec/stdlib/tx';
|
|
14
|
+
import { type TelemetryClient, type Tracer } from '@aztec/telemetry-client';
|
|
15
|
+
import type { FullNodeCheckpointsBuilder } from './checkpoint_builder.js';
|
|
16
|
+
import type { ValidatorMetrics } from './metrics.js';
|
|
17
|
+
export type BlockProposalValidationFailureReason = 'invalid_proposal' | 'parent_block_not_found' | 'block_source_not_synced' | 'parent_block_wrong_slot' | 'in_hash_mismatch' | 'global_variables_mismatch' | 'block_number_already_exists' | 'txs_not_available' | 'state_mismatch' | 'failed_txs' | 'initial_state_mismatch' | 'timeout' | 'unknown_error';
|
|
18
|
+
type ReexecuteTransactionsResult = {
|
|
19
|
+
block: L2Block;
|
|
20
|
+
failedTxs: FailedTx[];
|
|
21
|
+
reexecutionTimeMs: number;
|
|
22
|
+
totalManaUsed: number;
|
|
23
|
+
};
|
|
24
|
+
export type BlockProposalValidationSuccessResult = {
|
|
25
|
+
isValid: true;
|
|
26
|
+
blockNumber: BlockNumber;
|
|
27
|
+
reexecutionResult?: ReexecuteTransactionsResult;
|
|
28
|
+
};
|
|
29
|
+
export type BlockProposalValidationFailureResult = {
|
|
30
|
+
isValid: false;
|
|
31
|
+
reason: BlockProposalValidationFailureReason;
|
|
32
|
+
blockNumber?: BlockNumber;
|
|
33
|
+
reexecutionResult?: ReexecuteTransactionsResult;
|
|
34
|
+
};
|
|
35
|
+
export type BlockProposalValidationResult = BlockProposalValidationSuccessResult | BlockProposalValidationFailureResult;
|
|
36
|
+
export type CheckpointProposalValidationResult = {
|
|
37
|
+
isValid: true;
|
|
38
|
+
} | {
|
|
39
|
+
isValid: false;
|
|
40
|
+
reason: string;
|
|
41
|
+
};
|
|
42
|
+
/** Handles block and checkpoint proposals for both validator and non-validator nodes. */
|
|
43
|
+
export declare class ProposalHandler {
|
|
44
|
+
private checkpointsBuilder;
|
|
45
|
+
private worldState;
|
|
46
|
+
private blockSource;
|
|
47
|
+
private l1ToL2MessageSource;
|
|
48
|
+
private txProvider;
|
|
49
|
+
private blockProposalValidator;
|
|
50
|
+
private epochCache;
|
|
51
|
+
private config;
|
|
52
|
+
private blobClient;
|
|
53
|
+
private metrics?;
|
|
54
|
+
private dateProvider;
|
|
55
|
+
private log;
|
|
56
|
+
readonly tracer: Tracer;
|
|
57
|
+
constructor(checkpointsBuilder: FullNodeCheckpointsBuilder, worldState: WorldStateSynchronizer, blockSource: L2BlockSource & L2BlockSink, l1ToL2MessageSource: L1ToL2MessageSource, txProvider: ITxProvider, blockProposalValidator: BlockProposalValidator, epochCache: EpochCache, config: ValidatorClientFullConfig, blobClient: BlobClientInterface, metrics?: ValidatorMetrics | undefined, dateProvider?: DateProvider, telemetry?: TelemetryClient, log?: import("@aztec/foundation/log").Logger);
|
|
58
|
+
/**
|
|
59
|
+
* Registers non-validator handlers for block and checkpoint proposals on the p2p client.
|
|
60
|
+
* Block proposals are always registered. Checkpoint proposals are registered if the blob client can upload.
|
|
61
|
+
*/
|
|
62
|
+
register(p2pClient: P2P, shouldReexecute: boolean): ProposalHandler;
|
|
63
|
+
handleBlockProposal(proposal: BlockProposal, proposalSender: PeerId, shouldReexecute: boolean): Promise<BlockProposalValidationResult>;
|
|
64
|
+
private getParentBlock;
|
|
65
|
+
private computeCheckpointNumber;
|
|
66
|
+
/**
|
|
67
|
+
* Validates that a non-first block in a checkpoint has consistent global variables with its parent.
|
|
68
|
+
* For blocks with indexWithinCheckpoint > 0, all global variables except blockNumber must match the parent.
|
|
69
|
+
* @returns A failure result if validation fails, undefined if validation passes
|
|
70
|
+
*/
|
|
71
|
+
private validateNonFirstBlockInCheckpoint;
|
|
72
|
+
private getReexecutionDeadline;
|
|
73
|
+
private waitForBlockSourceSync;
|
|
74
|
+
private getReexecuteFailureReason;
|
|
75
|
+
reexecuteTransactions(proposal: BlockProposal, blockNumber: BlockNumber, checkpointNumber: CheckpointNumber, txs: Tx[], l1ToL2Messages: Fr[], previousCheckpointOutHashes: Fr[]): Promise<ReexecuteTransactionsResult>;
|
|
76
|
+
/**
|
|
77
|
+
* Validates a checkpoint proposal and uploads blobs if configured.
|
|
78
|
+
* Used by both non-validator nodes (via register) and the validator client (via delegation).
|
|
79
|
+
*/
|
|
80
|
+
handleCheckpointProposal(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<CheckpointProposalValidationResult>;
|
|
81
|
+
/**
|
|
82
|
+
* Validates a checkpoint proposal by building the full checkpoint and comparing it with the proposal.
|
|
83
|
+
* @returns Validation result with isValid flag and reason if invalid.
|
|
84
|
+
*/
|
|
85
|
+
validateCheckpointProposal(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<CheckpointProposalValidationResult>;
|
|
86
|
+
/** Extracts checkpoint global variables from a block. */
|
|
87
|
+
private extractCheckpointConstants;
|
|
88
|
+
/** Triggers blob upload for a checkpoint if the blob client can upload (fire and forget). */
|
|
89
|
+
protected tryUploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): void;
|
|
90
|
+
/** Uploads blobs for a checkpoint to the filestore. */
|
|
91
|
+
protected uploadBlobsForCheckpoint(proposal: CheckpointProposalCore, proposalInfo: LogData): Promise<void>;
|
|
92
|
+
}
|
|
93
|
+
export {};
|
|
94
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvcG9zYWxfaGFuZGxlci5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL3Byb3Bvc2FsX2hhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUdyRSxPQUFPLEtBQUssRUFBRSxVQUFVLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxPQUFPLEVBQUUsV0FBVyxFQUFFLGdCQUFnQixFQUFjLE1BQU0saUNBQWlDLENBQUM7QUFFNUYsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBRXBELE9BQU8sS0FBSyxFQUFFLE9BQU8sRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBR3JELE9BQU8sRUFBRSxZQUFZLEVBQVMsTUFBTSx5QkFBeUIsQ0FBQztBQUM5RCxPQUFPLEtBQUssRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQzlDLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ25FLE9BQU8sS0FBSyxFQUFhLE9BQU8sRUFBRSxXQUFXLEVBQUUsYUFBYSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFJMUYsT0FBTyxLQUFLLEVBQUUsV0FBVyxFQUFFLHlCQUF5QixFQUFFLHNCQUFzQixFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDdEgsT0FBTyxFQUNMLEtBQUssbUJBQW1CLEVBR3pCLE1BQU0seUJBQXlCLENBQUM7QUFDakMsT0FBTyxLQUFLLEVBQUUsYUFBYSxFQUFFLHNCQUFzQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFL0UsT0FBTyxLQUFLLEVBQTZCLFFBQVEsRUFBRSxFQUFFLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQVFoRixPQUFPLEVBQUUsS0FBSyxlQUFlLEVBQUUsS0FBSyxNQUFNLEVBQXNCLE1BQU0seUJBQXlCLENBQUM7QUFFaEcsT0FBTyxLQUFL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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposal_handler.d.ts","sourceRoot":"","sources":["../src/proposal_handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -63,7 +63,9 @@ function _ts_dispose_resources(env) {
|
|
|
63
63
|
return next();
|
|
64
64
|
})(env);
|
|
65
65
|
}
|
|
66
|
+
import { encodeCheckpointBlobDataFromBlocks, getBlobsPerL1Block } from '@aztec/blob-lib';
|
|
66
67
|
import { INITIAL_L2_BLOCK_NUM } from '@aztec/constants';
|
|
68
|
+
import { validateFeeAssetPriceModifier } from '@aztec/ethereum/contracts';
|
|
67
69
|
import { BlockNumber, CheckpointNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
68
70
|
import { pick } from '@aztec/foundation/collection';
|
|
69
71
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
@@ -71,13 +73,14 @@ import { TimeoutError } from '@aztec/foundation/error';
|
|
|
71
73
|
import { createLogger } from '@aztec/foundation/log';
|
|
72
74
|
import { retryUntil } from '@aztec/foundation/retry';
|
|
73
75
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
76
|
+
import { validateCheckpoint } from '@aztec/stdlib/checkpoint';
|
|
74
77
|
import { getEpochAtSlot, getTimestampForSlot } from '@aztec/stdlib/epoch-helpers';
|
|
75
78
|
import { Gas } from '@aztec/stdlib/gas';
|
|
76
|
-
import { computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
79
|
+
import { accumulateCheckpointOutHashes, computeInHashFromL1ToL2Messages } from '@aztec/stdlib/messaging';
|
|
77
80
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
78
81
|
import { ReExFailedTxsError, ReExInitialStateMismatchError, ReExStateMismatchError, ReExTimeoutError, TransactionsNotAvailableError } from '@aztec/stdlib/validators';
|
|
79
82
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
80
|
-
export class
|
|
83
|
+
/** Handles block and checkpoint proposals for both validator and non-validator nodes. */ export class ProposalHandler {
|
|
81
84
|
checkpointsBuilder;
|
|
82
85
|
worldState;
|
|
83
86
|
blockSource;
|
|
@@ -86,11 +89,12 @@ export class BlockProposalHandler {
|
|
|
86
89
|
blockProposalValidator;
|
|
87
90
|
epochCache;
|
|
88
91
|
config;
|
|
92
|
+
blobClient;
|
|
89
93
|
metrics;
|
|
90
94
|
dateProvider;
|
|
91
95
|
log;
|
|
92
96
|
tracer;
|
|
93
|
-
constructor(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, metrics, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator:
|
|
97
|
+
constructor(checkpointsBuilder, worldState, blockSource, l1ToL2MessageSource, txProvider, blockProposalValidator, epochCache, config, blobClient, metrics, dateProvider = new DateProvider(), telemetry = getTelemetryClient(), log = createLogger('validator:proposal-handler')){
|
|
94
98
|
this.checkpointsBuilder = checkpointsBuilder;
|
|
95
99
|
this.worldState = worldState;
|
|
96
100
|
this.blockSource = blockSource;
|
|
@@ -99,18 +103,22 @@ export class BlockProposalHandler {
|
|
|
99
103
|
this.blockProposalValidator = blockProposalValidator;
|
|
100
104
|
this.epochCache = epochCache;
|
|
101
105
|
this.config = config;
|
|
106
|
+
this.blobClient = blobClient;
|
|
102
107
|
this.metrics = metrics;
|
|
103
108
|
this.dateProvider = dateProvider;
|
|
104
109
|
this.log = log;
|
|
105
110
|
if (config.fishermanMode) {
|
|
106
111
|
this.log = this.log.createChild('[FISHERMAN]');
|
|
107
112
|
}
|
|
108
|
-
this.tracer = telemetry.getTracer('
|
|
113
|
+
this.tracer = telemetry.getTracer('ProposalHandler');
|
|
109
114
|
}
|
|
110
|
-
|
|
115
|
+
/**
|
|
116
|
+
* Registers non-validator handlers for block and checkpoint proposals on the p2p client.
|
|
117
|
+
* Block proposals are always registered. Checkpoint proposals are registered if the blob client can upload.
|
|
118
|
+
*/ register(p2pClient, shouldReexecute) {
|
|
111
119
|
// Non-validator handler that processes or re-executes for monitoring but does not attest.
|
|
112
120
|
// Returns boolean indicating whether the proposal was valid.
|
|
113
|
-
const
|
|
121
|
+
const blockHandler = async (proposal, proposalSender)=>{
|
|
114
122
|
try {
|
|
115
123
|
const { slotNumber, blockNumber } = proposal;
|
|
116
124
|
const result = await this.handleBlockProposal(proposal, proposalSender, shouldReexecute);
|
|
@@ -137,7 +145,30 @@ export class BlockProposalHandler {
|
|
|
137
145
|
return false;
|
|
138
146
|
}
|
|
139
147
|
};
|
|
140
|
-
p2pClient.registerBlockProposalHandler(
|
|
148
|
+
p2pClient.registerBlockProposalHandler(blockHandler);
|
|
149
|
+
// Register checkpoint proposal handler if blob uploads are enabled and we are reexecuting
|
|
150
|
+
if (this.blobClient.canUpload() && shouldReexecute) {
|
|
151
|
+
const checkpointHandler = async (checkpoint, _sender)=>{
|
|
152
|
+
try {
|
|
153
|
+
const proposalInfo = {
|
|
154
|
+
proposalSlotNumber: checkpoint.slotNumber,
|
|
155
|
+
archive: checkpoint.archive.toString(),
|
|
156
|
+
proposer: checkpoint.getSender()?.toString()
|
|
157
|
+
};
|
|
158
|
+
const result = await this.handleCheckpointProposal(checkpoint, proposalInfo);
|
|
159
|
+
if (result.isValid) {
|
|
160
|
+
this.log.info(`Non-validator checkpoint proposal at slot ${checkpoint.slotNumber} handled`, proposalInfo);
|
|
161
|
+
} else {
|
|
162
|
+
this.log.warn(`Non-validator checkpoint proposal at slot ${checkpoint.slotNumber} failed: ${result.reason}`, proposalInfo);
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
this.log.error('Error processing checkpoint proposal in non-validator handler', error);
|
|
166
|
+
}
|
|
167
|
+
// Non-validators don't attest
|
|
168
|
+
return undefined;
|
|
169
|
+
};
|
|
170
|
+
p2pClient.registerCheckpointProposalHandler(checkpointHandler);
|
|
171
|
+
}
|
|
141
172
|
return this;
|
|
142
173
|
}
|
|
143
174
|
async handleBlockProposal(proposal, proposalSender, shouldReexecute) {
|
|
@@ -611,4 +642,215 @@ export class BlockProposalHandler {
|
|
|
611
642
|
if (result) await result;
|
|
612
643
|
}
|
|
613
644
|
}
|
|
645
|
+
/**
|
|
646
|
+
* Validates a checkpoint proposal and uploads blobs if configured.
|
|
647
|
+
* Used by both non-validator nodes (via register) and the validator client (via delegation).
|
|
648
|
+
*/ async handleCheckpointProposal(proposal, proposalInfo) {
|
|
649
|
+
const proposer = proposal.getSender();
|
|
650
|
+
if (!proposer) {
|
|
651
|
+
this.log.warn(`Received checkpoint proposal with invalid signature for slot ${proposal.slotNumber}`);
|
|
652
|
+
return {
|
|
653
|
+
isValid: false,
|
|
654
|
+
reason: 'invalid_signature'
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
if (!validateFeeAssetPriceModifier(proposal.feeAssetPriceModifier)) {
|
|
658
|
+
this.log.warn(`Received checkpoint proposal with invalid feeAssetPriceModifier ${proposal.feeAssetPriceModifier} for slot ${proposal.slotNumber}`);
|
|
659
|
+
return {
|
|
660
|
+
isValid: false,
|
|
661
|
+
reason: 'invalid_fee_asset_price_modifier'
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
const result = await this.validateCheckpointProposal(proposal, proposalInfo);
|
|
665
|
+
// Upload blobs to filestore if validation passed (fire and forget)
|
|
666
|
+
if (result.isValid) {
|
|
667
|
+
this.tryUploadBlobsForCheckpoint(proposal, proposalInfo);
|
|
668
|
+
}
|
|
669
|
+
return result;
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* Validates a checkpoint proposal by building the full checkpoint and comparing it with the proposal.
|
|
673
|
+
* @returns Validation result with isValid flag and reason if invalid.
|
|
674
|
+
*/ async validateCheckpointProposal(proposal, proposalInfo) {
|
|
675
|
+
const slot = proposal.slotNumber;
|
|
676
|
+
// Timeout block syncing at the start of the next slot
|
|
677
|
+
const config = this.checkpointsBuilder.getConfig();
|
|
678
|
+
const nextSlotTimestampSeconds = Number(getTimestampForSlot(SlotNumber(slot + 1), config));
|
|
679
|
+
const timeoutSeconds = Math.max(1, nextSlotTimestampSeconds - Math.floor(this.dateProvider.now() / 1000));
|
|
680
|
+
// Wait for last block to sync by archive
|
|
681
|
+
let lastBlockHeader;
|
|
682
|
+
try {
|
|
683
|
+
lastBlockHeader = await retryUntil(async ()=>{
|
|
684
|
+
await this.blockSource.syncImmediate();
|
|
685
|
+
return this.blockSource.getBlockHeaderByArchive(proposal.archive);
|
|
686
|
+
}, `waiting for block with archive ${proposal.archive.toString()} for slot ${slot}`, timeoutSeconds, 0.5);
|
|
687
|
+
} catch (err) {
|
|
688
|
+
if (err instanceof TimeoutError) {
|
|
689
|
+
this.log.warn(`Timed out waiting for block with archive matching checkpoint proposal`, proposalInfo);
|
|
690
|
+
return {
|
|
691
|
+
isValid: false,
|
|
692
|
+
reason: 'last_block_not_found'
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
this.log.error(`Error fetching last block for checkpoint proposal`, err, proposalInfo);
|
|
696
|
+
return {
|
|
697
|
+
isValid: false,
|
|
698
|
+
reason: 'block_fetch_error'
|
|
699
|
+
};
|
|
700
|
+
}
|
|
701
|
+
if (!lastBlockHeader) {
|
|
702
|
+
this.log.warn(`Last block not found for checkpoint proposal`, proposalInfo);
|
|
703
|
+
return {
|
|
704
|
+
isValid: false,
|
|
705
|
+
reason: 'last_block_not_found'
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
// Get all full blocks for the slot and checkpoint
|
|
709
|
+
const blocks = await this.blockSource.getBlocksForSlot(slot);
|
|
710
|
+
if (blocks.length === 0) {
|
|
711
|
+
this.log.warn(`No blocks found for slot ${slot}`, proposalInfo);
|
|
712
|
+
return {
|
|
713
|
+
isValid: false,
|
|
714
|
+
reason: 'no_blocks_for_slot'
|
|
715
|
+
};
|
|
716
|
+
}
|
|
717
|
+
// Ensure the last block for this slot matches the archive in the checkpoint proposal
|
|
718
|
+
if (!blocks.at(-1)?.archive.root.equals(proposal.archive)) {
|
|
719
|
+
this.log.warn(`Last block archive mismatch for checkpoint proposal`, proposalInfo);
|
|
720
|
+
return {
|
|
721
|
+
isValid: false,
|
|
722
|
+
reason: 'last_block_archive_mismatch'
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
this.log.debug(`Found ${blocks.length} blocks for slot ${slot}`, {
|
|
726
|
+
...proposalInfo,
|
|
727
|
+
blockNumbers: blocks.map((b)=>b.number)
|
|
728
|
+
});
|
|
729
|
+
// Get checkpoint constants from first block
|
|
730
|
+
const firstBlock = blocks[0];
|
|
731
|
+
const constants = this.extractCheckpointConstants(firstBlock);
|
|
732
|
+
const checkpointNumber = firstBlock.checkpointNumber;
|
|
733
|
+
// Get L1-to-L2 messages for this checkpoint
|
|
734
|
+
const l1ToL2Messages = await this.l1ToL2MessageSource.getL1ToL2Messages(checkpointNumber);
|
|
735
|
+
// Collect the out hashes of all the checkpoints before this one in the same epoch
|
|
736
|
+
const epoch = getEpochAtSlot(slot, this.epochCache.getL1Constants());
|
|
737
|
+
const previousCheckpointOutHashes = (await this.blockSource.getCheckpointsDataForEpoch(epoch)).filter((c)=>c.checkpointNumber < checkpointNumber).map((c)=>c.checkpointOutHash);
|
|
738
|
+
// Fork world state at the block before the first block
|
|
739
|
+
const parentBlockNumber = BlockNumber(firstBlock.number - 1);
|
|
740
|
+
const fork = await this.worldState.fork(parentBlockNumber);
|
|
741
|
+
try {
|
|
742
|
+
// Create checkpoint builder with all existing blocks
|
|
743
|
+
const checkpointBuilder = await this.checkpointsBuilder.openCheckpoint(checkpointNumber, constants, proposal.feeAssetPriceModifier, l1ToL2Messages, previousCheckpointOutHashes, fork, blocks, this.log.getBindings());
|
|
744
|
+
// Complete the checkpoint to get computed values
|
|
745
|
+
const computedCheckpoint = await checkpointBuilder.completeCheckpoint();
|
|
746
|
+
// Compare checkpoint header with proposal
|
|
747
|
+
if (!computedCheckpoint.header.equals(proposal.checkpointHeader)) {
|
|
748
|
+
this.log.warn(`Checkpoint header mismatch`, {
|
|
749
|
+
...proposalInfo,
|
|
750
|
+
computed: computedCheckpoint.header.toInspect(),
|
|
751
|
+
proposal: proposal.checkpointHeader.toInspect()
|
|
752
|
+
});
|
|
753
|
+
return {
|
|
754
|
+
isValid: false,
|
|
755
|
+
reason: 'checkpoint_header_mismatch'
|
|
756
|
+
};
|
|
757
|
+
}
|
|
758
|
+
// Compare archive root with proposal
|
|
759
|
+
if (!computedCheckpoint.archive.root.equals(proposal.archive)) {
|
|
760
|
+
this.log.warn(`Archive root mismatch`, {
|
|
761
|
+
...proposalInfo,
|
|
762
|
+
computed: computedCheckpoint.archive.root.toString(),
|
|
763
|
+
proposal: proposal.archive.toString()
|
|
764
|
+
});
|
|
765
|
+
return {
|
|
766
|
+
isValid: false,
|
|
767
|
+
reason: 'archive_mismatch'
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
// Check that the accumulated epoch out hash matches the value in the proposal.
|
|
771
|
+
// The epoch out hash is the accumulated hash of all checkpoint out hashes in the epoch.
|
|
772
|
+
const checkpointOutHash = computedCheckpoint.getCheckpointOutHash();
|
|
773
|
+
const computedEpochOutHash = accumulateCheckpointOutHashes([
|
|
774
|
+
...previousCheckpointOutHashes,
|
|
775
|
+
checkpointOutHash
|
|
776
|
+
]);
|
|
777
|
+
const proposalEpochOutHash = proposal.checkpointHeader.epochOutHash;
|
|
778
|
+
if (!computedEpochOutHash.equals(proposalEpochOutHash)) {
|
|
779
|
+
this.log.warn(`Epoch out hash mismatch`, {
|
|
780
|
+
proposalEpochOutHash: proposalEpochOutHash.toString(),
|
|
781
|
+
computedEpochOutHash: computedEpochOutHash.toString(),
|
|
782
|
+
checkpointOutHash: checkpointOutHash.toString(),
|
|
783
|
+
previousCheckpointOutHashes: previousCheckpointOutHashes.map((h)=>h.toString()),
|
|
784
|
+
...proposalInfo
|
|
785
|
+
});
|
|
786
|
+
return {
|
|
787
|
+
isValid: false,
|
|
788
|
+
reason: 'out_hash_mismatch'
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
// Final round of validations on the checkpoint, just in case.
|
|
792
|
+
try {
|
|
793
|
+
validateCheckpoint(computedCheckpoint, {
|
|
794
|
+
rollupManaLimit: this.checkpointsBuilder.getConfig().rollupManaLimit,
|
|
795
|
+
maxDABlockGas: this.config.validateMaxDABlockGas,
|
|
796
|
+
maxL2BlockGas: this.config.validateMaxL2BlockGas,
|
|
797
|
+
maxTxsPerBlock: this.config.validateMaxTxsPerBlock,
|
|
798
|
+
maxTxsPerCheckpoint: this.config.validateMaxTxsPerCheckpoint
|
|
799
|
+
});
|
|
800
|
+
} catch (err) {
|
|
801
|
+
this.log.warn(`Checkpoint validation failed: ${err}`, proposalInfo);
|
|
802
|
+
return {
|
|
803
|
+
isValid: false,
|
|
804
|
+
reason: 'checkpoint_validation_failed'
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
this.log.verbose(`Checkpoint proposal validation successful for slot ${slot}`, proposalInfo);
|
|
808
|
+
return {
|
|
809
|
+
isValid: true
|
|
810
|
+
};
|
|
811
|
+
} finally{
|
|
812
|
+
await fork.close();
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
/** Extracts checkpoint global variables from a block. */ extractCheckpointConstants(block) {
|
|
816
|
+
const gv = block.header.globalVariables;
|
|
817
|
+
return {
|
|
818
|
+
chainId: gv.chainId,
|
|
819
|
+
version: gv.version,
|
|
820
|
+
slotNumber: gv.slotNumber,
|
|
821
|
+
timestamp: gv.timestamp,
|
|
822
|
+
coinbase: gv.coinbase,
|
|
823
|
+
feeRecipient: gv.feeRecipient,
|
|
824
|
+
gasFees: gv.gasFees
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
/** Triggers blob upload for a checkpoint if the blob client can upload (fire and forget). */ tryUploadBlobsForCheckpoint(proposal, proposalInfo) {
|
|
828
|
+
if (this.blobClient.canUpload()) {
|
|
829
|
+
void this.uploadBlobsForCheckpoint(proposal, proposalInfo);
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
/** Uploads blobs for a checkpoint to the filestore. */ async uploadBlobsForCheckpoint(proposal, proposalInfo) {
|
|
833
|
+
try {
|
|
834
|
+
const lastBlockHeader = await this.blockSource.getBlockHeaderByArchive(proposal.archive);
|
|
835
|
+
if (!lastBlockHeader) {
|
|
836
|
+
this.log.warn(`Failed to get last block header for blob upload`, proposalInfo);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
const blocks = await this.blockSource.getBlocksForSlot(proposal.slotNumber);
|
|
840
|
+
if (blocks.length === 0) {
|
|
841
|
+
this.log.warn(`No blocks found for blob upload`, proposalInfo);
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
const blockBlobData = blocks.map((b)=>b.toBlockBlobData());
|
|
845
|
+
const blobFields = encodeCheckpointBlobDataFromBlocks(blockBlobData);
|
|
846
|
+
const blobs = await getBlobsPerL1Block(blobFields);
|
|
847
|
+
await this.blobClient.sendBlobsToFilestore(blobs);
|
|
848
|
+
this.log.debug(`Uploaded ${blobs.length} blobs to filestore for checkpoint at slot ${proposal.slotNumber}`, {
|
|
849
|
+
...proposalInfo,
|
|
850
|
+
numBlobs: blobs.length
|
|
851
|
+
});
|
|
852
|
+
} catch (err) {
|
|
853
|
+
this.log.warn(`Failed to upload blobs for checkpoint: ${err}`, proposalInfo);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
614
856
|
}
|