From f7b6cbaa218191ae6e9f0ccd2599af3f66b86464 Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Wed, 2 Oct 2024 17:20:42 +1300 Subject: [PATCH 1/4] Implemented decoding and hash for execution requests --- .../electra/ConsolidationRequest.java | 5 + .../versions/electra/DepositRequest.java | 5 + .../electra/ExecutionRequestsDataCodec.java | 110 ++++++++++ .../versions/electra/WithdrawalRequest.java | 5 + .../ExecutionRequestsDataCodecTest.java | 195 ++++++++++++++++++ 5 files changed, 320 insertions(+) create mode 100644 ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java create mode 100644 ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java index e54220c4807..2f706fec06a 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java @@ -20,9 +20,14 @@ import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.spec.datastructures.type.SszPublicKey; +/* + https://eips.ethereum.org/EIPS/eip-7251 +*/ public class ConsolidationRequest extends Container3 { + public static final byte REQUEST_TYPE = 0x2; + public static final ConsolidationRequestSchema SSZ_SCHEMA = new ConsolidationRequestSchema(); protected ConsolidationRequest( diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java index fc67724a394..230d0f8c243 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java @@ -24,10 +24,15 @@ import tech.pegasys.teku.spec.datastructures.type.SszPublicKey; import tech.pegasys.teku.spec.datastructures.type.SszSignature; +/* + https://eips.ethereum.org/EIPS/eip-6110 +*/ public class DepositRequest extends Container5< DepositRequest, SszPublicKey, SszBytes32, SszUInt64, SszSignature, SszUInt64> { + public static final byte REQUEST_TYPE = 0x0; + DepositRequest( final DepositRequestSchema schema, final BLSPublicKey pubkey, diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java new file mode 100644 index 00000000000..9e61ae78281 --- /dev/null +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java @@ -0,0 +1,110 @@ +/* + * Copyright Consensys Software Inc., 2024 + * + * 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.spec.datastructures.execution.versions.electra; + +import com.google.common.annotations.VisibleForTesting; +import java.util.Comparator; +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import tech.pegasys.teku.infrastructure.crypto.Hash; +import tech.pegasys.teku.infrastructure.ssz.SszList; +import tech.pegasys.teku.spec.datastructures.execution.ExecutionRequestsBuilder; + +/* + Implement the rules for decoding and hashing execution requests according to https://eips.ethereum.org/EIPS/eip-7685 +*/ +public class ExecutionRequestsDataCodec { + + private final ExecutionRequestsSchema executionRequestsSchema; + + public ExecutionRequestsDataCodec(final ExecutionRequestsSchema executionRequestsSchema) { + this.executionRequestsSchema = executionRequestsSchema; + } + + public ExecutionRequests decode(final List executionRequestData) { + final ExecutionRequestsBuilder executionRequestsBuilder = + new ExecutionRequestsBuilderElectra(executionRequestsSchema); + + executionRequestData.forEach( + data -> { + // First byte of the data is the type of the execution request + final byte type = data.get(0); + switch (type) { + case DepositRequest.REQUEST_TYPE: + // https://eips.ethereum.org/EIPS/eip-6110 + executionRequestsBuilder.deposits( + executionRequestsSchema + .getDepositRequestsSchema() + .sszDeserialize(data.slice(1)) + .asList()); + break; + case WithdrawalRequest.REQUEST_TYPE: + // https://eips.ethereum.org/EIPS/eip-7002 + executionRequestsBuilder.withdrawals( + executionRequestsSchema + .getWithdrawalRequestsSchema() + .sszDeserialize(data.slice(1)) + .asList()); + break; + case ConsolidationRequest.REQUEST_TYPE: + // https://eips.ethereum.org/EIPS/eip-7251 + executionRequestsBuilder.consolidations( + executionRequestsSchema + .getConsolidationRequestsSchema() + .sszDeserialize(data.slice(1)) + .asList()); + break; + default: + throw new IllegalArgumentException("Invalid execution request type: " + type); + } + }); + + return executionRequestsBuilder.build(); + } + + @VisibleForTesting + List encode(final ExecutionRequests executionRequests) { + final SszList depositRequestsSszList = + executionRequestsSchema + .getDepositRequestsSchema() + .createFromElements(executionRequests.getDeposits()); + final SszList withdrawalRequestsSszList = + executionRequestsSchema + .getWithdrawalRequestsSchema() + .createFromElements(executionRequests.getWithdrawals()); + final SszList consolidationRequestsSszList = + executionRequestsSchema + .getConsolidationRequestsSchema() + .createFromElements(executionRequests.getConsolidations()); + + return List.of( + Bytes.concatenate( + Bytes.of(DepositRequest.REQUEST_TYPE), depositRequestsSszList.sszSerialize()), + Bytes.concatenate( + Bytes.of(WithdrawalRequest.REQUEST_TYPE), withdrawalRequestsSszList.sszSerialize()), + Bytes.concatenate( + Bytes.of(ConsolidationRequest.REQUEST_TYPE), + consolidationRequestsSszList.sszSerialize())); + } + + public Bytes32 hash(final ExecutionRequests executionRequests) { + final Bytes sortedEncodedRequests = + encode(executionRequests).stream() + // Encoded requests are sorted by their type (first byte) + .sorted(Comparator.comparingInt(b -> b.get(0))) + .reduce(Bytes.EMPTY, Bytes::concatenate); + return Hash.sha256(sortedEncodedRequests); + } +} diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java index f07a9e0de68..200875db5dd 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java @@ -22,9 +22,14 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.type.SszPublicKey; +/* + https://eips.ethereum.org/EIPS/eip-7002 +*/ public class WithdrawalRequest extends Container3 { + public static final byte REQUEST_TYPE = 0x1; + public static final WithdrawalRequestSchema SSZ_SCHEMA = new WithdrawalRequestSchema(); protected WithdrawalRequest( diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java new file mode 100644 index 00000000000..488669074d3 --- /dev/null +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java @@ -0,0 +1,195 @@ +/* + * Copyright Consensys Software Inc., 2024 + * + * 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.spec.datastructures.execution.versions.electra; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.List; +import org.apache.tuweni.bytes.Bytes; +import org.apache.tuweni.bytes.Bytes32; +import org.junit.jupiter.api.Test; +import tech.pegasys.teku.bls.BLSPublicKey; +import tech.pegasys.teku.bls.BLSSignature; +import tech.pegasys.teku.infrastructure.bytes.Bytes20; +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.config.SpecConfigElectra; +import tech.pegasys.teku.spec.util.DataStructureUtil; + +class ExecutionRequestsDataCodecTest { + + private final Spec spec = TestSpecFactory.createMinimalElectra(); + private final SpecConfigElectra specConfigElectra = + SpecConfigElectra.required(spec.forMilestone(SpecMilestone.ELECTRA).getConfig()); + private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); + private final ExecutionRequestsSchema executionRequestsSchema = + new ExecutionRequestsSchema(specConfigElectra); + private final ExecutionRequestsDataCodec codec = + new ExecutionRequestsDataCodec(executionRequestsSchema); + + @Test + public void encodeDecodeRoundTrip() { + final ExecutionRequests executionRequests = dataStructureUtil.randomExecutionRequests(); + + final List encodedExecutionRequests = codec.encode(executionRequests); + final ExecutionRequests decodedExecutionRequests = codec.decode(encodedExecutionRequests); + + assertEquals(executionRequests, decodedExecutionRequests); + } + + @Test + public void decodeExecutionRequestData() { + final List executionRequestsData = + List.of( + depositRequestListEncoded, + withdrawalRequestsListEncoded, + consolidationRequestsListEncoded); + + final ExecutionRequests executionRequests = codec.decode(executionRequestsData); + + assertThat(executionRequests.getDeposits()).containsExactly(depositRequest1, depositRequest2); + assertThat(executionRequests.getWithdrawals()) + .containsExactly(withdrawalRequest1, withdrawalRequest2); + assertThat(executionRequests.getConsolidations()).containsExactly(consolidationRequest1); + } + + @Test + public void decodeInvalidRequestTypeShouldThrowIllegalArgumentException() { + final Bytes invalidRequestType = Bytes.of(0xf); + // Replace valid 0x0 request type for deposits with invalid 0xf request type + final Bytes depositsWithInvalidRequestType = + Bytes.concatenate(invalidRequestType, depositRequestListEncoded.slice(1)); + + final List invalidExecutionRequestsData = + List.of( + depositsWithInvalidRequestType, + withdrawalRequestsListEncoded, + consolidationRequestsListEncoded); + + assertThatThrownBy(() -> codec.decode(invalidExecutionRequestsData)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void encodeExecutionRequests() { + final ExecutionRequests executionRequests = + new ExecutionRequestsBuilderElectra(executionRequestsSchema) + .deposits(List.of(depositRequest1, depositRequest2)) + .withdrawals(List.of(withdrawalRequest1, withdrawalRequest2)) + .consolidations(List.of(consolidationRequest1)) + .build(); + + final List encodedRequests = codec.encode(executionRequests); + + assertThat(encodedRequests) + .containsExactly( + depositRequestListEncoded, + withdrawalRequestsListEncoded, + consolidationRequestsListEncoded); + } + + @Test + public void hashExecutionRequests() { + // Previously known hash of the encoded execution requests + final Bytes expectedHash = + Bytes.fromHexString("0x9a1d06e635eb434e1ba98b03606ef0d20e87a78811f3d4abd04175e4f39847e3"); + final ExecutionRequests executionRequests = + new ExecutionRequestsBuilderElectra(executionRequestsSchema) + .deposits(List.of(depositRequest1, depositRequest2)) + .withdrawals(List.of(withdrawalRequest1, withdrawalRequest2)) + .consolidations(List.of(consolidationRequest1)) + .build(); + + // Hash will only match if elements and order are correct + assertThat(codec.hash(executionRequests)).isEqualTo(expectedHash); + } + + /* + Examples taken from https://github.com/ethereum/execution-apis/blob/main/src/engine/openrpc/methods/payload.yaml + + Note: Removed one of the consolidation elements from the list as in Electra the max length for the list is one. + */ + + private final Bytes depositRequestListEncoded = + Bytes.fromHexString( + "0x0096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20100000000000000b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9f000000000000000a5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca01000000000000009561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1f100000000000000"); + + private final DepositRequest depositRequest1 = + new DepositRequest( + (DepositRequestSchema) + executionRequestsSchema.getDepositRequestsSchema().getElementSchema(), + BLSPublicKey.fromHexString( + "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9"), + Bytes32.fromHexString( + "0x003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef2"), + UInt64.valueOf(1L), + BLSSignature.fromBytesCompressed( + Bytes.fromHexString( + "0xb1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9")), + UInt64.valueOf(240L)); + + private final DepositRequest depositRequest2 = + new DepositRequest( + (DepositRequestSchema) + executionRequestsSchema.getDepositRequestsSchema().getElementSchema(), + BLSPublicKey.fromHexString( + "0xa5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b"), + Bytes32.fromHexString( + "0x001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca"), + UInt64.valueOf(1L), + BLSSignature.fromBytesCompressed( + Bytes.fromHexString( + "0x9561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1")), + UInt64.valueOf(241L)); + + private final Bytes withdrawalRequestsListEncoded = + Bytes.fromHexString( + "0x01a94f5374fce5edbc8e2a8697c15331677e6ebf0b85103a5617937691dfeeb89b86a80d5dc9e3c9d3a1a0e7ce311e26e0bb732eabaa47ffa288f0d54de28209a62a7d29d0000000000000000000000000000000000000000000000000000010f698daeed734da114470da559bd4b4c7259e1f7952555241dcbc90cf194a2ef676fc6005f3672fada2a3645edb297a75530100000000000000"); + + private final WithdrawalRequest withdrawalRequest1 = + new WithdrawalRequest( + (WithdrawalRequestSchema) + executionRequestsSchema.getWithdrawalRequestsSchema().getElementSchema(), + Bytes20.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"), + BLSPublicKey.fromHexString( + "0x85103a5617937691dfeeb89b86a80d5dc9e3c9d3a1a0e7ce311e26e0bb732eabaa47ffa288f0d54de28209a62a7d29d0"), + UInt64.valueOf(0L)); + + private final WithdrawalRequest withdrawalRequest2 = + new WithdrawalRequest( + (WithdrawalRequestSchema) + executionRequestsSchema.getWithdrawalRequestsSchema().getElementSchema(), + Bytes20.fromHexString("0x00000000000000000000000000000000000010f6"), + BLSPublicKey.fromHexString( + "0x98daeed734da114470da559bd4b4c7259e1f7952555241dcbc90cf194a2ef676fc6005f3672fada2a3645edb297a7553"), + UInt64.valueOf(1L)); + + private final Bytes consolidationRequestsListEncoded = + Bytes.fromHexString( + "0x02a94f5374fce5edbc8e2a8697c15331677e6ebf0b85103a5617937691dfeeb89b86a80d5dc9e3c9d3a1a0e7ce311e26e0bb732eabaa47ffa288f0d54de28209a62a7d29d098daeed734da114470da559bd4b4c7259e1f7952555241dcbc90cf194a2ef676fc6005f3672fada2a3645edb297a7553"); + + private final ConsolidationRequest consolidationRequest1 = + new ConsolidationRequest( + (ConsolidationRequestSchema) + executionRequestsSchema.getConsolidationRequestsSchema().getElementSchema(), + Bytes20.fromHexString("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"), + BLSPublicKey.fromHexString( + "0x85103a5617937691dfeeb89b86a80d5dc9e3c9d3a1a0e7ce311e26e0bb732eabaa47ffa288f0d54de28209a62a7d29d0"), + BLSPublicKey.fromHexString( + "0x98daeed734da114470da559bd4b4c7259e1f7952555241dcbc90cf194a2ef676fc6005f3672fada2a3645edb297a7553")); +} From 3a7c9378e2cb254784faad8e4c18b60c04ce01dc Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Wed, 2 Oct 2024 19:39:27 +1300 Subject: [PATCH 2/4] PR comments --- .../electra/ConsolidationRequest.java | 4 +- .../versions/electra/DepositRequest.java | 4 +- .../electra/ExecutionRequestsDataCodec.java | 46 ++++++++----------- .../versions/electra/WithdrawalRequest.java | 4 +- 4 files changed, 23 insertions(+), 35 deletions(-) diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java index 2f706fec06a..5d0420fb9fb 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ConsolidationRequest.java @@ -20,9 +20,7 @@ import tech.pegasys.teku.infrastructure.ssz.tree.TreeNode; import tech.pegasys.teku.spec.datastructures.type.SszPublicKey; -/* - https://eips.ethereum.org/EIPS/eip-7251 -*/ +// https://eips.ethereum.org/EIPS/eip-7251 public class ConsolidationRequest extends Container3 { diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java index 230d0f8c243..56a12d1c71f 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/DepositRequest.java @@ -24,9 +24,7 @@ import tech.pegasys.teku.spec.datastructures.type.SszPublicKey; import tech.pegasys.teku.spec.datastructures.type.SszSignature; -/* - https://eips.ethereum.org/EIPS/eip-6110 -*/ +// https://eips.ethereum.org/EIPS/eip-6110 public class DepositRequest extends Container5< DepositRequest, SszPublicKey, SszBytes32, SszUInt64, SszSignature, SszUInt64> { diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java index 9e61ae78281..9ce778cd738 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java @@ -42,32 +42,26 @@ public ExecutionRequests decode(final List executionRequestData) { // First byte of the data is the type of the execution request final byte type = data.get(0); switch (type) { - case DepositRequest.REQUEST_TYPE: - // https://eips.ethereum.org/EIPS/eip-6110 - executionRequestsBuilder.deposits( - executionRequestsSchema - .getDepositRequestsSchema() - .sszDeserialize(data.slice(1)) - .asList()); - break; - case WithdrawalRequest.REQUEST_TYPE: - // https://eips.ethereum.org/EIPS/eip-7002 - executionRequestsBuilder.withdrawals( - executionRequestsSchema - .getWithdrawalRequestsSchema() - .sszDeserialize(data.slice(1)) - .asList()); - break; - case ConsolidationRequest.REQUEST_TYPE: - // https://eips.ethereum.org/EIPS/eip-7251 - executionRequestsBuilder.consolidations( - executionRequestsSchema - .getConsolidationRequestsSchema() - .sszDeserialize(data.slice(1)) - .asList()); - break; - default: - throw new IllegalArgumentException("Invalid execution request type: " + type); + case DepositRequest.REQUEST_TYPE -> + executionRequestsBuilder.deposits( + executionRequestsSchema + .getDepositRequestsSchema() + .sszDeserialize(data.slice(1)) + .asList()); + case WithdrawalRequest.REQUEST_TYPE -> + executionRequestsBuilder.withdrawals( + executionRequestsSchema + .getWithdrawalRequestsSchema() + .sszDeserialize(data.slice(1)) + .asList()); + case ConsolidationRequest.REQUEST_TYPE -> + executionRequestsBuilder.consolidations( + executionRequestsSchema + .getConsolidationRequestsSchema() + .sszDeserialize(data.slice(1)) + .asList()); + default -> + throw new IllegalArgumentException("Invalid execution request type: " + type); } }); diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java index 200875db5dd..1f7d270fe8c 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/WithdrawalRequest.java @@ -22,9 +22,7 @@ import tech.pegasys.teku.infrastructure.unsigned.UInt64; import tech.pegasys.teku.spec.datastructures.type.SszPublicKey; -/* - https://eips.ethereum.org/EIPS/eip-7002 -*/ +// https://eips.ethereum.org/EIPS/eip-7002 public class WithdrawalRequest extends Container3 { From 9a0f71057b0069efdd62a05a76c4a18411f2168f Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Tue, 8 Oct 2024 17:47:42 +1300 Subject: [PATCH 3/4] Updated hash and decoding logic --- .../electra/ExecutionRequestsDataCodec.java | 66 ++++---- .../ExecutionRequestsDataCodecTest.java | 149 ++++++++++++++---- 2 files changed, 154 insertions(+), 61 deletions(-) diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java index 9ce778cd738..652b7416a07 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java @@ -14,7 +14,6 @@ package tech.pegasys.teku.spec.datastructures.execution.versions.electra; import com.google.common.annotations.VisibleForTesting; -import java.util.Comparator; import java.util.List; import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; @@ -27,6 +26,8 @@ */ public class ExecutionRequestsDataCodec { + private static final int EXPECTED_REQUEST_DATA_ELEMENTS = 3; + private final ExecutionRequestsSchema executionRequestsSchema; public ExecutionRequestsDataCodec(final ExecutionRequestsSchema executionRequestsSchema) { @@ -34,36 +35,41 @@ public ExecutionRequestsDataCodec(final ExecutionRequestsSchema executionRequest } public ExecutionRequests decode(final List executionRequestData) { + if (executionRequestData.size() != EXPECTED_REQUEST_DATA_ELEMENTS) { + throw new IllegalArgumentException( + "Invalid number of execution request data elements: expected " + + EXPECTED_REQUEST_DATA_ELEMENTS + + ", received " + + executionRequestData.size()); + } + final ExecutionRequestsBuilder executionRequestsBuilder = new ExecutionRequestsBuilderElectra(executionRequestsSchema); - executionRequestData.forEach( - data -> { - // First byte of the data is the type of the execution request - final byte type = data.get(0); - switch (type) { - case DepositRequest.REQUEST_TYPE -> - executionRequestsBuilder.deposits( - executionRequestsSchema - .getDepositRequestsSchema() - .sszDeserialize(data.slice(1)) - .asList()); - case WithdrawalRequest.REQUEST_TYPE -> - executionRequestsBuilder.withdrawals( - executionRequestsSchema - .getWithdrawalRequestsSchema() - .sszDeserialize(data.slice(1)) - .asList()); - case ConsolidationRequest.REQUEST_TYPE -> - executionRequestsBuilder.consolidations( - executionRequestsSchema - .getConsolidationRequestsSchema() - .sszDeserialize(data.slice(1)) - .asList()); - default -> - throw new IllegalArgumentException("Invalid execution request type: " + type); - } - }); + for (int index = 0; index < executionRequestData.size(); index++) { + // The request type is implicitly defined as the index of the element in executionRequestData + switch ((byte) index) { + case DepositRequest.REQUEST_TYPE -> + executionRequestsBuilder.deposits( + executionRequestsSchema + .getDepositRequestsSchema() + .sszDeserialize(executionRequestData.get(index)) + .asList()); + case WithdrawalRequest.REQUEST_TYPE -> + executionRequestsBuilder.withdrawals( + executionRequestsSchema + .getWithdrawalRequestsSchema() + .sszDeserialize(executionRequestData.get(index)) + .asList()); + case ConsolidationRequest.REQUEST_TYPE -> + executionRequestsBuilder.consolidations( + executionRequestsSchema + .getConsolidationRequestsSchema() + .sszDeserialize(executionRequestData.get(index)) + .asList()); + default -> throw new IllegalArgumentException("Invalid execution request type: " + index); + } + } return executionRequestsBuilder.build(); } @@ -96,8 +102,8 @@ List encode(final ExecutionRequests executionRequests) { public Bytes32 hash(final ExecutionRequests executionRequests) { final Bytes sortedEncodedRequests = encode(executionRequests).stream() - // Encoded requests are sorted by their type (first byte) - .sorted(Comparator.comparingInt(b -> b.get(0))) + .map(Hash::sha256) + .map(Bytes.class::cast) .reduce(Bytes.EMPTY, Bytes::concatenate); return Hash.sha256(sortedEncodedRequests); } diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java index 488669074d3..e6752871dfd 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java @@ -15,7 +15,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; import org.apache.tuweni.bytes.Bytes; @@ -29,29 +28,17 @@ import tech.pegasys.teku.spec.SpecMilestone; import tech.pegasys.teku.spec.TestSpecFactory; import tech.pegasys.teku.spec.config.SpecConfigElectra; -import tech.pegasys.teku.spec.util.DataStructureUtil; class ExecutionRequestsDataCodecTest { private final Spec spec = TestSpecFactory.createMinimalElectra(); private final SpecConfigElectra specConfigElectra = SpecConfigElectra.required(spec.forMilestone(SpecMilestone.ELECTRA).getConfig()); - private final DataStructureUtil dataStructureUtil = new DataStructureUtil(spec); private final ExecutionRequestsSchema executionRequestsSchema = new ExecutionRequestsSchema(specConfigElectra); private final ExecutionRequestsDataCodec codec = new ExecutionRequestsDataCodec(executionRequestsSchema); - @Test - public void encodeDecodeRoundTrip() { - final ExecutionRequests executionRequests = dataStructureUtil.randomExecutionRequests(); - - final List encodedExecutionRequests = codec.encode(executionRequests); - final ExecutionRequests decodedExecutionRequests = codec.decode(encodedExecutionRequests); - - assertEquals(executionRequests, decodedExecutionRequests); - } - @Test public void decodeExecutionRequestData() { final List executionRequestsData = @@ -69,17 +56,66 @@ public void decodeExecutionRequestData() { } @Test - public void decodeInvalidRequestTypeShouldThrowIllegalArgumentException() { - final Bytes invalidRequestType = Bytes.of(0xf); - // Replace valid 0x0 request type for deposits with invalid 0xf request type - final Bytes depositsWithInvalidRequestType = - Bytes.concatenate(invalidRequestType, depositRequestListEncoded.slice(1)); + public void decodeExecutionRequestDataWithAllRequestTypesEmpty() { + final List executionRequestsData = List.of(Bytes.EMPTY, Bytes.EMPTY, Bytes.EMPTY); + + final ExecutionRequests executionRequests = codec.decode(executionRequestsData); + + assertThat(executionRequests.getDeposits()).isEmpty(); + assertThat(executionRequests.getWithdrawals()).isEmpty(); + assertThat(executionRequests.getConsolidations()).isEmpty(); + } + + @Test + public void decodeExecutionRequestDataWithOneRequestTypeEmpty() { + final List executionRequestsData = + List.of(depositRequestListEncoded, Bytes.EMPTY, consolidationRequestsListEncoded); + + final ExecutionRequests executionRequests = codec.decode(executionRequestsData); + + assertThat(executionRequests.getDeposits()).containsExactly(depositRequest1, depositRequest2); + assertThat(executionRequests.getWithdrawals()).isEmpty(); + assertThat(executionRequests.getConsolidations()).containsExactly(consolidationRequest1); + } + + @Test + public void decodeExecutionRequestDataWithMoreElementsThanExpected() { + final List invalidExecutionRequestsData = + List.of( + depositRequestListEncoded, + withdrawalRequestsListEncoded, + consolidationRequestsListEncoded, + Bytes.random(10)); + + assertThatThrownBy(() -> codec.decode(invalidExecutionRequestsData)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void decodeExecutionRequestDataWithLessThanExpectedElements() { + final List invalidExecutionRequestsData = + List.of(depositRequestListEncoded, withdrawalRequestsListEncoded); + + assertThatThrownBy(() -> codec.decode(invalidExecutionRequestsData)) + .isInstanceOf(IllegalArgumentException.class); + } + @Test + public void decodeExecutionRequestDataWithMoreThanExpectedElements() { final List invalidExecutionRequestsData = List.of( - depositsWithInvalidRequestType, + depositRequestListEncoded, withdrawalRequestsListEncoded, - consolidationRequestsListEncoded); + consolidationRequestsListEncoded, + depositRequestListEncoded); + + assertThatThrownBy(() -> codec.decode(invalidExecutionRequestsData)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + public void decodeExecutionRequestDataWithZeroElements() { + final List invalidExecutionRequestsData = List.of(); assertThatThrownBy(() -> codec.decode(invalidExecutionRequestsData)) .isInstanceOf(IllegalArgumentException.class); @@ -98,16 +134,55 @@ public void encodeExecutionRequests() { assertThat(encodedRequests) .containsExactly( - depositRequestListEncoded, - withdrawalRequestsListEncoded, - consolidationRequestsListEncoded); + Bytes.concatenate(Bytes.of(DepositRequest.REQUEST_TYPE), depositRequestListEncoded), + Bytes.concatenate( + Bytes.of(WithdrawalRequest.REQUEST_TYPE), withdrawalRequestsListEncoded), + Bytes.concatenate( + Bytes.of(ConsolidationRequest.REQUEST_TYPE), consolidationRequestsListEncoded)); + } + + @Test + public void encodeExecutionRequestsWithOneEmptyRequestList() { + final ExecutionRequests executionRequests = + new ExecutionRequestsBuilderElectra(executionRequestsSchema) + .deposits(List.of(depositRequest1, depositRequest2)) + .withdrawals(List.of()) + .consolidations(List.of(consolidationRequest1)) + .build(); + + final List encodedRequests = codec.encode(executionRequests); + + assertThat(encodedRequests) + .containsExactly( + Bytes.concatenate(Bytes.of(DepositRequest.REQUEST_TYPE), depositRequestListEncoded), + Bytes.of(WithdrawalRequest.REQUEST_TYPE), + Bytes.concatenate( + Bytes.of(ConsolidationRequest.REQUEST_TYPE), consolidationRequestsListEncoded)); + } + + @Test + public void encodeExecutionRequestsWithAllEmptyRequestLists() { + final ExecutionRequests executionRequests = + new ExecutionRequestsBuilderElectra(executionRequestsSchema) + .deposits(List.of()) + .withdrawals(List.of()) + .consolidations(List.of()) + .build(); + + final List encodedRequests = codec.encode(executionRequests); + + assertThat(encodedRequests) + .containsExactly( + Bytes.of(DepositRequest.REQUEST_TYPE), + Bytes.of(WithdrawalRequest.REQUEST_TYPE), + Bytes.of(ConsolidationRequest.REQUEST_TYPE)); } @Test public void hashExecutionRequests() { // Previously known hash of the encoded execution requests final Bytes expectedHash = - Bytes.fromHexString("0x9a1d06e635eb434e1ba98b03606ef0d20e87a78811f3d4abd04175e4f39847e3"); + Bytes.fromHexString("0xc0ff01be6ca468a08f1f5fb1dc83b3d92cc782b47ee567bcf17f925e73ff9c00"); final ExecutionRequests executionRequests = new ExecutionRequestsBuilderElectra(executionRequestsSchema) .deposits(List.of(depositRequest1, depositRequest2)) @@ -119,15 +194,27 @@ public void hashExecutionRequests() { assertThat(codec.hash(executionRequests)).isEqualTo(expectedHash); } - /* - Examples taken from https://github.com/ethereum/execution-apis/blob/main/src/engine/openrpc/methods/payload.yaml + @Test + public void hashExecutionRequestsWithAllEmptyRequestLists() { + // Previously known hash of the encoded execution requests + final Bytes expectedHash = + Bytes.fromHexString("0x6036c41849da9c076ed79654d434017387a88fb833c2856b32e18218b3341c5f"); + final ExecutionRequests executionRequests = + new ExecutionRequestsBuilderElectra(executionRequestsSchema) + .deposits(List.of()) + .withdrawals(List.of()) + .consolidations(List.of()) + .build(); - Note: Removed one of the consolidation elements from the list as in Electra the max length for the list is one. - */ + // Hash will only match if elements and order are correct + assertThat(codec.hash(executionRequests)).isEqualTo(expectedHash); + } + // Examples taken from + // https://github.com/ethereum/execution-apis/blob/main/src/engine/openrpc/methods/payload.yaml private final Bytes depositRequestListEncoded = Bytes.fromHexString( - "0x0096a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20100000000000000b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9f000000000000000a5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca01000000000000009561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1f100000000000000"); + "0x96a96086cff07df17668f35f7418ef8798079167e3f4f9b72ecde17b28226137cf454ab1dd20ef5d924786ab3483c2f9003f5102dabe0a27b1746098d1dc17a5d3fbd478759fea9287e4e419b3c3cef20100000000000000b1acdb2c4d3df3f1b8d3bfd33421660df358d84d78d16c4603551935f4b67643373e7eb63dcb16ec359be0ec41fee33b03a16e80745f2374ff1d3c352508ac5d857c6476d3c3bcf7e6ca37427c9209f17be3af5264c0e2132b3dd1156c28b4e9f000000000000000a5c85a60ba2905c215f6a12872e62b1ee037051364244043a5f639aa81b04a204c55e7cc851f29c7c183be253ea1510b001db70c485b6264692f26b8aeaab5b0c384180df8e2184a21a808a3ec8e86ca01000000000000009561731785b48cf1886412234531e4940064584463e96ac63a1a154320227e333fb51addc4a89b7e0d3f862d7c1fd4ea03bd8eb3d8806f1e7daf591cbbbb92b0beb74d13c01617f22c5026b4f9f9f294a8a7c32db895de3b01bee0132c9209e1f100000000000000"); private final DepositRequest depositRequest1 = new DepositRequest( @@ -159,7 +246,7 @@ public void hashExecutionRequests() { private final Bytes withdrawalRequestsListEncoded = Bytes.fromHexString( - "0x01a94f5374fce5edbc8e2a8697c15331677e6ebf0b85103a5617937691dfeeb89b86a80d5dc9e3c9d3a1a0e7ce311e26e0bb732eabaa47ffa288f0d54de28209a62a7d29d0000000000000000000000000000000000000000000000000000010f698daeed734da114470da559bd4b4c7259e1f7952555241dcbc90cf194a2ef676fc6005f3672fada2a3645edb297a75530100000000000000"); + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b85103a5617937691dfeeb89b86a80d5dc9e3c9d3a1a0e7ce311e26e0bb732eabaa47ffa288f0d54de28209a62a7d29d0000000000000000000000000000000000000000000000000000010f698daeed734da114470da559bd4b4c7259e1f7952555241dcbc90cf194a2ef676fc6005f3672fada2a3645edb297a75530100000000000000"); private final WithdrawalRequest withdrawalRequest1 = new WithdrawalRequest( @@ -181,7 +268,7 @@ public void hashExecutionRequests() { private final Bytes consolidationRequestsListEncoded = Bytes.fromHexString( - "0x02a94f5374fce5edbc8e2a8697c15331677e6ebf0b85103a5617937691dfeeb89b86a80d5dc9e3c9d3a1a0e7ce311e26e0bb732eabaa47ffa288f0d54de28209a62a7d29d098daeed734da114470da559bd4b4c7259e1f7952555241dcbc90cf194a2ef676fc6005f3672fada2a3645edb297a7553"); + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b85103a5617937691dfeeb89b86a80d5dc9e3c9d3a1a0e7ce311e26e0bb732eabaa47ffa288f0d54de28209a62a7d29d098daeed734da114470da559bd4b4c7259e1f7952555241dcbc90cf194a2ef676fc6005f3672fada2a3645edb297a7553"); private final ConsolidationRequest consolidationRequest1 = new ConsolidationRequest( From 68567dc90bcbb66d106c52b6932dfde157001b4e Mon Sep 17 00:00:00 2001 From: Lucas Saldanha Date: Tue, 8 Oct 2024 20:23:24 +1300 Subject: [PATCH 4/4] PR comments --- .../electra/ExecutionRequestsDataCodec.java | 17 +++++++++-------- .../electra/ExecutionRequestsDataCodecTest.java | 12 ++++++------ 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java index 652b7416a07..a31930f38c7 100644 --- a/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java +++ b/ethereum/spec/src/main/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodec.java @@ -27,6 +27,10 @@ public class ExecutionRequestsDataCodec { private static final int EXPECTED_REQUEST_DATA_ELEMENTS = 3; + private static final Bytes DEPOSIT_REQUEST_PREFIX = Bytes.of(DepositRequest.REQUEST_TYPE); + private static final Bytes WITHDRAWAL_REQUEST_PREFIX = Bytes.of(WithdrawalRequest.REQUEST_TYPE); + private static final Bytes CONSOLIDATION_REQUEST_PREFIX = + Bytes.of(ConsolidationRequest.REQUEST_TYPE); private final ExecutionRequestsSchema executionRequestsSchema; @@ -75,7 +79,7 @@ public ExecutionRequests decode(final List executionRequestData) { } @VisibleForTesting - List encode(final ExecutionRequests executionRequests) { + List encodeWithTypePrefix(final ExecutionRequests executionRequests) { final SszList depositRequestsSszList = executionRequestsSchema .getDepositRequestsSchema() @@ -90,18 +94,15 @@ List encode(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( - Bytes.of(DepositRequest.REQUEST_TYPE), depositRequestsSszList.sszSerialize()), - Bytes.concatenate( - Bytes.of(WithdrawalRequest.REQUEST_TYPE), withdrawalRequestsSszList.sszSerialize()), - Bytes.concatenate( - Bytes.of(ConsolidationRequest.REQUEST_TYPE), - consolidationRequestsSszList.sszSerialize())); + CONSOLIDATION_REQUEST_PREFIX, consolidationRequestsSszList.sszSerialize())); } public Bytes32 hash(final ExecutionRequests executionRequests) { final Bytes sortedEncodedRequests = - encode(executionRequests).stream() + encodeWithTypePrefix(executionRequests).stream() .map(Hash::sha256) .map(Bytes.class::cast) .reduce(Bytes.EMPTY, Bytes::concatenate); diff --git a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java index e6752871dfd..520565983b2 100644 --- a/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java +++ b/ethereum/spec/src/test/java/tech/pegasys/teku/spec/datastructures/execution/versions/electra/ExecutionRequestsDataCodecTest.java @@ -122,7 +122,7 @@ public void decodeExecutionRequestDataWithZeroElements() { } @Test - public void encodeExecutionRequests() { + public void encodeWithTypePrefixExecutionRequests() { final ExecutionRequests executionRequests = new ExecutionRequestsBuilderElectra(executionRequestsSchema) .deposits(List.of(depositRequest1, depositRequest2)) @@ -130,7 +130,7 @@ public void encodeExecutionRequests() { .consolidations(List.of(consolidationRequest1)) .build(); - final List encodedRequests = codec.encode(executionRequests); + final List encodedRequests = codec.encodeWithTypePrefix(executionRequests); assertThat(encodedRequests) .containsExactly( @@ -142,7 +142,7 @@ public void encodeExecutionRequests() { } @Test - public void encodeExecutionRequestsWithOneEmptyRequestList() { + public void encodeWithTypePrefixExecutionRequestsWithOneEmptyRequestList() { final ExecutionRequests executionRequests = new ExecutionRequestsBuilderElectra(executionRequestsSchema) .deposits(List.of(depositRequest1, depositRequest2)) @@ -150,7 +150,7 @@ public void encodeExecutionRequestsWithOneEmptyRequestList() { .consolidations(List.of(consolidationRequest1)) .build(); - final List encodedRequests = codec.encode(executionRequests); + final List encodedRequests = codec.encodeWithTypePrefix(executionRequests); assertThat(encodedRequests) .containsExactly( @@ -161,7 +161,7 @@ public void encodeExecutionRequestsWithOneEmptyRequestList() { } @Test - public void encodeExecutionRequestsWithAllEmptyRequestLists() { + public void encodeWithTypePrefixExecutionRequestsWithAllEmptyRequestLists() { final ExecutionRequests executionRequests = new ExecutionRequestsBuilderElectra(executionRequestsSchema) .deposits(List.of()) @@ -169,7 +169,7 @@ public void encodeExecutionRequestsWithAllEmptyRequestLists() { .consolidations(List.of()) .build(); - final List encodedRequests = codec.encode(executionRequests); + final List encodedRequests = codec.encodeWithTypePrefix(executionRequests); assertThat(encodedRequests) .containsExactly(