Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

### Additions and Improvements
- "Big-EOF" (the EOF version initially slotted for Shanghai) has been moved from Cancun to FutureEIPs [#5429](https://github.com/hyperledger/besu/pull/5429)
- EIP-4844: Zero blob transactions are invalid [#5425](https://github.com/hyperledger/besu/pull/5425)

### Bug Fixes
- Fix eth_feeHistory response for the case in which blockCount is higher than highestBlock requested. [#5397](https://github.com/hyperledger/besu/pull/5397)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public void eip1559TransactionWithShortWeiVals() {
new TransactionCompleteResult(
new TransactionWithMetadata(
new TransactionTestFixture()
.type(TransactionType.EIP1559)
.maxFeePerGas(Optional.of(Wei.ONE))
.maxPriorityFeePerGas(Optional.of(Wei.ZERO))
.createTransaction(gen.generateKeyPair()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ public Transaction(
if (transactionType.supportsBlob()) {
checkArgument(
versionedHashes.isPresent(), "Must specify blob versioned hashes for blob transaction");
checkArgument(
!versionedHashes.get().isEmpty(), "Blob transaction must have at least one blob");
checkArgument(
maxFeePerDataGas.isPresent(), "Must specify max fee per data gas for blob transaction");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,29 @@

import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.AccessListEntry;
import org.hyperledger.besu.plugin.data.TransactionType;

import java.math.BigInteger;
import java.util.List;
import java.util.Optional;

import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;

public class TransactionTestFixture {
private static final Hash DEFAULT_VERSIONED_HASH =
Hash.wrap(
Bytes32.wrap(
Bytes.concatenate(Bytes.fromHexString("0x01"), Bytes.repeat((byte) 42, 31))));

private TransactionType transactionType = TransactionType.FRONTIER;

private long nonce = 0;

private Wei gasPrice = Wei.of(5000);
private Optional<Wei> gasPrice = Optional.empty();

private long gasLimit = 5000;

Expand All @@ -45,6 +53,10 @@ public class TransactionTestFixture {

private Optional<Wei> maxPriorityFeePerGas = Optional.empty();
private Optional<Wei> maxFeePerGas = Optional.empty();
private Optional<Wei> maxFeePerDataGas = Optional.empty();

private Optional<List<AccessListEntry>> accessListEntries = Optional.empty();
private Optional<List<Hash>> versionedHashes = Optional.empty();

private Optional<BigInteger> v = Optional.empty();

Expand All @@ -53,18 +65,35 @@ public Transaction createTransaction(final KeyPair keys) {
builder
.type(transactionType)
.gasLimit(gasLimit)
.gasPrice(gasPrice)
.nonce(nonce)
.payload(payload)
.value(value)
.sender(sender);

switch (transactionType) {
case FRONTIER:
builder.gasPrice(gasPrice.orElse(Wei.of(5000)));
break;
case ACCESS_LIST:
builder.gasPrice(gasPrice.orElse(Wei.of(5000)));
builder.accessList(accessListEntries.orElse(List.of()));
break;
case EIP1559:
builder.maxPriorityFeePerGas(maxPriorityFeePerGas.orElse(Wei.of(500)));
builder.maxFeePerGas(maxFeePerGas.orElse(Wei.of(5000)));
builder.accessList(accessListEntries.orElse(List.of()));
break;
case BLOB:
builder.maxPriorityFeePerGas(maxPriorityFeePerGas.orElse(Wei.of(500)));
builder.maxFeePerGas(maxFeePerGas.orElse(Wei.of(5000)));
builder.accessList(accessListEntries.orElse(List.of()));
builder.maxFeePerDataGas(maxFeePerDataGas.orElse(Wei.ONE));
builder.versionedHashes(versionedHashes.orElse(List.of(DEFAULT_VERSIONED_HASH)));
break;
}

to.ifPresent(builder::to);
chainId.ifPresent(builder::chainId);

maxPriorityFeePerGas.ifPresent(builder::maxPriorityFeePerGas);
maxFeePerGas.ifPresent(builder::maxFeePerGas);

v.ifPresent(builder::v);

return builder.signAndBuild(keys);
Expand All @@ -81,7 +110,7 @@ public TransactionTestFixture nonce(final long nonce) {
}

public TransactionTestFixture gasPrice(final Wei gasPrice) {
this.gasPrice = gasPrice;
this.gasPrice = Optional.ofNullable(gasPrice);
return this;
}

Expand Down Expand Up @@ -125,6 +154,21 @@ public TransactionTestFixture maxFeePerGas(final Optional<Wei> maxFeePerGas) {
return this;
}

public TransactionTestFixture maxFeePerDataGas(final Optional<Wei> maxFeePerDataGas) {
this.maxFeePerDataGas = maxFeePerDataGas;
return this;
}

public TransactionTestFixture accessList(final List<AccessListEntry> accessListEntries) {
this.accessListEntries = Optional.ofNullable(accessListEntries);
return this;
}

public TransactionTestFixture versionedHashes(final List<Hash> versionedHashes) {
this.versionedHashes = Optional.ofNullable(versionedHashes);
return this;
}

public TransactionTestFixture v(final Optional<BigInteger> v) {
this.v = v;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,29 @@

import static java.util.stream.Collectors.toUnmodifiableSet;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.fail;

import org.hyperledger.besu.crypto.KeyPair;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.AccessListEntry;
import org.hyperledger.besu.plugin.data.TransactionType;

import java.math.BigInteger;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Stream;

import com.google.common.base.Suppliers;
import org.junit.Test;

public class TransactionBuilderTest {
private static final Supplier<SignatureAlgorithm> SIGNATURE_ALGORITHM =
Suppliers.memoize(SignatureAlgorithmFactory::getInstance);
private static final KeyPair senderKeys = SIGNATURE_ALGORITHM.get().generateKeyPair();

@Test
public void guessTypeCanGuessAllTypes() {
Expand All @@ -50,4 +61,18 @@ public void guessTypeCanGuessAllTypes() {
TransactionType.FRONTIER, TransactionType.ACCESS_LIST, TransactionType.EIP1559
});
}

@Test
public void zeroBlobTransactionIsInvalid() {
try {
new TransactionTestFixture()
.type(TransactionType.BLOB)
.chainId(Optional.of(BigInteger.ONE))
.versionedHashes(List.of())
.createTransaction(senderKeys);
fail();
} catch (IllegalArgumentException iea) {
assertThat(iea).hasMessage("Blob transaction must have at least one blob");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,29 @@ public void shouldRejectTooLargeInitcode() {
.isEqualTo("Initcode size of 49153 exceeds maximum size of 49152");
}

@Test
public void shouldAcceptTransactionWithAtLeastOneBlob() {
final MainnetTransactionValidator validator =
new MainnetTransactionValidator(
gasCalculator,
GasLimitCalculator.constant(),
FeeMarket.london(0L),
false,
Optional.of(BigInteger.ONE),
Set.of(TransactionType.FRONTIER, TransactionType.EIP1559, TransactionType.BLOB),
0xc000);

var blobTx =
new TransactionTestFixture()
.type(TransactionType.BLOB)
.chainId(Optional.of(BigInteger.ONE))
.createTransaction(senderKeys);
var validationResult =
validator.validate(blobTx, Optional.empty(), transactionValidationParams);

assertThat(validationResult.isValid()).isTrue();
}

private Account accountWithNonce(final long nonce) {
return account(basicTransaction.getUpfrontCost(0L), nonce);
}
Expand Down