Skip to content

Commit

Permalink
feat:add op deposit tx encode/decode.
Browse files Browse the repository at this point in the history
Signed-off-by: Chen Kai <281165273grape@gmail.com>
  • Loading branch information
GrapeBaBa committed Nov 23, 2023
1 parent 7a9313c commit 7c649af
Show file tree
Hide file tree
Showing 12 changed files with 231 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,27 @@ default Optional<? extends Quantity> getMaxFeePerBlobGas() {
*/
Optional<BlobsWithCommitments> getBlobsWithCommitments();

/**
* Return the source hash for this transaction.
*
* @return optional source hash
*/
Optional<Hash> getSourceHash();

/**
* Return the mint value for this transaction.
*
* @return optional mint value
*/
Optional<Wei> getMint();

/**
* Return the is system transaction flag for this transaction.
*
* @return optional is system transaction flag
*/
Optional<Boolean> getIsSystemTx();

/**
* Return the address of the contract, if the transaction creates one
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ public enum TransactionType {
/** Eip1559 transaction type. */
EIP1559(0x02),
/** Blob transaction type. */
BLOB(0x03);
BLOB(0x03),
/** Optimism Deposit transaction type. */
OPTIMISM_DEPOSIT(0x7e);

private static final Set<TransactionType> ACCESS_LIST_SUPPORTED_TRANSACTION_TYPES =
Set.of(ACCESS_LIST, EIP1559, BLOB);
Expand Down Expand Up @@ -83,7 +85,8 @@ public static TransactionType of(final int serializedTypeValue) {
TransactionType.FRONTIER,
TransactionType.ACCESS_LIST,
TransactionType.EIP1559,
TransactionType.BLOB
TransactionType.BLOB,
TransactionType.OPTIMISM_DEPOSIT
})
.filter(transactionType -> transactionType.typeValue == serializedTypeValue)
.findFirst()
Expand Down Expand Up @@ -117,7 +120,7 @@ public boolean supports1559FeeMarket() {
* @return the boolean
*/
public boolean requiresChainId() {
return !this.equals(FRONTIER);
return !this.equals(FRONTIER) && !this.equals(OPTIMISM_DEPOSIT);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public class Transaction

private final Optional<Hash> sourceHash;

private final Optional<BigInteger> mint;
private final Optional<Wei> mint;

private final Optional<Boolean> isSystemTx;

Expand Down Expand Up @@ -184,7 +184,7 @@ private Transaction(
final Optional<List<VersionedHash>> versionedHashes,
final Optional<BlobsWithCommitments> blobsWithCommitments,
final Optional<Hash> sourceHash,
final Optional<BigInteger> mint,
final Optional<Wei> mint,
final Optional<Boolean> isSystemTx) {
this.sourceHash = sourceHash;
this.mint = mint;
Expand Down Expand Up @@ -243,7 +243,9 @@ private Transaction(
this.versionedHashes = versionedHashes;
this.blobsWithCommitments = blobsWithCommitments;

if (!forCopy && isUpfrontGasCostTooHigh()) {
if (!forCopy
&& transactionType != TransactionType.OPTIMISM_DEPOSIT
&& isUpfrontGasCostTooHigh()) {
throw new IllegalArgumentException("Upfront gas cost exceeds UInt256");
}
}
Expand Down Expand Up @@ -678,6 +680,21 @@ public Optional<BlobsWithCommitments> getBlobsWithCommitments() {
return blobsWithCommitments;
}

@Override
public Optional<Hash> getSourceHash() {
return sourceHash;
}

@Override
public Optional<Wei> getMint() {
return mint;
}

@Override
public Optional<Boolean> getIsSystemTx() {
return isSystemTx;
}

/**
* Return the list of transaction hashes extracted from the collection of Transaction passed as
* argument
Expand Down Expand Up @@ -1138,7 +1155,7 @@ public static class Builder {

private Hash sourceHash;

private BigInteger mint;
private Wei mint;

private Boolean isSystemTx;

Expand Down Expand Up @@ -1230,7 +1247,7 @@ public Builder sourceHash(final Hash sourceHash) {
return this;
}

public Builder mint(final BigInteger mint) {
public Builder mint(final Wei mint) {
this.mint = mint;
return this;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* Copyright optimism-java.
*
* 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.Address;
import org.hyperledger.besu.datatypes.Hash;
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;

public class OptimismDepositTransactionDecoder {

public static Transaction decode(final RLPInput input) {
input.enterList();
final Transaction.Builder builder =
Transaction.builder()
.type(TransactionType.OPTIMISM_DEPOSIT)
.sourceHash(Hash.wrap(input.readBytes32()))
.sender(Address.wrap(input.readBytes()))
.to(input.readBytes(v -> v.isEmpty() ? null : Address.wrap(v)))
.mint(Wei.of(input.readUInt256Scalar()))
.value(Wei.of(input.readUInt256Scalar()))
.gasLimit(input.readLongScalar())
.isSystemTx(input.readBigIntegerScalar().compareTo(BigInteger.ONE) == 0)
.payload(input.readBytes());
input.leaveList();
return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright optimism-java.
*
* 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.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.rlp.RLPOutput;

import java.math.BigInteger;

import org.apache.tuweni.bytes.Bytes;

public class OptimismDepositTransactionEncoder {

public static void encode(final Transaction transaction, final RLPOutput out) {
out.startList();
out.writeBytes(transaction.getSourceHash().orElseThrow());
out.writeBytes(transaction.getSender());
out.writeBytes(transaction.getTo().map(Bytes::copy).orElse(Bytes.EMPTY));
out.writeUInt256Scalar(transaction.getMint().orElse(Wei.ZERO));
out.writeUInt256Scalar(transaction.getValue() != null ? transaction.getValue() : Wei.ZERO);
out.writeLongScalar(transaction.getGasLimit());
out.writeBigIntegerScalar(
transaction.getIsSystemTx().map(b -> b ? BigInteger.ONE : BigInteger.ZERO).orElseThrow());
out.writeBytes(transaction.getPayload() != null ? transaction.getPayload() : Bytes.EMPTY);
out.endList();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ interface Decoder {
TransactionType.EIP1559,
EIP1559TransactionDecoder::decode,
TransactionType.BLOB,
BlobTransactionDecoder::decode);
BlobTransactionDecoder::decode,
TransactionType.OPTIMISM_DEPOSIT,
OptimismDepositTransactionDecoder::decode);

private static final ImmutableMap<TransactionType, Decoder> POOLED_TRANSACTION_DECODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionDecoder::decode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ interface Encoder {
TransactionType.EIP1559,
EIP1559TransactionEncoder::encode,
TransactionType.BLOB,
BlobTransactionEncoder::encode);
BlobTransactionEncoder::encode,
TransactionType.OPTIMISM_DEPOSIT,
OptimismDepositTransactionEncoder::encode);

private static final ImmutableMap<TransactionType, Encoder> POOLED_TRANSACTION_ENCODERS =
ImmutableMap.of(TransactionType.BLOB, BlobPooledTransactionEncoder::encode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ public Transaction transaction(
case EIP1559 -> eip1559Transaction(payload, to);
case ACCESS_LIST -> accessListTransaction(payload, to);
case BLOB -> blobTransaction(payload, to);

case OPTIMISM_DEPOSIT -> optimismDepositTransaction(payload, to);
// no default, all types accounted for.
};
}
Expand Down Expand Up @@ -450,6 +450,20 @@ private Transaction frontierTransaction(final Bytes payload, final Address to) {
.signAndBuild(generateKeyPair());
}

private Transaction optimismDepositTransaction(final Bytes payload, final Address to) {
return Transaction.builder()
.type(TransactionType.OPTIMISM_DEPOSIT)
.gasLimit(positiveLong())
.to(to)
.value(Wei.wrap(bytes32()))
.payload(payload)
.isSystemTx(false)
.mint(Wei.of(BigInteger.ONE))
.sourceHash(Hash.ZERO)
.chainId(BigInteger.TEN)
.signAndBuild(generateKeyPair());
}

public Set<Transaction> transactions(final int n, final TransactionType... transactionTypes) {
return Stream.generate(() -> transaction(transactionTypes))
.parallel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
Expand Down Expand Up @@ -92,6 +93,11 @@ public Transaction createTransaction(final KeyPair keys) {
builder.kzgBlobs(bwc.getKzgCommitments(), bwc.getBlobs(), bwc.getKzgProofs());
});
break;
case OPTIMISM_DEPOSIT:
builder.sourceHash(Hash.ZERO);
builder.isSystemTx(true);
builder.mint(Wei.of(BigInteger.ONE));
break;
}

to.ifPresent(builder::to);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.hyperledger.besu.evm.account.Account.MAX_NONCE;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
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;
Expand All @@ -43,6 +47,24 @@ class TransactionRLPDecoderTest {
private static final String NONCE_64_BIT_MAX_MINUS_2_TX_RLP =
"0xf86788fffffffffffffffe0182520894095e7baea6a6c7c4c2dfeb977efac326af552d8780801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804";

private static final String OPTIMISM_DEPOSIT_TX_RLP =
"0xb8417ef83ea0000000000000000000000000000000000000000000000000000000000000000094000000000000000000000000000000000000000080648082c3500180";

@Test
void decodeOptimismDepositNominalCase() {
final Transaction transaction =
decodeRLP(RLP.input(Bytes.fromHexString(OPTIMISM_DEPOSIT_TX_RLP)));
assertThat(transaction).isNotNull();
assertThat(transaction.getType()).isEqualTo(TransactionType.OPTIMISM_DEPOSIT);
assertThat(transaction.getSourceHash().get()).isEqualTo(Hash.ZERO);
assertThat(transaction.getSender()).isEqualTo(Address.ZERO);
assertTrue(transaction.getIsSystemTx().get());
assertThat(transaction.getMint().get()).isEqualByComparingTo(Wei.of(100L));
assertThat(transaction.getValue()).isEqualByComparingTo(Wei.ZERO);
assertThat(transaction.getGasLimit()).isEqualTo(50000L);
assertTrue(transaction.getData().isEmpty());
}

@Test
void decodeFrontierNominalCase() {
final Transaction transaction = decodeRLP(RLP.input(Bytes.fromHexString(FRONTIER_TX_RLP)));
Expand Down Expand Up @@ -84,7 +106,8 @@ private static Collection<Object[]> dataTransactionSize() {
new Object[][] {
{FRONTIER_TX_RLP, "FRONTIER_TX_RLP"},
{EIP1559_TX_RLP, "EIP1559_TX_RLP"},
{NONCE_64_BIT_MAX_MINUS_2_TX_RLP, "NONCE_64_BIT_MAX_MINUS_2_TX_RLP"}
{NONCE_64_BIT_MAX_MINUS_2_TX_RLP, "NONCE_64_BIT_MAX_MINUS_2_TX_RLP"},
{OPTIMISM_DEPOSIT_TX_RLP, "OPTIMISM_DEPOSIT_TX_RLP"}
});
}

Expand All @@ -102,7 +125,13 @@ void shouldCalculateCorrectTransactionSize(final String rlp_tx, final String ign
}

@ParameterizedTest
@ValueSource(strings = {FRONTIER_TX_RLP, EIP1559_TX_RLP, NONCE_64_BIT_MAX_MINUS_2_TX_RLP})
@ValueSource(
strings = {
FRONTIER_TX_RLP,
EIP1559_TX_RLP,
NONCE_64_BIT_MAX_MINUS_2_TX_RLP,
OPTIMISM_DEPOSIT_TX_RLP
})
void shouldReturnCorrectEncodedBytes(final String txRlp) {
final Transaction transaction = decodeRLP(RLP.input(Bytes.fromHexString(txRlp)));
assertThat(transaction.encoded()).isEqualTo(Bytes.fromHexString(txRlp));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

import static org.assertj.core.api.Assertions.assertThat;

import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.Transaction;
Expand All @@ -35,6 +39,25 @@ class TransactionRLPEncoderTest {
private static final String NONCE_64_BIT_MAX_MINUS_2_TX_RLP =
"0xf86788fffffffffffffffe0182520894095e7baea6a6c7c4c2dfeb977efac326af552d8780801ba048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a01fffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804";

private static final String OPTIMISM_DEPOSIT_TX_RLP =
"0xb8417ef83ea0000000000000000000000000000000000000000000000000000000000000000094000000000000000000000000000000000000000080648082c3500180";

@Test
void encodeOptimismDepositNominalCase() {
final Transaction transaction =
Transaction.builder()
.type(TransactionType.OPTIMISM_DEPOSIT)
.sourceHash(Hash.ZERO)
.sender(Address.ZERO)
.mint(Wei.of(100L))
.gasLimit(50000L)
.isSystemTx(true)
.build();
final BytesValueRLPOutput output = new BytesValueRLPOutput();
encodeRLP(transaction, output);
assertThat(output.encoded().toHexString()).isEqualTo(OPTIMISM_DEPOSIT_TX_RLP);
}

@Test
void encodeFrontierTxNominalCase() {
final Transaction transaction = decodeRLP(RLP.input(Bytes.fromHexString(FRONTIER_TX_RLP)));
Expand Down
Loading

0 comments on commit 7c649af

Please sign in to comment.