add Tx simulate method that accepts state override (#7892)

* 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>
main
Sally MacFarlane 13 hours ago committed by GitHub
parent c127f9c1d7
commit 55920e002a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 13
      besu/src/main/java/org/hyperledger/besu/services/TransactionSimulationServiceImpl.java
  2. 66
      datatypes/src/main/java/org/hyperledger/besu/datatypes/AccountOverride.java
  3. 6
      datatypes/src/main/java/org/hyperledger/besu/datatypes/AccountOverrideMap.java
  4. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java
  5. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java
  6. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java
  7. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java
  8. 6
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  9. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java
  10. 2
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/util/AccountOverrideParameterTest.java
  11. 2
      plugin-api/build.gradle
  12. 18
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/TransactionSimulationService.java

@ -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;
@ -62,6 +63,17 @@ public class TransactionSimulationServiceImpl implements TransactionSimulationSe
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);
@ -79,6 +91,7 @@ public class TransactionSimulationServiceImpl implements TransactionSimulationSe
return transactionSimulator
.process(
callParameter,
maybeAccountOverrides,
isAllowExceedingBalance
? SIMULATOR_ALLOWING_EXCEEDING_BALANCE
: TransactionValidationParams.transactionSimulator(),

@ -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;
@ -26,11 +24,7 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
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 {
@ -52,22 +46,43 @@ public class 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();
@ -77,31 +92,66 @@ public class AccountOverride {
/** 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(

@ -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() {}
}

@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
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;
@ -41,7 +42,6 @@ import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult;
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;

@ -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;
@ -29,7 +30,6 @@ import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams;
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;

@ -27,6 +27,8 @@ import static org.mockito.Mockito.verify;
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;
@ -51,8 +53,6 @@ import org.hyperledger.besu.ethereum.transaction.CallParameter;
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;

@ -21,6 +21,8 @@ import static org.mockito.Mockito.mock;
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;
@ -44,8 +46,6 @@ import org.hyperledger.besu.ethereum.transaction.CallParameter;
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;

@ -19,6 +19,8 @@ import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalcu
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;
@ -34,8 +36,6 @@ 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.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;
@ -105,6 +105,7 @@ public class TransactionSimulator {
final BlockHeader header = blockchain.getBlockHeader(blockNumber).orElse(null);
return process(
callParams,
Optional.empty(),
transactionValidationParams,
operationTracer,
(mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult,
@ -118,6 +119,7 @@ public class TransactionSimulator {
final BlockHeader blockHeader) {
return process(
callParams,
Optional.empty(),
transactionValidationParams,
operationTracer,
(mutableWorldState, transactionSimulatorResult) -> transactionSimulatorResult,

@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
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;
@ -48,7 +49,6 @@ 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.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;

@ -18,6 +18,8 @@ import static org.assertj.core.api.Assertions.assertThat;
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;

@ -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')

@ -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;
@ -39,4 +40,21 @@ public interface TransactionSimulationService extends BesuService {
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);
}

Loading…
Cancel
Save