Skip to content

Commit c93c873

Browse files
Add engine_getPayloadV4 and engine_newPayloadV4 for Electra (Consensys#8115)
1 parent 015f4e3 commit c93c873

File tree

20 files changed

+1048
-28
lines changed

20 files changed

+1048
-28
lines changed

Diff for: ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ExecutionEngineClient.java

+9
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1;
2121
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2;
2222
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3;
23+
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4;
2324
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1;
2425
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult;
2526
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV2Response;
2627
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV3Response;
28+
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV4Response;
2729
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV1;
2830
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV2;
2931
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV3;
@@ -47,6 +49,8 @@ public interface ExecutionEngineClient {
4749

4850
SafeFuture<Response<GetPayloadV3Response>> getPayloadV3(Bytes8 payloadId);
4951

52+
SafeFuture<Response<GetPayloadV4Response>> getPayloadV4(Bytes8 payloadId);
53+
5054
SafeFuture<Response<PayloadStatusV1>> newPayloadV1(ExecutionPayloadV1 executionPayload);
5155

5256
SafeFuture<Response<PayloadStatusV1>> newPayloadV2(ExecutionPayloadV2 executionPayload);
@@ -56,6 +60,11 @@ SafeFuture<Response<PayloadStatusV1>> newPayloadV3(
5660
List<VersionedHash> blobVersionedHashes,
5761
Bytes32 parentBeaconBlockRoot);
5862

63+
SafeFuture<Response<PayloadStatusV1>> newPayloadV4(
64+
ExecutionPayloadV4 executionPayload,
65+
List<VersionedHash> blobVersionedHashes,
66+
Bytes32 parentBeaconBlockRoot);
67+
5968
SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV1(
6069
ForkChoiceStateV1 forkChoiceState, Optional<PayloadAttributesV1> payloadAttributes);
6170

Diff for: ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/ThrottlingExecutionEngineClient.java

+16
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1;
2222
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2;
2323
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3;
24+
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4;
2425
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1;
2526
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult;
2627
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV2Response;
2728
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV3Response;
29+
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV4Response;
2830
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV1;
2931
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV2;
3032
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV3;
@@ -79,6 +81,11 @@ public SafeFuture<Response<GetPayloadV3Response>> getPayloadV3(final Bytes8 payl
7981
return taskQueue.queueTask(() -> delegate.getPayloadV3(payloadId));
8082
}
8183

84+
@Override
85+
public SafeFuture<Response<GetPayloadV4Response>> getPayloadV4(final Bytes8 payloadId) {
86+
return taskQueue.queueTask(() -> delegate.getPayloadV4(payloadId));
87+
}
88+
8289
@Override
8390
public SafeFuture<Response<PayloadStatusV1>> newPayloadV1(
8491
final ExecutionPayloadV1 executionPayload) {
@@ -100,6 +107,15 @@ public SafeFuture<Response<PayloadStatusV1>> newPayloadV3(
100107
() -> delegate.newPayloadV3(executionPayload, blobVersionedHashes, parentBeaconBlockRoot));
101108
}
102109

110+
@Override
111+
public SafeFuture<Response<PayloadStatusV1>> newPayloadV4(
112+
final ExecutionPayloadV4 executionPayload,
113+
final List<VersionedHash> blobVersionedHashes,
114+
final Bytes32 parentBeaconBlockRoot) {
115+
return taskQueue.queueTask(
116+
() -> delegate.newPayloadV4(executionPayload, blobVersionedHashes, parentBeaconBlockRoot));
117+
}
118+
103119
@Override
104120
public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV1(
105121
final ForkChoiceStateV1 forkChoiceState,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright Consensys Software Inc., 2023
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package tech.pegasys.teku.ethereum.executionclient.methods;
15+
16+
import org.apache.logging.log4j.LogManager;
17+
import org.apache.logging.log4j.Logger;
18+
import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient;
19+
import tech.pegasys.teku.ethereum.executionclient.response.ResponseUnwrapper;
20+
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV4Response;
21+
import tech.pegasys.teku.infrastructure.async.SafeFuture;
22+
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
23+
import tech.pegasys.teku.spec.Spec;
24+
import tech.pegasys.teku.spec.datastructures.blobs.versions.deneb.BlobSchema;
25+
import tech.pegasys.teku.spec.datastructures.execution.BlobsBundle;
26+
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload;
27+
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadContext;
28+
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayloadSchema;
29+
import tech.pegasys.teku.spec.datastructures.execution.GetPayloadResponse;
30+
import tech.pegasys.teku.spec.schemas.SchemaDefinitions;
31+
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsBellatrix;
32+
import tech.pegasys.teku.spec.schemas.SchemaDefinitionsDeneb;
33+
34+
public class EngineGetPayloadV4 extends AbstractEngineJsonRpcMethod<GetPayloadResponse> {
35+
36+
private static final Logger LOG = LogManager.getLogger();
37+
38+
private final Spec spec;
39+
40+
public EngineGetPayloadV4(final ExecutionEngineClient executionEngineClient, final Spec spec) {
41+
super(executionEngineClient);
42+
this.spec = spec;
43+
}
44+
45+
@Override
46+
public String getName() {
47+
return EngineApiMethod.ENGINE_GET_PAYLOAD.getName();
48+
}
49+
50+
@Override
51+
public int getVersion() {
52+
return 4;
53+
}
54+
55+
@Override
56+
public SafeFuture<GetPayloadResponse> execute(final JsonRpcRequestParams params) {
57+
final ExecutionPayloadContext executionPayloadContext =
58+
params.getRequiredParameter(0, ExecutionPayloadContext.class);
59+
final UInt64 slot = params.getRequiredParameter(1, UInt64.class);
60+
61+
LOG.trace(
62+
"Calling {}(payloadId={}, slot={})",
63+
getVersionedName(),
64+
executionPayloadContext.getPayloadId(),
65+
slot);
66+
67+
return executionEngineClient
68+
.getPayloadV4(executionPayloadContext.getPayloadId())
69+
.thenApply(ResponseUnwrapper::unwrapExecutionClientResponseOrThrow)
70+
.thenApply(
71+
response -> {
72+
final SchemaDefinitions schemaDefinitions = spec.atSlot(slot).getSchemaDefinitions();
73+
final ExecutionPayloadSchema<?> payloadSchema =
74+
SchemaDefinitionsBellatrix.required(schemaDefinitions)
75+
.getExecutionPayloadSchema();
76+
final ExecutionPayload executionPayload =
77+
response.executionPayload.asInternalExecutionPayload(payloadSchema);
78+
final BlobsBundle blobsBundle = getBlobsBundle(response, schemaDefinitions);
79+
return new GetPayloadResponse(
80+
executionPayload,
81+
response.blockValue,
82+
blobsBundle,
83+
response.shouldOverrideBuilder);
84+
})
85+
.thenPeek(
86+
getPayloadResponse ->
87+
LOG.trace(
88+
"Response {}(payloadId={}, slot={}) -> {}",
89+
getVersionedName(),
90+
executionPayloadContext.getPayloadId(),
91+
slot,
92+
getPayloadResponse));
93+
}
94+
95+
private BlobsBundle getBlobsBundle(
96+
final GetPayloadV4Response response, final SchemaDefinitions schemaDefinitions) {
97+
final BlobSchema blobSchema =
98+
SchemaDefinitionsDeneb.required(schemaDefinitions).getBlobSchema();
99+
return response.blobsBundle.asInternalBlobsBundle(blobSchema);
100+
}
101+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright Consensys Software Inc., 2023
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package tech.pegasys.teku.ethereum.executionclient.methods;
15+
16+
import java.util.List;
17+
import org.apache.logging.log4j.LogManager;
18+
import org.apache.logging.log4j.Logger;
19+
import org.apache.tuweni.bytes.Bytes32;
20+
import tech.pegasys.teku.ethereum.executionclient.ExecutionEngineClient;
21+
import tech.pegasys.teku.ethereum.executionclient.response.ResponseUnwrapper;
22+
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4;
23+
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadStatusV1;
24+
import tech.pegasys.teku.infrastructure.async.SafeFuture;
25+
import tech.pegasys.teku.spec.datastructures.execution.ExecutionPayload;
26+
import tech.pegasys.teku.spec.executionlayer.PayloadStatus;
27+
import tech.pegasys.teku.spec.logic.versions.deneb.types.VersionedHash;
28+
29+
public class EngineNewPayloadV4 extends AbstractEngineJsonRpcMethod<PayloadStatus> {
30+
31+
private static final Logger LOG = LogManager.getLogger();
32+
33+
public EngineNewPayloadV4(final ExecutionEngineClient executionEngineClient) {
34+
super(executionEngineClient);
35+
}
36+
37+
@Override
38+
public String getName() {
39+
return EngineApiMethod.ENGINE_NEW_PAYLOAD.getName();
40+
}
41+
42+
@Override
43+
public int getVersion() {
44+
return 4;
45+
}
46+
47+
@Override
48+
public SafeFuture<PayloadStatus> execute(final JsonRpcRequestParams params) {
49+
final ExecutionPayload executionPayload =
50+
params.getRequiredParameter(0, ExecutionPayload.class);
51+
final List<VersionedHash> blobVersionedHashes =
52+
params.getRequiredListParameter(1, VersionedHash.class);
53+
final Bytes32 parentBeaconBlockRoot = params.getRequiredParameter(2, Bytes32.class);
54+
55+
LOG.trace(
56+
"Calling {}(executionPayload={}, blobVersionedHashes={}, parentBeaconBlockRoot={})",
57+
getVersionedName(),
58+
executionPayload,
59+
blobVersionedHashes,
60+
parentBeaconBlockRoot);
61+
62+
final ExecutionPayloadV4 executionPayloadV4 =
63+
ExecutionPayloadV4.fromInternalExecutionPayload(executionPayload);
64+
return executionEngineClient
65+
.newPayloadV4(executionPayloadV4, blobVersionedHashes, parentBeaconBlockRoot)
66+
.thenApply(ResponseUnwrapper::unwrapExecutionClientResponseOrThrow)
67+
.thenApply(PayloadStatusV1::asInternalExecutionPayload)
68+
.thenPeek(
69+
payloadStatus ->
70+
LOG.trace(
71+
"Response {}(executionPayload={}) -> {}",
72+
getVersionedName(),
73+
executionPayload,
74+
payloadStatus))
75+
.exceptionally(PayloadStatus::failedExecution);
76+
}
77+
}

Diff for: ethereum/executionclient/src/main/java/tech/pegasys/teku/ethereum/executionclient/metrics/MetricRecordingExecutionEngineClient.java

+19
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV1;
2424
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV2;
2525
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV3;
26+
import tech.pegasys.teku.ethereum.executionclient.schema.ExecutionPayloadV4;
2627
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceStateV1;
2728
import tech.pegasys.teku.ethereum.executionclient.schema.ForkChoiceUpdatedResult;
2829
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV2Response;
2930
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV3Response;
31+
import tech.pegasys.teku.ethereum.executionclient.schema.GetPayloadV4Response;
3032
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV1;
3133
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV2;
3234
import tech.pegasys.teku.ethereum.executionclient.schema.PayloadAttributesV3;
@@ -59,7 +61,9 @@ public class MetricRecordingExecutionEngineClient extends MetricRecordingAbstrac
5961
public static final String FORKCHOICE_UPDATED_WITH_ATTRIBUTES_V3_METHOD =
6062
"forkchoice_updated_with_attributesV3";
6163
public static final String GET_PAYLOAD_V3_METHOD = "get_payloadV3";
64+
public static final String GET_PAYLOAD_V4_METHOD = "get_payloadV4";
6265
public static final String NEW_PAYLOAD_V3_METHOD = "new_payloadV3";
66+
public static final String NEW_PAYLOAD_V4_METHOD = "new_payloadV4";
6367
public static final String EXCHANGE_CAPABILITIES_METHOD = "exchange_capabilities";
6468
public static final String GET_CLIENT_VERSION_V1_METHOD = "get_client_versionV1";
6569

@@ -106,6 +110,11 @@ public SafeFuture<Response<GetPayloadV3Response>> getPayloadV3(final Bytes8 payl
106110
return countRequest(() -> delegate.getPayloadV3(payloadId), GET_PAYLOAD_V3_METHOD);
107111
}
108112

113+
@Override
114+
public SafeFuture<Response<GetPayloadV4Response>> getPayloadV4(final Bytes8 payloadId) {
115+
return countRequest(() -> delegate.getPayloadV4(payloadId), GET_PAYLOAD_V4_METHOD);
116+
}
117+
109118
@Override
110119
public SafeFuture<Response<PayloadStatusV1>> newPayloadV1(
111120
final ExecutionPayloadV1 executionPayload) {
@@ -128,6 +137,16 @@ public SafeFuture<Response<PayloadStatusV1>> newPayloadV3(
128137
NEW_PAYLOAD_V3_METHOD);
129138
}
130139

140+
@Override
141+
public SafeFuture<Response<PayloadStatusV1>> newPayloadV4(
142+
final ExecutionPayloadV4 executionPayload,
143+
final List<VersionedHash> blobVersionedHashes,
144+
final Bytes32 parentBeaconBlockRoot) {
145+
return countRequest(
146+
() -> delegate.newPayloadV4(executionPayload, blobVersionedHashes, parentBeaconBlockRoot),
147+
NEW_PAYLOAD_V4_METHOD);
148+
}
149+
131150
@Override
132151
public SafeFuture<Response<ForkChoiceUpdatedResult>> forkChoiceUpdatedV1(
133152
final ForkChoiceStateV1 forkChoiceState,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright Consensys Software Inc., 2024
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5+
* the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10+
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
* specific language governing permissions and limitations under the License.
12+
*/
13+
14+
package tech.pegasys.teku.ethereum.executionclient.schema;
15+
16+
import com.fasterxml.jackson.annotation.JsonProperty;
17+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
18+
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
19+
import org.apache.tuweni.bytes.Bytes;
20+
import org.apache.tuweni.bytes.Bytes32;
21+
import org.apache.tuweni.bytes.Bytes48;
22+
import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes32Deserializer;
23+
import tech.pegasys.teku.ethereum.executionclient.serialization.Bytes48Deserializer;
24+
import tech.pegasys.teku.ethereum.executionclient.serialization.BytesDeserializer;
25+
import tech.pegasys.teku.ethereum.executionclient.serialization.BytesSerializer;
26+
import tech.pegasys.teku.ethereum.executionclient.serialization.UInt64AsHexDeserializer;
27+
import tech.pegasys.teku.ethereum.executionclient.serialization.UInt64AsHexSerializer;
28+
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
29+
30+
public class DepositReceiptV1 {
31+
@JsonSerialize(using = BytesSerializer.class)
32+
@JsonDeserialize(using = Bytes48Deserializer.class)
33+
public final Bytes48 pubkey;
34+
35+
@JsonSerialize(using = BytesSerializer.class)
36+
@JsonDeserialize(using = Bytes32Deserializer.class)
37+
public final Bytes32 withdrawalCredentials;
38+
39+
@JsonSerialize(using = UInt64AsHexSerializer.class)
40+
@JsonDeserialize(using = UInt64AsHexDeserializer.class)
41+
public final UInt64 amount;
42+
43+
@JsonSerialize(using = BytesSerializer.class)
44+
@JsonDeserialize(using = BytesDeserializer.class)
45+
public final Bytes signature;
46+
47+
@JsonSerialize(using = UInt64AsHexSerializer.class)
48+
@JsonDeserialize(using = UInt64AsHexDeserializer.class)
49+
public final UInt64 index;
50+
51+
public DepositReceiptV1(
52+
@JsonProperty("pubkey") final Bytes48 pubkey,
53+
@JsonProperty("withdrawalCredentials") final Bytes32 withdrawalCredentials,
54+
@JsonProperty("amount") final UInt64 amount,
55+
@JsonProperty("signature") final Bytes signature,
56+
@JsonProperty("index") final UInt64 index) {
57+
this.pubkey = pubkey;
58+
this.withdrawalCredentials = withdrawalCredentials;
59+
this.amount = amount;
60+
this.signature = signature;
61+
this.index = index;
62+
}
63+
}

0 commit comments

Comments
 (0)