T8n support for isStateTest and empty accounts (#7275)

Update t8n executor to support new isStateTest env flag that will
disable extra-transactional processing such as block rewards and beacon
root.
Also, make sure such extra-transactional commits don't create empty
accounts.

Signed-off-by: Danno Ferrin <danno@numisight.com>
Co-authored-by: Usman Saleem <usman@usmans.info>
pull/7278/head
Danno Ferrin 5 months ago committed by GitHub
parent 3c5ce8bb89
commit 75f565e0c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 53
      ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nExecutor.java
  2. 3
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/BlockchainReferenceTestCaseSpec.java
  3. 23
      ethereum/referencetests/src/main/java/org/hyperledger/besu/ethereum/referencetests/ReferenceTestEnv.java

@ -51,6 +51,7 @@ 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.trie.diffbased.common.DiffBasedAccount;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.hyperledger.besu.evm.log.Log;
@ -265,9 +266,11 @@ public class T8nExecutor {
.blobGasPricePerGas(calculateExcessBlobGasForParent(protocolSpec, blockHeader));
long blobGasLimit = protocolSpec.getGasLimitCalculator().currentBlobGasLimit();
protocolSpec
.getBlockHashProcessor()
.processBlockHashes(blockchain, worldState, referenceTestEnv);
if (!referenceTestEnv.isStateTest()) {
protocolSpec
.getBlockHashProcessor()
.processBlockHashes(blockchain, worldState, referenceTestEnv);
}
final WorldUpdater rootWorldStateUpdater = worldState.updater();
List<TransactionReceipt> receipts = new ArrayList<>();
@ -318,13 +321,12 @@ public class T8nExecutor {
timer.stop();
if (shouldClearEmptyAccounts(fork)) {
final Account coinbase = worldStateUpdater.getOrCreate(blockHeader.getCoinbase());
if (coinbase != null && coinbase.isEmpty()) {
worldStateUpdater.deleteAccount(coinbase.getAddress());
}
final Account txSender = worldStateUpdater.getAccount(transaction.getSender());
if (txSender != null && txSender.isEmpty()) {
worldStateUpdater.deleteAccount(txSender.getAddress());
var entries = new ArrayList<>(worldState.getAccumulator().getAccountsToUpdate().entrySet());
for (var entry : entries) {
DiffBasedAccount updated = entry.getValue().getUpdated();
if (updated != null && updated.isEmpty()) {
worldState.getAccumulator().deleteAccount(entry.getKey());
}
}
}
if (result.isInvalid()) {
@ -397,7 +399,9 @@ public class T8nExecutor {
// block reward
// The max production reward was 5 Eth, longs can hold over 18 Eth.
if (!validTransactions.isEmpty() && (rewardString == null || Long.decode(rewardString) > 0)) {
if (!referenceTestEnv.isStateTest()
&& !validTransactions.isEmpty()
&& (rewardString == null || Long.decode(rewardString) > 0)) {
Wei reward =
(rewardString == null)
? protocolSpec.getBlockReward()
@ -408,15 +412,24 @@ public class T8nExecutor {
}
rootWorldStateUpdater.commit();
// Invoke the withdrawal processor to handle CL withdrawals.
if (!referenceTestEnv.getWithdrawals().isEmpty()) {
try {
protocolSpec
.getWithdrawalsProcessor()
.ifPresent(
p -> p.processWithdrawals(referenceTestEnv.getWithdrawals(), worldState.updater()));
} catch (RuntimeException re) {
resultObject.put("exception", re.getMessage());
if (referenceTestEnv.isStateTest()) {
if (!referenceTestEnv.getWithdrawals().isEmpty()) {
resultObject.put("exception", "withdrawals are not supported in state tests");
}
} else {
// Invoke the withdrawal processor to handle CL withdrawals.
if (!referenceTestEnv.getWithdrawals().isEmpty()) {
try {
protocolSpec
.getWithdrawalsProcessor()
.ifPresent(
p ->
p.processWithdrawals(
referenceTestEnv.getWithdrawals(), worldState.updater()));
} catch (RuntimeException re) {
resultObject.put("exception", re.getMessage());
}
}
}

@ -249,7 +249,8 @@ public class BlockchainReferenceTestCaseSpec {
@JsonProperty("uncleHeaders") final Object uncleHeaders,
@JsonProperty("withdrawals") final Object withdrawals,
@JsonProperty("depositRequests") final Object depositRequests,
@JsonProperty("withdrawalRequests") final Object withdrawalRequests) {
@JsonProperty("withdrawalRequests") final Object withdrawalRequests,
@JsonProperty("consolidationRequests") final Object consolidationRequests) {
boolean blockVaid = true;
// The BLOCK__WrongCharAtRLP_0 test has an invalid character in its rlp string.
Bytes rlpAttempt = null;

@ -83,6 +83,8 @@ public class ReferenceTestEnv extends BlockHeader {
private final Bytes32 beaconRoot;
private final boolean isStateTest;
/**
* Public constructor.
*
@ -120,7 +122,8 @@ public class ReferenceTestEnv extends BlockHeader {
@JsonProperty("parentGasLimit") final String parentGasLimit,
@JsonProperty("parentGasUsed") final String parentGasUsed,
@JsonProperty("parentTimestamp") final String parentTimestamp,
@JsonProperty("parentUncleHash") final String _parentUncleHash) {
@JsonProperty("parentUncleHash") final String _parentUncleHash,
@JsonProperty("isStateTest") final String isStateTest) {
super(
generateTestBlockHash(previousHash, number),
Hash.EMPTY_LIST_HASH, // ommersHash
@ -164,10 +167,16 @@ public class ReferenceTestEnv extends BlockHeader {
Map.entry(
Long.decode(entry.getKey()), Hash.fromHexString(entry.getValue())))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
this.beaconRoot =
beaconRoot == null
? (currentBeaconRoot == null ? null : Hash.fromHexString(currentBeaconRoot))
: Hash.fromHexString(beaconRoot);
if (beaconRoot == null) {
if (currentBeaconRoot == null) {
this.beaconRoot = null;
} else {
this.beaconRoot = Hash.fromHexString(currentBeaconRoot);
}
} else {
this.beaconRoot = Hash.fromHexString(beaconRoot);
}
this.isStateTest = Boolean.parseBoolean(isStateTest);
}
@Override
@ -239,6 +248,10 @@ public class ReferenceTestEnv extends BlockHeader {
return blockHashes;
}
public boolean isStateTest() {
return isStateTest;
}
@Override
public boolean equals(final Object o) {
if (this == o) return true;

Loading…
Cancel
Save