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));
}
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);
}
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));
}
}
Aggregations