@aztec/ethereum 0.0.1-commit.35158ae7e → 0.0.1-commit.3750d92a7
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 +68 -18
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +240 -50
- 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.d.ts +3 -1
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -1
- package/dest/l1_tx_utils/l1_tx_utils.js +34 -26
- 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 +256 -43
- 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 +24 -14
- 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/src/contracts/rollup.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
4
4
|
import { memoize } from '@aztec/foundation/decorators';
|
|
5
5
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
6
6
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
7
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
7
8
|
import { makeBackoff, retry } from '@aztec/foundation/retry';
|
|
8
9
|
import { EscapeHatchAbi } from '@aztec/l1-artifacts/EscapeHatchAbi';
|
|
9
10
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
type Hex,
|
|
17
18
|
type StateOverride,
|
|
18
19
|
type WatchContractEventReturnType,
|
|
20
|
+
encodeAbiParameters,
|
|
19
21
|
encodeFunctionData,
|
|
20
22
|
getContract,
|
|
21
23
|
hexToBigInt,
|
|
@@ -29,11 +31,10 @@ import type { L1ReaderConfig } from '../l1_reader.js';
|
|
|
29
31
|
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
30
32
|
import type { ViemClient } from '../types.js';
|
|
31
33
|
import { formatViemError } from '../utils.js';
|
|
32
|
-
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
33
34
|
import { GSEContract } from './gse.js';
|
|
34
35
|
import type { L1EventLog } from './log.js';
|
|
35
36
|
import { SlasherContract } from './slasher_contract.js';
|
|
36
|
-
import {
|
|
37
|
+
import { SlashingProposerContract } from './slashing_proposer.js';
|
|
37
38
|
import { checkBlockTag } from './utils.js';
|
|
38
39
|
|
|
39
40
|
export type ViemCommitteeAttestation = {
|
|
@@ -55,7 +56,6 @@ export type L1RollupContractAddresses = Pick<
|
|
|
55
56
|
| 'feeJuiceAddress'
|
|
56
57
|
| 'stakingAssetAddress'
|
|
57
58
|
| 'rewardDistributorAddress'
|
|
58
|
-
| 'slashFactoryAddress'
|
|
59
59
|
| 'gseAddress'
|
|
60
60
|
>;
|
|
61
61
|
|
|
@@ -85,12 +85,6 @@ export type ViemGasFees = {
|
|
|
85
85
|
feePerL2Gas: bigint;
|
|
86
86
|
};
|
|
87
87
|
|
|
88
|
-
export enum SlashingProposerType {
|
|
89
|
-
None = 0,
|
|
90
|
-
Tally = 1,
|
|
91
|
-
Empire = 2,
|
|
92
|
-
}
|
|
93
|
-
|
|
94
88
|
/**
|
|
95
89
|
* Status of a validator/attester in the staking system.
|
|
96
90
|
* Matches the Status enum in StakingLib.sol
|
|
@@ -134,6 +128,17 @@ export type L1FeeData = {
|
|
|
134
128
|
blobFee: bigint;
|
|
135
129
|
};
|
|
136
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
|
+
|
|
137
142
|
/** Components of the minimum fee per mana, as returned by the L1 rollup contract. */
|
|
138
143
|
export type ManaMinFeeComponents = {
|
|
139
144
|
sequencerCost: bigint;
|
|
@@ -212,6 +217,7 @@ export type CheckpointProposedLog = L1EventLog<CheckpointProposedArgs>;
|
|
|
212
217
|
|
|
213
218
|
export class RollupContract {
|
|
214
219
|
private readonly rollup: GetContractReturnType<typeof RollupAbi, ViemClient>;
|
|
220
|
+
private readonly logger = createLogger('ethereum:rollup');
|
|
215
221
|
|
|
216
222
|
private static cachedStfStorageSlot: Hex | undefined;
|
|
217
223
|
private cachedEscapeHatch?: {
|
|
@@ -267,34 +273,18 @@ export class RollupContract {
|
|
|
267
273
|
return this.rollup;
|
|
268
274
|
}
|
|
269
275
|
|
|
270
|
-
public async getSlashingProposer(): Promise<
|
|
271
|
-
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
272
|
-
> {
|
|
276
|
+
public async getSlashingProposer(): Promise<SlashingProposerContract | undefined> {
|
|
273
277
|
const slasher = await this.getSlasherContract();
|
|
274
278
|
if (!slasher) {
|
|
275
279
|
return undefined;
|
|
276
280
|
}
|
|
277
281
|
|
|
278
282
|
const proposerAddress = await slasher.getProposer();
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
type: 'function',
|
|
282
|
-
name: 'SLASHING_PROPOSER_TYPE',
|
|
283
|
-
inputs: [],
|
|
284
|
-
outputs: [{ name: '', type: 'uint8', internalType: 'enum SlasherFlavor' }],
|
|
285
|
-
stateMutability: 'view',
|
|
286
|
-
},
|
|
287
|
-
] as const;
|
|
288
|
-
|
|
289
|
-
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
290
|
-
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
291
|
-
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
292
|
-
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
293
|
-
} else if (proposerType === SlashingProposerType.Empire.valueOf()) {
|
|
294
|
-
return new EmpireSlashingProposerContract(this.client, proposerAddress);
|
|
295
|
-
} else {
|
|
296
|
-
throw new Error(`Unknown slashing proposer type: ${proposerType}`);
|
|
283
|
+
if (proposerAddress.isZero()) {
|
|
284
|
+
return undefined;
|
|
297
285
|
}
|
|
286
|
+
|
|
287
|
+
return new SlashingProposerContract(this.client, proposerAddress);
|
|
298
288
|
}
|
|
299
289
|
|
|
300
290
|
@memoize
|
|
@@ -495,7 +485,11 @@ export class RollupContract {
|
|
|
495
485
|
|
|
496
486
|
const [isOpen] = await escapeHatch.read.isHatchOpen([BigInt(epoch)]);
|
|
497
487
|
return isOpen;
|
|
498
|
-
} catch {
|
|
488
|
+
} catch (err) {
|
|
489
|
+
this.logger.warn('isEscapeHatchOpen failed (treating as closed); RPC or contract error may cause liveness risk', {
|
|
490
|
+
epoch: Number(epoch),
|
|
491
|
+
error: err,
|
|
492
|
+
});
|
|
499
493
|
return false;
|
|
500
494
|
}
|
|
501
495
|
}
|
|
@@ -531,8 +525,9 @@ export class RollupContract {
|
|
|
531
525
|
return this.rollup.read.getCheckpointReward();
|
|
532
526
|
}
|
|
533
527
|
|
|
534
|
-
async getCheckpointNumber(): Promise<CheckpointNumber> {
|
|
535
|
-
|
|
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));
|
|
536
531
|
}
|
|
537
532
|
|
|
538
533
|
async getProvenCheckpointNumber(options?: { blockNumber?: bigint }): Promise<CheckpointNumber> {
|
|
@@ -540,18 +535,31 @@ export class RollupContract {
|
|
|
540
535
|
return CheckpointNumber.fromBigInt(await this.rollup.read.getProvenCheckpointNumber(options));
|
|
541
536
|
}
|
|
542
537
|
|
|
543
|
-
async getSlotNumber(): Promise<SlotNumber> {
|
|
544
|
-
|
|
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));
|
|
545
541
|
}
|
|
546
542
|
|
|
547
|
-
async getL1FeesAt(timestamp: bigint): Promise<L1FeeData> {
|
|
548
|
-
|
|
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);
|
|
549
546
|
return {
|
|
550
547
|
baseFee: result.baseFee,
|
|
551
548
|
blobFee: result.blobFee,
|
|
552
549
|
};
|
|
553
550
|
}
|
|
554
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
|
+
|
|
555
563
|
getEthPerFeeAsset(): Promise<bigint> {
|
|
556
564
|
return this.rollup.read.getEthPerFeeAsset();
|
|
557
565
|
}
|
|
@@ -626,8 +634,9 @@ export class RollupContract {
|
|
|
626
634
|
return EthAddress.fromString(result);
|
|
627
635
|
}
|
|
628
636
|
|
|
629
|
-
async getCheckpoint(checkpointNumber: CheckpointNumber): Promise<CheckpointLog> {
|
|
630
|
-
|
|
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);
|
|
631
640
|
return {
|
|
632
641
|
archive: Fr.fromString(result.archive),
|
|
633
642
|
headerHash: Buffer32.fromString(result.headerHash),
|
|
@@ -660,6 +669,30 @@ export class RollupContract {
|
|
|
660
669
|
);
|
|
661
670
|
}
|
|
662
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
|
+
|
|
663
696
|
async getTips(): Promise<{ pending: CheckpointNumber; proven: CheckpointNumber }> {
|
|
664
697
|
const { pending, proven } = await this.rollup.read.getTips();
|
|
665
698
|
return {
|
|
@@ -782,7 +815,7 @@ export class RollupContract {
|
|
|
782
815
|
archive: Buffer,
|
|
783
816
|
account: `0x${string}` | Account,
|
|
784
817
|
timestamp: bigint,
|
|
785
|
-
|
|
818
|
+
stateOverride: StateOverride = [],
|
|
786
819
|
): Promise<{ slot: SlotNumber; checkpointNumber: CheckpointNumber; timeOfNextL1Slot: bigint }> {
|
|
787
820
|
const timeOfNextL1Slot = timestamp;
|
|
788
821
|
const who = typeof account === 'string' ? account : account.address;
|
|
@@ -796,7 +829,7 @@ export class RollupContract {
|
|
|
796
829
|
functionName: 'canProposeAtTime',
|
|
797
830
|
args: [timeOfNextL1Slot, `0x${archive.toString('hex')}`, who],
|
|
798
831
|
account,
|
|
799
|
-
stateOverride
|
|
832
|
+
stateOverride,
|
|
800
833
|
});
|
|
801
834
|
|
|
802
835
|
return {
|
|
@@ -832,6 +865,151 @@ export class RollupContract {
|
|
|
832
865
|
];
|
|
833
866
|
}
|
|
834
867
|
|
|
868
|
+
/**
|
|
869
|
+
* Returns a state override that sets tempCheckpointLogs[checkpointNumber].feeHeader to the compressed fee header.
|
|
870
|
+
* Used when simulating a propose call where the parent checkpoint hasn't landed on L1 yet (pipelining).
|
|
871
|
+
*/
|
|
872
|
+
public async makeFeeHeaderOverride(checkpointNumber: CheckpointNumber, feeHeader: FeeHeader): Promise<StateOverride> {
|
|
873
|
+
const { epochDuration, proofSubmissionEpochs } = await this.getRollupConstants();
|
|
874
|
+
const roundaboutSize = BigInt(epochDuration * (proofSubmissionEpochs + 1) + 1);
|
|
875
|
+
const circularIndex = BigInt(checkpointNumber) % roundaboutSize;
|
|
876
|
+
|
|
877
|
+
// tempCheckpointLogs is at offset 2 in RollupStore
|
|
878
|
+
const tempCheckpointLogsMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 2n;
|
|
879
|
+
|
|
880
|
+
// Solidity mapping slot: keccak256(abi.encode(key, baseSlot))
|
|
881
|
+
const structBaseSlot = hexToBigInt(
|
|
882
|
+
keccak256(
|
|
883
|
+
encodeAbiParameters([{ type: 'uint256' }, { type: 'uint256' }], [circularIndex, tempCheckpointLogsMappingBase]),
|
|
884
|
+
),
|
|
885
|
+
);
|
|
886
|
+
|
|
887
|
+
// feeHeader is the 7th field (offset 6) in CompressedTempCheckpointLog
|
|
888
|
+
const feeHeaderSlot = structBaseSlot + 6n;
|
|
889
|
+
const compressed = RollupContract.compressFeeHeader(feeHeader);
|
|
890
|
+
|
|
891
|
+
return [
|
|
892
|
+
{
|
|
893
|
+
address: this.address,
|
|
894
|
+
stateDiff: [
|
|
895
|
+
{
|
|
896
|
+
slot: `0x${feeHeaderSlot.toString(16).padStart(64, '0')}`,
|
|
897
|
+
value: `0x${compressed.toString(16).padStart(64, '0')}`,
|
|
898
|
+
},
|
|
899
|
+
],
|
|
900
|
+
},
|
|
901
|
+
];
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Returns a state override that sets archives[checkpointNumber] to the given archive value.
|
|
906
|
+
* Used when simulating a canProposeAtTime call where the local archive differs from L1
|
|
907
|
+
* (e.g. pipelining where the parent checkpoint hasn't landed on L1 yet).
|
|
908
|
+
*/
|
|
909
|
+
public makeArchiveOverride(checkpointNumber: CheckpointNumber, archive: Fr): StateOverride {
|
|
910
|
+
const archivesMappingBase = hexToBigInt(RollupContract.stfStorageSlot) + 1n;
|
|
911
|
+
const archiveSlot = hexToBigInt(
|
|
912
|
+
keccak256(
|
|
913
|
+
encodeAbiParameters(
|
|
914
|
+
[{ type: 'uint256' }, { type: 'uint256' }],
|
|
915
|
+
[BigInt(checkpointNumber), archivesMappingBase],
|
|
916
|
+
),
|
|
917
|
+
),
|
|
918
|
+
);
|
|
919
|
+
return [
|
|
920
|
+
{
|
|
921
|
+
address: this.address,
|
|
922
|
+
stateDiff: [
|
|
923
|
+
{
|
|
924
|
+
slot: `0x${archiveSlot.toString(16).padStart(64, '0')}`,
|
|
925
|
+
value: archive.toString(),
|
|
926
|
+
},
|
|
927
|
+
],
|
|
928
|
+
},
|
|
929
|
+
];
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/** Merges multiple StateOverride arrays, combining stateDiff entries for the same address. */
|
|
933
|
+
public static mergeStateOverrides(...overrides: StateOverride[]): StateOverride {
|
|
934
|
+
type StateDiffEntry = { slot: `0x${string}`; value: `0x${string}` };
|
|
935
|
+
const byAddress = new Map<string, { address: `0x${string}`; balance?: bigint; stateDiff: StateDiffEntry[] }>();
|
|
936
|
+
for (const override of overrides) {
|
|
937
|
+
for (const entry of override) {
|
|
938
|
+
const key = entry.address.toLowerCase();
|
|
939
|
+
const existing = byAddress.get(key);
|
|
940
|
+
if (existing) {
|
|
941
|
+
existing.stateDiff.push(...(entry.stateDiff ?? []));
|
|
942
|
+
if (entry.balance !== undefined) {
|
|
943
|
+
existing.balance = entry.balance;
|
|
944
|
+
}
|
|
945
|
+
} else {
|
|
946
|
+
byAddress.set(key, {
|
|
947
|
+
address: entry.address,
|
|
948
|
+
balance: entry.balance,
|
|
949
|
+
stateDiff: [...(entry.stateDiff ?? [])],
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
return [...byAddress.values()];
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/** Compresses a FeeHeader into a uint256 matching FeeHeaderLib.compress() in FeeStructs.sol. */
|
|
958
|
+
public static compressFeeHeader(feeHeader: FeeHeader): bigint {
|
|
959
|
+
const MASK_48_BITS = (1n << 48n) - 1n;
|
|
960
|
+
const MASK_64_BITS = (1n << 64n) - 1n;
|
|
961
|
+
const MASK_63_BITS = (1n << 63n) - 1n;
|
|
962
|
+
|
|
963
|
+
let value = BigInt(feeHeader.manaUsed) & ((1n << 32n) - 1n); // bits [0:31]
|
|
964
|
+
value |= (feeHeader.excessMana < MASK_48_BITS ? feeHeader.excessMana : MASK_48_BITS) << 32n; // bits [32:79]
|
|
965
|
+
value |= (BigInt(feeHeader.ethPerFeeAsset) & MASK_48_BITS) << 80n; // bits [80:127]
|
|
966
|
+
value |= (feeHeader.congestionCost < MASK_64_BITS ? feeHeader.congestionCost : MASK_64_BITS) << 128n; // bits [128:191]
|
|
967
|
+
value |= (feeHeader.proverCost < MASK_63_BITS ? feeHeader.proverCost : MASK_63_BITS) << 192n; // bits [192:254]
|
|
968
|
+
value |= 1n << 255n; // preheat flag
|
|
969
|
+
return value;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
/** Computes the fee header for a child checkpoint given parent fee header and child data.
|
|
973
|
+
* Must stay in sync with Solidity FeeLib.sol (computeNewEthPerFeeAsset, clampedAdd). */
|
|
974
|
+
public static computeChildFeeHeader(
|
|
975
|
+
parentFeeHeader: FeeHeader,
|
|
976
|
+
childManaUsed: bigint,
|
|
977
|
+
feeAssetPriceModifier: bigint,
|
|
978
|
+
manaTarget: bigint,
|
|
979
|
+
): FeeHeader {
|
|
980
|
+
const MIN_ETH_PER_FEE_ASSET = 100n;
|
|
981
|
+
const MAX_ETH_PER_FEE_ASSET = 100_000_000_000_000n; // 1e14, matches FeeLib.sol
|
|
982
|
+
|
|
983
|
+
// excessMana = clampedAdd(parent.excessMana + parent.manaUsed, -manaTarget)
|
|
984
|
+
const sum = parentFeeHeader.excessMana + parentFeeHeader.manaUsed;
|
|
985
|
+
const excessMana = sum > manaTarget ? sum - manaTarget : 0n;
|
|
986
|
+
|
|
987
|
+
// ethPerFeeAsset = computeNewEthPerFeeAsset(max(parent.ethPerFeeAsset, MIN), modifier)
|
|
988
|
+
const parentPrice =
|
|
989
|
+
parentFeeHeader.ethPerFeeAsset > MIN_ETH_PER_FEE_ASSET ? parentFeeHeader.ethPerFeeAsset : MIN_ETH_PER_FEE_ASSET;
|
|
990
|
+
let newPrice: bigint;
|
|
991
|
+
if (feeAssetPriceModifier >= 0n) {
|
|
992
|
+
newPrice = (parentPrice * (10_000n + feeAssetPriceModifier)) / 10_000n;
|
|
993
|
+
} else {
|
|
994
|
+
const absMod = -feeAssetPriceModifier;
|
|
995
|
+
newPrice = (parentPrice * (10_000n - absMod)) / 10_000n;
|
|
996
|
+
}
|
|
997
|
+
if (newPrice < MIN_ETH_PER_FEE_ASSET) {
|
|
998
|
+
newPrice = MIN_ETH_PER_FEE_ASSET;
|
|
999
|
+
}
|
|
1000
|
+
if (newPrice > MAX_ETH_PER_FEE_ASSET) {
|
|
1001
|
+
newPrice = MAX_ETH_PER_FEE_ASSET;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
return {
|
|
1005
|
+
excessMana,
|
|
1006
|
+
manaUsed: childManaUsed,
|
|
1007
|
+
ethPerFeeAsset: newPrice,
|
|
1008
|
+
congestionCost: 0n,
|
|
1009
|
+
proverCost: 0n,
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
|
|
835
1013
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
836
1014
|
public buildInvalidateBadAttestationRequest(
|
|
837
1015
|
checkpointNumber: CheckpointNumber,
|
|
@@ -880,8 +1058,8 @@ export class RollupContract {
|
|
|
880
1058
|
return this.rollup.read.getHasSubmitted([BigInt(epochNumber), BigInt(numberOfCheckpointsInEpoch), prover]);
|
|
881
1059
|
}
|
|
882
1060
|
|
|
883
|
-
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean): Promise<bigint> {
|
|
884
|
-
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset]);
|
|
1061
|
+
getManaMinFeeAt(timestamp: bigint, inFeeAsset: boolean, stateOverride?: StateOverride): Promise<bigint> {
|
|
1062
|
+
return this.rollup.read.getManaMinFeeAt([timestamp, inFeeAsset], { stateOverride });
|
|
885
1063
|
}
|
|
886
1064
|
|
|
887
1065
|
async getManaMinFeeComponentsAt(timestamp: bigint, inFeeAsset: boolean): Promise<ManaMinFeeComponents> {
|
|
@@ -1120,4 +1298,39 @@ export class RollupContract {
|
|
|
1120
1298
|
},
|
|
1121
1299
|
}));
|
|
1122
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
|
+
}
|
|
1123
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,
|
package/src/l1_artifacts.ts
CHANGED
|
@@ -3,10 +3,6 @@ import {
|
|
|
3
3
|
CoinIssuerBytecode,
|
|
4
4
|
DateGatedRelayerAbi,
|
|
5
5
|
DateGatedRelayerBytecode,
|
|
6
|
-
EmpireSlasherDeploymentExtLibAbi,
|
|
7
|
-
EmpireSlasherDeploymentExtLibBytecode,
|
|
8
|
-
EmpireSlashingProposerAbi,
|
|
9
|
-
EmpireSlashingProposerBytecode,
|
|
10
6
|
FeeAssetHandlerAbi,
|
|
11
7
|
FeeAssetHandlerBytecode,
|
|
12
8
|
FeeJuicePortalAbi,
|
|
@@ -42,16 +38,14 @@ import {
|
|
|
42
38
|
RollupLinkReferences,
|
|
43
39
|
RollupOperationsExtLibAbi,
|
|
44
40
|
RollupOperationsExtLibBytecode,
|
|
45
|
-
SlashFactoryAbi,
|
|
46
|
-
SlashFactoryBytecode,
|
|
47
41
|
SlasherAbi,
|
|
48
42
|
SlasherBytecode,
|
|
43
|
+
SlasherDeploymentExtLibAbi,
|
|
44
|
+
SlasherDeploymentExtLibBytecode,
|
|
45
|
+
SlashingProposerAbi,
|
|
46
|
+
SlashingProposerBytecode,
|
|
49
47
|
StakingAssetHandlerAbi,
|
|
50
48
|
StakingAssetHandlerBytecode,
|
|
51
|
-
TallySlasherDeploymentExtLibAbi,
|
|
52
|
-
TallySlasherDeploymentExtLibBytecode,
|
|
53
|
-
TallySlashingProposerAbi,
|
|
54
|
-
TallySlashingProposerBytecode,
|
|
55
49
|
TestERC20Abi,
|
|
56
50
|
TestERC20Bytecode,
|
|
57
51
|
ValidatorOperationsExtLibAbi,
|
|
@@ -107,15 +101,10 @@ export const RollupArtifact = {
|
|
|
107
101
|
contractAbi: RewardExtLibAbi,
|
|
108
102
|
contractBytecode: RewardExtLibBytecode as Hex,
|
|
109
103
|
},
|
|
110
|
-
|
|
111
|
-
name: '
|
|
112
|
-
contractAbi:
|
|
113
|
-
contractBytecode:
|
|
114
|
-
},
|
|
115
|
-
EmpireSlasherDeploymentExtLib: {
|
|
116
|
-
name: 'EmpireSlasherDeploymentExtLib',
|
|
117
|
-
contractAbi: EmpireSlasherDeploymentExtLibAbi,
|
|
118
|
-
contractBytecode: EmpireSlasherDeploymentExtLibBytecode as Hex,
|
|
104
|
+
SlasherDeploymentExtLib: {
|
|
105
|
+
name: 'SlasherDeploymentExtLib',
|
|
106
|
+
contractAbi: SlasherDeploymentExtLibAbi,
|
|
107
|
+
contractBytecode: SlasherDeploymentExtLibBytecode as Hex,
|
|
119
108
|
},
|
|
120
109
|
},
|
|
121
110
|
},
|
|
@@ -175,22 +164,10 @@ export const SlasherArtifact = {
|
|
|
175
164
|
contractBytecode: SlasherBytecode as Hex,
|
|
176
165
|
};
|
|
177
166
|
|
|
178
|
-
export const
|
|
179
|
-
name: '
|
|
180
|
-
contractAbi:
|
|
181
|
-
contractBytecode:
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
export const TallySlashingProposerArtifact = {
|
|
185
|
-
name: 'TallySlashingProposer',
|
|
186
|
-
contractAbi: TallySlashingProposerAbi,
|
|
187
|
-
contractBytecode: TallySlashingProposerBytecode as Hex,
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
export const SlashFactoryArtifact = {
|
|
191
|
-
name: 'SlashFactory',
|
|
192
|
-
contractAbi: SlashFactoryAbi,
|
|
193
|
-
contractBytecode: SlashFactoryBytecode as Hex,
|
|
167
|
+
export const SlashingProposerArtifact = {
|
|
168
|
+
name: 'SlashingProposer',
|
|
169
|
+
contractAbi: SlashingProposerAbi,
|
|
170
|
+
contractBytecode: SlashingProposerBytecode as Hex,
|
|
194
171
|
};
|
|
195
172
|
|
|
196
173
|
export const RegisterNewRollupVersionPayloadArtifact = {
|
|
@@ -27,7 +27,6 @@ export const L1ContractsNames = [
|
|
|
27
27
|
export type L1ContractAddresses = {
|
|
28
28
|
[K in (typeof L1ContractsNames)[number]]: EthAddress;
|
|
29
29
|
} & {
|
|
30
|
-
slashFactoryAddress?: EthAddress | undefined;
|
|
31
30
|
feeAssetHandlerAddress?: EthAddress | undefined;
|
|
32
31
|
stakingAssetHandlerAddress?: EthAddress | undefined;
|
|
33
32
|
zkPassportVerifierAddress?: EthAddress | undefined;
|
|
@@ -48,7 +47,6 @@ export const L1ContractAddressesSchema = zodFor<L1ContractAddresses>()(
|
|
|
48
47
|
rewardDistributorAddress: schemas.EthAddress,
|
|
49
48
|
governanceProposerAddress: schemas.EthAddress,
|
|
50
49
|
governanceAddress: schemas.EthAddress,
|
|
51
|
-
slashFactoryAddress: schemas.EthAddress.optional(),
|
|
52
50
|
feeAssetHandlerAddress: schemas.EthAddress.optional(),
|
|
53
51
|
stakingAssetHandlerAddress: schemas.EthAddress.optional(),
|
|
54
52
|
zkPassportVerifierAddress: schemas.EthAddress.optional(),
|
|
@@ -67,11 +65,6 @@ export const l1ContractAddressesMapping: ConfigMappingsType<
|
|
|
67
65
|
description: 'The deployed L1 registry contract address.',
|
|
68
66
|
parseEnv,
|
|
69
67
|
},
|
|
70
|
-
slashFactoryAddress: {
|
|
71
|
-
env: 'SLASH_FACTORY_CONTRACT_ADDRESS',
|
|
72
|
-
description: 'The deployed L1 slashFactory contract address',
|
|
73
|
-
parseEnv,
|
|
74
|
-
},
|
|
75
68
|
feeAssetHandlerAddress: {
|
|
76
69
|
env: 'FEE_ASSET_HANDLER_CONTRACT_ADDRESS',
|
|
77
70
|
description: 'The deployed L1 feeAssetHandler contract address',
|