use of org.hyperledger.besu.evm.Gas in project hedera-services by hashgraph.
the class HederaSStoreOperation method execute.
@Override
public Operation.OperationResult execute(final MessageFrame frame, final EVM evm) {
final UInt256 key = UInt256.fromBytes(frame.popStackItem());
final UInt256 value = UInt256.fromBytes(frame.popStackItem());
final MutableAccount account = frame.getWorldUpdater().getAccount(frame.getRecipientAddress()).getMutable();
if (account == null) {
return ILLEGAL_STATE_CHANGE;
}
UInt256 currentValue = account.getStorageValue(key);
boolean currentZero = currentValue.isZero();
boolean newZero = value.isZero();
boolean checkCalculator = checkSuperCost;
Gas gasCost = Gas.ZERO;
if (currentZero && !newZero) {
final var updater = (HederaWorldUpdater) frame.getWorldUpdater();
HederaWorldState.WorldStateAccount hederaAccount = updater.getHederaAccount(frame.getRecipientAddress());
long durationInSeconds = Math.max(0, (hederaAccount != null ? hederaAccount.getExpiry() : HederaOperationUtil.newContractExpiryIn(frame)) - frame.getBlockValues().getTimestamp());
long sbh = frame.getMessageFrameStack().getLast().getContextVariable("sbh");
Wei gasPrice = frame.getGasPrice();
gasCost = Gas.of(calculateStorageGasNeeded(64, /*two 256-bit words*/
durationInSeconds, sbh, gasPrice.toLong()));
((HederaWorldUpdater) frame.getWorldUpdater()).addSbhRefund(gasCost);
} else {
checkCalculator = true;
}
if (checkCalculator) {
Address address = account.getAddress();
boolean slotIsWarm = frame.warmUpStorage(address, key);
gasCost = gasCost.max(gasCalculator().calculateStorageCost(account, key, value).plus(slotIsWarm ? Gas.ZERO : this.gasCalculator().getColdSloadCost()));
frame.incrementGasRefund(gasCalculator().calculateStorageRefundAmount(account, key, value));
}
Optional<Gas> optionalCost = Optional.of(gasCost);
final Gas remainingGas = frame.getRemainingGas();
if (frame.isStatic()) {
return new OperationResult(optionalCost, Optional.of(ExceptionalHaltReason.ILLEGAL_STATE_CHANGE));
} else if (remainingGas.compareTo(gasCost) < 0) {
return new OperationResult(optionalCost, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
}
if (dynamicProperties.shouldEnableTraceability()) {
HederaOperationUtil.cacheExistingValue(frame, account.getAddress(), key, currentValue);
}
account.setStorageValue(key, value);
frame.storageWasUpdated(key, value);
return new Operation.OperationResult(optionalCost, Optional.empty());
}
use of org.hyperledger.besu.evm.Gas in project hedera-services by hashgraph.
the class EvmTxProcessor method calculateGasUsedByTX.
private Gas calculateGasUsedByTX(final long txGasLimit, final MessageFrame initialFrame) {
Gas gasUsedByTransaction = Gas.of(txGasLimit).minus(initialFrame.getRemainingGas());
/* Return leftover gas */
final Gas selfDestructRefund = gasCalculator.getSelfDestructRefundAmount().times(initialFrame.getSelfDestructs().size()).min(gasUsedByTransaction.dividedBy(gasCalculator.getMaxRefundQuotient()));
gasUsedByTransaction = gasUsedByTransaction.minus(selfDestructRefund).minus(initialFrame.getGasRefund());
final var maxRefundPercent = dynamicProperties.maxGasRefundPercentage();
gasUsedByTransaction = Gas.of(Math.max(gasUsedByTransaction.toLong(), txGasLimit - txGasLimit * maxRefundPercent / 100));
return gasUsedByTransaction;
}
use of org.hyperledger.besu.evm.Gas in project hedera-services by hashgraph.
the class HederaMessageCallProcessor method executeHederaPrecompile.
void executeHederaPrecompile(final PrecompiledContract contract, final MessageFrame frame, final OperationTracer operationTracer) {
// EVM value transfers are not allowed
if (!Objects.equals(Wei.ZERO, frame.getValue())) {
frame.setRevertReason(INVALID_TRANSFER);
frame.setState(REVERT);
return;
}
final Bytes output = contract.compute(frame.getInputData(), frame);
final Gas gasRequirement = contract.gasRequirement(frame.getInputData());
operationTracer.tracePrecompileCall(frame, gasRequirement, output);
if (frame.getRemainingGas().compareTo(gasRequirement) < 0) {
frame.decrementRemainingGas(frame.getRemainingGas());
frame.setExceptionalHaltReason(Optional.of(INSUFFICIENT_GAS));
frame.setState(EXCEPTIONAL_HALT);
} else if (output != null) {
frame.decrementRemainingGas(gasRequirement);
frame.setOutputData(output);
frame.setState(COMPLETED_SUCCESS);
} else {
frame.setState(EXCEPTIONAL_HALT);
}
}
use of org.hyperledger.besu.evm.Gas in project besu by hyperledger.
the class MessageCallProcessor method executePrecompile.
/**
* Executes this message call knowing that it is a call to the provided pre-compiled contract.
*
* @param contract The contract this is a message call to.
*/
private void executePrecompile(final PrecompiledContract contract, final MessageFrame frame, final OperationTracer operationTracer) {
final Gas gasRequirement = contract.gasRequirement(frame.getInputData());
if (frame.getRemainingGas().compareTo(gasRequirement) < 0) {
LOG.trace("Not enough gas available for pre-compiled contract code {}: requiring " + "{} but only {} gas available", contract, gasRequirement, frame.getRemainingGas());
frame.setExceptionalHaltReason(Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
frame.setState(MessageFrame.State.EXCEPTIONAL_HALT);
} else {
frame.decrementRemainingGas(gasRequirement);
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 {
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);
}
}
use of org.hyperledger.besu.evm.Gas in project besu by hyperledger.
the class MainnetTransactionProcessor method refunded.
protected Gas refunded(final Transaction transaction, final Gas gasRemaining, final Gas gasRefund) {
// Integer truncation takes care of the the floor calculation needed after the divide.
final Gas maxRefundAllowance = Gas.of(transaction.getGasLimit()).minus(gasRemaining).dividedBy(gasCalculator.getMaxRefundQuotient());
final Gas refundAllowance = maxRefundAllowance.min(gasRefund);
return gasRemaining.plus(refundAllowance);
}
Aggregations