From 403297b874b68cb414c4bf13e98549b3597c61ca Mon Sep 17 00:00:00 2001 From: Danno Ferrin Date: Wed, 26 Jul 2023 12:27:17 -0600 Subject: [PATCH] EIP-4844 testing support (#5702) Add two new fields to reference tests (versionedHashes, maxFeePerDataGas) Rename DataHash to BlobHash (to align with EIP4844 text) Signed-off-by: Danno Ferrin --- .../besu/datatypes/VersionedHash.java | 18 +++++++++++++++++- .../StateTestVersionedTransaction.java | 16 +++++++++++++++- .../org/hyperledger/besu/evm/MainnetEVMs.java | 6 +++--- ...shOperation.java => BlobHashOperation.java} | 18 +++++++----------- ...ionTest.java => BlobHashOperationTest.java} | 12 ++++++------ 5 files changed, 48 insertions(+), 22 deletions(-) rename evm/src/main/java/org/hyperledger/besu/evm/operation/{DataHashOperation.java => BlobHashOperation.java} (84%) rename evm/src/test/java/org/hyperledger/besu/evm/operations/{DataHashOperationTest.java => BlobHashOperationTest.java} (92%) diff --git a/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java b/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java index 97cb093f4d..21f296e0ae 100644 --- a/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java +++ b/datatypes/src/main/java/org/hyperledger/besu/datatypes/VersionedHash.java @@ -17,6 +17,7 @@ package org.hyperledger.besu.datatypes; 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; @@ -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); /** @@ -68,6 +69,21 @@ public class VersionedHash { 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. * diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java index 69ad926753..e8f171fafe 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/StateTestVersionedTransaction.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.crypto.KeyPair; 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; @@ -71,6 +72,8 @@ public class StateTestVersionedTransaction { private final List values; private final List payloads; private final Optional>> maybeAccessLists; + private final Wei maxFeePerDataGas; + private final List blobVersionedHashes; /** * Constructor for populating a mock transaction with json data. @@ -98,7 +101,9 @@ public class StateTestVersionedTransaction { @JsonProperty("secretKey") final String secretKey, @JsonProperty("data") final String[] data, @JsonDeserialize(using = StateTestAccessListDeserializer.class) @JsonProperty("accessLists") - final List> maybeAccessLists) { + final List> maybeAccessLists, + @JsonProperty("maxFeePerDataGas") final String maxFeePerDataGas, + @JsonProperty("blobVersionedHashes") final List blobVersionedHashes) { this.nonce = Bytes.fromHexStringLenient(nonce).toLong(); this.gasPrice = Optional.ofNullable(gasPrice).map(Wei::fromHexString).orElse(null); @@ -116,9 +121,16 @@ public class 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 List parseArray(final String[] array, final Function parseFct) { + if (array == null) { + return null; + } + final List res = new ArrayList<>(array.length); for (final String str : array) { try { @@ -148,6 +160,8 @@ public class StateTestVersionedTransaction { 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()) { diff --git a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java index 4df9415a10..6398f23a50 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/MainnetEVMs.java @@ -32,6 +32,7 @@ import org.hyperledger.besu.evm.operation.AddressOperation; 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; @@ -48,7 +49,6 @@ import org.hyperledger.besu.evm.operation.CodeSizeOperation; 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; @@ -847,8 +847,8 @@ public class MainnetEVMs { 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)); diff --git a/evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java b/evm/src/main/java/org/hyperledger/besu/evm/operation/BlobHashOperation.java similarity index 84% rename from evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java rename to evm/src/main/java/org/hyperledger/besu/evm/operation/BlobHashOperation.java index 9439709ca3..3fe212b8b3 100644 --- a/evm/src/main/java/org/hyperledger/besu/evm/operation/DataHashOperation.java +++ b/evm/src/main/java/org/hyperledger/besu/evm/operation/BlobHashOperation.java @@ -24,24 +24,25 @@ import java.util.List; import org.apache.tuweni.bytes.Bytes; /** - * The DataHash operation. https://eips.ethereum.org/EIPS/eip-4844 + * The BlobHash operation. As specified in EIP-4844 * *

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 < 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 @@ -67,9 +68,4 @@ public class DataHashOperation extends AbstractOperation { } return new OperationResult(3, null); } - - @Override - public boolean isVirtualOperation() { - return super.isVirtualOperation(); - } } diff --git a/evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java b/evm/src/test/java/org/hyperledger/besu/evm/operations/BlobHashOperationTest.java similarity index 92% rename from evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java rename to evm/src/test/java/org/hyperledger/besu/evm/operations/BlobHashOperationTest.java index 02f4964e85..0f789a9447 100644 --- a/evm/src/test/java/org/hyperledger/besu/evm/operations/DataHashOperationTest.java +++ b/evm/src/test/java/org/hyperledger/besu/evm/operations/BlobHashOperationTest.java @@ -26,7 +26,7 @@ import org.hyperledger.besu.evm.EVM; 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; @@ -38,7 +38,7 @@ import org.apache.tuweni.bytes.Bytes; import org.apache.tuweni.bytes.Bytes32; import org.junit.jupiter.api.Test; -class DataHashOperationTest { +class BlobHashOperationTest { private static final String testVersionedHash = "0x01cafebabeb0b0facedeadbeefbeef0001cafebabeb0b0facedeadbeefbeef00"; @@ -47,7 +47,7 @@ class DataHashOperationTest { void putsHashOnStack() { VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); List 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)); @@ -63,7 +63,7 @@ class DataHashOperationTest { 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()); @@ -84,7 +84,7 @@ class DataHashOperationTest { void pushZeroOnVersionIndexOutOFBounds() { VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); List 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)); @@ -99,7 +99,7 @@ class DataHashOperationTest { public void pushZeroWhenPopsMissingUint256SizedIndex() { VersionedHash version0Hash = new VersionedHash(Bytes32.fromHexStringStrict(testVersionedHash)); List 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));