Skip to content

Commit

Permalink
Merge branch 'master' into save-earliest-slot-block-in-dbvariable
Browse files Browse the repository at this point in the history
  • Loading branch information
gfukushima authored Oct 18, 2024
2 parents ca03731 + 3796cd7 commit a5a4afc
Show file tree
Hide file tree
Showing 13 changed files with 154 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ void triggerValidatorExitWithFullWithdrawal() throws Exception {
tekuNode.waitForNewFinalization();

final ValidatorKeys validator = validatorKeys.getValidatorKeys().get(0);
final BLSPublicKey validatorPublicKey = validator.getValidatorKey().getPublicKey();
final BLSPublicKey validatorPubkey = validator.getValidatorKey().getPublicKey();

besuNode.createWithdrawalRequest(eth1PrivateKey, validatorPublicKey, UInt64.ZERO);
besuNode.createWithdrawalRequest(eth1PrivateKey, validatorPubkey, UInt64.ZERO);

// Wait for validator exit confirmation
tekuNode.waitForLogMessageContaining(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,19 @@ void consolidateValidator() throws Exception {
tekuNode.waitForNewFinalization();

final ValidatorKeys sourceValidator = validatorKeys.getValidatorKeys().get(0);
final BLSPublicKey sourceValidatorPublicKey = sourceValidator.getValidatorKey().getPublicKey();
final BLSPublicKey sourceValidatorPubkey = sourceValidator.getValidatorKey().getPublicKey();

final ValidatorKeys targetValidator = validatorKeys.getValidatorKeys().get(1);
final BLSPublicKey targetValidatorPublicKey = targetValidator.getValidatorKey().getPublicKey();
final BLSPublicKey targetValidatorPubkey = targetValidator.getValidatorKey().getPublicKey();

besuNode.createConsolidationRequest(
eth1PrivateKey, sourceValidatorPublicKey, targetValidatorPublicKey);
waitForValidatorExit(tekuNode, sourceValidatorPublicKey);
eth1PrivateKey, sourceValidatorPubkey, targetValidatorPubkey);
waitForValidatorExit(tekuNode, sourceValidatorPubkey);
}

private void waitForValidatorExit(
final TekuBeaconNode tekuNode, final BLSPublicKey validatorPublicKey) {
final String pubKeySubstring = validatorPublicKey.toHexString().substring(2, 9);
final TekuBeaconNode tekuNode, final BLSPublicKey validatorPubkey) {
final String pubKeySubstring = validatorPubkey.toHexString().substring(2, 9);
tekuNode.waitForLogMessageContaining(
"Validator "
+ pubKeySubstring
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,15 @@ public SafeFuture<TransactionReceipt> createWithdrawalRequest(
}

public SafeFuture<TransactionReceipt> createConsolidationRequest(
final BLSPublicKey sourceValidatorPublicKey, final BLSPublicKey targetValidatorPublicKey) {
final BLSPublicKey sourceValidatorPubkey, final BLSPublicKey targetValidatorPubkey) {
// Sanity check that we can interact with the contract
Waiter.waitFor(
() ->
assertThat(consolidationRequestContract.getExcessConsolidationRequests().get())
.isEqualTo(0));

return consolidationRequestContract
.createConsolidationRequest(sourceValidatorPublicKey, targetValidatorPublicKey)
.createConsolidationRequest(sourceValidatorPubkey, targetValidatorPubkey)
.thenCompose(
response -> {
final String txHash = response.getResult();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,12 @@ public ExecutionRequests(
.toList();
final List<
tech.pegasys.teku.spec.datastructures.execution.versions.electra.ConsolidationRequest>
consolidationInternal =
consolidationsInternal =
consolidations.stream()
.map(
consolidationRequest ->
consolidationRequest.asInternalConsolidationRequest(consolidationSchema))
.toList();
return schema.create(depositsInternal, withdrawalsInternal, consolidationInternal);
return schema.create(depositsInternal, withdrawalsInternal, consolidationsInternal);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ public class WithdrawalRequest {
private final Eth1Address sourceAddress;

@JsonProperty("validator_pubkey")
private final BLSPublicKey validatorPublicKey;
private final BLSPublicKey validatorPubkey;

@JsonProperty("amount")
private final UInt64 amount;

public WithdrawalRequest(
@JsonProperty("source_address") final Eth1Address sourceAddress,
@JsonProperty("validator_pubkey") final BLSPublicKey validatorPublicKey,
@JsonProperty("validator_pubkey") final BLSPublicKey validatorPubkey,
@JsonProperty("amount") final UInt64 amount) {
this.sourceAddress = sourceAddress;
this.validatorPublicKey = validatorPublicKey;
this.validatorPubkey = validatorPubkey;
this.amount = amount;
}

Expand All @@ -44,12 +44,12 @@ public WithdrawalRequest(
withdrawalRequest) {
this.sourceAddress =
Eth1Address.fromBytes(withdrawalRequest.getSourceAddress().getWrappedBytes());
this.validatorPublicKey = withdrawalRequest.getValidatorPublicKey();
this.validatorPubkey = withdrawalRequest.getValidatorPubkey();
this.amount = withdrawalRequest.getAmount();
}

public final tech.pegasys.teku.spec.datastructures.execution.versions.electra.WithdrawalRequest
asInternalWithdrawalRequest(final WithdrawalRequestSchema schema) {
return schema.create(sourceAddress, validatorPublicKey, amount);
return schema.create(sourceAddress, validatorPubkey, amount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright Consensys Software Inc., 2022
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*/

package tech.pegasys.teku.ethereum.executionclient.web3j;

import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;

enum JsonRpcErrorCodes {
PARSE_ERROR(-32700, "Parse error"),
INVALID_REQUEST(-32600, "Invalid Request"),
METHOD_NOT_FOUND(-32601, "Method not found"),
INVALID_PARAMS(-32602, "Invalid params"),
INTERNAL_ERROR(-32603, "Internal error"),
SERVER_ERROR(-32000, "Server error");

private final int errorCode;
private final String description;
private static final Int2ObjectOpenHashMap<JsonRpcErrorCodes> CODE_TO_ERROR_MAP;

static {
CODE_TO_ERROR_MAP = new Int2ObjectOpenHashMap<>();
for (final JsonRpcErrorCodes error : values()) {
CODE_TO_ERROR_MAP.put(error.getErrorCode(), error);
}
}

JsonRpcErrorCodes(final int errorCode, final String description) {
this.errorCode = errorCode;
this.description = description;
}

public int getErrorCode() {
return errorCode;
}

public String getDescription() {
return description;
}

public static String getDescription(final int errorCode) {
return fromCode(errorCode).getDescription();
}

public static JsonRpcErrorCodes fromCode(final int errorCode) {
final JsonRpcErrorCodes error = CODE_TO_ERROR_MAP.get(errorCode);
if (error != null) {
return error;
}
return errorCode >= -32099 && errorCode <= -32000 ? SERVER_ERROR : INTERNAL_ERROR;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

import static tech.pegasys.teku.infrastructure.exceptions.ExceptionUtil.getMessageOrSimpleName;

import java.io.IOException;
import java.net.ConnectException;
import java.time.Duration;
import java.util.Collection;
Expand Down Expand Up @@ -86,21 +85,41 @@ public <T> SafeFuture<Response<T>> doRequest(
(response, exception) -> {
final boolean isCriticalRequest = isCriticalRequest(web3jRequest);
if (exception != null) {
final boolean couldBeAuthError = isAuthenticationException(exception);
handleError(isCriticalRequest, exception, couldBeAuthError);
return Response.withErrorMessage(getMessageOrSimpleName(exception));
return handleException(exception, isCriticalRequest);
} else if (response.hasError()) {
final String errorMessage =
response.getError().getCode() + ": " + response.getError().getMessage();
handleError(isCriticalRequest, new IOException(errorMessage), false);
return Response.withErrorMessage(errorMessage);
return handleJsonRpcError(response.getError(), isCriticalRequest);
} else {
handleSuccess(isCriticalRequest);
return new Response<>(response.getResult());
}
});
}

private <T> Response<T> handleException(
final Throwable exception, final boolean isCriticalRequest) {
final boolean couldBeAuthError = isAuthenticationException(exception);
handleError(isCriticalRequest, exception, couldBeAuthError);
return Response.withErrorMessage(getMessageOrSimpleName(exception));
}

private <T> Response<T> handleJsonRpcError(
final org.web3j.protocol.core.Response.Error error, final boolean isCriticalRequest) {
final int errorCode = error.getCode();
final String errorType = JsonRpcErrorCodes.getDescription(errorCode);
final String formattedError =
String.format("JSON-RPC error: %s (%d): %s", errorType, errorCode, error.getMessage());

if (isCriticalRequest) {
logError(formattedError);
}

return Response.withErrorMessage(formattedError);
}

private void logError(final String errorMessage) {
eventLog.executionClientRequestFailed(new Exception(errorMessage), false);
}

private boolean isCriticalRequest(final Request<?, ?> request) {
return !nonCriticalMethods.contains(request.getMethod());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package tech.pegasys.teku.ethereum.executionclient.web3j;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
Expand Down Expand Up @@ -272,6 +273,40 @@ void shouldNotUpdateAvailabilityWhenNonCriticalMethodFailsWithErrorResponse(
verifyNoInteractions(executionClientEventsPublisher);
}

@ParameterizedTest
@MethodSource("getClientInstances")
void shouldDecodeJsonRpcErrorCodesCorrectly(final ClientFactory clientFactory) throws Exception {
final Web3JClient client = clientFactory.create(eventLog, executionClientEventsPublisher);
Request<Void, VoidResponse> request = createRequest(client);

// Create a response with a specific JSON-RPC error
VoidResponse errorResponse = new VoidResponse();
Error rpcError =
new Error(
JsonRpcErrorCodes.INVALID_PARAMS.getErrorCode(),
"engine_newPayload method has been called with invalid parameters");
errorResponse.setError(rpcError);

when(client.getWeb3jService().sendAsync(request, VoidResponse.class))
.thenReturn(SafeFuture.completedFuture(errorResponse));

final SafeFuture<Response<Void>> result = client.doRequest(request, DEFAULT_TIMEOUT);
Waiter.waitFor(result);

SafeFutureAssert.assertThatSafeFuture(result).isCompleted();
final Response<Void> response = SafeFutureAssert.safeJoin(result);

assertThat(response.getErrorMessage())
.isEqualTo(
String.format(
"JSON-RPC error: %s (%d): %s",
JsonRpcErrorCodes.INVALID_PARAMS.getDescription(),
JsonRpcErrorCodes.INVALID_PARAMS.getErrorCode(),
"engine_newPayload method has been called with invalid parameters"));

verify(eventLog).executionClientRequestFailed(any(Exception.class), eq(false));
}

private static Request<Void, VoidResponse> createRequest(final Web3JClient client) {
return new Request<>("test", new ArrayList<>(), client.getWeb3jService(), VoidResponse.class);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ public class WithdrawalRequest
protected WithdrawalRequest(
final WithdrawalRequestSchema schema,
final Bytes20 sourceAddress,
final BLSPublicKey validatorPublicKey,
final BLSPublicKey validatorPubkey,
final UInt64 amount) {
super(
schema,
SszByteVector.fromBytes(sourceAddress.getWrappedBytes()),
new SszPublicKey(validatorPublicKey),
new SszPublicKey(validatorPubkey),
SszUInt64.of(amount));
}

Expand All @@ -50,7 +50,7 @@ public Bytes20 getSourceAddress() {
return new Bytes20(getField0().getBytes());
}

public BLSPublicKey getValidatorPublicKey() {
public BLSPublicKey getValidatorPubkey() {
return getField1().getBLSPublicKey();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ public WithdrawalRequestSchema() {
}

public WithdrawalRequest create(
final Bytes20 sourceAddress, final BLSPublicKey validatorPublicKey, final UInt64 amount) {
return new WithdrawalRequest(this, sourceAddress, validatorPublicKey, amount);
final Bytes20 sourceAddress, final BLSPublicKey validatorPubkey, final UInt64 amount) {
return new WithdrawalRequest(this, sourceAddress, validatorPubkey, amount);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,11 @@ public void processWithdrawalRequests(
}

final Optional<Integer> maybeValidatorIndex =
validatorsUtil.getValidatorIndex(state, withdrawalRequest.getValidatorPublicKey());
validatorsUtil.getValidatorIndex(state, withdrawalRequest.getValidatorPubkey());
if (maybeValidatorIndex.isEmpty()) {
LOG.debug(
"process_withdrawal_request: no matching validator for public key {}",
withdrawalRequest.getValidatorPublicKey().toAbbreviatedString());
withdrawalRequest.getValidatorPubkey().toAbbreviatedString());
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,32 +31,32 @@ class WithdrawalRequestTest {
new DataStructureUtil(TestSpecFactory.createMinimal(SpecMilestone.ELECTRA));
private final WithdrawalRequestSchema withdrawalRequestSchema = new WithdrawalRequestSchema();
private final Bytes20 sourceAddress = dataStructureUtil.randomBytes20();
private final BLSPublicKey validatorPublicKey = dataStructureUtil.randomPublicKey();
private final BLSPublicKey validatorPubkey = dataStructureUtil.randomPublicKey();
private final UInt64 amount = dataStructureUtil.randomUInt64();

@Test
public void objectEquality() {
final WithdrawalRequest withdrawalRequest1 =
withdrawalRequestSchema.create(sourceAddress, validatorPublicKey, amount);
withdrawalRequestSchema.create(sourceAddress, validatorPubkey, amount);
final WithdrawalRequest withdrawalRequest2 =
withdrawalRequestSchema.create(sourceAddress, validatorPublicKey, amount);
withdrawalRequestSchema.create(sourceAddress, validatorPubkey, amount);

assertThat(withdrawalRequest1).isEqualTo(withdrawalRequest2);
}

@Test
public void objectAccessorMethods() {
final WithdrawalRequest withdrawalRequest =
withdrawalRequestSchema.create(sourceAddress, validatorPublicKey, amount);
withdrawalRequestSchema.create(sourceAddress, validatorPubkey, amount);

assertThat(withdrawalRequest.getSourceAddress()).isEqualTo(sourceAddress);
assertThat(withdrawalRequest.getValidatorPublicKey()).isEqualTo(validatorPublicKey);
assertThat(withdrawalRequest.getValidatorPubkey()).isEqualTo(validatorPubkey);
}

@Test
public void roundTripSSZ() {
final WithdrawalRequest withdrawalRequest =
withdrawalRequestSchema.create(sourceAddress, validatorPublicKey, amount);
withdrawalRequestSchema.create(sourceAddress, validatorPubkey, amount);

final Bytes sszBytes = withdrawalRequest.sszSerialize();
final WithdrawalRequest deserializedObject = withdrawalRequestSchema.sszDeserialize(sszBytes);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ public void processWithdrawalRequests_ExitForAbsentValidator_DoesNothing() {
preState.getValidators().stream()
.filter(
validator ->
validator.getPublicKey().equals(withdrawalRequest.getValidatorPublicKey())))
validator.getPublicKey().equals(withdrawalRequest.getValidatorPubkey())))
.isEmpty();

final BeaconStateElectra postState =
Expand Down

0 comments on commit a5a4afc

Please sign in to comment.