Search in sources :

Example 1 with ValidationResult

use of org.hyperledger.besu.ethereum.mainnet.ValidationResult in project besu by hyperledger.

the class TransactionPool method validateTransaction.

private ValidationResult<TransactionInvalidReason> validateTransaction(final Transaction transaction, final boolean isLocal) {
    final BlockHeader chainHeadBlockHeader = getChainHeadBlockHeader();
    final FeeMarket feeMarket = protocolSchedule.getByBlockNumber(chainHeadBlockHeader.getNumber()).getFeeMarket();
    // Check whether it's a GoQuorum transaction
    boolean goQuorumCompatibilityMode = getTransactionValidator().getGoQuorumCompatibilityMode();
    if (transaction.isGoQuorumPrivateTransaction(goQuorumCompatibilityMode)) {
        final Optional<Wei> weiValue = ofNullable(transaction.getValue());
        if (weiValue.isPresent() && !weiValue.get().isZero()) {
            return ValidationResult.invalid(TransactionInvalidReason.ETHER_VALUE_NOT_SUPPORTED);
        }
    }
    // executable:
    if ((!effectiveGasPriceIsAboveConfiguredMinGasPrice(transaction) && !miningParameters.isMiningEnabled()) || (!feeMarket.satisfiesFloorTxCost(transaction))) {
        return ValidationResult.invalid(TransactionInvalidReason.GAS_PRICE_TOO_LOW);
    }
    final ValidationResult<TransactionInvalidReason> basicValidationResult = getTransactionValidator().validate(transaction, chainHeadBlockHeader.getBaseFee(), TransactionValidationParams.transactionPool());
    if (!basicValidationResult.isValid()) {
        return basicValidationResult;
    }
    if (isLocal && strictReplayProtectionShouldBeEnforceLocally(chainHeadBlockHeader) && transaction.getChainId().isEmpty()) {
        // Strict replay protection is enabled but the tx is not replay-protected
        return ValidationResult.invalid(TransactionInvalidReason.REPLAY_PROTECTED_SIGNATURE_REQUIRED);
    }
    if (transaction.getGasLimit() > chainHeadBlockHeader.getGasLimit()) {
        return ValidationResult.invalid(TransactionInvalidReason.EXCEEDS_BLOCK_GAS_LIMIT, String.format("Transaction gas limit of %s exceeds block gas limit of %s", transaction.getGasLimit(), chainHeadBlockHeader.getGasLimit()));
    }
    if (transaction.getType().equals(TransactionType.EIP1559) && !feeMarket.implementsBaseFee()) {
        return ValidationResult.invalid(TransactionInvalidReason.INVALID_TRANSACTION_FORMAT, "EIP-1559 transaction are not allowed yet");
    }
    return protocolContext.getWorldStateArchive().getMutable(chainHeadBlockHeader.getStateRoot(), chainHeadBlockHeader.getHash(), false).map(worldState -> {
        final Account senderAccount = worldState.get(transaction.getSender());
        return getTransactionValidator().validateForSender(transaction, senderAccount, TransactionValidationParams.transactionPool());
    }).orElseGet(() -> ValidationResult.invalid(CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE));
}
Also used : ADDED(org.hyperledger.besu.ethereum.eth.transactions.sorter.AbstractPendingTransactionsSorter.TransactionAddedStatus.ADDED) ValidationResult(org.hyperledger.besu.ethereum.mainnet.ValidationResult) AbstractPendingTransactionsSorter(org.hyperledger.besu.ethereum.eth.transactions.sorter.AbstractPendingTransactionsSorter) Account(org.hyperledger.besu.evm.account.Account) EthPeer(org.hyperledger.besu.ethereum.eth.manager.EthPeer) LoggerFactory(org.slf4j.LoggerFactory) FeeMarket(org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket) Collections.singletonList(java.util.Collections.singletonList) MainnetTransactionValidator(org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator) ProtocolSchedule(org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule) HashSet(java.util.HashSet) TransactionAddedStatus(org.hyperledger.besu.ethereum.eth.transactions.sorter.AbstractPendingTransactionsSorter.TransactionAddedStatus) CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason.CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE) Wei(org.hyperledger.besu.datatypes.Wei) TransactionInvalidReason(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason) BlockAddedEvent(org.hyperledger.besu.ethereum.chain.BlockAddedEvent) BlockAddedObserver(org.hyperledger.besu.ethereum.chain.BlockAddedObserver) Logger(org.slf4j.Logger) Optional.ofNullable(java.util.Optional.ofNullable) BlockHeader(org.hyperledger.besu.ethereum.core.BlockHeader) BesuMetricCategory(org.hyperledger.besu.metrics.BesuMetricCategory) Collection(java.util.Collection) EthContext(org.hyperledger.besu.ethereum.eth.manager.EthContext) Set(java.util.Set) TransactionValidationParams(org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams) MiningParameters(org.hyperledger.besu.ethereum.core.MiningParameters) LabelledMetric(org.hyperledger.besu.plugin.services.metrics.LabelledMetric) ProtocolContext(org.hyperledger.besu.ethereum.ProtocolContext) Optional(java.util.Optional) MetricsSystem(org.hyperledger.besu.plugin.services.MetricsSystem) MutableBlockchain(org.hyperledger.besu.ethereum.chain.MutableBlockchain) TransactionType(org.hyperledger.besu.plugin.data.TransactionType) Transaction(org.hyperledger.besu.ethereum.core.Transaction) Hash(org.hyperledger.besu.datatypes.Hash) Counter(org.hyperledger.besu.plugin.services.metrics.Counter) FeeMarket(org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket) Account(org.hyperledger.besu.evm.account.Account) TransactionInvalidReason(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason) Wei(org.hyperledger.besu.datatypes.Wei) BlockHeader(org.hyperledger.besu.ethereum.core.BlockHeader)

Example 2 with ValidationResult

use of org.hyperledger.besu.ethereum.mainnet.ValidationResult in project besu by hyperledger.

the class GoQuorumBlockProcessor method processBlock.

@Override
public Result processBlock(final Blockchain blockchain, final MutableWorldState publicWorldState, final MutableWorldState privateWorldState, final Block block) {
    final BlockHeader blockHeader = block.getHeader();
    final List<Transaction> transactions = block.getBody().getTransactions();
    final List<BlockHeader> ommers = block.getBody().getOmmers();
    final List<TransactionReceipt> publicTxReceipts = new ArrayList<>();
    final List<TransactionReceipt> privateTxReceipts = new ArrayList<>();
    long currentGasUsed = 0;
    final GoQuorumPrivateStorage.Updater privateStorageUpdater = goQuorumPrivateStorage.updater();
    for (final Transaction transaction : transactions) {
        if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) {
            return AbstractBlockProcessor.Result.failed();
        }
        final WorldUpdater publicWorldStateUpdater = publicWorldState.updater();
        final BlockHashLookup blockHashLookup = new BlockHashLookup(blockHeader, blockchain);
        final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);
        WorldUpdater effectiveWorldUpdater = null;
        Transaction effectiveTransaction;
        final boolean isGoQuorumPrivateTransaction = transaction.isGoQuorumPrivateTransaction(transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode());
        if (isGoQuorumPrivateTransaction) {
            // private transaction
            try {
                effectiveTransaction = retrievePrivateTransactionFromEnclave(transaction);
                effectiveWorldUpdater = new GoQuorumMutablePrivateWorldStateUpdater(publicWorldStateUpdater, privateWorldState.updater());
            } catch (final EnclaveClientException e) {
                // private transaction but not party to it
                // We do not have to execute anything, but we still need to validate the transaction
                effectiveTransaction = null;
                final ValidationResult<TransactionInvalidReason> validationResult = validateTransaction(blockHeader, transaction, publicWorldStateUpdater);
                if (!validationResult.isValid()) {
                    return AbstractBlockProcessor.Result.failed();
                }
            }
        } else {
            // public Transaction
            effectiveWorldUpdater = publicWorldState.updater();
            effectiveTransaction = transaction;
        }
        if (effectiveTransaction != null) {
            // public tx, or private tx that we are party to
            final TransactionProcessingResult result = transactionProcessor.processTransaction(blockchain, effectiveWorldUpdater, blockHeader, effectiveTransaction, miningBeneficiary, OperationTracer.NO_TRACING, blockHashLookup, true, TransactionValidationParams.processingBlock(), null);
            if (result.isInvalid()) {
                LOG.info("Block processing error: transaction invalid '{}'. Block {} Transaction {}", result.getValidationResult().getInvalidReason(), blockHeader.getHash().toHexString(), transaction.getHash().toHexString());
                return AbstractBlockProcessor.Result.failed();
            }
            if (isGoQuorumPrivateTransaction) {
                // private transaction we are party to
                publicTxReceipts.add(transactionReceiptFactory.create(transaction.getType(), publicResultForWhenWeHaveAPrivateTransaction(transaction), publicWorldState, currentGasUsed));
                privateTxReceipts.add(transactionReceiptFactory.create(transaction.getType(), result, privateWorldState, currentGasUsed));
                publicWorldStateUpdater.getOrCreate(effectiveTransaction.getSender()).getMutable().incrementNonce();
                effectiveWorldUpdater.commit();
            } else {
                // public transaction
                final long gasUsed = transaction.getGasLimit() - result.getGasRemaining();
                currentGasUsed += gasUsed;
                publicTxReceipts.add(transactionReceiptFactory.create(transaction.getType(), result, publicWorldState, currentGasUsed));
                privateTxReceipts.add(null);
                effectiveWorldUpdater.commit();
            }
        } else {
            // private transaction we are not party to
            publicTxReceipts.add(transactionReceiptFactory.create(transaction.getType(), publicResultForWhenWeHaveAPrivateTransaction(transaction), publicWorldState, currentGasUsed));
            privateTxReceipts.add(null);
            publicWorldStateUpdater.getOrCreate(transaction.getSender()).getMutable().incrementNonce();
        }
        publicWorldStateUpdater.commit();
    }
    if (!rewardCoinbase(publicWorldState, blockHeader, ommers, skipZeroBlockRewards)) {
        // no need to log, rewardCoinbase logs the error.
        return AbstractBlockProcessor.Result.failed();
    }
    // create the bloom for the private transactions in the block and store it
    final LogsBloomFilter.Builder privateBloomBuilder = LogsBloomFilter.builder();
    privateTxReceipts.stream().filter(pr -> pr != null).forEach(pr -> privateBloomBuilder.insertFilter(pr.getBloomFilter()));
    blockHeader.setPrivateLogsBloom(privateBloomBuilder.build());
    publicWorldState.persist(blockHeader);
    privateWorldState.persist(null);
    privateStorageUpdater.putPrivateStateRootHashMapping(publicWorldState.rootHash(), privateWorldState.rootHash());
    privateStorageUpdater.commit();
    return Result.successful(publicTxReceipts, privateTxReceipts);
}
Also used : MainnetBlockProcessor(org.hyperledger.besu.ethereum.mainnet.MainnetBlockProcessor) ValidationResult(org.hyperledger.besu.ethereum.mainnet.ValidationResult) EvmAccount(org.hyperledger.besu.evm.account.EvmAccount) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) LoggerFactory(org.slf4j.LoggerFactory) OperationTracer(org.hyperledger.besu.evm.tracing.OperationTracer) GoQuorumMutablePrivateWorldStateUpdater(org.hyperledger.besu.ethereum.worldstate.GoQuorumMutablePrivateWorldStateUpdater) Bytes(org.apache.tuweni.bytes.Bytes) Address(org.hyperledger.besu.datatypes.Address) GoQuorumReceiveResponse(org.hyperledger.besu.enclave.types.GoQuorumReceiveResponse) MainnetTransactionValidator(org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator) ArrayList(java.util.ArrayList) GoQuorumPrivacyParameters(org.hyperledger.besu.ethereum.core.GoQuorumPrivacyParameters) GoQuorumEnclave(org.hyperledger.besu.enclave.GoQuorumEnclave) TransactionReceipt(org.hyperledger.besu.ethereum.core.TransactionReceipt) Wei(org.hyperledger.besu.datatypes.Wei) TransactionInvalidReason(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason) Block(org.hyperledger.besu.ethereum.core.Block) AbstractBlockProcessor(org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor) Logger(org.slf4j.Logger) BlockHeader(org.hyperledger.besu.ethereum.core.BlockHeader) Blockchain(org.hyperledger.besu.ethereum.chain.Blockchain) LogsBloomFilter(org.hyperledger.besu.evm.log.LogsBloomFilter) MutableWorldState(org.hyperledger.besu.ethereum.core.MutableWorldState) MainnetTransactionProcessor(org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor) BlockHashLookup(org.hyperledger.besu.ethereum.vm.BlockHashLookup) TransactionValidationParams(org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams) EnclaveClientException(org.hyperledger.besu.enclave.EnclaveClientException) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) List(java.util.List) Optional(java.util.Optional) MiningBeneficiaryCalculator(org.hyperledger.besu.ethereum.mainnet.MiningBeneficiaryCalculator) Transaction(org.hyperledger.besu.ethereum.core.Transaction) Collections(java.util.Collections) Address(org.hyperledger.besu.datatypes.Address) LogsBloomFilter(org.hyperledger.besu.evm.log.LogsBloomFilter) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) TransactionReceipt(org.hyperledger.besu.ethereum.core.TransactionReceipt) ArrayList(java.util.ArrayList) GoQuorumMutablePrivateWorldStateUpdater(org.hyperledger.besu.ethereum.worldstate.GoQuorumMutablePrivateWorldStateUpdater) ValidationResult(org.hyperledger.besu.ethereum.mainnet.ValidationResult) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) Transaction(org.hyperledger.besu.ethereum.core.Transaction) BlockHashLookup(org.hyperledger.besu.ethereum.vm.BlockHashLookup) BlockHeader(org.hyperledger.besu.ethereum.core.BlockHeader) EnclaveClientException(org.hyperledger.besu.enclave.EnclaveClientException)

Example 3 with ValidationResult

use of org.hyperledger.besu.ethereum.mainnet.ValidationResult in project besu by hyperledger.

the class PrivateTransactionProcessor method processTransaction.

public TransactionProcessingResult processTransaction(final WorldUpdater publicWorldState, final WorldUpdater privateWorldState, final ProcessableBlockHeader blockHeader, final Hash pmtHash, final PrivateTransaction transaction, final Address miningBeneficiary, final OperationTracer operationTracer, final Function<Long, Hash> blockHashLookup, final Bytes privacyGroupId) {
    try {
        LOG.trace("Starting private execution of {}", transaction);
        final Address senderAddress = transaction.getSender();
        final EvmAccount maybePrivateSender = privateWorldState.getAccount(senderAddress);
        final MutableAccount sender = maybePrivateSender != null ? maybePrivateSender.getMutable() : privateWorldState.createAccount(senderAddress, 0, Wei.ZERO).getMutable();
        final ValidationResult<TransactionInvalidReason> validationResult = privateTransactionValidator.validate(transaction, sender.getNonce(), false);
        if (!validationResult.isValid()) {
            return TransactionProcessingResult.invalid(validationResult);
        }
        final long previousNonce = sender.incrementNonce();
        LOG.trace("Incremented private sender {} nonce ({} -> {})", senderAddress, previousNonce, sender.getNonce());
        final WorldUpdater mutablePrivateWorldStateUpdater = new DefaultMutablePrivateWorldStateUpdater(publicWorldState, privateWorldState);
        final Deque<MessageFrame> messageFrameStack = new ArrayDeque<>();
        final MessageFrame.Builder commonMessageFrameBuilder = MessageFrame.builder().messageFrameStack(messageFrameStack).maxStackSize(maxStackSize).worldUpdater(mutablePrivateWorldStateUpdater).initialGas(Long.MAX_VALUE).originator(senderAddress).gasPrice(transaction.getGasPrice()).sender(senderAddress).value(transaction.getValue()).apparentValue(transaction.getValue()).blockValues(blockHeader).depth(0).completer(__ -> {
        }).miningBeneficiary(miningBeneficiary).blockHashLookup(blockHashLookup).contextVariables(Map.of(KEY_TRANSACTION_HASH, pmtHash));
        final MessageFrame initialFrame;
        if (transaction.isContractCreation()) {
            final Address privateContractAddress = Address.privateContractAddress(senderAddress, previousNonce, privacyGroupId);
            LOG.debug("Calculated contract address {} from sender {} with nonce {} and privacy group {}", privateContractAddress, senderAddress, previousNonce, privacyGroupId);
            final Bytes initCodeBytes = transaction.getPayload();
            initialFrame = commonMessageFrameBuilder.type(MessageFrame.Type.CONTRACT_CREATION).address(privateContractAddress).contract(privateContractAddress).inputData(Bytes.EMPTY).code(contractCreationProcessor.getCodeFromEVM(Hash.hash(initCodeBytes), initCodeBytes)).build();
        } else {
            final Address to = transaction.getTo().get();
            final Optional<Account> maybeContract = Optional.ofNullable(mutablePrivateWorldStateUpdater.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) {
            mutablePrivateWorldStateUpdater.commit();
        }
        if (initialFrame.getState() == MessageFrame.State.COMPLETED_SUCCESS) {
            return TransactionProcessingResult.successful(initialFrame.getLogs(), 0, 0, initialFrame.getOutputData(), ValidationResult.valid());
        } else {
            return TransactionProcessingResult.failed(0, 0, ValidationResult.invalid(TransactionInvalidReason.PRIVATE_TRANSACTION_FAILED), 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 : ValidationResult(org.hyperledger.besu.ethereum.mainnet.ValidationResult) 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) LoggerFactory(org.slf4j.LoggerFactory) OperationTracer(org.hyperledger.besu.evm.tracing.OperationTracer) Bytes(org.apache.tuweni.bytes.Bytes) Deque(java.util.Deque) Address(org.hyperledger.besu.datatypes.Address) Function(java.util.function.Function) MainnetTransactionValidator(org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator) AbstractMessageProcessor(org.hyperledger.besu.evm.processor.AbstractMessageProcessor) Map(java.util.Map) Wei(org.hyperledger.besu.datatypes.Wei) TransactionInvalidReason(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason) Code(org.hyperledger.besu.evm.Code) ProcessableBlockHeader(org.hyperledger.besu.ethereum.core.ProcessableBlockHeader) Logger(org.slf4j.Logger) TransactionProcessingResult(org.hyperledger.besu.ethereum.processing.TransactionProcessingResult) GasCalculator(org.hyperledger.besu.evm.gascalculator.GasCalculator) DefaultMutablePrivateWorldStateUpdater(org.hyperledger.besu.ethereum.worldstate.DefaultMutablePrivateWorldStateUpdater) 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) WorldUpdater(org.hyperledger.besu.evm.worldstate.WorldUpdater) MessageFrame(org.hyperledger.besu.evm.frame.MessageFrame) ArrayDeque(java.util.ArrayDeque) Bytes(org.apache.tuweni.bytes.Bytes) EvmAccount(org.hyperledger.besu.evm.account.EvmAccount) TransactionInvalidReason(org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason) MutableAccount(org.hyperledger.besu.evm.account.MutableAccount) DefaultMutablePrivateWorldStateUpdater(org.hyperledger.besu.ethereum.worldstate.DefaultMutablePrivateWorldStateUpdater)

Aggregations

Optional (java.util.Optional)3 Wei (org.hyperledger.besu.datatypes.Wei)3 Transaction (org.hyperledger.besu.ethereum.core.Transaction)3 MainnetTransactionValidator (org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator)3 ValidationResult (org.hyperledger.besu.ethereum.mainnet.ValidationResult)3 TransactionInvalidReason (org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason)3 Logger (org.slf4j.Logger)3 LoggerFactory (org.slf4j.LoggerFactory)3 Bytes (org.apache.tuweni.bytes.Bytes)2 Address (org.hyperledger.besu.datatypes.Address)2 Hash (org.hyperledger.besu.datatypes.Hash)2 BlockHeader (org.hyperledger.besu.ethereum.core.BlockHeader)2 TransactionValidationParams (org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams)2 TransactionProcessingResult (org.hyperledger.besu.ethereum.processing.TransactionProcessingResult)2 EvmAccount (org.hyperledger.besu.evm.account.EvmAccount)2 OperationTracer (org.hyperledger.besu.evm.tracing.OperationTracer)2 WorldUpdater (org.hyperledger.besu.evm.worldstate.WorldUpdater)2 ArrayDeque (java.util.ArrayDeque)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1