Skip to content

Commit

Permalink
add Tx simulate method that accepts state override (#7892)
Browse files Browse the repository at this point in the history
* move AccountOverrides into plugin datatypes; add simulate method that accepts this param

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

---------

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
  • Loading branch information
macfarla authored Nov 20, 2024
1 parent c127f9c commit 55920e0
Show file tree
Hide file tree
Showing 12 changed files with 106 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.services;

import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.ethereum.chain.Blockchain;
Expand Down Expand Up @@ -62,6 +63,17 @@ public Optional<TransactionSimulationResult> simulate(
final Hash blockHash,
final OperationTracer operationTracer,
final boolean isAllowExceedingBalance) {
return simulate(
transaction, Optional.empty(), blockHash, operationTracer, isAllowExceedingBalance);
}

@Override
public Optional<TransactionSimulationResult> simulate(
final Transaction transaction,
final Optional<AccountOverrideMap> maybeAccountOverrides,
final Hash blockHash,
final OperationTracer operationTracer,
final boolean isAllowExceedingBalance) {

final CallParameter callParameter = CallParameter.fromTransaction(transaction);

Expand All @@ -79,6 +91,7 @@ public Optional<TransactionSimulationResult> simulate(
return transactionSimulator
.process(
callParameter,
maybeAccountOverrides,
isAllowExceedingBalance
? SIMULATOR_ALLOWING_EXCEEDING_BALANCE
: TransactionValidationParams.transactionSimulator(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.util;

import org.hyperledger.besu.datatypes.Wei;
package org.hyperledger.besu.datatypes;

import java.util.Map;
import java.util.Objects;
Expand All @@ -26,11 +24,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

// similar to AccountDiff
// BUT
// there are more fields that need to be added
// stateDiff
// movePrecompileToAddress
/** Account Override parameter class */
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonDeserialize(builder = AccountOverride.Builder.class)
public class AccountOverride {
Expand All @@ -52,22 +46,43 @@ private AccountOverride(
this.stateDiff = stateDiff;
}

/**
* Gets the balance override
*
* @return the balance if present
*/
public Optional<Wei> getBalance() {
return balance;
}

/**
* Gets the nonce override
*
* @return the nonce if present
*/
public Optional<Long> getNonce() {
return nonce;
}

/**
* Gets the code override
*
* @return the code if present
*/
public Optional<String> getCode() {
return code;
}

/**
* Gets the state override map
*
* @return the state override map if present
*/
public Optional<Map<String, String>> getStateDiff() {
return stateDiff;
}

/** Builder class for Account overrides */
public static class Builder {
private Optional<Wei> balance = Optional.empty();
private Optional<Long> nonce = Optional.empty();
Expand All @@ -77,31 +92,66 @@ public static class Builder {
/** Default constructor. */
public Builder() {}

/**
* Sets the balance override
*
* @param balance the balance override
* @return the builder
*/
public Builder withBalance(final Wei balance) {
this.balance = Optional.ofNullable(balance);
return this;
}

/**
* Sets the nonce override
*
* @param nonce the nonce override
* @return the builder
*/
public Builder withNonce(final Long nonce) {
this.nonce = Optional.ofNullable(nonce);
return this;
}

/**
* Sets the code override
*
* @param code the code override
* @return the builder
*/
public Builder withCode(final String code) {
this.code = Optional.ofNullable(code);
return this;
}

/**
* Sets the state diff override
*
* @param stateDiff the map of state overrides
* @return the builder
*/
public Builder withStateDiff(final Map<String, String> stateDiff) {
this.stateDiff = Optional.ofNullable(stateDiff);
return this;
}

/**
* build the account override from the builder
*
* @return account override
*/
public AccountOverride build() {
return new AccountOverride(balance, nonce, code, stateDiff);
}
}

/**
* utility method to log unknown properties
*
* @param key key for the unrecognized value
* @param value the unrecognized value
*/
@JsonAnySetter
public void withUnknownProperties(final String key, final Object value) {
LOG.debug(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,16 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.ethereum.util;

import org.hyperledger.besu.datatypes.Address;
package org.hyperledger.besu.datatypes;

import java.util.HashMap;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

/** Map of account overrides, indexed by address */
@JsonIgnoreProperties(ignoreUnknown = true)
public class AccountOverrideMap extends HashMap<Address, AccountOverride> {

/** Default constructor */
public AccountOverrideMap() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.BLOCK_NOT_FOUND;
import static org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType.INTERNAL_ERROR;

import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
Expand All @@ -41,7 +42,6 @@
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
import org.hyperledger.besu.evm.tracing.OperationTracer;

import java.util.Optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;

import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcRequestException;
Expand All @@ -29,7 +30,6 @@
import org.hyperledger.besu.ethereum.transaction.CallParameter;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
import org.hyperledger.besu.evm.tracing.EstimateGasOperationTracer;

import java.util.Optional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import org.hyperledger.besu.datatypes.AccountOverride;
import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
Expand All @@ -51,8 +53,6 @@
import org.hyperledger.besu.ethereum.transaction.PreCloseStateHandler;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
import org.hyperledger.besu.ethereum.util.AccountOverride;
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;

import java.util.Optional;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.hyperledger.besu.datatypes.AccountOverride;
import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
Expand All @@ -44,8 +46,6 @@
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
import org.hyperledger.besu.ethereum.util.AccountOverride;
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.tracing.OperationTracer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccountOverride;
import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobGas;
import org.hyperledger.besu.datatypes.Hash;
Expand All @@ -34,8 +36,6 @@
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.util.AccountOverride;
import org.hyperledger.besu.ethereum.util.AccountOverrideMap;
import org.hyperledger.besu.ethereum.vm.CachingBlockHashLookup;
import org.hyperledger.besu.ethereum.vm.DebugOperationTracer;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
Expand Down Expand Up @@ -105,6 +105,7 @@ public Optional<TransactionSimulatorResult> process(
final BlockHeader header = blockchain.getBlockHeader(blockNumber).orElse(null);
return process(
callParams,
Optional.empty(),
transactionValidationParams,
operationTracer,
(mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult,
Expand All @@ -118,6 +119,7 @@ public Optional<TransactionSimulatorResult> process(
final BlockHeader blockHeader) {
return process(
callParams,
Optional.empty(),
transactionValidationParams,
operationTracer,
(mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.AccountOverride;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash;
Expand All @@ -48,7 +49,6 @@
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult.Status;
import org.hyperledger.besu.ethereum.util.AccountOverride;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.account.Account;
import org.hyperledger.besu.evm.account.MutableAccount;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import org.hyperledger.besu.datatypes.AccountOverride;
import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
Expand Down
2 changes: 1 addition & 1 deletion plugin-api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files
knownHash = 'wOjR3/uPElPs1GonuLMBWStn1zukFMyy/GfQ9OYChpI='
knownHash = 'IPpTJJxjDbjW08c3Cm8GbBhULYFy0jq9m3BzliGzrf8='
}
check.dependsOn('checkAPIChanges')

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.plugin.services;

import org.hyperledger.besu.datatypes.AccountOverrideMap;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Transaction;
import org.hyperledger.besu.evm.tracing.OperationTracer;
Expand All @@ -39,4 +40,21 @@ Optional<TransactionSimulationResult> simulate(
Hash blockHash,
OperationTracer operationTracer,
boolean isAllowExceedingBalance);

/**
* Simulate transaction execution at the block identified by the hash
*
* @param transaction tx
* @param accountOverrides state overrides to apply to this simulation
* @param blockHash the hash of the block
* @param operationTracer the tracer
* @param isAllowExceedingBalance should ignore the sender balance during the simulation?
* @return the result of the simulation
*/
Optional<TransactionSimulationResult> simulate(
Transaction transaction,
Optional<AccountOverrideMap> accountOverrides,
Hash blockHash,
OperationTracer operationTracer,
boolean isAllowExceedingBalance);
}

0 comments on commit 55920e0

Please sign in to comment.