Commit 8c28b149 authored by luxq's avatar luxq

fix compile error

parent ac83284e
jar { enabled = false }
dependencies {
implementation project(':infrastructure:async')
implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'org.apache.tuweni:tuweni-bytes'
testImplementation project(':infrastructure:test-support')
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-core'
testImplementation 'org.junit.jupiter:junit-jupiter-api'
testImplementation 'org.junit.jupiter:junit-jupiter-engine'
}
description = 'Teku Attacker Client'
\ No newline at end of file
package tech.pegasys.teku.attacker;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.HexFormat;
public class Attacker {
private static final AtomicBoolean initOnce = new AtomicBoolean(false);
private static String serviceUrl;
private static AttackClient client;
public static byte[] fromHex(String s) throws IllegalArgumentException {
String hex = s.startsWith("0x") ? s.substring(2) : s;
if (hex.length() % 2 != 0) {
throw new IllegalArgumentException("Invalid hex string");
}
return HexFormat.of().parseHex(hex);
}
private static void initAttacker() {
serviceUrl = System.getenv("ATTACKER_SERVICE_URL");
}
public static AttackClient getAttacker() {
if (initOnce.compareAndSet(false, true)) {
initAttacker();
}
if (client != null) {
return client;
}
if (serviceUrl == null || serviceUrl.isEmpty()) {
return null;
}
try {
client = AttackClient.dial(serviceUrl, 0);
return client;
} catch (Exception e) {
return null;
}
}
}
\ No newline at end of file
package tech.pegasys.teku.attacker.client;
import java.net.URI;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import org.apache.tuweni.bytes.Bytes;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
/**
* AttackerClient defines typed wrappers for the Attacker RPC API.
*/
public class AttackerClient {
private final RpcConnection rpcConnection;
private final int validatorIndex;
private static final String BLOCK_MODULE = "block";
private static final String ATTEST_MODULE = "attest";
/**
* Dial connects a client to the given URL.
*
* @param rawUrl The URL to connect to
* @param validatorIndex The validator index
* @return A new AttackerClient
* @throws Exception If connection fails
*/
public static AttackerClient dial(String rawUrl, int validatorIndex) throws Exception {
return new AttackerClient(new HttpRpcConnection(URI.create(rawUrl)), validatorIndex);
}
/**
* Creates a client that uses the given RPC connection.
*
* @param rpcConnection The RPC connection
* @param validatorIndex The validator index
*/
public AttackerClient(RpcConnection rpcConnection, int validatorIndex) {
this.rpcConnection = rpcConnection;
this.validatorIndex = validatorIndex;
}
/**
* Close closes the underlying RPC connection.
*/
public void close() {
rpcConnection.close();
}
/**
* Get new parent root for block.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param parentRoot The parent root
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> blockGetNewParentRoot(long slot, String pubkey, String parentRoot) {
return rpcConnection.call(
BLOCK_MODULE + "_getNewParentRoot",
AttackerResponse.class,
slot,
pubkey,
parentRoot);
}
/**
* Delay for receive block.
*
* @param slot The slot number
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> delayForReceiveBlock(long slot) {
return rpcConnection.call(
BLOCK_MODULE + "_delayForReceiveBlock",
AttackerResponse.class,
slot);
}
/**
* Before block broadcast.
*
* @param slot The slot number
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> blockBeforeBroadcast(long slot) {
return rpcConnection.call(
BLOCK_MODULE + "_beforeBroadCast",
AttackerResponse.class,
slot);
}
/**
* After block broadcast.
*
* @param slot The slot number
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> blockAfterBroadcast(long slot) {
return rpcConnection.call(
BLOCK_MODULE + "_afterBroadCast",
AttackerResponse.class,
slot);
}
/**
* Before sign block.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param blockDataBase64 The block data in base64 encoding
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> blockBeforeSign(long slot, String pubkey, String blockDataBase64) {
return rpcConnection.call(
BLOCK_MODULE + "_beforeSign",
AttackerResponse.class,
slot,
pubkey,
blockDataBase64);
}
/**
* After sign block.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param signedBlockDataBase64 The signed block data in base64 encoding
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> blockAfterSign(long slot, String pubkey, String signedBlockDataBase64) {
return rpcConnection.call(
BLOCK_MODULE + "_afterSign",
AttackerResponse.class,
slot,
pubkey,
signedBlockDataBase64);
}
/**
* Before propose block.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param signedBlockDataBase64 The signed block data in base64 encoding
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> blockBeforePropose(long slot, String pubkey, String signedBlockDataBase64) {
return rpcConnection.call(
BLOCK_MODULE + "_beforePropose",
AttackerResponse.class,
slot,
pubkey,
signedBlockDataBase64);
}
/**
* After propose block.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param signedBlockDataBase64 The signed block data in base64 encoding
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> blockAfterPropose(long slot, String pubkey, String signedBlockDataBase64) {
return rpcConnection.call(
BLOCK_MODULE + "_afterPropose",
AttackerResponse.class,
slot,
pubkey,
signedBlockDataBase64);
}
/**
* Before attestation broadcast.
*
* @param slot The slot number
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> attestBeforeBroadcast(long slot) {
return rpcConnection.call(
ATTEST_MODULE + "_beforeBroadCast",
AttackerResponse.class,
slot);
}
/**
* After attestation broadcast.
*
* @param slot The slot number
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> attestAfterBroadcast(long slot) {
return rpcConnection.call(
ATTEST_MODULE + "_afterBroadCast",
AttackerResponse.class,
slot);
}
/**
* Before signing attestation.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param attestDataBase64 The attestation data in base64 encoding
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> attestBeforeSign(
long slot,
String pubkey,
String attestDataBase64) {
return rpcConnection.call(
ATTEST_MODULE + "_beforeSign",
AttackerResponse.class,
slot,
pubkey,
attestDataBase64);
}
/**
* After signing attestation.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param signedAttestDataBase64 The signed attestation data in base64 encoding
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> attestAfterSign(
long slot,
String pubkey,
String signedAttestDataBase64) {
return rpcConnection.call(
ATTEST_MODULE + "_afterSign",
AttackerResponse.class,
slot,
pubkey,
signedAttestDataBase64);
}
/**
* Before proposing attestation.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param signedAttestDataBase64 The signed attestation data in base64 encoding
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> attestBeforePropose(
long slot,
String pubkey,
String signedAttestDataBase64) {
return rpcConnection.call(
ATTEST_MODULE + "_beforePropose",
AttackerResponse.class,
slot,
pubkey,
signedAttestDataBase64);
}
/**
* After proposing attestation.
*
* @param slot The slot number
* @param pubkey The validator public key
* @param signedAttestDataBase64 The signed attestation data in base64 encoding
* @return A future that completes with the response
*/
public SafeFuture<AttackerResponse> attestAfterPropose(
long slot,
String pubkey,
String signedAttestDataBase64) {
return rpcConnection.call(
ATTEST_MODULE + "_afterPropose",
AttackerResponse.class,
slot,
pubkey,
signedAttestDataBase64);
}
}
\ No newline at end of file
package tech.pegasys.teku.attacker.client;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
/**
* AttackerCommand defines the command types that can be returned by the attacker client API.
* This matches the Go implementation in tsinghua-cel/attacker-client-go/client/type.go.
*/
public enum AttackerCommand {
CMD_NULL(0),
CMD_CONTINUE(1),
CMD_RETURN(2),
CMD_ABORT(3),
CMD_SKIP(4),
CMD_ROLE_TO_NORMAL(5), // Role changes to normal node
CMD_ROLE_TO_ATTACKER(6), // Role changes to attacker
CMD_EXIT(7),
CMD_UPDATE_STATE(8),
CMP_DELAY_BROAD_CAST(9);
private final int value;
AttackerCommand(int value) {
this.value = value;
}
@JsonValue
public int getValue() {
return value;
}
@JsonCreator
public static AttackerCommand fromValue(int value) {
for (AttackerCommand command : AttackerCommand.values()) {
if (command.value == value) {
return command;
}
}
throw new IllegalArgumentException("Unknown AttackerCommand value: " + value);
}
}
\ No newline at end of file
package tech.pegasys.teku.attacker.client;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* AttackerResponse defines the response from the attacker client API.
* This matches the Go implementation in tsinghua-cel/attacker-client-go/client/type.go.
*/
public class AttackerResponse {
@JsonProperty("cmd")
private AttackerCommand cmd;
@JsonProperty("result")
private String result;
public AttackerResponse() {
// Default constructor for Jackson deserialization
}
public AttackerResponse(AttackerCommand cmd, String result) {
this.cmd = cmd;
this.result = result;
}
public AttackerCommand getCmd() {
return cmd;
}
public String getResult() {
return result;
}
/**
* Convenience method to check if the command is CMD_CONTINUE.
*
* @return true if the command is CMD_CONTINUE, false otherwise
*/
public boolean shouldContinue() {
return cmd == AttackerCommand.CMD_CONTINUE;
}
/**
* Convenience method to check if the command is CMD_ABORT.
*
* @return true if the command is CMD_ABORT, false otherwise
*/
public boolean shouldAbort() {
return cmd == AttackerCommand.CMD_ABORT;
}
@Override
public String toString() {
return "AttackerResponse{" +
"cmd=" + cmd +
", result='" + result + '\'' +
'}';
}
}
\ No newline at end of file
package tech.pegasys.teku.attacker.client;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.concurrent.atomic.AtomicLong;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
public class HttpRpcConnection implements RpcConnection {
private static final ObjectMapper MAPPER = new ObjectMapper();
private final HttpClient httpClient;
private final URI endpoint;
private final AtomicLong idCounter = new AtomicLong(0);
public HttpRpcConnection(URI endpoint) {
this.endpoint = endpoint;
this.httpClient = HttpClient.newHttpClient();
}
@Override
public <T> SafeFuture<T> call(String method, Class<T> responseType, Object... params) {
SafeFuture<T> future = new SafeFuture<>();
try {
ObjectNode requestNode = MAPPER.createObjectNode();
requestNode.put("jsonrpc", "2.0");
requestNode.put("id", idCounter.incrementAndGet());
requestNode.put("method", method);
ArrayNode paramsNode = MAPPER.createArrayNode();
for (Object param : params) {
paramsNode.addPOJO(param);
}
requestNode.set("params", paramsNode);
String requestBody = MAPPER.writeValueAsString(requestNode);
HttpRequest request = HttpRequest.newBuilder()
.uri(endpoint)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
httpClient.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(response -> {
try {
ObjectNode responseNode = (ObjectNode) MAPPER.readTree(response.body());
if (responseNode.has("error")) {
throw new RuntimeException("RPC error: " + responseNode.get("error").toString());
}
return MAPPER.treeToValue(responseNode.get("result"), responseType);
} catch (Exception e) {
throw new RuntimeException("Failed to parse RPC response", e);
}
})
.thenAccept(future::complete)
.exceptionally(e -> {
future.completeExceptionally(e);
return null;
});
} catch (Exception e) {
future.completeExceptionally(e);
}
return future;
}
@Override
public void close() {
// HttpClient doesn't need explicit closing
}
}
\ No newline at end of file
package tech.pegasys.teku.attacker.client;
import java.net.URI;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import org.apache.tuweni.bytes.Bytes;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
/**
* AttackerClient defines typed wrappers for the Attacker RPC API.
*/
public class AttackerClient {
private final RpcConnection rpcConnection;
private final int validatorIndex;
/**
* Dial connects a client to the given URL.
*
* @param rawUrl The URL to connect to
* @param validatorIndex The validator index
* @return A new AttackerClient
* @throws Exception If connection fails
*/
public static AttackerClient dial(String rawUrl, int validatorIndex) throws Exception {
return new AttackerClient(new HttpRpcConnection(URI.create(rawUrl)), validatorIndex);
}
/**
* Creates a client that uses the given RPC connection.
*
* @param rpcConnection The RPC connection
* @param validatorIndex The validator index
*/
public AttackerClient(RpcConnection rpcConnection, int validatorIndex) {
this.rpcConnection = rpcConnection;
this.validatorIndex = validatorIndex;
}
/**
* Close closes the underlying RPC connection.
*/
public void close() {
rpcConnection.close();
}
}
\ No newline at end of file
package tech.pegasys.teku.attacker.client;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.concurrent.ExecutionException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import tech.pegasys.teku.infrastructure.async.SafeFuture;
public class AttackerClientTest {
private static final long SLOT = 1234L;
private static final String PUBKEY = "0x8f763c496d974ef3e641428bb863a9c7fe85498bcd2f78b26cc1d7ee3a312eb715e9c8736f5b305c68c4d2eb25bd0f78";
private static final String BLOCK_DATA = "blockDataBase64";
private static final String SIGNED_BLOCK_DATA = "signedBlockDataBase64";
private static final String PARENT_ROOT = "0xabcdef1234567890";
private static final String ATTEST_DATA = "attestDataBase64";
private static final String SIGNED_ATTEST_DATA = "signedAttestDataBase64";
private RpcConnection rpcConnection;
private AttackerClient attackerClient;
@BeforeEach
public void setup() {
rpcConnection = mock(RpcConnection.class);
attackerClient = new AttackerClient(rpcConnection, 0);
}
@Test
public void shouldCallBlockGetNewParentRoot() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.blockGetNewParentRoot(SLOT, PUBKEY, PARENT_ROOT);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("block_getNewParentRoot"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(PARENT_ROOT));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallDelayForReceiveBlock() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.delayForReceiveBlock(SLOT);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("block_delayForReceiveBlock"),
eq(AttackerResponse.class),
eq(SLOT));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallBlockBeforeBroadcast() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.blockBeforeBroadcast(SLOT);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("block_beforeBroadCast"),
eq(AttackerResponse.class),
eq(SLOT));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallBlockAfterBroadcast() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.blockAfterBroadcast(SLOT);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("block_afterBroadCast"),
eq(AttackerResponse.class),
eq(SLOT));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallBlockBeforeSign() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.blockBeforeSign(SLOT, PUBKEY, BLOCK_DATA);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("block_beforeSign"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(BLOCK_DATA));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallBlockAfterSign() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.blockAfterSign(SLOT, PUBKEY, SIGNED_BLOCK_DATA);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("block_afterSign"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(SIGNED_BLOCK_DATA));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallBlockBeforePropose() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.blockBeforePropose(SLOT, PUBKEY, SIGNED_BLOCK_DATA);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("block_beforePropose"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(SIGNED_BLOCK_DATA));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallBlockAfterPropose() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.blockAfterPropose(SLOT, PUBKEY, SIGNED_BLOCK_DATA);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("block_afterPropose"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(SIGNED_BLOCK_DATA));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallAttestBeforeBroadcast() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.attestBeforeBroadcast(SLOT);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("attest_beforeBroadCast"),
eq(AttackerResponse.class),
eq(SLOT));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallAttestAfterBroadcast() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.attestAfterBroadcast(SLOT);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("attest_afterBroadCast"),
eq(AttackerResponse.class),
eq(SLOT));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallAttestBeforeSign() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.attestBeforeSign(SLOT, PUBKEY, ATTEST_DATA);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("attest_beforeSign"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(ATTEST_DATA));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallAttestAfterSign() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.attestAfterSign(SLOT, PUBKEY, SIGNED_ATTEST_DATA);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("attest_afterSign"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(SIGNED_ATTEST_DATA));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallAttestBeforePropose() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.attestBeforePropose(SLOT, PUBKEY, SIGNED_ATTEST_DATA);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("attest_beforePropose"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(SIGNED_ATTEST_DATA));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldCallAttestAfterPropose() throws Exception {
mockRpcResponse(AttackerCommand.CMD_CONTINUE, "success");
SafeFuture<AttackerResponse> future = attackerClient.attestAfterPropose(SLOT, PUBKEY, SIGNED_ATTEST_DATA);
AttackerResponse response = future.get();
verify(rpcConnection).call(
eq("attest_afterPropose"),
eq(AttackerResponse.class),
eq(SLOT),
eq(PUBKEY),
eq(SIGNED_ATTEST_DATA));
assertThat(response.getCmd()).isEqualTo(AttackerCommand.CMD_CONTINUE);
assertThat(response.getResult()).isEqualTo("success");
}
@Test
public void shouldHandleDifferentCommandTypes() throws Exception {
// Test handling of each command type
for (AttackerCommand command : AttackerCommand.values()) {
String result = "result for " + command.name();
mockRpcResponse(command, result);
SafeFuture<AttackerResponse> future = attackerClient.blockBeforeSign(SLOT, PUBKEY, BLOCK_DATA);
AttackerResponse response = future.get();
assertThat(response.getCmd()).isEqualTo(command);
assertThat(response.getResult()).isEqualTo(result);
// Test utility methods
if (command == AttackerCommand.CMD_CONTINUE) {
assertThat(response.shouldContinue()).isTrue();
} else {
assertThat(response.shouldContinue()).isFalse();
}
if (command == AttackerCommand.CMD_ABORT) {
assertThat(response.shouldAbort()).isTrue();
} else {
assertThat(response.shouldAbort()).isFalse();
}
}
}
private void mockRpcResponse(AttackerCommand cmd, String result) {
AttackerResponse response = new AttackerResponse(cmd, result);
SafeFuture<AttackerResponse> future = SafeFuture.completedFuture(response);
when(rpcConnection.call(anyString(), eq(AttackerResponse.class), any())).thenReturn(future);
}
}
\ No newline at end of file
...@@ -51,5 +51,5 @@ dependencies { ...@@ -51,5 +51,5 @@ dependencies {
jmhImplementation testFixtures(project(':ethereum:spec')) jmhImplementation testFixtures(project(':ethereum:spec'))
jmhImplementation 'org.mockito:mockito-core' jmhImplementation 'org.mockito:mockito-core'
jmhImplementation testFixtures(project(':eth-benchmark-tests')) // jmhImplementation testFixtures(project(':eth-benchmark-tests'))
} }
...@@ -22,7 +22,6 @@ import static tech.pegasys.teku.infrastructure.json.types.CoreTypes.UINT64_TYPE; ...@@ -22,7 +22,6 @@ import static tech.pegasys.teku.infrastructure.json.types.CoreTypes.UINT64_TYPE;
import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntList;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Fork;
...@@ -34,18 +33,13 @@ import org.openjdk.jmh.annotations.Setup; ...@@ -34,18 +33,13 @@ import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.annotations.Warmup;
import org.openjdk.jmh.infra.Blackhole; import org.openjdk.jmh.infra.Blackhole;
import tech.pegasys.teku.benchmarks.gen.KeyFileGenerator;
import tech.pegasys.teku.bls.BLSConstants;
import tech.pegasys.teku.bls.BLSKeyPair;
import tech.pegasys.teku.ethereum.json.types.validator.AttesterDuties; import tech.pegasys.teku.ethereum.json.types.validator.AttesterDuties;
import tech.pegasys.teku.ethereum.json.types.validator.AttesterDuty; import tech.pegasys.teku.ethereum.json.types.validator.AttesterDuty;
import tech.pegasys.teku.infrastructure.json.types.SerializableTypeDefinition; import tech.pegasys.teku.infrastructure.json.types.SerializableTypeDefinition;
import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec; import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.datastructures.interop.GenesisStateBuilder;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.bellatrix.BeaconStateBellatrix; import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.bellatrix.BeaconStateBellatrix;
import tech.pegasys.teku.spec.datastructures.state.beaconstate.versions.bellatrix.MutableBeaconStateBellatrix;
@Fork(1) @Fork(1)
@State(Scope.Thread) @State(Scope.Thread)
...@@ -88,32 +82,32 @@ public class AttesterDutiesGeneraterBenchmark { ...@@ -88,32 +82,32 @@ public class AttesterDutiesGeneraterBenchmark {
@Setup(Level.Trial) @Setup(Level.Trial)
public void init() { public void init() {
BLSConstants.disableBLSVerification(); // BLSConstants.disableBLSVerification();
List<BLSKeyPair> validatorKeys = KeyFileGenerator.readValidatorKeys(validatorsCount); // List<BLSKeyPair> validatorKeys = KeyFileGenerator.readValidatorKeys(validatorsCount);
state = // state =
BeaconStateBellatrix.required( // BeaconStateBellatrix.required(
new GenesisStateBuilder() // new GenesisStateBuilder()
.spec(spec) // .spec(spec)
.signDeposits(true) // .signDeposits(true)
.addValidators(validatorKeys) // .addValidators(validatorKeys)
.build()); // .build());
final MutableBeaconStateBellatrix mutableState = state.createWritableCopy(); // final MutableBeaconStateBellatrix mutableState = state.createWritableCopy();
mutableState.setSlot(UInt64.ONE); // mutableState.setSlot(UInt64.ONE);
state = mutableState.commitChanges(); // state = mutableState.commitChanges();
//
System.out.println("active validators: " + state.getValidators().size()); // System.out.println("active validators: " + state.getValidators().size());
//
for (int i = 0; i < querySize; i++) { // for (int i = 0; i < querySize; i++) {
validatorIndices.add(i); // validatorIndices.add(i);
} // }
//
attesterDutiesGenerator = new AttesterDutiesGenerator(spec); // attesterDutiesGenerator = new AttesterDutiesGenerator(spec);
epoch = spec.computeEpochAtSlot(state.getSlot()).increment(); // epoch = spec.computeEpochAtSlot(state.getSlot()).increment();
//
int generatedDuties = computeAttesterDuties().getDuties().size(); // int generatedDuties = computeAttesterDuties().getDuties().size();
if (generatedDuties == 0) { // if (generatedDuties == 0) {
throw new IllegalStateException("No duties generated, check the state"); // throw new IllegalStateException("No duties generated, check the state");
} // }
System.out.println("computed duties: " + computeAttesterDuties().getDuties().size()); System.out.println("computed duties: " + computeAttesterDuties().getDuties().size());
System.out.println("Done!"); System.out.println("Done!");
......
...@@ -94,11 +94,12 @@ public abstract class AbstractBlockPublisher implements BlockPublisher { ...@@ -94,11 +94,12 @@ public abstract class AbstractBlockPublisher implements BlockPublisher {
// when broadcast validation is disabled, we can publish the block (and blob sidecars) // when broadcast validation is disabled, we can publish the block (and blob sidecars)
// immediately and then import // immediately and then import
// todo: luxq add bf inject point, for receiveBlock. // todo: luxq add bf inject point, for receiveBlock.
importBlobSidecars(blobSidecars.get(), blockPublishingPerformance); importBlobSidecars(blobSidecars.get(), blockPublishingPerformance);
SafeFuture<BlockImportAndBroadcastValidationResults> future = importBlock(block, broadcastValidationLevel, blockPublishingPerformance); SafeFuture<BlockImportAndBroadcastValidationResults> future =
importBlock(block, broadcastValidationLevel, blockPublishingPerformance);
// todo: luxq add bf inject point, for broadcastBlock. // todo: luxq add bf inject point, for broadcastBlock.
publishBlockAndBlobs(block, blobSidecars, blockPublishingPerformance); publishBlockAndBlobs(block, blobSidecars, blockPublishingPerformance);
return future; return future;
......
rootProject.name='teku' rootProject.name='teku'
include 'acceptance-tests' include 'acceptance-tests'
include 'attacker' include 'attacker:client'
include 'beacon:pow' include 'beacon:pow'
include 'beacon:sync' include 'beacon:sync'
include 'beacon:validator' include 'beacon:validator'
...@@ -68,7 +68,7 @@ include 'validator:eventadapter' ...@@ -68,7 +68,7 @@ include 'validator:eventadapter'
include 'validator:remote' include 'validator:remote'
include 'eth-tests' include 'eth-tests'
include 'eth-reference-tests' include 'eth-reference-tests'
include 'eth-benchmark-tests' //include 'eth-benchmark-tests'
include 'fork-choice-tests' include 'fork-choice-tests'
include 'ethereum:performance-trackers' include 'ethereum:performance-trackers'
...@@ -111,7 +111,7 @@ public class AttestationProductionDuty implements Duty { ...@@ -111,7 +111,7 @@ public class AttestationProductionDuty implements Duty {
.getForkInfo(slot) .getForkInfo(slot)
.thenCompose( .thenCompose(
forkInfo -> forkInfo ->
// todo: luxq add bf inject point, before/after attest broadcast. // todo: luxq add bf inject point, before/after attest broadcast.
sendingStrategy.send( sendingStrategy.send(
produceAllAttestations(slot, forkInfo, validatorsByCommitteeIndex))); produceAllAttestations(slot, forkInfo, validatorsByCommitteeIndex)));
} }
...@@ -236,7 +236,7 @@ public class AttestationProductionDuty implements Duty { ...@@ -236,7 +236,7 @@ public class AttestationProductionDuty implements Duty {
.signAttestationData(attestationData, forkInfo) .signAttestationData(attestationData, forkInfo)
.thenApply( .thenApply(
signature -> signature ->
// todo: luxq add bf jnject point, after attest sign. // todo: luxq add bf jnject point, after attest sign.
signedAttestationProducer.createSignedAttestation( signedAttestationProducer.createSignedAttestation(
attestationData, validator, signature)) attestationData, validator, signature))
.thenApply( .thenApply(
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment