@aztec/ethereum 0.0.1-commit.2d9cb6034 → 0.0.1-commit.2e20a94
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/config.d.ts +6 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +5 -9
- package/dest/contracts/chain_state_override.d.ts +38 -0
- package/dest/contracts/chain_state_override.d.ts.map +1 -0
- package/dest/contracts/chain_state_override.js +100 -0
- package/dest/contracts/inbox.d.ts +3 -3
- package/dest/contracts/inbox.d.ts.map +1 -1
- package/dest/contracts/inbox.js +5 -6
- package/dest/contracts/index.d.ts +3 -3
- package/dest/contracts/index.d.ts.map +1 -1
- package/dest/contracts/index.js +2 -2
- package/dest/contracts/rollup.d.ts +48 -21
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +93 -45
- package/dest/contracts/{tally_slashing_proposer.d.ts → slashing_proposer.d.ts} +3 -4
- package/dest/contracts/slashing_proposer.d.ts.map +1 -0
- package/dest/contracts/{tally_slashing_proposer.js → slashing_proposer.js} +13 -15
- package/dest/deploy_aztec_l1_contracts.d.ts +3 -6
- package/dest/deploy_aztec_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_aztec_l1_contracts.js +2 -4
- package/dest/generated/l1-contracts-defaults.d.ts +1 -1
- package/dest/generated/l1-contracts-defaults.js +1 -1
- package/dest/l1_artifacts.d.ts +8644 -15983
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +9 -24
- package/dest/l1_contract_addresses.d.ts +1 -5
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +0 -6
- package/dest/l1_tx_utils/l1_tx_utils.js +1 -1
- package/dest/queries.js +3 -3
- package/dest/test/rollup_cheat_codes.d.ts +5 -1
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +9 -1
- package/package.json +5 -5
- package/src/config.ts +9 -13
- package/src/contracts/chain_state_override.ts +147 -0
- package/src/contracts/inbox.ts +4 -4
- package/src/contracts/index.ts +2 -2
- package/src/contracts/rollup.ts +100 -47
- package/src/contracts/{tally_slashing_proposer.ts → slashing_proposer.ts} +14 -16
- package/src/deploy_aztec_l1_contracts.ts +1 -5
- package/src/generated/l1-contracts-defaults.ts +1 -1
- package/src/l1_artifacts.ts +12 -35
- package/src/l1_contract_addresses.ts +0 -7
- package/src/l1_tx_utils/l1_tx_utils.ts +1 -1
- package/src/queries.ts +3 -3
- package/src/test/rollup_cheat_codes.ts +11 -1
- package/dest/contracts/empire_slashing_proposer.d.ts +0 -69
- package/dest/contracts/empire_slashing_proposer.d.ts.map +0 -1
- package/dest/contracts/empire_slashing_proposer.js +0 -216
- package/dest/contracts/tally_slashing_proposer.d.ts.map +0 -1
- package/src/contracts/empire_slashing_proposer.ts +0 -265
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aztec/ethereum",
|
|
3
|
-
"version": "0.0.1-commit.
|
|
3
|
+
"version": "0.0.1-commit.2e20a94",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
"./account": "./dest/account.js",
|
|
@@ -50,10 +50,10 @@
|
|
|
50
50
|
"../package.common.json"
|
|
51
51
|
],
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@aztec/blob-lib": "0.0.1-commit.
|
|
54
|
-
"@aztec/constants": "0.0.1-commit.
|
|
55
|
-
"@aztec/foundation": "0.0.1-commit.
|
|
56
|
-
"@aztec/l1-artifacts": "0.0.1-commit.
|
|
53
|
+
"@aztec/blob-lib": "0.0.1-commit.2e20a94",
|
|
54
|
+
"@aztec/constants": "0.0.1-commit.2e20a94",
|
|
55
|
+
"@aztec/foundation": "0.0.1-commit.2e20a94",
|
|
56
|
+
"@aztec/l1-artifacts": "0.0.1-commit.2e20a94",
|
|
57
57
|
"dotenv": "^16.0.3",
|
|
58
58
|
"lodash.chunk": "^4.2.0",
|
|
59
59
|
"lodash.pickby": "^4.5.0",
|
package/src/config.ts
CHANGED
|
@@ -2,7 +2,6 @@ import {
|
|
|
2
2
|
type ConfigMappingsType,
|
|
3
3
|
bigintConfigHelper,
|
|
4
4
|
booleanConfigHelper,
|
|
5
|
-
enumConfigHelper,
|
|
6
5
|
getConfigFromMappings,
|
|
7
6
|
getDefaultConfig,
|
|
8
7
|
numberConfigHelper,
|
|
@@ -60,13 +59,13 @@ export type L1ContractsConfig = {
|
|
|
60
59
|
slashingOffsetInRounds: number;
|
|
61
60
|
/** How long slashing can be disabled for in seconds when vetoer disables it */
|
|
62
61
|
slashingDisableDuration: number;
|
|
63
|
-
/**
|
|
64
|
-
|
|
65
|
-
/** Minimum amount that can be slashed
|
|
62
|
+
/** Whether to deploy a slasher proposer */
|
|
63
|
+
slasherEnabled: boolean;
|
|
64
|
+
/** Minimum amount that can be slashed */
|
|
66
65
|
slashAmountSmall: bigint;
|
|
67
|
-
/** Medium amount to slash
|
|
66
|
+
/** Medium amount to slash */
|
|
68
67
|
slashAmountMedium: bigint;
|
|
69
|
-
/** Largest amount that can be slashed per round
|
|
68
|
+
/** Largest amount that can be slashed per round */
|
|
70
69
|
slashAmountLarge: bigint;
|
|
71
70
|
/** Governance proposing quorum (defaults to roundSize/2 + 1) */
|
|
72
71
|
governanceProposerQuorum?: number;
|
|
@@ -152,13 +151,10 @@ export const l1ContractsConfigMappings: ConfigMappingsType<L1ContractsConfig> =
|
|
|
152
151
|
'How many slashing rounds back we slash (ie when slashing in round N, we slash for offenses committed during epochs of round N-offset)',
|
|
153
152
|
...numberConfigHelper(l1ContractsDefaultEnv.AZTEC_SLASHING_OFFSET_IN_ROUNDS),
|
|
154
153
|
},
|
|
155
|
-
|
|
156
|
-
env: '
|
|
157
|
-
description: '
|
|
158
|
-
...
|
|
159
|
-
['empire', 'tally', 'none'] as const,
|
|
160
|
-
l1ContractsDefaultEnv.AZTEC_SLASHER_FLAVOR as 'empire' | 'tally' | 'none',
|
|
161
|
-
),
|
|
154
|
+
slasherEnabled: {
|
|
155
|
+
env: 'AZTEC_SLASHER_ENABLED',
|
|
156
|
+
description: 'Whether to deploy a slasher proposer',
|
|
157
|
+
...booleanConfigHelper(true),
|
|
162
158
|
},
|
|
163
159
|
slashAmountSmall: {
|
|
164
160
|
env: 'AZTEC_SLASH_AMOUNT_SMALL',
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { toHex as toPaddedHex } from '@aztec/foundation/bigint-buffer';
|
|
2
|
+
import type { CheckpointNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
|
+
|
|
5
|
+
import type { StateOverride } from 'viem';
|
|
6
|
+
|
|
7
|
+
import { type FeeHeader, RollupContract } from './rollup.js';
|
|
8
|
+
|
|
9
|
+
export type PendingCheckpointOverrideState = {
|
|
10
|
+
archive?: Fr;
|
|
11
|
+
feeHeader?: FeeHeader;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** Describes the simulated L1 rollup state that downstream calls should observe. */
|
|
15
|
+
export type SimulationOverridesPlan = {
|
|
16
|
+
pendingCheckpointNumber?: CheckpointNumber;
|
|
17
|
+
pendingCheckpointState?: PendingCheckpointOverrideState;
|
|
18
|
+
disableBlobCheck?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/** Builds a single-checkpoint simulation plan before it is translated into a viem state override. */
|
|
22
|
+
export class SimulationOverridesBuilder {
|
|
23
|
+
private pendingCheckpointNumber?: CheckpointNumber;
|
|
24
|
+
private pendingCheckpointState?: PendingCheckpointOverrideState;
|
|
25
|
+
private disableBlobCheck = false;
|
|
26
|
+
|
|
27
|
+
/** Starts from an existing plan so callers can extend or specialize it. */
|
|
28
|
+
public static from(plan: SimulationOverridesPlan | undefined): SimulationOverridesBuilder {
|
|
29
|
+
return new SimulationOverridesBuilder().merge(plan);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Merges another plan into this builder. Later values win. */
|
|
33
|
+
public merge(plan: SimulationOverridesPlan | undefined): this {
|
|
34
|
+
if (!plan) {
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
this.pendingCheckpointNumber = plan.pendingCheckpointNumber;
|
|
39
|
+
this.pendingCheckpointState = plan.pendingCheckpointState
|
|
40
|
+
? { ...(this.pendingCheckpointState ?? {}), ...plan.pendingCheckpointState }
|
|
41
|
+
: this.pendingCheckpointState;
|
|
42
|
+
this.disableBlobCheck = this.disableBlobCheck || (plan.disableBlobCheck ?? false);
|
|
43
|
+
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Sets the checkpoint number that archive and fee header overrides should attach to. */
|
|
48
|
+
public forPendingCheckpoint(pendingCheckpointNumber: CheckpointNumber | undefined): this {
|
|
49
|
+
this.pendingCheckpointNumber = pendingCheckpointNumber;
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Overrides the archive root for the configured pending checkpoint. */
|
|
54
|
+
public withPendingArchive(archive: Fr): this {
|
|
55
|
+
this.assertPendingCheckpointNumber();
|
|
56
|
+
this.pendingCheckpointState = { ...(this.pendingCheckpointState ?? {}), archive };
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Overrides the fee header for the configured pending checkpoint. */
|
|
61
|
+
public withPendingFeeHeader(feeHeader: FeeHeader): this {
|
|
62
|
+
this.assertPendingCheckpointNumber();
|
|
63
|
+
this.pendingCheckpointState = { ...(this.pendingCheckpointState ?? {}), feeHeader };
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Disables blob checking for simulations that cannot provide DA inputs. */
|
|
68
|
+
public withoutBlobCheck(): this {
|
|
69
|
+
this.disableBlobCheck = true;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Builds the final plan, or `undefined` when no overrides were configured. */
|
|
74
|
+
public build(): SimulationOverridesPlan | undefined {
|
|
75
|
+
if (!this.pendingCheckpointState && this.pendingCheckpointNumber === undefined && !this.disableBlobCheck) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
pendingCheckpointNumber: this.pendingCheckpointNumber,
|
|
81
|
+
pendingCheckpointState: this.pendingCheckpointState,
|
|
82
|
+
disableBlobCheck: this.disableBlobCheck || undefined,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private assertPendingCheckpointNumber(): void {
|
|
87
|
+
if (this.pendingCheckpointNumber === undefined) {
|
|
88
|
+
throw new Error('pendingCheckpointNumber must be set before attaching archive or fee header overrides');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Translates a simulation plan into the viem state override shape expected by rollup calls. */
|
|
94
|
+
export async function buildSimulationOverridesStateOverride(
|
|
95
|
+
rollup: RollupContract,
|
|
96
|
+
plan: SimulationOverridesPlan | undefined,
|
|
97
|
+
): Promise<StateOverride> {
|
|
98
|
+
if (!plan) {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const rollupStateDiff: NonNullable<StateOverride[number]['stateDiff']> = [];
|
|
103
|
+
|
|
104
|
+
if (plan.pendingCheckpointNumber !== undefined) {
|
|
105
|
+
rollupStateDiff.push(
|
|
106
|
+
...extractRollupStateDiff(await rollup.makePendingCheckpointNumberOverride(plan.pendingCheckpointNumber)),
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (plan.pendingCheckpointState && plan.pendingCheckpointNumber === undefined) {
|
|
111
|
+
throw new Error('pendingCheckpointState requires pendingCheckpointNumber to be set');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (plan.pendingCheckpointState?.archive) {
|
|
115
|
+
rollupStateDiff.push(
|
|
116
|
+
...extractRollupStateDiff(
|
|
117
|
+
rollup.makeArchiveOverride(plan.pendingCheckpointNumber!, plan.pendingCheckpointState.archive),
|
|
118
|
+
),
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (plan.pendingCheckpointState?.feeHeader) {
|
|
123
|
+
rollupStateDiff.push(
|
|
124
|
+
...extractRollupStateDiff(
|
|
125
|
+
await rollup.makeFeeHeaderOverride(plan.pendingCheckpointNumber!, plan.pendingCheckpointState.feeHeader),
|
|
126
|
+
),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (plan.disableBlobCheck) {
|
|
131
|
+
rollupStateDiff.push({
|
|
132
|
+
slot: toPaddedHex(RollupContract.checkBlobStorageSlot, true),
|
|
133
|
+
value: toPaddedHex(0n, true),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (rollupStateDiff.length === 0) {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return [{ address: rollup.address, stateDiff: rollupStateDiff }];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function extractRollupStateDiff(override: StateOverride | StateOverride[number] | undefined) {
|
|
145
|
+
const entries = Array.isArray(override) ? override : override ? [override] : [];
|
|
146
|
+
return entries.flatMap(entry => entry.stateDiff ?? []);
|
|
147
|
+
}
|
package/src/contracts/inbox.ts
CHANGED
|
@@ -82,10 +82,10 @@ export class InboxContract {
|
|
|
82
82
|
.map(log => this.mapMessageSentLog(log));
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
/** Fetches MessageSent events for a specific message hash
|
|
86
|
-
async getMessageSentEventByHash(
|
|
87
|
-
const
|
|
88
|
-
return
|
|
85
|
+
/** Fetches MessageSent events for a specific message hash at a specific block. */
|
|
86
|
+
async getMessageSentEventByHash(msgHash: Hex, l1BlockHash: Hex): Promise<MessageSentLog> {
|
|
87
|
+
const [log] = await this.inbox.getEvents.MessageSent({ hash: msgHash }, { blockHash: l1BlockHash });
|
|
88
|
+
return log && this.mapMessageSentLog(log);
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
private mapMessageSentLog(log: {
|
package/src/contracts/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export * from './chain_state_override.js';
|
|
1
2
|
export * from './empire_base.js';
|
|
2
3
|
export * from './errors.js';
|
|
3
4
|
export * from './fee_asset_handler.js';
|
|
@@ -12,6 +13,5 @@ export * from './multicall.js';
|
|
|
12
13
|
export * from './outbox.js';
|
|
13
14
|
export * from './registry.js';
|
|
14
15
|
export * from './rollup.js';
|
|
15
|
-
export * from './
|
|
16
|
-
export * from './tally_slashing_proposer.js';
|
|
16
|
+
export * from './slashing_proposer.js';
|
|
17
17
|
export * from './slasher_contract.js';
|
package/src/contracts/rollup.ts
CHANGED
|
@@ -31,11 +31,10 @@ import type { L1ReaderConfig } from '../l1_reader.js';
|
|
|
31
31
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
32
32
|
import type { ViemClient } from '../types.js';
|
|
33
33
|
import { formatViemError } from '../utils.js';
|
|
34
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
35
34
|
import { GSEContract } from './gse.js';
|
|
36
35
|
import type { L1EventLog } from './log.js';
|
|
37
36
|
import { SlasherContract } from './slasher_contract.js';
|
|
38
|
-
import {
|
|
37
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
39
38
|
import { checkBlockTag } from './utils.js';
|
|
40
39
|
|
|
41
40
|
export type ViemCommitteeAttestation = {
|
|
@@ -57,7 +56,6 @@ export type L1RollupContractAddresses = Pick<
|
|
|
57
56
|
| 'feeJuiceAddress'
|
|
58
57
|
| 'stakingAssetAddress'
|
|
59
58
|
| 'rewardDistributorAddress'
|
|
60
|
-
| 'slashFactoryAddress'
|
|
61
59
|
| 'gseAddress'
|
|
62
60
|
>;
|
|
63
61
|
|
|
@@ -87,12 +85,6 @@ export type ViemGasFees = {
|
|
|
87
85
|
feePerL2Gas: bigint;
|
|
88
86
|
};
|
|
89
87
|
|
|
90
|
-
export enum SlashingProposerType {
|
|
91
|
-
None = 0,
|
|
92
|
-
Tally = 1,
|
|
93
|
-
Empire = 2,
|
|
94
|
-
}
|
|
95
|
-
|
|
96
88
|
/**
|
|
97
89
|
* Status of a validator/attester in the staking system.
|
|
98
90
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -136,6 +128,17 @@ export type L1FeeData = {
|
|
|
136
128
|
blobFee: bigint;
|
|
137
129
|
};
|
|
138
130
|
|
|
131
|
+
/** Field offsets within the CompressedTempCheckpointLog struct in Solidity storage. */
|
|
132
|
+
export enum TempCheckpointLogField {
|
|
133
|
+
HeaderHash = 0,
|
|
134
|
+
BlobCommitmentsHash = 1,
|
|
135
|
+
OutHash = 2,
|
|
136
|
+
AttestationsHash = 3,
|
|
137
|
+
PayloadDigest = 4,
|
|
138
|
+
SlotNumber = 5,
|
|
139
|
+
FeeHeader = 6,
|
|
140
|
+
}
|
|
141
|
+
|
|
139
142
|
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
140
143
|
export type ManaMinFeeComponents = {
|
|
141
144
|
sequencerCost: bigint;
|
|
@@ -270,34 +273,18 @@ export class RollupContract {
|
|
|
270
273
|
return this.rollup;
|
|
271
274
|
}
|
|
272
275
|
|
|
273
|
-
public async getSlashingProposer(): Promise<
|
|
274
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
275
|
-
> {
|
|
276
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
276
277
|
const slasher = await this.getSlasherContract();
|
|
277
278
|
if (!slasher) {
|
|
278
279
|
return undefined;
|
|
279
280
|
}
|
|
280
281
|
|
|
281
282
|
const proposerAddress = await slasher.getProposer();
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
type: 'function',
|
|
285
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
286
|
-
inputs: [],
|
|
287
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
288
|
-
stateMutability: 'view',
|
|
289
|
-
},
|
|
290
|
-
] as const;
|
|
291
|
-
|
|
292
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
293
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
294
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
295
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
296
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
297
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
298
|
-
} else {
|
|
299
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
283
|
+
if (proposerAddress.isZero()) {
|
|
284
|
+
return undefined;
|
|
300
285
|
}
|
|
286
|
+
|
|
287
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
301
288
|
}
|
|
302
289
|
|
|
303
290
|
@memoize
|
|
@@ -538,8 +525,9 @@ export class RollupContract {
|
|
|
538
525
|
return this.rollup.read.getCheckpointReward();
|
|
539
526
|
}
|
|
540
527
|
|
|
541
|
-
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
542
|
-
|
|
528
|
+
async getCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
529
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
530
|
+
return CheckpointNumber.fromBigInt(await this.rollup.read.getPendingCheckpointNumber(options));
|
|
543
531
|
}
|
|
544
532
|
|
|
545
533
|
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
@@ -547,18 +535,31 @@ export class RollupContract {
|
|
|
547
535
|
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
548
536
|
}
|
|
549
537
|
|
|
550
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
551
|
-
|
|
538
|
+
async getSlotNumber(options?: { blockNumber?: bigint }): Promise<SlotNumber> {
|
|
539
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
540
|
+
return SlotNumber.fromBigInt(await this.rollup.read.getCurrentSlot(options));
|
|
552
541
|
}
|
|
553
542
|
|
|
554
|
-
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
555
|
-
|
|
543
|
+
async getL1FeesAt(timestamp: bigint, options?: { blockNumber?: bigint }): Promise<L1FeeData> {
|
|
544
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
545
|
+
const result = await this.rollup.read.getL1FeesAt([timestamp], options);
|
|
556
546
|
return {
|
|
557
547
|
baseFee: result.baseFee,
|
|
558
548
|
blobFee: result.blobFee,
|
|
559
549
|
};
|
|
560
550
|
}
|
|
561
551
|
|
|
552
|
+
async getFeeHeader(checkpointNumber: bigint): Promise<FeeHeader> {
|
|
553
|
+
const result = await this.rollup.read.getFeeHeader([checkpointNumber]);
|
|
554
|
+
return {
|
|
555
|
+
excessMana: result.excessMana,
|
|
556
|
+
manaUsed: result.manaUsed,
|
|
557
|
+
ethPerFeeAsset: result.ethPerFeeAsset,
|
|
558
|
+
congestionCost: result.congestionCost,
|
|
559
|
+
proverCost: result.proverCost,
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
|
|
562
563
|
getEthPerFeeAsset(): Promise<bigint> {
|
|
563
564
|
return this.rollup.read.getEthPerFeeAsset();
|
|
564
565
|
}
|
|
@@ -633,8 +634,9 @@ export class RollupContract {
|
|
|
633
634
|
return EthAddress.fromString(result);
|
|
634
635
|
}
|
|
635
636
|
|
|
636
|
-
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
637
|
-
|
|
637
|
+
async getCheckpoint(checkpointNumber: CheckpointNumber, options?: { blockNumber?: bigint }): Promise<CheckpointLog> {
|
|
638
|
+
await checkBlockTag(options?.blockNumber, this.client);
|
|
639
|
+
const result = await this.rollup.read.getCheckpoint([BigInt(checkpointNumber)], options);
|
|
638
640
|
return {
|
|
639
641
|
archive: Fr.fromString(result.archive),
|
|
640
642
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -667,6 +669,30 @@ export class RollupContract {
|
|
|
667
669
|
);
|
|
668
670
|
}
|
|
669
671
|
|
|
672
|
+
/**
|
|
673
|
+
* Returns the effective pending checkpoint, accounting for potential prunes.
|
|
674
|
+
* When a prune can happen, the L1 contract uses the proven checkpoint instead of the pending one.
|
|
675
|
+
* This mirrors the behavior of getEffectivePendingCheckpointNumber in STFLib.sol.
|
|
676
|
+
* @param atTimestamp - The timestamp to evaluate pruneability at. Defaults to the current L1 block timestamp.
|
|
677
|
+
* @param options - Optional L1 block number to pin the queries to.
|
|
678
|
+
*/
|
|
679
|
+
getEffectivePendingCheckpoint(atTimestamp?: bigint, options?: { blockNumber?: bigint }) {
|
|
680
|
+
return retry(
|
|
681
|
+
async () => {
|
|
682
|
+
const timestamp = atTimestamp ?? (await this.client.getBlock()).timestamp;
|
|
683
|
+
const canPrune = await this.canPruneAtTime(timestamp, options);
|
|
684
|
+
if (canPrune) {
|
|
685
|
+
const provenCheckpointNumber = await this.getProvenCheckpointNumber(options);
|
|
686
|
+
return await this.getCheckpoint(provenCheckpointNumber, options);
|
|
687
|
+
}
|
|
688
|
+
const pendingCheckpointNumber = await this.getCheckpointNumber(options);
|
|
689
|
+
return await this.getCheckpoint(pendingCheckpointNumber, options);
|
|
690
|
+
},
|
|
691
|
+
'getting effective pending checkpoint',
|
|
692
|
+
makeBackoff([0.5, 0.5, 0.5]),
|
|
693
|
+
);
|
|
694
|
+
}
|
|
695
|
+
|
|
670
696
|
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
671
697
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
672
698
|
return {
|
|
@@ -789,19 +815,11 @@ export class RollupContract {
|
|
|
789
815
|
archive: Buffer,
|
|
790
816
|
account: `0x${string}` | Account,
|
|
791
817
|
timestamp: bigint,
|
|
792
|
-
|
|
793
|
-
forcePendingCheckpointNumber?: CheckpointNumber;
|
|
794
|
-
forceArchive?: { checkpointNumber: CheckpointNumber; archive: Fr };
|
|
795
|
-
} = {},
|
|
818
|
+
stateOverride: StateOverride = [],
|
|
796
819
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
797
820
|
const timeOfNextL1Slot = timestamp;
|
|
798
821
|
const who = typeof account === 'string' ? account : account.address;
|
|
799
822
|
|
|
800
|
-
const stateOverride = RollupContract.mergeStateOverrides(
|
|
801
|
-
await this.makePendingCheckpointNumberOverride(opts.forcePendingCheckpointNumber),
|
|
802
|
-
opts.forceArchive ? this.makeArchiveOverride(opts.forceArchive.checkpointNumber, opts.forceArchive.archive) : [],
|
|
803
|
-
);
|
|
804
|
-
|
|
805
823
|
try {
|
|
806
824
|
const {
|
|
807
825
|
result: [slot, checkpointNumber],
|
|
@@ -1280,4 +1298,39 @@ export class RollupContract {
|
|
|
1280
1298
|
},
|
|
1281
1299
|
}));
|
|
1282
1300
|
}
|
|
1301
|
+
|
|
1302
|
+
/** Packs pending and proven checkpoint numbers into the chain tips storage format. */
|
|
1303
|
+
static packChainTips(pendingCheckpointNumber: bigint, provenCheckpointNumber: bigint): bigint {
|
|
1304
|
+
return (pendingCheckpointNumber << 128n) | (provenCheckpointNumber & ((1n << 128n) - 1n));
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
/** Storage slot for the chain tips (offset 0 within the STF storage struct). */
|
|
1308
|
+
static get chainTipsStorageSlot(): bigint {
|
|
1309
|
+
return BigInt(RollupContract.stfStorageSlot);
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
/**
|
|
1313
|
+
* Computes the storage slot for a field within a tempCheckpointLog entry.
|
|
1314
|
+
* @param checkpointNumber - The checkpoint number
|
|
1315
|
+
* @param field - The field within the CompressedTempCheckpointLog struct
|
|
1316
|
+
*/
|
|
1317
|
+
async getTempCheckpointLogStorageSlot(
|
|
1318
|
+
checkpointNumber: CheckpointNumber,
|
|
1319
|
+
field: TempCheckpointLogField,
|
|
1320
|
+
): Promise<bigint> {
|
|
1321
|
+
const fieldOffset = BigInt(field);
|
|
1322
|
+
const [epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
1323
|
+
this.getEpochDuration(),
|
|
1324
|
+
this.getProofSubmissionEpochs(),
|
|
1325
|
+
]);
|
|
1326
|
+
const roundaboutSize = BigInt(epochDuration) * (BigInt(proofSubmissionEpochs) + 1n) + 1n;
|
|
1327
|
+
const tempCheckpointLogsBase = BigInt(RollupContract.stfStorageSlot) + 2n;
|
|
1328
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
1329
|
+
const entryBase = BigInt(
|
|
1330
|
+
keccak256(
|
|
1331
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsBase]),
|
|
1332
|
+
),
|
|
1333
|
+
);
|
|
1334
|
+
return entryBase + fieldOffset;
|
|
1335
|
+
}
|
|
1283
1336
|
}
|
|
@@ -7,7 +7,7 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
7
7
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
8
8
|
import { hexToBuffer } from '@aztec/foundation/string';
|
|
9
9
|
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
|
|
10
|
-
import {
|
|
10
|
+
import { SlashingProposerAbi } from '@aztec/l1-artifacts/SlashingProposerAbi';
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
type GetContractReturnType,
|
|
@@ -19,13 +19,11 @@ import {
|
|
|
19
19
|
} from 'viem';
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
|
-
* Wrapper around the
|
|
22
|
+
* Wrapper around the SlashingProposer contract that provides
|
|
23
23
|
* a TypeScript interface for interacting with the consensus-based slashing system.
|
|
24
24
|
*/
|
|
25
|
-
export class
|
|
26
|
-
private readonly contract: GetContractReturnType<typeof
|
|
27
|
-
|
|
28
|
-
public readonly type = 'tally' as const;
|
|
25
|
+
export class SlashingProposerContract {
|
|
26
|
+
private readonly contract: GetContractReturnType<typeof SlashingProposerAbi, ViemClient>;
|
|
29
27
|
|
|
30
28
|
constructor(
|
|
31
29
|
public readonly client: ViemClient,
|
|
@@ -33,7 +31,7 @@ export class TallySlashingProposerContract {
|
|
|
33
31
|
) {
|
|
34
32
|
this.contract = getContract({
|
|
35
33
|
address: typeof address === 'string' ? address : address.toString(),
|
|
36
|
-
abi:
|
|
34
|
+
abi: SlashingProposerAbi,
|
|
37
35
|
client,
|
|
38
36
|
});
|
|
39
37
|
}
|
|
@@ -136,12 +134,12 @@ export class TallySlashingProposerContract {
|
|
|
136
134
|
|
|
137
135
|
/** Tries to extract a VoteCast event from the given logs. */
|
|
138
136
|
public tryExtractVoteCastEvent(logs: Log[]) {
|
|
139
|
-
return tryExtractEvent(logs, this.address.toString(),
|
|
137
|
+
return tryExtractEvent(logs, this.address.toString(), SlashingProposerAbi, 'VoteCast');
|
|
140
138
|
}
|
|
141
139
|
|
|
142
140
|
/** Tries to extract a RoundExecuted event from the given logs. */
|
|
143
141
|
public tryExtractRoundExecutedEvent(logs: Log[]) {
|
|
144
|
-
return tryExtractEvent(logs, this.address.toString(),
|
|
142
|
+
return tryExtractEvent(logs, this.address.toString(), SlashingProposerAbi, 'RoundExecuted');
|
|
145
143
|
}
|
|
146
144
|
|
|
147
145
|
/**
|
|
@@ -161,9 +159,9 @@ export class TallySlashingProposerContract {
|
|
|
161
159
|
|
|
162
160
|
return {
|
|
163
161
|
to: this.contract.address,
|
|
164
|
-
abi:
|
|
162
|
+
abi: SlashingProposerAbi,
|
|
165
163
|
data: encodeFunctionData({
|
|
166
|
-
abi:
|
|
164
|
+
abi: SlashingProposerAbi,
|
|
167
165
|
functionName: 'vote',
|
|
168
166
|
args: [votes, signature.toViemSignature()],
|
|
169
167
|
}),
|
|
@@ -173,7 +171,7 @@ export class TallySlashingProposerContract {
|
|
|
173
171
|
/** Returns the typed data definition to EIP712-sign for voting */
|
|
174
172
|
public buildVoteTypedData(votes: Hex, slot: SlotNumber): TypedDataDefinition {
|
|
175
173
|
const domain = {
|
|
176
|
-
name: '
|
|
174
|
+
name: 'SlashingProposer',
|
|
177
175
|
version: '1',
|
|
178
176
|
chainId: this.client.chain.id,
|
|
179
177
|
verifyingContract: this.contract.address,
|
|
@@ -209,9 +207,9 @@ export class TallySlashingProposerContract {
|
|
|
209
207
|
public buildVoteRequestWithSignature(votes: Hex, signature: { v: number; r: Hex; s: Hex }): L1TxRequest {
|
|
210
208
|
return {
|
|
211
209
|
to: this.contract.address,
|
|
212
|
-
abi:
|
|
210
|
+
abi: SlashingProposerAbi,
|
|
213
211
|
data: encodeFunctionData({
|
|
214
|
-
abi:
|
|
212
|
+
abi: SlashingProposerAbi,
|
|
215
213
|
functionName: 'vote',
|
|
216
214
|
args: [votes, signature],
|
|
217
215
|
}),
|
|
@@ -227,9 +225,9 @@ export class TallySlashingProposerContract {
|
|
|
227
225
|
public buildExecuteRoundRequest(round: bigint, committees: EthAddress[][]): L1TxRequest {
|
|
228
226
|
return {
|
|
229
227
|
to: this.contract.address,
|
|
230
|
-
abi: mergeAbis([
|
|
228
|
+
abi: mergeAbis([SlashingProposerAbi, SlasherAbi]),
|
|
231
229
|
data: encodeFunctionData({
|
|
232
|
-
abi:
|
|
230
|
+
abi: SlashingProposerAbi,
|
|
233
231
|
functionName: 'executeRound',
|
|
234
232
|
args: [round, committees.map(c => c.map(addr => addr.toString()))],
|
|
235
233
|
}),
|
|
@@ -230,7 +230,6 @@ export function computeValidatorData(operator: Operator): ValidatorJson {
|
|
|
230
230
|
export interface RollupUpgradeAddresses {
|
|
231
231
|
rollupAddress: string;
|
|
232
232
|
verifierAddress: string;
|
|
233
|
-
slashFactoryAddress: string;
|
|
234
233
|
inboxAddress: string;
|
|
235
234
|
outboxAddress: string;
|
|
236
235
|
feeJuicePortalAddress: string;
|
|
@@ -243,7 +242,6 @@ export interface RollupUpgradeAddresses {
|
|
|
243
242
|
export interface ForgeRollupUpgradeResult {
|
|
244
243
|
rollupAddress: Hex;
|
|
245
244
|
verifierAddress: Hex;
|
|
246
|
-
slashFactoryAddress: Hex;
|
|
247
245
|
inboxAddress: Hex;
|
|
248
246
|
outboxAddress: Hex;
|
|
249
247
|
feeJuicePortalAddress: Hex;
|
|
@@ -403,7 +401,6 @@ export async function deployAztecL1Contracts(
|
|
|
403
401
|
governanceProposerAddress: EthAddress.fromString(result.governanceProposerAddress),
|
|
404
402
|
governanceAddress: EthAddress.fromString(result.governanceAddress),
|
|
405
403
|
stakingAssetAddress: EthAddress.fromString(result.stakingAssetAddress),
|
|
406
|
-
slashFactoryAddress: result.slashFactoryAddress ? EthAddress.fromString(result.slashFactoryAddress) : undefined,
|
|
407
404
|
feeAssetHandlerAddress: result.feeAssetHandlerAddress
|
|
408
405
|
? EthAddress.fromString(result.feeAssetHandlerAddress)
|
|
409
406
|
: undefined,
|
|
@@ -585,7 +582,7 @@ export function getDeployRollupForUpgradeEnvVars(
|
|
|
585
582
|
AZTEC_EXIT_DELAY_SECONDS: args.exitDelaySeconds.toString(),
|
|
586
583
|
AZTEC_PROVING_COST_PER_MANA: args.provingCostPerMana.toString(),
|
|
587
584
|
AZTEC_INITIAL_ETH_PER_FEE_ASSET: args.initialEthPerFeeAsset.toString(),
|
|
588
|
-
|
|
585
|
+
AZTEC_SLASHER_ENABLED: args.slasherEnabled ? 'true' : 'false',
|
|
589
586
|
AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: args.slashingRoundSizeInEpochs.toString(),
|
|
590
587
|
AZTEC_SLASHING_QUORUM: args.slashingQuorum?.toString(),
|
|
591
588
|
AZTEC_SLASHING_OFFSET_IN_ROUNDS: args.slashingOffsetInRounds.toString(),
|
|
@@ -645,6 +642,5 @@ export const deployRollupForUpgrade = async (
|
|
|
645
642
|
|
|
646
643
|
return {
|
|
647
644
|
rollup,
|
|
648
|
-
slashFactoryAddress: result.slashFactoryAddress,
|
|
649
645
|
};
|
|
650
646
|
};
|
|
@@ -18,7 +18,7 @@ export const l1ContractsDefaultEnv = {
|
|
|
18
18
|
AZTEC_MANA_TARGET: 100000000,
|
|
19
19
|
AZTEC_PROVING_COST_PER_MANA: 100,
|
|
20
20
|
AZTEC_INITIAL_ETH_PER_FEE_ASSET: 10000000,
|
|
21
|
-
|
|
21
|
+
AZTEC_SLASHER_ENABLED: true,
|
|
22
22
|
AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS: 4,
|
|
23
23
|
AZTEC_SLASHING_LIFETIME_IN_ROUNDS: 5,
|
|
24
24
|
AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS: 0,
|