Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated GetPayloadV4 with executionRequests decoding #8698

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,35 @@
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSchema;
import tech.pegasys.teku.spec.datastructures.execution.BlobsBundle;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadContext;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema;
import tech.pegasys.teku.spec.datastructures.execution.GetPayloadResponse;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsDataCodec;
import tech.pegasys.teku.spec.schemas.SchemaDefinitions;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra;

public class EngineGetPayloadV4 extends AbstractEngineJsonRpcMethod<GetPayloadResponse> {

private static final Logger LOG = LogManager.getLogger();

private final Spec spec;
private final ExecutionRequestsDataCodec executionRequestsDataDecoder;

public EngineGetPayloadV4(final ExecutionEngineClient executionEngineClient, final Spec spec) {
super(executionEngineClient);
this.spec = spec;
this.executionRequestsDataDecoder =
new ExecutionRequestsDataCodec(
SchemaDefinitionsElectra.required(
spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions())
.getExecutionRequestsSchema());
}

@Override
Expand Down Expand Up @@ -76,11 +86,14 @@ public SafeFuture<GetPayloadResponse> execute(final JsonRpcRequestParams params)
final ExecutionPayload executionPayload =
response.executionPayload.asInternalExecutionPayload(payloadSchema);
final BlobsBundle blobsBundle = getBlobsBundle(response, schemaDefinitions);
final ExecutionRequests executionRequests =
executionRequestsDataDecoder.decode(response.executionRequests);
return new GetPayloadResponse(
executionPayload,
response.blockValue,
blobsBundle,
response.shouldOverrideBuilder);
response.shouldOverrideBuilder,
executionRequests);
})
.thenPeek(
getPayloadResponse ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.util.List;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import tech.pegasys.teku.ethereum.executionclient.serialization.BytesDeserializer;
import tech.pegasys.teku.ethereum.executionclient.serialization.BytesSerializer;
import tech.pegasys.teku.ethereum.executionclient.serialization.UInt256AsHexDeserializer;
import tech.pegasys.teku.ethereum.executionclient.serialization.UInt256AsHexSerializer;
import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSchema;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema;
import tech.pegasys.teku.spec.datastructures.execution.GetPayloadResponse;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsDataCodec;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsSchema;

public class GetPayloadV4Response {
public final ExecutionPayloadV3 executionPayload;
Expand All @@ -36,26 +42,36 @@ public class GetPayloadV4Response {

public final boolean shouldOverrideBuilder;

@JsonSerialize(contentUsing = BytesSerializer.class)
@JsonDeserialize(contentUsing = BytesDeserializer.class)
public final List<Bytes> executionRequests;

public GetPayloadV4Response(
final @JsonProperty("executionPayload") ExecutionPayloadV3 executionPayload,
final @JsonProperty("blockValue") UInt256 blockValue,
final @JsonProperty("blobsBundle") BlobsBundleV1 blobsBundle,
final @JsonProperty("shouldOverrideBuilder") boolean shouldOverrideBuilder) {
final @JsonProperty("shouldOverrideBuilder") boolean shouldOverrideBuilder,
final @JsonProperty("executionRequests") List<Bytes> executionRequests) {
checkNotNull(executionPayload, "executionPayload");
checkNotNull(blockValue, "blockValue");
checkNotNull(blobsBundle, "blobsBundle");
checkNotNull(executionRequests, "executionRequests");
this.executionPayload = executionPayload;
this.blockValue = blockValue;
this.blobsBundle = blobsBundle;
this.shouldOverrideBuilder = shouldOverrideBuilder;
this.executionRequests = executionRequests;
}

public GetPayloadResponse asInternalGetPayloadResponse(
final ExecutionPayloadSchema<?> executionPayloadSchema, final BlobSchema blobSchema) {
final ExecutionPayloadSchema<?> executionPayloadSchema,
final BlobSchema blobSchema,
final ExecutionRequestsSchema executionRequestsSchema) {
return new GetPayloadResponse(
executionPayload.asInternalExecutionPayload(executionPayloadSchema),
blockValue,
blobsBundle.asInternalBlobsBundle(blobSchema),
shouldOverrideBuilder);
shouldOverrideBuilder,
new ExecutionRequestsDataCodec(executionRequestsSchema).decode(executionRequests));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.units.bigints.UInt256;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
Expand All @@ -37,19 +39,28 @@
import tech.pegasys.teku.infrastructure.async.SafeFuture;
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
import tech.pegasys.teku.spec.Spec;
import tech.pegasys.teku.spec.SpecMilestone;
import tech.pegasys.teku.spec.TestSpecFactory;
import tech.pegasys.teku.spec.datastructures.execution.BlobsBundle;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload;
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadContext;
import tech.pegasys.teku.spec.datastructures.execution.GetPayloadResponse;
import tech.pegasys.teku.spec.datastructures.execution.versions.deneb.ExecutionPayloadDeneb;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsDataCodec;
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsElectra;
import tech.pegasys.teku.spec.util.DataStructureUtil;

class EngineGetPayloadV4Test {

private final Spec spec = TestSpecFactory.createMinimalElectra();
private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec);
private final ExecutionEngineClient executionEngineClient = mock(ExecutionEngineClient.class);
private final ExecutionRequestsDataCodec executionRequestsDataCodec =
new ExecutionRequestsDataCodec(
SchemaDefinitionsElectra.required(
spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions())
.getExecutionRequestsSchema());
private EngineGetPayloadV4 jsonRpcMethod;

@BeforeEach
Expand Down Expand Up @@ -117,18 +128,24 @@ public void shouldCallGetPayloadV4AndParseResponseSuccessfully() {
final UInt256 blockValue = UInt256.MAX_VALUE;
final BlobsBundle blobsBundle = dataStructureUtil.randomBlobsBundle();
final ExecutionPayload executionPayloadElectra = dataStructureUtil.randomExecutionPayload();
final ExecutionRequests executionRequests = dataStructureUtil.randomExecutionRequests();
final List<Bytes> encodedExecutionRequests =
executionRequestsDataCodec.encodeWithoutTypePrefix(executionRequests);
assertThat(executionPayloadElectra).isInstanceOf(ExecutionPayloadDeneb.class);

when(executionEngineClient.getPayloadV4(eq(executionPayloadContext.getPayloadId())))
.thenReturn(dummySuccessfulResponse(executionPayloadElectra, blockValue, blobsBundle));
.thenReturn(
dummySuccessfulResponse(
executionPayloadElectra, blockValue, blobsBundle, encodedExecutionRequests));

final JsonRpcRequestParams params =
new JsonRpcRequestParams.Builder().add(executionPayloadContext).add(UInt64.ZERO).build();

jsonRpcMethod = new EngineGetPayloadV4(executionEngineClient, spec);

final GetPayloadResponse expectedGetPayloadResponse =
new GetPayloadResponse(executionPayloadElectra, blockValue, blobsBundle, false);
new GetPayloadResponse(
executionPayloadElectra, blockValue, blobsBundle, false, executionRequests);
assertThat(jsonRpcMethod.execute(params)).isCompletedWithValue(expectedGetPayloadResponse);

verify(executionEngineClient).getPayloadV4(eq(executionPayloadContext.getPayloadId()));
Expand All @@ -138,14 +155,16 @@ public void shouldCallGetPayloadV4AndParseResponseSuccessfully() {
private SafeFuture<Response<GetPayloadV4Response>> dummySuccessfulResponse(
final ExecutionPayload executionPayload,
final UInt256 blockValue,
final BlobsBundle blobsBundle) {
final BlobsBundle blobsBundle,
final List<Bytes> encodedExecutionRequests) {
return SafeFuture.completedFuture(
new Response<>(
new GetPayloadV4Response(
ExecutionPayloadV3.fromInternalExecutionPayload(executionPayload),
blockValue,
BlobsBundleV1.fromInternalBlobsBundle(blobsBundle),
false)));
false,
encodedExecutionRequests)));
}

private SafeFuture<Response<GetPayloadV4Response>> dummyFailedResponse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ void engineGetPayload_shouldCallGetPayloadV4() {
dataStructureUtil.randomExecutionPayload()),
UInt256.MAX_VALUE,
BlobsBundleV1.fromInternalBlobsBundle(dataStructureUtil.randomBlobsBundle()),
true);
true,
dataStructureUtil.randomEncodedExecutionRequests());
final SafeFuture<Response<GetPayloadV4Response>> dummyResponse =
SafeFuture.completedFuture(new Response<>(responseData));
when(executionEngineClient.getPayloadV4(context.getPayloadId())).thenReturn(dummyResponse);
Expand All @@ -83,9 +84,12 @@ void engineGetPayload_shouldCallGetPayloadV4() {
final ExecutionPayloadSchema<?> executionPayloadSchema =
schemaDefinitionElectra.getExecutionPayloadSchema();
final BlobSchema blobSchema = schemaDefinitionElectra.getBlobSchema();
assertThat(future)
.isCompletedWithValue(
responseData.asInternalGetPayloadResponse(executionPayloadSchema, blobSchema));
final GetPayloadResponse expectedGetPayloadResponse =
responseData.asInternalGetPayloadResponse(
executionPayloadSchema,
blobSchema,
schemaDefinitionElectra.getExecutionRequestsSchema());
assertThat(future).isCompletedWithValue(expectedGetPayloadResponse);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,22 @@
import java.util.Objects;
import java.util.Optional;
import org.apache.tuweni.units.bigints.UInt256;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests;

public class GetPayloadResponse {

private final ExecutionPayload executionPayload;
private final UInt256 executionPayloadValue;
private final Optional<BlobsBundle> blobsBundle;
private final boolean shouldOverrideBuilder;
private final Optional<ExecutionRequests> executionRequests;

public GetPayloadResponse(final ExecutionPayload executionPayload) {
this.executionPayload = executionPayload;
this.executionPayloadValue = UInt256.ZERO;
this.blobsBundle = Optional.empty();
this.shouldOverrideBuilder = false;
this.executionRequests = Optional.empty();
}

public GetPayloadResponse(
Expand All @@ -38,6 +41,7 @@ public GetPayloadResponse(
this.executionPayloadValue = executionPayloadValue;
this.blobsBundle = Optional.empty();
this.shouldOverrideBuilder = false;
this.executionRequests = Optional.empty();
}

public GetPayloadResponse(
Expand All @@ -49,6 +53,20 @@ public GetPayloadResponse(
this.executionPayloadValue = executionPayloadValue;
this.blobsBundle = Optional.of(blobsBundle);
this.shouldOverrideBuilder = shouldOverrideBuilder;
this.executionRequests = Optional.empty();
}

public GetPayloadResponse(
final ExecutionPayload executionPayload,
final UInt256 executionPayloadValue,
final BlobsBundle blobsBundle,
final boolean shouldOverrideBuilder,
final ExecutionRequests executionRequests) {
this.executionPayload = executionPayload;
this.executionPayloadValue = executionPayloadValue;
this.blobsBundle = Optional.of(blobsBundle);
this.shouldOverrideBuilder = shouldOverrideBuilder;
this.executionRequests = Optional.of(executionRequests);
}

public ExecutionPayload getExecutionPayload() {
Expand All @@ -67,6 +85,10 @@ public boolean getShouldOverrideBuilder() {
return shouldOverrideBuilder;
}

public Optional<ExecutionRequests> getExecutionRequests() {
return executionRequests;
}

@Override
public boolean equals(final Object o) {
if (this == o) {
Expand All @@ -79,13 +101,18 @@ public boolean equals(final Object o) {
return shouldOverrideBuilder == that.shouldOverrideBuilder
&& Objects.equals(executionPayload, that.executionPayload)
&& Objects.equals(executionPayloadValue, that.executionPayloadValue)
&& Objects.equals(blobsBundle, that.blobsBundle);
&& Objects.equals(blobsBundle, that.blobsBundle)
&& Objects.equals(executionRequests, that.executionRequests);
}

@Override
public int hashCode() {
return Objects.hash(
executionPayload, executionPayloadValue, blobsBundle, shouldOverrideBuilder);
executionPayload,
executionPayloadValue,
blobsBundle,
shouldOverrideBuilder,
executionRequests);
}

@Override
Expand All @@ -95,6 +122,7 @@ public String toString() {
.add("executionPayloadValue", executionPayloadValue)
.add("blobsBundle", blobsBundle)
.add("shouldOverrideBuilder", shouldOverrideBuilder)
.add("executionRequests", executionRequests)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,8 +78,17 @@ public ExecutionRequests decode(final List<Bytes> executionRequestData) {
return executionRequestsBuilder.build();
}

public Bytes32 hash(final ExecutionRequests executionRequests) {
final Bytes sortedEncodedRequests =
encodeWithTypePrefix(executionRequests).stream()
.map(Hash::sha256)
.map(Bytes.class::cast)
.reduce(Bytes.EMPTY, Bytes::concatenate);
return Hash.sha256(sortedEncodedRequests);
}

@VisibleForTesting
List<Bytes> encodeWithTypePrefix(final ExecutionRequests executionRequests) {
public List<Bytes> encodeWithoutTypePrefix(final ExecutionRequests executionRequests) {
final SszList<DepositRequest> depositRequestsSszList =
executionRequestsSchema
.getDepositRequestsSchema()
Expand All @@ -94,18 +103,17 @@ List<Bytes> encodeWithTypePrefix(final ExecutionRequests executionRequests) {
.createFromElements(executionRequests.getConsolidations());

return List.of(
Bytes.concatenate(DEPOSIT_REQUEST_PREFIX, depositRequestsSszList.sszSerialize()),
Bytes.concatenate(WITHDRAWAL_REQUEST_PREFIX, withdrawalRequestsSszList.sszSerialize()),
Bytes.concatenate(
CONSOLIDATION_REQUEST_PREFIX, consolidationRequestsSszList.sszSerialize()));
depositRequestsSszList.sszSerialize(),
withdrawalRequestsSszList.sszSerialize(),
consolidationRequestsSszList.sszSerialize());
}

public Bytes32 hash(final ExecutionRequests executionRequests) {
final Bytes sortedEncodedRequests =
encodeWithTypePrefix(executionRequests).stream()
.map(Hash::sha256)
.map(Bytes.class::cast)
.reduce(Bytes.EMPTY, Bytes::concatenate);
return Hash.sha256(sortedEncodedRequests);
@VisibleForTesting
List<Bytes> encodeWithTypePrefix(final ExecutionRequests executionRequests) {
final List<Bytes> encodeWithoutTypePrefix = encodeWithoutTypePrefix(executionRequests);
return List.of(
Bytes.concatenate(DEPOSIT_REQUEST_PREFIX, encodeWithoutTypePrefix.get(0)),
Bytes.concatenate(WITHDRAWAL_REQUEST_PREFIX, encodeWithoutTypePrefix.get(1)),
Bytes.concatenate(CONSOLIDATION_REQUEST_PREFIX, encodeWithoutTypePrefix.get(2)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.DepositRequest;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequests;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsBuilderElectra;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsDataCodec;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.ExecutionRequestsSchema;
import tech.pegasys.teku.spec.datastructures.execution.versions.electra.WithdrawalRequest;
import tech.pegasys.teku.spec.datastructures.forkchoice.VoteTracker;
import tech.pegasys.teku.spec.datastructures.lightclient.LightClientBootstrap;
Expand Down Expand Up @@ -2504,6 +2506,15 @@ public ExecutionRequests randomExecutionRequests() {
.build();
}

public List<Bytes> randomEncodedExecutionRequests() {
final ExecutionRequestsSchema executionRequestsSchema =
SchemaDefinitionsElectra.required(
spec.forMilestone(SpecMilestone.ELECTRA).getSchemaDefinitions())
.getExecutionRequestsSchema();
return new ExecutionRequestsDataCodec(executionRequestsSchema)
.encodeWithoutTypePrefix(randomExecutionRequests());
}

public WithdrawalRequest randomWithdrawalRequest() {
return getElectraSchemaDefinitions(randomSlot())
.getWithdrawalRequestSchema()
Expand Down