Skip to content

Commit

Permalink
EIP-4844 testing support (hyperledger#5702)
Browse files Browse the repository at this point in the history
Add two new fields to reference tests (versionedHashes, maxFeePerDataGas)
Rename DataHash to BlobHash (to align with EIP4844 text)

Signed-off-by: Danno Ferrin <danno.ferrin@swirldslabs.com>
  • Loading branch information
shemnon authored Jul 26, 2023
1 parent ba2fc3d commit 403297b
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.util.Objects;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
Expand All @@ -37,7 +38,7 @@ public class VersionedHash {
public static final byte SHA256_VERSION_ID = 1;

/** A default versioned hash, nonsensical but valid. */
public static VersionedHash DEFAULT_VERSIONED_HASH =
public static final VersionedHash DEFAULT_VERSIONED_HASH =
new VersionedHash(SHA256_VERSION_ID, Hash.ZERO);

/**
Expand Down Expand Up @@ -68,6 +69,21 @@ public VersionedHash(final Bytes32 typedHash) {
this.hashish = typedHash;
}

/**
* Parse a hexadecimal string representing a versioned hash value.
*
* @param str A hexadecimal string (with or without the leading '0x') representing a valid hash
* value.
* @return The parsed hash.
* @throws NullPointerException if the provided string is {@code null}.
* @throws IllegalArgumentException if the string is either not hexadecimal, or not the valid
* representation of a versioned hash (not 32 bytes or bad version).
*/
@JsonCreator
public static VersionedHash fromHexString(final String str) {
return new VersionedHash(Bytes32.fromHexString(str));
}

/**
* Convert it to raw bytes.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.evm.AccessListEntry;
Expand Down Expand Up @@ -71,6 +72,8 @@ public class StateTestVersionedTransaction {
private final List<Wei> values;
private final List<Bytes> payloads;
private final Optional<List<List<AccessListEntry>>> maybeAccessLists;
private final Wei maxFeePerDataGas;
private final List<VersionedHash> blobVersionedHashes;

/**
* Constructor for populating a mock transaction with json data.
Expand Down Expand Up @@ -98,7 +101,9 @@ public StateTestVersionedTransaction(
@JsonProperty("secretKey") final String secretKey,
@JsonProperty("data") final String[] data,
@JsonDeserialize(using = StateTestAccessListDeserializer.class) @JsonProperty("accessLists")
final List<List<AccessListEntry>> maybeAccessLists) {
final List<List<AccessListEntry>> maybeAccessLists,
@JsonProperty("maxFeePerDataGas") final String maxFeePerDataGas,
@JsonProperty("blobVersionedHashes") final List<VersionedHash> blobVersionedHashes) {

this.nonce = Bytes.fromHexStringLenient(nonce).toLong();
this.gasPrice = Optional.ofNullable(gasPrice).map(Wei::fromHexString).orElse(null);
Expand All @@ -116,9 +121,16 @@ public StateTestVersionedTransaction(
this.values = parseArray(value, Wei::fromHexString);
this.payloads = parseArray(data, Bytes::fromHexString);
this.maybeAccessLists = Optional.ofNullable(maybeAccessLists);
this.maxFeePerDataGas =
Optional.ofNullable(maxFeePerDataGas).map(Wei::fromHexString).orElse(null);
this.blobVersionedHashes = blobVersionedHashes;
}

private static <T> List<T> parseArray(final String[] array, final Function<String, T> parseFct) {
if (array == null) {
return null;
}

final List<T> res = new ArrayList<>(array.length);
for (final String str : array) {
try {
Expand Down Expand Up @@ -148,6 +160,8 @@ public Transaction get(final GeneralStateTestCaseSpec.Indexes indexes) {
Optional.ofNullable(maxPriorityFeePerGas).ifPresent(transactionBuilder::maxPriorityFeePerGas);
maybeAccessLists.ifPresent(
accessLists -> transactionBuilder.accessList(accessLists.get(indexes.data)));
Optional.ofNullable(maxFeePerDataGas).ifPresent(transactionBuilder::maxFeePerDataGas);
transactionBuilder.versionedHashes(blobVersionedHashes);

transactionBuilder.guessType();
if (transactionBuilder.getTransactionType().requiresChainId()) {
Expand Down
6 changes: 3 additions & 3 deletions evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import org.hyperledger.besu.evm.operation.AndOperation;
import org.hyperledger.besu.evm.operation.BalanceOperation;
import org.hyperledger.besu.evm.operation.BaseFeeOperation;
import org.hyperledger.besu.evm.operation.BlobHashOperation;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.evm.operation.ByteOperation;
import org.hyperledger.besu.evm.operation.CallCodeOperation;
Expand All @@ -48,7 +49,6 @@
import org.hyperledger.besu.evm.operation.CoinbaseOperation;
import org.hyperledger.besu.evm.operation.Create2Operation;
import org.hyperledger.besu.evm.operation.CreateOperation;
import org.hyperledger.besu.evm.operation.DataHashOperation;
import org.hyperledger.besu.evm.operation.DelegateCallOperation;
import org.hyperledger.besu.evm.operation.DifficultyOperation;
import org.hyperledger.besu.evm.operation.DivOperation;
Expand Down Expand Up @@ -847,8 +847,8 @@ public static void registerCancunOperations(
registry.put(new TStoreOperation(gasCalculator));
registry.put(new TLoadOperation(gasCalculator));

// EIP-4844 DATAHASH
registry.put(new DataHashOperation(gasCalculator));
// EIP-4844 BLOBHASH
registry.put(new BlobHashOperation(gasCalculator));

// EIP-5656 MCOPY
registry.put(new MCopyOperation(gasCalculator));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,24 +24,25 @@
import org.apache.tuweni.bytes.Bytes;

/**
* The DataHash operation. https://eips.ethereum.org/EIPS/eip-4844
* The BlobHash operation. As specified in <a
* href="https://eips.ethereum.org/EIPS/eip-4844">EIP-4844</a>
*
* <p>Reads index from the top of the stack as big-endian uint256, and replaces it on the stack with
* tx.message.blob_versioned_hashes[index] if index &lt; len(tx.message.blob_versioned_hashes), and
* otherwise with a zeroed bytes32 value.
*/
public class DataHashOperation extends AbstractOperation {
public class BlobHashOperation extends AbstractOperation {

/** DATAHASH opcode number */
/** BLOBHASH opcode number */
public static final int OPCODE = 0x49;

/**
* Instantiates a new DataHash operation.
* Instantiates a new BlobHash operation.
*
* @param gasCalculator the gas calculator
*/
public DataHashOperation(final GasCalculator gasCalculator) {
super(OPCODE, "DATAHASH", 1, 1, gasCalculator);
public BlobHashOperation(final GasCalculator gasCalculator) {
super(OPCODE, "BLOBHASH", 1, 1, gasCalculator);
}

@Override
Expand All @@ -67,9 +68,4 @@ public OperationResult execute(final MessageFrame frame, final EVM evm) {
}
return new OperationResult(3, null);
}

@Override
public boolean isVirtualOperation() {
return super.isVirtualOperation();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;
import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator;
import org.hyperledger.besu.evm.operation.DataHashOperation;
import org.hyperledger.besu.evm.operation.BlobHashOperation;
import org.hyperledger.besu.evm.operation.Operation;

import java.util.ArrayList;
Expand All @@ -38,7 +38,7 @@
import org.apache.tuweni.bytes.Bytes32;
import org.junit.jupiter.api.Test;

class DataHashOperationTest {
class BlobHashOperationTest {

private static final String testVersionedHash =
"0x01cafebabeb0b0facedeadbeefbeef0001cafebabeb0b0facedeadbeefbeef00";
Expand All @@ -47,7 +47,7 @@ class DataHashOperationTest {
void putsHashOnStack() {
VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash));
List<VersionedHash> versionedHashes = Arrays.asList(version0Hash);
DataHashOperation getHash = new DataHashOperation(new LondonGasCalculator());
BlobHashOperation getHash = new BlobHashOperation(new LondonGasCalculator());
MessageFrame frame = mock(MessageFrame.class);
when(frame.popStackItem()).thenReturn(Bytes.of(0));
when(frame.getVersionedHashes()).thenReturn(Optional.of(versionedHashes));
Expand All @@ -63,7 +63,7 @@ void pushesZeroOnBloblessTx() {

EVM fakeEVM = mock(EVM.class);

DataHashOperation getHash = new DataHashOperation(new CancunGasCalculator());
BlobHashOperation getHash = new BlobHashOperation(new CancunGasCalculator());
MessageFrame frame = mock(MessageFrame.class);
when(frame.popStackItem()).thenReturn(Bytes.of(0));
when(frame.getVersionedHashes()).thenReturn(Optional.empty());
Expand All @@ -84,7 +84,7 @@ void pushesZeroOnBloblessTx() {
void pushZeroOnVersionIndexOutOFBounds() {
VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash));
List<VersionedHash> versionedHashes = Arrays.asList(version0Hash);
DataHashOperation getHash = new DataHashOperation(new CancunGasCalculator());
BlobHashOperation getHash = new BlobHashOperation(new CancunGasCalculator());
MessageFrame frame = mock(MessageFrame.class);
when(frame.popStackItem()).thenReturn(Bytes.of(1));
when(frame.getVersionedHashes()).thenReturn(Optional.of(versionedHashes));
Expand All @@ -99,7 +99,7 @@ void pushZeroOnVersionIndexOutOFBounds() {
public void pushZeroWhenPopsMissingUint256SizedIndex() {
VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash));
List<VersionedHash> versionedHashes = Arrays.asList(version0Hash);
DataHashOperation getHash = new DataHashOperation(new CancunGasCalculator());
BlobHashOperation getHash = new BlobHashOperation(new CancunGasCalculator());
MessageFrame frame = mock(MessageFrame.class);
when(frame.popStackItem()).thenReturn(Bytes32.repeat((byte) 0x2C));
when(frame.getVersionedHashes()).thenReturn(Optional.of(versionedHashes));
Expand Down

0 comments on commit 403297b

Please sign in to comment.