Skip to content

Commit be4f9b7

Browse files
Implemented decoding and hash rules for execution requests (#8668)
1 parent 28d559b commit be4f9b7

File tree

5 files changed

+402
-0
lines changed

5 files changed

+402
-0
lines changed

ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java

+3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@
2020
import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode;
2121
import tech.pegasys.teku.spec.datastructures.type.SszPublicKey;
2222

23+
// https://eips.ethereum.org/EIPS/eip-7251
2324
public class ConsolidationRequest
2425
extends Container3<ConsolidationRequest, SszByteVector, SszPublicKey, SszPublicKey> {
2526

27+
public static final byte REQUEST_TYPE = 0x2;
28+
2629
public static final ConsolidationRequestSchema SSZ_SCHEMA = new ConsolidationRequestSchema();
2730

2831
protected ConsolidationRequest(

ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java

+3
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,13 @@
2424
import tech.pegasys.teku.spec.datastructures.type.SszPublicKey;
2525
import tech.pegasys.teku.spec.datastructures.type.SszSignature;
2626

27+
// https://eips.ethereum.org/EIPS/eip-6110
2728
public class DepositRequest
2829
extends Container5<
2930
DepositRequest, SszPublicKey, SszBytes32, SszUInt64, SszSignature, SszUInt64> {
3031

32+
public static final byte REQUEST_TYPE = 0x0;
33+
3134
DepositRequest(
3235
final DepositRequestSchema schema,
3336
final BLSPublicKey pubkey,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
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.spec.datastructures.execution.versions.electra;
15+
16+
import com.google.common.annotations.VisibleForTesting;
17+
import java.util.List;
18+
import org.apache.tuweni.bytes.Bytes;
19+
import org.apache.tuweni.bytes.Bytes32;
20+
import tech.pegasys.teku.infrastructure.crypto.Hash;
21+
import tech.pegasys.teku.infrastructure.ssz.SszList;
22+
import tech.pegasys.teku.spec.datastructures.execution.ExecutionRequestsBuilder;
23+
24+
/*
25+
Implement the rules for decoding and hashing execution requests according to https://eips.ethereum.org/EIPS/eip-7685
26+
*/
27+
public class ExecutionRequestsDataCodec {
28+
29+
private static final int EXPECTED_REQUEST_DATA_ELEMENTS = 3;
30+
private static final Bytes DEPOSIT_REQUEST_PREFIX = Bytes.of(DepositRequest.REQUEST_TYPE);
31+
private static final Bytes WITHDRAWAL_REQUEST_PREFIX = Bytes.of(WithdrawalRequest.REQUEST_TYPE);
32+
private static final Bytes CONSOLIDATION_REQUEST_PREFIX =
33+
Bytes.of(ConsolidationRequest.REQUEST_TYPE);
34+
35+
private final ExecutionRequestsSchema executionRequestsSchema;
36+
37+
public ExecutionRequestsDataCodec(final ExecutionRequestsSchema executionRequestsSchema) {
38+
this.executionRequestsSchema = executionRequestsSchema;
39+
}
40+
41+
public ExecutionRequests decode(final List<Bytes> executionRequestData) {
42+
if (executionRequestData.size() != EXPECTED_REQUEST_DATA_ELEMENTS) {
43+
throw new IllegalArgumentException(
44+
"Invalid number of execution request data elements: expected "
45+
+ EXPECTED_REQUEST_DATA_ELEMENTS
46+
+ ", received "
47+
+ executionRequestData.size());
48+
}
49+
50+
final ExecutionRequestsBuilder executionRequestsBuilder =
51+
new ExecutionRequestsBuilderElectra(executionRequestsSchema);
52+
53+
for (int index = 0; index < executionRequestData.size(); index++) {
54+
// The request type is implicitly defined as the index of the element in executionRequestData
55+
switch ((byte) index) {
56+
case DepositRequest.REQUEST_TYPE ->
57+
executionRequestsBuilder.deposits(
58+
executionRequestsSchema
59+
.getDepositRequestsSchema()
60+
.sszDeserialize(executionRequestData.get(index))
61+
.asList());
62+
case WithdrawalRequest.REQUEST_TYPE ->
63+
executionRequestsBuilder.withdrawals(
64+
executionRequestsSchema
65+
.getWithdrawalRequestsSchema()
66+
.sszDeserialize(executionRequestData.get(index))
67+
.asList());
68+
case ConsolidationRequest.REQUEST_TYPE ->
69+
executionRequestsBuilder.consolidations(
70+
executionRequestsSchema
71+
.getConsolidationRequestsSchema()
72+
.sszDeserialize(executionRequestData.get(index))
73+
.asList());
74+
default -> throw new IllegalArgumentException("Invalid execution request type: " + index);
75+
}
76+
}
77+
78+
return executionRequestsBuilder.build();
79+
}
80+
81+
@VisibleForTesting
82+
List<Bytes> encodeWithTypePrefix(final ExecutionRequests executionRequests) {
83+
final SszList<DepositRequest> depositRequestsSszList =
84+
executionRequestsSchema
85+
.getDepositRequestsSchema()
86+
.createFromElements(executionRequests.getDeposits());
87+
final SszList<WithdrawalRequest> withdrawalRequestsSszList =
88+
executionRequestsSchema
89+
.getWithdrawalRequestsSchema()
90+
.createFromElements(executionRequests.getWithdrawals());
91+
final SszList<ConsolidationRequest> consolidationRequestsSszList =
92+
executionRequestsSchema
93+
.getConsolidationRequestsSchema()
94+
.createFromElements(executionRequests.getConsolidations());
95+
96+
return List.of(
97+
Bytes.concatenate(DEPOSIT_REQUEST_PREFIX, depositRequestsSszList.sszSerialize()),
98+
Bytes.concatenate(WITHDRAWAL_REQUEST_PREFIX, withdrawalRequestsSszList.sszSerialize()),
99+
Bytes.concatenate(
100+
CONSOLIDATION_REQUEST_PREFIX, consolidationRequestsSszList.sszSerialize()));
101+
}
102+
103+
public Bytes32 hash(final ExecutionRequests executionRequests) {
104+
final Bytes sortedEncodedRequests =
105+
encodeWithTypePrefix(executionRequests).stream()
106+
.map(Hash::sha256)
107+
.map(Bytes.class::cast)
108+
.reduce(Bytes.EMPTY, Bytes::concatenate);
109+
return Hash.sha256(sortedEncodedRequests);
110+
}
111+
}

ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java

+3
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,12 @@
2222
import tech.pegasys.teku.infrastructure.unsigned.UInt64;
2323
import tech.pegasys.teku.spec.datastructures.type.SszPublicKey;
2424

25+
// https://eips.ethereum.org/EIPS/eip-7002
2526
public class WithdrawalRequest
2627
extends Container3<WithdrawalRequest, SszByteVector, SszPublicKey, SszUInt64> {
2728

29+
public static final byte REQUEST_TYPE = 0x1;
30+
2831
public static final WithdrawalRequestSchema SSZ_SCHEMA = new WithdrawalRequestSchema();
2932

3033
protected WithdrawalRequest(

0 commit comments

Comments
 (0)