@aztec/sequencer-client 0.70.0 → 0.72.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/client/sequencer-client.js +2 -2
- package/dest/config.js +2 -2
- package/dest/publisher/l1-publisher.d.ts +1 -1
- package/dest/publisher/l1-publisher.d.ts.map +1 -1
- package/dest/publisher/l1-publisher.js +95 -29
- package/dest/sequencer/allowed.js +3 -3
- package/dest/sequencer/sequencer.d.ts +19 -22
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +53 -131
- package/dest/sequencer/timetable.d.ts +38 -0
- package/dest/sequencer/timetable.d.ts.map +1 -0
- package/dest/sequencer/timetable.js +96 -0
- package/dest/slasher/factory.d.ts.map +1 -1
- package/dest/slasher/factory.js +3 -3
- package/dest/slasher/slasher_client.d.ts.map +1 -1
- package/dest/slasher/slasher_client.js +3 -4
- package/dest/test/index.d.ts +2 -3
- package/dest/test/index.d.ts.map +1 -1
- package/dest/test/index.js +1 -1
- package/dest/tx_validator/gas_validator.d.ts +1 -1
- package/dest/tx_validator/gas_validator.d.ts.map +1 -1
- package/dest/tx_validator/gas_validator.js +8 -4
- package/package.json +21 -21
- package/src/client/sequencer-client.ts +1 -1
- package/src/config.ts +1 -1
- package/src/publisher/l1-publisher.ts +106 -27
- package/src/sequencer/allowed.ts +2 -2
- package/src/sequencer/sequencer.ts +68 -173
- package/src/sequencer/timetable.ts +123 -0
- package/src/slasher/factory.ts +2 -3
- package/src/slasher/slasher_client.ts +2 -3
- package/src/test/index.ts +2 -3
- package/src/tx_validator/gas_validator.ts +15 -3
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
import { type FeeRecipient, type RootRollupPublicInputs } from '@aztec/circuits.js/rollup';
|
|
20
20
|
import {
|
|
21
21
|
type EthereumChain,
|
|
22
|
+
FormattedViemError,
|
|
22
23
|
type GasPrice,
|
|
23
24
|
type L1ContractsConfig,
|
|
24
25
|
L1TxUtils,
|
|
@@ -36,8 +37,7 @@ import { type Tuple, serializeToBuffer } from '@aztec/foundation/serialize';
|
|
|
36
37
|
import { InterruptibleSleep } from '@aztec/foundation/sleep';
|
|
37
38
|
import { Timer } from '@aztec/foundation/timer';
|
|
38
39
|
import { EmpireBaseAbi, RollupAbi, SlasherAbi } from '@aztec/l1-artifacts';
|
|
39
|
-
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
40
|
-
import { NoopTelemetryClient } from '@aztec/telemetry-client/noop';
|
|
40
|
+
import { type TelemetryClient, getTelemetryClient } from '@aztec/telemetry-client';
|
|
41
41
|
|
|
42
42
|
import pick from 'lodash.pick';
|
|
43
43
|
import {
|
|
@@ -209,7 +209,7 @@ export class L1Publisher {
|
|
|
209
209
|
this.sleepTimeMs = config?.l1PublishRetryIntervalMS ?? 60_000;
|
|
210
210
|
this.ethereumSlotDuration = BigInt(config.ethereumSlotDuration);
|
|
211
211
|
|
|
212
|
-
const telemetry = deps.telemetry ??
|
|
212
|
+
const telemetry = deps.telemetry ?? getTelemetryClient();
|
|
213
213
|
this.blobSinkClient = deps.blobSinkClient ?? createBlobSinkClient(config.blobSinkUrl);
|
|
214
214
|
|
|
215
215
|
this.metrics = new L1PublisherMetrics(telemetry, 'L1Publisher');
|
|
@@ -417,7 +417,7 @@ export class L1Publisher {
|
|
|
417
417
|
digest: Buffer.alloc(32),
|
|
418
418
|
signatures: [],
|
|
419
419
|
},
|
|
420
|
-
): Promise<
|
|
420
|
+
): Promise<bigint> {
|
|
421
421
|
const ts = BigInt((await this.publicClient.getBlock()).timestamp + this.ethereumSlotDuration);
|
|
422
422
|
|
|
423
423
|
const formattedSignatures = attestationData.signatures.map(attest => attest.toViemSignature());
|
|
@@ -442,6 +442,7 @@ export class L1Publisher {
|
|
|
442
442
|
}
|
|
443
443
|
throw error;
|
|
444
444
|
}
|
|
445
|
+
return ts;
|
|
445
446
|
}
|
|
446
447
|
|
|
447
448
|
public async getCurrentEpochCommittee(): Promise<EthAddress[]> {
|
|
@@ -546,8 +547,8 @@ export class L1Publisher {
|
|
|
546
547
|
account: this.account,
|
|
547
548
|
});
|
|
548
549
|
} catch (err) {
|
|
549
|
-
const
|
|
550
|
-
logger.error(`Failed to vote`,
|
|
550
|
+
const { message, metaMessages } = formatViemError(err);
|
|
551
|
+
logger.error(`Failed to vote`, message, { metaMessages });
|
|
551
552
|
this.myLastVotes[voteType] = cachedMyLastVote;
|
|
552
553
|
return false;
|
|
553
554
|
}
|
|
@@ -610,15 +611,15 @@ export class L1Publisher {
|
|
|
610
611
|
// This means that we can avoid the simulation issues in later checks.
|
|
611
612
|
// By simulation issue, I mean the fact that the block.timestamp is equal to the last block, not the next, which
|
|
612
613
|
// make time consistency checks break.
|
|
613
|
-
await this.validateBlockForSubmission(block.header, {
|
|
614
|
+
const ts = await this.validateBlockForSubmission(block.header, {
|
|
614
615
|
digest: digest.toBuffer(),
|
|
615
616
|
signatures: attestations ?? [],
|
|
616
617
|
});
|
|
617
618
|
|
|
618
619
|
this.log.debug(`Submitting propose transaction`);
|
|
619
620
|
const result = proofQuote
|
|
620
|
-
? await this.sendProposeAndClaimTx(proposeTxArgs, proofQuote, opts)
|
|
621
|
-
: await this.sendProposeTx(proposeTxArgs, opts);
|
|
621
|
+
? await this.sendProposeAndClaimTx(proposeTxArgs, proofQuote, opts, ts)
|
|
622
|
+
: await this.sendProposeTx(proposeTxArgs, opts, ts);
|
|
622
623
|
|
|
623
624
|
if (!result?.receipt) {
|
|
624
625
|
this.log.info(`Failed to publish block ${block.number} to L1`, ctx);
|
|
@@ -690,9 +691,17 @@ export class L1Publisher {
|
|
|
690
691
|
}),
|
|
691
692
|
});
|
|
692
693
|
} catch (err) {
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
694
|
+
if (err instanceof FormattedViemError) {
|
|
695
|
+
const { message, metaMessages } = err;
|
|
696
|
+
this.log.error(`Failed to claim epoch proof right`, message, {
|
|
697
|
+
metaMessages,
|
|
698
|
+
proofQuote: proofQuote.toInspect(),
|
|
699
|
+
});
|
|
700
|
+
} else {
|
|
701
|
+
this.log.error(`Failed to claim epoch proof right`, err, {
|
|
702
|
+
proofQuote: proofQuote.toInspect(),
|
|
703
|
+
});
|
|
704
|
+
}
|
|
696
705
|
return false;
|
|
697
706
|
}
|
|
698
707
|
|
|
@@ -962,6 +971,8 @@ export class L1Publisher {
|
|
|
962
971
|
|
|
963
972
|
private async prepareProposeTx(encodedData: L1ProcessArgs) {
|
|
964
973
|
const kzg = Blob.getViemKzgInstance();
|
|
974
|
+
const blobInput = Blob.getEthBlobEvaluationInputs(encodedData.blobs);
|
|
975
|
+
this.log.debug('Validating blob input', { blobInput });
|
|
965
976
|
const blobEvaluationGas = await this.l1TxUtils.estimateGas(
|
|
966
977
|
this.account,
|
|
967
978
|
{
|
|
@@ -969,7 +980,7 @@ export class L1Publisher {
|
|
|
969
980
|
data: encodeFunctionData({
|
|
970
981
|
abi: this.rollupContract.abi,
|
|
971
982
|
functionName: 'validateBlobs',
|
|
972
|
-
args: [
|
|
983
|
+
args: [blobInput],
|
|
973
984
|
}),
|
|
974
985
|
},
|
|
975
986
|
{},
|
|
@@ -979,12 +990,6 @@ export class L1Publisher {
|
|
|
979
990
|
},
|
|
980
991
|
);
|
|
981
992
|
|
|
982
|
-
// @note We perform this guesstimate instead of the usual `gasEstimate` since
|
|
983
|
-
// viem will use the current state to simulate against, which means that
|
|
984
|
-
// we will fail estimation in the case where we are simulating for the
|
|
985
|
-
// first ethereum block within our slot (as current time is not in the
|
|
986
|
-
// slot yet).
|
|
987
|
-
const gasGuesstimate = blobEvaluationGas + L1Publisher.PROPOSE_GAS_GUESS;
|
|
988
993
|
const attestations = encodedData.attestations
|
|
989
994
|
? encodedData.attestations.map(attest => attest.toViemSignature())
|
|
990
995
|
: [];
|
|
@@ -1004,10 +1009,10 @@ export class L1Publisher {
|
|
|
1004
1009
|
attestations,
|
|
1005
1010
|
// TODO(#9101): Extract blobs from beacon chain => calldata will only contain what's needed to verify blob and body input can be removed
|
|
1006
1011
|
`0x${encodedData.body.toString('hex')}`,
|
|
1007
|
-
|
|
1012
|
+
blobInput,
|
|
1008
1013
|
] as const;
|
|
1009
1014
|
|
|
1010
|
-
return { args,
|
|
1015
|
+
return { args, blobEvaluationGas };
|
|
1011
1016
|
}
|
|
1012
1017
|
|
|
1013
1018
|
private getSubmitEpochProofArgs(args: {
|
|
@@ -1043,26 +1048,58 @@ export class L1Publisher {
|
|
|
1043
1048
|
private async sendProposeTx(
|
|
1044
1049
|
encodedData: L1ProcessArgs,
|
|
1045
1050
|
opts: { txTimeoutAt?: Date } = {},
|
|
1051
|
+
timestamp: bigint,
|
|
1046
1052
|
): Promise<L1ProcessReturnType | undefined> {
|
|
1047
1053
|
if (this.interrupted) {
|
|
1048
1054
|
return undefined;
|
|
1049
1055
|
}
|
|
1050
1056
|
try {
|
|
1051
1057
|
const kzg = Blob.getViemKzgInstance();
|
|
1052
|
-
const { args,
|
|
1058
|
+
const { args, blobEvaluationGas } = await this.prepareProposeTx(encodedData);
|
|
1053
1059
|
const data = encodeFunctionData({
|
|
1054
1060
|
abi: this.rollupContract.abi,
|
|
1055
1061
|
functionName: 'propose',
|
|
1056
1062
|
args,
|
|
1057
1063
|
});
|
|
1064
|
+
|
|
1065
|
+
const simulationResult = await this.l1TxUtils.simulateGasUsed(
|
|
1066
|
+
{
|
|
1067
|
+
to: this.rollupContract.address,
|
|
1068
|
+
data,
|
|
1069
|
+
gas: L1Publisher.PROPOSE_GAS_GUESS,
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
// @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
|
|
1073
|
+
time: timestamp + 1n,
|
|
1074
|
+
// @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit
|
|
1075
|
+
gasLimit: L1Publisher.PROPOSE_GAS_GUESS * 2n,
|
|
1076
|
+
},
|
|
1077
|
+
[
|
|
1078
|
+
{
|
|
1079
|
+
address: this.rollupContract.address,
|
|
1080
|
+
// @note we override checkBlob to false since blobs are not part simulate()
|
|
1081
|
+
stateDiff: [
|
|
1082
|
+
{
|
|
1083
|
+
slot: toHex(9n, true),
|
|
1084
|
+
value: toHex(0n, true),
|
|
1085
|
+
},
|
|
1086
|
+
],
|
|
1087
|
+
},
|
|
1088
|
+
],
|
|
1089
|
+
{
|
|
1090
|
+
// @note fallback gas estimate to use if the node doesn't support simulation API
|
|
1091
|
+
fallbackGasEstimate: L1Publisher.PROPOSE_GAS_GUESS,
|
|
1092
|
+
},
|
|
1093
|
+
);
|
|
1094
|
+
|
|
1058
1095
|
const result = await this.l1TxUtils.sendAndMonitorTransaction(
|
|
1059
1096
|
{
|
|
1060
1097
|
to: this.rollupContract.address,
|
|
1061
1098
|
data,
|
|
1062
1099
|
},
|
|
1063
1100
|
{
|
|
1064
|
-
fixedGas: gas,
|
|
1065
1101
|
...opts,
|
|
1102
|
+
gasLimit: this.l1TxUtils.bumpGasLimit(simulationResult + blobEvaluationGas),
|
|
1066
1103
|
},
|
|
1067
1104
|
{
|
|
1068
1105
|
blobs: encodedData.blobs.map(b => b.dataWithZeros),
|
|
@@ -1077,7 +1114,12 @@ export class L1Publisher {
|
|
|
1077
1114
|
data,
|
|
1078
1115
|
};
|
|
1079
1116
|
} catch (err) {
|
|
1080
|
-
|
|
1117
|
+
if (err instanceof FormattedViemError) {
|
|
1118
|
+
const { message, metaMessages } = err;
|
|
1119
|
+
this.log.error(`Rollup publish failed.`, message, { metaMessages });
|
|
1120
|
+
} else {
|
|
1121
|
+
this.log.error(`Rollup publish failed.`, err);
|
|
1122
|
+
}
|
|
1081
1123
|
return undefined;
|
|
1082
1124
|
}
|
|
1083
1125
|
}
|
|
@@ -1086,26 +1128,58 @@ export class L1Publisher {
|
|
|
1086
1128
|
encodedData: L1ProcessArgs,
|
|
1087
1129
|
quote: EpochProofQuote,
|
|
1088
1130
|
opts: { txTimeoutAt?: Date } = {},
|
|
1131
|
+
timestamp: bigint,
|
|
1089
1132
|
): Promise<L1ProcessReturnType | undefined> {
|
|
1090
1133
|
if (this.interrupted) {
|
|
1091
1134
|
return undefined;
|
|
1092
1135
|
}
|
|
1136
|
+
|
|
1093
1137
|
try {
|
|
1094
1138
|
const kzg = Blob.getViemKzgInstance();
|
|
1095
|
-
const { args,
|
|
1139
|
+
const { args, blobEvaluationGas } = await this.prepareProposeTx(encodedData);
|
|
1096
1140
|
const data = encodeFunctionData({
|
|
1097
1141
|
abi: this.rollupContract.abi,
|
|
1098
1142
|
functionName: 'proposeAndClaim',
|
|
1099
1143
|
args: [...args, quote.toViemArgs()],
|
|
1100
1144
|
});
|
|
1145
|
+
|
|
1146
|
+
const simulationResult = await this.l1TxUtils.simulateGasUsed(
|
|
1147
|
+
{
|
|
1148
|
+
to: this.rollupContract.address,
|
|
1149
|
+
data,
|
|
1150
|
+
gas: L1Publisher.PROPOSE_AND_CLAIM_GAS_GUESS,
|
|
1151
|
+
},
|
|
1152
|
+
{
|
|
1153
|
+
// @note we add 1n to the timestamp because geth implementation doesn't like simulation timestamp to be equal to the current block timestamp
|
|
1154
|
+
time: timestamp + 1n,
|
|
1155
|
+
// @note reth should have a 30m gas limit per block but throws errors that this tx is beyond limit
|
|
1156
|
+
gasLimit: L1Publisher.PROPOSE_AND_CLAIM_GAS_GUESS * 2n,
|
|
1157
|
+
},
|
|
1158
|
+
[
|
|
1159
|
+
{
|
|
1160
|
+
address: this.rollupContract.address,
|
|
1161
|
+
// @note we override checkBlob to false since blobs are not part simulate()
|
|
1162
|
+
stateDiff: [
|
|
1163
|
+
{
|
|
1164
|
+
slot: toHex(9n, true),
|
|
1165
|
+
value: toHex(0n, true),
|
|
1166
|
+
},
|
|
1167
|
+
],
|
|
1168
|
+
},
|
|
1169
|
+
],
|
|
1170
|
+
{
|
|
1171
|
+
// @note fallback gas estimate to use if the node doesn't support simulation API
|
|
1172
|
+
fallbackGasEstimate: L1Publisher.PROPOSE_AND_CLAIM_GAS_GUESS,
|
|
1173
|
+
},
|
|
1174
|
+
);
|
|
1101
1175
|
const result = await this.l1TxUtils.sendAndMonitorTransaction(
|
|
1102
1176
|
{
|
|
1103
1177
|
to: this.rollupContract.address,
|
|
1104
1178
|
data,
|
|
1105
1179
|
},
|
|
1106
1180
|
{
|
|
1107
|
-
fixedGas: gas,
|
|
1108
1181
|
...opts,
|
|
1182
|
+
gasLimit: this.l1TxUtils.bumpGasLimit(simulationResult + blobEvaluationGas),
|
|
1109
1183
|
},
|
|
1110
1184
|
{
|
|
1111
1185
|
blobs: encodedData.blobs.map(b => b.dataWithZeros),
|
|
@@ -1121,7 +1195,12 @@ export class L1Publisher {
|
|
|
1121
1195
|
data,
|
|
1122
1196
|
};
|
|
1123
1197
|
} catch (err) {
|
|
1124
|
-
|
|
1198
|
+
if (err instanceof FormattedViemError) {
|
|
1199
|
+
const { message, metaMessages } = err;
|
|
1200
|
+
this.log.error(`Rollup publish failed.`, message, { metaMessages });
|
|
1201
|
+
} else {
|
|
1202
|
+
this.log.error(`Rollup publish failed.`, err);
|
|
1203
|
+
}
|
|
1125
1204
|
return undefined;
|
|
1126
1205
|
}
|
|
1127
1206
|
}
|
package/src/sequencer/allowed.ts
CHANGED
|
@@ -17,13 +17,13 @@ export function getDefaultAllowedSetupFunctions(): AllowedElement[] {
|
|
|
17
17
|
{
|
|
18
18
|
address: ProtocolContractAddress.FeeJuice,
|
|
19
19
|
// We can't restrict the selector because public functions get routed via dispatch.
|
|
20
|
-
// selector: FunctionSelector.fromSignature('_increase_public_balance((Field),Field)'),
|
|
20
|
+
// selector: FunctionSelector.fromSignature('_increase_public_balance((Field),(Field,Field))'),
|
|
21
21
|
},
|
|
22
22
|
// needed for private transfers via FPC
|
|
23
23
|
{
|
|
24
24
|
classId: getContractClassFromArtifact(TokenContractArtifact).id,
|
|
25
25
|
// We can't restrict the selector because public functions get routed via dispatch.
|
|
26
|
-
// selector: FunctionSelector.fromSignature('_increase_public_balance((Field),Field)'),
|
|
26
|
+
// selector: FunctionSelector.fromSignature('_increase_public_balance((Field),(Field,Field))'),
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
classId: getContractClassFromArtifact(FPCContract.artifact).id,
|