Skip to content

Commit

Permalink
add attester slashing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mehdi-aouadi committed Jan 25, 2024
1 parent f4d06ad commit ea839de
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,14 @@

package tech.pegasys.teku.test.acceptance;

import java.io.IOException;
import java.util.List;
import org.junit.jupiter.api.Test;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import tech.pegasys.teku.bls.BLSKeyPair;
import tech.pegasys.teku.bls.BLSSecretKey;
import tech.pegasys.teku.infrastructure.time.SystemTimeProvider;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.datastructures.interop.MockStartValidatorKeyPairFactory;
Expand All @@ -28,8 +33,19 @@ public class ValidatorSlashingDetectionAcceptanceTest extends AcceptanceTestBase
private final SystemTimeProvider timeProvider = new SystemTimeProvider();
private final String network = "swift";

@Test
void shouldShutDownWhenOwnedValidatorSlashed_SingleProcess_SinglePeer() throws Exception {
private enum SlashingEventType {
PROPOSER_SLASHING,
ATTESTER_SLASHING;
}

public static Stream<Arguments> getSlashingEventTypes() {
return Stream.of(SlashingEventType.values()).map(Arguments::of);
}

@ParameterizedTest
@MethodSource("getSlashingEventTypes")
void shouldShutDownWhenOwnedValidatorSlashed_SingleProcess_SinglePeer(
final SlashingEventType slashingEventType) throws Exception {

final int genesisTime = timeProvider.getTimeInSeconds().plus(10).intValue();
final UInt64 altairEpoch = UInt64.valueOf(100);
Expand All @@ -51,19 +67,23 @@ void shouldShutDownWhenOwnedValidatorSlashed_SingleProcess_SinglePeer() throws E
new MockStartValidatorKeyPairFactory().generateKeyPairs(0, slashedValidatorIndex + 1);
final BLSKeyPair slashedValidatorKeyPair = blsKeyPairs.get(slashedValidatorIndex);

tekuNode.postProposerSlashing(
postSlashing(
UInt64.valueOf(3),
UInt64.valueOf(slashedValidatorIndex),
slashedValidatorKeyPair.getSecretKey());
slashedValidatorKeyPair.getSecretKey(),
tekuNode,
slashingEventType);

tekuNode.waitForLogMessageContaining(
String.format(
"Validator(s) with public key(s) %s got slashed. Shutting down...",
slashedValidatorKeyPair.getPublicKey().toHexString()));
}

@Test
void shouldShutDownWhenOwnedValidatorSlashed_StandAloneVC_SinglePeer() throws Exception {
@ParameterizedTest
@MethodSource("getSlashingEventTypes")
void shouldShutDownWhenOwnedValidatorSlashed_StandAloneVC_SinglePeer(
final SlashingEventType slashingEventType) throws Exception {

final int genesisTime = timeProvider.getTimeInSeconds().plus(10).intValue();
final UInt64 altairEpoch = UInt64.valueOf(100);
Expand All @@ -90,19 +110,23 @@ void shouldShutDownWhenOwnedValidatorSlashed_StandAloneVC_SinglePeer() throws Ex
new MockStartValidatorKeyPairFactory().generateKeyPairs(0, slashedValidatorIndex + 1);
final BLSKeyPair slashedValidatorKeyPair = blsKeyPairs.get(slashedValidatorIndex);

beaconNode.postProposerSlashing(
postSlashing(
UInt64.valueOf(3),
UInt64.valueOf(slashedValidatorIndex),
slashedValidatorKeyPair.getSecretKey());
slashedValidatorKeyPair.getSecretKey(),
beaconNode,
slashingEventType);

validatorClient.waitForLogMessageContaining(
String.format(
"Validator(s) with public key(s) %s got slashed. Shutting down...",
slashedValidatorKeyPair.getPublicKey().toHexString()));
}

@Test
void shouldShutDownWhenOwnedValidatorSlashed_SingleProcess_MultiplePeers() throws Exception {
@ParameterizedTest
@MethodSource("getSlashingEventTypes")
void shouldShutDownWhenOwnedValidatorSlashed_SingleProcess_MultiplePeers(
final SlashingEventType slashingEventType) throws Exception {

final int genesisTime = timeProvider.getTimeInSeconds().plus(10).intValue();
final UInt64 altairEpoch = UInt64.valueOf(100);
Expand Down Expand Up @@ -136,10 +160,12 @@ void shouldShutDownWhenOwnedValidatorSlashed_SingleProcess_MultiplePeers() throw
new MockStartValidatorKeyPairFactory().generateKeyPairs(0, 34 + 1);
final BLSKeyPair slashedValidatorKeyPair = blsKeyPairs.get(slashedValidatorIndex);

firstTekuNode.postProposerSlashing(
postSlashing(
UInt64.valueOf(3),
UInt64.valueOf(slashedValidatorIndex),
slashedValidatorKeyPair.getSecretKey());
slashedValidatorKeyPair.getSecretKey(),
firstTekuNode,
slashingEventType);

secondTekuNode.waitForLogMessageContaining(
String.format(
Expand All @@ -149,8 +175,10 @@ void shouldShutDownWhenOwnedValidatorSlashed_SingleProcess_MultiplePeers() throw
firstTekuNode.stop();
}

@Test
void shouldShutDownWhenOwnedValidatorSlashed_StandAloneVC_MultiplePeers() throws Exception {
@ParameterizedTest
@MethodSource("getSlashingEventTypes")
void shouldShutDownWhenOwnedValidatorSlashed_StandAloneVC_MultiplePeers(
final SlashingEventType slashingEventType) throws Exception {

final int genesisTime = timeProvider.getTimeInSeconds().plus(10).intValue();
final UInt64 altairEpoch = UInt64.valueOf(100);
Expand Down Expand Up @@ -194,10 +222,12 @@ void shouldShutDownWhenOwnedValidatorSlashed_StandAloneVC_MultiplePeers() throws
new MockStartValidatorKeyPairFactory().generateKeyPairs(0, 34 + 1);
final BLSKeyPair slashedValidatorKeyPair = blsKeyPairs.get(slashedValidatorIndex);

firstTekuNode.postProposerSlashing(
postSlashing(
UInt64.valueOf(3),
UInt64.valueOf(slashedValidatorIndex),
slashedValidatorKeyPair.getSecretKey());
slashedValidatorKeyPair.getSecretKey(),
firstTekuNode,
slashingEventType);

secondValidatorClient.waitForLogMessageContaining(
String.format(
Expand All @@ -211,4 +241,19 @@ void shouldShutDownWhenOwnedValidatorSlashed_StandAloneVC_MultiplePeers() throws
private TekuNode.Config configureNode(final TekuNode.Config node, final int genesisTime) {
return node.withNetwork(network).withGenesisTime(genesisTime).withRealNetwork();
}

private void postSlashing(
final UInt64 slashingSlot,
final UInt64 slashedIndex,
final BLSSecretKey slashedValidatorSecretKey,
final TekuNode tekuNode,
final SlashingEventType slashingEventType)
throws IOException {
switch (slashingEventType) {
case ATTESTER_SLASHING -> tekuNode.postAttesterSlashing(
slashingSlot, slashedIndex, slashedValidatorSecretKey);
case PROPOSER_SLASHING -> tekuNode.postProposerSlashing(
slashingSlot, slashedIndex, slashedValidatorSecretKey);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,12 @@
import tech.pegasys.teku.api.response.v1.validator.PostValidatorLivenessResponse;
import tech.pegasys.teku.api.response.v1.validator.ValidatorLiveness;
import tech.pegasys.teku.api.response.v2.beacon.GetBlockResponseV2;
import tech.pegasys.teku.api.schema.AttestationData;
import tech.pegasys.teku.api.schema.AttesterSlashing;
import tech.pegasys.teku.api.schema.BLSSignature;
import tech.pegasys.teku.api.schema.BeaconBlockHeader;
import tech.pegasys.teku.api.schema.Checkpoint;
import tech.pegasys.teku.api.schema.IndexedAttestation;
import tech.pegasys.teku.api.schema.ProposerSlashing;
import tech.pegasys.teku.api.schema.SignedBeaconBlock;
import tech.pegasys.teku.api.schema.SignedBeaconBlockHeader;
Expand Down Expand Up @@ -118,6 +122,7 @@ public class TekuNode extends Node {
private static final Logger LOG = LogManager.getLogger();
public static final String LOCAL_VALIDATOR_LIVENESS_URL = "/eth/v1/validator/liveness/{epoch}";
public static final String POST_PROPOSER_SLASHING_URL = "/eth/v1/beacon/pool/proposer_slashings";
public static final String POST_ATTESTER_SLASHING_URL = "/eth/v1/beacon/pool/attester_slashings";
private final Config config;
private final Spec spec;
private Optional<EventStreamListener> maybeEventStreamListener = Optional.empty();
Expand Down Expand Up @@ -330,6 +335,56 @@ public String postProposerSlashing(
return httpClient.post(getRestApiUrl(), POST_PROPOSER_SLASHING_URL, body);
}

public String postAttesterSlashing(
final UInt64 slashingSlot,
final UInt64 slashedIndex,
final BLSSecretKey slashedValidatorSecretKey)
throws IOException {

final Fork fork = spec.getForkSchedule().getFork(spec.computeEpochAtSlot(slashingSlot));
final Bytes32 genesisValidatorRoot = fetchGenesis().getGenesisValidatorsRoot();
final ForkInfo forkInfo = new ForkInfo(fork, genesisValidatorRoot);
final SigningRootUtil signingRootUtil = new SigningRootUtil(spec);

final AttestationData attestationData1 =
new AttestationData(
slashingSlot,
slashedIndex,
Bytes32.random(),
new Checkpoint(UInt64.valueOf(1), Bytes32.random()),
new Checkpoint(UInt64.valueOf(2), Bytes32.random()));
final BLSSignature blsSignature1 =
new BLSSignature(
BLS.sign(
slashedValidatorSecretKey,
signingRootUtil.signingRootForSignAttestationData(
attestationData1.asInternalAttestationData(), forkInfo)));
final IndexedAttestation indexedAttestation1 =
new IndexedAttestation(List.of(slashedIndex), attestationData1, blsSignature1);

final AttestationData attestationData2 =
new AttestationData(
slashingSlot,
slashedIndex,
Bytes32.random(),
new Checkpoint(UInt64.valueOf(1), Bytes32.random()),
new Checkpoint(UInt64.valueOf(2), Bytes32.random()));
final BLSSignature blsSignature2 =
new BLSSignature(
BLS.sign(
slashedValidatorSecretKey,
signingRootUtil.signingRootForSignAttestationData(
attestationData2.asInternalAttestationData(), forkInfo)));
final IndexedAttestation indexedAttestation2 =
new IndexedAttestation(List.of(slashedIndex), attestationData2, blsSignature2);

final AttesterSlashing attesterSlashing =
new AttesterSlashing(indexedAttestation1, indexedAttestation2);
final String body = JSON_PROVIDER.objectToJSON(attesterSlashing);

return httpClient.post(getRestApiUrl(), POST_ATTESTER_SLASHING_URL, body);
}

public void submitBlsToExecutionChange(
final int validatorIndex,
final BLSKeyPair validatorKeyPair,
Expand Down

0 comments on commit ea839de

Please sign in to comment.