diff --git a/ethereum/evmtool/build.gradle b/ethereum/evmtool/build.gradle index 989c865412c..fa3f989cdd8 100644 --- a/ethereum/evmtool/build.gradle +++ b/ethereum/evmtool/build.gradle @@ -56,8 +56,6 @@ dependencies { implementation 'info.picocli:picocli' implementation 'io.vertx:vertx-core' - runtimeOnly 'org.slf4j:slf4j-nop' - annotationProcessor 'com.google.dagger:dagger-compiler' annotationProcessor 'info.picocli:picocli-codegen' @@ -67,6 +65,9 @@ dependencies { testImplementation 'org.mockito:mockito-core' testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' + + // No logging in grallvm EvmTool + nativeImageClasspath 'org.slf4j:slf4j-nop' } mainClassName = 'org.hyperledger.besu.evmtool.EvmTool' diff --git a/ethereum/evmtool/src/main/graal/reflection-config.json b/ethereum/evmtool/src/main/graal/reflection-config.json index 12c2d5e9737..bedc322c76c 100644 --- a/ethereum/evmtool/src/main/graal/reflection-config.json +++ b/ethereum/evmtool/src/main/graal/reflection-config.json @@ -102,7 +102,7 @@ "unsafeAllocated": true }, { - "name": "org.hyperledger.besu.evmtool.T8nSubCommand$RejectedTransaction", + "name": "org.hyperledger.besu.evmtool.T8nExecutor$RejectedTransaction", "queryAllPublicConstructors": true, "queryAllPublicMethods": true, "allDeclaredConstructors": true, diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java index 3b6da40c5c0..c3838237858 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java @@ -18,6 +18,9 @@ import static org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules.shouldClearEmptyAccounts; import org.hyperledger.besu.config.StubGenesisConfigOptions; +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.DataGas; import org.hyperledger.besu.datatypes.Hash; @@ -36,24 +39,33 @@ import org.hyperledger.besu.ethereum.referencetests.ReferenceTestBlockchain; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules; +import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput; import org.hyperledger.besu.ethereum.rlp.RLP; import org.hyperledger.besu.ethereum.worldstate.DefaultMutableWorldState; +import org.hyperledger.besu.evm.AccessListEntry; import org.hyperledger.besu.evm.account.Account; import org.hyperledger.besu.evm.account.AccountStorageEntry; import org.hyperledger.besu.evm.log.Log; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.worldstate.WorldUpdater; import org.hyperledger.besu.evmtool.exception.UnsupportedForkException; +import org.hyperledger.besu.plugin.data.TransactionType; import java.io.IOException; +import java.io.PrintWriter; import java.math.BigInteger; import java.util.ArrayList; import java.util.Comparator; +import java.util.Iterator; import java.util.List; import java.util.NavigableMap; +import java.util.Spliterator; +import java.util.Spliterators; import java.util.concurrent.TimeUnit; +import java.util.stream.StreamSupport; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; @@ -64,6 +76,149 @@ import org.apache.tuweni.units.bigints.UInt256; public class T8nExecutor { + + record RejectedTransaction(int index, String error) {} + + protected static List extractTransactions( + final PrintWriter out, + final Iterator it, + final List transactions, + final List rejections) { + int i = 0; + while (it.hasNext()) { + try { + JsonNode txNode = it.next(); + if (txNode.isTextual()) { + BytesValueRLPInput rlpInput = + new BytesValueRLPInput(Bytes.fromHexString(txNode.asText()), false); + rlpInput.enterList(); + while (!rlpInput.isEndOfCurrentList()) { + Transaction tx = Transaction.readFrom(rlpInput); + transactions.add(tx); + } + } else if (txNode.isObject()) { + if (txNode.has("txBytes")) { + Transaction tx = + Transaction.readFrom(Bytes.fromHexString(txNode.get("txbytes").asText())); + transactions.add(tx); + } else { + Transaction.Builder builder = Transaction.builder(); + int type = Bytes.fromHexStringLenient(txNode.get("type").textValue()).toInt(); + TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type); + builder.type(transactionType); + builder.nonce(Bytes.fromHexStringLenient(txNode.get("nonce").textValue()).toLong()); + builder.gasLimit(Bytes.fromHexStringLenient(txNode.get("gas").textValue()).toLong()); + builder.value(Wei.fromHexString(txNode.get("value").textValue())); + builder.payload(Bytes.fromHexString(txNode.get("input").textValue())); + + if (txNode.has("gasPrice")) { + builder.gasPrice(Wei.fromHexString(txNode.get("gasPrice").textValue())); + } + if (txNode.has("maxPriorityFeePerGas")) { + builder.maxPriorityFeePerGas( + Wei.fromHexString(txNode.get("maxPriorityFeePerGas").textValue())); + } + if (txNode.has("maxFeePerGas")) { + builder.maxFeePerGas(Wei.fromHexString(txNode.get("maxFeePerGas").textValue())); + } + if (txNode.has("maxFeePerDataGas")) { + builder.maxFeePerDataGas( + Wei.fromHexString(txNode.get("maxFeePerDataGas").textValue())); + } + + if (txNode.has("to")) { + builder.to(Address.fromHexString(txNode.get("to").textValue())); + } + + if (transactionType.requiresChainId() + || !txNode.has("protected") + || txNode.get("protected").booleanValue()) { + // chainid if protected + builder.chainId( + new BigInteger( + 1, + Bytes.fromHexStringLenient(txNode.get("chainId").textValue()) + .toArrayUnsafe())); + } + + if (txNode.has("accessList")) { + JsonNode accessList = txNode.get("accessList"); + if (!accessList.isArray()) { + out.printf( + "TX json node unparseable: expected accessList to be an array - %s%n", txNode); + continue; + } + List entries = new ArrayList<>(accessList.size()); + for (JsonNode entryAsJson : accessList) { + Address address = Address.fromHexString(entryAsJson.get("address").textValue()); + List storageKeys = + StreamSupport.stream( + Spliterators.spliteratorUnknownSize( + entryAsJson.get("storageKeys").elements(), Spliterator.ORDERED), + false) + .map(JsonNode::textValue) + .toList(); + var accessListEntry = AccessListEntry.createAccessListEntry(address, storageKeys); + entries.add(accessListEntry); + } + builder.accessList(entries); + } + + if (txNode.has("blobVersionedHashes")) { + JsonNode blobVersionedHashes = txNode.get("blobVersionedHashes"); + if (!blobVersionedHashes.isArray()) { + out.printf( + "TX json node unparseable: expected blobVersionedHashes to be an array - %s%n", + txNode); + continue; + } + // FUTURE: placeholder code until 4844 PR merges + // List entries = new ArrayList<>(blobVersionedHashes.size()); + // for (JsonNode versionedHashNode : blobVersionedHashes) { + // entries.add( + // new VersionedHash(Bytes32.fromHexString(versionedHashNode.textValue()))); + // } + // builder.versionedHashes(entries); + } + + if (txNode.has("secretKey")) { + SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); + KeyPair keys = + signatureAlgorithm.createKeyPair( + signatureAlgorithm.createPrivateKey( + Bytes32.fromHexString(txNode.get("secretKey").textValue()))); + + transactions.add(builder.signAndBuild(keys)); + } else { + BigInteger v = + Bytes.fromHexStringLenient(txNode.get("v").textValue()).toUnsignedBigInteger(); + if (v.compareTo(BigInteger.valueOf(35)) >= 0) { + v = v.subtract(BigInteger.valueOf(35)).mod(BigInteger.TWO); + } else if (v.compareTo(BigInteger.valueOf(27)) >= 0) { + v = v.subtract(BigInteger.valueOf(27)).mod(BigInteger.TWO); + } + builder.signature( + SignatureAlgorithmFactory.getInstance() + .createSignature( + Bytes.fromHexStringLenient(txNode.get("r").textValue()) + .toUnsignedBigInteger(), + Bytes.fromHexStringLenient(txNode.get("s").textValue()) + .toUnsignedBigInteger(), + v.byteValueExact())); + transactions.add(builder.build()); + } + } + } else { + out.printf("TX json node unparseable: %s%n", txNode); + } + } catch (IllegalArgumentException iae) { + rejections.add(new RejectedTransaction(i, iae.getMessage())); + } + i++; + } + return transactions; + } + static T8nResult runTest( final Long chainId, final String fork, @@ -72,6 +227,7 @@ static T8nResult runTest( final ReferenceTestEnv referenceTestEnv, final MutableWorldState initialWorldState, final List transactions, + final List rejections, final TracerManager tracerManager) { final ReferenceTestProtocolSchedules referenceTestProtocolSchedules = @@ -95,7 +251,7 @@ static T8nResult runTest( final Wei dataGasPrice = protocolSpec.getFeeMarket().dataPrice(DataGas.ZERO); List receipts = new ArrayList<>(); - List invalidTransactions = new ArrayList<>(); + List invalidTransactions = new ArrayList<>(rejections); List validTransactions = new ArrayList<>(); ArrayNode receiptsArray = objectMapper.createArrayNode(); long gasUsed = 0; @@ -138,8 +294,7 @@ static T8nResult runTest( } if (result.isInvalid()) { invalidTransactions.add( - new T8nSubCommand.RejectedTransaction( - i, result.getValidationResult().getErrorMessage())); + new RejectedTransaction(i, result.getValidationResult().getErrorMessage())); } else { validTransactions.add(transaction); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java index a93ac8ac7a1..5bbf3199075 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java @@ -15,33 +15,29 @@ */ package org.hyperledger.besu.evmtool; -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 static org.hyperledger.besu.evmtool.T8nExecutor.extractTransactions; + import org.hyperledger.besu.datatypes.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; import org.hyperledger.besu.evm.tracing.OperationTracer; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.evmtool.T8nExecutor.RejectedTransaction; import org.hyperledger.besu.util.LogConfigurator; -import java.math.BigInteger; +import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; import io.vertx.core.Vertx; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; import picocli.CommandLine; @CommandLine.Command( @@ -69,6 +65,7 @@ public void run() { req -> req.bodyHandler( body -> { + ObjectMapper objectMapper = JsonUtils.createObjectMapper(); JsonObject t8nRequest = body.toJsonObject(); JsonObject state = t8nRequest.getJsonObject("state"); String fork = state.getString("fork"); @@ -81,18 +78,27 @@ public void run() { ReferenceTestWorldState initialWorldState = input.getJsonObject("alloc").mapTo(ReferenceTestWorldState.class); initialWorldState.persist(null); - List transactions = Collections.emptyList(); + List transactions = new ArrayList<>(); + List rejections = new ArrayList<>(); Object txs = input.getValue("txs"); if (txs != null) { if (txs instanceof JsonArray txsArray) { - transactions = extractTransactions(txsArray); + extractTransactions( + new PrintWriter(System.err, true, StandardCharsets.UTF_8), + txsArray.stream().map(s -> (JsonNode) s).iterator(), + transactions, + rejections); } else if (txs instanceof String tx) { transactions = - extractTransactions(new JsonArray().add(removeSurrounding("\"", tx))); + extractTransactions( + new PrintWriter(System.err, true, StandardCharsets.UTF_8), + List.of(new TextNode(removeSurrounding("\"", tx))) + .iterator(), + transactions, + rejections); } } - ObjectMapper objectMapper = JsonUtils.createObjectMapper(); final T8nExecutor.T8nResult result = T8nExecutor.runTest( chainId, @@ -102,6 +108,7 @@ public void run() { referenceTestEnv, initialWorldState, transactions, + rejections, new T8nExecutor.TracerManager() { @Override public OperationTracer getManagedTracer( @@ -138,72 +145,6 @@ public void disposeTracer(final OperationTracer tracer) { err -> System.err.println("Failed to start transition server: " + err.getMessage())); } - private List extractTransactions(final JsonArray jsonArray) { - List transactions = new ArrayList<>(); - for (int i = 0; i < jsonArray.size(); i++) { - Object rawTx = jsonArray.getValue(i); - if (rawTx instanceof String txNode) { - BytesValueRLPInput rlpInput = new BytesValueRLPInput(Bytes.fromHexString(txNode), false); - rlpInput.enterList(); - while (!rlpInput.isEndOfCurrentList()) { - Transaction tx = Transaction.readFrom(rlpInput); - transactions.add(tx); - } - } else if (rawTx instanceof JsonObject txNode) { - if (txNode.containsKey("txBytes")) { - JsonObject txBytesNode = txNode.getJsonObject("txBytes"); - Transaction tx = - Transaction.readFrom(Bytes.fromHexString(txBytesNode.getString("txbytes"))); - transactions.add(tx); - } else { - Transaction.Builder builder = Transaction.builder(); - int type = Bytes.fromHexStringLenient(txNode.getString("type")).toInt(); - TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type); - builder.type(transactionType); - builder.nonce(Bytes.fromHexStringLenient(txNode.getString("nonce")).toLong()); - builder.gasPrice(Wei.fromHexString(txNode.getString("gasPrice"))); - builder.gasLimit(Bytes.fromHexStringLenient(txNode.getString("gas")).toLong()); - builder.value(Wei.fromHexString(txNode.getString("value"))); - builder.payload(Bytes.fromHexString(txNode.getString("input"))); - if (txNode.containsKey("to")) { - builder.to(Address.fromHexString(txNode.getString("to"))); - } - - if (transactionType.requiresChainId() - || !txNode.containsKey("protected") - || txNode.getBoolean("protected")) { - // chainid if protected - builder.chainId( - new BigInteger( - 1, Bytes.fromHexStringLenient(txNode.getString("chainId")).toArrayUnsafe())); - } - - if (txNode.containsKey("secretKey")) { - SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); - KeyPair keys = - signatureAlgorithm.createKeyPair( - signatureAlgorithm.createPrivateKey( - Bytes32.fromHexString(txNode.getString("secretKey")))); - - transactions.add(builder.signAndBuild(keys)); - } else { - builder.signature( - SignatureAlgorithmFactory.getInstance() - .createSignature( - Bytes.fromHexString(txNode.getString("r")).toUnsignedBigInteger(), - Bytes.fromHexString(txNode.getString("s")).toUnsignedBigInteger(), - Bytes.fromHexString(txNode.getString("v")) - .toUnsignedBigInteger() - .subtract(Transaction.REPLAY_UNPROTECTED_V_BASE) - .byteValueExact())); - transactions.add(builder.build()); - } - } - } - } - return transactions; - } - private static String removeSurrounding(final String delimiter, final String message) { if (message.startsWith(delimiter) && message.endsWith(delimiter)) { return message.substring(delimiter.length(), message.length() - delimiter.length()); diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java index 426c34e2514..dbf5a59756c 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nSubCommand.java @@ -19,28 +19,20 @@ import static org.hyperledger.besu.evmtool.T8nSubCommand.COMMAND_ALIAS; import static org.hyperledger.besu.evmtool.T8nSubCommand.COMMAND_NAME; -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.Hash; -import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv; import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState; -import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput; -import org.hyperledger.besu.evm.AccessListEntry; import org.hyperledger.besu.evm.tracing.OperationTracer; import org.hyperledger.besu.evm.tracing.StandardJsonTracer; -import org.hyperledger.besu.plugin.data.TransactionType; +import org.hyperledger.besu.evmtool.T8nExecutor.RejectedTransaction; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; -import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.ArrayList; @@ -49,10 +41,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Spliterator; -import java.util.Spliterators; import java.util.Stack; -import java.util.stream.StreamSupport; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; @@ -60,8 +49,6 @@ import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectWriter; import com.fasterxml.jackson.databind.node.ObjectNode; -import org.apache.tuweni.bytes.Bytes; -import org.apache.tuweni.bytes.Bytes32; import picocli.CommandLine.Command; import picocli.CommandLine.IParameterConsumer; import picocli.CommandLine.Model.ArgSpec; @@ -79,8 +66,6 @@ versionProvider = VersionProvider.class) public class T8nSubCommand implements Runnable { - record RejectedTransaction(int index, String error) {} - static final String COMMAND_NAME = "transition"; static final String COMMAND_ALIAS = "t8n"; private static final Path stdoutPath = Path.of("stdout"); @@ -187,7 +172,8 @@ public void run() { MutableWorldState initialWorldState; ReferenceTestEnv referenceTestEnv; - List transactions; + List transactions = new ArrayList<>(); + List rejections = new ArrayList<>(); try { ObjectNode config; if (env.equals(stdinPath) || alloc.equals(stdinPath) || txs.equals(stdinPath)) { @@ -229,7 +215,7 @@ public void run() { it = List.of(node).iterator(); } - transactions = extractTransactions(it); + T8nExecutor.extractTransactions(parentCommand.out, it, transactions, rejections); if (!outDir.toString().isBlank()) { outDir.toFile().mkdirs(); } @@ -299,6 +285,7 @@ public void disposeTracer(final OperationTracer tracer) { referenceTestEnv, initialWorldState, transactions, + rejections, tracerManager); try { @@ -340,96 +327,4 @@ public void disposeTracer(final OperationTracer tracer) { ioe.printStackTrace(System.err); } } - - private List extractTransactions(final Iterator it) { - List transactions = new ArrayList<>(); - while (it.hasNext()) { - JsonNode txNode = it.next(); - if (txNode.isTextual()) { - BytesValueRLPInput rlpInput = - new BytesValueRLPInput(Bytes.fromHexString(txNode.asText()), false); - rlpInput.enterList(); - while (!rlpInput.isEndOfCurrentList()) { - Transaction tx = Transaction.readFrom(rlpInput); - transactions.add(tx); - } - } else if (txNode.isObject()) { - if (txNode.has("txBytes")) { - Transaction tx = - Transaction.readFrom(Bytes.fromHexString(txNode.get("txbytes").asText())); - transactions.add(tx); - } else { - Transaction.Builder builder = Transaction.builder(); - int type = Bytes.fromHexStringLenient(txNode.get("type").textValue()).toInt(); - TransactionType transactionType = TransactionType.of(type == 0 ? 0xf8 : type); - builder.type(transactionType); - builder.nonce(Bytes.fromHexStringLenient(txNode.get("nonce").textValue()).toLong()); - builder.gasPrice(Wei.fromHexString(txNode.get("gasPrice").textValue())); - builder.gasLimit(Bytes.fromHexStringLenient(txNode.get("gas").textValue()).toLong()); - builder.value(Wei.fromHexString(txNode.get("value").textValue())); - builder.payload(Bytes.fromHexString(txNode.get("input").textValue())); - if (txNode.has("to")) { - builder.to(Address.fromHexString(txNode.get("to").textValue())); - } - - if (transactionType.requiresChainId() - || !txNode.has("protected") - || txNode.get("protected").booleanValue()) { - // chainid if protected - builder.chainId( - new BigInteger( - 1, - Bytes.fromHexStringLenient(txNode.get("chainId").textValue()).toArrayUnsafe())); - } - - if (txNode.has("accessList")) { - JsonNode accessList = txNode.get("accessList"); - if (!accessList.isArray()) { - parentCommand.out.printf( - "TX json node unparseable: expected accessList to be an array - %s%n", txNode); - continue; - } - List entries = new ArrayList<>(accessList.size()); - for (JsonNode entryAsJson : accessList) { - Address address = Address.fromHexString(entryAsJson.get("address").textValue()); - List storageKeys = - StreamSupport.stream( - Spliterators.spliteratorUnknownSize( - entryAsJson.get("storageKeys").elements(), Spliterator.ORDERED), - false) - .map(JsonNode::textValue) - .toList(); - var accessListEntry = AccessListEntry.createAccessListEntry(address, storageKeys); - entries.add(accessListEntry); - } - builder.accessList(entries); - } - - if (txNode.has("secretKey")) { - SignatureAlgorithm signatureAlgorithm = SignatureAlgorithmFactory.getInstance(); - KeyPair keys = - signatureAlgorithm.createKeyPair( - signatureAlgorithm.createPrivateKey( - Bytes32.fromHexString(txNode.get("secretKey").textValue()))); - - transactions.add(builder.signAndBuild(keys)); - } else { - builder.signature( - SignatureAlgorithmFactory.getInstance() - .createSignature( - Bytes.fromHexString(txNode.get("r").textValue()).toUnsignedBigInteger(), - Bytes.fromHexString(txNode.get("s").textValue()).toUnsignedBigInteger(), - Bytes.fromHexString(txNode.get("v").textValue()) - .toUnsignedBigInteger() - .subtract(Transaction.REPLAY_UNPROTECTED_V_BASE) - .byteValueExact())); - transactions.add(builder.build()); - } - } - } else { - parentCommand.out.printf("TX json node unparseable: %s%n", txNode); - } - } - return transactions; - } } diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json index 3de9d7ed247..1a3c7a178c6 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-calculate-difficulty.json @@ -51,7 +51,7 @@ "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0x87c5fa7cef8b99fc333b662c1a4306c7d41d9d43a23414b15aa25b3e093ae88f" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json index 3de9d7ed247..1a3c7a178c6 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/berlin-example-yul.json @@ -51,7 +51,7 @@ "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0x87c5fa7cef8b99fc333b662c1a4306c7d41d9d43a23414b15aa25b3e093ae88f" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json new file mode 100644 index 00000000000..8ee3e7b21ad --- /dev/null +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/cancun-blobs-per-tx.json @@ -0,0 +1,105 @@ +{ + "cli": [ + "t8n", + "--input.alloc=stdin", + "--input.txs=stdin", + "--input.env=stdin", + "--output.result=stdout", + "--output.alloc=stdout", + "--output.body=txs.rlp", + "--state.fork=Cancun", + "--state.chainid=1", + "--state.reward=0" + ], + "stdin": { + "alloc": { + "0x0000000000000000000000000000000000000200": { + "balance": "0x1" + }, + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "balance": "0x3b908bc7", + "nonce": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x43e39" + } + }, + "txs": [ + { + "type": "0x3", + "chainId": "0x1", + "nonce": "0x0", + "maxPriorityFeePerGas": "0x0", + "maxFeePerGas": "0x7", + "gas": "0x5208", + "value": "0x1", + "input": "0x", + "to": "0x0000000000000000000000000000000000000100", + "accessList": [], + "protected": true, + "maxFeePerDataGas": "0x1", + "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "blobVersionedHashes": [ + "0x0100000000000000000000000000000000000000000000000000000000000000" + ], + "v": "0x1", + "r": "0xa8f4757869fbb831ba4ed3a7c8f868b0e2e0c1eda97937aab035560fffdedf3c", + "s": "0x19d9b041540e3d6f5f56dc29deb8834a08171e92037cf567b922357e70f8e54a" + } + ], + "env": { + "currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba", + "currentGasLimit": "100000000000000000", + "currentNumber": "2", + "currentTimestamp": "24", + "currentRandom": "0", + "currentDifficulty": "0", + "parentDifficulty": "0", + "parentBaseFee": "7", + "parentGasUsed": "21000", + "parentGasLimit": "100000000000000000", + "parentTimestamp": "12", + "blockHashes": { + "0": "0x7801ae59edc1754a571e2eb418e8e8a44079b1e7ce3cd032cd3169973deb6be9", + "1": "0xe67fa9e2865de83bcff54ca002c4b9dcde6cd094367ed4e85f28c1298fdb23a5" + }, + "ommers": [], + "withdrawals": [], + "parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "currentExcessDataGas": "0", + "currentDataGasUsed": "0" + } + }, + "stdout": { + "alloc": { + "0x0000000000000000000000000000000000000200": { + "balance": "0x1" + }, + "0x8a0a19589531694250d570040a0c4b74576919b8": { + "balance": "0x3b908bc7", + "nonce": "0x1" + }, + "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": { + "balance": "0x43e39" + } + }, + "result": { + "stateRoot": "0xa6c91f68d20d3b6137ca1184a3995344256f0b53410b3577c9ab0a764a782cfb", + "txRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", + "logsHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "receipts": [], + "rejected": [ + { + "index": 0, + "error": "Unsupported transaction type 3" + } + ], + "currentDifficulty": null, + "gasUsed": "0x0", + "currentBaseFee": "0x7", + "withdrawalsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421" + } + } +} \ No newline at end of file diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json index 7146666176f..d3dd7021df7 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/istanbul-cumulative-gas.json @@ -366,7 +366,7 @@ "parentDifficulty": "131072", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0xa2886eb8890eda7143a5d6bcb16949db9f3871f4c2dcc8618ab62c0632a23ab7" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json index dcfe6a32b82..052ebb5260b 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/london-env-no-basefee.json @@ -52,7 +52,7 @@ "parentBaseFee": "7", "parentGasUsed": "50000000000000000", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0xe3c84688fa32c20955c535c7d25b5b4b196079e40a9c47c9cb1edb5e58b3dce5" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json index c393d1cef2b..e1c331206d2 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-blockhash.json @@ -51,7 +51,7 @@ "parentDifficulty": "0", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "12", + "parentTimestamp": "12", "blockHashes": { "0": "0x651666d6d8727a6478a750dc8406c1bda0be85abc99094dca694807fa772f83c", "1": "0x0275fc82fe832100726ec7c26078ffb1c1dbff14a3b52d93dc359768fc8c7baa" diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json index 3c398c92de6..d33e96bfd53 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-init-code.json @@ -47,7 +47,7 @@ "parentBaseFee": "7", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0xea2d7e0192d890c222f0302d972a02db0bf0c6d08257d73aa1210d08d24f30c3" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json index d967e398ef6..3bf5beaae52 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-no-nonce.json @@ -45,7 +45,7 @@ "parentDifficulty": "0", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "12", + "parentTimestamp": "12", "blockHashes": { "0": "0x651666d6d8727a6478a750dc8406c1bda0be85abc99094dca694807fa772f83c", "1": "0x0275fc82fe832100726ec7c26078ffb1c1dbff14a3b52d93dc359768fc8c7baa" diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json index ca3eed9f676..8f8b29b7525 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals-overflow.json @@ -38,7 +38,7 @@ "parentBaseFee": "7", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0xfc63c00c7fe67bcc6ae52ea4eed5ff00b8673b1afb581d090c34b5fa6eca9467" }, diff --git a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json index 6e3769bef22..046a9194cdf 100644 --- a/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json +++ b/ethereum/evmtool/src/test/resources/org/hyperledger/besu/evmtool/t8n/shanghai-withdrawals.json @@ -41,7 +41,7 @@ "parentBaseFee": "7", "parentGasUsed": "0", "parentGasLimit": "100000000000000000", - "parentTimstamp": "0", + "parentTimestamp": "0", "blockHashes": { "0": "0x651666d6d8727a6478a750dc8406c1bda0be85abc99094dca694807fa772f83c" }, diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java index 7898960c384..cc0d6d7d5c3 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java @@ -19,6 +19,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import org.hyperledger.besu.datatypes.Address; +import org.hyperledger.besu.datatypes.DataGas; import org.hyperledger.besu.datatypes.GWei; import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Wei; @@ -39,7 +40,6 @@ import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.google.common.base.Strings; import org.apache.tuweni.bytes.Bytes; @@ -47,7 +47,6 @@ import org.apache.tuweni.units.bigints.UInt64; /** A memory holder for testing. */ -@JsonIgnoreProperties(ignoreUnknown = true) public class ReferenceTestEnv extends BlockHeader { public record EnvWithdrawal( @@ -79,6 +78,10 @@ Withdrawal asWithdrawal() { private final Map blockHashes; + private final String parentExcessDataGas; + + private final String parentDataGasUsed; + /** * Public constructor. * @@ -105,8 +108,14 @@ public ReferenceTestEnv( @JsonProperty("parentGasUsed") final String parentGasUsed, @JsonProperty("parentGasLimit") final String parentGasLimit, @JsonProperty("parentTimestamp") final String parentTimestamp, + @JsonProperty("ommers") final List _ommers, + @JsonProperty("parentUncleHash") final String _parentUncleHash, @JsonProperty("withdrawals") final List withdrawals, - @JsonProperty("blockHashes") final Map blockHashes) { + @JsonProperty("blockHashes") final Map blockHashes, + @JsonProperty("currentExcessDataGas") final String currentExcessDataGas, + @JsonProperty("currentDataGasUsed") final String currentDataGasUsed, + @JsonProperty("parentExcessDataGas") final String parentExcessDataGas, + @JsonProperty("parentDataGasUsed") final String parentDataGasUsed) { super( generateTestBlockHash(previousHash, number), Hash.EMPTY_LIST_HASH, // ommersHash @@ -125,14 +134,16 @@ public ReferenceTestEnv( Optional.ofNullable(random).map(Difficulty::fromHexString).orElse(Difficulty.ZERO), 0L, null, // withdrawalsRoot + currentExcessDataGas == null ? null : DataGas.fromHexString(currentExcessDataGas), null, // depositsRoot - null, new MainnetBlockHeaderFunctions()); this.parentDifficulty = parentDifficulty; this.parentBaseFee = parentBaseFee; this.parentGasUsed = parentGasUsed; this.parentGasLimit = parentGasLimit; this.parentTimestamp = parentTimestamp; + this.parentExcessDataGas = parentExcessDataGas; + this.parentDataGasUsed = parentDataGasUsed; this.withdrawals = withdrawals == null ? List.of() @@ -217,6 +228,8 @@ public boolean equals(final Object o) { && Objects.equals(parentGasUsed, that.parentGasUsed) && Objects.equals(parentGasLimit, that.parentGasLimit) && Objects.equals(parentTimestamp, that.parentTimestamp) + && Objects.equals(parentDataGasUsed, that.parentDataGasUsed) + && Objects.equals(parentExcessDataGas, that.parentExcessDataGas) && Objects.equals(withdrawals, that.withdrawals); } @@ -229,6 +242,8 @@ public int hashCode() { parentGasUsed, parentGasLimit, parentTimestamp, + parentDataGasUsed, + parentExcessDataGas, withdrawals); } } diff --git a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java index 0ec30b0959f..4f5a7d7b7c2 100644 --- a/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java +++ b/ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestProtocolSchedules.java @@ -74,6 +74,9 @@ public static ReferenceTestProtocolSchedules create(final StubGenesisConfigOptio builder.put("GrayGlacier", createSchedule(genesisStub.clone().grayGlacierBlock(0))); builder.put("Merge", createSchedule(genesisStub.clone().mergeNetSplitBlock(0))); builder.put("Shanghai", createSchedule(genesisStub.clone().shanghaiTime(0))); + builder.put( + "ShanghaiToCancunAtTime15k", + createSchedule(genesisStub.clone().shanghaiTime(0).cancunTime(15000))); builder.put("Cancun", createSchedule(genesisStub.clone().cancunTime(0))); builder.put("Future_EIPs", createSchedule(genesisStub.clone().futureEipsTime(0))); builder.put("Experimental_EIPs", createSchedule(genesisStub.clone().experimentalEipsTime(0)));