Skip to content

Commit

Permalink
GoQuorum private tx when mining (hyperledger#1938)
Browse files Browse the repository at this point in the history
* hand craft receipt for goquorum private tx when creating a block
* validate goquorum private transaction and handle nonce issues

Signed-off-by: Sally MacFarlane <sally.macfarlane@consensys.net>
  • Loading branch information
macfarla authored Feb 24, 2021
1 parent 1c86ecb commit ef99782
Showing 1 changed file with 85 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
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;
Expand All @@ -30,18 +31,24 @@
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
Expand All @@ -64,6 +71,7 @@
* not cleared between executions of buildTransactionListForBlock().
*/
public class BlockTransactionSelector {
private static final Logger LOG = LogManager.getLogger();

private final Wei minTransactionGasPrice;
private final Double minBlockOccupancyRatio;
Expand Down Expand Up @@ -213,34 +221,79 @@ private TransactionSelectionResult evaluateTransaction(
final WorldUpdater worldStateUpdater = worldState.updater();
final BlockHashLookup blockHashLookup = new BlockHashLookup(processableBlockHeader, blockchain);

final TransactionProcessingResult result =
transactionProcessor.processTransaction(
blockchain,
worldStateUpdater,
processableBlockHeader,
transaction,
miningBeneficiary,
blockHashLookup,
false,
TransactionValidationParams.mining());

if (!result.isInvalid()) {
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,
processableBlockHeader,
transaction,
miningBeneficiary,
blockHashLookup,
false,
TransactionValidationParams.mining());
}

if (!effectiveResult.isInvalid()) {
worldStateUpdater.commit();
updateTransactionResultTracking(transaction, result);
updateTransactionResultTracking(transaction, effectiveResult);
} else {
// If the transaction has an incorrect nonce, leave it in the pool and continue
if (result
.getValidationResult()
.getInvalidReason()
.equals(TransactionInvalidReason.INCORRECT_NONCE)) {
return TransactionSelectionResult.CONTINUE;
}
// If the transaction was invalid for any other reason, delete it, and continue.
return TransactionSelectionResult.DELETE_TRANSACTION_AND_CONTINUE;
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 (invalidReasonValidationResult
.getInvalidReason()
.equals(TransactionInvalidReason.INCORRECT_NONCE)) {
return TransactionSelectionResult.CONTINUE;
}
// If the transaction was invalid for any other reason, delete it, and continue.
return TransactionSelectionResult.DELETE_TRANSACTION_AND_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;
}

/*
Responsible for updating the state maintained between transaction validation (i.e. receipts,
cumulative gas, world state root hash.).
Expand Down Expand Up @@ -268,6 +321,16 @@ private void updateTransactionResultTracking(
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) {

Expand Down

0 comments on commit ef99782

Please sign in to comment.