@aztec/ethereum 3.0.0-canary.a9708bd → 3.0.0-devnet.2
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.d.ts +1 -1
- package/dest/client.d.ts.map +1 -1
- package/dest/config.d.ts +11 -6
- package/dest/config.d.ts.map +1 -1
- package/dest/config.js +124 -64
- package/dest/contracts/empire_base.d.ts +1 -1
- package/dest/contracts/empire_base.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.d.ts +2 -2
- package/dest/contracts/empire_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/empire_slashing_proposer.js +1 -1
- package/dest/contracts/fee_asset_handler.d.ts +3 -3
- package/dest/contracts/fee_asset_handler.d.ts.map +1 -1
- package/dest/contracts/governance.js +7 -3
- package/dest/contracts/governance_proposer.d.ts +1 -2
- package/dest/contracts/governance_proposer.d.ts.map +1 -1
- package/dest/contracts/governance_proposer.js +1 -2
- package/dest/contracts/multicall.d.ts +3 -5
- package/dest/contracts/multicall.d.ts.map +1 -1
- package/dest/contracts/multicall.js +6 -4
- package/dest/contracts/rollup.d.ts +39 -19
- package/dest/contracts/rollup.d.ts.map +1 -1
- package/dest/contracts/rollup.js +84 -88
- package/dest/contracts/slasher_contract.d.ts +10 -0
- package/dest/contracts/slasher_contract.d.ts.map +1 -1
- package/dest/contracts/slasher_contract.js +18 -0
- package/dest/contracts/tally_slashing_proposer.d.ts +22 -3
- package/dest/contracts/tally_slashing_proposer.d.ts.map +1 -1
- package/dest/contracts/tally_slashing_proposer.js +55 -5
- package/dest/deploy_l1_contracts.d.ts +22 -7
- package/dest/deploy_l1_contracts.d.ts.map +1 -1
- package/dest/deploy_l1_contracts.js +555 -362
- package/dest/index.d.ts +1 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +1 -1
- package/dest/l1_artifacts.d.ts +8729 -6014
- package/dest/l1_artifacts.d.ts.map +1 -1
- package/dest/l1_artifacts.js +10 -5
- package/dest/l1_contract_addresses.d.ts +5 -1
- package/dest/l1_contract_addresses.d.ts.map +1 -1
- package/dest/l1_contract_addresses.js +16 -26
- package/dest/l1_reader.d.ts +1 -1
- package/dest/l1_reader.d.ts.map +1 -1
- package/dest/l1_reader.js +8 -8
- package/dest/l1_tx_utils/config.d.ts +59 -0
- package/dest/l1_tx_utils/config.d.ts.map +1 -0
- package/dest/l1_tx_utils/config.js +73 -0
- package/dest/l1_tx_utils/constants.d.ts +6 -0
- package/dest/l1_tx_utils/constants.d.ts.map +1 -0
- package/dest/l1_tx_utils/constants.js +14 -0
- package/dest/l1_tx_utils/factory.d.ts +24 -0
- package/dest/l1_tx_utils/factory.d.ts.map +1 -0
- package/dest/l1_tx_utils/factory.js +12 -0
- package/dest/l1_tx_utils/index.d.ts +10 -0
- package/dest/l1_tx_utils/index.d.ts.map +1 -0
- package/dest/l1_tx_utils/index.js +10 -0
- package/dest/l1_tx_utils/interfaces.d.ts +76 -0
- package/dest/l1_tx_utils/interfaces.d.ts.map +1 -0
- package/dest/l1_tx_utils/interfaces.js +4 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts +95 -0
- package/dest/l1_tx_utils/l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_tx_utils.js +610 -0
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts +26 -0
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.d.ts.map +1 -0
- package/dest/l1_tx_utils/l1_tx_utils_with_blobs.js +26 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts +81 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/readonly_l1_tx_utils.js +294 -0
- package/dest/l1_tx_utils/signer.d.ts +4 -0
- package/dest/l1_tx_utils/signer.d.ts.map +1 -0
- package/dest/l1_tx_utils/signer.js +16 -0
- package/dest/l1_tx_utils/types.d.ts +67 -0
- package/dest/l1_tx_utils/types.d.ts.map +1 -0
- package/dest/l1_tx_utils/types.js +26 -0
- package/dest/l1_tx_utils/utils.d.ts +4 -0
- package/dest/l1_tx_utils/utils.d.ts.map +1 -0
- package/dest/l1_tx_utils/utils.js +14 -0
- package/dest/publisher_manager.d.ts +7 -2
- package/dest/publisher_manager.d.ts.map +1 -1
- package/dest/publisher_manager.js +36 -8
- package/dest/queries.d.ts.map +1 -1
- package/dest/queries.js +11 -12
- package/dest/test/chain_monitor.d.ts +11 -0
- package/dest/test/chain_monitor.d.ts.map +1 -1
- package/dest/test/chain_monitor.js +81 -12
- package/dest/test/delayed_tx_utils.d.ts +2 -2
- package/dest/test/delayed_tx_utils.d.ts.map +1 -1
- package/dest/test/delayed_tx_utils.js +2 -2
- package/dest/test/eth_cheat_codes.d.ts +32 -6
- package/dest/test/eth_cheat_codes.d.ts.map +1 -1
- package/dest/test/eth_cheat_codes.js +115 -28
- package/dest/test/rollup_cheat_codes.d.ts +11 -9
- package/dest/test/rollup_cheat_codes.d.ts.map +1 -1
- package/dest/test/rollup_cheat_codes.js +38 -6
- package/dest/test/upgrade_utils.d.ts.map +1 -1
- package/dest/test/upgrade_utils.js +3 -2
- package/dest/utils.d.ts.map +1 -1
- package/dest/utils.js +10 -161
- package/dest/zkPassportVerifierAddress.js +1 -1
- package/package.json +7 -7
- package/src/client.ts +1 -1
- package/src/config.ts +136 -68
- package/src/contracts/empire_base.ts +1 -1
- package/src/contracts/empire_slashing_proposer.ts +7 -3
- package/src/contracts/fee_asset_handler.ts +1 -1
- package/src/contracts/governance.ts +3 -3
- package/src/contracts/governance_proposer.ts +3 -4
- package/src/contracts/multicall.ts +12 -10
- package/src/contracts/rollup.ts +104 -106
- package/src/contracts/slasher_contract.ts +22 -0
- package/src/contracts/tally_slashing_proposer.ts +54 -6
- package/src/deploy_l1_contracts.ts +570 -328
- package/src/index.ts +1 -1
- package/src/l1_artifacts.ts +14 -6
- package/src/l1_contract_addresses.ts +17 -26
- package/src/l1_reader.ts +9 -9
- package/src/l1_tx_utils/README.md +177 -0
- package/src/l1_tx_utils/config.ts +140 -0
- package/src/l1_tx_utils/constants.ts +18 -0
- package/src/l1_tx_utils/factory.ts +64 -0
- package/src/l1_tx_utils/index.ts +12 -0
- package/src/l1_tx_utils/interfaces.ts +86 -0
- package/src/l1_tx_utils/l1_tx_utils.ts +718 -0
- package/src/l1_tx_utils/l1_tx_utils_with_blobs.ts +77 -0
- package/src/l1_tx_utils/readonly_l1_tx_utils.ts +372 -0
- package/src/l1_tx_utils/signer.ts +28 -0
- package/src/l1_tx_utils/types.ts +85 -0
- package/src/l1_tx_utils/utils.ts +16 -0
- package/src/publisher_manager.ts +51 -9
- package/src/queries.ts +13 -8
- package/src/test/chain_monitor.ts +89 -9
- package/src/test/delayed_tx_utils.ts +2 -2
- package/src/test/eth_cheat_codes.ts +142 -29
- package/src/test/rollup_cheat_codes.ts +54 -14
- package/src/test/upgrade_utils.ts +3 -2
- package/src/utils.ts +13 -185
- package/src/zkPassportVerifierAddress.ts +1 -1
- package/dest/l1_tx_utils.d.ts +0 -250
- package/dest/l1_tx_utils.d.ts.map +0 -1
- package/dest/l1_tx_utils.js +0 -826
- package/dest/l1_tx_utils_with_blobs.d.ts +0 -19
- package/dest/l1_tx_utils_with_blobs.d.ts.map +0 -1
- package/dest/l1_tx_utils_with_blobs.js +0 -85
- package/src/l1_tx_utils.ts +0 -1105
- package/src/l1_tx_utils_with_blobs.ts +0 -144
package/src/contracts/rollup.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
3
3
|
import type { ViemSignature } from '@aztec/foundation/eth-signature';
|
|
4
4
|
import { RollupAbi } from '@aztec/l1-artifacts/RollupAbi';
|
|
5
5
|
import { RollupStorage } from '@aztec/l1-artifacts/RollupStorage';
|
|
6
|
-
import { SlasherAbi } from '@aztec/l1-artifacts/SlasherAbi';
|
|
7
6
|
|
|
8
7
|
import chunk from 'lodash.chunk';
|
|
9
8
|
import {
|
|
@@ -11,8 +10,8 @@ import {
|
|
|
11
10
|
type GetContractReturnType,
|
|
12
11
|
type Hex,
|
|
13
12
|
type StateOverride,
|
|
13
|
+
type WatchContractEventReturnType,
|
|
14
14
|
encodeFunctionData,
|
|
15
|
-
getAddress,
|
|
16
15
|
getContract,
|
|
17
16
|
hexToBigInt,
|
|
18
17
|
keccak256,
|
|
@@ -22,7 +21,7 @@ import { getPublicClient } from '../client.js';
|
|
|
22
21
|
import type { DeployL1ContractsReturnType } from '../deploy_l1_contracts.js';
|
|
23
22
|
import type { L1ContractAddresses } from '../l1_contract_addresses.js';
|
|
24
23
|
import type { L1ReaderConfig } from '../l1_reader.js';
|
|
25
|
-
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils.js';
|
|
24
|
+
import type { L1TxRequest, L1TxUtils } from '../l1_tx_utils/index.js';
|
|
26
25
|
import type { ViemClient } from '../types.js';
|
|
27
26
|
import { formatViemError } from '../utils.js';
|
|
28
27
|
import { EmpireSlashingProposerContract } from './empire_slashing_proposer.js';
|
|
@@ -160,13 +159,12 @@ export class RollupContract {
|
|
|
160
159
|
public async getSlashingProposer(): Promise<
|
|
161
160
|
EmpireSlashingProposerContract | TallySlashingProposerContract | undefined
|
|
162
161
|
> {
|
|
163
|
-
const
|
|
164
|
-
if (
|
|
162
|
+
const slasher = await this.getSlasherContract();
|
|
163
|
+
if (!slasher) {
|
|
165
164
|
return undefined;
|
|
166
165
|
}
|
|
167
166
|
|
|
168
|
-
const
|
|
169
|
-
const proposerAddress = await slasher.read.PROPOSER();
|
|
167
|
+
const proposerAddress = await slasher.getProposer();
|
|
170
168
|
const proposerAbi = [
|
|
171
169
|
{
|
|
172
170
|
type: 'function',
|
|
@@ -177,7 +175,7 @@ export class RollupContract {
|
|
|
177
175
|
},
|
|
178
176
|
] as const;
|
|
179
177
|
|
|
180
|
-
const proposer = getContract({ address: proposerAddress, abi: proposerAbi, client: this.client });
|
|
178
|
+
const proposer = getContract({ address: proposerAddress.toString(), abi: proposerAbi, client: this.client });
|
|
181
179
|
const proposerType = await proposer.read.SLASHING_PROPOSER_TYPE();
|
|
182
180
|
if (proposerType === SlashingProposerType.Tally.valueOf()) {
|
|
183
181
|
return new TallySlashingProposerContract(this.client, proposerAddress);
|
|
@@ -223,6 +221,16 @@ export class RollupContract {
|
|
|
223
221
|
return this.rollup.read.getEjectionThreshold();
|
|
224
222
|
}
|
|
225
223
|
|
|
224
|
+
@memoize
|
|
225
|
+
getLocalEjectionThreshold() {
|
|
226
|
+
return this.rollup.read.getLocalEjectionThreshold();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
@memoize
|
|
230
|
+
getLagInEpochs() {
|
|
231
|
+
return this.rollup.read.getLagInEpochs();
|
|
232
|
+
}
|
|
233
|
+
|
|
226
234
|
@memoize
|
|
227
235
|
getActivationThreshold() {
|
|
228
236
|
return this.rollup.read.getActivationThreshold();
|
|
@@ -260,20 +268,51 @@ export class RollupContract {
|
|
|
260
268
|
|
|
261
269
|
@memoize
|
|
262
270
|
async getGenesisArchiveTreeRoot(): Promise<`0x${string}`> {
|
|
263
|
-
|
|
264
|
-
|
|
271
|
+
return await this.rollup.read.archiveAt([0n]);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Returns rollup constants used for epoch queries.
|
|
276
|
+
* Return type is `L1RollupConstants` which is defined in stdlib,
|
|
277
|
+
* so we cant reference it until we move this contract to that package.
|
|
278
|
+
*/
|
|
279
|
+
@memoize
|
|
280
|
+
public async getRollupConstants(): Promise<{
|
|
281
|
+
l1StartBlock: bigint;
|
|
282
|
+
l1GenesisTime: bigint;
|
|
283
|
+
slotDuration: number;
|
|
284
|
+
epochDuration: number;
|
|
285
|
+
proofSubmissionEpochs: number;
|
|
286
|
+
}> {
|
|
287
|
+
const [l1StartBlock, l1GenesisTime, slotDuration, epochDuration, proofSubmissionEpochs] = await Promise.all([
|
|
288
|
+
this.getL1StartBlock(),
|
|
289
|
+
this.getL1GenesisTime(),
|
|
290
|
+
this.getSlotDuration(),
|
|
291
|
+
this.getEpochDuration(),
|
|
292
|
+
this.getProofSubmissionEpochs(),
|
|
293
|
+
]);
|
|
294
|
+
return {
|
|
295
|
+
l1StartBlock,
|
|
296
|
+
l1GenesisTime,
|
|
297
|
+
slotDuration: Number(slotDuration),
|
|
298
|
+
epochDuration: Number(epochDuration),
|
|
299
|
+
proofSubmissionEpochs: Number(proofSubmissionEpochs),
|
|
300
|
+
};
|
|
265
301
|
}
|
|
266
302
|
|
|
267
|
-
|
|
303
|
+
getSlasherAddress() {
|
|
268
304
|
return this.rollup.read.getSlasher();
|
|
269
305
|
}
|
|
270
306
|
|
|
271
307
|
/**
|
|
272
308
|
* Returns a SlasherContract instance for interacting with the slasher contract.
|
|
273
309
|
*/
|
|
274
|
-
async getSlasherContract(): Promise<SlasherContract> {
|
|
275
|
-
const slasherAddress = await this.
|
|
276
|
-
|
|
310
|
+
async getSlasherContract(): Promise<SlasherContract | undefined> {
|
|
311
|
+
const slasherAddress = EthAddress.fromString(await this.getSlasherAddress());
|
|
312
|
+
if (slasherAddress.isZero()) {
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
return new SlasherContract(this.client, slasherAddress);
|
|
277
316
|
}
|
|
278
317
|
|
|
279
318
|
getOwner() {
|
|
@@ -285,13 +324,11 @@ export class RollupContract {
|
|
|
285
324
|
}
|
|
286
325
|
|
|
287
326
|
public async getSlashingProposerAddress() {
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
});
|
|
294
|
-
return EthAddress.fromString(await slasher.read.PROPOSER());
|
|
327
|
+
const slasher = await this.getSlasherContract();
|
|
328
|
+
if (!slasher) {
|
|
329
|
+
return EthAddress.ZERO;
|
|
330
|
+
}
|
|
331
|
+
return await slasher.getProposer();
|
|
295
332
|
}
|
|
296
333
|
|
|
297
334
|
getBlockReward() {
|
|
@@ -388,8 +425,8 @@ export class RollupContract {
|
|
|
388
425
|
return result;
|
|
389
426
|
}
|
|
390
427
|
|
|
391
|
-
getBlock(blockNumber: bigint) {
|
|
392
|
-
return this.rollup.read.getBlock([blockNumber]);
|
|
428
|
+
getBlock(blockNumber: bigint | number) {
|
|
429
|
+
return this.rollup.read.getBlock([BigInt(blockNumber)]);
|
|
393
430
|
}
|
|
394
431
|
|
|
395
432
|
getTips() {
|
|
@@ -404,8 +441,19 @@ export class RollupContract {
|
|
|
404
441
|
return this.rollup.read.getEntryQueueLength();
|
|
405
442
|
}
|
|
406
443
|
|
|
407
|
-
|
|
408
|
-
|
|
444
|
+
getAvailableValidatorFlushes() {
|
|
445
|
+
return this.rollup.read.getAvailableValidatorFlushes();
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
getNextFlushableEpoch() {
|
|
449
|
+
return this.rollup.read.getNextFlushableEpoch();
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
getCurrentEpochNumber(): Promise<bigint> {
|
|
453
|
+
return this.rollup.read.getCurrentEpoch();
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
getEpochNumberForBlock(blockNumber: bigint) {
|
|
409
457
|
return this.rollup.read.getEpochForBlock([BigInt(blockNumber)]);
|
|
410
458
|
}
|
|
411
459
|
|
|
@@ -461,6 +509,7 @@ export class RollupContract {
|
|
|
461
509
|
ViemHeader,
|
|
462
510
|
ViemCommitteeAttestations,
|
|
463
511
|
`0x${string}`[],
|
|
512
|
+
ViemSignature,
|
|
464
513
|
`0x${string}`,
|
|
465
514
|
`0x${string}`,
|
|
466
515
|
{
|
|
@@ -483,77 +532,6 @@ export class RollupContract {
|
|
|
483
532
|
}
|
|
484
533
|
}
|
|
485
534
|
|
|
486
|
-
/**
|
|
487
|
-
* Packs an array of committee attestations into the format expected by the Solidity contract
|
|
488
|
-
*
|
|
489
|
-
* @param attestations - Array of committee attestations with addresses and signatures
|
|
490
|
-
* @returns Packed attestations with bitmap and tightly packed signature/address data
|
|
491
|
-
*/
|
|
492
|
-
static packAttestations(attestations: ViemCommitteeAttestation[]): ViemCommitteeAttestations {
|
|
493
|
-
const length = attestations.length;
|
|
494
|
-
|
|
495
|
-
// Calculate bitmap size (1 bit per attestation, rounded up to nearest byte)
|
|
496
|
-
const bitmapSize = Math.ceil(length / 8);
|
|
497
|
-
const signatureIndices = new Uint8Array(bitmapSize);
|
|
498
|
-
|
|
499
|
-
// Calculate total data size needed
|
|
500
|
-
let totalDataSize = 0;
|
|
501
|
-
for (let i = 0; i < length; i++) {
|
|
502
|
-
const signature = attestations[i].signature;
|
|
503
|
-
// Check if signature is empty (v = 0)
|
|
504
|
-
const isEmpty = signature.v === 0;
|
|
505
|
-
|
|
506
|
-
if (!isEmpty) {
|
|
507
|
-
totalDataSize += 65; // v (1) + r (32) + s (32)
|
|
508
|
-
} else {
|
|
509
|
-
totalDataSize += 20; // address only
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
const signaturesOrAddresses = new Uint8Array(totalDataSize);
|
|
514
|
-
let dataIndex = 0;
|
|
515
|
-
|
|
516
|
-
// Pack the data
|
|
517
|
-
for (let i = 0; i < length; i++) {
|
|
518
|
-
const attestation = attestations[i];
|
|
519
|
-
const signature = attestation.signature;
|
|
520
|
-
|
|
521
|
-
// Check if signature is empty
|
|
522
|
-
const isEmpty = signature.v === 0;
|
|
523
|
-
|
|
524
|
-
if (!isEmpty) {
|
|
525
|
-
// Set bit in bitmap (bit 7-0 in each byte, left to right)
|
|
526
|
-
const byteIndex = Math.floor(i / 8);
|
|
527
|
-
const bitIndex = 7 - (i % 8);
|
|
528
|
-
signatureIndices[byteIndex] |= 1 << bitIndex;
|
|
529
|
-
|
|
530
|
-
// Pack signature: v + r + s
|
|
531
|
-
signaturesOrAddresses[dataIndex] = signature.v;
|
|
532
|
-
dataIndex++;
|
|
533
|
-
|
|
534
|
-
// Pack r (32 bytes)
|
|
535
|
-
const rBytes = Buffer.from(signature.r.slice(2), 'hex');
|
|
536
|
-
signaturesOrAddresses.set(rBytes, dataIndex);
|
|
537
|
-
dataIndex += 32;
|
|
538
|
-
|
|
539
|
-
// Pack s (32 bytes)
|
|
540
|
-
const sBytes = Buffer.from(signature.s.slice(2), 'hex');
|
|
541
|
-
signaturesOrAddresses.set(sBytes, dataIndex);
|
|
542
|
-
dataIndex += 32;
|
|
543
|
-
} else {
|
|
544
|
-
// Pack address only (20 bytes)
|
|
545
|
-
const addrBytes = Buffer.from(attestation.addr.slice(2), 'hex');
|
|
546
|
-
signaturesOrAddresses.set(addrBytes, dataIndex);
|
|
547
|
-
dataIndex += 20;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
return {
|
|
552
|
-
signatureIndices: `0x${Buffer.from(signatureIndices).toString('hex')}`,
|
|
553
|
-
signaturesOrAddresses: `0x${Buffer.from(signaturesOrAddresses).toString('hex')}`,
|
|
554
|
-
};
|
|
555
|
-
}
|
|
556
|
-
|
|
557
535
|
/**
|
|
558
536
|
* @notice Calls `canProposeAtTime` with the time of the next Ethereum block and the sender address
|
|
559
537
|
*
|
|
@@ -618,7 +596,7 @@ export class RollupContract {
|
|
|
618
596
|
/** Creates a request to Rollup#invalidateBadAttestation to be simulated or sent */
|
|
619
597
|
public buildInvalidateBadAttestationRequest(
|
|
620
598
|
blockNumber: number,
|
|
621
|
-
|
|
599
|
+
attestationsAndSigners: ViemCommitteeAttestations,
|
|
622
600
|
committee: EthAddress[],
|
|
623
601
|
invalidIndex: number,
|
|
624
602
|
): L1TxRequest {
|
|
@@ -629,7 +607,7 @@ export class RollupContract {
|
|
|
629
607
|
functionName: 'invalidateBadAttestation',
|
|
630
608
|
args: [
|
|
631
609
|
BigInt(blockNumber),
|
|
632
|
-
|
|
610
|
+
attestationsAndSigners,
|
|
633
611
|
committee.map(addr => addr.toString()),
|
|
634
612
|
BigInt(invalidIndex),
|
|
635
613
|
],
|
|
@@ -640,7 +618,7 @@ export class RollupContract {
|
|
|
640
618
|
/** Creates a request to Rollup#invalidateInsufficientAttestations to be simulated or sent */
|
|
641
619
|
public buildInvalidateInsufficientAttestationsRequest(
|
|
642
620
|
blockNumber: number,
|
|
643
|
-
|
|
621
|
+
attestationsAndSigners: ViemCommitteeAttestations,
|
|
644
622
|
committee: EthAddress[],
|
|
645
623
|
): L1TxRequest {
|
|
646
624
|
return {
|
|
@@ -648,11 +626,7 @@ export class RollupContract {
|
|
|
648
626
|
data: encodeFunctionData({
|
|
649
627
|
abi: RollupAbi,
|
|
650
628
|
functionName: 'invalidateInsufficientAttestations',
|
|
651
|
-
args: [
|
|
652
|
-
BigInt(blockNumber),
|
|
653
|
-
RollupContract.packAttestations(attestations),
|
|
654
|
-
committee.map(addr => addr.toString()),
|
|
655
|
-
],
|
|
629
|
+
args: [BigInt(blockNumber), attestationsAndSigners, committee.map(addr => addr.toString())],
|
|
656
630
|
}),
|
|
657
631
|
};
|
|
658
632
|
}
|
|
@@ -742,6 +716,10 @@ export class RollupContract {
|
|
|
742
716
|
return this.rollup.read.getStakingAsset();
|
|
743
717
|
}
|
|
744
718
|
|
|
719
|
+
getRewardConfig() {
|
|
720
|
+
return this.rollup.read.getRewardConfig();
|
|
721
|
+
}
|
|
722
|
+
|
|
745
723
|
setupEpoch(l1TxUtils: L1TxUtils) {
|
|
746
724
|
return l1TxUtils.sendAndMonitorTransaction({
|
|
747
725
|
to: this.address,
|
|
@@ -764,7 +742,9 @@ export class RollupContract {
|
|
|
764
742
|
});
|
|
765
743
|
}
|
|
766
744
|
|
|
767
|
-
public listenToSlasherChanged(
|
|
745
|
+
public listenToSlasherChanged(
|
|
746
|
+
callback: (args: { oldSlasher: `0x${string}`; newSlasher: `0x${string}` }) => unknown,
|
|
747
|
+
): WatchContractEventReturnType {
|
|
768
748
|
return this.rollup.watchEvent.SlasherUpdated(
|
|
769
749
|
{},
|
|
770
750
|
{
|
|
@@ -780,6 +760,22 @@ export class RollupContract {
|
|
|
780
760
|
);
|
|
781
761
|
}
|
|
782
762
|
|
|
763
|
+
public listenToBlockInvalidated(callback: (args: { blockNumber: bigint }) => unknown): WatchContractEventReturnType {
|
|
764
|
+
return this.rollup.watchEvent.BlockInvalidated(
|
|
765
|
+
{},
|
|
766
|
+
{
|
|
767
|
+
onLogs: logs => {
|
|
768
|
+
for (const log of logs) {
|
|
769
|
+
const args = log.args;
|
|
770
|
+
if (args.blockNumber !== undefined) {
|
|
771
|
+
callback({ blockNumber: args.blockNumber });
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
},
|
|
775
|
+
},
|
|
776
|
+
);
|
|
777
|
+
}
|
|
778
|
+
|
|
783
779
|
public async getSlashEvents(l1BlockHash: Hex): Promise<{ amount: bigint; attester: EthAddress }[]> {
|
|
784
780
|
const events = await this.rollup.getEvents.Slashed({}, { blockHash: l1BlockHash, strict: true });
|
|
785
781
|
return events.map(event => ({
|
|
@@ -788,7 +784,9 @@ export class RollupContract {
|
|
|
788
784
|
}));
|
|
789
785
|
}
|
|
790
786
|
|
|
791
|
-
public listenToSlash(
|
|
787
|
+
public listenToSlash(
|
|
788
|
+
callback: (args: { amount: bigint; attester: EthAddress }) => unknown,
|
|
789
|
+
): WatchContractEventReturnType {
|
|
792
790
|
return this.rollup.watchEvent.Slashed(
|
|
793
791
|
{},
|
|
794
792
|
{
|
|
@@ -38,6 +38,19 @@ export class SlasherContract {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Checks if slashing is currently enabled. Slashing can be disabled by the vetoer.
|
|
43
|
+
* @returns True if slashing is enabled, false otherwise
|
|
44
|
+
*/
|
|
45
|
+
public async isSlashingEnabled(): Promise<boolean> {
|
|
46
|
+
try {
|
|
47
|
+
return await this.contract.read.isSlashingEnabled();
|
|
48
|
+
} catch (error) {
|
|
49
|
+
this.log.error(`Error checking if slashing is enabled`, error);
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
41
54
|
/**
|
|
42
55
|
* Gets the current vetoer address.
|
|
43
56
|
* @returns The vetoer address
|
|
@@ -47,6 +60,15 @@ export class SlasherContract {
|
|
|
47
60
|
return EthAddress.fromString(vetoer);
|
|
48
61
|
}
|
|
49
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Gets the disable duration by the vetoer.
|
|
65
|
+
* @returns The disable duration in seconds
|
|
66
|
+
*/
|
|
67
|
+
public async getSlashingDisableDuration(): Promise<number> {
|
|
68
|
+
const duration = await this.contract.read.SLASHING_DISABLE_DURATION();
|
|
69
|
+
return Number(duration);
|
|
70
|
+
}
|
|
71
|
+
|
|
50
72
|
/**
|
|
51
73
|
* Gets the current governance address.
|
|
52
74
|
* @returns The governance address
|
|
@@ -2,9 +2,9 @@ import { type L1TxRequest, type ViemClient, tryExtractEvent } from '@aztec/ether
|
|
|
2
2
|
import { Buffer32 } from '@aztec/foundation/buffer';
|
|
3
3
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
4
|
import { Signature } from '@aztec/foundation/eth-signature';
|
|
5
|
+
import { hexToBuffer } from '@aztec/foundation/string';
|
|
5
6
|
import { TallySlashingProposerAbi } from '@aztec/l1-artifacts/TallySlashingProposerAbi';
|
|
6
7
|
|
|
7
|
-
import EventEmitter from 'events';
|
|
8
8
|
import {
|
|
9
9
|
type GetContractReturnType,
|
|
10
10
|
type Hex,
|
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
* Wrapper around the TallySlashingProposer contract that provides
|
|
19
19
|
* a TypeScript interface for interacting with the consensus-based slashing system.
|
|
20
20
|
*/
|
|
21
|
-
export class TallySlashingProposerContract
|
|
21
|
+
export class TallySlashingProposerContract {
|
|
22
22
|
private readonly contract: GetContractReturnType<typeof TallySlashingProposerAbi, ViemClient>;
|
|
23
23
|
|
|
24
24
|
public readonly type = 'tally' as const;
|
|
@@ -27,7 +27,6 @@ export class TallySlashingProposerContract extends EventEmitter {
|
|
|
27
27
|
public readonly client: ViemClient,
|
|
28
28
|
address: Hex | EthAddress,
|
|
29
29
|
) {
|
|
30
|
-
super();
|
|
31
30
|
this.contract = getContract({
|
|
32
31
|
address: typeof address === 'string' ? address : address.toString(),
|
|
33
32
|
abi: TallySlashingProposerAbi,
|
|
@@ -86,11 +85,20 @@ export class TallySlashingProposerContract extends EventEmitter {
|
|
|
86
85
|
*/
|
|
87
86
|
public async getRound(round: bigint): Promise<{
|
|
88
87
|
isExecuted: boolean;
|
|
89
|
-
readyToExecute: boolean;
|
|
90
88
|
voteCount: bigint;
|
|
91
89
|
}> {
|
|
92
|
-
const [isExecuted,
|
|
93
|
-
return { isExecuted,
|
|
90
|
+
const [isExecuted, voteCount] = await this.contract.read.getRound([round]);
|
|
91
|
+
return { isExecuted, voteCount };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check if a round is ready to execute at a given slot
|
|
96
|
+
* @param round - The round number to check
|
|
97
|
+
* @param slot - The slot number to check at
|
|
98
|
+
* @returns Whether the round is ready to execute
|
|
99
|
+
*/
|
|
100
|
+
public async isRoundReadyToExecute(round: bigint, slot: bigint): Promise<boolean> {
|
|
101
|
+
return await this.contract.read.isRoundReadyToExecute([round, slot]);
|
|
94
102
|
}
|
|
95
103
|
|
|
96
104
|
/** Returns the slash actions and payload address for a given round (zero if no slash actions) */
|
|
@@ -221,6 +229,21 @@ export class TallySlashingProposerContract extends EventEmitter {
|
|
|
221
229
|
};
|
|
222
230
|
}
|
|
223
231
|
|
|
232
|
+
/** Returns the last vote emitted for a given round */
|
|
233
|
+
public async getLastVote(round: bigint) {
|
|
234
|
+
const { voteCount } = await this.getRound(round);
|
|
235
|
+
const validators = (await this.contract.simulate.getSlashTargetCommittees([round])).result.flat();
|
|
236
|
+
const vote = await this.contract.read.getVotes([round, voteCount - 1n]);
|
|
237
|
+
const decoded = decodeSlashConsensusVotes(hexToBuffer(vote));
|
|
238
|
+
const slashAmounts = await this.getSlashingAmounts();
|
|
239
|
+
return decoded
|
|
240
|
+
.map((units, i) => ({
|
|
241
|
+
validator: EthAddress.fromString(validators[i]),
|
|
242
|
+
slashAmount: slashAmounts[units - 1] ?? 0n,
|
|
243
|
+
}))
|
|
244
|
+
.filter(v => v.slashAmount > 0n);
|
|
245
|
+
}
|
|
246
|
+
|
|
224
247
|
/**
|
|
225
248
|
* Listen for VoteCast events
|
|
226
249
|
* @param callback - Callback function to handle vote cast events
|
|
@@ -265,3 +288,28 @@ export class TallySlashingProposerContract extends EventEmitter {
|
|
|
265
288
|
);
|
|
266
289
|
}
|
|
267
290
|
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Decodes a Buffer containing slash votes back into an array of numbers.
|
|
294
|
+
* Each vote is represented as a 2-bit value (0, 1, 2, or 3) representing slashing units.
|
|
295
|
+
* @dev This should live in stdlib next to encodeSlashConsensusVotes but is here since we
|
|
296
|
+
* do not have a dependency to stdlib from the ethereum package. We need a larger refactor to fix this.
|
|
297
|
+
* @param buffer - The Buffer containing encoded slash votes
|
|
298
|
+
* @returns An array of numbers representing the slash votes
|
|
299
|
+
*/
|
|
300
|
+
export function decodeSlashConsensusVotes(buffer: Buffer): number[] {
|
|
301
|
+
const votes: number[] = [];
|
|
302
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
303
|
+
const voteByte = buffer.readUInt8(i);
|
|
304
|
+
// Decode votes from Solidity's bit order (LSB to MSB)
|
|
305
|
+
// Bits 0-1: validator at index i*4
|
|
306
|
+
// Bits 2-3: validator at index i*4+1
|
|
307
|
+
// Bits 4-5: validator at index i*4+2
|
|
308
|
+
// Bits 6-7: validator at index i*4+3
|
|
309
|
+
votes.push((voteByte >> 0) & 0x03);
|
|
310
|
+
votes.push((voteByte >> 2) & 0x03);
|
|
311
|
+
votes.push((voteByte >> 4) & 0x03);
|
|
312
|
+
votes.push((voteByte >> 6) & 0x03);
|
|
313
|
+
}
|
|
314
|
+
return votes;
|
|
315
|
+
}
|