Skip to content

Commit

Permalink
Pectra devnet 0 EEST support (#7123)
Browse files Browse the repository at this point in the history
* Pectra devnet 0 EEST support

Add the required fields to the t8n responses
to enable ethereum execution spec tests to fill tests using Besu.

Signed-off-by: Danno Ferrin <[email protected]>

* tests

Signed-off-by: Danno Ferrin <[email protected]>

* spotless

Signed-off-by: Danno Ferrin <[email protected]>

* fix issue with warm state crossing transaciton boundaries in t8n tool

Signed-off-by: Danno Ferrin <[email protected]>

* test results change when bugs a re fixed

Signed-off-by: Danno Ferrin <[email protected]>

* fix changed method name

Signed-off-by: Danno Ferrin <[email protected]>

---------

Signed-off-by: Danno Ferrin <[email protected]>
  • Loading branch information
shemnon authored May 29, 2024
1 parent 3c57ca2 commit fb25f18
Show file tree
Hide file tree
Showing 4 changed files with 698 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ public class WithdrawalRequestContractHelper {
public static final Address WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS =
Address.fromHexString("0x00A3ca265EBcb825B45F985A16CEFB49958cE017");

/** private constructor to prevent instantiations */
private WithdrawalRequestContractHelper() {}

@VisibleForTesting
// Storage slot to store the difference between number of withdrawal requests since last block and
// target withdrawal requests
Expand Down Expand Up @@ -82,7 +85,7 @@ public static List<WithdrawalRequest> popWithdrawalRequestsFromQueue(
final MutableWorldState mutableWorldState) {
final WorldUpdater worldUpdater = mutableWorldState.updater();
final MutableAccount account = worldUpdater.getAccount(WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS);
if (Hash.EMPTY.equals(account.getCodeHash())) {
if (account == null || Hash.EMPTY.equals(account.getCodeHash())) {
return List.of();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,17 @@
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Deposit;
import org.hyperledger.besu.ethereum.core.Request;
import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.WithdrawalRequest;
import org.hyperledger.besu.ethereum.mainnet.BodyValidation;
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.mainnet.requests.RequestUtil;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.referencetests.BonsaiReferenceTestWorldState;
import org.hyperledger.besu.ethereum.referencetests.ReferenceTestEnv;
Expand All @@ -63,10 +67,11 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.StreamSupport;

import com.fasterxml.jackson.databind.JsonNode;
Expand Down Expand Up @@ -160,7 +165,8 @@ protected static List<Transaction> extractTransactions(
false)
.map(JsonNode::textValue)
.toList();
var accessListEntry = AccessListEntry.createAccessListEntry(address, storageKeys);
AccessListEntry accessListEntry =
AccessListEntry.createAccessListEntry(address, storageKeys);
entries.add(accessListEntry);
}
builder.accessList(entries);
Expand Down Expand Up @@ -260,15 +266,17 @@ static T8nResult runTest(
.getBlockHashProcessor()
.processBlockHashes(blockchain, worldState, referenceTestEnv);

final WorldUpdater worldStateUpdater = worldState.updater();
final WorldUpdater rootWorldStateUpdater = worldState.updater();
List<TransactionReceipt> receipts = new ArrayList<>();
List<RejectedTransaction> invalidTransactions = new ArrayList<>(rejections);
List<Transaction> validTransactions = new ArrayList<>();
ArrayNode receiptsArray = objectMapper.createArrayNode();
long gasUsed = 0;
long blobGasUsed = 0;
for (int i = 0; i < transactions.size(); i++) {
Transaction transaction = transactions.get(i);
final WorldUpdater worldStateUpdater = rootWorldStateUpdater.updater();
for (int transactionIndex = 0; transactionIndex < transactions.size(); transactionIndex++) {
worldStateUpdater.markTransactionBoundary();
Transaction transaction = transactions.get(transactionIndex);
final Stopwatch timer = Stopwatch.createStarted();

GasCalculator gasCalculator = protocolSpec.getGasCalculator();
Expand All @@ -277,7 +285,7 @@ static T8nResult runTest(
if (blobGasUsed > blobGasLimit) {
invalidTransactions.add(
new RejectedTransaction(
i,
transactionIndex,
String.format(
"blob gas (%d) would exceed block maximum %d", blobGasUsed, blobGasLimit)));
continue;
Expand All @@ -286,7 +294,7 @@ static T8nResult runTest(

final TransactionProcessingResult result;
try {
tracer = tracerManager.getManagedTracer(i, transaction.getHash());
tracer = tracerManager.getManagedTracer(transactionIndex, transaction.getHash());
tracer.tracePrepareTransaction(worldStateUpdater, transaction);
tracer.traceStartTransaction(worldStateUpdater, transaction);
result =
Expand Down Expand Up @@ -318,7 +326,8 @@ static T8nResult runTest(
}
if (result.isInvalid()) {
invalidTransactions.add(
new RejectedTransaction(i, result.getValidationResult().getErrorMessage()));
new RejectedTransaction(
transactionIndex, result.getValidationResult().getErrorMessage()));
continue;
}
validTransactions.add(transaction);
Expand Down Expand Up @@ -354,16 +363,30 @@ static T8nResult runTest(
receiptObject.putNull("logs");
} else {
ArrayNode logsArray = receiptObject.putArray("logs");
for (Log log : result.getLogs()) {
logsArray.addPOJO(log);
List<Log> logs = result.getLogs();
for (int logIndex = 0; logIndex < logs.size(); logIndex++) {
Log log = logs.get(logIndex);
var obj = logsArray.addObject();
obj.put("address", log.getLogger().toHexString());
var topics = obj.putArray("topics");
log.getTopics().forEach(topic -> topics.add(topic.toHexString()));
obj.put("data", log.getData().toHexString());
obj.put("blockNumber", blockHeader.getNumber());
obj.put("transactionHash", transaction.getHash().toHexString());
obj.put("transactionIndex", String.format("0x%x", transactionIndex));
obj.put("blockHash", blockHeader.getHash().toHexString());
obj.put("logIndex", String.format("0x%x", logIndex));
obj.put("removed", "false");
}
}
receiptObject.put("transactionHash", transaction.getHash().toHexString());
receiptObject.put(
"contractAddress", transaction.contractAddress().orElse(Address.ZERO).toHexString());
receiptObject.put("gasUsed", gasUsedInTransaction.toQuantityHexString());
receiptObject.put("blockHash", Hash.ZERO.toHexString());
receiptObject.put("transactionIndex", Bytes.ofUnsignedLong(i).toQuantityHexString());
receiptObject.put(
"transactionIndex", Bytes.ofUnsignedLong(transactionIndex).toQuantityHexString());
worldStateUpdater.commit();
}

final ObjectNode resultObject = objectMapper.createObjectNode();
Expand All @@ -375,12 +398,12 @@ static T8nResult runTest(
(rewardString == null)
? protocolSpec.getBlockReward()
: Wei.of(Long.decode(rewardString));
worldStateUpdater
rootWorldStateUpdater
.getOrCreateSenderAccount(blockHeader.getCoinbase())
.incrementBalance(reward);
}

worldStateUpdater.commit();
rootWorldStateUpdater.commit();
// Invoke the withdrawal processor to handle CL withdrawals.
if (!referenceTestEnv.getWithdrawals().isEmpty()) {
try {
Expand Down Expand Up @@ -425,32 +448,58 @@ static T8nResult runTest(
blockHeader
.getWithdrawalsRoot()
.ifPresent(wr -> resultObject.put("withdrawalsRoot", wr.toHexString()));
AtomicLong bgHolder = new AtomicLong(blobGasUsed);
blockHeader
.getExcessBlobGas()
.ifPresent(
ebg -> {
resultObject.put(
"currentExcessBlobGas",
calculateExcessBlobGasForParent(protocolSpec, blockHeader)
.toBytes()
.toQuantityHexString());
resultObject.put(
"blobGasUsed", Bytes.ofUnsignedLong(bgHolder.longValue()).toQuantityHexString());
});
var maybeExcessBlobGas = blockHeader.getExcessBlobGas();
if (maybeExcessBlobGas.isPresent()) {
resultObject.put(
"currentExcessBlobGas",
calculateExcessBlobGasForParent(protocolSpec, blockHeader)
.toBytes()
.toQuantityHexString());
resultObject.put("blobGasUsed", Bytes.ofUnsignedLong(blobGasUsed).toQuantityHexString());
}

var requestProcessorCoordinator = protocolSpec.getRequestProcessorCoordinator();
if (requestProcessorCoordinator.isPresent()) {
var rpc = requestProcessorCoordinator.get();
Optional<List<Request>> maybeRequests = rpc.process(worldState, receipts);
Hash requestRoot = BodyValidation.requestsRoot(maybeRequests.orElse(List.of()));

resultObject.put("requestsRoot", requestRoot.toHexString());
var deposits = resultObject.putArray("depositRequests");
RequestUtil.filterRequestsOfType(maybeRequests.orElse(List.of()), Deposit.class)
.forEach(
deposit -> {
var obj = deposits.addObject();
obj.put("pubkey", deposit.getPubkey().toHexString());
obj.put("withdrawalCredentials", deposit.getWithdrawalCredentials().toHexString());
obj.put("amount", deposit.getAmount().toHexString());
obj.put("signature", deposit.getSignature().toHexString());
obj.put("index", deposit.getIndex().toHexString());
});

var withdrawlRequests = resultObject.putArray("withdrawalRequests");
RequestUtil.filterRequestsOfType(maybeRequests.orElse(List.of()), WithdrawalRequest.class)
.forEach(
wr -> {
var obj = withdrawlRequests.addObject();
obj.put("sourceAddress", wr.getSourceAddress().toHexString());
obj.put("validatorPublicKey", wr.getValidatorPublicKey().toHexString());
obj.put("amount", wr.getAmount().toHexString());
});
}

ObjectNode allocObject = objectMapper.createObjectNode();
worldState
.streamAccounts(Bytes32.ZERO, Integer.MAX_VALUE)
.sorted(Comparator.comparing(o -> o.getAddress().get().toHexString()))
.forEach(
a -> {
var account = worldState.get(a.getAddress().get());
Account account = worldState.get(a.getAddress().get());
ObjectNode accountObject = allocObject.putObject(account.getAddress().toHexString());
if (account.getCode() != null && !account.getCode().isEmpty()) {
accountObject.put("code", account.getCode().toHexString());
}
var storageEntries =
List<Entry<UInt256, UInt256>> storageEntries =
account.storageEntriesFrom(Bytes32.ZERO, Integer.MAX_VALUE).values().stream()
.map(
e ->
Expand Down
Loading

0 comments on commit fb25f18

Please sign in to comment.