diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommand.java index 51542a361b..6e7e09f58a 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/TxParseSubCommand.java @@ -19,7 +19,6 @@ import static org.hyperledger.besu.cli.subcommands.TxParseSubCommand.COMMAND_NAM import org.hyperledger.besu.cli.util.VersionProvider; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import java.io.BufferedReader; @@ -105,7 +104,7 @@ public class TxParseSubCommand implements Runnable { void dump(final Bytes tx) { try { - var transaction = TransactionDecoder.decodeOpaqueBytes(tx, EncodingContext.BLOCK_BODY); + var transaction = TransactionDecoder.decodeOpaqueBytes(tx); // https://github.com/hyperledger/besu/blob/5fe49c60b30fe2954c7967e8475c3b3e9afecf35/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/MainnetTransactionValidator.java#L252 if (transaction.getChainId().isPresent() && !transaction.getChainId().get().equals(chainId)) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java index 8562e140f5..cae7c96936 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/AbstractEngineNewPayload.java @@ -51,7 +51,6 @@ import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Withdrawal; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.eth.manager.EthPeers; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; @@ -221,7 +220,7 @@ public abstract class AbstractEngineNewPayload extends ExecutionEngineJsonRpcMet transactions = blockParam.getTransactions().stream() .map(Bytes::fromHexString) - .map(in -> TransactionDecoder.decodeOpaqueBytes(in, EncodingContext.BLOCK_BODY)) + .map(TransactionDecoder::decodeOpaqueBytes) .collect(Collectors.toList()); transactions.forEach( transaction -> diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java index 66bb879569..434d79f445 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/BlockResultFactory.java @@ -23,7 +23,6 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Request; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import java.util.ArrayList; @@ -97,8 +96,7 @@ public class BlockResultFactory { final List txs = block.getBody().getTransactions().stream() .map( - transaction -> - TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) + TransactionEncoder::encodeOpaqueBytes) .map(Bytes::toHexString) .collect(Collectors.toList()); @@ -110,8 +108,7 @@ public class BlockResultFactory { final List txs = blockWithReceipts.getBlock().getBody().getTransactions().stream() .map( - transaction -> - TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) + TransactionEncoder::encodeOpaqueBytes) .map(Bytes::toHexString) .collect(Collectors.toList()); @@ -136,8 +133,7 @@ public class BlockResultFactory { final List txs = blockWithReceipts.getBlock().getBody().getTransactions().stream() .map( - transaction -> - TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) + TransactionEncoder::encodeOpaqueBytes) .map(Bytes::toHexString) .collect(Collectors.toList()); @@ -156,8 +152,7 @@ public class BlockResultFactory { final List txs = blockWithReceipts.getBlock().getBody().getTransactions().stream() .map( - transaction -> - TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) + TransactionEncoder::encodeOpaqueBytes) .map(Bytes::toHexString) .collect(Collectors.toList()); final Optional> requestsWithoutRequestId = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java index 8e2afcd918..651ddfabdf 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/EngineGetPayloadBodiesResultV1.java @@ -16,7 +16,6 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.WithdrawalParameter; import org.hyperledger.besu.ethereum.core.BlockBody; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import java.util.Collections; @@ -54,8 +53,7 @@ public class EngineGetPayloadBodiesResultV1 { this.transactions = blockBody.getTransactions().stream() .map( - transaction -> - TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY)) + TransactionEncoder::encodeOpaqueBytes) .map(Bytes::toHexString) .collect(Collectors.toList()); this.withdrawals = diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java index 2cbf5dd225..9f988822cf 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/TransactionPendingResult.java @@ -20,8 +20,7 @@ import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.VersionedHash; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; -import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionEncoder; import java.util.List; @@ -103,7 +102,7 @@ public class TransactionPendingResult implements TransactionResult { this.nonce = Quantity.create(transaction.getNonce()); this.publicKey = transaction.getPublicKey().orElse(null); this.raw = - TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.POOLED_TRANSACTION) + PooledTransactionEncoder.encodeOpaqueBytes(transaction) .toString(); this.to = transaction.getTo().map(Address::toHexString).orElse(null); if (transactionType == TransactionType.FRONTIER) { diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java index bf9d49d4e9..7c2a5a9aef 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtils.java @@ -17,8 +17,7 @@ package org.hyperledger.besu.ethereum.api.util; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; -import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionDecoder; import org.hyperledger.besu.ethereum.rlp.RLPException; import org.apache.tuweni.bytes.Bytes; @@ -29,7 +28,7 @@ public class DomainObjectDecodeUtils { throws InvalidJsonRpcRequestException { try { Bytes txnBytes = Bytes.fromHexString(rawTransaction); - return TransactionDecoder.decodeOpaqueBytes(txnBytes, EncodingContext.POOLED_TRANSACTION); + return PooledTransactionDecoder.decodeOpaqueBytes(txnBytes); } catch (final IllegalArgumentException e) { throw new InvalidJsonRpcRequestException( "Invalid raw transaction hex", RpcErrorType.INVALID_TRANSACTION_PARAMS, e); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java index 1810ce9450..e34bb2b299 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/engine/EngineNewPayloadV3Test.java @@ -48,8 +48,7 @@ import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.Withdrawal; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; -import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionEncoder; import org.hyperledger.besu.ethereum.mainnet.BodyValidation; import org.hyperledger.besu.ethereum.mainnet.CancunTargetingGasLimitCalculator; import org.hyperledger.besu.ethereum.mainnet.ValidationResult; @@ -226,8 +225,8 @@ public class EngineNewPayloadV3Test extends EngineNewPayloadV2Test { public void shouldRejectTransactionsWithFullBlobs() { Bytes transactionWithBlobsBytes = - TransactionEncoder.encodeOpaqueBytes( - createTransactionWithBlobs(), EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeOpaqueBytes( + createTransactionWithBlobs()); List transactions = List.of(transactionWithBlobsBytes.toString()); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java index af48e26823..fd74b715af 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/util/DomainObjectDecodeUtilsTest.java @@ -21,8 +21,7 @@ import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; -import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionEncoder; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import java.math.BigInteger; @@ -58,7 +57,7 @@ public class DomainObjectDecodeUtilsTest { @Test public void testAccessListRLPSerDes() { final BytesValueRLPOutput encoded = new BytesValueRLPOutput(); - TransactionEncoder.encodeRLP(accessListTxn, encoded, EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeRLP(accessListTxn, encoded); Transaction decoded = DomainObjectDecodeUtils.decodeRawTransaction(encoded.encoded().toHexString()); Assertions.assertThat(decoded.getAccessList().isPresent()).isTrue(); @@ -68,7 +67,7 @@ public class DomainObjectDecodeUtilsTest { @Test public void testAccessList2718OpaqueSerDes() { final Bytes encoded = - TransactionEncoder.encodeOpaqueBytes(accessListTxn, EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeOpaqueBytes(accessListTxn); Transaction decoded = DomainObjectDecodeUtils.decodeRawTransaction(encoded.toString()); Assertions.assertThat(decoded.getAccessList().isPresent()).isTrue(); Assertions.assertThat(decoded.getAccessList().map(List::size).get()).isEqualTo(1); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java index 0da8f8f28a..6eeefad333 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/Transaction.java @@ -39,7 +39,7 @@ import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.BlobTransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.CodeDelegationEncoder; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; @@ -135,7 +135,7 @@ public class Transaction } public static Transaction readFrom(final RLPInput rlpInput) { - return TransactionDecoder.decodeRLP(rlpInput, EncodingContext.BLOCK_BODY); + return TransactionDecoder.decodeRLP(rlpInput); } /** @@ -485,7 +485,7 @@ public class Transaction * @param out the output to write the transaction to */ public void writeTo(final RLPOutput out) { - TransactionEncoder.encodeRLP(this, out, EncodingContext.BLOCK_BODY); + TransactionEncoder.encodeRLP(this, out); } @Override @@ -556,11 +556,11 @@ public class Transaction } private void memoizeHashAndSize() { - final Bytes bytes = TransactionEncoder.encodeOpaqueBytes(this, EncodingContext.BLOCK_BODY); + final Bytes bytes = TransactionEncoder.encodeOpaqueBytes(this); hash = Hash.hash(bytes); if (transactionType.supportsBlob() && getBlobsWithCommitments().isPresent()) { final Bytes pooledBytes = - TransactionEncoder.encodeOpaqueBytes(this, EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeOpaqueBytes(this); size = pooledBytes.size(); return; } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EncodingContext.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EncodingContext.java deleted file mode 100644 index 96104d6e2a..0000000000 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/EncodingContext.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright contributors to Hyperledger Besu. - * - * 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. - * - * SPDX-License-Identifier: Apache-2.0 - */ -package org.hyperledger.besu.ethereum.core.encoding; - -/** - * Enum representing the context in which a transaction is being encoded. This context is used to - * determine the appropriate encoding strategy for a transaction. - * - *

The context can be one of the following: - * - *

    - *
  • {@link #BLOCK_BODY}: The transaction is part of a block body. This context is used when - * encoding transactions for inclusion in a block. - *
  • {@link #POOLED_TRANSACTION}: The transaction is part of a transaction pool. This context is - * used when encoding transactions that are currently in the transaction pool, waiting to be - * included in a block. It is also used when encoding transactions for RPC calls related to - * the transaction pool. - *
- */ -public enum EncodingContext { - /** Represents the context where the transaction is part of a block body. */ - BLOCK_BODY, - - /** - * Represents the context where the transaction is part of a transaction pool. This context is - * also used when encoding transactions for RPC calls related to the transaction pool. - */ - POOLED_TRANSACTION, -} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/PooledTransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/PooledTransactionDecoder.java new file mode 100644 index 0000000000..40b65fd552 --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/PooledTransactionDecoder.java @@ -0,0 +1,36 @@ +package org.hyperledger.besu.ethereum.core.encoding; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; +import org.hyperledger.besu.datatypes.TransactionType; + +public class PooledTransactionDecoder extends TransactionDecoder{ + + private static final ImmutableMap POOLED_TRANSACTION_DECODERS = + ImmutableMap.of( + TransactionType.ACCESS_LIST, + AccessListTransactionDecoder::decode, + TransactionType.EIP1559, + EIP1559TransactionDecoder::decode, + TransactionType.BLOB, + BlobPooledTransactionDecoder::decode , + TransactionType.DELEGATE_CODE, + CodeDelegationTransactionDecoder::decode); + + /** + * Gets the decoder for a given transaction type + * + * @param transactionType the transaction type + * @return the decoder + */ +@VisibleForTesting + protected static TransactionDecoder.Decoder getDecoder( + final TransactionType transactionType) { + return checkNotNull( + POOLED_TRANSACTION_DECODERS.get(transactionType), + "Developer Error. A supported transaction type %s has no associated decoding logic", + transactionType); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/PooledTransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/PooledTransactionEncoder.java new file mode 100644 index 0000000000..cfe52c2d0e --- /dev/null +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/PooledTransactionEncoder.java @@ -0,0 +1,49 @@ +/* + * Copyright ConsenSys AG. + * + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.core.encoding; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; +import org.apache.tuweni.bytes.Bytes; +import org.hyperledger.besu.datatypes.TransactionType; +import org.hyperledger.besu.ethereum.core.Transaction; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; +import org.hyperledger.besu.ethereum.rlp.RLP; +import org.hyperledger.besu.ethereum.rlp.RLPOutput; + +public class PooledTransactionEncoder extends TransactionEncoder { + + private static final ImmutableMap POOLED_TRANSACTION_ENCODERS = + ImmutableMap.of( + TransactionType.ACCESS_LIST, + AccessListTransactionEncoder::encode, + TransactionType.EIP1559, + EIP1559TransactionEncoder::encode, + TransactionType.BLOB, + BlobPooledTransactionEncoder::encode, + TransactionType.DELEGATE_CODE, + CodeDelegationEncoder::encode); + + @VisibleForTesting + protected static Encoder getEncoder( + final TransactionType transactionType) { + return checkNotNull( + POOLED_TRANSACTION_ENCODERS.get(transactionType), + "Developer Error. A supported transaction type %s has no associated encoding logic", + transactionType); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java index 7261aecbea..afaebcef43 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionDecoder.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.core.encoding; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.annotations.VisibleForTesting; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -29,7 +30,7 @@ import org.apache.tuweni.bytes.Bytes; public class TransactionDecoder { @FunctionalInterface - interface Decoder { + protected interface Decoder { Transaction decode(RLPInput input); } @@ -44,9 +45,6 @@ public class TransactionDecoder { TransactionType.DELEGATE_CODE, CodeDelegationTransactionDecoder::decode); - private static final ImmutableMap POOLED_TRANSACTION_DECODERS = - ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionDecoder::decode); - /** * Decodes an RLP input into a transaction. If the input represents a typed transaction, it uses * the appropriate decoder for that type. Otherwise, it uses the frontier decoder. @@ -55,9 +53,9 @@ public class TransactionDecoder { * @return the decoded transaction */ public static Transaction decodeRLP( - final RLPInput rlpInput, final EncodingContext encodingContext) { + final RLPInput rlpInput) { if (isTypedTransaction(rlpInput)) { - return decodeTypedTransaction(rlpInput, encodingContext); + return decodeTypedTransaction(rlpInput); } else { return FrontierTransactionDecoder.decode(rlpInput); } @@ -71,7 +69,7 @@ public class TransactionDecoder { * @return the decoded transaction */ private static Transaction decodeTypedTransaction( - final RLPInput rlpInput, final EncodingContext context) { + final RLPInput rlpInput) { // Read the typed transaction bytes from the RLP input final Bytes typedTransactionBytes = rlpInput.readBytes(); @@ -79,7 +77,7 @@ public class TransactionDecoder { TransactionType transactionType = getTransactionType(typedTransactionBytes) .orElseThrow((() -> new IllegalArgumentException("Unsupported transaction type"))); - return decodeTypedTransaction(typedTransactionBytes, transactionType, context); + return decodeTypedTransaction(typedTransactionBytes, transactionType); } /** @@ -89,17 +87,15 @@ public class TransactionDecoder { * * @param transactionBytes the transaction bytes * @param transactionType the type of the transaction - * @param context the encoding context * @return the decoded transaction */ private static Transaction decodeTypedTransaction( final Bytes transactionBytes, - final TransactionType transactionType, - final EncodingContext context) { + final TransactionType transactionType) { // Slice the transaction bytes to exclude the transaction type and prepare for decoding final RLPInput transactionInput = RLP.input(transactionBytes.slice(1)); // Use the appropriate decoder for the transaction type to decode the remaining bytes - return getDecoder(transactionType, context).decode(transactionInput); + return getDecoder(transactionType).decode(transactionInput); } /** @@ -108,17 +104,16 @@ public class TransactionDecoder { * for that type. If the type is not present, it decodes the bytes as an RLP input. * * @param opaqueBytes the opaque bytes - * @param context the encoding context * @return the decoded transaction */ public static Transaction decodeOpaqueBytes( - final Bytes opaqueBytes, final EncodingContext context) { + final Bytes opaqueBytes) { var transactionType = getTransactionType(opaqueBytes); if (transactionType.isPresent()) { - return decodeTypedTransaction(opaqueBytes, transactionType.get(), context); + return decodeTypedTransaction(opaqueBytes, transactionType.get()); } else { // If the transaction type is not present, decode the opaque bytes as RLP - return decodeRLP(RLP.input(opaqueBytes), context); + return decodeRLP(RLP.input(opaqueBytes)); } } @@ -157,21 +152,14 @@ public class TransactionDecoder { } /** - * Gets the decoder for a given transaction type and encoding context. If the context is - * POOLED_TRANSACTION, it uses the network decoder for the type. Otherwise, it uses the typed - * decoder. + * Gets the decoder for a given transaction type * * @param transactionType the transaction type - * @param encodingContext the encoding context * @return the decoder */ - private static Decoder getDecoder( - final TransactionType transactionType, final EncodingContext encodingContext) { - if (encodingContext.equals(EncodingContext.POOLED_TRANSACTION)) { - if (POOLED_TRANSACTION_DECODERS.containsKey(transactionType)) { - return POOLED_TRANSACTION_DECODERS.get(transactionType); - } - } + @VisibleForTesting + protected static Decoder getDecoder( + final TransactionType transactionType) { return checkNotNull( TYPED_TRANSACTION_DECODERS.get(transactionType), "Developer Error. A supported transaction type %s has no associated decoding logic", diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java index 26bad56c6d..7c51f50f50 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/encoding/TransactionEncoder.java @@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.core.encoding; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.common.annotations.VisibleForTesting; import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; @@ -28,7 +29,7 @@ import org.apache.tuweni.bytes.Bytes; public class TransactionEncoder { @FunctionalInterface - interface Encoder { + protected interface Encoder { void encode(Transaction transaction, RLPOutput output); } @@ -43,22 +44,17 @@ public class TransactionEncoder { TransactionType.DELEGATE_CODE, CodeDelegationEncoder::encode); - private static final ImmutableMap POOLED_TRANSACTION_ENCODERS = - ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode); - /** * Encodes a transaction into RLP format. * * @param transaction the transaction to encode * @param rlpOutput the RLP output stream - * @param encodingContext the encoding context */ public static void encodeRLP( final Transaction transaction, - final RLPOutput rlpOutput, - final EncodingContext encodingContext) { + final RLPOutput rlpOutput) { final TransactionType transactionType = getTransactionType(transaction); - Bytes opaqueBytes = encodeOpaqueBytes(transaction, encodingContext); + Bytes opaqueBytes = encodeOpaqueBytes(transaction); encodeRLP(transactionType, opaqueBytes, rlpOutput); } @@ -83,16 +79,15 @@ public class TransactionEncoder { * Encodes a transaction into opaque bytes. * * @param transaction the transaction to encode - * @param encodingContext the encoding context * @return the encoded transaction as bytes */ public static Bytes encodeOpaqueBytes( - final Transaction transaction, final EncodingContext encodingContext) { + final Transaction transaction) { final TransactionType transactionType = getTransactionType(transaction); if (TransactionType.FRONTIER.equals(transactionType)) { return RLP.encode(rlpOutput -> FrontierTransactionEncoder.encode(transaction, rlpOutput)); } else { - final Encoder encoder = getEncoder(transactionType, encodingContext); + final Encoder encoder = getEncoder(transactionType); final BytesValueRLPOutput out = new BytesValueRLPOutput(); out.writeByte(transaction.getType().getSerializedType()); encoder.encode(transaction, out); @@ -120,14 +115,9 @@ public class TransactionEncoder { transaction.getType(), "Transaction type for %s was not specified.", transaction); } - private static Encoder getEncoder( - final TransactionType transactionType, final EncodingContext encodingContext) { - - if (encodingContext.equals(EncodingContext.POOLED_TRANSACTION)) { - if (POOLED_TRANSACTION_ENCODERS.containsKey(transactionType)) { - return POOLED_TRANSACTION_ENCODERS.get(transactionType); - } - } + @VisibleForTesting + protected static Encoder getEncoder( + final TransactionType transactionType) { return checkNotNull( TYPED_TRANSACTION_ENCODERS.get(transactionType), "Developer Error. A supported transaction type %s has no associated encoding logic", diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java index f9835c2de5..40ba0de458 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/BodyValidation.java @@ -23,7 +23,6 @@ import org.hyperledger.besu.ethereum.core.Request; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.Withdrawal; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; import org.hyperledger.besu.ethereum.core.encoding.WithdrawalEncoder; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -68,7 +67,7 @@ public final class BodyValidation { trie.put( indexKey(i), TransactionEncoder.encodeOpaqueBytes( - transactions.get(i), EncodingContext.BLOCK_BODY))); + transactions.get(i)))); return Hash.wrap(trie.getRootHash()); } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java index e53c1b50e0..fed0ddfdc7 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/BlobTransactionEncodingTest.java @@ -58,14 +58,14 @@ public class BlobTransactionEncodingTest { Bytes bytes = argument.bytes; // Decode the transaction from the wire using the TransactionDecoder. final Transaction transaction = - TransactionDecoder.decodeOpaqueBytes(bytes, EncodingContext.POOLED_TRANSACTION); + PooledTransactionDecoder.decodeOpaqueBytes(bytes); final BytesValueRLPOutput output = new BytesValueRLPOutput(); TransactionEncoder.encodeRLP(transaction.getType(), bytes, output); final BytesValueRLPOutput bytesValueRLPOutput = new BytesValueRLPOutput(); - TransactionEncoder.encodeRLP( - transaction, bytesValueRLPOutput, EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeRLP( + transaction, bytesValueRLPOutput); assertThat(transaction.getSize()).isEqualTo(bytes.size()); } @@ -75,10 +75,10 @@ public class BlobTransactionEncodingTest { Bytes bytes = argument.bytes; // Decode the transaction from the wire using the TransactionDecoder. final Transaction transaction = - TransactionDecoder.decodeOpaqueBytes(bytes, EncodingContext.BLOCK_BODY); + TransactionDecoder.decodeOpaqueBytes(bytes); // Encode the transaction for wire using the TransactionEncoder. - Bytes encoded = TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.BLOCK_BODY); + Bytes encoded = TransactionEncoder.encodeOpaqueBytes(transaction); // Assert that the encoded transaction matches the original bytes. assertThat(encoded.toHexString()).isEqualTo(bytes.toHexString()); diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java index 19f3e5bf7a..182ea3111c 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPDecoderTest.java @@ -15,10 +15,12 @@ package org.hyperledger.besu.ethereum.core.encoding; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.hyperledger.besu.evm.account.Account.MAX_NONCE; import static org.junit.jupiter.api.Assumptions.assumeTrue; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.rlp.RLP; @@ -28,6 +30,7 @@ import org.hyperledger.besu.ethereum.rlp.RLPInput; import java.math.BigInteger; import java.util.Arrays; import java.util.Collection; +import java.util.stream.Stream; import org.apache.tuweni.bytes.Bytes; import org.junit.jupiter.api.Test; @@ -67,7 +70,7 @@ class TransactionRLPDecoderTest { assertThatThrownBy( () -> TransactionDecoder.decodeOpaqueBytes( - Bytes.fromHexString(txWithBigFees), EncodingContext.BLOCK_BODY)) + Bytes.fromHexString(txWithBigFees))) .isInstanceOf(RLPException.class); } @@ -113,7 +116,7 @@ class TransactionRLPDecoderTest { // Decode bytes into a transaction final Transaction transaction = decodeRLP(RLP.input(bytes)); Bytes transactionBytes = - TransactionEncoder.encodeOpaqueBytes(transaction, EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeOpaqueBytes(transaction); // Bytes size should be equal to transaction size assertThat(transaction.getSize()).isEqualTo(transactionBytes.size()); } @@ -140,7 +143,17 @@ class TransactionRLPDecoderTest { } } + @Test + void shouldHaveDecodersForAllTransactionTypes(){ + Stream.of(TransactionType.values()) + .filter(v -> v != TransactionType.FRONTIER).forEach( v -> { + assertThatNoException().isThrownBy(() -> TransactionDecoder.getDecoder(v)); + assertThatNoException().isThrownBy(() -> PooledTransactionDecoder.getDecoder(v)); + } + ); + } + private Transaction decodeRLP(final RLPInput input) { - return TransactionDecoder.decodeRLP(input, EncodingContext.POOLED_TRANSACTION); + return PooledTransactionDecoder.decodeRLP(input); } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java index fa84bc5ef7..59fa476a28 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/encoding/TransactionRLPEncoderTest.java @@ -15,7 +15,10 @@ package org.hyperledger.besu.ethereum.core.encoding; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatNoException; +import java.util.stream.Stream; +import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Transaction; @@ -75,11 +78,21 @@ class TransactionRLPEncoderTest { assertThat(output.encoded().toHexString()).isEqualTo(NONCE_64_BIT_MAX_MINUS_2_TX_RLP); } + @Test + void shouldHaveEncodersForAllTransactionTypes(){ + Stream.of(TransactionType.values()) + .filter(v -> v != TransactionType.FRONTIER).forEach( v -> { + assertThatNoException().isThrownBy(() -> TransactionEncoder.getEncoder(v)); + assertThatNoException().isThrownBy(() -> PooledTransactionEncoder.getEncoder(v)); + } + ); + } + private Transaction decodeRLP(final RLPInput input) { - return TransactionDecoder.decodeRLP(input, EncodingContext.BLOCK_BODY); + return TransactionDecoder.decodeRLP(input); } private void encodeRLP(final Transaction transaction, final BytesValueRLPOutput output) { - TransactionEncoder.encodeRLP(transaction, output, EncodingContext.BLOCK_BODY); + TransactionEncoder.encodeRLP(transaction, output); } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java index d70623d7bf..1cd8c371db 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/manager/EthServer.java @@ -20,8 +20,7 @@ import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; -import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionEncoder; import org.hyperledger.besu.ethereum.eth.EthProtocolConfiguration; import org.hyperledger.besu.ethereum.eth.messages.BlockBodiesMessage; import org.hyperledger.besu.ethereum.eth.messages.BlockHeadersMessage; @@ -273,7 +272,7 @@ class EthServer { } final BytesValueRLPOutput txRlp = new BytesValueRLPOutput(); - TransactionEncoder.encodeRLP(maybeTx.get(), txRlp, EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeRLP(maybeTx.get(), txRlp); final int encodedSize = txRlp.encodedSize(); if (responseSizeEstimate + encodedSize > maxMessageSize) { break; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java index 8218210164..6290841e93 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/messages/PooledTransactionsMessage.java @@ -15,9 +15,8 @@ package org.hyperledger.besu.ethereum.eth.messages; import org.hyperledger.besu.ethereum.core.Transaction; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; -import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; -import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionDecoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionEncoder; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.AbstractMessageData; import org.hyperledger.besu.ethereum.p2p.rlpx.wire.MessageData; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; @@ -45,9 +44,7 @@ public final class PooledTransactionsMessage extends AbstractMessageData { final BytesValueRLPOutput out = new BytesValueRLPOutput(); out.writeList( transactions, - (transaction, rlpOutput) -> { - TransactionEncoder.encodeRLP(transaction, rlpOutput, EncodingContext.POOLED_TRANSACTION); - }); + PooledTransactionEncoder::encodeRLP); return new PooledTransactionsMessage(out.encoded()); } @@ -80,7 +77,7 @@ public final class PooledTransactionsMessage extends AbstractMessageData { final BytesValueRLPInput in = new BytesValueRLPInput(getData(), false); pooledTransactions = in.readList( - input -> TransactionDecoder.decodeRLP(input, EncodingContext.POOLED_TRANSACTION)); + PooledTransactionDecoder::decodeRLP); } return pooledTransactions; } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java index af54f668fe..af606981ea 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/transactions/PendingTransactionEstimatedMemorySizeTest.java @@ -24,9 +24,8 @@ import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionTestFixture; -import org.hyperledger.besu.ethereum.core.encoding.EncodingContext; -import org.hyperledger.besu.ethereum.core.encoding.TransactionDecoder; -import org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionDecoder; +import org.hyperledger.besu.ethereum.core.encoding.PooledTransactionEncoder; import org.hyperledger.besu.ethereum.eth.transactions.layered.BaseTransactionPoolTest; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; @@ -210,11 +209,11 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo prepareTransaction(TransactionType.BLOB, 10, Wei.of(500), Wei.of(50), 10, 1); Transaction txBlob = preparedTx.createTransaction(KEYS1); BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); - TransactionEncoder.encodeRLP(txBlob, rlpOut, EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeRLP(txBlob, rlpOut); txBlob = - TransactionDecoder.decodeRLP( - new BytesValueRLPInput(rlpOut.encoded(), false), EncodingContext.POOLED_TRANSACTION) + PooledTransactionDecoder.decodeRLP( + new BytesValueRLPInput(rlpOut.encoded(), false)) .detachedCopy(); System.out.println(txBlob.getSender()); System.out.println(txBlob.getHash()); @@ -242,11 +241,11 @@ public class PendingTransactionEstimatedMemorySizeTest extends BaseTransactionPo prepareTransaction(TransactionType.BLOB, 10, Wei.of(500), Wei.of(50), 10, 1); Transaction txBlob = preparedTx.createTransaction(KEYS1); BytesValueRLPOutput rlpOut = new BytesValueRLPOutput(); - TransactionEncoder.encodeRLP(txBlob, rlpOut, EncodingContext.POOLED_TRANSACTION); + PooledTransactionEncoder.encodeRLP(txBlob, rlpOut); txBlob = - TransactionDecoder.decodeRLP( - new BytesValueRLPInput(rlpOut.encoded(), false), EncodingContext.POOLED_TRANSACTION) + PooledTransactionDecoder.decodeRLP( + new BytesValueRLPInput(rlpOut.encoded(), false)) .detachedCopy(); System.out.println(txBlob.getSender()); System.out.println(txBlob.getHash());