Skip to content

Commit

Permalink
HIP-584: Handle read only precompile calls via ViewExecutor/RedirectV…
Browse files Browse the repository at this point in the history
…iewExecutor (#6557)

This PR allows all type of calls (view/pure/dynamic) to read only precompiles to be handled via ViewExecutor/RedirectViewExecutor, thus removing the need of having a copy of separate precompile class implementations.

That is possible since the executors read the data from the same place (the Store interface) and they share the same gas calculation logic with the precompile class implementations in hedera-services codebase. Consequently, we could just reuse the executor logic to handle eth_call and eth_estimateGas requests.

Signed-off-by: Ivan Ivanov <ivanivanov.ii726@gmail.com>
Signed-off-by: IvanKavaldzhiev <ivankavaldzhiev@gmail.com>
Co-authored-by: Ivan Ivanov <ivanivanov.ii726@gmail.com>
  • Loading branch information
IvanKavaldzhiev and 0xivanov authored Aug 1, 2023
1 parent 618ca58 commit 7759c70
Showing 1 changed file with 14 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,17 @@
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;
import org.hyperledger.besu.evm.precompile.PrecompiledContract.PrecompileContractResult;

/**
* This class is a modified copy of HTSPrecompiledContract from hedera-services repo. Additionally, it implements an
* adapter interface which is used by
* {@link com.hedera.mirror.web3.evm.store.contract.precompile.MirrorHTSPrecompiledContract}. In this way once we start
* consuming libraries like smart-contract-service it would be easier to delete the code base inside com.hedera.services package.
*
* Differences with the original class:
* 1. Use abstraction for the state by introducing {@link Store} interface.
* 2. Use workaround to execute read only precompiles via calling ViewExecutor and RedirectViewExecutors, thus removing the need of having separate precompile classes
*/
public class HTSPrecompiledContract implements HTSPrecompiledContractAdapter {

Expand Down Expand Up @@ -132,21 +135,20 @@ public Pair<Long, Bytes> computeCosted(

return evmHTSPrecompiledContract.computeCosted(input, frame, viewGasCalculator, tokenAccessor);
}
final var result = computePrecompile(input, frame);
return Pair.of(gasRequirement, result.getOutput());
}

@NonNull
public PrecompileContractResult computePrecompile(final Bytes input, @NonNull final MessageFrame frame) {
/* TODO Temporary workaround allowing eth_call to execute precompile methods in a dynamic context (non pure/view).
This is done by calling ViewExecutor/RedirectViewExecutor logic instead of Precompile classes.
After the Precompile classes are implemented, this workaround won't be needed. */
/* Workaround allowing execution of read only precompile methods in a dynamic context (non pure/view).
This is done by calling ViewExecutor/RedirectViewExecutor logic instead of Precompile classes.*/

// redirect operations
if ((isTokenProxyRedirect(input) || isViewFunction(input)) && !isNestedFunctionSelectorForWrite(input)) {
return handleReadsFromDynamicContext(input, frame);
}

final var result = computePrecompile(input, frame);
return Pair.of(gasRequirement, result.getOutput());
}

@NonNull
public PrecompileContractResult computePrecompile(final Bytes input, @NonNull final MessageFrame frame) {
if (unqualifiedDelegateDetected(frame)) {
frame.setExceptionalHaltReason(Optional.of(ExceptionalHaltReason.PRECOMPILE_ERROR));
return INVALID_DELEGATE;
Expand Down Expand Up @@ -357,8 +359,7 @@ void prepareFields(final MessageFrame frame) {
this.mirrorNodeEvmProperties = updater.aliases();
}

private PrecompiledContract.PrecompileContractResult handleReadsFromDynamicContext(
final Bytes input, @NonNull final MessageFrame frame) {
private Pair<Long, Bytes> handleReadsFromDynamicContext(final Bytes input, @NonNull final MessageFrame frame) {
Pair<Long, Bytes> resultFromExecutor = Pair.of(-1L, Bytes.EMPTY);
if (isTokenProxyRedirect(input)) {
final var executor =
Expand All @@ -368,14 +369,11 @@ private PrecompiledContract.PrecompileContractResult handleReadsFromDynamicConte
if (resultFromExecutor.getRight() == null) {
throw new UnsupportedOperationException(UNSUPPORTED_ERROR);
}

} else if (isViewFunction(input)) {
final var executor = infrastructureFactory.newViewExecutor(input, frame, viewGasCalculator, tokenAccessor);
resultFromExecutor = executor.computeCosted();
}
return resultFromExecutor == null
? PrecompileContractResult.halt(null, Optional.of(ExceptionalHaltReason.NONE))
: PrecompileContractResult.success(resultFromExecutor.getRight());
return resultFromExecutor;
}

private boolean isNestedFunctionSelectorForWrite(Bytes input) {
Expand Down

0 comments on commit 7759c70

Please sign in to comment.