Search in sources :

Example 21 with Wei

use of org.hyperledger.besu.datatypes.Wei in project besu by hyperledger.

the class StateTrieAccountValueTest method roundTripMainNetAccountValue.

@Test
public void roundTripMainNetAccountValue() {
    final long nonce = 0;
    final Wei balance = Wei.ZERO;
    // Have the storageRoot and codeHash as different values to ensure the encode / decode
    // doesn't cross the values over.
    final Hash storageRoot = Hash.EMPTY_TRIE_HASH;
    final Hash codeHash = Hash.EMPTY_LIST_HASH;
    roundTripMainNetAccountValue(nonce, balance, storageRoot, codeHash);
}
Also used : Wei(org.hyperledger.besu.datatypes.Wei) Hash(org.hyperledger.besu.datatypes.Hash) Test(org.junit.Test)

Example 22 with Wei

use of org.hyperledger.besu.datatypes.Wei in project besu by hyperledger.

the class MainnetBlockProcessor method rewardCoinbase.

@Override
protected boolean rewardCoinbase(final MutableWorldState worldState, final BlockHeader header, final List<BlockHeader> ommers, final boolean skipZeroBlockRewards) {
    if (skipZeroBlockRewards && blockReward.isZero()) {
        return true;
    }
    final Wei coinbaseReward = getCoinbaseReward(blockReward, header.getNumber(), ommers.size());
    final WorldUpdater updater = worldState.updater();
    final Address miningBeneficiary = getMiningBeneficiaryCalculator().calculateBeneficiary(header);
    final MutableAccount miningBeneficiaryAccount = updater.getOrCreate(miningBeneficiary).getMutable();
    miningBeneficiaryAccount.incrementBalance(coinbaseReward);
    for (final BlockHeader ommerHeader : ommers) {
        if (ommerHeader.getNumber() - header.getNumber() > MAX_GENERATION) {
            LOG.info("Block processing error: ommer block number {} more than {} generations. Block {}", ommerHeader.getNumber(), MAX_GENERATION, header.getHash().toHexString());
            return false;
        }
        final MutableAccount ommerCoinbase = updater.getOrCreate(ommerHeader.getCoinbase()).getMutable();
        final Wei ommerReward = getOmmerReward(blockReward, header.getNumber(), ommerHeader.getNumber());
        ommerCoinbase.incrementBalance(ommerReward);
    }
    updater.commit();
    return true;
}
Also used : Address(org.hyperledger.besu.datatypes.Address) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) Wei(org.hyperledger.besu.datatypes.Wei) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount) BlockHeader(org.hyperledger.besu.ethereum.core.BlockHeader)

Example 23 with Wei

use of org.hyperledger.besu.datatypes.Wei in project besu by hyperledger.

the class MainnetTransactionProcessor method processTransaction.

public TransactionProcessingResult processTransaction(final Blockchain blockchain, final WorldUpdater worldState, final ProcessableBlockHeader blockHeader, final Transaction transaction, final Address miningBeneficiary, final OperationTracer operationTracer, final BlockHashLookup blockHashLookup, final Boolean isPersistingPrivateState, final TransactionValidationParams transactionValidationParams, final PrivateMetadataUpdater privateMetadataUpdater) {
    try {
        LOG.trace("Starting execution of {}", transaction);
        ValidationResult<TransactionInvalidReason> validationResult = transactionValidator.validate(transaction, blockHeader.getBaseFee(), transactionValidationParams);
        // be signed correctly to extract the sender).
        if (!validationResult.isValid()) {
            LOG.debug("Invalid transaction: {}", validationResult.getErrorMessage());
            return TransactionProcessingResult.invalid(validationResult);
        }
        final Address senderAddress = transaction.getSender();
        final EvmAccount sender = worldState.getOrCreateSenderAccount(senderAddress);
        validationResult = transactionValidator.validateForSender(transaction, sender, transactionValidationParams);
        if (!validationResult.isValid()) {
            LOG.debug("Invalid transaction: {}", validationResult.getErrorMessage());
            return TransactionProcessingResult.invalid(validationResult);
        }
        final MutableAccount senderMutableAccount = sender.getMutable();
        final long previousNonce = senderMutableAccount.incrementNonce();
        final Wei transactionGasPrice = feeMarket.getTransactionPriceCalculator().price(transaction, blockHeader.getBaseFee());
        LOG.trace("Incremented sender {} nonce ({} -> {})", senderAddress, previousNonce, sender.getNonce());
        final Wei upfrontGasCost = transaction.getUpfrontGasCost(transactionGasPrice);
        final Wei previousBalance = senderMutableAccount.decrementBalance(upfrontGasCost);
        LOG.trace("Deducted sender {} upfront gas cost {} ({} -> {})", senderAddress, upfrontGasCost, previousBalance, sender.getBalance());
        final List<AccessListEntry> accessListEntries = transaction.getAccessList().orElse(List.of());
        // we need to keep a separate hash set of addresses in case they specify no storage.
        // No-storage is a common pattern, especially for Externally Owned Accounts
        final Set<Address> addressList = new HashSet<>();
        final Multimap<Address, Bytes32> storageList = HashMultimap.create();
        int accessListStorageCount = 0;
        for (final var entry : accessListEntries) {
            final Address address = entry.getAddress();
            addressList.add(address);
            final List<Bytes32> storageKeys = entry.getStorageKeys();
            storageList.putAll(address, storageKeys);
            accessListStorageCount += storageKeys.size();
        }
        final long intrinsicGas = gasCalculator.transactionIntrinsicGasCost(transaction.getPayload(), transaction.isContractCreation());
        final long accessListGas = gasCalculator.accessListGasCost(accessListEntries.size(), accessListStorageCount);
        final long gasAvailable = transaction.getGasLimit() - intrinsicGas - accessListGas;
        LOG.trace("Gas available for execution {} = {} - {} (limit - intrinsic)", gasAvailable, transaction.getGasLimit(), intrinsicGas);
        final WorldUpdater worldUpdater = worldState.updater();
        final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
        final ImmutableMap.Builder<String, Object> contextVariablesBuilder = ImmutableMap.<String, Object>builder().put(KEY_IS_PERSISTING_PRIVATE_STATE, isPersistingPrivateState).put(KEY_TRANSACTION, transaction).put(KEY_TRANSACTION_HASH, transaction.getHash());
        if (privateMetadataUpdater != null) {
            contextVariablesBuilder.put(KEY_PRIVATE_METADATA_UPDATER, privateMetadataUpdater);
        }
        final MessageFrame.Builder commonMessageFrameBuilder = MessageFrame.builder().messageFrameStack(messageFrameStack).maxStackSize(maxStackSize).worldUpdater(worldUpdater.updater()).initialGas(gasAvailable).originator(senderAddress).gasPrice(transactionGasPrice).sender(senderAddress).value(transaction.getValue()).apparentValue(transaction.getValue()).blockValues(blockHeader).depth(0).completer(__ -> {
        }).miningBeneficiary(miningBeneficiary).blockHashLookup(blockHashLookup).contextVariables(contextVariablesBuilder.build()).accessListWarmAddresses(addressList).accessListWarmStorage(storageList);
        final MessageFrame initialFrame;
        if (transaction.isContractCreation()) {
            final Address contractAddress = Address.contractAddress(senderAddress, senderMutableAccount.getNonce() - 1L);
            final Bytes initCodeBytes = transaction.getPayload();
            initialFrame = commonMessageFrameBuilder.type(MessageFrame.Type.CONTRACT_CREATION).address(contractAddress).contract(contractAddress).inputData(Bytes.EMPTY).code(contractCreationProcessor.getCodeFromEVM(Hash.hash(initCodeBytes), initCodeBytes)).build();
        } else {
            // isContractCall tests isPresent
            @SuppressWarnings("OptionalGetWithoutIsPresent") final Address to = transaction.getTo().get();
            final Optional<Account> maybeContract = Optional.ofNullable(worldState.get(to));
            initialFrame = commonMessageFrameBuilder.type(MessageFrame.Type.MESSAGE_CALL).address(to).contract(to).inputData(transaction.getPayload()).code(maybeContract.map(c -> messageCallProcessor.getCodeFromEVM(c.getCodeHash(), c.getCode())).orElse(Code.EMPTY_CODE)).build();
        }
        messageFrameStack.addFirst(initialFrame);
        while (!messageFrameStack.isEmpty()) {
            process(messageFrameStack.peekFirst(), operationTracer);
        }
        if (initialFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
            worldUpdater.commit();
        }
        if (LOG.isTraceEnabled()) {
            LOG.trace("Gas used by transaction: {}, by message call/contract creation: {}", transaction.getGasLimit() - initialFrame.getRemainingGas(), gasAvailable - initialFrame.getRemainingGas());
        }
        // Refund the sender by what we should and pay the miner fee (note that we're doing them one
        // after the other so that if it is the same account somehow, we end up with the right result)
        final long selfDestructRefund = gasCalculator.getSelfDestructRefundAmount() * initialFrame.getSelfDestructs().size();
        final long refundGas = initialFrame.getGasRefund() + selfDestructRefund;
        final long refunded = refunded(transaction, initialFrame.getRemainingGas(), refundGas);
        final Wei refundedWei = transactionGasPrice.multiply(refunded);
        senderMutableAccount.incrementBalance(refundedWei);
        final long gasUsedByTransaction = transaction.getGasLimit() - initialFrame.getRemainingGas();
        if (!worldState.getClass().equals(GoQuorumMutablePrivateWorldStateUpdater.class)) {
            // if this is not a private GoQuorum transaction we have to update the coinbase
            final var coinbase = worldState.getOrCreate(miningBeneficiary).getMutable();
            final long coinbaseFee = transaction.getGasLimit() - refunded;
            if (blockHeader.getBaseFee().isPresent()) {
                final Wei baseFee = blockHeader.getBaseFee().get();
                if (transactionGasPrice.compareTo(baseFee) < 0) {
                    return TransactionProcessingResult.failed(gasUsedByTransaction, refunded, ValidationResult.invalid(TransactionInvalidReason.TRANSACTION_PRICE_TOO_LOW, "transaction price must be greater than base fee"), Optional.empty());
                }
            }
            final CoinbaseFeePriceCalculator coinbaseCalculator = blockHeader.getBaseFee().isPresent() ? coinbaseFeePriceCalculator : CoinbaseFeePriceCalculator.frontier();
            final Wei coinbaseWeiDelta = coinbaseCalculator.price(coinbaseFee, transactionGasPrice, blockHeader.getBaseFee());
            coinbase.incrementBalance(coinbaseWeiDelta);
        }
        initialFrame.getSelfDestructs().forEach(worldState::deleteAccount);
        if (clearEmptyAccounts) {
            clearEmptyAccounts(worldState);
        }
        if (initialFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
            return TransactionProcessingResult.successful(initialFrame.getLogs(), gasUsedByTransaction, refunded, initialFrame.getOutputData(), validationResult);
        } else {
            return TransactionProcessingResult.failed(gasUsedByTransaction, refunded, validationResult, initialFrame.getRevertReason());
        }
    } catch (final RuntimeException re) {
        LOG.error("Critical Exception Processing Transaction", re);
        return TransactionProcessingResult.invalid(ValidationResult.invalid(TransactionInvalidReason.INTERNAL_ERROR, "Internal Error in Besu - " + re));
    }
}
Also used : EvmAccount(org.hyperledger.besu.evm.account.EvmAccount) KEY_TRANSACTION_HASH(org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION_HASH) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) Account(org.hyperledger.besu.evm.account.Account) AccessListEntry(org.hyperledger.besu.evm.AccessListEntry) LoggerFactory(org.slf4j.LoggerFactory) FeeMarket(org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket) OperationTracer(org.hyperledger.besu.evm.tracing.OperationTracer) GoQuorumMutablePrivateWorldStateUpdater(org.hyperledger.besu.ethereum.worldstate.GoQuorumMutablePrivateWorldStateUpdater) Bytes(org.apache.tuweni.bytes.Bytes) KEY_PRIVATE_METADATA_UPDATER(org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_PRIVATE_METADATA_UPDATER) Deque(java.util.Deque) Multimap(com.google.common.collect.Multimap) Address(org.hyperledger.besu.datatypes.Address) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) AbstractMessageProcessor(org.hyperledger.besu.evm.processor.AbstractMessageProcessor) HashMultimap(com.google.common.collect.HashMultimap) Wei(org.hyperledger.besu.datatypes.Wei) TransactionInvalidReason(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason) Code(org.hyperledger.besu.evm.Code) Bytes32(org.apache.tuweni.bytes.Bytes32) ProcessableBlockHeader(org.hyperledger.besu.ethereum.core.ProcessableBlockHeader) PrivateMetadataUpdater(org.hyperledger.besu.ethereum.privacy.storage.PrivateMetadataUpdater) KEY_IS_PERSISTING_PRIVATE_STATE(org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_IS_PERSISTING_PRIVATE_STATE) Logger(org.slf4j.Logger) ImmutableMap(com.google.common.collect.ImmutableMap) Blockchain(org.hyperledger.besu.ethereum.chain.Blockchain) CoinbaseFeePriceCalculator(org.hyperledger.besu.ethereum.core.feemarket.CoinbaseFeePriceCalculator) Set(java.util.Set) BlockHashLookup(org.hyperledger.besu.ethereum.vm.BlockHashLookup) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) GasCalculator(org.hyperledger.besu.evm.gascalculator.GasCalculator) List(java.util.List) KEY_TRANSACTION(org.hyperledger.besu.ethereum.mainnet.PrivateStateUtils.KEY_TRANSACTION) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount) Optional(java.util.Optional) MessageFrame(org.hyperledger.besu.evm.frame.MessageFrame) ArrayDeque(java.util.ArrayDeque) Transaction(org.hyperledger.besu.ethereum.core.Transaction) Hash(org.hyperledger.besu.datatypes.Hash) EvmAccount(org.hyperledger.besu.evm.account.EvmAccount) Account(org.hyperledger.besu.evm.account.Account) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount) Address(org.hyperledger.besu.datatypes.Address) MessageFrame(org.hyperledger.besu.evm.frame.MessageFrame) Bytes32(org.apache.tuweni.bytes.Bytes32) Bytes(org.apache.tuweni.bytes.Bytes) AccessListEntry(org.hyperledger.besu.evm.AccessListEntry) EvmAccount(org.hyperledger.besu.evm.account.EvmAccount) TransactionInvalidReason(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount) HashSet(java.util.HashSet) CoinbaseFeePriceCalculator(org.hyperledger.besu.ethereum.core.feemarket.CoinbaseFeePriceCalculator) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) GoQuorumMutablePrivateWorldStateUpdater(org.hyperledger.besu.ethereum.worldstate.GoQuorumMutablePrivateWorldStateUpdater) ArrayDeque(java.util.ArrayDeque) ImmutableMap(com.google.common.collect.ImmutableMap) Wei(org.hyperledger.besu.datatypes.Wei)

Example 24 with Wei

use of org.hyperledger.besu.datatypes.Wei in project besu by hyperledger.

the class BaseFeeMarketBlockHeaderGasPriceValidationRule method validate.

@Override
public boolean validate(final BlockHeader header, final BlockHeader parent) {
    try {
        // if this is the fork block, baseFee should be the initial baseFee
        if (baseFeeMarket.isForkBlock(header.getNumber())) {
            return baseFeeMarket.getInitialBasefee().equals(header.getBaseFee().orElseThrow(() -> MissingBaseFeeFromBlockHeader()));
        }
        final Wei parentBaseFee = parent.getBaseFee().orElseThrow(() -> MissingBaseFeeFromBlockHeader());
        final Wei currentBaseFee = header.getBaseFee().orElseThrow(() -> MissingBaseFeeFromBlockHeader());
        final long targetGasUsed = baseFeeMarket.targetGasUsed(parent);
        final Wei expectedBaseFee = baseFeeMarket.computeBaseFee(header.getNumber(), parentBaseFee, parent.getGasUsed(), targetGasUsed);
        if (!expectedBaseFee.equals(currentBaseFee)) {
            LOG.info("Invalid block header: basefee {} does not equal expected basefee {}", header.getBaseFee().orElseThrow(), expectedBaseFee);
            return false;
        }
        return true;
    } catch (final FeeMarketException e) {
        LOG.info("Invalid block header: " + e.getMessage());
        return false;
    }
}
Also used : FeeMarketException(org.hyperledger.besu.ethereum.core.feemarket.FeeMarketException) Wei(org.hyperledger.besu.datatypes.Wei)

Example 25 with Wei

use of org.hyperledger.besu.datatypes.Wei in project besu by hyperledger.

the class ClassicBlockProcessor method getCoinbaseReward.

@Override
public Wei getCoinbaseReward(final Wei blockReward, final long blockNumber, final int ommersSize) {
    final int blockEra = getBlockEra(blockNumber, eraLength);
    final Wei winnerReward = getBlockWinnerRewardByEra(blockEra);
    return winnerReward.plus(winnerReward.multiply(ommersSize).divide(32));
}
Also used : Wei(org.hyperledger.besu.datatypes.Wei)

Aggregations

Wei (org.hyperledger.besu.datatypes.Wei)69 Address (org.hyperledger.besu.datatypes.Address)24 Test (org.junit.Test)20 Transaction (org.hyperledger.besu.ethereum.core.Transaction)18 Bytes (org.apache.tuweni.bytes.Bytes)16 Hash (org.hyperledger.besu.datatypes.Hash)14 BlockHeader (org.hyperledger.besu.ethereum.core.BlockHeader)13 MutableAccount (org.hyperledger.besu.evm.account.MutableAccount)12 Account (org.hyperledger.besu.evm.account.Account)9 WorldUpdater (org.hyperledger.besu.evm.worldstate.WorldUpdater)9 Optional (java.util.Optional)8 TransactionInvalidReason (org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason)7 ArrayList (java.util.ArrayList)6 JsonRpcSuccessResponse (org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse)6 ProtocolSchedule (org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule)6 JsonObject (io.vertx.core.json.JsonObject)5 Response (okhttp3.Response)5 Bytes32 (org.apache.tuweni.bytes.Bytes32)5 MessageFrame (org.hyperledger.besu.evm.frame.MessageFrame)5 List (java.util.List)4