Search in sources :

Example 46 with MutableAccount

use of org.hyperledger.besu.evm.account.MutableAccount in project besu by hyperledger.

the class ContractCreationProcessor method codeSuccess.

@Override
public void codeSuccess(final MessageFrame frame, final OperationTracer operationTracer) {
    final Bytes contractCode = frame.getOutputData();
    final long depositFee = gasCalculator.codeDepositGasCost(contractCode.size());
    if (frame.getRemainingGas() < depositFee) {
        LOG.trace("Not enough gas to pay the code deposit fee for {}: " + "remaining gas = {} < {} = deposit fee", frame.getContractAddress(), frame.getRemainingGas(), depositFee);
        if (requireCodeDepositToSucceed) {
            LOG.trace("Contract creation error: insufficient funds for code deposit");
            frame.setExceptionalHaltReason(Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
            frame.setState(MessageFrame.State.EXCEPTIONAL_HALT);
            operationTracer.traceAccountCreationResult(frame, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
        } else {
            frame.setState(MessageFrame.State.COMPLETED_SUCCESS);
        }
    } else {
        final var invalidReason = contractValidationRules.stream().map(rule -> rule.validate(frame)).filter(Optional::isPresent).findFirst();
        if (invalidReason.isEmpty()) {
            frame.decrementRemainingGas(depositFee);
            // Finalize contract creation, setting the contract code.
            final MutableAccount contract = frame.getWorldUpdater().getOrCreate(frame.getContractAddress()).getMutable();
            contract.setCode(contractCode);
            LOG.trace("Successful creation of contract {} with code of size {} (Gas remaining: {})", frame.getContractAddress(), contractCode.size(), frame.getRemainingGas());
            frame.setState(MessageFrame.State.COMPLETED_SUCCESS);
        } else {
            final Optional<ExceptionalHaltReason> exceptionalHaltReason = invalidReason.get();
            frame.setExceptionalHaltReason(exceptionalHaltReason);
            frame.setState(MessageFrame.State.EXCEPTIONAL_HALT);
            operationTracer.traceAccountCreationResult(frame, exceptionalHaltReason);
        }
    }
}
Also used : Bytes(org.apache.tuweni.bytes.Bytes) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount) ExceptionalHaltReason(org.hyperledger.besu.evm.frame.ExceptionalHaltReason)

Example 47 with MutableAccount

use of org.hyperledger.besu.evm.account.MutableAccount in project besu by hyperledger.

the class ContractCreationProcessor method start.

@Override
public void start(final MessageFrame frame, final OperationTracer operationTracer) {
    if (LOG.isTraceEnabled()) {
        LOG.trace("Executing contract-creation");
    }
    try {
        final MutableAccount sender = frame.getWorldUpdater().getSenderAccount(frame).getMutable();
        sender.decrementBalance(frame.getValue());
        final MutableAccount contract = frame.getWorldUpdater().getOrCreate(frame.getContractAddress()).getMutable();
        if (accountExists(contract)) {
            LOG.trace("Contract creation error: account has already been created for address {}", frame.getContractAddress());
            frame.setExceptionalHaltReason(Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
            frame.setState(MessageFrame.State.EXCEPTIONAL_HALT);
            operationTracer.traceAccountCreationResult(frame, Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
        } else {
            contract.incrementBalance(frame.getValue());
            contract.setNonce(initialContractNonce);
            contract.clearStorage();
            frame.setState(MessageFrame.State.CODE_EXECUTING);
        }
    } catch (final ModificationNotAllowedException ex) {
        LOG.trace("Contract creation error: attempt to mutate an immutable account");
        frame.setExceptionalHaltReason(Optional.of(ExceptionalHaltReason.ILLEGAL_STATE_CHANGE));
        frame.setState(MessageFrame.State.EXCEPTIONAL_HALT);
    }
}
Also used : ModificationNotAllowedException(org.hyperledger.besu.evm.ModificationNotAllowedException) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount)

Example 48 with MutableAccount

use of org.hyperledger.besu.evm.account.MutableAccount in project besu by hyperledger.

the class SelfDestructOperation method execute.

@Override
public OperationResult execute(final MessageFrame frame, final EVM evm) {
    final Address recipientAddress = Words.toAddress(frame.popStackItem());
    // because of weird EIP150/158 reasons we care about a null account, so we can't merge this.
    final Account recipientNullable = frame.getWorldUpdater().get(recipientAddress);
    final Wei inheritance = frame.getWorldUpdater().get(frame.getRecipientAddress()).getBalance();
    final boolean accountIsWarm = frame.warmUpAddress(recipientAddress) || gasCalculator().isPrecompile(recipientAddress);
    final long cost = gasCalculator().selfDestructOperationGasCost(recipientNullable, inheritance) + (accountIsWarm ? 0L : gasCalculator().getColdAccountAccessCost());
    if (frame.isStatic()) {
        return new OperationResult(OptionalLong.of(cost), Optional.of(ExceptionalHaltReason.ILLEGAL_STATE_CHANGE));
    } else if (frame.getRemainingGas() < cost) {
        return new OperationResult(OptionalLong.of(cost), Optional.of(ExceptionalHaltReason.INSUFFICIENT_GAS));
    }
    final Address address = frame.getRecipientAddress();
    final MutableAccount account = frame.getWorldUpdater().getAccount(address).getMutable();
    frame.addSelfDestruct(address);
    final MutableAccount recipient = frame.getWorldUpdater().getOrCreate(recipientAddress).getMutable();
    if (!account.getAddress().equals(recipient.getAddress())) {
        recipient.incrementBalance(account.getBalance());
    }
    // add refund in message frame
    frame.addRefund(recipient.getAddress(), account.getBalance());
    account.setBalance(Wei.ZERO);
    frame.setState(MessageFrame.State.CODE_SUCCESS);
    return new OperationResult(OptionalLong.of(cost), Optional.empty());
}
Also used : Account(org.hyperledger.besu.evm.account.Account) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount) Address(org.hyperledger.besu.datatypes.Address) Wei(org.hyperledger.besu.datatypes.Wei) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount)

Example 49 with MutableAccount

use of org.hyperledger.besu.evm.account.MutableAccount in project hedera-services by hashgraph.

the class EvmTxProcessor method execute.

/**
 * Executes the {@link MessageFrame} of the EVM transaction. Returns the result as {@link
 * TransactionProcessingResult}
 *
 * @param sender
 * 		The origin {@link Account} that initiates the transaction
 * @param receiver
 * 		the priority form of the receiving {@link Address} (i.e., EIP-1014 if present); or the newly created address
 * @param gasPrice
 * 		GasPrice to use for gas calculations
 * @param gasLimit
 * 		Externally provided gas limit
 * @param value
 * 		Evm transaction value (HBars)
 * @param payload
 * 		Transaction payload. For Create transactions, the bytecode + constructor arguments
 * @param contractCreation
 * 		Whether or not this is a contract creation transaction
 * @param consensusTime
 * 		Current consensus time
 * @param isStatic
 * 		Whether or not the execution is static
 * @param expiry
 * 		In the case of Create transactions, the expiry of the top-level contract being created
 * @param mirrorReceiver
 * 		the mirror form of the receiving {@link Address}; or the newly created address
 * @return the result of the EVM execution returned as {@link TransactionProcessingResult}
 */
protected TransactionProcessingResult execute(final Account sender, final Address receiver, final long gasPrice, final long gasLimit, final long value, final Bytes payload, final boolean contractCreation, final Instant consensusTime, final boolean isStatic, final OptionalLong expiry, final Address mirrorReceiver) {
    final Wei gasCost = Wei.of(Math.multiplyExact(gasLimit, gasPrice));
    final Wei upfrontCost = gasCost.add(value);
    final Gas intrinsicGas = gasCalculator.transactionIntrinsicGasCost(Bytes.EMPTY, contractCreation);
    final HederaWorldState.Updater updater = (HederaWorldState.Updater) worldState.updater();
    final var senderEvmAddress = sender.getId().asEvmAddress();
    final var senderAccount = updater.getOrCreateSenderAccount(senderEvmAddress);
    final MutableAccount mutableSender = senderAccount.getMutable();
    if (!isStatic) {
        if (intrinsicGas.toLong() > gasLimit) {
            throw new InvalidTransactionException(INSUFFICIENT_GAS);
        }
        final var senderCanAffordGas = mutableSender.getBalance().compareTo(upfrontCost) >= 0;
        validateTrue(senderCanAffordGas, INSUFFICIENT_PAYER_BALANCE);
        mutableSender.decrementBalance(gasCost);
    }
    final Address coinbase = Id.fromGrpcAccount(dynamicProperties.fundingAccount()).asEvmAddress();
    final HederaBlockValues blockValues = new HederaBlockValues(gasLimit, consensusTime.getEpochSecond());
    final Gas gasAvailable = Gas.of(gasLimit).minus(intrinsicGas);
    final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
    final var stackedUpdater = updater.updater();
    Wei valueAsWei = Wei.of(value);
    final MessageFrame.Builder commonInitialFrame = MessageFrame.builder().messageFrameStack(messageFrameStack).maxStackSize(MAX_STACK_SIZE).worldUpdater(stackedUpdater).initialGas(gasAvailable).originator(senderEvmAddress).gasPrice(Wei.of(gasPrice)).sender(senderEvmAddress).value(valueAsWei).apparentValue(valueAsWei).blockValues(blockValues).depth(0).completer(unused -> {
    }).isStatic(isStatic).miningBeneficiary(coinbase).blockHashLookup(ALWAYS_UNAVAILABLE_BLOCK_HASH).contextVariables(Map.of("sbh", storageByteHoursTinyBarsGiven(consensusTime), "HederaFunctionality", getFunctionType(), "expiry", expiry));
    final MessageFrame initialFrame = buildInitialFrame(commonInitialFrame, updater, receiver, payload);
    messageFrameStack.addFirst(initialFrame);
    while (!messageFrameStack.isEmpty()) {
        process(messageFrameStack.peekFirst(), new HederaTracer());
    }
    var gasUsedByTransaction = calculateGasUsedByTX(gasLimit, initialFrame);
    final Gas sbhRefund = updater.getSbhRefund();
    final Map<Address, Map<Bytes, Pair<Bytes, Bytes>>> stateChanges;
    if (isStatic) {
        stateChanges = Map.of();
    } else {
        // return gas price to accounts
        final Gas refunded = Gas.of(gasLimit).minus(gasUsedByTransaction).plus(sbhRefund);
        final Wei refundedWei = refunded.priceFor(Wei.of(gasPrice));
        mutableSender.incrementBalance(refundedWei);
        /* Send TX fees to coinbase */
        final var mutableCoinbase = updater.getOrCreate(coinbase).getMutable();
        final Gas coinbaseFee = Gas.of(gasLimit).minus(refunded);
        mutableCoinbase.incrementBalance(coinbaseFee.priceFor(Wei.of(gasPrice)));
        initialFrame.getSelfDestructs().forEach(updater::deleteAccount);
        if (dynamicProperties.shouldEnableTraceability()) {
            stateChanges = updater.getFinalStateChanges();
        } else {
            stateChanges = Map.of();
        }
        /* Commit top level Updater */
        updater.commit();
    }
    /* Externalise Result */
    if (initialFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
        return TransactionProcessingResult.successful(initialFrame.getLogs(), gasUsedByTransaction.toLong(), sbhRefund.toLong(), gasPrice, initialFrame.getOutputData(), mirrorReceiver, stateChanges);
    } else {
        return TransactionProcessingResult.failed(gasUsedByTransaction.toLong(), sbhRefund.toLong(), gasPrice, initialFrame.getRevertReason(), initialFrame.getExceptionalHaltReason(), stateChanges);
    }
}
Also used : Address(org.hyperledger.besu.datatypes.Address) MessageFrame(org.hyperledger.besu.evm.frame.MessageFrame) HederaWorldState(com.hedera.services.store.contracts.HederaWorldState) InvalidTransactionException(com.hedera.services.exceptions.InvalidTransactionException) ArrayDeque(java.util.ArrayDeque) Bytes(org.apache.tuweni.bytes.Bytes) HederaWorldUpdater(com.hedera.services.store.contracts.HederaWorldUpdater) Gas(org.hyperledger.besu.evm.Gas) Wei(org.hyperledger.besu.datatypes.Wei) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount) Map(java.util.Map)

Aggregations

MutableAccount (org.hyperledger.besu.evm.account.MutableAccount)49 WorldUpdater (org.hyperledger.besu.evm.worldstate.WorldUpdater)33 Test (org.junit.Test)23 MutableWorldState (org.hyperledger.besu.ethereum.core.MutableWorldState)19 Address (org.hyperledger.besu.datatypes.Address)14 Wei (org.hyperledger.besu.datatypes.Wei)14 UInt256 (org.apache.tuweni.units.bigints.UInt256)10 Bytes (org.apache.tuweni.bytes.Bytes)9 MessageFrame (org.hyperledger.besu.evm.frame.MessageFrame)7 Bytes32 (org.apache.tuweni.bytes.Bytes32)5 Hash (org.hyperledger.besu.datatypes.Hash)5 ProcessableBlockHeader (org.hyperledger.besu.ethereum.core.ProcessableBlockHeader)5 ArrayDeque (java.util.ArrayDeque)4 ArrayList (java.util.ArrayList)4 BlockHeader (org.hyperledger.besu.ethereum.core.BlockHeader)4 Code (org.hyperledger.besu.evm.Code)4 Gas (org.hyperledger.besu.evm.Gas)4 Account (org.hyperledger.besu.evm.account.Account)4 Map (java.util.Map)3 TreeMap (java.util.TreeMap)3