@ -17,6 +17,7 @@ package org.hyperledger.besu.ethereum.blockcreation;
import org.hyperledger.besu.config.experimental.ExperimentalEIPs ;
import org.hyperledger.besu.ethereum.chain.Blockchain ;
import org.hyperledger.besu.ethereum.core.Address ;
import org.hyperledger.besu.ethereum.core.EvmAccount ;
import org.hyperledger.besu.ethereum.core.MutableWorldState ;
import org.hyperledger.besu.ethereum.core.ProcessableBlockHeader ;
import org.hyperledger.besu.ethereum.core.Transaction ;
@ -30,18 +31,24 @@ import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions;
import org.hyperledger.besu.ethereum.eth.transactions.PendingTransactions.TransactionSelectionResult ;
import org.hyperledger.besu.ethereum.mainnet.AbstractBlockProcessor ;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionProcessor ;
import org.hyperledger.besu.ethereum.mainnet.MainnetTransactionValidator ;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidationParams ;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult ;
import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult ;
import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason ;
import org.hyperledger.besu.ethereum.vm.BlockHashLookup ;
import org.hyperledger.besu.plugin.data.TransactionType ;
import java.util.Collections ;
import java.util.List ;
import java.util.Optional ;
import java.util.concurrent.CancellationException ;
import java.util.function.Supplier ;
import com.google.common.collect.Lists ;
import org.apache.logging.log4j.LogManager ;
import org.apache.logging.log4j.Logger ;
import org.apache.tuweni.bytes.Bytes ;
/ * *
* Responsible for extracting transactions from PendingTransactions and determining if the
@ -64,6 +71,7 @@ import com.google.common.collect.Lists;
* not cleared between executions of buildTransactionListForBlock ( ) .
* /
public class BlockTransactionSelector {
private static final Logger LOG = LogManager . getLogger ( ) ;
private final Wei minTransactionGasPrice ;
private final Double minBlockOccupancyRatio ;
@ -213,7 +221,25 @@ public class BlockTransactionSelector {
final WorldUpdater worldStateUpdater = worldState . updater ( ) ;
final BlockHashLookup blockHashLookup = new BlockHashLookup ( processableBlockHeader , blockchain ) ;
final TransactionProcessingResult result =
TransactionProcessingResult effectiveResult ;
if ( transaction . isGoQuorumPrivateTransaction ( ) ) {
final ValidationResult < TransactionInvalidReason > validationResult =
validateTransaction ( processableBlockHeader , transaction , worldStateUpdater ) ;
if ( ! validationResult . isValid ( ) ) {
LOG . warn (
"Invalid transaction: {}. Block {} Transaction {}" ,
validationResult . getErrorMessage ( ) ,
processableBlockHeader . getParentHash ( ) . toHexString ( ) ,
transaction . getHash ( ) . toHexString ( ) ) ;
return transactionSelectionResultForInvalidResult ( validationResult ) ;
} else {
// valid GoQuorum private tx, we need to hand craft the receipt and increment the nonce
effectiveResult = publicResultForWhenWeHaveAPrivateTransaction ( transaction ) ;
worldStateUpdater . getOrCreate ( transaction . getSender ( ) ) . getMutable ( ) . incrementNonce ( ) ;
}
} else {
effectiveResult =
transactionProcessor . processTransaction (
blockchain ,
worldStateUpdater ,
@ -223,14 +249,21 @@ public class BlockTransactionSelector {
blockHashLookup ,
false ,
TransactionValidationParams . mining ( ) ) ;
}
if ( ! r esult. isInvalid ( ) ) {
if ( ! effectiveR esult. isInvalid ( ) ) {
worldStateUpdater . commit ( ) ;
updateTransactionResultTracking ( transaction , r esult) ;
updateTransactionResultTracking ( transaction , effectiveR esult) ;
} else {
return transactionSelectionResultForInvalidResult ( effectiveResult . getValidationResult ( ) ) ;
}
return TransactionSelectionResult . CONTINUE ;
}
private TransactionSelectionResult transactionSelectionResultForInvalidResult (
final ValidationResult < TransactionInvalidReason > invalidReasonValidationResult ) {
// If the transaction has an incorrect nonce, leave it in the pool and continue
if ( result
. getValidationResult ( )
if ( invalidReasonValidationResult
. getInvalidReason ( )
. equals ( TransactionInvalidReason . INCORRECT_NONCE ) ) {
return TransactionSelectionResult . CONTINUE ;
@ -238,7 +271,27 @@ public class BlockTransactionSelector {
// If the transaction was invalid for any other reason, delete it, and continue.
return TransactionSelectionResult . DELETE_TRANSACTION_AND_CONTINUE ;
}
return TransactionSelectionResult . CONTINUE ;
private ValidationResult < TransactionInvalidReason > validateTransaction (
final ProcessableBlockHeader blockHeader ,
final Transaction transaction ,
final WorldUpdater publicWorldStateUpdater ) {
final MainnetTransactionValidator transactionValidator =
transactionProcessor . getTransactionValidator ( ) ;
ValidationResult < TransactionInvalidReason > validationResult =
transactionValidator . validate ( transaction , blockHeader . getBaseFee ( ) ) ;
if ( ! validationResult . isValid ( ) ) {
return validationResult ;
}
final Address senderAddress = transaction . getSender ( ) ;
final EvmAccount sender = publicWorldStateUpdater . getOrCreate ( senderAddress ) ;
validationResult =
transactionValidator . validateForSender (
transaction , sender , TransactionValidationParams . processingBlock ( ) ) ;
return validationResult ;
}
/ *
@ -268,6 +321,16 @@ public class BlockTransactionSelector {
gasUsedByTransaction ) ;
}
private TransactionProcessingResult publicResultForWhenWeHaveAPrivateTransaction (
final Transaction transaction ) {
return TransactionProcessingResult . successful (
Collections . emptyList ( ) ,
0 ,
transaction . getGasLimit ( ) ,
Bytes . EMPTY ,
ValidationResult . valid ( ) ) ;
}
private boolean transactionTooLargeForBlock (
final long blockNumber , final long gasLimit , final Transaction transaction ) {