@aztec/sequencer-client 2.0.0-nightly.20250821 → 2.0.0-nightly.20250823
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.d.ts +2 -2
- package/dest/client/sequencer-client.d.ts.map +1 -1
- package/dest/client/sequencer-client.js +6 -3
- package/dest/publisher/sequencer-publisher.d.ts +18 -15
- package/dest/publisher/sequencer-publisher.d.ts.map +1 -1
- package/dest/publisher/sequencer-publisher.js +155 -42
- package/dest/sequencer/sequencer.d.ts +6 -5
- package/dest/sequencer/sequencer.d.ts.map +1 -1
- package/dest/sequencer/sequencer.js +11 -12
- package/package.json +26 -26
- package/src/client/sequencer-client.ts +10 -5
- package/src/publisher/sequencer-publisher.ts +197 -46
- package/src/sequencer/sequencer.ts +23 -31
|
@@ -4,7 +4,7 @@ import { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
|
4
4
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
5
5
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
6
6
|
import type { P2P } from '@aztec/p2p';
|
|
7
|
-
import type {
|
|
7
|
+
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
8
8
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
9
9
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
10
10
|
import type { IFullNodeBlockBuilder, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
@@ -37,7 +37,7 @@ export declare class SequencerClient {
|
|
|
37
37
|
validatorClient: ValidatorClient | undefined;
|
|
38
38
|
p2pClient: P2P;
|
|
39
39
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
40
|
-
slasherClient:
|
|
40
|
+
slasherClient: SlasherClientInterface | undefined;
|
|
41
41
|
blockBuilder: IFullNodeBlockBuilder;
|
|
42
42
|
l2BlockSource: L2BlockSource;
|
|
43
43
|
l1ToL2MessageSource: L1ToL2MessageSource;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer-client.d.ts","sourceRoot":"","sources":["../../src/client/sequencer-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"sequencer-client.d.ts","sourceRoot":"","sources":["../../src/client/sequencer-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAQhD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAE3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAErG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExE;;GAEG;AACH,qBAAa,eAAe;IAExB,SAAS,CAAC,SAAS,EAAE,SAAS;IAC9B,SAAS,CAAC,eAAe,CAAC,EAAE,eAAe;gBADjC,SAAS,EAAE,SAAS,EACpB,eAAe,CAAC,EAAE,eAAe,YAAA;IAG7C;;;;;;;;;;;OAWG;WACiB,GAAG,CACrB,MAAM,EAAE,qBAAqB,EAC7B,IAAI,EAAE;QACJ,eAAe,EAAE,eAAe,GAAG,SAAS,CAAC;QAC7C,SAAS,EAAE,GAAG,CAAC;QACf,sBAAsB,EAAE,sBAAsB,CAAC;QAC/C,aAAa,EAAE,sBAAsB,GAAG,SAAS,CAAC;QAClD,YAAY,EAAE,qBAAqB,CAAC;QACpC,aAAa,EAAE,aAAa,CAAC;QAC7B,mBAAmB,EAAE,mBAAmB,CAAC;QACzC,SAAS,EAAE,eAAe,CAAC;QAC3B,SAAS,CAAC,EAAE,kBAAkB,CAAC;QAC/B,cAAc,CAAC,EAAE,uBAAuB,CAAC;QACzC,YAAY,EAAE,YAAY,CAAC;QAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;QACxB,SAAS,CAAC,EAAE,kBAAkB,CAAC;KAChC;IA2GH;;;OAGG;IACI,qBAAqB,CAAC,MAAM,EAAE,eAAe;IAIpD,4BAA4B;IACf,KAAK;IAKlB;;OAEG;IACU,IAAI;IAIjB;;OAEG;IACI,MAAM;IAIN,YAAY,IAAI,SAAS;IAIhC,IAAI,QAAQ,IAAI,UAAU,CAEzB;IAED,IAAI,YAAY,IAAI,YAAY,CAE/B;IAED,IAAI,kBAAkB,IAAI,UAAU,EAAE,GAAG,SAAS,CAEjD;IAED,IAAI,aAAa,IAAI,MAAM,GAAG,SAAS,CAEtC;CACF"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { EpochCache } from '@aztec/epoch-cache';
|
|
2
|
-
import { GovernanceProposerContract, RollupContract,
|
|
2
|
+
import { GovernanceProposerContract, RollupContract, createEthereumChain, createExtendedL1Client, isAnvilTestChain } from '@aztec/ethereum';
|
|
3
3
|
import { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
4
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
5
|
import { createLogger } from '@aztec/foundation/log';
|
|
6
|
+
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
5
7
|
import { GlobalVariableBuilder } from '../global_variable_builder/index.js';
|
|
6
8
|
import { SequencerPublisher } from '../publisher/index.js';
|
|
7
9
|
import { Sequencer } from '../sequencer/index.js';
|
|
@@ -38,8 +40,7 @@ import { Sequencer } from '../sequencer/index.js';
|
|
|
38
40
|
rollupContract.getSlotDuration()
|
|
39
41
|
]);
|
|
40
42
|
const governanceProposerContract = new GovernanceProposerContract(l1Client, config.l1Contracts.governanceProposerAddress.toString());
|
|
41
|
-
const
|
|
42
|
-
const slashingProposerContract = new SlashingProposerContract(l1Client, slashingProposerAddress.toString());
|
|
43
|
+
const slashingProposerContract = await rollupContract.getSlashingProposer();
|
|
43
44
|
const epochCache = deps.epochCache ?? await EpochCache.create(config.l1Contracts.rollupAddress, {
|
|
44
45
|
l1RpcUrls: rpcUrls,
|
|
45
46
|
l1ChainId: chainId,
|
|
@@ -50,6 +51,7 @@ import { Sequencer } from '../sequencer/index.js';
|
|
|
50
51
|
}, {
|
|
51
52
|
dateProvider: deps.dateProvider
|
|
52
53
|
});
|
|
54
|
+
const slashFactoryContract = new SlashFactoryContract(l1Client, config.l1Contracts.slashFactoryAddress?.toString() ?? EthAddress.ZERO.toString());
|
|
53
55
|
const publisher = deps.publisher ?? new SequencerPublisher(config, {
|
|
54
56
|
l1TxUtils,
|
|
55
57
|
telemetry: telemetryClient,
|
|
@@ -58,6 +60,7 @@ import { Sequencer } from '../sequencer/index.js';
|
|
|
58
60
|
epochCache,
|
|
59
61
|
governanceProposerContract,
|
|
60
62
|
slashingProposerContract,
|
|
63
|
+
slashFactoryContract,
|
|
61
64
|
dateProvider: deps.dateProvider
|
|
62
65
|
});
|
|
63
66
|
const globalsBuilder = new GlobalVariableBuilder(config);
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { L2Block } from '@aztec/aztec.js';
|
|
2
2
|
import { type BlobSinkClientInterface } from '@aztec/blob-sink/client';
|
|
3
3
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
4
|
-
import { FormattedViemError, type GasPrice, type GovernanceProposerContract, type L1BlobInputs, type L1ContractsConfig, type L1GasConfig, type L1TxRequest, RollupContract, type
|
|
4
|
+
import { type EmpireSlashingProposerContract, FormattedViemError, type GasPrice, type GovernanceProposerContract, type L1BlobInputs, type L1ContractsConfig, type L1GasConfig, type L1TxRequest, RollupContract, type TallySlashingProposerContract, type TransactionStats } from '@aztec/ethereum';
|
|
5
5
|
import type { L1TxUtilsWithBlobs } from '@aztec/ethereum/l1-tx-utils-with-blobs';
|
|
6
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
7
|
import type { Fr } from '@aztec/foundation/fields';
|
|
8
8
|
import { DateProvider } from '@aztec/foundation/timer';
|
|
9
|
+
import { type ProposerSlashAction } from '@aztec/slasher';
|
|
9
10
|
import { CommitteeAttestation, type ValidateBlockResult } from '@aztec/stdlib/block';
|
|
11
|
+
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
10
12
|
import { type ProposedBlockHeader, TxHash } from '@aztec/stdlib/tx';
|
|
11
13
|
import { type TelemetryClient } from '@aztec/telemetry-client';
|
|
12
14
|
import { type TransactionReceipt, type TypedDataDefinition } from 'viem';
|
|
@@ -15,8 +17,7 @@ export declare enum SignalType {
|
|
|
15
17
|
GOVERNANCE = 0,
|
|
16
18
|
SLASHING = 1
|
|
17
19
|
}
|
|
18
|
-
|
|
19
|
-
declare const Actions: readonly ["propose", "governance-signal", "slashing-signal", "invalidate-by-invalid-attestation", "invalidate-by-insufficient-attestations"];
|
|
20
|
+
declare const Actions: readonly ["propose", "governance-signal", "empire-slashing-signal", "create-empire-payload", "execute-empire-payload", "vote-offenses", "execute-slash", "invalidate-by-invalid-attestation", "invalidate-by-insufficient-attestations"];
|
|
20
21
|
export type Action = (typeof Actions)[number];
|
|
21
22
|
export type InvalidateBlockRequest = {
|
|
22
23
|
request: L1TxRequest;
|
|
@@ -46,7 +47,7 @@ export declare class SequencerPublisher {
|
|
|
46
47
|
protected governanceLog: import("@aztec/foundation/log").Logger;
|
|
47
48
|
private governancePayload;
|
|
48
49
|
protected slashingLog: import("@aztec/foundation/log").Logger;
|
|
49
|
-
|
|
50
|
+
protected slashingProposerAddress?: EthAddress;
|
|
50
51
|
private myLastSignals;
|
|
51
52
|
protected log: import("@aztec/foundation/log").Logger;
|
|
52
53
|
protected ethereumSlotDuration: bigint;
|
|
@@ -57,20 +58,21 @@ export declare class SequencerPublisher {
|
|
|
57
58
|
l1TxUtils: L1TxUtilsWithBlobs;
|
|
58
59
|
rollupContract: RollupContract;
|
|
59
60
|
govProposerContract: GovernanceProposerContract;
|
|
60
|
-
slashingProposerContract:
|
|
61
|
+
slashingProposerContract: EmpireSlashingProposerContract | TallySlashingProposerContract;
|
|
62
|
+
slashFactoryContract: SlashFactoryContract;
|
|
61
63
|
protected requests: RequestWithExpiry[];
|
|
62
64
|
constructor(config: TxSenderConfig & PublisherConfig & Pick<L1ContractsConfig, 'ethereumSlotDuration'>, deps: {
|
|
63
65
|
telemetry?: TelemetryClient;
|
|
64
66
|
blobSinkClient?: BlobSinkClientInterface;
|
|
65
67
|
l1TxUtils: L1TxUtilsWithBlobs;
|
|
66
68
|
rollupContract: RollupContract;
|
|
67
|
-
slashingProposerContract:
|
|
69
|
+
slashingProposerContract: EmpireSlashingProposerContract | TallySlashingProposerContract;
|
|
68
70
|
governanceProposerContract: GovernanceProposerContract;
|
|
71
|
+
slashFactoryContract: SlashFactoryContract;
|
|
69
72
|
epochCache: EpochCache;
|
|
70
73
|
dateProvider: DateProvider;
|
|
71
74
|
});
|
|
72
75
|
getRollupContract(): RollupContract;
|
|
73
|
-
registerSlashPayloadGetter(callback: GetSlashPayloadCallBack): void;
|
|
74
76
|
getSenderAddress(): EthAddress;
|
|
75
77
|
getGovernancePayload(): EthAddress;
|
|
76
78
|
setGovernancePayload(payload: EthAddress): void;
|
|
@@ -95,10 +97,10 @@ export declare class SequencerPublisher {
|
|
|
95
97
|
errorMsg: string | undefined;
|
|
96
98
|
stats?: undefined;
|
|
97
99
|
};
|
|
98
|
-
expiredActions: ("propose" | "governance-signal" | "slashing-signal" | "invalidate-by-invalid-attestation" | "invalidate-by-insufficient-attestations")[];
|
|
99
|
-
sentActions: ("propose" | "governance-signal" | "slashing-signal" | "invalidate-by-invalid-attestation" | "invalidate-by-insufficient-attestations")[];
|
|
100
|
-
successfulActions: ("propose" | "governance-signal" | "slashing-signal" | "invalidate-by-invalid-attestation" | "invalidate-by-insufficient-attestations")[];
|
|
101
|
-
failedActions: ("propose" | "governance-signal" | "slashing-signal" | "invalidate-by-invalid-attestation" | "invalidate-by-insufficient-attestations")[];
|
|
100
|
+
expiredActions: ("propose" | "governance-signal" | "empire-slashing-signal" | "create-empire-payload" | "execute-empire-payload" | "vote-offenses" | "execute-slash" | "invalidate-by-invalid-attestation" | "invalidate-by-insufficient-attestations")[];
|
|
101
|
+
sentActions: ("propose" | "governance-signal" | "empire-slashing-signal" | "create-empire-payload" | "execute-empire-payload" | "vote-offenses" | "execute-slash" | "invalidate-by-invalid-attestation" | "invalidate-by-insufficient-attestations")[];
|
|
102
|
+
successfulActions: ("propose" | "governance-signal" | "empire-slashing-signal" | "create-empire-payload" | "execute-empire-payload" | "vote-offenses" | "execute-slash" | "invalidate-by-invalid-attestation" | "invalidate-by-insufficient-attestations")[];
|
|
103
|
+
failedActions: ("propose" | "governance-signal" | "empire-slashing-signal" | "create-empire-payload" | "execute-empire-payload" | "vote-offenses" | "execute-slash" | "invalidate-by-invalid-attestation" | "invalidate-by-insufficient-attestations")[];
|
|
102
104
|
} | undefined>;
|
|
103
105
|
private callbackBundledTransactions;
|
|
104
106
|
/**
|
|
@@ -144,15 +146,15 @@ export declare class SequencerPublisher {
|
|
|
144
146
|
forcePendingBlockNumber?: number;
|
|
145
147
|
}): Promise<bigint>;
|
|
146
148
|
private enqueueCastSignalHelper;
|
|
147
|
-
private getSignalConfig;
|
|
148
149
|
/**
|
|
149
|
-
* Enqueues a castSignal transaction to cast a signal for a given slot number.
|
|
150
|
+
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
150
151
|
* @param slotNumber - The slot number to cast a signal for.
|
|
151
152
|
* @param timestamp - The timestamp of the slot to cast a signal for.
|
|
152
|
-
* @param signalType - The type of signal to cast.
|
|
153
153
|
* @returns True if the signal was successfully enqueued, false otherwise.
|
|
154
154
|
*/
|
|
155
|
-
|
|
155
|
+
enqueueGovernanceCastSignal(slotNumber: bigint, timestamp: bigint, signerAddress: EthAddress, signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>): Promise<boolean>;
|
|
156
|
+
/** Enqueues all slashing actions as returned by the slasher client. */
|
|
157
|
+
enqueueSlashingActions(actions: ProposerSlashAction[], slotNumber: bigint, timestamp: bigint, signerAddress: EthAddress, signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>): Promise<boolean>;
|
|
156
158
|
/**
|
|
157
159
|
* Proposes a L2 block on L1.
|
|
158
160
|
*
|
|
@@ -166,6 +168,7 @@ export declare class SequencerPublisher {
|
|
|
166
168
|
enqueueInvalidateBlock(request: InvalidateBlockRequest | undefined, opts?: {
|
|
167
169
|
txTimeoutAt?: Date;
|
|
168
170
|
}): void;
|
|
171
|
+
private simulateAndEnqueueRequest;
|
|
169
172
|
/**
|
|
170
173
|
* Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
|
|
171
174
|
* Be warned, the call may return false even if the tx subsequently gets successfully mined.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer-publisher.d.ts","sourceRoot":"","sources":["../../src/publisher/sequencer-publisher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,OAAO,EAAE,KAAK,uBAAuB,EAAwB,MAAM,yBAAyB,CAAC;AAC7F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EACL,kBAAkB,EAClB,KAAK,QAAQ,EACb,KAAK,0BAA0B,EAE/B,KAAK,YAAY,EACjB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,EAGhB,cAAc,EACd,KAAK,
|
|
1
|
+
{"version":3,"file":"sequencer-publisher.d.ts","sourceRoot":"","sources":["../../src/publisher/sequencer-publisher.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,8 +5,10 @@ import { sumBigint } from '@aztec/foundation/bigint';
|
|
|
5
5
|
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
6
6
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
7
7
|
import { createLogger } from '@aztec/foundation/log';
|
|
8
|
+
import { bufferToHex } from '@aztec/foundation/string';
|
|
8
9
|
import { Timer } from '@aztec/foundation/timer';
|
|
9
10
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
11
|
+
import { encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
10
12
|
import { CommitteeAttestation } from '@aztec/stdlib/block';
|
|
11
13
|
import { ConsensusPayload, SignatureDomainSeparator, getHashedSignaturePayload } from '@aztec/stdlib/p2p';
|
|
12
14
|
import { getTelemetryClient } from '@aztec/telemetry-client';
|
|
@@ -21,11 +23,15 @@ export var SignalType = /*#__PURE__*/ function(SignalType) {
|
|
|
21
23
|
const Actions = [
|
|
22
24
|
'propose',
|
|
23
25
|
'governance-signal',
|
|
24
|
-
'slashing-signal',
|
|
26
|
+
'empire-slashing-signal',
|
|
27
|
+
'create-empire-payload',
|
|
28
|
+
'execute-empire-payload',
|
|
29
|
+
'vote-offenses',
|
|
30
|
+
'execute-slash',
|
|
25
31
|
'invalidate-by-invalid-attestation',
|
|
26
32
|
'invalidate-by-insufficient-attestations'
|
|
27
33
|
];
|
|
28
|
-
// Sorting for actions such that invalidations go
|
|
34
|
+
// Sorting for actions such that invalidations go before proposals, and proposals go before votes
|
|
29
35
|
const compareActions = (a, b)=>Actions.indexOf(b) - Actions.indexOf(a);
|
|
30
36
|
export class SequencerPublisher {
|
|
31
37
|
config;
|
|
@@ -35,7 +41,7 @@ export class SequencerPublisher {
|
|
|
35
41
|
governanceLog;
|
|
36
42
|
governancePayload;
|
|
37
43
|
slashingLog;
|
|
38
|
-
|
|
44
|
+
slashingProposerAddress;
|
|
39
45
|
myLastSignals;
|
|
40
46
|
log;
|
|
41
47
|
ethereumSlotDuration;
|
|
@@ -52,6 +58,7 @@ export class SequencerPublisher {
|
|
|
52
58
|
rollupContract;
|
|
53
59
|
govProposerContract;
|
|
54
60
|
slashingProposerContract;
|
|
61
|
+
slashFactoryContract;
|
|
55
62
|
requests;
|
|
56
63
|
constructor(config, deps){
|
|
57
64
|
this.config = config;
|
|
@@ -59,7 +66,6 @@ export class SequencerPublisher {
|
|
|
59
66
|
this.governanceLog = createLogger('sequencer:publisher:governance');
|
|
60
67
|
this.governancePayload = EthAddress.ZERO;
|
|
61
68
|
this.slashingLog = createLogger('sequencer:publisher:slashing');
|
|
62
|
-
this.getSlashPayload = undefined;
|
|
63
69
|
this.myLastSignals = {
|
|
64
70
|
[0]: 0n,
|
|
65
71
|
[1]: 0n
|
|
@@ -82,13 +88,11 @@ export class SequencerPublisher {
|
|
|
82
88
|
const newSlashingProposer = await this.rollupContract.getSlashingProposer();
|
|
83
89
|
this.slashingProposerContract = newSlashingProposer;
|
|
84
90
|
});
|
|
91
|
+
this.slashFactoryContract = deps.slashFactoryContract;
|
|
85
92
|
}
|
|
86
93
|
getRollupContract() {
|
|
87
94
|
return this.rollupContract;
|
|
88
95
|
}
|
|
89
|
-
registerSlashPayloadGetter(callback) {
|
|
90
|
-
this.getSlashPayload = callback;
|
|
91
|
-
}
|
|
92
96
|
getSenderAddress() {
|
|
93
97
|
return EthAddress.fromString(this.l1TxUtils.getSenderAddress());
|
|
94
98
|
}
|
|
@@ -422,7 +426,7 @@ export class SequencerPublisher {
|
|
|
422
426
|
}
|
|
423
427
|
const cachedLastVote = this.myLastSignals[signalType];
|
|
424
428
|
this.myLastSignals[signalType] = slotNumber;
|
|
425
|
-
const action = signalType === 0 ? 'governance-signal' : 'slashing-signal';
|
|
429
|
+
const action = signalType === 0 ? 'governance-signal' : 'empire-slashing-signal';
|
|
426
430
|
const request = await base.createSignalRequestWithSignature(payload.toString(), slotNumber, this.config.l1ChainId, signerAddress.toString(), signer);
|
|
427
431
|
this.log.debug(`Created ${action} request with signature`, {
|
|
428
432
|
request,
|
|
@@ -438,9 +442,10 @@ export class SequencerPublisher {
|
|
|
438
442
|
request
|
|
439
443
|
});
|
|
440
444
|
} catch (err) {
|
|
441
|
-
this.log.
|
|
445
|
+
this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, err);
|
|
442
446
|
// Yes, we enqueue the request anyway, in case there was a bug with the simulation itself
|
|
443
447
|
}
|
|
448
|
+
// TODO(palla/slash): All votes (governance and slashing) should txTimeoutAt at the end of the slot.
|
|
444
449
|
this.addRequest({
|
|
445
450
|
gasConfig: {
|
|
446
451
|
gasLimit: SequencerPublisher.VOTE_GAS_GUESS
|
|
@@ -468,43 +473,100 @@ export class SequencerPublisher {
|
|
|
468
473
|
});
|
|
469
474
|
return true;
|
|
470
475
|
}
|
|
471
|
-
async getSignalConfig(slotNumber, signalType) {
|
|
472
|
-
if (signalType === 0) {
|
|
473
|
-
return {
|
|
474
|
-
payload: this.governancePayload,
|
|
475
|
-
base: this.govProposerContract
|
|
476
|
-
};
|
|
477
|
-
} else if (signalType === 1) {
|
|
478
|
-
if (!this.getSlashPayload) {
|
|
479
|
-
return undefined;
|
|
480
|
-
}
|
|
481
|
-
const slashPayload = await this.getSlashPayload(slotNumber);
|
|
482
|
-
if (!slashPayload) {
|
|
483
|
-
return undefined;
|
|
484
|
-
}
|
|
485
|
-
this.log.info(`Slash payload: ${slashPayload}`);
|
|
486
|
-
return {
|
|
487
|
-
payload: slashPayload,
|
|
488
|
-
base: this.slashingProposerContract
|
|
489
|
-
};
|
|
490
|
-
} else {
|
|
491
|
-
const _ = signalType;
|
|
492
|
-
throw new Error('Unreachable: Invalid signal type');
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
476
|
/**
|
|
496
|
-
* Enqueues a castSignal transaction to cast a signal for a given slot number.
|
|
477
|
+
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
497
478
|
* @param slotNumber - The slot number to cast a signal for.
|
|
498
479
|
* @param timestamp - The timestamp of the slot to cast a signal for.
|
|
499
|
-
* @param signalType - The type of signal to cast.
|
|
500
480
|
* @returns True if the signal was successfully enqueued, false otherwise.
|
|
501
|
-
*/
|
|
502
|
-
|
|
503
|
-
|
|
481
|
+
*/ enqueueGovernanceCastSignal(slotNumber, timestamp, signerAddress, signer) {
|
|
482
|
+
return this.enqueueCastSignalHelper(slotNumber, timestamp, 0, this.governancePayload, this.govProposerContract, signerAddress, signer);
|
|
483
|
+
}
|
|
484
|
+
/** Enqueues all slashing actions as returned by the slasher client. */ async enqueueSlashingActions(actions, slotNumber, timestamp, signerAddress, signer) {
|
|
485
|
+
if (actions.length === 0) {
|
|
486
|
+
this.log.debug(`No slashing actions to enqueue for slot ${slotNumber}`);
|
|
504
487
|
return false;
|
|
505
488
|
}
|
|
506
|
-
const
|
|
507
|
-
|
|
489
|
+
for (const action of actions){
|
|
490
|
+
switch(action.type){
|
|
491
|
+
case 'vote-empire-payload':
|
|
492
|
+
{
|
|
493
|
+
if (this.slashingProposerContract.type !== 'empire') {
|
|
494
|
+
this.log.error('Cannot vote for empire payload on non-empire slashing contract');
|
|
495
|
+
break;
|
|
496
|
+
}
|
|
497
|
+
this.log.debug(`Enqueuing slashing vote for payload ${action.payload} at slot ${slotNumber}`, {
|
|
498
|
+
signerAddress
|
|
499
|
+
});
|
|
500
|
+
await this.enqueueCastSignalHelper(slotNumber, timestamp, 1, action.payload, this.slashingProposerContract, signerAddress, signer);
|
|
501
|
+
break;
|
|
502
|
+
}
|
|
503
|
+
case 'create-empire-payload':
|
|
504
|
+
{
|
|
505
|
+
this.log.debug(`Enqueuing slashing create payload at slot ${slotNumber}`, {
|
|
506
|
+
slotNumber,
|
|
507
|
+
signerAddress
|
|
508
|
+
});
|
|
509
|
+
const request = this.slashFactoryContract.buildCreatePayloadRequest(action.data);
|
|
510
|
+
await this.simulateAndEnqueueRequest('create-empire-payload', request, (receipt)=>!!this.slashFactoryContract.tryExtractSlashPayloadCreatedEvent(receipt.logs), slotNumber, timestamp);
|
|
511
|
+
break;
|
|
512
|
+
}
|
|
513
|
+
case 'execute-empire-payload':
|
|
514
|
+
{
|
|
515
|
+
this.log.debug(`Enqueuing slashing execute payload at slot ${slotNumber}`, {
|
|
516
|
+
slotNumber,
|
|
517
|
+
signerAddress
|
|
518
|
+
});
|
|
519
|
+
if (this.slashingProposerContract.type !== 'empire') {
|
|
520
|
+
this.log.error('Cannot execute slashing payload on non-empire slashing contract');
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
const empireSlashingProposer = this.slashingProposerContract;
|
|
524
|
+
const request = empireSlashingProposer.buildExecuteRoundRequest(action.round);
|
|
525
|
+
await this.simulateAndEnqueueRequest('execute-empire-payload', request, (receipt)=>!!empireSlashingProposer.tryExtractPayloadSubmittedEvent(receipt.logs), slotNumber, timestamp);
|
|
526
|
+
break;
|
|
527
|
+
}
|
|
528
|
+
case 'vote-offenses':
|
|
529
|
+
{
|
|
530
|
+
this.log.debug(`Enqueuing slashing vote for ${action.votes.length} votes at slot ${slotNumber}`, {
|
|
531
|
+
slotNumber,
|
|
532
|
+
round: action.round,
|
|
533
|
+
votesCount: action.votes.length,
|
|
534
|
+
signerAddress
|
|
535
|
+
});
|
|
536
|
+
if (this.slashingProposerContract.type !== 'tally') {
|
|
537
|
+
this.log.error('Cannot vote for slashing offenses on non-tally slashing contract');
|
|
538
|
+
return false;
|
|
539
|
+
}
|
|
540
|
+
const tallySlashingProposer = this.slashingProposerContract;
|
|
541
|
+
const votes = bufferToHex(encodeSlashConsensusVotes(action.votes));
|
|
542
|
+
const request = await tallySlashingProposer.buildVoteRequestFromSigner(votes, slotNumber, signer);
|
|
543
|
+
await this.simulateAndEnqueueRequest('vote-offenses', request, (receipt)=>!!tallySlashingProposer.tryExtractVoteCastEvent(receipt.logs), slotNumber, timestamp);
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
case 'execute-slash':
|
|
547
|
+
{
|
|
548
|
+
this.log.debug(`Enqueuing slash execution for round ${action.round} at slot ${slotNumber}`, {
|
|
549
|
+
slotNumber,
|
|
550
|
+
round: action.round,
|
|
551
|
+
signerAddress
|
|
552
|
+
});
|
|
553
|
+
if (this.slashingProposerContract.type !== 'tally') {
|
|
554
|
+
this.log.error('Cannot execute slashing offenses on non-tally slashing contract');
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
const tallySlashingProposer = this.slashingProposerContract;
|
|
558
|
+
const request = tallySlashingProposer.buildExecuteRoundRequest(action.round, action.committees);
|
|
559
|
+
await this.simulateAndEnqueueRequest('execute-slash', request, (receipt)=>!!tallySlashingProposer.tryExtractRoundExecutedEvent(receipt.logs), slotNumber, timestamp);
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
default:
|
|
563
|
+
{
|
|
564
|
+
const _ = action;
|
|
565
|
+
throw new Error(`Unknown slashing action type: ${action.type}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return true;
|
|
508
570
|
}
|
|
509
571
|
/**
|
|
510
572
|
* Proposes a L2 block on L1.
|
|
@@ -556,7 +618,7 @@ export class SequencerPublisher {
|
|
|
556
618
|
if (!request) {
|
|
557
619
|
return;
|
|
558
620
|
}
|
|
559
|
-
// We
|
|
621
|
+
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
560
622
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(request.gasUsed) * 64 / 63)));
|
|
561
623
|
const logData = {
|
|
562
624
|
...pick(request, 'gasUsed', 'blockNumber'),
|
|
@@ -589,6 +651,57 @@ export class SequencerPublisher {
|
|
|
589
651
|
}
|
|
590
652
|
});
|
|
591
653
|
}
|
|
654
|
+
async simulateAndEnqueueRequest(action, request, checkSuccess, slotNumber, timestamp) {
|
|
655
|
+
const logData = {
|
|
656
|
+
slotNumber,
|
|
657
|
+
timestamp,
|
|
658
|
+
gasLimit: undefined
|
|
659
|
+
};
|
|
660
|
+
let gasUsed;
|
|
661
|
+
this.log.debug(`Simulating ${action}`, logData);
|
|
662
|
+
try {
|
|
663
|
+
({ gasUsed } = await this.l1TxUtils.simulate(request, {
|
|
664
|
+
time: timestamp
|
|
665
|
+
}, [], ErrorsAbi)); // TODO(palla/slash): Check the timestamp logic
|
|
666
|
+
this.log.verbose(`Simulation for ${action} succeeded`, {
|
|
667
|
+
...logData,
|
|
668
|
+
request,
|
|
669
|
+
gasUsed
|
|
670
|
+
});
|
|
671
|
+
} catch (err) {
|
|
672
|
+
const viemError = formatViemError(err);
|
|
673
|
+
this.log.error(`Simulation for ${action} at ${slotNumber} failed`, viemError, logData);
|
|
674
|
+
return false;
|
|
675
|
+
}
|
|
676
|
+
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
677
|
+
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil(Number(gasUsed) * 64 / 63)));
|
|
678
|
+
logData.gasLimit = gasLimit;
|
|
679
|
+
this.log.debug(`Enqueuing ${action}`, logData);
|
|
680
|
+
this.addRequest({
|
|
681
|
+
action,
|
|
682
|
+
request,
|
|
683
|
+
gasConfig: {
|
|
684
|
+
gasLimit
|
|
685
|
+
},
|
|
686
|
+
lastValidL2Slot: slotNumber,
|
|
687
|
+
checkSuccess: (_req, result)=>{
|
|
688
|
+
const success = result && result.receipt && result.receipt.status === 'success' && checkSuccess(result.receipt);
|
|
689
|
+
if (!success) {
|
|
690
|
+
this.log.warn(`Action ${action} at ${slotNumber} failed`, {
|
|
691
|
+
...result,
|
|
692
|
+
...logData
|
|
693
|
+
});
|
|
694
|
+
} else {
|
|
695
|
+
this.log.info(`Action ${action} at ${slotNumber} succeeded`, {
|
|
696
|
+
...result,
|
|
697
|
+
...logData
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
return !!success;
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
return true;
|
|
704
|
+
}
|
|
592
705
|
/**
|
|
593
706
|
* Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
|
|
594
707
|
* Be warned, the call may return false even if the tx subsequently gets successfully mined.
|
|
@@ -728,7 +841,7 @@ export class SequencerPublisher {
|
|
|
728
841
|
blobs: encodedData.blobs.map((b)=>b.data),
|
|
729
842
|
kzg
|
|
730
843
|
},
|
|
731
|
-
checkSuccess: (
|
|
844
|
+
checkSuccess: (_request, result)=>{
|
|
732
845
|
if (!result) {
|
|
733
846
|
return false;
|
|
734
847
|
}
|
|
@@ -4,7 +4,7 @@ import { Fr } from '@aztec/foundation/fields';
|
|
|
4
4
|
import { type DateProvider } from '@aztec/foundation/timer';
|
|
5
5
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
6
6
|
import type { P2P } from '@aztec/p2p';
|
|
7
|
-
import type {
|
|
7
|
+
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
8
8
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
9
9
|
import type { CommitteeAttestation, L2BlockSource, ValidateBlockResult } from '@aztec/stdlib/block';
|
|
10
10
|
import { type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
|
|
@@ -14,7 +14,7 @@ import { Tx, type TxHash } from '@aztec/stdlib/tx';
|
|
|
14
14
|
import { type TelemetryClient, type Tracer } from '@aztec/telemetry-client';
|
|
15
15
|
import type { ValidatorClient } from '@aztec/validator-client';
|
|
16
16
|
import type { GlobalVariableBuilder } from '../global_variable_builder/global_builder.js';
|
|
17
|
-
import {
|
|
17
|
+
import type { Action, InvalidateBlockRequest, SequencerPublisher } from '../publisher/sequencer-publisher.js';
|
|
18
18
|
import type { SequencerConfig } from './config.js';
|
|
19
19
|
import { SequencerTimetable } from './timetable.js';
|
|
20
20
|
import { SequencerState, type SequencerStateWithSlot } from './utils.js';
|
|
@@ -64,7 +64,7 @@ export declare class Sequencer extends Sequencer_base {
|
|
|
64
64
|
protected globalsBuilder: GlobalVariableBuilder;
|
|
65
65
|
protected p2pClient: P2P;
|
|
66
66
|
protected worldState: WorldStateSynchronizer;
|
|
67
|
-
protected slasherClient:
|
|
67
|
+
protected slasherClient: SlasherClientInterface | undefined;
|
|
68
68
|
protected l2BlockSource: L2BlockSource;
|
|
69
69
|
protected l1ToL2MessageSource: L1ToL2MessageSource;
|
|
70
70
|
protected blockBuilder: IFullNodeBlockBuilder;
|
|
@@ -90,7 +90,7 @@ export declare class Sequencer extends Sequencer_base {
|
|
|
90
90
|
protected timetable: SequencerTimetable;
|
|
91
91
|
protected enforceTimeTable: boolean;
|
|
92
92
|
constructor(publisher: SequencerPublisher, validatorClient: ValidatorClient | undefined, // During migration the validator client can be inactive
|
|
93
|
-
globalsBuilder: GlobalVariableBuilder, p2pClient: P2P, worldState: WorldStateSynchronizer, slasherClient:
|
|
93
|
+
globalsBuilder: GlobalVariableBuilder, p2pClient: P2P, worldState: WorldStateSynchronizer, slasherClient: SlasherClientInterface | undefined, l2BlockSource: L2BlockSource, l1ToL2MessageSource: L1ToL2MessageSource, blockBuilder: IFullNodeBlockBuilder, l1Constants: SequencerRollupConstants, dateProvider: DateProvider, config?: SequencerConfig, telemetry?: TelemetryClient, log?: import("@aztec/aztec.js").Logger);
|
|
94
94
|
get tracer(): Tracer;
|
|
95
95
|
getValidatorAddresses(): EthAddress[] | undefined;
|
|
96
96
|
getConfig(): SequencerConfig;
|
|
@@ -181,11 +181,12 @@ export declare class Sequencer extends Sequencer_base {
|
|
|
181
181
|
*/
|
|
182
182
|
protected considerInvalidatingBlock(syncedTo: NonNullable<Awaited<ReturnType<Sequencer['getChainTip']>>>, currentSlot: bigint, ourValidatorAddresses: EthAddress[]): Promise<void>;
|
|
183
183
|
private getSlotStartBuildTimestamp;
|
|
184
|
+
private getTxTimeoutForSlot;
|
|
184
185
|
private getSecondsIntoSlot;
|
|
185
186
|
get aztecSlotDuration(): number;
|
|
186
187
|
get coinbase(): EthAddress;
|
|
187
188
|
get feeRecipient(): AztecAddress;
|
|
188
189
|
get maxL2BlockGas(): number | undefined;
|
|
189
|
-
getSlasherClient():
|
|
190
|
+
getSlasherClient(): SlasherClientInterface | undefined;
|
|
190
191
|
}
|
|
191
192
|
//# sourceMappingURL=sequencer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sequencer.d.ts","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI/C,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,EAAE,EAAE,MAAM,0BAA0B,CAAC;AAG9C,OAAO,EAAE,KAAK,YAAY,EAAS,MAAM,yBAAyB,CAAC;AACnE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"sequencer.d.ts","sourceRoot":"","sources":["../../src/sequencer/sequencer.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,7 +23,6 @@ import { ContentCommitment, ProposedBlockHeader } from '@aztec/stdlib/tx';
|
|
|
23
23
|
import { AttestationTimeoutError } from '@aztec/stdlib/validators';
|
|
24
24
|
import { Attributes, L1Metrics, getTelemetryClient, trackSpan } from '@aztec/telemetry-client';
|
|
25
25
|
import EventEmitter from 'node:events';
|
|
26
|
-
import { SignalType } from '../publisher/sequencer-publisher.js';
|
|
27
26
|
import { SequencerMetrics } from './metrics.js';
|
|
28
27
|
import { SequencerTimetable, SequencerTooSlowError } from './timetable.js';
|
|
29
28
|
import { SequencerState } from './utils.js';
|
|
@@ -73,8 +72,6 @@ export { SequencerState };
|
|
|
73
72
|
this.l1Metrics = new L1Metrics(telemetry.getMeter('SequencerL1Metrics'), publisher.l1TxUtils.client, [
|
|
74
73
|
publisher.getSenderAddress()
|
|
75
74
|
]);
|
|
76
|
-
// Register the slasher on the publisher to fetch slashing payloads
|
|
77
|
-
this.publisher.registerSlashPayloadGetter(this.slasherClient.getSlashPayload.bind(this.slasherClient));
|
|
78
75
|
// Initialize config
|
|
79
76
|
this.updateConfig(this.config);
|
|
80
77
|
}
|
|
@@ -302,8 +299,10 @@ export { SequencerState };
|
|
|
302
299
|
validatorAddresses
|
|
303
300
|
});
|
|
304
301
|
const newGlobalVariables = await this.globalsBuilder.buildGlobalVariables(newBlockNumber, this.coinbase, this._feeRecipient, slot);
|
|
305
|
-
const
|
|
306
|
-
const
|
|
302
|
+
const { timestamp } = newGlobalVariables;
|
|
303
|
+
const signerFn = (msg)=>this.validatorClient.signWithAddress(proposerAddress, msg).then((s)=>s.toString());
|
|
304
|
+
const enqueueGovernanceSignalPromise = this.publisher.enqueueGovernanceCastSignal(slot, timestamp, proposerAddress, signerFn);
|
|
305
|
+
const enqueueSlashingActionsPromise = this.slasherClient?.getProposerActions(slot)?.then((actions)=>this.publisher.enqueueSlashingActions(actions, slot, timestamp, proposerAddress, signerFn));
|
|
307
306
|
if (invalidateBlock && !this.config.skipInvalidateBlockAsProposer) {
|
|
308
307
|
this.publisher.enqueueInvalidateBlock(invalidateBlock);
|
|
309
308
|
}
|
|
@@ -355,14 +354,14 @@ export { SequencerState };
|
|
|
355
354
|
availableTxs: pendingTxCount
|
|
356
355
|
});
|
|
357
356
|
}
|
|
358
|
-
await
|
|
357
|
+
await enqueueGovernanceSignalPromise?.catch((err)=>{
|
|
359
358
|
this.log.error(`Error enqueuing governance vote`, err, {
|
|
360
359
|
blockNumber: newBlockNumber,
|
|
361
360
|
slot
|
|
362
361
|
});
|
|
363
362
|
});
|
|
364
|
-
await
|
|
365
|
-
this.log.error(`Error enqueuing slashing
|
|
363
|
+
await enqueueSlashingActionsPromise?.catch((err)=>{
|
|
364
|
+
this.log.error(`Error enqueuing slashing actions`, err, {
|
|
366
365
|
blockNumber: newBlockNumber,
|
|
367
366
|
slot
|
|
368
367
|
});
|
|
@@ -567,11 +566,8 @@ export { SequencerState };
|
|
|
567
566
|
*/ async enqueuePublishL2Block(block, attestations, txHashes, invalidateBlock) {
|
|
568
567
|
// Publishes new block to the network and awaits the tx to be mined
|
|
569
568
|
this.setState(SequencerState.PUBLISHING_BLOCK, block.header.globalVariables.slotNumber.toBigInt());
|
|
570
|
-
// Time out tx at the end of the slot
|
|
571
|
-
const slot = block.header.globalVariables.slotNumber.toNumber();
|
|
572
|
-
const txTimeoutAt = new Date((this.getSlotStartBuildTimestamp(slot) + this.aztecSlotDuration) * 1000);
|
|
573
569
|
const enqueued = await this.publisher.enqueueProposeL2Block(block, attestations, txHashes, {
|
|
574
|
-
txTimeoutAt,
|
|
570
|
+
txTimeoutAt: this.getTxTimeoutForSlot(block.slot),
|
|
575
571
|
forcePendingBlockNumber: invalidateBlock?.forcePendingBlockNumber
|
|
576
572
|
});
|
|
577
573
|
if (!enqueued) {
|
|
@@ -675,6 +671,9 @@ export { SequencerState };
|
|
|
675
671
|
getSlotStartBuildTimestamp(slotNumber) {
|
|
676
672
|
return Number(this.l1Constants.l1GenesisTime) + Number(slotNumber) * this.l1Constants.slotDuration - this.l1Constants.ethereumSlotDuration;
|
|
677
673
|
}
|
|
674
|
+
getTxTimeoutForSlot(slotNumber) {
|
|
675
|
+
return new Date((this.getSlotStartBuildTimestamp(slotNumber) + this.aztecSlotDuration) * 1000);
|
|
676
|
+
}
|
|
678
677
|
getSecondsIntoSlot(slotNumber) {
|
|
679
678
|
const slotStartTimestamp = this.getSlotStartBuildTimestamp(slotNumber);
|
|
680
679
|
return Number((this.dateProvider.now() / 1000 - slotStartTimestamp).toFixed(3));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/sequencer-client",
|
|
3
|
-
"version": "2.0.0-nightly.
|
|
3
|
+
"version": "2.0.0-nightly.20250823",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./dest/index.js",
|
|
@@ -26,37 +26,37 @@
|
|
|
26
26
|
"test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules $(yarn bin jest) --no-cache --config jest.integration.config.json"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@aztec/aztec.js": "2.0.0-nightly.
|
|
30
|
-
"@aztec/bb-prover": "2.0.0-nightly.
|
|
31
|
-
"@aztec/blob-lib": "2.0.0-nightly.
|
|
32
|
-
"@aztec/blob-sink": "2.0.0-nightly.
|
|
33
|
-
"@aztec/constants": "2.0.0-nightly.
|
|
34
|
-
"@aztec/epoch-cache": "2.0.0-nightly.
|
|
35
|
-
"@aztec/ethereum": "2.0.0-nightly.
|
|
36
|
-
"@aztec/foundation": "2.0.0-nightly.
|
|
37
|
-
"@aztec/l1-artifacts": "2.0.0-nightly.
|
|
38
|
-
"@aztec/merkle-tree": "2.0.0-nightly.
|
|
39
|
-
"@aztec/noir-acvm_js": "2.0.0-nightly.
|
|
40
|
-
"@aztec/noir-contracts.js": "2.0.0-nightly.
|
|
41
|
-
"@aztec/noir-protocol-circuits-types": "2.0.0-nightly.
|
|
42
|
-
"@aztec/noir-types": "2.0.0-nightly.
|
|
43
|
-
"@aztec/p2p": "2.0.0-nightly.
|
|
44
|
-
"@aztec/protocol-contracts": "2.0.0-nightly.
|
|
45
|
-
"@aztec/prover-client": "2.0.0-nightly.
|
|
46
|
-
"@aztec/simulator": "2.0.0-nightly.
|
|
47
|
-
"@aztec/slasher": "2.0.0-nightly.
|
|
48
|
-
"@aztec/stdlib": "2.0.0-nightly.
|
|
49
|
-
"@aztec/telemetry-client": "2.0.0-nightly.
|
|
50
|
-
"@aztec/validator-client": "2.0.0-nightly.
|
|
51
|
-
"@aztec/world-state": "2.0.0-nightly.
|
|
29
|
+
"@aztec/aztec.js": "2.0.0-nightly.20250823",
|
|
30
|
+
"@aztec/bb-prover": "2.0.0-nightly.20250823",
|
|
31
|
+
"@aztec/blob-lib": "2.0.0-nightly.20250823",
|
|
32
|
+
"@aztec/blob-sink": "2.0.0-nightly.20250823",
|
|
33
|
+
"@aztec/constants": "2.0.0-nightly.20250823",
|
|
34
|
+
"@aztec/epoch-cache": "2.0.0-nightly.20250823",
|
|
35
|
+
"@aztec/ethereum": "2.0.0-nightly.20250823",
|
|
36
|
+
"@aztec/foundation": "2.0.0-nightly.20250823",
|
|
37
|
+
"@aztec/l1-artifacts": "2.0.0-nightly.20250823",
|
|
38
|
+
"@aztec/merkle-tree": "2.0.0-nightly.20250823",
|
|
39
|
+
"@aztec/noir-acvm_js": "2.0.0-nightly.20250823",
|
|
40
|
+
"@aztec/noir-contracts.js": "2.0.0-nightly.20250823",
|
|
41
|
+
"@aztec/noir-protocol-circuits-types": "2.0.0-nightly.20250823",
|
|
42
|
+
"@aztec/noir-types": "2.0.0-nightly.20250823",
|
|
43
|
+
"@aztec/p2p": "2.0.0-nightly.20250823",
|
|
44
|
+
"@aztec/protocol-contracts": "2.0.0-nightly.20250823",
|
|
45
|
+
"@aztec/prover-client": "2.0.0-nightly.20250823",
|
|
46
|
+
"@aztec/simulator": "2.0.0-nightly.20250823",
|
|
47
|
+
"@aztec/slasher": "2.0.0-nightly.20250823",
|
|
48
|
+
"@aztec/stdlib": "2.0.0-nightly.20250823",
|
|
49
|
+
"@aztec/telemetry-client": "2.0.0-nightly.20250823",
|
|
50
|
+
"@aztec/validator-client": "2.0.0-nightly.20250823",
|
|
51
|
+
"@aztec/world-state": "2.0.0-nightly.20250823",
|
|
52
52
|
"lodash.chunk": "^4.2.0",
|
|
53
53
|
"lodash.pick": "^4.4.0",
|
|
54
54
|
"tslib": "^2.4.0",
|
|
55
55
|
"viem": "2.23.7"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@aztec/archiver": "2.0.0-nightly.
|
|
59
|
-
"@aztec/kv-store": "2.0.0-nightly.
|
|
58
|
+
"@aztec/archiver": "2.0.0-nightly.20250823",
|
|
59
|
+
"@aztec/kv-store": "2.0.0-nightly.20250823",
|
|
60
60
|
"@jest/globals": "^30.0.0",
|
|
61
61
|
"@types/jest": "^30.0.0",
|
|
62
62
|
"@types/lodash.chunk": "^4.2.7",
|
|
@@ -3,7 +3,6 @@ import { EpochCache } from '@aztec/epoch-cache';
|
|
|
3
3
|
import {
|
|
4
4
|
GovernanceProposerContract,
|
|
5
5
|
RollupContract,
|
|
6
|
-
SlashingProposerContract,
|
|
7
6
|
createEthereumChain,
|
|
8
7
|
createExtendedL1Client,
|
|
9
8
|
isAnvilTestChain,
|
|
@@ -13,10 +12,11 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
13
12
|
import { createLogger } from '@aztec/foundation/log';
|
|
14
13
|
import type { DateProvider } from '@aztec/foundation/timer';
|
|
15
14
|
import type { P2P } from '@aztec/p2p';
|
|
16
|
-
import type {
|
|
15
|
+
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
17
16
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
18
17
|
import type { L2BlockSource } from '@aztec/stdlib/block';
|
|
19
18
|
import type { IFullNodeBlockBuilder, WorldStateSynchronizer } from '@aztec/stdlib/interfaces/server';
|
|
19
|
+
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
20
20
|
import type { L1ToL2MessageSource } from '@aztec/stdlib/messaging';
|
|
21
21
|
import type { TelemetryClient } from '@aztec/telemetry-client';
|
|
22
22
|
import type { ValidatorClient } from '@aztec/validator-client';
|
|
@@ -53,7 +53,7 @@ export class SequencerClient {
|
|
|
53
53
|
validatorClient: ValidatorClient | undefined; // allowed to be undefined while we migrate
|
|
54
54
|
p2pClient: P2P;
|
|
55
55
|
worldStateSynchronizer: WorldStateSynchronizer;
|
|
56
|
-
slasherClient:
|
|
56
|
+
slasherClient: SlasherClientInterface | undefined;
|
|
57
57
|
blockBuilder: IFullNodeBlockBuilder;
|
|
58
58
|
l2BlockSource: L2BlockSource;
|
|
59
59
|
l1ToL2MessageSource: L1ToL2MessageSource;
|
|
@@ -90,8 +90,7 @@ export class SequencerClient {
|
|
|
90
90
|
l1Client,
|
|
91
91
|
config.l1Contracts.governanceProposerAddress.toString(),
|
|
92
92
|
);
|
|
93
|
-
const
|
|
94
|
-
const slashingProposerContract = new SlashingProposerContract(l1Client, slashingProposerAddress.toString());
|
|
93
|
+
const slashingProposerContract = await rollupContract.getSlashingProposer();
|
|
95
94
|
const epochCache =
|
|
96
95
|
deps.epochCache ??
|
|
97
96
|
(await EpochCache.create(
|
|
@@ -107,6 +106,11 @@ export class SequencerClient {
|
|
|
107
106
|
{ dateProvider: deps.dateProvider },
|
|
108
107
|
));
|
|
109
108
|
|
|
109
|
+
const slashFactoryContract = new SlashFactoryContract(
|
|
110
|
+
l1Client,
|
|
111
|
+
config.l1Contracts.slashFactoryAddress?.toString() ?? EthAddress.ZERO.toString(),
|
|
112
|
+
);
|
|
113
|
+
|
|
110
114
|
const publisher =
|
|
111
115
|
deps.publisher ??
|
|
112
116
|
new SequencerPublisher(config, {
|
|
@@ -117,6 +121,7 @@ export class SequencerClient {
|
|
|
117
121
|
epochCache,
|
|
118
122
|
governanceProposerContract,
|
|
119
123
|
slashingProposerContract,
|
|
124
|
+
slashFactoryContract,
|
|
120
125
|
dateProvider: deps.dateProvider,
|
|
121
126
|
});
|
|
122
127
|
const globalsBuilder = new GlobalVariableBuilder(config);
|
|
@@ -3,6 +3,7 @@ import { Blob } from '@aztec/blob-lib';
|
|
|
3
3
|
import { type BlobSinkClientInterface, createBlobSinkClient } from '@aztec/blob-sink/client';
|
|
4
4
|
import type { EpochCache } from '@aztec/epoch-cache';
|
|
5
5
|
import {
|
|
6
|
+
type EmpireSlashingProposerContract,
|
|
6
7
|
FormattedViemError,
|
|
7
8
|
type GasPrice,
|
|
8
9
|
type GovernanceProposerContract,
|
|
@@ -14,7 +15,7 @@ import {
|
|
|
14
15
|
MULTI_CALL_3_ADDRESS,
|
|
15
16
|
Multicall3,
|
|
16
17
|
RollupContract,
|
|
17
|
-
type
|
|
18
|
+
type TallySlashingProposerContract,
|
|
18
19
|
type TransactionStats,
|
|
19
20
|
type ViemCommitteeAttestations,
|
|
20
21
|
type ViemHeader,
|
|
@@ -28,9 +29,12 @@ import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
|
28
29
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
29
30
|
import type { Fr } from '@aztec/foundation/fields';
|
|
30
31
|
import { createLogger } from '@aztec/foundation/log';
|
|
32
|
+
import { bufferToHex } from '@aztec/foundation/string';
|
|
31
33
|
import { DateProvider, Timer } from '@aztec/foundation/timer';
|
|
32
34
|
import { EmpireBaseAbi, ErrorsAbi, RollupAbi } from '@aztec/l1-artifacts';
|
|
35
|
+
import { type ProposerSlashAction, encodeSlashConsensusVotes } from '@aztec/slasher';
|
|
33
36
|
import { CommitteeAttestation, type ValidateBlockResult } from '@aztec/stdlib/block';
|
|
37
|
+
import { SlashFactoryContract } from '@aztec/stdlib/l1-contracts';
|
|
34
38
|
import { ConsensusPayload, SignatureDomainSeparator, getHashedSignaturePayload } from '@aztec/stdlib/p2p';
|
|
35
39
|
import type { L1PublishBlockStats } from '@aztec/stdlib/stats';
|
|
36
40
|
import { type ProposedBlockHeader, StateReference, TxHash } from '@aztec/stdlib/tx';
|
|
@@ -63,18 +67,20 @@ export enum SignalType {
|
|
|
63
67
|
SLASHING,
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
type GetSlashPayloadCallBack = (slotNumber: bigint) => Promise<EthAddress | undefined>;
|
|
67
|
-
|
|
68
70
|
const Actions = [
|
|
69
71
|
'propose',
|
|
70
72
|
'governance-signal',
|
|
71
|
-
'slashing-signal',
|
|
73
|
+
'empire-slashing-signal',
|
|
74
|
+
'create-empire-payload',
|
|
75
|
+
'execute-empire-payload',
|
|
76
|
+
'vote-offenses',
|
|
77
|
+
'execute-slash',
|
|
72
78
|
'invalidate-by-invalid-attestation',
|
|
73
79
|
'invalidate-by-insufficient-attestations',
|
|
74
80
|
] as const;
|
|
75
81
|
export type Action = (typeof Actions)[number];
|
|
76
82
|
|
|
77
|
-
// Sorting for actions such that invalidations go
|
|
83
|
+
// Sorting for actions such that invalidations go before proposals, and proposals go before votes
|
|
78
84
|
const compareActions = (a: Action, b: Action) => Actions.indexOf(b) - Actions.indexOf(a);
|
|
79
85
|
|
|
80
86
|
export type InvalidateBlockRequest = {
|
|
@@ -106,7 +112,7 @@ export class SequencerPublisher {
|
|
|
106
112
|
private governancePayload: EthAddress = EthAddress.ZERO;
|
|
107
113
|
|
|
108
114
|
protected slashingLog = createLogger('sequencer:publisher:slashing');
|
|
109
|
-
|
|
115
|
+
protected slashingProposerAddress?: EthAddress;
|
|
110
116
|
|
|
111
117
|
private myLastSignals: Record<SignalType, bigint> = {
|
|
112
118
|
[SignalType.GOVERNANCE]: 0n,
|
|
@@ -131,7 +137,8 @@ export class SequencerPublisher {
|
|
|
131
137
|
public l1TxUtils: L1TxUtilsWithBlobs;
|
|
132
138
|
public rollupContract: RollupContract;
|
|
133
139
|
public govProposerContract: GovernanceProposerContract;
|
|
134
|
-
public slashingProposerContract:
|
|
140
|
+
public slashingProposerContract: EmpireSlashingProposerContract | TallySlashingProposerContract;
|
|
141
|
+
public slashFactoryContract: SlashFactoryContract;
|
|
135
142
|
|
|
136
143
|
protected requests: RequestWithExpiry[] = [];
|
|
137
144
|
|
|
@@ -142,8 +149,9 @@ export class SequencerPublisher {
|
|
|
142
149
|
blobSinkClient?: BlobSinkClientInterface;
|
|
143
150
|
l1TxUtils: L1TxUtilsWithBlobs;
|
|
144
151
|
rollupContract: RollupContract;
|
|
145
|
-
slashingProposerContract:
|
|
152
|
+
slashingProposerContract: EmpireSlashingProposerContract | TallySlashingProposerContract;
|
|
146
153
|
governanceProposerContract: GovernanceProposerContract;
|
|
154
|
+
slashFactoryContract: SlashFactoryContract;
|
|
147
155
|
epochCache: EpochCache;
|
|
148
156
|
dateProvider: DateProvider;
|
|
149
157
|
},
|
|
@@ -168,16 +176,13 @@ export class SequencerPublisher {
|
|
|
168
176
|
const newSlashingProposer = await this.rollupContract.getSlashingProposer();
|
|
169
177
|
this.slashingProposerContract = newSlashingProposer;
|
|
170
178
|
});
|
|
179
|
+
this.slashFactoryContract = deps.slashFactoryContract;
|
|
171
180
|
}
|
|
172
181
|
|
|
173
182
|
public getRollupContract(): RollupContract {
|
|
174
183
|
return this.rollupContract;
|
|
175
184
|
}
|
|
176
185
|
|
|
177
|
-
public registerSlashPayloadGetter(callback: GetSlashPayloadCallBack) {
|
|
178
|
-
this.getSlashPayload = callback;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
186
|
public getSenderAddress() {
|
|
182
187
|
return EthAddress.fromString(this.l1TxUtils.getSenderAddress());
|
|
183
188
|
}
|
|
@@ -554,7 +559,7 @@ export class SequencerPublisher {
|
|
|
554
559
|
const cachedLastVote = this.myLastSignals[signalType];
|
|
555
560
|
this.myLastSignals[signalType] = slotNumber;
|
|
556
561
|
|
|
557
|
-
const action = signalType === SignalType.GOVERNANCE ? 'governance-signal' : 'slashing-signal';
|
|
562
|
+
const action = signalType === SignalType.GOVERNANCE ? 'governance-signal' : 'empire-slashing-signal';
|
|
558
563
|
|
|
559
564
|
const request = await base.createSignalRequestWithSignature(
|
|
560
565
|
payload.toString(),
|
|
@@ -574,10 +579,11 @@ export class SequencerPublisher {
|
|
|
574
579
|
await this.l1TxUtils.simulate(request, { time: timestamp }, [], ErrorsAbi);
|
|
575
580
|
this.log.debug(`Simulation for ${action} at slot ${slotNumber} succeeded`, { request });
|
|
576
581
|
} catch (err) {
|
|
577
|
-
this.log.
|
|
582
|
+
this.log.error(`Failed simulation for ${action} at slot ${slotNumber} (enqueuing the action anyway)`, err);
|
|
578
583
|
// Yes, we enqueue the request anyway, in case there was a bug with the simulation itself
|
|
579
584
|
}
|
|
580
585
|
|
|
586
|
+
// TODO(palla/slash): All votes (governance and slashing) should txTimeoutAt at the end of the slot.
|
|
581
587
|
this.addRequest({
|
|
582
588
|
gasConfig: { gasLimit: SequencerPublisher.VOTE_GAS_GUESS },
|
|
583
589
|
action,
|
|
@@ -610,48 +616,150 @@ export class SequencerPublisher {
|
|
|
610
616
|
return true;
|
|
611
617
|
}
|
|
612
618
|
|
|
613
|
-
private async getSignalConfig(
|
|
614
|
-
slotNumber: bigint,
|
|
615
|
-
signalType: SignalType,
|
|
616
|
-
): Promise<{ payload: EthAddress; base: IEmpireBase } | undefined> {
|
|
617
|
-
if (signalType === SignalType.GOVERNANCE) {
|
|
618
|
-
return { payload: this.governancePayload, base: this.govProposerContract };
|
|
619
|
-
} else if (signalType === SignalType.SLASHING) {
|
|
620
|
-
if (!this.getSlashPayload) {
|
|
621
|
-
return undefined;
|
|
622
|
-
}
|
|
623
|
-
const slashPayload = await this.getSlashPayload(slotNumber);
|
|
624
|
-
if (!slashPayload) {
|
|
625
|
-
return undefined;
|
|
626
|
-
}
|
|
627
|
-
this.log.info(`Slash payload: ${slashPayload}`);
|
|
628
|
-
return { payload: slashPayload, base: this.slashingProposerContract };
|
|
629
|
-
} else {
|
|
630
|
-
const _: never = signalType;
|
|
631
|
-
throw new Error('Unreachable: Invalid signal type');
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
|
|
635
619
|
/**
|
|
636
|
-
* Enqueues a castSignal transaction to cast a signal for a given slot number.
|
|
620
|
+
* Enqueues a governance castSignal transaction to cast a signal for a given slot number.
|
|
637
621
|
* @param slotNumber - The slot number to cast a signal for.
|
|
638
622
|
* @param timestamp - The timestamp of the slot to cast a signal for.
|
|
639
|
-
* @param signalType - The type of signal to cast.
|
|
640
623
|
* @returns True if the signal was successfully enqueued, false otherwise.
|
|
641
624
|
*/
|
|
642
|
-
public
|
|
625
|
+
public enqueueGovernanceCastSignal(
|
|
626
|
+
slotNumber: bigint,
|
|
627
|
+
timestamp: bigint,
|
|
628
|
+
signerAddress: EthAddress,
|
|
629
|
+
signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>,
|
|
630
|
+
): Promise<boolean> {
|
|
631
|
+
return this.enqueueCastSignalHelper(
|
|
632
|
+
slotNumber,
|
|
633
|
+
timestamp,
|
|
634
|
+
SignalType.GOVERNANCE,
|
|
635
|
+
this.governancePayload,
|
|
636
|
+
this.govProposerContract,
|
|
637
|
+
signerAddress,
|
|
638
|
+
signer,
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/** Enqueues all slashing actions as returned by the slasher client. */
|
|
643
|
+
public async enqueueSlashingActions(
|
|
644
|
+
actions: ProposerSlashAction[],
|
|
643
645
|
slotNumber: bigint,
|
|
644
646
|
timestamp: bigint,
|
|
645
|
-
signalType: SignalType,
|
|
646
647
|
signerAddress: EthAddress,
|
|
647
648
|
signer: (msg: TypedDataDefinition) => Promise<`0x${string}`>,
|
|
648
649
|
): Promise<boolean> {
|
|
649
|
-
|
|
650
|
-
|
|
650
|
+
if (actions.length === 0) {
|
|
651
|
+
this.log.debug(`No slashing actions to enqueue for slot ${slotNumber}`);
|
|
651
652
|
return false;
|
|
652
653
|
}
|
|
653
|
-
|
|
654
|
-
|
|
654
|
+
|
|
655
|
+
for (const action of actions) {
|
|
656
|
+
switch (action.type) {
|
|
657
|
+
case 'vote-empire-payload': {
|
|
658
|
+
if (this.slashingProposerContract.type !== 'empire') {
|
|
659
|
+
this.log.error('Cannot vote for empire payload on non-empire slashing contract');
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
this.log.debug(`Enqueuing slashing vote for payload ${action.payload} at slot ${slotNumber}`, {
|
|
663
|
+
signerAddress,
|
|
664
|
+
});
|
|
665
|
+
await this.enqueueCastSignalHelper(
|
|
666
|
+
slotNumber,
|
|
667
|
+
timestamp,
|
|
668
|
+
SignalType.SLASHING,
|
|
669
|
+
action.payload,
|
|
670
|
+
this.slashingProposerContract,
|
|
671
|
+
signerAddress,
|
|
672
|
+
signer,
|
|
673
|
+
);
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
case 'create-empire-payload': {
|
|
678
|
+
this.log.debug(`Enqueuing slashing create payload at slot ${slotNumber}`, { slotNumber, signerAddress });
|
|
679
|
+
const request = this.slashFactoryContract.buildCreatePayloadRequest(action.data);
|
|
680
|
+
await this.simulateAndEnqueueRequest(
|
|
681
|
+
'create-empire-payload',
|
|
682
|
+
request,
|
|
683
|
+
(receipt: TransactionReceipt) =>
|
|
684
|
+
!!this.slashFactoryContract.tryExtractSlashPayloadCreatedEvent(receipt.logs),
|
|
685
|
+
slotNumber,
|
|
686
|
+
timestamp,
|
|
687
|
+
);
|
|
688
|
+
break;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
case 'execute-empire-payload': {
|
|
692
|
+
this.log.debug(`Enqueuing slashing execute payload at slot ${slotNumber}`, { slotNumber, signerAddress });
|
|
693
|
+
if (this.slashingProposerContract.type !== 'empire') {
|
|
694
|
+
this.log.error('Cannot execute slashing payload on non-empire slashing contract');
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
const empireSlashingProposer = this.slashingProposerContract as EmpireSlashingProposerContract;
|
|
698
|
+
const request = empireSlashingProposer.buildExecuteRoundRequest(action.round);
|
|
699
|
+
await this.simulateAndEnqueueRequest(
|
|
700
|
+
'execute-empire-payload',
|
|
701
|
+
request,
|
|
702
|
+
(receipt: TransactionReceipt) => !!empireSlashingProposer.tryExtractPayloadSubmittedEvent(receipt.logs),
|
|
703
|
+
slotNumber,
|
|
704
|
+
timestamp,
|
|
705
|
+
);
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
case 'vote-offenses': {
|
|
710
|
+
this.log.debug(`Enqueuing slashing vote for ${action.votes.length} votes at slot ${slotNumber}`, {
|
|
711
|
+
slotNumber,
|
|
712
|
+
round: action.round,
|
|
713
|
+
votesCount: action.votes.length,
|
|
714
|
+
signerAddress,
|
|
715
|
+
});
|
|
716
|
+
if (this.slashingProposerContract.type !== 'tally') {
|
|
717
|
+
this.log.error('Cannot vote for slashing offenses on non-tally slashing contract');
|
|
718
|
+
return false;
|
|
719
|
+
}
|
|
720
|
+
const tallySlashingProposer = this.slashingProposerContract as TallySlashingProposerContract;
|
|
721
|
+
const votes = bufferToHex(encodeSlashConsensusVotes(action.votes));
|
|
722
|
+
const request = await tallySlashingProposer.buildVoteRequestFromSigner(votes, slotNumber, signer);
|
|
723
|
+
await this.simulateAndEnqueueRequest(
|
|
724
|
+
'vote-offenses',
|
|
725
|
+
request,
|
|
726
|
+
(receipt: TransactionReceipt) => !!tallySlashingProposer.tryExtractVoteCastEvent(receipt.logs),
|
|
727
|
+
slotNumber,
|
|
728
|
+
timestamp,
|
|
729
|
+
);
|
|
730
|
+
break;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
case 'execute-slash': {
|
|
734
|
+
this.log.debug(`Enqueuing slash execution for round ${action.round} at slot ${slotNumber}`, {
|
|
735
|
+
slotNumber,
|
|
736
|
+
round: action.round,
|
|
737
|
+
signerAddress,
|
|
738
|
+
});
|
|
739
|
+
if (this.slashingProposerContract.type !== 'tally') {
|
|
740
|
+
this.log.error('Cannot execute slashing offenses on non-tally slashing contract');
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
const tallySlashingProposer = this.slashingProposerContract as TallySlashingProposerContract;
|
|
744
|
+
const request = tallySlashingProposer.buildExecuteRoundRequest(action.round, action.committees);
|
|
745
|
+
await this.simulateAndEnqueueRequest(
|
|
746
|
+
'execute-slash',
|
|
747
|
+
request,
|
|
748
|
+
(receipt: TransactionReceipt) => !!tallySlashingProposer.tryExtractRoundExecutedEvent(receipt.logs),
|
|
749
|
+
slotNumber,
|
|
750
|
+
timestamp,
|
|
751
|
+
);
|
|
752
|
+
break;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
default: {
|
|
756
|
+
const _: never = action;
|
|
757
|
+
throw new Error(`Unknown slashing action type: ${(action as ProposerSlashAction).type}`);
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
return true;
|
|
655
763
|
}
|
|
656
764
|
|
|
657
765
|
/**
|
|
@@ -711,7 +819,7 @@ export class SequencerPublisher {
|
|
|
711
819
|
return;
|
|
712
820
|
}
|
|
713
821
|
|
|
714
|
-
// We
|
|
822
|
+
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
715
823
|
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil((Number(request.gasUsed) * 64) / 63)));
|
|
716
824
|
|
|
717
825
|
const logData = { ...pick(request, 'gasUsed', 'blockNumber'), gasLimit, opts };
|
|
@@ -737,6 +845,49 @@ export class SequencerPublisher {
|
|
|
737
845
|
});
|
|
738
846
|
}
|
|
739
847
|
|
|
848
|
+
private async simulateAndEnqueueRequest(
|
|
849
|
+
action: RequestWithExpiry['action'],
|
|
850
|
+
request: L1TxRequest,
|
|
851
|
+
checkSuccess: (receipt: TransactionReceipt) => boolean | undefined,
|
|
852
|
+
slotNumber: bigint,
|
|
853
|
+
timestamp: bigint,
|
|
854
|
+
) {
|
|
855
|
+
const logData = { slotNumber, timestamp, gasLimit: undefined as bigint | undefined };
|
|
856
|
+
let gasUsed: bigint;
|
|
857
|
+
|
|
858
|
+
this.log.debug(`Simulating ${action}`, logData);
|
|
859
|
+
try {
|
|
860
|
+
({ gasUsed } = await this.l1TxUtils.simulate(request, { time: timestamp }, [], ErrorsAbi)); // TODO(palla/slash): Check the timestamp logic
|
|
861
|
+
this.log.verbose(`Simulation for ${action} succeeded`, { ...logData, request, gasUsed });
|
|
862
|
+
} catch (err) {
|
|
863
|
+
const viemError = formatViemError(err);
|
|
864
|
+
this.log.error(`Simulation for ${action} at ${slotNumber} failed`, viemError, logData);
|
|
865
|
+
return false;
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
// We issued the simulation against the rollup contract, so we need to account for the overhead of the multicall3
|
|
869
|
+
const gasLimit = this.l1TxUtils.bumpGasLimit(BigInt(Math.ceil((Number(gasUsed) * 64) / 63)));
|
|
870
|
+
logData.gasLimit = gasLimit;
|
|
871
|
+
|
|
872
|
+
this.log.debug(`Enqueuing ${action}`, logData);
|
|
873
|
+
this.addRequest({
|
|
874
|
+
action,
|
|
875
|
+
request,
|
|
876
|
+
gasConfig: { gasLimit },
|
|
877
|
+
lastValidL2Slot: slotNumber,
|
|
878
|
+
checkSuccess: (_req, result) => {
|
|
879
|
+
const success = result && result.receipt && result.receipt.status === 'success' && checkSuccess(result.receipt);
|
|
880
|
+
if (!success) {
|
|
881
|
+
this.log.warn(`Action ${action} at ${slotNumber} failed`, { ...result, ...logData });
|
|
882
|
+
} else {
|
|
883
|
+
this.log.info(`Action ${action} at ${slotNumber} succeeded`, { ...result, ...logData });
|
|
884
|
+
}
|
|
885
|
+
return !!success;
|
|
886
|
+
},
|
|
887
|
+
});
|
|
888
|
+
return true;
|
|
889
|
+
}
|
|
890
|
+
|
|
740
891
|
/**
|
|
741
892
|
* Calling `interrupt` will cause any in progress call to `publishRollup` to return `false` asap.
|
|
742
893
|
* Be warned, the call may return false even if the tx subsequently gets successfully mined.
|
|
@@ -928,7 +1079,7 @@ export class SequencerPublisher {
|
|
|
928
1079
|
blobs: encodedData.blobs.map(b => b.data),
|
|
929
1080
|
kzg,
|
|
930
1081
|
},
|
|
931
|
-
checkSuccess: (
|
|
1082
|
+
checkSuccess: (_request, result) => {
|
|
932
1083
|
if (!result) {
|
|
933
1084
|
return false;
|
|
934
1085
|
}
|
|
@@ -9,7 +9,7 @@ import { RunningPromise } from '@aztec/foundation/running-promise';
|
|
|
9
9
|
import { type DateProvider, Timer } from '@aztec/foundation/timer';
|
|
10
10
|
import type { TypedEventEmitter } from '@aztec/foundation/types';
|
|
11
11
|
import type { P2P } from '@aztec/p2p';
|
|
12
|
-
import type {
|
|
12
|
+
import type { SlasherClientInterface } from '@aztec/slasher';
|
|
13
13
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
14
14
|
import type { CommitteeAttestation, L2BlockSource, ValidateBlockResult } from '@aztec/stdlib/block';
|
|
15
15
|
import { type L1RollupConstants, getSlotAtTimestamp } from '@aztec/stdlib/epoch-helpers';
|
|
@@ -46,14 +46,10 @@ import {
|
|
|
46
46
|
import type { ValidatorClient } from '@aztec/validator-client';
|
|
47
47
|
|
|
48
48
|
import EventEmitter from 'node:events';
|
|
49
|
+
import type { TypedDataDefinition } from 'viem';
|
|
49
50
|
|
|
50
51
|
import type { GlobalVariableBuilder } from '../global_variable_builder/global_builder.js';
|
|
51
|
-
import {
|
|
52
|
-
type Action,
|
|
53
|
-
type InvalidateBlockRequest,
|
|
54
|
-
type SequencerPublisher,
|
|
55
|
-
SignalType,
|
|
56
|
-
} from '../publisher/sequencer-publisher.js';
|
|
52
|
+
import type { Action, InvalidateBlockRequest, SequencerPublisher } from '../publisher/sequencer-publisher.js';
|
|
57
53
|
import type { SequencerConfig } from './config.js';
|
|
58
54
|
import { SequencerMetrics } from './metrics.js';
|
|
59
55
|
import { SequencerTimetable, SequencerTooSlowError } from './timetable.js';
|
|
@@ -117,7 +113,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
117
113
|
protected globalsBuilder: GlobalVariableBuilder,
|
|
118
114
|
protected p2pClient: P2P,
|
|
119
115
|
protected worldState: WorldStateSynchronizer,
|
|
120
|
-
protected slasherClient:
|
|
116
|
+
protected slasherClient: SlasherClientInterface | undefined,
|
|
121
117
|
protected l2BlockSource: L2BlockSource,
|
|
122
118
|
protected l1ToL2MessageSource: L1ToL2MessageSource,
|
|
123
119
|
protected blockBuilder: IFullNodeBlockBuilder,
|
|
@@ -142,9 +138,6 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
142
138
|
[publisher.getSenderAddress()],
|
|
143
139
|
);
|
|
144
140
|
|
|
145
|
-
// Register the slasher on the publisher to fetch slashing payloads
|
|
146
|
-
this.publisher.registerSlashPayloadGetter(this.slasherClient.getSlashPayload.bind(this.slasherClient));
|
|
147
|
-
|
|
148
141
|
// Initialize config
|
|
149
142
|
this.updateConfig(this.config);
|
|
150
143
|
}
|
|
@@ -415,22 +408,21 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
415
408
|
slot,
|
|
416
409
|
);
|
|
417
410
|
|
|
418
|
-
const
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
SignalType.GOVERNANCE,
|
|
422
|
-
proposerAddress,
|
|
423
|
-
msg => this.validatorClient!.signWithAddress(proposerAddress, msg).then(s => s.toString()),
|
|
424
|
-
);
|
|
411
|
+
const { timestamp } = newGlobalVariables;
|
|
412
|
+
const signerFn = (msg: TypedDataDefinition) =>
|
|
413
|
+
this.validatorClient!.signWithAddress(proposerAddress, msg).then(s => s.toString());
|
|
425
414
|
|
|
426
|
-
const
|
|
415
|
+
const enqueueGovernanceSignalPromise = this.publisher.enqueueGovernanceCastSignal(
|
|
427
416
|
slot,
|
|
428
|
-
|
|
429
|
-
SignalType.SLASHING,
|
|
417
|
+
timestamp,
|
|
430
418
|
proposerAddress,
|
|
431
|
-
|
|
419
|
+
signerFn,
|
|
432
420
|
);
|
|
433
421
|
|
|
422
|
+
const enqueueSlashingActionsPromise = this.slasherClient
|
|
423
|
+
?.getProposerActions(slot)
|
|
424
|
+
?.then(actions => this.publisher.enqueueSlashingActions(actions, slot, timestamp, proposerAddress, signerFn));
|
|
425
|
+
|
|
434
426
|
if (invalidateBlock && !this.config.skipInvalidateBlockAsProposer) {
|
|
435
427
|
this.publisher.enqueueInvalidateBlock(invalidateBlock);
|
|
436
428
|
}
|
|
@@ -484,11 +476,11 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
484
476
|
this.emit('tx-count-check-failed', { minTxs: this.minTxsPerBlock, availableTxs: pendingTxCount });
|
|
485
477
|
}
|
|
486
478
|
|
|
487
|
-
await
|
|
479
|
+
await enqueueGovernanceSignalPromise?.catch(err => {
|
|
488
480
|
this.log.error(`Error enqueuing governance vote`, err, { blockNumber: newBlockNumber, slot });
|
|
489
481
|
});
|
|
490
|
-
await
|
|
491
|
-
this.log.error(`Error enqueuing slashing
|
|
482
|
+
await enqueueSlashingActionsPromise?.catch(err => {
|
|
483
|
+
this.log.error(`Error enqueuing slashing actions`, err, { blockNumber: newBlockNumber, slot });
|
|
492
484
|
});
|
|
493
485
|
|
|
494
486
|
const l1Response = await this.publisher.sendRequests();
|
|
@@ -781,12 +773,8 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
781
773
|
// Publishes new block to the network and awaits the tx to be mined
|
|
782
774
|
this.setState(SequencerState.PUBLISHING_BLOCK, block.header.globalVariables.slotNumber.toBigInt());
|
|
783
775
|
|
|
784
|
-
// Time out tx at the end of the slot
|
|
785
|
-
const slot = block.header.globalVariables.slotNumber.toNumber();
|
|
786
|
-
const txTimeoutAt = new Date((this.getSlotStartBuildTimestamp(slot) + this.aztecSlotDuration) * 1000);
|
|
787
|
-
|
|
788
776
|
const enqueued = await this.publisher.enqueueProposeL2Block(block, attestations, txHashes, {
|
|
789
|
-
txTimeoutAt,
|
|
777
|
+
txTimeoutAt: this.getTxTimeoutForSlot(block.slot),
|
|
790
778
|
forcePendingBlockNumber: invalidateBlock?.forcePendingBlockNumber,
|
|
791
779
|
});
|
|
792
780
|
|
|
@@ -942,6 +930,10 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
942
930
|
);
|
|
943
931
|
}
|
|
944
932
|
|
|
933
|
+
private getTxTimeoutForSlot(slotNumber: number | bigint): Date {
|
|
934
|
+
return new Date((this.getSlotStartBuildTimestamp(slotNumber) + this.aztecSlotDuration) * 1000);
|
|
935
|
+
}
|
|
936
|
+
|
|
945
937
|
private getSecondsIntoSlot(slotNumber: number | bigint): number {
|
|
946
938
|
const slotStartTimestamp = this.getSlotStartBuildTimestamp(slotNumber);
|
|
947
939
|
return Number((this.dateProvider.now() / 1000 - slotStartTimestamp).toFixed(3));
|
|
@@ -967,7 +959,7 @@ export class Sequencer extends (EventEmitter as new () => TypedEventEmitter<Sequ
|
|
|
967
959
|
return this.config.maxL2BlockGas;
|
|
968
960
|
}
|
|
969
961
|
|
|
970
|
-
public getSlasherClient():
|
|
962
|
+
public getSlasherClient(): SlasherClientInterface | undefined {
|
|
971
963
|
return this.slasherClient;
|
|
972
964
|
}
|
|
973
965
|
}
|