Skip to content

Commit e6f9e87

Browse files
author
AztecBot
committed
Merge branch 'next' into merge-train/barretenberg
2 parents 77fb5fb + e353048 commit e6f9e87

File tree

46 files changed

+843
-335
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+843
-335
lines changed

.test_patterns.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@ tests:
221221
error_regex: "expect\\(received\\).toContain\\(expected\\)"
222222
owners:
223223
- *palla
224+
# http://ci.aztec-labs.com/3b197577b96c3639
225+
# http://ci.aztec-labs.com/d429457d95d075e2
226+
- regex: "src/e2e_p2p/slash_veto_demo.test.ts"
227+
error_regex: "timeout: sending signal TERM to command|ValidatorSelection__InsufficientValidatorSetSize"
228+
owners:
229+
- *palla
224230

225231
# yarn-project tests
226232
- regex: "p2p/src/services/discv5/discv5_service.test.ts"

docs/docs/developers/reference/environment_reference/cli_reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ aztec start --port 8081 --pxe --pxe.nodeUrl=$BOOTNODE --pxe.proverEnabled true -
301301
#### Example Usage
302302

303303
```bash
304-
aztec start --network alpha-testnet --l1-rpc-urls https://example.com --l1-consensus-host-urls https://example.com --sequencer.blobSinkUrl http://34.82.117.158:5052 --sequencer.validatorPrivateKey 0xYourPrivateKey --sequencer.coinbase 0xYourAddress --p2p.p2pIp 999.99.999.99
304+
aztec start --network alpha-testnet --l1-rpc-urls https://example.com --l1-consensus-host-urls https://example.com --sequencer.blobSinkUrl http://34.82.117.158:5052 --sequencer.validatorPrivateKeys 0xYourPrivateKey --sequencer.coinbase 0xYourAddress --p2p.p2pIp 999.99.999.99
305305
```
306306

307307
#### Blob Sink Options

docs/docs/the_aztec_network/guides/run_nodes/how_to_run_sequencer.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ aztec start --node --archiver --sequencer \
8181
--network alpha-testnet \
8282
--l1-rpc-urls $ETHEREUM_HOSTS \
8383
--l1-consensus-host-urls $L1_CONSENSUS_HOST_URLS \
84-
--sequencer.validatorPrivateKey $VALIDATOR_PRIVATE_KEY \
84+
--sequencer.validatorPrivateKeys $VALIDATOR_PRIVATE_KEY \
8585
--sequencer.coinbase $COINBASE \
8686
--p2p.p2pIp $P2P_IP
8787
```
@@ -146,7 +146,7 @@ To use the `aztec start` command, you need to obtain the following:
146146

147147
#### Ethereum Keys
148148

149-
You will need an Ethereum private key and the corresponding public address. The private key is set via the `--sequencer.validatorPrivateKey` flag while the public address should be specified via the `--sequencer.coinbase ` flag.
149+
You will need an Ethereum private key and the corresponding public address. The private key is set via the `--sequencer.validatorPrivateKeys` flag while the public address should be specified via the `--sequencer.coinbase ` flag.
150150

151151
The private key is needed as your validator will post blocks to Ethereum, and the public address will be the recipient of any block rewards.
152152

@@ -176,7 +176,7 @@ aztec start --node --archiver --sequencer \
176176
--network alpha-testnet \
177177
--l1-rpc-urls https://example.com \
178178
--l1-consensus-host-urls https://example.com \
179-
--sequencer.validatorPrivateKey 0xYourPrivateKey \
179+
--sequencer.validatorPrivateKeys 0xYourPrivateKey \
180180
--sequencer.coinbase 0xYourAddress \
181181
--p2p.p2pIp 999.99.999.99 \
182182
--p2p.maxTxPoolSize 1000000000

docs/versioned_docs/version-v1.2.0/developers/reference/environment_reference/cli_reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ aztec start --port 8081 --pxe --pxe.nodeUrl=$BOOTNODE --pxe.proverEnabled true -
301301
#### Example Usage
302302

303303
```bash
304-
aztec start --network alpha-testnet --l1-rpc-urls https://example.com --l1-consensus-host-urls https://example.com --sequencer.blobSinkUrl http://34.82.117.158:5052 --sequencer.validatorPrivateKey 0xYourPrivateKey --sequencer.coinbase 0xYourAddress --p2p.p2pIp 999.99.999.99
304+
aztec start --network alpha-testnet --l1-rpc-urls https://example.com --l1-consensus-host-urls https://example.com --sequencer.blobSinkUrl http://34.82.117.158:5052 --sequencer.validatorPrivateKeys 0xYourPrivateKey --sequencer.coinbase 0xYourAddress --p2p.p2pIp 999.99.999.99
305305
```
306306

307307
#### Blob Sink Options

docs/versioned_docs/version-v1.2.0/the_aztec_network/guides/run_nodes/how_to_run_sequencer.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ aztec start --node --archiver --sequencer \
8181
--network alpha-testnet \
8282
--l1-rpc-urls $ETHEREUM_HOSTS \
8383
--l1-consensus-host-urls $L1_CONSENSUS_HOST_URLS \
84-
--sequencer.validatorPrivateKey $VALIDATOR_PRIVATE_KEY \
84+
--sequencer.validatorPrivateKeys $VALIDATOR_PRIVATE_KEY \
8585
--sequencer.coinbase $COINBASE \
8686
--p2p.p2pIp $P2P_IP
8787
```
@@ -146,7 +146,7 @@ To use the `aztec start` command, you need to obtain the following:
146146

147147
#### Ethereum Keys
148148

149-
You will need an Ethereum private key and the corresponding public address. The private key is set via the `--sequencer.validatorPrivateKey` flag while the public address should be specified via the `--sequencer.coinbase ` flag.
149+
You will need an Ethereum private key and the corresponding public address. The private key is set via the `--sequencer.validatorPrivateKeys` flag while the public address should be specified via the `--sequencer.coinbase ` flag.
150150

151151
The private key is needed as your validator will post blocks to Ethereum, and the public address will be the recipient of any block rewards.
152152

@@ -176,7 +176,7 @@ aztec start --node --archiver --sequencer \
176176
--network alpha-testnet \
177177
--l1-rpc-urls https://example.com \
178178
--l1-consensus-host-urls https://example.com \
179-
--sequencer.validatorPrivateKey 0xYourPrivateKey \
179+
--sequencer.validatorPrivateKeys 0xYourPrivateKey \
180180
--sequencer.coinbase 0xYourAddress \
181181
--p2p.p2pIp 999.99.999.99 \
182182
--p2p.maxTxPoolSize 1000000000

spartan/bootstrap.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ function network_test_cmds {
7979
local run_test_script="yarn-project/end-to-end/scripts/run_test.sh"
8080
echo $run_test_script simple src/spartan/smoke.test.ts
8181
echo $run_test_script simple src/spartan/transfer.test.ts
82+
echo $run_test_script simple src/spartan/slash_inactivity.test.ts
8283
}
8384

8485
function single_test {

spartan/environments/scenario.local.env

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,18 @@ SALT=123
55
LABS_INFRA_MNEMONIC="test test test test test test test test test test test junk"
66
FUNDING_PRIVATE_KEY="0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
77
REAL_VERIFIER=false
8-
AZTEC_EPOCH_DURATION=8
8+
SENTINEL_ENABLED=true
9+
10+
AZTEC_EPOCH_DURATION=4
911
AZTEC_SLOT_DURATION=24
12+
AZTEC_SLASHING_ROUND_SIZE_IN_EPOCHS=2
13+
AZTEC_SLASHING_EXECUTION_DELAY_IN_ROUNDS=1
14+
AZTEC_SLASHING_OFFSET_IN_ROUNDS=1
15+
AZTEC_ACTIVATION_THRESHOLD=100000000000000000000
16+
AZTEC_EJECTION_THRESHOLD=50000000000000000000
17+
AZTEC_SLASH_AMOUNT_SMALL=5000000000000000000
18+
AZTEC_SLASH_AMOUNT_MEDIUM=10000000000000000000
19+
AZTEC_SLASH_AMOUNT_LARGE=15000000000000000000
1020

1121
# The following need to be set manually
1222
# AZTEC_DOCKER_IMAGE=aztecprotocol/aztec:whatever

yarn-project/aztec-node/src/aztec-node/server.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1122,7 +1122,7 @@ export class AztecNodeService implements AztecNode, AztecNodeAdmin, Traceable {
11221122

11231123
public async setConfig(config: Partial<AztecNodeAdminConfig>): Promise<void> {
11241124
const newConfig = { ...this.config, ...config };
1125-
this.sequencer?.updateSequencerConfig(config);
1125+
this.sequencer?.updateConfig(config);
11261126
this.slasherClient?.updateConfig(config);
11271127
this.validatorsSentinel?.updateConfig(config);
11281128
// this.blockBuilder.updateConfig(config); // TODO: Spyros has a PR to add the builder to `this`, so we can do this

yarn-project/aztec-node/src/sentinel/sentinel.test.ts

Lines changed: 48 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Secp256k1Signer } from '@aztec/foundation/crypto';
44
import { EthAddress } from '@aztec/foundation/eth-address';
55
import { AztecLMDBStoreV2, openTmpStore } from '@aztec/kv-store/lmdb-v2';
66
import type { P2PClient } from '@aztec/p2p';
7-
import { OffenseType, WANT_TO_SLASH_EVENT } from '@aztec/slasher';
7+
import { OffenseType, WANT_TO_SLASH_EVENT, type WantToSlashArgs } from '@aztec/slasher';
88
import type { SlasherConfig } from '@aztec/slasher/config';
99
import {
1010
type L2BlockSource,
@@ -24,7 +24,7 @@ import type {
2424
} from '@aztec/stdlib/validators';
2525

2626
import { jest } from '@jest/globals';
27-
import { type MockProxy, mock, mockDeep } from 'jest-mock-extended';
27+
import { type MockProxy, mock } from 'jest-mock-extended';
2828

2929
import { Sentinel } from './sentinel.js';
3030
import { SentinelStore } from './store.js';
@@ -287,8 +287,8 @@ describe('sentinel', () => {
287287
jest.spyOn(sentinel, 'computeStatsForValidator').mockReturnValue({
288288
address: validator,
289289
totalSlots: 2,
290-
missedProposals: { count: 0, currentStreak: 0, rate: 0 },
291-
missedAttestations: { count: 0, currentStreak: 0, rate: 0 },
290+
missedProposals: { count: 0, currentStreak: 0, rate: 0, total: 0 },
291+
missedAttestations: { count: 0, currentStreak: 0, rate: 0, total: 0 },
292292
history: mockHistory,
293293
});
294294

@@ -298,8 +298,8 @@ describe('sentinel', () => {
298298
validator: {
299299
address: validator,
300300
totalSlots: 2,
301-
missedProposals: { count: 0, currentStreak: 0, rate: 0 },
302-
missedAttestations: { count: 0, currentStreak: 0, rate: 0 },
301+
missedProposals: { count: 0, currentStreak: 0, rate: 0, total: 0 },
302+
missedAttestations: { count: 0, currentStreak: 0, rate: 0, total: 0 },
303303
history: mockHistory,
304304
},
305305
allTimeProvenPerformance: mockProvenPerformance,
@@ -316,8 +316,8 @@ describe('sentinel', () => {
316316
const computeStatsSpy = jest.spyOn(sentinel, 'computeStatsForValidator').mockReturnValue({
317317
address: validator,
318318
totalSlots: 1,
319-
missedProposals: { count: 0, currentStreak: 0, rate: 0 },
320-
missedAttestations: { count: 0, currentStreak: 0, rate: 0 },
319+
missedProposals: { count: 0, currentStreak: 0, rate: 0, total: 0 },
320+
missedAttestations: { count: 0, currentStreak: 0, rate: 0, total: 0 },
321321
history: mockHistory,
322322
});
323323

@@ -333,8 +333,8 @@ describe('sentinel', () => {
333333
const computeStatsSpy = jest.spyOn(sentinel, 'computeStatsForValidator').mockReturnValue({
334334
address: validator,
335335
totalSlots: 1,
336-
missedProposals: { count: 0, currentStreak: 0, rate: 0 },
337-
missedAttestations: { count: 0, currentStreak: 0, rate: 0 },
336+
missedProposals: { count: 0, currentStreak: 0, rate: 0, total: 0 },
337+
missedAttestations: { count: 0, currentStreak: 0, rate: 0, total: 0 },
338338
history: mockHistory,
339339
});
340340

@@ -357,8 +357,8 @@ describe('sentinel', () => {
357357
jest.spyOn(sentinel, 'computeStatsForValidator').mockReturnValue({
358358
address: validator,
359359
totalSlots: 1,
360-
missedProposals: { count: 0, currentStreak: 0, rate: 0 },
361-
missedAttestations: { count: 0, currentStreak: 0, rate: 0 },
360+
missedProposals: { count: 0, currentStreak: 0, rate: 0, total: 0 },
361+
missedAttestations: { count: 0, currentStreak: 0, rate: 0, total: 0 },
362362
history: mockHistory,
363363
});
364364

@@ -379,65 +379,52 @@ describe('sentinel', () => {
379379
const epochNumber = getEpochAtSlot(slot, l1Constants);
380380
const validator1 = EthAddress.random();
381381
const validator2 = EthAddress.random();
382-
const headerSlots = times(5, i => slot - BigInt(i));
383-
const mockHeaders = headerSlots.map(s => {
384-
const header = mockDeep<PublishedL2Block['block']['header']>();
385-
header.getSlot.mockReturnValue(s);
386-
return header;
387-
});
382+
const validator3 = EthAddress.random();
383+
const headerSlots = times(l1Constants.epochDuration, i => slot - BigInt(i)).reverse();
388384

389385
epochCache.getEpochAndSlotNow.mockReturnValue({ epoch: epochNumber, slot, ts, now: ts });
390386
archiver.getBlock.calledWith(blockNumber).mockResolvedValue(mockBlock.block);
391387
archiver.getL1Constants.mockResolvedValue(l1Constants);
392-
393-
archiver.getBlockHeadersForEpoch.calledWith(epochNumber).mockResolvedValue(mockHeaders as any);
388+
epochCache.getL1Constants.mockReturnValue(l1Constants);
394389

395390
epochCache.getCommittee.mockResolvedValue({
396-
committee: [validator1, validator2],
391+
committee: [validator1, validator2, validator3],
397392
seed: 0n,
398393
epoch: epochNumber,
399394
});
400-
const statsResult = {
395+
396+
const statsResult: ValidatorsStats = {
401397
stats: {
398+
// Validator 1 missed 1 attestation only, we won't slash them
402399
[validator1.toString()]: {
403400
address: validator1,
404401
totalSlots: headerSlots.length,
405-
missedProposals: { count: 0, currentStreak: 0, rate: 0 },
406-
missedAttestations: { count: 1, currentStreak: 0, rate: 1 / 5 },
407-
history: [
408-
{ slot: headerSlots[0], status: 'attestation-sent' },
409-
{ slot: headerSlots[1], status: 'attestation-missed' },
410-
{ slot: headerSlots[2], status: 'attestation-sent' },
411-
{ slot: headerSlots[3], status: 'attestation-sent' },
412-
{ slot: headerSlots[4], status: 'attestation-sent' },
413-
],
414-
} as ValidatorStats,
402+
missedProposals: { count: 0, currentStreak: 0, rate: 0, total: 0 },
403+
missedAttestations: { count: 1, currentStreak: 0, rate: 1 / 8, total: 8 },
404+
history: [],
405+
},
406+
// Validator 2 missed 7 out of 8, we will slash them
415407
[validator2.toString()]: {
416408
address: validator2,
417409
totalSlots: headerSlots.length,
418-
missedProposals: { count: 0, currentStreak: 0, rate: 0 },
419-
// We should only count the slots that are in the proven epoch (0, 1, 2)!!
420-
missedAttestations: { count: 4, currentStreak: 3, rate: 4 / 5 },
421-
history: [
422-
{ slot: headerSlots[0], status: 'attestation-missed' },
423-
{ slot: headerSlots[1], status: 'attestation-sent' },
424-
{ slot: headerSlots[2], status: 'attestation-missed' },
425-
{ slot: headerSlots[3], status: 'attestation-missed' },
426-
{ slot: headerSlots[4], status: 'attestation-missed' },
427-
],
428-
} as ValidatorStats,
429-
'0xNotAnAddress': {
430-
address: EthAddress.ZERO, // Placeholder
431-
totalSlots: 0,
432-
missedProposals: { count: 0, currentStreak: 0, rate: undefined },
433-
missedAttestations: { count: 0, currentStreak: 0, rate: undefined },
410+
missedProposals: { count: 0, currentStreak: 0, rate: 0, total: 0 },
411+
missedAttestations: { count: 7, currentStreak: 3, rate: 7 / 8, total: 8 },
412+
history: [],
413+
},
414+
// Validator 3 missed 4 attestations out of 4, so we will slash them even though the epoch has 8 slots
415+
// This difference happens because we don't count attestations for a slot where there was no proposal
416+
[validator3.toString()]: {
417+
address: validator3,
418+
totalSlots: headerSlots.length,
419+
missedProposals: { count: 0, currentStreak: 0, rate: 0, total: 0 },
420+
missedAttestations: { count: 4, currentStreak: 4, rate: 4 / 4, total: 4 },
434421
history: [],
435-
} as ValidatorStats, // To test filtering
422+
},
436423
},
437424
lastProcessedSlot: slot,
438425
initialSlot: 0n,
439426
slotWindow: 15,
440-
} as ValidatorsStats;
427+
};
441428
const computeStatsSpy = jest.spyOn(sentinel, 'computeStats').mockResolvedValue(statsResult);
442429
const emitSpy = jest.spyOn(sentinel, 'emit');
443430

@@ -446,20 +433,20 @@ describe('sentinel', () => {
446433
expect(computeStatsSpy).toHaveBeenCalledWith({
447434
fromSlot: headerSlots[0],
448435
toSlot: headerSlots[headerSlots.length - 1],
436+
validators: [validator1, validator2, validator3],
437+
});
438+
const makeInactivitySlash = (validator: EthAddress): WantToSlashArgs => ({
439+
validator,
440+
amount: config.slashInactivityPenalty,
441+
offenseType: OffenseType.INACTIVITY,
442+
epochOrSlot: 1n,
449443
});
450444

451445
expect(emitSpy).toHaveBeenCalledTimes(1);
452-
expect(emitSpy).toHaveBeenCalledWith(
453-
WANT_TO_SLASH_EVENT,
454-
expect.arrayContaining([
455-
expect.objectContaining({
456-
validator: validator2,
457-
amount: config.slashInactivityPenalty,
458-
offenseType: OffenseType.INACTIVITY,
459-
epochOrSlot: epochNumber,
460-
}),
461-
]),
462-
);
446+
expect(emitSpy).toHaveBeenCalledWith(WANT_TO_SLASH_EVENT, [
447+
makeInactivitySlash(validator2),
448+
makeInactivitySlash(validator3),
449+
]);
463450
});
464451
});
465452

@@ -673,10 +660,6 @@ class TestSentinel extends Sentinel {
673660
return super.handleProvenPerformance(epoch, performance);
674661
}
675662

676-
public override updateProvenPerformance(epoch: bigint, performance: ValidatorsEpochPerformance) {
677-
return super.updateProvenPerformance(epoch, performance);
678-
}
679-
680663
public override getValidatorStats(validatorAddress: EthAddress, fromSlot?: bigint, toSlot?: bigint) {
681664
return super.getValidatorStats(validatorAddress, fromSlot, toSlot);
682665
}

0 commit comments

Comments
 (0)