Richer return information for Precompiled Contracts (#3546)

Allow precompiled contracts to return richer information instead of
results/fail. System/precompile contracts can now revert, fail, refund
gas, etc. instead of just succeed or fail.

Signed-off-by: Danno Ferrin <danno.ferrin@gmail.com>
pull/3556/head
Danno Ferrin 3 years ago committed by GitHub
parent de432ce32e
commit ed54f09f8a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 7
      ethereum/core/src/integration-test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractIntegrationTest.java
  3. 19
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/FlexiblePrivacyPrecompiledContract.java
  4. 13
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPluginPrecompiledContract.java
  5. 23
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContract.java
  6. 31
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/FlexiblePrivacyPrecompiledContractTest.java
  7. 5
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPluginPrecompiledContractTest.java
  8. 38
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/mainnet/precompiles/privacy/PrivacyPrecompiledContractTest.java
  9. 9
      evm/src/main/java/org/hyperledger/besu/evm/precompile/AbstractPrecompiledContract.java
  10. 89
      evm/src/main/java/org/hyperledger/besu/evm/precompile/PrecompiledContract.java
  11. 37
      evm/src/main/java/org/hyperledger/besu/evm/processor/MessageCallProcessor.java
  12. 6
      evm/src/test/java/org/hyperledger/besu/evm/precompile/Benchmarks.java

@ -10,6 +10,7 @@
- new API methods: trace_rawTransaction, trace_get, trace_callMany
- added revertReason to trace APIs including: trace_transaction, trace_get, trace_call, trace_callMany, and trace_rawTransaction
- Allow mining beneficiary to transition at specific blocks for ibft2 and qbft consensus mechanisms. [#3115](https://github.com/hyperledger/besu/issues/3115)
- Return richer information from the PrecompiledContract interface. [\#3546](https://github.com/hyperledger/besu/pull/3546)
### Bug Fixes
- Reject locally-sourced transactions below the minimum gas price when not mining. [#3397](https://github.com/hyperledger/besu/pull/3397)

@ -47,6 +47,7 @@ import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.enclave.testutil.EnclaveKeyConfiguration;
@ -203,8 +204,10 @@ public class PrivacyPrecompiledContractIntegrationTest {
privacyPrecompiledContract.setPrivateTransactionProcessor(mockPrivateTxProcessor());
final Bytes actual =
privacyPrecompiledContract.compute(Bytes.fromBase64String(sr.getKey()), messageFrame);
final PrecompiledContract.PrecompileContractResult result =
privacyPrecompiledContract.computePrecompile(
Bytes.fromBase64String(sr.getKey()), messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.fromHexString(DEFAULT_OUTPUT));
}

@ -99,10 +99,10 @@ public class FlexiblePrivacyPrecompiledContract extends PrivacyPrecompiledContra
}
@Override
public Bytes compute(final Bytes input, final MessageFrame messageFrame) {
public PrecompileContractResult computePrecompile(
final Bytes input, final MessageFrame messageFrame) {
if (skipContractExecution(messageFrame)) {
return Bytes.EMPTY;
return NO_RESULT;
}
final Hash pmtHash = messageFrame.getContextVariable(KEY_TRANSACTION_HASH);
@ -114,7 +114,7 @@ public class FlexiblePrivacyPrecompiledContract extends PrivacyPrecompiledContra
receiveResponse = getReceiveResponse(key);
} catch (final EnclaveClientException e) {
LOG.debug("Can not fetch private transaction payload with key {}", key, e);
return Bytes.EMPTY;
return NO_RESULT;
}
final BytesValueRLPInput bytesValueRLPInput =
@ -127,12 +127,12 @@ public class FlexiblePrivacyPrecompiledContract extends PrivacyPrecompiledContra
final Bytes privateFrom = privateTransaction.getPrivateFrom();
if (!privateFromMatchesSenderKey(privateFrom, receiveResponse.getSenderKey())) {
return Bytes.EMPTY;
return NO_RESULT;
}
final Optional<Bytes> maybeGroupId = privateTransaction.getPrivacyGroupId();
if (maybeGroupId.isEmpty()) {
return Bytes.EMPTY;
return NO_RESULT;
}
final Bytes32 privacyGroupId = Bytes32.wrap(maybeGroupId.get());
@ -168,7 +168,7 @@ public class FlexiblePrivacyPrecompiledContract extends PrivacyPrecompiledContra
disposablePrivateState,
privateWorldStateUpdater,
privateFrom)) {
return Bytes.EMPTY;
return NO_RESULT;
}
final TransactionProcessingResult result =
@ -183,7 +183,7 @@ public class FlexiblePrivacyPrecompiledContract extends PrivacyPrecompiledContra
privateMetadataUpdater.putTransactionReceipt(pmtHash, new PrivateTransactionReceipt(result));
return Bytes.EMPTY;
return NO_RESULT;
}
sendParticipantRemovedEvent(privateTransaction);
@ -197,7 +197,8 @@ public class FlexiblePrivacyPrecompiledContract extends PrivacyPrecompiledContra
pmtHash, privacyGroupId, disposablePrivateState, privateMetadataUpdater, result);
}
return result.getOutput();
return new PrecompileContractResult(
result.getOutput(), true, MessageFrame.State.CODE_EXECUTING, Optional.empty());
}
private void sendParticipantRemovedEvent(final PrivateTransaction privateTransaction) {

@ -44,10 +44,10 @@ public class PrivacyPluginPrecompiledContract extends PrivacyPrecompiledContract
}
@Override
public Bytes compute(final Bytes input, final MessageFrame messageFrame) {
public PrecompileContractResult computePrecompile(
final Bytes input, final MessageFrame messageFrame) {
if (skipContractExecution(messageFrame)) {
return Bytes.EMPTY;
return NO_RESULT;
}
final Optional<org.hyperledger.besu.plugin.data.PrivateTransaction> pluginPrivateTransaction =
@ -58,7 +58,7 @@ public class PrivacyPluginPrecompiledContract extends PrivacyPrecompiledContract
messageFrame.getContextVariable(PrivateStateUtils.KEY_TRANSACTION));
if (pluginPrivateTransaction.isEmpty()) {
return Bytes.EMPTY;
return NO_RESULT;
}
final PrivateTransaction privateTransaction =
@ -101,7 +101,7 @@ public class PrivacyPluginPrecompiledContract extends PrivacyPrecompiledContract
privateMetadataUpdater.putTransactionReceipt(pmtHash, new PrivateTransactionReceipt(result));
return Bytes.EMPTY;
return NO_RESULT;
}
if (messageFrame.getContextVariable(PrivateStateUtils.KEY_IS_PERSISTING_PRIVATE_STATE, false)) {
@ -113,6 +113,7 @@ public class PrivacyPluginPrecompiledContract extends PrivacyPrecompiledContract
pmtHash, privacyGroupId, disposablePrivateState, privateMetadataUpdater, result);
}
return result.getOutput();
return new PrecompileContractResult(
result.getOutput(), true, MessageFrame.State.CODE_EXECUTING, Optional.empty());
}
}

@ -50,6 +50,7 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.Hash;
import java.util.Base64;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
@ -65,6 +66,10 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
private static final Logger LOG = LoggerFactory.getLogger(PrivacyPrecompiledContract.class);
static final PrecompileContractResult NO_RESULT =
new PrecompileContractResult(
Bytes.EMPTY, true, MessageFrame.State.CODE_EXECUTING, Optional.empty());
public PrivacyPrecompiledContract(
final GasCalculator gasCalculator,
final PrivacyParameters privacyParameters,
@ -103,10 +108,11 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
}
@Override
public Bytes compute(final Bytes input, final MessageFrame messageFrame) {
public PrecompileContractResult computePrecompile(
final Bytes input, final MessageFrame messageFrame) {
if (skipContractExecution(messageFrame)) {
return Bytes.EMPTY;
return NO_RESULT;
}
final org.hyperledger.besu.plugin.data.Hash pmtHash =
@ -118,7 +124,7 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
receiveResponse = getReceiveResponse(key);
} catch (final EnclaveClientException e) {
LOG.debug("Can not fetch private transaction payload with key {}", key, e);
return Bytes.EMPTY;
return NO_RESULT;
}
final BytesValueRLPInput bytesValueRLPInput =
@ -129,7 +135,7 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
final Bytes privateFrom = privateTransaction.getPrivateFrom();
if (!privateFromMatchesSenderKey(privateFrom, receiveResponse.getSenderKey())) {
return Bytes.EMPTY;
return NO_RESULT;
}
final Bytes32 privacyGroupId =
@ -141,11 +147,11 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
.retrievePrivacyGroup(privacyGroupId.toBase64String())
.getMembers()
.contains(privateFrom.toBase64String())) {
return Bytes.EMPTY;
return NO_RESULT;
}
} catch (final EnclaveClientException e) {
// This exception is thrown when the privacy group can not be found
return Bytes.EMPTY;
return NO_RESULT;
} catch (final EnclaveServerException e) {
throw new IllegalStateException(
"Enclave is responding with an error, perhaps it has a misconfiguration?", e);
@ -184,7 +190,7 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
privateMetadataUpdater.putTransactionReceipt(pmtHash, new PrivateTransactionReceipt(result));
return Bytes.EMPTY;
return NO_RESULT;
}
if (messageFrame.getContextVariable(KEY_IS_PERSISTING_PRIVATE_STATE, false)) {
@ -195,7 +201,8 @@ public class PrivacyPrecompiledContract extends AbstractPrecompiledContract {
pmtHash, privacyGroupId, disposablePrivateState, privateMetadataUpdater, result);
}
return result.getOutput();
return new PrecompileContractResult(
result.getOutput(), true, MessageFrame.State.CODE_EXECUTING, Optional.empty());
}
protected void maybeApplyGenesisToPrivateWorldState(

@ -54,6 +54,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@ -166,7 +167,9 @@ public class FlexiblePrivacyPrecompiledContractTest {
.when(contractSpy)
.canExecute(any(), any(), any(), any(), any(), any(), any(), any());
final Bytes actual = contractSpy.compute(privateTransactionLookupId, messageFrame);
final PrecompiledContract.PrecompileContractResult result =
contractSpy.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.fromHexString(DEFAULT_OUTPUT));
}
@ -178,8 +181,11 @@ public class FlexiblePrivacyPrecompiledContractTest {
when(enclave.receive(any(String.class))).thenThrow(EnclaveClientException.class);
final Bytes expected = contract.compute(privateTransactionLookupId, messageFrame);
assertThat(expected).isEqualTo(Bytes.EMPTY);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.EMPTY);
}
@Test(expected = RuntimeException.class)
@ -189,7 +195,7 @@ public class FlexiblePrivacyPrecompiledContractTest {
when(enclave.receive(any(String.class))).thenThrow(new RuntimeException());
contract.compute(privateTransactionLookupId, messageFrame);
contract.computePrecompile(privateTransactionLookupId, messageFrame);
}
@Test
@ -205,7 +211,7 @@ public class FlexiblePrivacyPrecompiledContractTest {
when(enclave.receive(eq(privateTransactionLookupId.toBase64String())))
.thenReturn(responseWithoutSenderKey);
assertThatThrownBy(() -> contract.compute(privateTransactionLookupId, messageFrame))
assertThatThrownBy(() -> contract.computePrecompile(privateTransactionLookupId, messageFrame))
.isInstanceOf(EnclaveConfigurationException.class)
.hasMessage("Incompatible Orion version. Orion version must be 1.6.0 or greater.");
}
@ -224,8 +230,11 @@ public class FlexiblePrivacyPrecompiledContractTest {
when(enclave.receive(eq(privateTransactionLookupId.toBase64String())))
.thenReturn(responseWithWrongSenderKey);
final Bytes expected = contract.compute(privateTransactionLookupId, messageFrame);
assertThat(expected).isEqualTo(Bytes.EMPTY);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.EMPTY);
}
@Test
@ -282,7 +291,9 @@ public class FlexiblePrivacyPrecompiledContractTest {
new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, privateFrom);
when(enclave.receive(any(String.class))).thenReturn(response);
final Bytes actual = contractSpy.compute(privateTransactionLookupId, messageFrame);
final PrecompiledContract.PrecompileContractResult result =
contractSpy.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.EMPTY);
}
@ -319,7 +330,9 @@ public class FlexiblePrivacyPrecompiledContractTest {
when(enclave.receive(any(String.class))).thenReturn(response);
final Bytes actual = contractSpy.compute(privateTransactionLookupId, messageFrame);
final PrecompiledContract.PrecompileContractResult result =
contractSpy.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.EMPTY);
}

@ -47,6 +47,7 @@ import org.hyperledger.besu.ethereum.vm.BlockHashLookup;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import org.hyperledger.besu.plugin.data.PrivacyGenesis;
@ -181,7 +182,9 @@ public class PrivacyPluginPrecompiledContractTest {
when(messageFrame.getContextVariable(KEY_TRANSACTION)).thenReturn(transaction);
final Bytes actual = contract.compute(payload, messageFrame);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(payload, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.fromHexString(DEFAULT_OUTPUT));
}

@ -57,6 +57,7 @@ import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.SpuriousDragonGasCalculator;
import org.hyperledger.besu.evm.log.Log;
import org.hyperledger.besu.evm.precompile.PrecompiledContract;
import org.hyperledger.besu.evm.tracing.OperationTracer;
import org.hyperledger.besu.evm.worldstate.WorldUpdater;
@ -169,7 +170,9 @@ public class PrivacyPrecompiledContractTest {
new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, privateFrom);
when(enclave.receive(any(String.class))).thenReturn(response);
final Bytes actual = contract.compute(privateTransactionLookupId, messageFrame);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.fromHexString(DEFAULT_OUTPUT));
}
@ -181,8 +184,11 @@ public class PrivacyPrecompiledContractTest {
when(enclave.receive(any(String.class))).thenThrow(EnclaveClientException.class);
final Bytes expected = contract.compute(privateTransactionLookupId, messageFrame);
assertThat(expected).isEqualTo(Bytes.EMPTY);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.EMPTY);
}
@Test(expected = RuntimeException.class)
@ -192,7 +198,7 @@ public class PrivacyPrecompiledContractTest {
when(enclave.receive(any(String.class))).thenThrow(new RuntimeException());
contract.compute(privateTransactionLookupId, messageFrame);
contract.computePrecompile(privateTransactionLookupId, messageFrame);
}
@Test
@ -207,7 +213,7 @@ public class PrivacyPrecompiledContractTest {
when(enclave.receive(eq(privateTransactionLookupId.toBase64String())))
.thenReturn(responseWithoutSenderKey);
assertThatThrownBy(() -> contract.compute(privateTransactionLookupId, messageFrame))
assertThatThrownBy(() -> contract.computePrecompile(privateTransactionLookupId, messageFrame))
.isInstanceOf(EnclaveConfigurationException.class)
.hasMessage("Incompatible Orion version. Orion version must be 1.6.0 or greater.");
}
@ -242,8 +248,11 @@ public class PrivacyPrecompiledContractTest {
when(enclave.receive(eq(privateTransactionLookupId.toBase64String())))
.thenReturn(responseWithWrongSenderKey);
final Bytes expected = contract.compute(privateTransactionLookupId, messageFrame);
assertThat(expected).isEqualTo(Bytes.EMPTY);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.EMPTY);
}
@Test
@ -271,7 +280,9 @@ public class PrivacyPrecompiledContractTest {
new ReceiveResponse(payload, PAYLOAD_TEST_PRIVACY_GROUP_ID, privateFrom);
when(enclave.receive(any(String.class))).thenReturn(response);
final Bytes actual = contract.compute(privateTransactionLookupId, messageFrame);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.fromHexString(DEFAULT_OUTPUT));
}
@ -310,7 +321,9 @@ public class PrivacyPrecompiledContractTest {
when(enclave.receive(any(String.class))).thenReturn(response);
final Bytes actual = contract.compute(privateTransactionLookupId, messageFrame);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(privateTransactionLookupId, messageFrame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.EMPTY);
}
@ -324,8 +337,11 @@ public class PrivacyPrecompiledContractTest {
final MessageFrame frame = mock(MessageFrame.class);
when(frame.getContextVariable(KEY_PRIVATE_METADATA_UPDATER)).thenReturn(null);
final Bytes result = emptyContract.compute(null, frame);
assertThat(result).isEqualTo(Bytes.EMPTY);
final PrecompiledContract.PrecompileContractResult result =
emptyContract.computePrecompile(null, frame);
final Bytes actual = result.getOutput();
assertThat(actual).isEqualTo(Bytes.EMPTY);
}
private byte[] convertPrivateTransactionToBytes(final PrivateTransaction privateTransaction) {

@ -14,11 +14,8 @@
*/
package org.hyperledger.besu.evm.precompile;
import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.frame.MessageFrame;
import org.hyperledger.besu.evm.gascalculator.GasCalculator;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -45,10 +42,4 @@ public abstract class AbstractPrecompiledContract implements PrecompiledContract
public String getName() {
return name;
}
@Override
public abstract Gas gasRequirement(Bytes input);
@Override
public abstract Bytes compute(Bytes input, MessageFrame messageFrame);
}

@ -15,8 +15,10 @@
package org.hyperledger.besu.evm.precompile;
import org.hyperledger.besu.evm.Gas;
import org.hyperledger.besu.evm.frame.ExceptionalHaltReason;
import org.hyperledger.besu.evm.frame.MessageFrame;
import java.util.Optional;
import javax.annotation.Nonnull;
import org.apache.tuweni.bytes.Bytes;
@ -52,5 +54,90 @@ public interface PrecompiledContract {
* @param messageFrame context for this message
* @return the output of the pre-compiled contract.
*/
Bytes compute(Bytes input, @Nonnull MessageFrame messageFrame);
@SuppressWarnings("deprecation")
default PrecompileContractResult computePrecompile(
final Bytes input, @Nonnull final MessageFrame messageFrame) {
final Bytes result = compute(input, messageFrame);
if (result == null) {
return PrecompileContractResult.halt(null, Optional.of(ExceptionalHaltReason.NONE));
} else {
return PrecompileContractResult.success(result);
}
}
/**
* Executes the pre-compiled contract.
*
* @param input the input for the pre-compiled contract.
* @param messageFrame context for this message
* @return the output of the pre-compiled contract.
* @deprecated Migrate to use {@link #computePrecompile(Bytes, MessageFrame)}.
*/
@Deprecated(since = "22.1.2")
default Bytes compute(final Bytes input, final @Nonnull MessageFrame messageFrame) {
return computePrecompile(input, messageFrame).getOutput();
}
class PrecompileContractResult {
private final Bytes output;
private final boolean refundGas;
private final MessageFrame.State state;
private final Optional<ExceptionalHaltReason> haltReason;
/**
* Encapsulated result of precompiled contract.
*
* @param output output if successfull
* @param refundGas Should we charge the gasRequirement?
* @param state state of the EVM after execution (for format errors this would be
* ExceptionalHalt)
* @param haltReason the exceptional halt reason
*/
// TOO JDK17 use a record
public PrecompileContractResult(
final Bytes output,
final boolean refundGas,
final MessageFrame.State state,
final Optional<ExceptionalHaltReason> haltReason) {
this.output = output;
this.refundGas = refundGas;
this.state = state;
this.haltReason = haltReason;
}
public static PrecompileContractResult success(final Bytes output) {
return new PrecompileContractResult(
output, false, MessageFrame.State.COMPLETED_SUCCESS, Optional.empty());
}
public static PrecompileContractResult revert(final Bytes output) {
return new PrecompileContractResult(
output, false, MessageFrame.State.REVERT, Optional.empty());
}
public static PrecompileContractResult halt(
final Bytes output, final Optional<ExceptionalHaltReason> haltReason) {
if (haltReason.isEmpty()) {
throw new IllegalArgumentException("Halt reason cannot be empty");
}
return new PrecompileContractResult(
output, false, MessageFrame.State.EXCEPTIONAL_HALT, haltReason);
}
public Bytes getOutput() {
return output;
}
public boolean isRefundGas() {
return refundGas;
}
public MessageFrame.State getState() {
return state;
}
public Optional<ExceptionalHaltReason> getHaltReason() {
return haltReason;
}
}
}

@ -31,7 +31,6 @@ import java.util.Objects;
import java.util.Optional;
import com.google.common.collect.ImmutableSet;
import org.apache.tuweni.bytes.Bytes;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -150,28 +149,24 @@ public class MessageCallProcessor extends AbstractMessageProcessor {
frame.setState(MessageFrame.State.EXCEPTIONAL_HALT);
} else {
frame.decrementRemainingGas(gasRequirement);
final Bytes output = contract.compute(frame.getInputData(), frame);
operationTracer.tracePrecompileCall(frame, gasRequirement, output);
if (output != null) {
if (contract.getName().equals("Privacy")
|| contract.getName().equals("FlexiblePrivacy")
|| contract.getName().equals("PluginPrivacy")) {
// do not decrement the gas requirement for a privacy pre-compile contract call -> leads
// to discrepancies in receipts root between public and private nodes in a network.
frame.incrementRemainingGas(gasRequirement);
frame.setState(MessageFrame.State.CODE_EXECUTING);
return;
}
frame.setOutputData(output);
LOG.trace(
"Precompiled contract {} successfully executed (gas consumed: {})",
contract.getName(),
gasRequirement);
frame.setState(MessageFrame.State.COMPLETED_SUCCESS);
final PrecompiledContract.PrecompileContractResult result =
contract.computePrecompile(frame.getInputData(), frame);
operationTracer.tracePrecompileCall(frame, gasRequirement, result.getOutput());
if (result.isRefundGas()) {
frame.incrementRemainingGas(gasRequirement);
}
if (frame.getState() == MessageFrame.State.REVERT) {
frame.setRevertReason(result.getOutput());
} else {
LOG.trace("Precompiled contract {} failed (gas consumed: {})", contract, gasRequirement);
frame.setState(MessageFrame.State.EXCEPTIONAL_HALT);
frame.setOutputData(result.getOutput());
}
frame.setState(result.getState());
frame.setExceptionalHaltReason(result.getHaltReason());
LOG.trace(
"Precompiled contract {} {} (gasComsumed: {})",
contract.getName(),
result.getState(),
result.isRefundGas() ? Gas.ZERO : gasRequirement);
}
}
}

@ -620,16 +620,16 @@ public class Benchmarks {
}
private static double runBenchmark(final Bytes arg, final PrecompiledContract contract) {
if (contract.compute(arg, fakeFrame) == null) {
if (contract.computePrecompile(arg, fakeFrame).getOutput() == null) {
throw new RuntimeException("Input is Invalid");
}
for (int i = 0; i < MATH_WARMUP; i++) {
contract.compute(arg, fakeFrame);
contract.computePrecompile(arg, fakeFrame);
}
final Stopwatch timer = Stopwatch.createStarted();
for (int i = 0; i < MATH_ITERATIONS; i++) {
contract.compute(arg, fakeFrame);
contract.computePrecompile(arg, fakeFrame);
}
timer.stop();

Loading…
Cancel
Save