use of org.hyperledger.besu.ethereum.vm.BlockHashLookup in project besu by hyperledger.
the class PrivateGroupRehydrationBlockProcessor method processBlock.
public AbstractBlockProcessor.Result processBlock(final Blockchain blockchain, final MutableWorldState worldState, final WorldStateArchive privateWorldStateArchive, final PrivateStateStorage privateStateStorage, final PrivateStateRootResolver privateStateRootResolver, final Block block, final Map<Hash, PrivateTransaction> forExecution, final List<BlockHeader> ommers) {
long gasUsed = 0;
final List<TransactionReceipt> receipts = new ArrayList<>();
final List<Transaction> transactions = block.getBody().getTransactions();
final BlockHeader blockHeader = block.getHeader();
final PrivateMetadataUpdater metadataUpdater = new PrivateMetadataUpdater(blockHeader, privateStateStorage);
for (final Transaction transaction : transactions) {
final long remainingGasBudget = blockHeader.getGasLimit() - gasUsed;
if (Long.compareUnsigned(transaction.getGasLimit(), remainingGasBudget) > 0) {
LOG.warn("Transaction processing error: transaction gas limit {} exceeds available block budget" + " remaining {}", transaction.getGasLimit(), remainingGasBudget);
return AbstractBlockProcessor.Result.failed();
}
final WorldUpdater worldStateUpdater = worldState.updater();
final BlockHashLookup blockHashLookup = new BlockHashLookup(blockHeader, blockchain);
final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);
final Hash transactionHash = transaction.getHash();
if (forExecution.containsKey(transactionHash)) {
final PrivateTransaction privateTransaction = forExecution.get(transactionHash);
final Bytes32 privacyGroupId = Bytes32.wrap(privateTransaction.getPrivacyGroupId().get());
final Hash lastRootHash = privateStateRootResolver.resolveLastStateRoot(privacyGroupId, metadataUpdater);
final MutableWorldState disposablePrivateState = privateWorldStateArchive.getMutable(lastRootHash, null).get();
final WorldUpdater privateWorldStateUpdater = disposablePrivateState.updater();
if (lastRootHash.equals(EMPTY_ROOT_HASH)) {
privateStateGenesisAllocator.applyGenesisToPrivateWorldState(disposablePrivateState, privateWorldStateUpdater, privacyGroupId, blockHeader.getNumber());
}
LOG.debug("Pre-rehydrate root hash: {} for tx {}", disposablePrivateState.rootHash(), transactionHash);
final TransactionProcessingResult privateResult = privateTransactionProcessor.processTransaction(worldStateUpdater.updater(), privateWorldStateUpdater, blockHeader, transactionHash, privateTransaction, miningBeneficiary, OperationTracer.NO_TRACING, new BlockHashLookup(blockHeader, blockchain), privateTransaction.getPrivacyGroupId().get());
privateWorldStateUpdater.commit();
disposablePrivateState.persist(null);
storePrivateMetadata(transactionHash, privacyGroupId, disposablePrivateState, metadataUpdater, privateResult);
LOG.debug("Post-rehydrate root hash: {}", disposablePrivateState.rootHash());
}
// We have to process the public transactions here, because the private transactions can
// depend on public state
final TransactionProcessingResult result = transactionProcessor.processTransaction(blockchain, worldStateUpdater, blockHeader, transaction, miningBeneficiary, blockHashLookup, false, TransactionValidationParams.processingBlock());
if (result.isInvalid()) {
return AbstractBlockProcessor.Result.failed();
}
gasUsed = transaction.getGasLimit() - result.getGasRemaining() + gasUsed;
final TransactionReceipt transactionReceipt = transactionReceiptFactory.create(transaction.getType(), result, worldState, gasUsed);
receipts.add(transactionReceipt);
}
if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) {
return AbstractBlockProcessor.Result.failed();
}
metadataUpdater.commit();
return AbstractBlockProcessor.Result.successful(receipts);
}
use of org.hyperledger.besu.ethereum.vm.BlockHashLookup in project besu by hyperledger.
the class TransactionSimulator method processWithWorldUpdater.
@Nonnull
public Optional<TransactionSimulatorResult> processWithWorldUpdater(final CallParameter callParams, final TransactionValidationParams transactionValidationParams, final OperationTracer operationTracer, final BlockHeader header, final WorldUpdater updater) {
final ProtocolSpec protocolSpec = protocolSchedule.getByBlockNumber(header.getNumber());
final Address senderAddress = callParams.getFrom() != null ? callParams.getFrom() : DEFAULT_FROM;
BlockHeader blockHeaderToProcess = header;
if (transactionValidationParams.isAllowExceedingBalance() && header.getBaseFee().isPresent()) {
blockHeaderToProcess = BlockHeaderBuilder.fromHeader(header).baseFee(Wei.ZERO).blockHeaderFunctions(protocolSpec.getBlockHeaderFunctions()).buildBlockHeader();
}
final Account sender = updater.get(senderAddress);
final long nonce = sender != null ? sender.getNonce() : 0L;
final long gasLimit = callParams.getGasLimit() >= 0 ? callParams.getGasLimit() : blockHeaderToProcess.getGasLimit();
final Wei value = callParams.getValue() != null ? callParams.getValue() : Wei.ZERO;
final Bytes payload = callParams.getPayload() != null ? callParams.getPayload() : Bytes.EMPTY;
final MainnetTransactionProcessor transactionProcessor = protocolSchedule.getByBlockNumber(blockHeaderToProcess.getNumber()).getTransactionProcessor();
final Optional<Transaction> maybeTransaction = buildTransaction(callParams, transactionValidationParams, header, senderAddress, nonce, gasLimit, value, payload);
if (maybeTransaction.isEmpty()) {
return Optional.empty();
}
final Transaction transaction = maybeTransaction.get();
final TransactionProcessingResult result = transactionProcessor.processTransaction(blockchain, updater, blockHeaderToProcess, transaction, protocolSpec.getMiningBeneficiaryCalculator().calculateBeneficiary(blockHeaderToProcess), new BlockHashLookup(blockHeaderToProcess, blockchain), false, transactionValidationParams, operationTracer);
// If GoQuorum privacy enabled, and value = zero, get max gas possible for a PMT hash.
// It is possible to have a data field that has a lower intrinsic value than the PMT hash.
// This means a potential over-estimate of gas, but the tx, if sent with this gas, will not
// fail.
final boolean goQuorumCompatibilityMode = transactionProcessor.getTransactionValidator().getGoQuorumCompatibilityMode();
if (goQuorumCompatibilityMode && value.isZero()) {
final long privateGasEstimateAndState = protocolSpec.getGasCalculator().getMaximumTransactionCost(64);
if (privateGasEstimateAndState > result.getEstimateGasUsedByTransaction()) {
// modify the result to have the larger estimate
final TransactionProcessingResult resultPmt = TransactionProcessingResult.successful(result.getLogs(), privateGasEstimateAndState, result.getGasRemaining(), result.getOutput(), result.getValidationResult());
return Optional.of(new TransactionSimulatorResult(transaction, resultPmt));
}
}
return Optional.of(new TransactionSimulatorResult(transaction, result));
}
use of org.hyperledger.besu.ethereum.vm.BlockHashLookup in project besu by hyperledger.
the class PrivateMigrationBlockProcessor method processBlock.
public AbstractBlockProcessor.Result processBlock(final Blockchain blockchain, final MutableWorldState worldState, final BlockHeader blockHeader, final List<Transaction> transactions, final List<BlockHeader> ommers) {
long gasUsed = 0;
final List<TransactionReceipt> receipts = new ArrayList<>();
for (final Transaction transaction : transactions) {
final long remainingGasBudget = blockHeader.getGasLimit() - gasUsed;
if (Long.compareUnsigned(transaction.getGasLimit(), remainingGasBudget) > 0) {
LOG.warn("Transaction processing error: transaction gas limit {} exceeds available block budget" + " remaining {}", transaction.getGasLimit(), remainingGasBudget);
return AbstractBlockProcessor.Result.failed();
}
final WorldUpdater worldStateUpdater = worldState.updater();
final BlockHashLookup blockHashLookup = new BlockHashLookup(blockHeader, blockchain);
final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);
final TransactionProcessingResult result = transactionProcessor.processTransaction(blockchain, worldStateUpdater, blockHeader, transaction, miningBeneficiary, blockHashLookup, true, TransactionValidationParams.processingBlock());
if (result.isInvalid()) {
return AbstractBlockProcessor.Result.failed();
}
worldStateUpdater.commit();
gasUsed = transaction.getGasLimit() - result.getGasRemaining() + gasUsed;
final TransactionReceipt transactionReceipt = transactionReceiptFactory.create(transaction.getType(), result, worldState, gasUsed);
receipts.add(transactionReceipt);
}
if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) {
return AbstractBlockProcessor.Result.failed();
}
return AbstractBlockProcessor.Result.successful(receipts);
}
use of org.hyperledger.besu.ethereum.vm.BlockHashLookup 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.vm.BlockHashLookup in project besu by hyperledger.
the class AbstractBlockProcessor method processBlock.
@Override
public AbstractBlockProcessor.Result processBlock(final Blockchain blockchain, final MutableWorldState worldState, final BlockHeader blockHeader, final List<Transaction> transactions, final List<BlockHeader> ommers, final PrivateMetadataUpdater privateMetadataUpdater) {
final List<TransactionReceipt> receipts = new ArrayList<>();
long currentGasUsed = 0;
for (final Transaction transaction : transactions) {
if (!hasAvailableBlockBudget(blockHeader, transaction, currentGasUsed)) {
return AbstractBlockProcessor.Result.failed();
}
final WorldUpdater worldStateUpdater = worldState.updater();
final BlockHashLookup blockHashLookup = new BlockHashLookup(blockHeader, blockchain);
final Address miningBeneficiary = miningBeneficiaryCalculator.calculateBeneficiary(blockHeader);
final TransactionProcessingResult result = transactionProcessor.processTransaction(blockchain, worldStateUpdater, blockHeader, transaction, miningBeneficiary, OperationTracer.NO_TRACING, blockHashLookup, true, TransactionValidationParams.processingBlock(), privateMetadataUpdater);
if (result.isInvalid()) {
LOG.info("Block processing error: transaction invalid '{}'. Block {} Transaction {}", result.getValidationResult().getInvalidReason(), blockHeader.getHash().toHexString(), transaction.getHash().toHexString());
if (worldState instanceof BonsaiPersistedWorldState) {
((BonsaiWorldStateUpdater) worldStateUpdater).reset();
}
return AbstractBlockProcessor.Result.failed();
}
worldStateUpdater.commit();
currentGasUsed += transaction.getGasLimit() - result.getGasRemaining();
final TransactionReceipt transactionReceipt = transactionReceiptFactory.create(transaction.getType(), result, worldState, currentGasUsed);
receipts.add(transactionReceipt);
}
if (!rewardCoinbase(worldState, blockHeader, ommers, skipZeroBlockRewards)) {
// no need to log, rewardCoinbase logs the error.
if (worldState instanceof BonsaiPersistedWorldState) {
((BonsaiWorldStateUpdater) worldState.updater()).reset();
}
return AbstractBlockProcessor.Result.failed();
}
try {
worldState.persist(blockHeader);
} catch (Exception e) {
LOG.error("failed persisting block", e);
return AbstractBlockProcessor.Result.failed();
}
return AbstractBlockProcessor.Result.successful(receipts);
}
Aggregations