EIP-2935 Nyota updates (#7120)

Bring implementation up to nyota version of the EIP,
and remove invasive change into the EVM code.

Signed-off-by: Danno Ferrin <danno@numisight.com>

Co-authored-by: Lucas Saldanha <lucascrsaldanha@gmail.com>
Co-authored-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
Co-authored-by: Justin Florentine <justin+github@florentine.us>
Co-authored-by: Jason Frame <jason.frame@consensys.net>
Co-authored-by: Jason Frame <jasonwframe@gmail.com>
This commit is contained in:
Danno Ferrin
2024-05-20 00:56:51 -06:00
committed by GitHub
parent d7123ce5b4
commit 0cca642bc5
56 changed files with 191 additions and 422 deletions

View File

@@ -14,7 +14,7 @@
"executionPayload": {
"parentHash": "0x74e8ce9d96d325a605675a34175adfa34581f35091dcd7b107c525a82b0b9950",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x3057566307e82861160cd217c71c18a93023a752d268113a4e50148fe6f19be6",
"stateRoot": "0x546ac65b9d37c72d7185f8dd67419803c636dd4e5ddf9b325fb64e9ecf570871",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@@ -30,14 +30,14 @@
"withdrawalRequests": [
{
"sourceAddress": "0xa4664c40aacebd82a2db79f0ea36c06bc6a19adb",
"amount" : "0x0",
"validatorPublicKey": "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"
"validatorPublicKey": "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e",
"amount": "0x0"
}
],
"blockNumber": "0x2",
"blockHash": "0xdce2f62925b5ebb218943e71fa87af2aaeb6dab2d8aee12ea7f9f24eeae7b4c7",
"blobGasUsed": "0x0",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
"blockHash": "0xa7a92cc82e1d876476ad6433538599b0d592f88ba0823c23e80af93fb1748f14",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0"
},
"blockValue": "0x0",
"blobsBundle": {

View File

@@ -4,7 +4,7 @@
"method": "engine_newPayloadV4",
"params": [
{
"parentHash": "0x45811fa27a100ce9035e5e086b9669275041a4ec0ebbd920be028fd7b0aa2356",
"parentHash": "0xa7a92cc82e1d876476ad6433538599b0d592f88ba0823c23e80af93fb1748f14",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x9b8c4a9a86cb49252075c0db2f0e72fb1e49350a0f70ea36f26f700201961e62",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
@@ -17,9 +17,9 @@
"excessBlobGas": "0x0",
"transactions": [],
"withdrawals": [],
"depositRequests" : null,
"depositRequests": null,
"blockNumber": "0x2",
"blockHash": "0xf6c3f1180ba58d6ea4c69c9328c7afb1fda41df06c368741c1f8310567879de7",
"blockHash": "0x2331b2dc9c453e9a33685099742cbbcd529d42bd5681969f45754f06866c6766",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0"
},
@@ -34,7 +34,7 @@
"error": {
"code": -32602,
"message": "Invalid params",
"data" : "Missing deposit field"
"data": "Missing deposit field"
}
},
"statusCode": 200

View File

@@ -6,7 +6,7 @@
{
"parentHash": "0x74e8ce9d96d325a605675a34175adfa34581f35091dcd7b107c525a82b0b9950",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x778ccbc3adc59876b76489cdc1a2ff76ef2a31ae9d3bf761bc55bbab7d59c489",
"stateRoot": "0xdb2a9bb9097dd6946525203a14437cd925ef549289e1fe17c6ed845c53647a26",
"logsBloom": "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@@ -31,12 +31,12 @@
"withdrawalRequests": [
{
"sourceAddress": "0xa4664c40aacebd82a2db79f0ea36c06bc6a19adb",
"amount" : "0x0",
"amount": "0x0",
"validatorPublicKey": "0xb10a4a15bf67b328c9b101d09e5c6ee6672978fdad9ef0d9e2ceffaee99223555d8601f0cb3bcc4ce1af9864779a416e"
}
],
"blockNumber": "0x2",
"blockHash": "0xb56ecf32963d4160799d4db6fe3723f01226635d058ab86a11eaa9f8234af852",
"blockHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"receiptsRoot": "0x79ee3424eb720a3ad4b1c5a372bb8160580cbe4d893778660f34213c685627a9",
"blobGasUsed": "0x0"
},
@@ -50,7 +50,7 @@
"id": 67,
"result": {
"status": "VALID",
"latestValidHash": "0xb56ecf32963d4160799d4db6fe3723f01226635d058ab86a11eaa9f8234af852",
"latestValidHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"validationError": null
}
},

View File

@@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3",
"params": [
{
"headBlockHash": "0xb56ecf32963d4160799d4db6fe3723f01226635d058ab86a11eaa9f8234af852",
"safeBlockHash": "0xb56ecf32963d4160799d4db6fe3723f01226635d058ab86a11eaa9f8234af852",
"finalizedBlockHash": "0xb56ecf32963d4160799d4db6fe3723f01226635d058ab86a11eaa9f8234af852"
"headBlockHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"safeBlockHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"finalizedBlockHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d"
},
{
"timestamp": "0x30",
@@ -24,11 +24,11 @@
"result": {
"payloadStatus": {
"status": "VALID",
"latestValidHash": "0xb56ecf32963d4160799d4db6fe3723f01226635d058ab86a11eaa9f8234af852",
"latestValidHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"validationError": null
},
"payloadId": "0x282643ead6ad5331"
"payloadId": "0x282643e2da21a7cf"
}
},
"statusCode" : 200
"statusCode": 200
}

View File

@@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV4",
"params": [
"0x282643ead6ad5331"
"0x282643e2da21a7cf"
],
"id": 67
},
@@ -12,9 +12,9 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0xb56ecf32963d4160799d4db6fe3723f01226635d058ab86a11eaa9f8234af852",
"parentHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x61d2011dc13b003c48193f0902653fd4f7b67fa949dc0fa6eab9e69e349700fd",
"stateRoot": "0xcd9f15de5f17cf87a02bf795a0dc98c108eead4651eca57fc7195bda0d9c20ee",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@@ -29,7 +29,7 @@
"depositRequests": [],
"withdrawalRequests": [],
"blockNumber": "0x3",
"blockHash": "0x7a619ef406633a6d6589602009b5d242e1273fd8259cebcac4ab006edfdf81f9",
"blockHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"blobGasUsed": "0x0"
},

View File

@@ -4,9 +4,9 @@
"method": "engine_newPayloadV3",
"params": [
{
"parentHash": "0xb56ecf32963d4160799d4db6fe3723f01226635d058ab86a11eaa9f8234af852",
"parentHash": "0x5200df2eb24d08e7bceec64194d073e81a6e9c00c4f61d323fad5d70b40e6d6d",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x61d2011dc13b003c48193f0902653fd4f7b67fa949dc0fa6eab9e69e349700fd",
"stateRoot": "0xcd9f15de5f17cf87a02bf795a0dc98c108eead4651eca57fc7195bda0d9c20ee",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@@ -19,7 +19,7 @@
"depositRequests": [],
"withdrawalRequests": [],
"blockNumber": "0x3",
"blockHash": "0x7a619ef406633a6d6589602009b5d242e1273fd8259cebcac4ab006edfdf81f9",
"blockHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
"excessBlobGas": "0x0",
"blobGasUsed": "0x0"
@@ -34,7 +34,7 @@
"id": 67,
"result": {
"status": "VALID",
"latestValidHash": "0x7a619ef406633a6d6589602009b5d242e1273fd8259cebcac4ab006edfdf81f9",
"latestValidHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"validationError": null
}
},

View File

@@ -4,9 +4,9 @@
"method": "engine_forkchoiceUpdatedV3",
"params": [
{
"headBlockHash": "0x7a619ef406633a6d6589602009b5d242e1273fd8259cebcac4ab006edfdf81f9",
"safeBlockHash": "0x7a619ef406633a6d6589602009b5d242e1273fd8259cebcac4ab006edfdf81f9",
"finalizedBlockHash": "0x7a619ef406633a6d6589602009b5d242e1273fd8259cebcac4ab006edfdf81f9"
"headBlockHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"safeBlockHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"finalizedBlockHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42"
},
{
"timestamp": "0x40",
@@ -24,11 +24,11 @@
"result": {
"payloadStatus": {
"status": "VALID",
"latestValidHash": "0x7a619ef406633a6d6589602009b5d242e1273fd8259cebcac4ab006edfdf81f9",
"latestValidHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"validationError": null
},
"payloadId": "0x2826438a3f8a7741"
"payloadId": "0x282643de0e3d43bf"
}
},
"statusCode" : 200
"statusCode": 200
}

View File

@@ -3,7 +3,7 @@
"jsonrpc": "2.0",
"method": "engine_getPayloadV4",
"params": [
"0x2826438a3f8a7741"
"0x282643de0e3d43bf"
],
"id": 67
},
@@ -12,9 +12,9 @@
"id": 67,
"result": {
"executionPayload": {
"parentHash": "0x7a619ef406633a6d6589602009b5d242e1273fd8259cebcac4ab006edfdf81f9",
"parentHash": "0x79858f6eb8e82f0ec11087983ce4eb8c7edc10c9363a2a124dd78fd2c305dc42",
"feeRecipient": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"stateRoot": "0x847db08c6b9e6dcc91288bd963eb5623aea5387232016ef81fddb3ebc994c72f",
"stateRoot": "0xe4642cc58d61f2392fe056042c226e286f22a25e3104f4a4acb423dad9a43311",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"prevRandao": "0x0000000000000000000000000000000000000000000000000000000000000000",
"gasLimit": "0x1c9c380",
@@ -37,9 +37,9 @@
}
],
"blockNumber": "0x4",
"blobGasUsed": "0x0",
"receiptsRoot": "0x765bd9d63cc10fa47117d6cc0958f15e55a3bde540d4ed15d220f573fbb82cba",
"blockHash": "0xd0b81acdb3016abbc05599b083c8b090323efaf0b2aeab8d0755780e20214159"
"blobGasUsed": "0x0",
"blockHash": "0xb2d60adb2a0c73313ebdacf425b1d6bbd810c3ec6b28ad0d62a73cdc34cb696a"
},
"blockValue": "0x12855dcd153473b",
"blobsBundle": {

View File

@@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.Unstable;
import org.hyperledger.besu.plugin.data.BlockTraceResult;
@@ -216,7 +217,7 @@ public class TraceServiceImpl implements TraceService {
transaction,
protocolSpec.getMiningBeneficiaryCalculator().calculateBeneficiary(header),
tracer,
protocolSpec.getBlockHashProcessor().getBlockHashLookup(header, blockchain),
new CachingBlockHashLookup(header, blockchain),
false,
blobGasPrice);

View File

@@ -15,7 +15,6 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.Wei;
@@ -27,7 +26,9 @@ import org.hyperledger.besu.ethereum.debug.TraceFrame;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import java.util.List;
import java.util.Optional;
@@ -94,8 +95,7 @@ public class ExecuteTransactionStep implements Function<TransactionTrace, Transa
maybeParentHeader
.map(parent -> calculateExcessBlobGasForParent(protocolSpec, parent))
.orElse(BlobGas.ZERO));
final BlockHashLookup blockHashLookup =
protocolSpec.getBlockHashProcessor().getBlockHashLookup(header, blockchain);
final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(header, blockchain);
result =
transactionProcessor.processTransaction(
chainUpdater.getNextUpdater(),

View File

@@ -15,7 +15,6 @@
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.processor;
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.Hash;
@@ -31,6 +30,8 @@ import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import java.util.List;
import java.util.Optional;
@@ -89,8 +90,7 @@ public class BlockReplay {
return performActionWithBlock(
blockHash,
(body, header, blockchain, transactionProcessor, protocolSpec) -> {
final BlockHashLookup blockHashLookup =
protocolSpec.getBlockHashProcessor().getBlockHashLookup(header, blockchain);
final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(header, blockchain);
final Wei blobGasPrice =
protocolSpec
.getFeeMarket()
@@ -137,7 +137,7 @@ public class BlockReplay {
blockHeader,
transaction,
spec.getMiningBeneficiaryCalculator().calculateBeneficiary(blockHeader),
spec.getBlockHashProcessor().getBlockHashLookup(blockHeader, blockchain),
new CachingBlockHashLookup(blockHeader, blockchain),
false,
TransactionValidationParams.blockReplay(),
blobGasPrice);
@@ -180,10 +180,6 @@ public class BlockReplay {
return Optional.empty();
}
public ProtocolSpec getProtocolSpec(final BlockHeader header) {
return protocolSchedule.getByBlockHeader(header);
}
@FunctionalInterface
public interface BlockAction<T> {
Optional<T> perform(

View File

@@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.debug.TraceFrame;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@@ -68,10 +69,7 @@ public class BlockTracer {
transaction,
header.getCoinbase(),
tracer,
blockReplay
.getProtocolSpec(header)
.getBlockHashProcessor()
.getBlockHashLookup(header, blockchain),
new CachingBlockHashLookup(header, blockchain),
false,
blobGasPrice);
final List<TraceFrame> traceFrames = tracer.copyTraceFrames();

View File

@@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.debug.TraceOptions;
import org.hyperledger.besu.ethereum.mainnet.ImmutableTransactionValidationParams;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.tracing.StandardJsonTracer;
@@ -191,10 +192,7 @@ public class TransactionTracer {
transaction,
header.getCoinbase(),
tracer,
blockReplay
.getProtocolSpec(header)
.getBlockHashProcessor()
.getBlockHashLookup(header, blockchain),
new CachingBlockHashLookup(header, blockchain),
false,
ImmutableTransactionValidationParams.builder().isAllowFutureNonce(true).build(),
blobGasPrice);

View File

@@ -36,7 +36,6 @@ import org.hyperledger.besu.ethereum.debug.TraceFrame;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.blockhash.BlockHashProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
@@ -88,7 +87,6 @@ public class TransactionTracerTest {
@Mock private ProtocolSpec protocolSpec;
@Mock private GasCalculator gasCalculator;
@Mock private BlockHashProcessor blockHashProcessor;
@Mock private Tracer.TraceableState mutableWorldState;
@@ -125,7 +123,6 @@ public class TransactionTracerTest {
when(protocolSpec.getFeeMarket()).thenReturn(FeeMarket.london(0L));
when(blockchain.getChainHeadHeader()).thenReturn(blockHeader);
when(protocolSpec.getGasCalculator()).thenReturn(gasCalculator);
when(protocolSpec.getBlockHashProcessor()).thenReturn(blockHashProcessor);
when(protocolContext.getBadBlockManager()).thenReturn(badBlockManager);
lenient().when(gasCalculator.computeExcessBlobGas(anyLong(), anyInt())).thenReturn(0L);
}

View File

@@ -14,7 +14,6 @@
*/
package org.hyperledger.besu.ethereum.blockcreation.txselection;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.BLOCK_SELECTION_TIMEOUT;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.SELECTED;
import static org.hyperledger.besu.plugin.data.TransactionSelectionResult.TX_EVALUATION_TOO_LONG;
@@ -43,7 +42,9 @@ import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.mainnet.blockhash.BlockHashProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.TransactionSelectionResult;
import org.hyperledger.besu.plugin.services.tracer.BlockAwareOperationTracer;
@@ -326,9 +327,7 @@ public class BlockTransactionSelector {
private TransactionProcessingResult processTransaction(
final PendingTransaction pendingTransaction, final WorldUpdater worldStateUpdater) {
final BlockHashLookup blockHashLookup =
blockSelectionContext
.blockHashProcessor()
.getBlockHashLookup(blockSelectionContext.processableBlockHeader(), blockchain);
new CachingBlockHashLookup(blockSelectionContext.processableBlockHeader(), blockchain);
return transactionProcessor.processTransaction(
worldStateUpdater,
blockSelectionContext.processableBlockHeader(),

View File

@@ -16,7 +16,6 @@ package org.hyperledger.besu.ethereum.mainnet.precompiles.privacy;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.eq;
@@ -47,6 +46,7 @@ import org.hyperledger.besu.ethereum.rlp.BytesValueRLPOutput;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;

View File

@@ -33,7 +33,6 @@ import org.hyperledger.besu.ethereum.debug.TraceFrame;
import org.hyperledger.besu.ethereum.debug.TraceOptions;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.rlp.BytesValueRLPInput;
@@ -74,13 +73,11 @@ public class TraceTransactionIntegrationTest {
blockchain = contextTestFixture.getBlockchain();
worldStateArchive = contextTestFixture.getStateArchive();
final ProtocolSchedule protocolSchedule = contextTestFixture.getProtocolSchedule();
ProtocolSpec protocolSpec =
protocolSchedule.getByBlockHeader(new BlockHeaderTestFixture().number(0L).buildHeader());
transactionProcessor = protocolSpec.getTransactionProcessor();
blockHashLookup =
protocolSpec
.getBlockHashProcessor()
.getBlockHashLookup(genesisBlock.getHeader(), blockchain);
transactionProcessor =
protocolSchedule
.getByBlockHeader(new BlockHeaderTestFixture().number(0L).buildHeader())
.getTransactionProcessor();
blockHashLookup = new CachingBlockHashLookup(genesisBlock.getHeader(), blockchain);
}
@Test

View File

@@ -35,6 +35,7 @@ import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.trie.MerkleTrieException;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldState;
import org.hyperledger.besu.ethereum.trie.diffbased.bonsai.worldview.BonsaiWorldStateUpdateAccumulator;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldState;
@@ -114,8 +115,7 @@ public abstract class AbstractBlockProcessor implements BlockProcessor {
final WorldUpdater worldStateUpdater = worldState.updater();
final BlockHashLookup blockHashLookup =
protocolSpec.getBlockHashProcessor().getBlockHashLookup(blockHeader, blockchain);
final BlockHashLookup blockHashLookup = new CachingBlockHashLookup(blockHeader, blockchain);
final Address miningBeneficiary =
miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);

View File

@@ -183,7 +183,6 @@ public class ClassicProtocolSpecs {
messageCallProcessor,
true,
false,
false,
stackSizeLimit,
feeMarket,
CoinbaseFeePriceCalculator.frontier()))
@@ -373,7 +372,6 @@ public class ClassicProtocolSpecs {
messageCallProcessor,
true,
true,
false,
stackSizeLimit,
feeMarket,
CoinbaseFeePriceCalculator.frontier()))

View File

@@ -143,7 +143,6 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
false,
false,
false,
stackSizeLimit,
FeeMarket.legacy(),
CoinbaseFeePriceCalculator.frontier()))
@@ -298,7 +297,6 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
false,
false,
stackSizeLimit,
feeMarket,
CoinbaseFeePriceCalculator.frontier()))
@@ -492,7 +490,6 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
false,
false,
stackSizeLimit,
feeMarket,
CoinbaseFeePriceCalculator.eip1559()))
@@ -630,7 +627,6 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
true,
false,
stackSizeLimit,
feeMarket,
CoinbaseFeePriceCalculator.eip1559()))
@@ -707,7 +703,6 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
true,
false,
stackSizeLimit,
feeMarket,
CoinbaseFeePriceCalculator.eip1559()))
@@ -786,7 +781,6 @@ public abstract class MainnetProtocolSpecs {
messageCallProcessor,
true,
true,
true,
stackSizeLimit,
feeMarket,
CoinbaseFeePriceCalculator.eip1559()))
@@ -795,8 +789,7 @@ public abstract class MainnetProtocolSpecs {
.precompileContractRegistryBuilder(MainnetPrecompiledContractRegistries::prague)
.requestsValidator(pragueRequestsValidator(depositContractAddress))
.requestProcessorCoordinator(pragueRequestsProcessors(depositContractAddress))
.blockHashProcessor(
new PragueBlockHashProcessor(genesisConfigOptions.getPragueTime().orElse(0)))
.blockHashProcessor(new PragueBlockHashProcessor())
.name("Prague");
}

View File

@@ -27,7 +27,6 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.feemarket.CoinbaseFeePriceCalculator;
import org.hyperledger.besu.ethereum.mainnet.blockhash.PragueBlockHashProcessor;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
@@ -53,7 +52,6 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -74,7 +72,6 @@ public class MainnetTransactionProcessor {
private final boolean clearEmptyAccounts;
protected final boolean warmCoinbase;
protected final boolean warmBlockhash;
protected final FeeMarket feeMarket;
private final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator;
@@ -86,7 +83,6 @@ public class MainnetTransactionProcessor {
final AbstractMessageProcessor messageCallProcessor,
final boolean clearEmptyAccounts,
final boolean warmCoinbase,
final boolean warmBlockhash,
final int maxStackSize,
final FeeMarket feeMarket,
final CoinbaseFeePriceCalculator coinbaseFeePriceCalculator) {
@@ -96,7 +92,6 @@ public class MainnetTransactionProcessor {
this.messageCallProcessor = messageCallProcessor;
this.clearEmptyAccounts = clearEmptyAccounts;
this.warmCoinbase = warmCoinbase;
this.warmBlockhash = warmBlockhash;
this.maxStackSize = maxStackSize;
this.feeMarket = feeMarket;
this.coinbaseFeePriceCalculator = coinbaseFeePriceCalculator;
@@ -327,15 +322,6 @@ public class MainnetTransactionProcessor {
if (warmCoinbase) {
addressList.add(miningBeneficiary);
}
if (warmBlockhash) {
addressList.add(PragueBlockHashProcessor.HISTORY_STORAGE_ADDRESS);
storageList.putAll(
PragueBlockHashProcessor.HISTORY_STORAGE_ADDRESS,
List.of(
UInt256.valueOf(
(blockHeader.getNumber() - 1)
% PragueBlockHashProcessor.HISTORY_SERVE_WINDOW)));
}
final long intrinsicGas =
gasCalculator.transactionIntrinsicGasCost(

View File

@@ -14,8 +14,6 @@
*/
package org.hyperledger.besu.ethereum.mainnet.blockhash;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.plugin.data.ProcessableBlockHeader;
@@ -26,6 +24,4 @@ public interface BlockHashProcessor {
Blockchain blockchain,
MutableWorldState worldState,
ProcessableBlockHeader currentBlockHeader);
BlockHashLookup getBlockHashLookup(ProcessableBlockHeader currentHeader, Blockchain blockchain);
}

View File

@@ -14,24 +14,15 @@
*/
package org.hyperledger.besu.ethereum.mainnet.blockhash;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.mainnet.ParentBeaconBlockRootHelper;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.ProcessableBlockHeader;
/** Processes the beacon block storage if it is present in the block header. */
public class CancunBlockHashProcessor implements BlockHashProcessor {
@Override
public BlockHashLookup getBlockHashLookup(
final ProcessableBlockHeader currentHeader, final Blockchain blockchain) {
return new CachingBlockHashLookup(currentHeader, blockchain);
}
@Override
public void processBlockHashes(
final Blockchain blockchain,

View File

@@ -14,11 +14,8 @@
*/
package org.hyperledger.besu.ethereum.mainnet.blockhash;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.plugin.data.ProcessableBlockHeader;
public class FrontierBlockHashProcessor implements BlockHashProcessor {
@@ -29,10 +26,4 @@ public class FrontierBlockHashProcessor implements BlockHashProcessor {
final ProcessableBlockHeader currentBlockHeader) {
// do nothing
}
@Override
public BlockHashLookup getBlockHashLookup(
final ProcessableBlockHeader currentHeader, final Blockchain blockchain) {
return new CachingBlockHashLookup(currentHeader, blockchain);
}
}

View File

@@ -14,12 +14,9 @@
*/
package org.hyperledger.besu.ethereum.mainnet.blockhash;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.evm.account.MutableAccount;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@@ -44,53 +41,28 @@ public class PragueBlockHashProcessor extends CancunBlockHashProcessor {
/** The HISTORY_SERVE_WINDOW */
public static final long HISTORY_SERVE_WINDOW = 8192;
private final long forkTimestamp;
private final long historySaveWindow;
private final Address historyStorageAddress;
/**
* Constructs a BlockHashProcessor with a specified fork timestamp.
*
* @param forkTimestamp The timestamp at which the fork becomes active.
*/
public PragueBlockHashProcessor(final long forkTimestamp) {
this(forkTimestamp, HISTORY_STORAGE_ADDRESS, HISTORY_SERVE_WINDOW);
/** Constructs a BlockHashProcessor. */
public PragueBlockHashProcessor() {
this(HISTORY_STORAGE_ADDRESS, HISTORY_SERVE_WINDOW);
}
/**
* Constructs a BlockHashProcessor with a specified fork timestamp and history save window. This
* constructor is primarily used for testing.
* Constructs a BlockHashProcessor with a specified history save window. This constructor is
* primarily used for testing.
*
* @param forkTimestamp The timestamp at which the fork becomes active.
* @param historyStorageAddress the address of the contract storing the history
* @param historySaveWindow The number of blocks for which history should be saved.
*/
@VisibleForTesting
public PragueBlockHashProcessor(
final long forkTimestamp, final Address historyStorageAddress, final long historySaveWindow) {
this.forkTimestamp = forkTimestamp;
final Address historyStorageAddress, final long historySaveWindow) {
this.historyStorageAddress = historyStorageAddress;
this.historySaveWindow = historySaveWindow;
}
@Override
public BlockHashLookup getBlockHashLookup(
final ProcessableBlockHeader currentHeader, final Blockchain blockchain) {
return (frame, blockNumber) -> {
long currentBlockNumber = frame.getBlockValues().getNumber();
if (currentBlockNumber <= blockNumber
|| currentBlockNumber - blockNumber > historySaveWindow
|| blockNumber < 0) {
return Hash.ZERO;
}
return Hash.wrap(
frame
.getWorldUpdater()
.get(historyStorageAddress)
.getStorageValue(UInt256.valueOf(blockNumber % historySaveWindow)));
};
}
@Override
public void processBlockHashes(
final Blockchain blockchain,
@@ -99,21 +71,10 @@ public class PragueBlockHashProcessor extends CancunBlockHashProcessor {
super.processBlockHashes(blockchain, mutableWorldState, currentBlockHeader);
WorldUpdater worldUpdater = mutableWorldState.updater();
final MutableAccount historyStorageAccount = worldUpdater.getOrCreate(HISTORY_STORAGE_ADDRESS);
final MutableAccount historyStorageAccount = worldUpdater.getOrCreate(historyStorageAddress);
if (currentBlockHeader.getNumber() > 0) {
storeParentHash(historyStorageAccount, currentBlockHeader);
BlockHeader ancestor =
blockchain.getBlockHeader(currentBlockHeader.getParentHash()).orElseThrow();
// If fork block, add the parent's direct `HISTORY_SERVE_WINDOW - 1`
if (ancestor.getTimestamp() < forkTimestamp) {
for (int i = 0; i < (historySaveWindow - 1) && ancestor.getNumber() > 0; i++) {
ancestor = blockchain.getBlockHeader(ancestor.getParentHash()).orElseThrow();
storeBlockHeaderHash(historyStorageAccount, ancestor);
}
}
}
worldUpdater.commit();
}
@@ -128,16 +89,6 @@ public class PragueBlockHashProcessor extends CancunBlockHashProcessor {
storeHash(account, header.getNumber() - 1, header.getParentHash());
}
/**
* Stores the hash of a block in the world state.
*
* @param account The account associated with the historical block hash storage.
* @param header The block header whose hash is to be stored.
*/
private void storeBlockHeaderHash(final MutableAccount account, final BlockHeader header) {
storeHash(account, header.getNumber(), header.getHash());
}
/**
* Stores the hash in the world state.
*
@@ -146,11 +97,10 @@ public class PragueBlockHashProcessor extends CancunBlockHashProcessor {
* @param hash The hash to be stored.
*/
private void storeHash(final MutableAccount account, final long number, final Hash hash) {
UInt256 slot = UInt256.valueOf(number % historySaveWindow);
UInt256 value = UInt256.fromBytes(hash);
LOG.trace(
"Writing to {} {}=%{}",
account.getAddress(),
UInt256.valueOf(number % historySaveWindow).toDecimalString(),
UInt256.fromBytes(hash).toHexString());
account.setStorageValue(UInt256.valueOf(number % historySaveWindow), UInt256.fromBytes(hash));
"Writing to {} {}=%{}", account.getAddress(), slot.toDecimalString(), value.toHexString());
account.setStorageValue(slot, value);
}
}

View File

@@ -25,6 +25,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyGroupHeadBlockMap;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.LinkedHashMap;
@@ -166,7 +167,7 @@ public class PrivateStateRehydration {
privateStateStorage,
privateStateRootResolver,
block,
protocolSpec.getBlockHashProcessor().getBlockHashLookup(blockHeader, blockchain),
new CachingBlockHashLookup(blockHeader, blockchain),
pmtHashToPrivateTransactionMap,
block.getBody().getOmmers());

View File

@@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.transaction.CallParameter;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.tracing.OperationTracer;
@@ -139,7 +140,7 @@ public class PrivateTransactionSimulator {
transaction,
protocolSpec.getMiningBeneficiaryCalculator().calculateBeneficiary(header),
OperationTracer.NO_TRACING,
protocolSpec.getBlockHashProcessor().getBlockHashLookup(header, blockchain),
new CachingBlockHashLookup(header, blockchain),
privacyGroupId);
return Optional.of(result);

View File

@@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver;
import org.hyperledger.besu.ethereum.privacy.storage.LegacyPrivateStateStorage;
import org.hyperledger.besu.ethereum.privacy.storage.PrivacyGroupHeadBlockMap;
import org.hyperledger.besu.ethereum.privacy.storage.PrivateStateStorage;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import java.util.List;
@@ -112,7 +113,7 @@ public class PrivateStorageMigration {
privateMigrationBlockProcessor.processBlock(
blockchain,
publicWorldState,
protocolSpec.getBlockHashProcessor().getBlockHashLookup(blockHeader, blockchain),
new CachingBlockHashLookup(blockHeader, blockchain),
blockHeader,
transactionsToProcess,
ommers);

View File

@@ -34,6 +34,7 @@ import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.account.Account;
@@ -279,9 +280,7 @@ public class TransactionSimulator {
protocolSpec
.getMiningBeneficiaryCalculator()
.calculateBeneficiary(blockHeaderToProcess),
protocolSpec
.getBlockHashProcessor()
.getBlockHashLookup(blockHeaderToProcess, blockchain),
new CachingBlockHashLookup(blockHeaderToProcess, blockchain),
false,
transactionValidationParams,
operationTracer,

View File

@@ -15,13 +15,12 @@
package org.hyperledger.besu.ethereum.vm;
import static org.hyperledger.besu.datatypes.Hash.ZERO;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.plugin.data.ProcessableBlockHeader;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import java.util.HashMap;
import java.util.Map;
@@ -38,32 +37,17 @@ public class CachingBlockHashLookup implements BlockHashLookup {
private ProcessableBlockHeader searchStartHeader;
private final Blockchain blockchain;
private final long maxLookback;
private final Map<Long, Hash> hashByNumber = new HashMap<>();
public CachingBlockHashLookup(
final ProcessableBlockHeader currentBlock, final Blockchain blockchain) {
this(currentBlock, blockchain, BlockHashOperation.MAX_RELATIVE_BLOCK);
}
public CachingBlockHashLookup(
final ProcessableBlockHeader currentBlock,
final Blockchain blockchain,
final int maxLookback) {
this.searchStartHeader = currentBlock;
this.blockchain = blockchain;
this.maxLookback = maxLookback;
hashByNumber.put(currentBlock.getNumber() - 1, currentBlock.getParentHash());
}
@Override
public Hash apply(final MessageFrame frame, final Long blockNumber) {
long currentBlockNumber = frame.getBlockValues().getNumber();
long lookback = currentBlockNumber - blockNumber;
if (currentBlockNumber <= blockNumber || lookback > maxLookback) {
return Hash.ZERO;
}
public Hash apply(final Long blockNumber) {
final Hash cachedHash = hashByNumber.get(blockNumber);
if (cachedHash != null) {
return cachedHash;

View File

@@ -84,7 +84,6 @@ class MainnetTransactionProcessorTest {
messageCallProcessor,
false,
warmCoinbase,
false,
MAX_STACK_SIZE,
FeeMarket.legacy(),
CoinbaseFeePriceCalculator.frontier());

View File

@@ -34,7 +34,6 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.PrivateTransactionDataFixture;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.blockhash.BlockHashProcessor;
import org.hyperledger.besu.ethereum.privacy.PrivateStateGenesisAllocator;
import org.hyperledger.besu.ethereum.privacy.PrivateStateRootResolver;
import org.hyperledger.besu.ethereum.privacy.PrivateTransactionProcessor;
@@ -222,8 +221,6 @@ class PrivacyBlockProcessorTest {
when(protocolSpec.getMiningBeneficiaryCalculator())
.thenReturn(mock(MiningBeneficiaryCalculator.class));
when(protocolSpec.isSkipZeroBlockRewards()).thenReturn(true);
BlockHashProcessor blockHashProcessor = mock(BlockHashProcessor.class);
when(protocolSpec.getBlockHashProcessor()).thenReturn(blockHashProcessor);
return protocolSpec;
}
}

View File

@@ -42,7 +42,7 @@ class BlockHashProcessorTest {
private MutableAccount account;
private BlockHashProcessor processor;
private long historicalWindow = 8192;
private final long historicalWindow = 255;
@BeforeEach
void setUp() {
@@ -57,9 +57,8 @@ class BlockHashProcessorTest {
@Test
void shouldStoreParentBlockHash() {
long forkTimestamp = 0;
long currentBlock = 3;
processor = new PragueBlockHashProcessor(forkTimestamp);
processor = new PragueBlockHashProcessor();
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
mockAncestorHeaders(currentBlockHeader, 3);
processor.processBlockHashes(blockchain, mutableWorldState, currentBlockHeader);
@@ -72,9 +71,8 @@ class BlockHashProcessorTest {
void shouldNotStoreBlockHashForGenesisBlock() {
// For the fork to be activated at genesis, no history is written to the genesis state, and at
// the start of block 1, genesis hash will be written as a normal operation to slot 0.
long forkTimestamp = 0;
long currentBlock = 0;
processor = new PragueBlockHashProcessor(forkTimestamp);
processor = new PragueBlockHashProcessor();
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
mockAncestorHeaders(currentBlockHeader, 0);
@@ -86,9 +84,8 @@ class BlockHashProcessorTest {
void shouldStoreAncestorBlockHashesAtForkCorrectlyParentIsGenesis() {
// for activation at block 1, only genesis hash will be written at slot 0 as there is no
// additional history that needs to be persisted.
long forkTimestamp = 1;
long currentBlock = 1;
processor = new PragueBlockHashProcessor(forkTimestamp);
processor = new PragueBlockHashProcessor();
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
mockAncestorHeaders(currentBlockHeader, 10);
@@ -97,46 +94,9 @@ class BlockHashProcessorTest {
verifyAccount(0, historicalWindow);
}
@Test
void shouldStoreAncestorBlockHashesAtForkCorrectly() {
// for activation at block 32, block 31s hash will be written to slot 31 and additional history
// for 0..30s hashes will be persisted, so all in all 0..31s hashes.
long forkTimestamp = 32;
long currentBlock = 32;
processor = new PragueBlockHashProcessor(forkTimestamp);
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
mockAncestorHeaders(currentBlockHeader, 32);
processor.processBlockHashes(blockchain, mutableWorldState, currentBlockHeader);
verifyAncestor(currentBlock, 32, historicalWindow);
}
@Test
void shouldStoreAncestorBlockHashesAtForkCorrectlyMaxWindows() {
long forkTimestamp = 10000;
long currentBlock = 10000;
historicalWindow = 8192;
processor =
new PragueBlockHashProcessor(
forkTimestamp, PragueBlockHashProcessor.HISTORY_STORAGE_ADDRESS, historicalWindow);
BlockHeader currentBlockHeader = mockBlockHeader(currentBlock);
mockAncestorHeaders(currentBlockHeader, 10000);
processor.processBlockHashes(blockchain, mutableWorldState, currentBlockHeader);
// Total of historicalWindow hashes were stored
verify(account, times((int) historicalWindow)).setStorageValue(any(), any());
// for activation at block 10000, block 1808-9999s hashes will be presisted in the slot
verifyAccount(1808, historicalWindow);
verifyAccount(9999, historicalWindow);
// BLOCKHASH for 1807 or less would resolve to 0 as only HISTORY_SERVE_WINDOW are persisted.
verifyAccountNoIteraction(1807, historicalWindow);
verifyAccountNoIteraction(10000, historicalWindow);
}
@Test
void shouldWriteGenesisHashAtSlot0() {
processor = new PragueBlockHashProcessor(0);
processor = new PragueBlockHashProcessor();
BlockHeader header = mockBlockHeader(1);
mockAncestorHeaders(header, 1);
processor.processBlockHashes(blockchain, mutableWorldState, header);
@@ -144,26 +104,11 @@ class BlockHashProcessorTest {
.setStorageValue(UInt256.valueOf(0), UInt256.fromHexString(Hash.ZERO.toHexString()));
}
private void verifyAncestor(
final long blockNumber, final int count, final long historicalWindow) {
int totalTouchedSlots = (int) (blockNumber - count <= 0 ? blockNumber : count);
long firstAncestor = Math.max(blockNumber - count - 1, 0);
verify(account, times(totalTouchedSlots)).setStorageValue(any(), any());
for (long i = firstAncestor; i < blockNumber; i++) {
verifyAccount(i, historicalWindow);
}
}
private void verifyAccount(final long number, final long historicalWindow) {
verify(account)
.setStorageValue(UInt256.valueOf(number % historicalWindow), UInt256.valueOf(number));
}
private void verifyAccountNoIteraction(final long number, final long historicalWindow) {
verify(account, times(0))
.setStorageValue(UInt256.valueOf(number % historicalWindow), UInt256.valueOf(number));
}
private void mockAncestorHeaders(final BlockHeader blockHeader, final int count) {
long firstAncestor = Math.max(blockHeader.getNumber() - count, 0);
var block = blockHeader;

View File

@@ -14,9 +14,8 @@
*/
package org.hyperledger.besu.ethereum.vm;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
@@ -27,8 +26,7 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import java.util.Optional;
@@ -37,17 +35,13 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class CachingBlockHashLookupTest {
@Mock private Blockchain blockchain;
@Mock private MessageFrame messageFrame;
@Mock private BlockValues blockValues;
private static final int CURRENT_BLOCK_NUMBER = 300;
private static final int CURRENT_BLOCK_NUMBER = 256;
private final Blockchain blockchain = mock(Blockchain.class);
private final BlockHeader[] headers = new BlockHeader[CURRENT_BLOCK_NUMBER];
private BlockHashLookup lookup;
@@ -56,13 +50,10 @@ class CachingBlockHashLookupTest {
BlockHeader parentHeader = null;
for (int i = 0; i < headers.length; i++) {
final BlockHeader header = createHeader(i, parentHeader);
lenient().when(blockchain.getBlockHeader(header.getHash())).thenReturn(Optional.of(header));
when(blockchain.getBlockHeader(header.getHash())).thenReturn(Optional.of(header));
headers[i] = header;
parentHeader = headers[i];
}
when(messageFrame.getBlockValues()).thenReturn(blockValues);
when(blockValues.getNumber()).thenReturn((long) CURRENT_BLOCK_NUMBER);
lookup =
new CachingBlockHashLookup(
createHeader(CURRENT_BLOCK_NUMBER, headers[headers.length - 1]), blockchain);
@@ -80,33 +71,20 @@ class CachingBlockHashLookupTest {
assertHashForBlockNumber(CURRENT_BLOCK_NUMBER - 1);
}
@Test
void shouldGetHashOfGenesisBlock() {
assertHashForBlockNumber(0);
}
@Test
void shouldGetHashForRecentBlockAfterOlderBlock() {
assertHashForBlockNumber(100);
assertHashForBlockNumber(10);
assertHashForBlockNumber(CURRENT_BLOCK_NUMBER - 1);
}
@Test
void shouldReturnEmptyHashWhenRequestedGenesis() {
Assertions.assertThat(lookup.apply(messageFrame, 0L)).isEqualTo(Hash.ZERO);
}
@Test
void shouldReturnEmptyHashWhenRequestedTooFarBack() {
Assertions.assertThat(lookup.apply(messageFrame, CURRENT_BLOCK_NUMBER - 260L))
.isEqualTo(Hash.ZERO);
}
@Test
void shouldReturnEmptyHashWhenRequestedCurrentBlock() {
Assertions.assertThat(lookup.apply(messageFrame, (long) CURRENT_BLOCK_NUMBER))
.isEqualTo(Hash.ZERO);
}
@Test
void shouldReturnEmptyHashWhenRequestedBlockNotOnchain() {
Assertions.assertThat(lookup.apply(messageFrame, CURRENT_BLOCK_NUMBER + 20L))
.isEqualTo(Hash.ZERO);
Assertions.assertThat(lookup.apply(CURRENT_BLOCK_NUMBER + 20L)).isEqualTo(Hash.ZERO);
}
@Test
@@ -115,8 +93,7 @@ class CachingBlockHashLookupTest {
new CachingBlockHashLookup(
new BlockHeaderTestFixture().number(CURRENT_BLOCK_NUMBER + 20).buildHeader(),
blockchain);
Assertions.assertThat(
lookupWithUnavailableParent.apply(messageFrame, (long) CURRENT_BLOCK_NUMBER))
Assertions.assertThat(lookupWithUnavailableParent.apply((long) CURRENT_BLOCK_NUMBER))
.isEqualTo(Hash.ZERO);
}
@@ -137,7 +114,7 @@ class CachingBlockHashLookupTest {
}
private void assertHashForBlockNumber(final int blockNumber) {
Assertions.assertThat(lookup.apply(messageFrame, (long) blockNumber))
Assertions.assertThat(lookup.apply((long) blockNumber))
.isEqualTo(headers[blockNumber].getHash());
}

View File

@@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.core.MutableWorldState;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.Code;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.EvmSpecVersion;
@@ -429,10 +430,7 @@ public class EvmToolCommand implements Runnable {
.blockValues(blockHeader)
.completer(c -> {})
.miningBeneficiary(blockHeader.getCoinbase())
.blockHashLookup(
protocolSpec
.getBlockHashProcessor()
.getBlockHashLookup(blockHeader, component.getBlockchain()))
.blockHashLookup(new CachingBlockHashLookup(blockHeader, component.getBlockchain()))
.accessListWarmAddresses(addressList)
.build();
Deque<MessageFrame> messageFrameStack = initialMessageFrame.getMessageFrameStack();

View File

@@ -32,13 +32,10 @@ import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.referencetests.GeneralStateTestCaseEipSpec;
import org.hyperledger.besu.ethereum.referencetests.GeneralStateTestCaseSpec;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestBlockchain;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestProtocolSchedules;
import org.hyperledger.besu.ethereum.rlp.RLP;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.tracing.StandardJsonTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@@ -251,31 +248,13 @@ public class StateTestSubCommand implements Runnable {
final Stopwatch timer = Stopwatch.createStarted();
// Todo: EIP-4844 use the excessBlobGas of the parent instead of BlobGas.ZERO
final Wei blobGasPrice = protocolSpec.getFeeMarket().blobGasPricePerGas(BlobGas.ZERO);
BlockHashOperation.BlockHashLookup blockHashLookup =
protocolSpec
.getBlockHashProcessor()
.getBlockHashLookup(
blockHeader, new ReferenceTestBlockchain(blockHeader.getNumber()));
if (blockHashLookup instanceof CachingBlockHashLookup) {
blockHashLookup =
(messageFrame, number) -> {
long lookback = messageFrame.getBlockValues().getNumber() - number;
if (lookback <= 0 || lookback > BlockHashOperation.MAX_RELATIVE_BLOCK) {
return Hash.ZERO;
} else {
return Hash.hash(Bytes.wrap(Long.toString(number).getBytes(UTF_8)));
}
};
}
final TransactionProcessingResult result =
processor.processTransaction(
worldStateUpdater,
blockHeader,
transaction,
blockHeader.getCoinbase(),
blockHashLookup,
blockNumber -> Hash.hash(Bytes.wrap(Long.toString(blockNumber).getBytes(UTF_8))),
false,
TransactionValidationParams.processingBlock(),
tracer,

View File

@@ -47,11 +47,9 @@ import org.hyperledger.besu.ethereum.referencetests.ReferenceTestWorldState;
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.vm.CachingBlockHashLookup;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.evmtool.exception.UnsupportedForkException;
@@ -291,27 +289,13 @@ public class T8nExecutor {
tracer = tracerManager.getManagedTracer(i, transaction.getHash());
tracer.tracePrepareTransaction(worldStateUpdater, transaction);
tracer.traceStartTransaction(worldStateUpdater, transaction);
BlockHashOperation.BlockHashLookup blockHashLookup =
protocolSpec.getBlockHashProcessor().getBlockHashLookup(blockHeader, blockchain);
if (blockHashLookup instanceof CachingBlockHashLookup) {
// caching lookup won't work, use our own secret sauce
blockHashLookup =
(frame, number) -> {
long lookback = frame.getBlockValues().getNumber() - number;
if (lookback <= 0 || lookback > BlockHashOperation.MAX_RELATIVE_BLOCK) {
return Hash.ZERO;
} else {
return referenceTestEnv.getBlockhashByNumber(number).orElse(Hash.ZERO);
}
};
}
result =
processor.processTransaction(
worldStateUpdater,
blockHeader,
transaction,
blockHeader.getCoinbase(),
blockHashLookup,
number -> referenceTestEnv.getBlockhashByNumber(number).orElse(Hash.ZERO),
false,
TransactionValidationParams.processingBlock(),
tracer,

View File

@@ -62,7 +62,7 @@ public abstract class BenchmarkExecutor {
.code(CodeV0.EMPTY_CODE)
.completer(__ -> {})
.address(Address.ZERO)
.blockHashLookup((f, n) -> null)
.blockHashLookup(n -> null)
.blockValues(new SimpleBlockValues())
.gasPrice(Wei.ZERO)
.miningBeneficiary(Address.ZERO)

View File

@@ -106,9 +106,6 @@ public class GeneralStateReferenceTestTools {
// EOF tests are written against an older version of the spec
params.ignore("/stEOF/");
// None of the Prague tests have withdrawls and deposits handling
params.ignore("-Prague$");
}
private GeneralStateReferenceTestTools() {
@@ -160,7 +157,7 @@ public class GeneralStateReferenceTestTools {
blockHeader,
transaction,
blockHeader.getCoinbase(),
protocolSpec.getBlockHashProcessor().getBlockHashLookup(blockHeader, blockchain),
new CachingBlockHashLookup(blockHeader, blockchain),
false,
TransactionValidationParams.processingBlock(),
blobGasPrice);

View File

@@ -72,7 +72,7 @@ public class EVMExecutor {
private Wei ethValue = Wei.ZERO;
private Code code = CodeV0.EMPTY_CODE;
private BlockValues blockValues = new SimpleBlockValues();
private BlockHashLookup blockHashLookup = (h, n) -> null;
private BlockHashLookup blockHashLookup = n -> null;
private Optional<List<VersionedHash>> versionedHashes = Optional.empty();
private OperationTracer tracer = OperationTracer.NO_TRACING;
private boolean requireDeposit = true;

View File

@@ -16,7 +16,6 @@ package org.hyperledger.besu.evm.frame;
import static com.google.common.base.Preconditions.checkState;
import static java.util.Collections.emptySet;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.collections.trie.BytesTrieSet;
import org.hyperledger.besu.collections.undo.UndoScalar;
@@ -33,6 +32,7 @@ import org.hyperledger.besu.evm.internal.ReturnStack;
import org.hyperledger.besu.evm.internal.StorageEntry;
import org.hyperledger.besu.evm.internal.UnderflowException;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.evm.operation.Operation;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@@ -1427,9 +1427,6 @@ public class MessageFrame {
private Optional<List<VersionedHash>> versionedHashes = Optional.empty();
/** Instantiates a new Builder. */
public Builder() {}
/**
* The "parent" message frame. When present some fields will be populated from the parent and
* ignored if passed in via builder

View File

@@ -392,7 +392,7 @@ public class FrontierGasCalculator implements GasCalculator {
}
@Override
public long getBlockHashOperationGasCost(final MessageFrame frame) {
public long getBlockHashOperationGasCost() {
return BLOCKHASH_OPERATION_GAS_COST;
}

View File

@@ -345,10 +345,9 @@ public interface GasCalculator {
/**
* Returns the cost for executing a {@link BlockHashOperation}.
*
* @param frame The current frame
* @return the cost for executing the block hash operation
*/
long getBlockHashOperationGasCost(MessageFrame frame);
long getBlockHashOperationGasCost();
/**
* Returns the cost for executing a {@link ExpOperation}.

View File

@@ -21,8 +21,6 @@ import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.apache.tuweni.units.bigints.UInt256;
/**
* Gas Calculator for Prague
*
@@ -101,24 +99,4 @@ public class PragueGasCalculator extends CancunGasCalculator {
return cost;
}
/** Address of the contract historic block hashes are stored in. */
public static final Address HISTORY_STORAGE_ADDRESS =
Address.fromHexString("0x25a219378dad9b3503c8268c9ca836a52427a4fb");
/** The HISTORY_SERVE_WINDOW */
public static final long HISTORY_SERVE_WINDOW = 8192;
@Override
public long getBlockHashOperationGasCost(final MessageFrame frame) {
if (frame == null) {
return super.getBlockHashOperationGasCost(null);
} else {
UInt256 slot = UInt256.valueOf(frame.getBlockValues().getNumber() % HISTORY_SERVE_WINDOW);
return BLOCKHASH_OPERATION_GAS_COST
+ (frame.warmUpStorage(HISTORY_STORAGE_ADDRESS, slot)
? getWarmStorageReadCost()
: getColdSloadCost());
}
}
}

View File

@@ -16,27 +16,29 @@ package org.hyperledger.besu.evm.operation;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.EVM;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import java.util.function.BiFunction;
import java.util.function.Function;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt256;
/** The Block hash operation. */
public class BlockHashOperation extends AbstractOperation {
/** Frontier maximum relative block delta */
public static final int MAX_RELATIVE_BLOCK = 256;
public class BlockHashOperation extends AbstractFixedCostOperation {
/**
* Function that gets the block hash, passed in as part of TxValues.
*
* <p>First arg is the current block number, second is the block argument from the stack. The
* Result is the Hash, which may be zero based on lookup rules.
* <p>Arg is the current block number. The Result is the Hash, which may be zero based on lookup
* rules.
*/
public interface BlockHashLookup extends BiFunction<MessageFrame, Long, Hash> {}
public interface BlockHashLookup extends Function<Long, Hash> {}
/** Frontier maximum relative block delta */
public static final int MAX_RELATIVE_BLOCK = 256;
private static final int MAX_BLOCK_ARG_SIZE = 8;
@@ -46,25 +48,36 @@ public class BlockHashOperation extends AbstractOperation {
* @param gasCalculator the gas calculator
*/
public BlockHashOperation(final GasCalculator gasCalculator) {
super(0x40, "BLOCKHASH", 1, 1, gasCalculator);
super(0x40, "BLOCKHASH", 1, 1, gasCalculator, gasCalculator.getBlockHashOperationGasCost());
}
@Override
public OperationResult execute(MessageFrame frame, EVM evm) {
public Operation.OperationResult executeFixedCostOperation(
final MessageFrame frame, final EVM evm) {
final Bytes blockArg = frame.popStackItem().trimLeadingZeros();
// Short-circuit if value exceeds long
// Short-circuit if value is unreasonably large
if (blockArg.size() > MAX_BLOCK_ARG_SIZE) {
frame.pushStackItem(UInt256.ZERO);
return new OperationResult(gasCalculator().getBlockHashOperationGasCost(null), null);
return successResponse;
}
final long soughtBlock = blockArg.toLong();
final BlockHashLookup blockHashLookup = frame.getBlockHashLookup();
final Hash blockHash = blockHashLookup.apply(frame, soughtBlock);
frame.pushStackItem(blockHash);
return new OperationResult(
gasCalculator().getBlockHashOperationGasCost(Hash.ZERO.equals(blockHash) ? null : frame),
null);
final BlockValues blockValues = frame.getBlockValues();
final long currentBlockNumber = blockValues.getNumber();
// If the current block is the genesis block or the sought block is
// not within the last 256 completed blocks, zero is returned.
if (currentBlockNumber == 0
|| soughtBlock >= currentBlockNumber
|| soughtBlock < (currentBlockNumber - MAX_RELATIVE_BLOCK)) {
frame.pushStackItem(Bytes32.ZERO);
} else {
final BlockHashLookup blockHashLookup = frame.getBlockHashLookup();
final Hash blockHash = blockHashLookup.apply(soughtBlock);
frame.pushStackItem(blockHash);
}
return successResponse;
}
}

View File

@@ -97,7 +97,7 @@ class CodeV0Test {
.blockValues(mock(BlockValues.class))
.completer(f -> {})
.miningBeneficiary(Address.ZERO)
.blockHashLookup((f, n) -> Hash.EMPTY)
.blockHashLookup(l -> Hash.EMPTY)
.build();
frame.setPC(CURRENT_PC);

View File

@@ -188,7 +188,7 @@ class EVMExecutorTest {
.number(1)
.timestamp(100L)
.gasLimit(15_000_000L)
.blockHashLookup((height, number) -> Hash.ZERO)
.blockHashLookup(number -> Hash.ZERO)
.versionedHashes(Optional.empty())
.precompileContractRegistry(new PrecompileContractRegistry())
.requireDeposit(false)

View File

@@ -48,7 +48,7 @@ class MessageFrameTest {
.blobGasPrice(Wei.ONE)
.blockValues(new ToyBlockValues())
.miningBeneficiary(Address.ZERO)
.blockHashLookup((f, n) -> Hash.ZERO)
.blockHashLookup((l) -> Hash.ZERO)
.type(MessageFrame.Type.MESSAGE_CALL)
.initialGas(1)
.address(Address.ZERO)

View File

@@ -169,7 +169,7 @@ class AbstractCreateOperationTest {
.code(CodeFactory.createCode(SIMPLE_CREATE, 0, true))
.completer(__ -> {})
.address(Address.fromHexString(SENDER))
.blockHashLookup((f, n) -> Hash.hash(Words.longBytes(n)))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))
.blockValues(mock(BlockValues.class))
.gasPrice(Wei.ZERO)
.miningBeneficiary(Address.ZERO)

View File

@@ -15,12 +15,12 @@
package org.hyperledger.besu.evm.operations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.FrontierGasCalculator;
import org.hyperledger.besu.evm.operation.BlockHashOperation;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.evm.testutils.FakeBlockValues;
import org.hyperledger.besu.evm.testutils.TestMessageFrameBuilder;
@@ -31,20 +31,49 @@ import org.junit.jupiter.api.Test;
class BlockHashOperationTest {
private static final int MAXIMUM_COMPLETE_BLOCKS_BEHIND = 256;
private final BlockHashOperation blockHashOperation =
new BlockHashOperation(new FrontierGasCalculator());
@Test
void shouldReturnZeroWhenArgIsBiggerThanALong() {
assertBlockHash(
Bytes32.fromHexString("F".repeat(64)), Bytes32.ZERO, 100, (h, n) -> Hash.EMPTY_LIST_HASH);
Bytes32.fromHexString("F".repeat(64)), Bytes32.ZERO, 100, n -> Hash.EMPTY_LIST_HASH);
}
@Test
void shouldReturnZeroWhenCurrentBlockIsGenesis() {
assertBlockHash(Bytes32.ZERO, Bytes32.ZERO, 0, block -> Hash.EMPTY_LIST_HASH);
}
@Test
void shouldReturnZeroWhenRequestedBlockAheadOfCurrent() {
assertBlockHash(250, Bytes32.ZERO, 100, block -> Hash.EMPTY_LIST_HASH);
}
@Test
void shouldReturnZeroWhenRequestedBlockTooFarBehindCurrent() {
final int requestedBlock = 10;
// Our block is the one after the chain head (it's a new block), hence the + 1.
final int importingBlockNumber = MAXIMUM_COMPLETE_BLOCKS_BEHIND + requestedBlock + 1;
assertBlockHash(
requestedBlock, Bytes32.ZERO, importingBlockNumber, block -> Hash.EMPTY_LIST_HASH);
}
@Test
void shouldReturnZeroWhenRequestedBlockGreaterThanImportingBlock() {
assertBlockHash(101, Bytes32.ZERO, 100, block -> Hash.EMPTY_LIST_HASH);
}
@Test
void shouldReturnZeroWhenRequestedBlockEqualToImportingBlock() {
assertBlockHash(100, Bytes32.ZERO, 100, block -> Hash.EMPTY_LIST_HASH);
}
@Test
void shouldReturnBlockHashUsingLookupFromFrameWhenItIsWithinTheAllowedRange() {
final Hash blockHash = Hash.hash(Bytes.fromHexString("0x1293487297"));
assertBlockHash(
100, blockHash, 200, (h, block) -> block == 100 ? blockHash : Hash.EMPTY_LIST_HASH);
assertBlockHash(100, blockHash, 200, block -> block == 100 ? blockHash : Hash.EMPTY_LIST_HASH);
}
private void assertBlockHash(

View File

@@ -155,7 +155,7 @@ public class Create2OperationTest {
.code(CodeFactory.createCode(codeBytes, 0, true))
.completer(__ -> {})
.address(Address.fromHexString(sender))
.blockHashLookup((f, n) -> Hash.hash(Words.longBytes(n)))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))
.blockValues(mock(BlockValues.class))
.gasPrice(Wei.ZERO)
.miningBeneficiary(Address.ZERO)
@@ -269,7 +269,7 @@ public class Create2OperationTest {
.code(CodeFactory.createCode(SIMPLE_CREATE, 0, true))
.completer(__ -> {})
.address(Address.fromHexString(SENDER))
.blockHashLookup((f, n) -> Hash.hash(Words.longBytes(n)))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))
.blockValues(mock(BlockValues.class))
.gasPrice(Wei.ZERO)
.miningBeneficiary(Address.ZERO)

View File

@@ -289,7 +289,7 @@ class CreateOperationTest {
.code(CodeFactory.createCode(SIMPLE_CREATE, 0, true))
.completer(__ -> {})
.address(Address.fromHexString(SENDER))
.blockHashLookup((f, n) -> Hash.hash(Words.longBytes(n)))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))
.blockValues(mock(BlockValues.class))
.gasPrice(Wei.ZERO)
.miningBeneficiary(Address.ZERO)

View File

@@ -82,7 +82,7 @@ public class SelfDestructOperationTest {
.code(CodeFactory.createCode(SELFDESTRUCT_CODE, 0, true))
.completer(__ -> {})
.address(originatorAddress)
.blockHashLookup((f, n) -> Hash.hash(Words.longBytes(n)))
.blockHashLookup(n -> Hash.hash(Words.longBytes(n)))
.blockValues(mock(BlockValues.class))
.gasPrice(Wei.ZERO)
.miningBeneficiary(Address.ZERO)

View File

@@ -65,7 +65,7 @@ public class Benchmarks {
.code(CodeV0.EMPTY_CODE)
.completer(__ -> {})
.address(Address.ZERO)
.blockHashLookup((f, n) -> null)
.blockHashLookup(n -> null)
.blockValues(new SimpleBlockValues())
.gasPrice(Wei.ZERO)
.miningBeneficiary(Address.ZERO)

View File

@@ -15,7 +15,6 @@
package org.hyperledger.besu.evm.testutils;
import static org.hyperledger.besu.evm.frame.MessageFrame.DEFAULT_MAX_STACK_SIZE;
import static org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
@@ -25,6 +24,7 @@ import org.hyperledger.besu.evm.code.CodeV0;
import org.hyperledger.besu.evm.frame.BlockValues;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.internal.Words;
import org.hyperledger.besu.evm.operation.BlockHashOperation.BlockHashLookup;
import org.hyperledger.besu.evm.toy.ToyWorld;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@@ -161,7 +161,7 @@ public class TestMessageFrameBuilder {
.blockValues(blockValues.orElseGet(() -> new FakeBlockValues(1337)))
.completer(c -> {})
.miningBeneficiary(Address.ZERO)
.blockHashLookup(blockHashLookup.orElse((f, n) -> Hash.hash(Words.longBytes(n))))
.blockHashLookup(blockHashLookup.orElse(number -> Hash.hash(Words.longBytes(number))))
.maxStackSize(maxStackSize)
.build();
frame.setPC(pc);

View File

@@ -190,7 +190,7 @@ public class EvmToyCommand implements Runnable {
.blockValues(new ToyBlockValues())
.completer(c -> {})
.miningBeneficiary(Address.ZERO)
.blockHashLookup((f, n) -> null)
.blockHashLookup(n -> null)
.build();
final MessageCallProcessor mcp = new MessageCallProcessor(evm, precompileContractRegistry);