mirror of https://github.com/hyperledger/besu
[4844] Add encodingContext to TransactionEncoder and TransactionDecoder (#5820)
* Add decode type to TransactionDecoder * Refactoring TransactionDecoder * Invert methods order * Use Transaction encoder instead of writeTo * Move enter and leave list to inner method as pr suggestion * Size calculation should use opaque bytes instead of rlp --------- Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net> Co-authored-by: Sally MacFarlane <macfarla.github@gmail.com>pull/5875/head
parent
40273d7d3f
commit
1fa21e2f1a
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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 org.hyperledger.besu.crypto.SignatureAlgorithm; |
||||||
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; |
||||||
|
import org.hyperledger.besu.datatypes.AccessListEntry; |
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
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.RLPInput; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
import java.util.function.Supplier; |
||||||
|
|
||||||
|
import com.google.common.base.Suppliers; |
||||||
|
|
||||||
|
class AccessListTransactionDecoder { |
||||||
|
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM = |
||||||
|
Suppliers.memoize(SignatureAlgorithmFactory::getInstance); |
||||||
|
|
||||||
|
public static Transaction decode(final RLPInput rlpInput) { |
||||||
|
rlpInput.enterList(); |
||||||
|
final Transaction.Builder preSignatureTransactionBuilder = |
||||||
|
Transaction.builder() |
||||||
|
.type(TransactionType.ACCESS_LIST) |
||||||
|
.chainId(BigInteger.valueOf(rlpInput.readLongScalar())) |
||||||
|
.nonce(rlpInput.readLongScalar()) |
||||||
|
.gasPrice(Wei.of(rlpInput.readUInt256Scalar())) |
||||||
|
.gasLimit(rlpInput.readLongScalar()) |
||||||
|
.to( |
||||||
|
rlpInput.readBytes( |
||||||
|
addressBytes -> addressBytes.size() == 0 ? null : Address.wrap(addressBytes))) |
||||||
|
.value(Wei.of(rlpInput.readUInt256Scalar())) |
||||||
|
.payload(rlpInput.readBytes()) |
||||||
|
.accessList( |
||||||
|
rlpInput.readList( |
||||||
|
accessListEntryRLPInput -> { |
||||||
|
accessListEntryRLPInput.enterList(); |
||||||
|
final AccessListEntry accessListEntry = |
||||||
|
new AccessListEntry( |
||||||
|
Address.wrap(accessListEntryRLPInput.readBytes()), |
||||||
|
accessListEntryRLPInput.readList(RLPInput::readBytes32)); |
||||||
|
accessListEntryRLPInput.leaveList(); |
||||||
|
return accessListEntry; |
||||||
|
})); |
||||||
|
final byte recId = (byte) rlpInput.readIntScalar(); |
||||||
|
final Transaction transaction = |
||||||
|
preSignatureTransactionBuilder |
||||||
|
.signature( |
||||||
|
SIGNATURE_ALGORITHM |
||||||
|
.get() |
||||||
|
.createSignature( |
||||||
|
rlpInput.readUInt256Scalar().toUnsignedBigInteger(), |
||||||
|
rlpInput.readUInt256Scalar().toUnsignedBigInteger(), |
||||||
|
recId)) |
||||||
|
.build(); |
||||||
|
rlpInput.leaveList(); |
||||||
|
return transaction; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,109 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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 org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignature; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.AccessListEntry; |
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
import org.hyperledger.besu.datatypes.Wei; |
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
|
||||||
|
public class AccessListTransactionEncoder { |
||||||
|
|
||||||
|
public static void encode(final Transaction transaction, final RLPOutput rlpOutput) { |
||||||
|
rlpOutput.startList(); |
||||||
|
encodeAccessListInner( |
||||||
|
transaction.getChainId(), |
||||||
|
transaction.getNonce(), |
||||||
|
transaction.getGasPrice().orElseThrow(), |
||||||
|
transaction.getGasLimit(), |
||||||
|
transaction.getTo(), |
||||||
|
transaction.getValue(), |
||||||
|
transaction.getPayload(), |
||||||
|
transaction |
||||||
|
.getAccessList() |
||||||
|
.orElseThrow( |
||||||
|
() -> |
||||||
|
new IllegalStateException( |
||||||
|
"Developer error: access list should be guaranteed to be present")), |
||||||
|
rlpOutput); |
||||||
|
rlpOutput.writeIntScalar(transaction.getSignature().getRecId()); |
||||||
|
writeSignature(transaction, rlpOutput); |
||||||
|
rlpOutput.endList(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void encodeAccessListInner( |
||||||
|
final Optional<BigInteger> chainId, |
||||||
|
final long nonce, |
||||||
|
final Wei gasPrice, |
||||||
|
final long gasLimit, |
||||||
|
final Optional<Address> to, |
||||||
|
final Wei value, |
||||||
|
final Bytes payload, |
||||||
|
final List<AccessListEntry> accessList, |
||||||
|
final RLPOutput rlpOutput) { |
||||||
|
rlpOutput.writeBigIntegerScalar(chainId.orElseThrow()); |
||||||
|
rlpOutput.writeLongScalar(nonce); |
||||||
|
rlpOutput.writeUInt256Scalar(gasPrice); |
||||||
|
rlpOutput.writeLongScalar(gasLimit); |
||||||
|
rlpOutput.writeBytes(to.map(Bytes::copy).orElse(Bytes.EMPTY)); |
||||||
|
rlpOutput.writeUInt256Scalar(value); |
||||||
|
rlpOutput.writeBytes(payload); |
||||||
|
/* |
||||||
|
Access List encoding should look like this |
||||||
|
where hex strings represent raw bytes |
||||||
|
[ |
||||||
|
[ |
||||||
|
"0xde0b295669a9fd93d5f28d9ec85e40f4cb697bae", |
||||||
|
[ |
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000003", |
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000007" |
||||||
|
] |
||||||
|
], |
||||||
|
[ |
||||||
|
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413", |
||||||
|
[] |
||||||
|
] |
||||||
|
] */ |
||||||
|
writeAccessList(rlpOutput, Optional.of(accessList)); |
||||||
|
} |
||||||
|
|
||||||
|
public static void writeAccessList( |
||||||
|
final RLPOutput out, final Optional<List<AccessListEntry>> accessListEntries) { |
||||||
|
if (accessListEntries.isEmpty()) { |
||||||
|
out.writeEmptyList(); |
||||||
|
} else { |
||||||
|
out.writeList( |
||||||
|
accessListEntries.get(), |
||||||
|
(accessListEntry, accessListEntryRLPOutput) -> { |
||||||
|
accessListEntryRLPOutput.startList(); |
||||||
|
out.writeBytes(accessListEntry.address()); |
||||||
|
out.writeList( |
||||||
|
accessListEntry.storageKeys(), |
||||||
|
(storageKeyBytes, storageKeyBytesRLPOutput) -> |
||||||
|
storageKeyBytesRLPOutput.writeBytes(storageKeyBytes)); |
||||||
|
accessListEntryRLPOutput.endList(); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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 org.hyperledger.besu.datatypes.Blob; |
||||||
|
import org.hyperledger.besu.datatypes.KZGCommitment; |
||||||
|
import org.hyperledger.besu.datatypes.KZGProof; |
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
import org.hyperledger.besu.ethereum.rlp.RLPInput; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Class responsible for decoding blob transactions from the transaction pool. Blob transactions |
||||||
|
* have two network representations. During transaction gossip responses (PooledTransactions), the |
||||||
|
* EIP-2718 TransactionPayload of the blob transaction is wrapped to become: rlp([tx_payload_body, |
||||||
|
* blobs, commitments, proofs]). |
||||||
|
*/ |
||||||
|
public class BlobPooledTransactionDecoder { |
||||||
|
|
||||||
|
/** |
||||||
|
* Decodes a blob transaction from the provided RLP input. |
||||||
|
* |
||||||
|
* @param input the RLP input to decode |
||||||
|
* @return the decoded transaction |
||||||
|
*/ |
||||||
|
public static Transaction decode(final RLPInput input) { |
||||||
|
input.enterList(); |
||||||
|
final Transaction.Builder builder = Transaction.builder(); |
||||||
|
BlobTransactionDecoder.readTransactionPayloadInner(builder, input); |
||||||
|
List<Blob> blobs = input.readList(Blob::readFrom); |
||||||
|
List<KZGCommitment> commitments = input.readList(KZGCommitment::readFrom); |
||||||
|
List<KZGProof> proofs = input.readList(KZGProof::readFrom); |
||||||
|
input.leaveList(); |
||||||
|
builder.kzgBlobs(commitments, blobs, proofs); |
||||||
|
return builder.build(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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 org.slf4j.LoggerFactory.getLogger; |
||||||
|
|
||||||
|
import org.hyperledger.besu.datatypes.Blob; |
||||||
|
import org.hyperledger.besu.datatypes.KZGCommitment; |
||||||
|
import org.hyperledger.besu.datatypes.KZGProof; |
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput; |
||||||
|
|
||||||
|
import java.security.InvalidParameterException; |
||||||
|
|
||||||
|
import org.slf4j.Logger; |
||||||
|
|
||||||
|
public class BlobPooledTransactionEncoder { |
||||||
|
private static final Logger LOG = getLogger(BlobPooledTransactionEncoder.class); |
||||||
|
static final String NO_BLOBS_ERROR = |
||||||
|
"Transaction with no blobsWithCommitments cannot be encoded for Pooled Transaction"; |
||||||
|
|
||||||
|
public static void encode(final Transaction transaction, final RLPOutput out) { |
||||||
|
LOG.trace("Encoding transaction with blobs {}", transaction); |
||||||
|
var blobsWithCommitments = transaction.getBlobsWithCommitments(); |
||||||
|
if (blobsWithCommitments.isEmpty() || blobsWithCommitments.get().getBlobs().isEmpty()) { |
||||||
|
throw new InvalidParameterException(NO_BLOBS_ERROR); |
||||||
|
} |
||||||
|
out.startList(); |
||||||
|
BlobTransactionEncoder.encode(transaction, out); |
||||||
|
out.writeList(blobsWithCommitments.get().getBlobs(), Blob::writeTo); |
||||||
|
out.writeList(blobsWithCommitments.get().getKzgCommitments(), KZGCommitment::writeTo); |
||||||
|
out.writeList(blobsWithCommitments.get().getKzgProofs(), KZGProof::writeTo); |
||||||
|
out.endList(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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 org.hyperledger.besu.crypto.SignatureAlgorithm; |
||||||
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; |
||||||
|
import org.hyperledger.besu.datatypes.AccessListEntry; |
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
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.RLPInput; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
import java.util.function.Supplier; |
||||||
|
|
||||||
|
import com.google.common.base.Suppliers; |
||||||
|
|
||||||
|
public class EIP1559TransactionDecoder { |
||||||
|
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM = |
||||||
|
Suppliers.memoize(SignatureAlgorithmFactory::getInstance); |
||||||
|
|
||||||
|
public static Transaction decode(final RLPInput input) { |
||||||
|
input.enterList(); |
||||||
|
final BigInteger chainId = input.readBigIntegerScalar(); |
||||||
|
final Transaction.Builder builder = |
||||||
|
Transaction.builder() |
||||||
|
.type(TransactionType.EIP1559) |
||||||
|
.chainId(chainId) |
||||||
|
.nonce(input.readLongScalar()) |
||||||
|
.maxPriorityFeePerGas(Wei.of(input.readUInt256Scalar())) |
||||||
|
.maxFeePerGas(Wei.of(input.readUInt256Scalar())) |
||||||
|
.gasLimit(input.readLongScalar()) |
||||||
|
.to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v))) |
||||||
|
.value(Wei.of(input.readUInt256Scalar())) |
||||||
|
.payload(input.readBytes()) |
||||||
|
.accessList( |
||||||
|
input.readList( |
||||||
|
accessListEntryRLPInput -> { |
||||||
|
accessListEntryRLPInput.enterList(); |
||||||
|
final AccessListEntry accessListEntry = |
||||||
|
new AccessListEntry( |
||||||
|
Address.wrap(accessListEntryRLPInput.readBytes()), |
||||||
|
accessListEntryRLPInput.readList(RLPInput::readBytes32)); |
||||||
|
accessListEntryRLPInput.leaveList(); |
||||||
|
return accessListEntry; |
||||||
|
})); |
||||||
|
final byte recId = (byte) input.readIntScalar(); |
||||||
|
final Transaction transaction = |
||||||
|
builder |
||||||
|
.signature( |
||||||
|
SIGNATURE_ALGORITHM |
||||||
|
.get() |
||||||
|
.createSignature( |
||||||
|
input.readUInt256Scalar().toUnsignedBigInteger(), |
||||||
|
input.readUInt256Scalar().toUnsignedBigInteger(), |
||||||
|
recId)) |
||||||
|
.build(); |
||||||
|
input.leaveList(); |
||||||
|
return transaction; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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 org.hyperledger.besu.ethereum.core.encoding.AccessListTransactionEncoder.writeAccessList; |
||||||
|
import static org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignatureAndRecoveryId; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
|
||||||
|
public class EIP1559TransactionEncoder { |
||||||
|
|
||||||
|
public static void encode(final Transaction transaction, final RLPOutput out) { |
||||||
|
out.startList(); |
||||||
|
out.writeBigIntegerScalar(transaction.getChainId().orElseThrow()); |
||||||
|
out.writeLongScalar(transaction.getNonce()); |
||||||
|
out.writeUInt256Scalar(transaction.getMaxPriorityFeePerGas().orElseThrow()); |
||||||
|
out.writeUInt256Scalar(transaction.getMaxFeePerGas().orElseThrow()); |
||||||
|
out.writeLongScalar(transaction.getGasLimit()); |
||||||
|
out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); |
||||||
|
out.writeUInt256Scalar(transaction.getValue()); |
||||||
|
out.writeBytes(transaction.getPayload()); |
||||||
|
writeAccessList(out, transaction.getAccessList()); |
||||||
|
writeSignatureAndRecoveryId(transaction, out); |
||||||
|
out.endList(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* <p>The context can be one of the following: |
||||||
|
* |
||||||
|
* <ul> |
||||||
|
* <li>{@link #BLOCK_BODY}: The transaction is part of a block body. This context is used when |
||||||
|
* encoding transactions for inclusion in a block. |
||||||
|
* <li>{@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. |
||||||
|
* </ul> |
||||||
|
*/ |
||||||
|
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, |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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 org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_BASE; |
||||||
|
import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_PROTECTED_V_MIN; |
||||||
|
import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE; |
||||||
|
import static org.hyperledger.besu.ethereum.core.Transaction.REPLAY_UNPROTECTED_V_BASE_PLUS_1; |
||||||
|
import static org.hyperledger.besu.ethereum.core.Transaction.TWO; |
||||||
|
|
||||||
|
import org.hyperledger.besu.crypto.SECPSignature; |
||||||
|
import org.hyperledger.besu.crypto.SignatureAlgorithm; |
||||||
|
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; |
||||||
|
import org.hyperledger.besu.datatypes.Address; |
||||||
|
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.RLPInput; |
||||||
|
|
||||||
|
import java.math.BigInteger; |
||||||
|
import java.util.Optional; |
||||||
|
import java.util.function.Supplier; |
||||||
|
|
||||||
|
import com.google.common.base.Suppliers; |
||||||
|
|
||||||
|
public class FrontierTransactionDecoder { |
||||||
|
// Supplier for the signature algorithm
|
||||||
|
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM = |
||||||
|
Suppliers.memoize(SignatureAlgorithmFactory::getInstance); |
||||||
|
|
||||||
|
public static Transaction decode(final RLPInput input) { |
||||||
|
input.enterList(); |
||||||
|
final Transaction.Builder builder = |
||||||
|
Transaction.builder() |
||||||
|
.type(TransactionType.FRONTIER) |
||||||
|
.nonce(input.readLongScalar()) |
||||||
|
.gasPrice(Wei.of(input.readUInt256Scalar())) |
||||||
|
.gasLimit(input.readLongScalar()) |
||||||
|
.to(input.readBytes(v -> v.size() == 0 ? null : Address.wrap(v))) |
||||||
|
.value(Wei.of(input.readUInt256Scalar())) |
||||||
|
.payload(input.readBytes()); |
||||||
|
|
||||||
|
final BigInteger v = input.readBigIntegerScalar(); |
||||||
|
final byte recId; |
||||||
|
Optional<BigInteger> chainId = Optional.empty(); |
||||||
|
if (v.equals(REPLAY_UNPROTECTED_V_BASE) || v.equals(REPLAY_UNPROTECTED_V_BASE_PLUS_1)) { |
||||||
|
recId = v.subtract(REPLAY_UNPROTECTED_V_BASE).byteValueExact(); |
||||||
|
} else if (v.compareTo(REPLAY_PROTECTED_V_MIN) > 0) { |
||||||
|
chainId = Optional.of(v.subtract(REPLAY_PROTECTED_V_BASE).divide(TWO)); |
||||||
|
recId = v.subtract(TWO.multiply(chainId.get()).add(REPLAY_PROTECTED_V_BASE)).byteValueExact(); |
||||||
|
} else { |
||||||
|
throw new RuntimeException( |
||||||
|
String.format("An unsupported encoded `v` value of %s was found", v)); |
||||||
|
} |
||||||
|
final BigInteger r = input.readUInt256Scalar().toUnsignedBigInteger(); |
||||||
|
final BigInteger s = input.readUInt256Scalar().toUnsignedBigInteger(); |
||||||
|
final SECPSignature signature = SIGNATURE_ALGORITHM.get().createSignature(r, s, recId); |
||||||
|
|
||||||
|
input.leaveList(); |
||||||
|
|
||||||
|
chainId.ifPresent(builder::chainId); |
||||||
|
return builder.signature(signature).build(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
/* |
||||||
|
* Copyright Hyperledger Besu Contributors. |
||||||
|
* |
||||||
|
* 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 org.hyperledger.besu.ethereum.core.encoding.TransactionEncoder.writeSignatureAndV; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction; |
||||||
|
import org.hyperledger.besu.ethereum.rlp.RLPOutput; |
||||||
|
|
||||||
|
import org.apache.tuweni.bytes.Bytes; |
||||||
|
|
||||||
|
public class FrontierTransactionEncoder { |
||||||
|
public static void encode(final Transaction transaction, final RLPOutput out) { |
||||||
|
out.startList(); |
||||||
|
out.writeLongScalar(transaction.getNonce()); |
||||||
|
out.writeUInt256Scalar(transaction.getGasPrice().orElseThrow()); |
||||||
|
out.writeLongScalar(transaction.getGasLimit()); |
||||||
|
out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY)); |
||||||
|
out.writeUInt256Scalar(transaction.getValue()); |
||||||
|
out.writeBytes(transaction.getPayload()); |
||||||
|
writeSignatureAndV(transaction, out); |
||||||
|
out.endList(); |
||||||
|
} |
||||||
|
} |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue