BlockCreator returns BlockCreationResult transaction selection results (#4465)

* BlockCreator returns BlockCreationResult with block and transactions selection results

Signed-off-by: Pedro Novais <jpvnovais@gmail.com>
pull/4542/head
Pedro Novais 2 years ago committed by GitHub
parent 9f8a948e33
commit df56576ab0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      CHANGELOG.md
  2. 6
      consensus/clique/src/test/java/org/hyperledger/besu/consensus/clique/blockcreation/CliqueBlockCreatorTest.java
  3. 6
      consensus/ibft/src/integration-test/java/org/hyperledger/besu/consensus/ibft/support/TestContext.java
  4. 4
      consensus/ibft/src/main/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftRound.java
  5. 2
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/BftBlockCreatorTest.java
  6. 5
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftBlockHeightManagerTest.java
  7. 5
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/statemachine/IbftRoundTest.java
  8. 2
      consensus/ibftlegacy/src/test/java/org/hyperledger/besu/consensus/ibftlegacy/blockcreation/BftBlockCreatorTest.java
  9. 5
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeBlockCreator.java
  10. 13
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/MergeCoordinator.java
  11. 4
      consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/blockcreation/TransitionCoordinator.java
  12. 2
      consensus/qbft/src/integration-test/java/org/hyperledger/besu/consensus/qbft/support/TestContext.java
  13. 23
      consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/blockcreation/PkiQbftBlockCreator.java
  14. 4
      consensus/qbft/src/main/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftRound.java
  15. 9
      consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/blockcreation/PkiQbftBlockCreatorTest.java
  16. 5
      consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftBlockHeightManagerTest.java
  17. 5
      consensus/qbft/src/test/java/org/hyperledger/besu/consensus/qbft/statemachine/QbftRoundTest.java
  18. 12
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractBlockCreator.java
  19. 4
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinator.java
  20. 26
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockCreator.java
  21. 7
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockMiner.java
  22. 90
      ethereum/blockcreation/src/main/java/org/hyperledger/besu/ethereum/blockcreation/BlockTransactionSelector.java
  23. 8
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/BlockMinerTest.java
  24. 7
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/PoWBlockCreatorTest.java
  25. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/BlockValidator.java
  26. 3
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/BonsaiSnapshotIsolationTests.java
  27. 3
      ethereum/retesteth/src/main/java/org/hyperledger/besu/ethereum/retesteth/methods/TestMineBlocks.java

@ -3,6 +3,9 @@
### Breaking Changes
- Version 22.10.0 will require Java 17 to build and run.
### Additions and Improvements
- Block creation now returns `BlockCreationResult` which contains the new `Block` and `TransactionSelectionResults`.
## 22.10.0-RC2
### Breaking Changes

@ -144,7 +144,7 @@ public class CliqueBlockCreatorTest {
blockchain.getChainHeadHeader(),
epochManager);
final Block createdBlock = blockCreator.createBlock(5L);
final Block createdBlock = blockCreator.createBlock(5L).getBlock();
Java6Assertions.assertThat(CliqueHelpers.getProposerOfBlock(createdBlock.getHeader()))
.isEqualTo(proposerAddress);
@ -177,7 +177,7 @@ public class CliqueBlockCreatorTest {
blockchain.getChainHeadHeader(),
epochManager);
final Block createdBlock = blockCreator.createBlock(0L);
final Block createdBlock = blockCreator.createBlock(0L).getBlock();
assertThat(createdBlock.getHeader().getNonce()).isEqualTo(CliqueBlockInterface.ADD_NONCE);
assertThat(createdBlock.getHeader().getCoinbase()).isEqualTo(a1);
}
@ -212,7 +212,7 @@ public class CliqueBlockCreatorTest {
blockchain.getChainHeadHeader(),
epochManager);
final Block createdBlock = blockCreator.createBlock(0L);
final Block createdBlock = blockCreator.createBlock(0L).getBlock();
assertThat(createdBlock.getHeader().getNonce()).isEqualTo(CliqueBlockInterface.DROP_NONCE);
assertThat(createdBlock.getHeader().getCoinbase()).isEqualTo(Address.fromHexString("0"));
}

@ -88,7 +88,11 @@ public class TestContext {
public Block createBlockForProposal(
final BlockHeader parent, final int round, final long timestamp) {
return finalState.getBlockCreatorFactory().create(parent, round).createBlock(timestamp);
return finalState
.getBlockCreatorFactory()
.create(parent, round)
.createBlock(timestamp)
.getBlock();
}
public Block createBlockForProposalFromChainHead(final int round, final long timestamp) {

@ -90,7 +90,7 @@ public class IbftRound {
}
public void createAndSendProposalMessage(final long headerTimeStampSeconds) {
final Block block = blockCreator.createBlock(headerTimeStampSeconds);
final Block block = blockCreator.createBlock(headerTimeStampSeconds).getBlock();
final BftExtraData extraData = bftExtraDataCodec.decode(block.getHeader());
LOG.debug("Creating proposed block. round={}", roundState.getRoundIdentifier());
LOG.trace(
@ -107,7 +107,7 @@ public class IbftRound {
final Block blockToPublish;
if (!bestBlockFromRoundChange.isPresent()) {
LOG.debug("Sending proposal with new block. round={}", roundState.getRoundIdentifier());
blockToPublish = blockCreator.createBlock(headerTimestamp);
blockToPublish = blockCreator.createBlock(headerTimestamp).getBlock();
} else {
LOG.debug(
"Sending proposal from PreparedCertificate. round={}", roundState.getRoundIdentifier());

@ -144,7 +144,7 @@ public class BftBlockCreatorTest {
bftExtraDataEncoder);
final int secondsBetweenBlocks = 1;
final Block block = blockCreator.createBlock(parentHeader.getTimestamp() + 1);
final Block block = blockCreator.createBlock(parentHeader.getTimestamp() + 1).getBlock();
final BlockHeaderValidator rules =
IbftBlockHeaderValidationRulesetFactory.blockHeaderValidator(

@ -58,6 +58,8 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader;
@ -141,7 +143,8 @@ public class IbftBlockHeightManagerTest {
when(finalState.getBlockTimer()).thenReturn(blockTimer);
when(finalState.getQuorum()).thenReturn(3);
when(finalState.getValidatorMulticaster()).thenReturn(validatorMulticaster);
when(blockCreator.createBlock(anyLong())).thenReturn(createdBlock);
when(blockCreator.createBlock(anyLong()))
.thenReturn(new BlockCreationResult(createdBlock, new TransactionSelectionResults()));
when(futureRoundProposalMessageValidator.validateProposalMessage(any())).thenReturn(true);
when(messageValidatorFactory.createFutureRoundProposalMessageValidator(anyLong(), any()))

@ -45,6 +45,8 @@ import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.chain.MinedBlockObserver;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
@ -119,7 +121,8 @@ public class IbftRoundTest {
final BlockHeader header = headerTestFixture.buildHeader();
proposedBlock = new Block(header, new BlockBody(emptyList(), emptyList()));
when(blockCreator.createBlock(anyLong())).thenReturn(proposedBlock);
when(blockCreator.createBlock(anyLong()))
.thenReturn(new BlockCreationResult(proposedBlock, new TransactionSelectionResults()));
when(blockImporter.importBlock(any(), any(), any())).thenReturn(new BlockImportResult(true));

@ -117,7 +117,7 @@ public class BftBlockCreatorTest {
0.8,
parentHeader);
final Block block = blockCreator.createBlock(Instant.now().getEpochSecond());
final Block block = blockCreator.createBlock(Instant.now().getEpochSecond()).getBlock();
final BlockHeaderValidator rules =
IbftBlockHeaderValidationRulesetFactory.ibftProposedBlockValidator(0).build();

@ -18,7 +18,6 @@ import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.AbstractBlockCreator;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.core.Difficulty;
@ -60,7 +59,7 @@ public class MergeBlockCreator extends AbstractBlockCreator {
parentHeader);
}
public Block createBlock(
public BlockCreationResult createBlock(
final Optional<List<Transaction>> maybeTransactions,
final Bytes32 random,
final long timestamp) {
@ -73,7 +72,7 @@ public class MergeBlockCreator extends AbstractBlockCreator {
}
@Override
public Block createBlock(
public BlockCreationResult createBlock(
final Optional<List<Transaction>> maybeTransactions,
final Optional<List<BlockHeader>> maybeOmmers,
final long timestamp) {

@ -25,6 +25,7 @@ import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.BlockValidator.Result;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.chain.BadBlockManager;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
@ -205,7 +206,9 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
// put the empty block in first
final Block emptyBlock =
mergeBlockCreator.createBlock(Optional.of(Collections.emptyList()), prevRandao, timestamp);
mergeBlockCreator
.createBlock(Optional.of(Collections.emptyList()), prevRandao, timestamp)
.getBlock();
Result result = validateBlock(emptyBlock);
if (result.blockProcessingOutputs.isPresent()) {
@ -244,7 +247,7 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
final PayloadIdentifier payloadIdentifier,
final MergeBlockCreator mergeBlockCreator) {
final Supplier<Block> blockCreator =
final Supplier<BlockCreationResult> blockCreator =
() -> mergeBlockCreator.createBlock(Optional.empty(), random, timestamp);
LOG.debug(
@ -274,7 +277,7 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
}
private Void retryBlockCreationUntilUseful(
final PayloadIdentifier payloadIdentifier, final Supplier<Block> blockCreator) {
final PayloadIdentifier payloadIdentifier, final Supplier<BlockCreationResult> blockCreator) {
while (!isBlockCreationCancelled(payloadIdentifier)) {
try {
@ -299,11 +302,11 @@ public class MergeCoordinator implements MergeMiningCoordinator, BadChainListene
private void recoverableBlockCreation(
final PayloadIdentifier payloadIdentifier,
final Supplier<Block> blockCreator,
final Supplier<BlockCreationResult> blockCreator,
final long startedAt) {
try {
evaluateNewBlock(blockCreator.get(), payloadIdentifier, startedAt);
evaluateNewBlock(blockCreator.get().getBlock(), payloadIdentifier, startedAt);
} catch (final Throwable throwable) {
if (canRetryBlockCreation(throwable) && !isBlockCreationCancelled(payloadIdentifier)) {
debugLambda(

@ -46,6 +46,10 @@ public class TransitionCoordinator extends TransitionUtils<MiningCoordinator>
this.mergeCoordinator = (MergeMiningCoordinator) mergeCoordinator;
}
public MergeMiningCoordinator getMergeCoordinator() {
return mergeCoordinator;
}
@Override
public void start() {
if (isMiningBeforeMerge()) {

@ -103,7 +103,7 @@ public class TestContext {
public Block createBlockForProposal(
final BlockHeader parent, final long timestamp, final Address proposer) {
final Block block =
finalState.getBlockCreatorFactory().create(parent, 0).createBlock(timestamp);
finalState.getBlockCreatorFactory().create(parent, 0).createBlock(timestamp).getBlock();
final BlockHeaderBuilder headerBuilder = BlockHeaderBuilder.fromHeader(block.getHeader());
headerBuilder

@ -41,6 +41,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PkiQbftBlockCreator implements BlockCreator {
private static final Logger LOG = LoggerFactory.getLogger(PkiQbftBlockCreator.class);
private final BlockCreator blockCreator;
@ -74,20 +75,21 @@ public class PkiQbftBlockCreator implements BlockCreator {
}
@Override
public Block createBlock(final long timestamp) {
final Block block = blockCreator.createBlock(timestamp);
return replaceCmsInBlock(block);
public BlockCreationResult createBlock(final long timestamp) {
final BlockCreationResult blockCreationResult = blockCreator.createBlock(timestamp);
return replaceCmsInBlock(blockCreationResult);
}
@Override
public Block createBlock(
public BlockCreationResult createBlock(
final List<Transaction> transactions, final List<BlockHeader> ommers, final long timestamp) {
final Block block = blockCreator.createBlock(transactions, ommers, timestamp);
return replaceCmsInBlock(block);
final BlockCreationResult blockCreationResult =
blockCreator.createBlock(transactions, ommers, timestamp);
return replaceCmsInBlock(blockCreationResult);
}
@Override
public Block createBlock(
public BlockCreationResult createBlock(
final Optional<List<Transaction>> maybeTransactions,
final Optional<List<BlockHeader>> maybeOmmers,
final long timestamp) {
@ -97,7 +99,8 @@ public class PkiQbftBlockCreator implements BlockCreator {
timestamp);
}
private Block replaceCmsInBlock(final Block block) {
private BlockCreationResult replaceCmsInBlock(final BlockCreationResult blockCreationResult) {
final Block block = blockCreationResult.getBlock();
final BlockHeader blockHeader = block.getHeader();
final Hash hashWithoutCms =
PkiQbftBlockHeaderFunctions.forCmsSignature(pkiQbftExtraDataCodec).hash(block.getHeader());
@ -116,6 +119,8 @@ public class PkiQbftBlockCreator implements BlockCreator {
LOG.debug("Created CMS with signed hash {} for block {}", hashWithoutCms, newHeader.getHash());
return new Block(newHeader, block.getBody());
return new BlockCreationResult(
new Block(newHeader, block.getBody()),
blockCreationResult.getTransactionSelectionResults());
}
}

@ -97,7 +97,7 @@ public class QbftRound {
public void createAndSendProposalMessage(final long headerTimeStampSeconds) {
LOG.debug("Creating proposed block. round={}", roundState.getRoundIdentifier());
final Block block = blockCreator.createBlock(headerTimeStampSeconds);
final Block block = blockCreator.createBlock(headerTimeStampSeconds).getBlock();
LOG.trace("Creating proposed block blockHeader={}", block.getHeader());
updateStateWithProposalAndTransmit(block, emptyList(), emptyList());
@ -111,7 +111,7 @@ public class QbftRound {
final Block blockToPublish;
if (bestPreparedCertificate.isEmpty()) {
LOG.debug("Sending proposal with new block. round={}", roundState.getRoundIdentifier());
blockToPublish = blockCreator.createBlock(headerTimestamp);
blockToPublish = blockCreator.createBlock(headerTimestamp).getBlock();
} else {
LOG.debug(
"Sending proposal from PreparedCertificate. round={}", roundState.getRoundIdentifier());

@ -31,6 +31,8 @@ import org.hyperledger.besu.consensus.qbft.pki.PkiQbftExtraData;
import org.hyperledger.besu.consensus.qbft.pki.PkiQbftExtraDataCodec;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader;
@ -77,7 +79,7 @@ public class PkiQbftBlockCreatorTest {
final Bytes cms = Bytes.random(32);
when(cmsCreator.create(any(Bytes.class))).thenReturn(cms);
final Block proposedBlock = pkiQbftBlockCreator.createBlock(1L);
final Block proposedBlock = pkiQbftBlockCreator.createBlock(1L).getBlock();
final PkiQbftExtraData proposedBlockExtraData =
(PkiQbftExtraData) extraDataCodec.decodeRaw(proposedBlock.getHeader().getExtraData());
@ -103,7 +105,7 @@ public class PkiQbftBlockCreatorTest {
createBlockBeingProposed();
when(cmsCreator.create(any(Bytes.class))).thenReturn(Bytes.random(32));
final Block blockWithCms = pkiQbftBlockCreator.createBlock(1L);
final Block blockWithCms = pkiQbftBlockCreator.createBlock(1L).getBlock();
final Hash expectedBlockHash =
BftBlockHeaderFunctions.forCommittedSeal(extraDataCodec).hash(blockWithCms.getHeader());
@ -120,7 +122,8 @@ public class PkiQbftBlockCreatorTest {
new Block(
blockHeaderWithExtraData,
new BlockBody(Collections.emptyList(), Collections.emptyList()));
when(blockCreator.createBlock(eq(1L))).thenReturn(block);
when(blockCreator.createBlock(eq(1L)))
.thenReturn(new BlockCreationResult(block, new TransactionSelectionResults()));
return block;
}

@ -58,6 +58,8 @@ import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockHeader;
@ -141,7 +143,8 @@ public class QbftBlockHeightManagerTest {
when(finalState.getBlockTimer()).thenReturn(blockTimer);
when(finalState.getQuorum()).thenReturn(3);
when(finalState.getValidatorMulticaster()).thenReturn(validatorMulticaster);
when(blockCreator.createBlock(anyLong())).thenReturn(createdBlock);
when(blockCreator.createBlock(anyLong()))
.thenReturn(new BlockCreationResult(createdBlock, new TransactionSelectionResults()));
when(futureRoundProposalMessageValidator.validateProposalMessage(any())).thenReturn(true);
when(messageValidatorFactory.createFutureRoundProposalMessageValidator(anyLong(), any()))

@ -49,6 +49,8 @@ import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.chain.MinedBlockObserver;
import org.hyperledger.besu.ethereum.chain.MutableBlockchain;
import org.hyperledger.besu.ethereum.core.Block;
@ -127,7 +129,8 @@ public class QbftRoundTest {
final BlockHeader header = headerTestFixture.buildHeader();
proposedBlock = new Block(header, new BlockBody(emptyList(), emptyList()));
when(blockCreator.createBlock(anyLong())).thenReturn(proposedBlock);
when(blockCreator.createBlock(anyLong()))
.thenReturn(new BlockCreationResult(proposedBlock, new TransactionSelectionResults()));
when(blockImporter.importBlock(any(), any(), any())).thenReturn(new BlockImportResult(true));

@ -124,25 +124,25 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
* @return a block with appropriately selected transactions, seals and ommers.
*/
@Override
public Block createBlock(final long timestamp) {
public BlockCreationResult createBlock(final long timestamp) {
return createBlock(Optional.empty(), Optional.empty(), timestamp);
}
@Override
public Block createBlock(
public BlockCreationResult createBlock(
final List<Transaction> transactions, final List<BlockHeader> ommers, final long timestamp) {
return createBlock(Optional.of(transactions), Optional.of(ommers), timestamp);
}
@Override
public Block createBlock(
public BlockCreationResult createBlock(
final Optional<List<Transaction>> maybeTransactions,
final Optional<List<BlockHeader>> maybeOmmers,
final long timestamp) {
return createBlock(maybeTransactions, maybeOmmers, Optional.empty(), timestamp, true);
}
protected Block createBlock(
protected BlockCreationResult createBlock(
final Optional<List<Transaction>> maybeTransactions,
final Optional<List<BlockHeader>> maybeOmmers,
final Optional<Bytes32> maybePrevRandao,
@ -202,7 +202,9 @@ public abstract class AbstractBlockCreator implements AsyncBlockCreator {
final BlockHeader blockHeader = createFinalBlockHeader(sealableBlockHeader);
return new Block(blockHeader, new BlockBody(transactionResults.getTransactions(), ommers));
final Block block =
new Block(blockHeader, new BlockBody(transactionResults.getTransactions(), ommers));
return new BlockCreationResult(block, transactionResults);
} catch (final SecurityModuleException ex) {
throw new IllegalStateException("Failed to create block signature", ex);
} catch (final CancellationException ex) {

@ -72,13 +72,13 @@ public abstract class AbstractMiningCoordinator<
final List<Transaction> transactions,
final List<BlockHeader> ommers) {
final M miner = executor.createMiner(minedBlockObservers, ethHashObservers, parentHeader);
return Optional.of(miner.createBlock(parentHeader, transactions, ommers));
return Optional.of(miner.createBlock(parentHeader, transactions, ommers).getBlock());
}
@Override
public Optional<Block> createBlock(final BlockHeader parentHeader, final long timestamp) {
final M miner = executor.createMiner(minedBlockObservers, ethHashObservers, parentHeader);
return Optional.of(miner.createBlock(parentHeader, timestamp));
return Optional.of(miner.createBlock(parentHeader, timestamp).getBlock());
}
@Override

@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.ethereum.blockcreation;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction;
@ -22,12 +23,31 @@ import java.util.List;
import java.util.Optional;
public interface BlockCreator {
Block createBlock(final long timestamp);
class BlockCreationResult {
private final Block block;
private final TransactionSelectionResults transactionSelectionResults;
Block createBlock(
public BlockCreationResult(
final Block block, final TransactionSelectionResults transactionSelectionResults) {
this.block = block;
this.transactionSelectionResults = transactionSelectionResults;
}
public Block getBlock() {
return block;
}
public TransactionSelectionResults getTransactionSelectionResults() {
return transactionSelectionResults;
}
}
BlockCreationResult createBlock(final long timestamp);
BlockCreationResult createBlock(
final List<Transaction> transactions, final List<BlockHeader> ommers, final long timestamp);
Block createBlock(
BlockCreationResult createBlock(
final Optional<List<Transaction>> maybeTransactions,
final Optional<List<BlockHeader>> maybeOmmers,
final long timestamp);

@ -15,6 +15,7 @@
package org.hyperledger.besu.ethereum.blockcreation;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.chain.MinedBlockObserver;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeader;
@ -104,7 +105,7 @@ public class BlockMiner<M extends AbstractBlockCreator> implements Runnable {
* @param ommers The list of ommers to include.
* @return the newly created block.
*/
public Block createBlock(
public BlockCreationResult createBlock(
final BlockHeader parentHeader,
final List<Transaction> transactions,
final List<BlockHeader> ommers) {
@ -120,7 +121,7 @@ public class BlockMiner<M extends AbstractBlockCreator> implements Runnable {
* @param timestamp unix timestamp of the new block.
* @return the newly created block.
*/
public Block createBlock(final BlockHeader parentHeader, final long timestamp) {
public BlockCreationResult createBlock(final BlockHeader parentHeader, final long timestamp) {
final BlockCreator blockCreator = this.blockCreatorFactory.apply(parentHeader);
return blockCreator.createBlock(Optional.empty(), Optional.empty(), timestamp);
}
@ -134,7 +135,7 @@ public class BlockMiner<M extends AbstractBlockCreator> implements Runnable {
final Stopwatch stopwatch = Stopwatch.createStarted();
LOG.trace("Mining a new block with timestamp {}", newBlockTimestamp);
final Block block = minerBlockCreator.createBlock(newBlockTimestamp);
final Block block = minerBlockCreator.createBlock(newBlockTimestamp).getBlock();
LOG.trace(
"Block created, importing to local chain, block includes {} transactions",
block.getBody().getTransactions().size());

@ -39,6 +39,7 @@ import org.hyperledger.besu.evm.worldstate.WorldUpdater;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CancellationException;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@ -74,10 +75,49 @@ public class BlockTransactionSelector {
private final Wei minTransactionGasPrice;
private final Double minBlockOccupancyRatio;
public static class TransactionValidationResult {
private final Transaction transaction;
private final ValidationResult<TransactionInvalidReason> validationResult;
public TransactionValidationResult(
final Transaction transaction,
final ValidationResult<TransactionInvalidReason> validationResult) {
this.transaction = transaction;
this.validationResult = validationResult;
}
public Transaction getTransaction() {
return transaction;
}
public ValidationResult<TransactionInvalidReason> getValidationResult() {
return validationResult;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TransactionValidationResult that = (TransactionValidationResult) o;
return Objects.equals(transaction, that.transaction)
&& Objects.equals(validationResult, that.validationResult);
}
@Override
public int hashCode() {
return Objects.hash(transaction, validationResult);
}
}
public static class TransactionSelectionResults {
private final List<Transaction> transactions = Lists.newArrayList();
private final List<TransactionReceipt> receipts = Lists.newArrayList();
private final List<TransactionValidationResult> invalidTransactions = Lists.newArrayList();
private long cumulativeGasUsed = 0;
private void update(
@ -93,6 +133,12 @@ public class BlockTransactionSelector {
() -> cumulativeGasUsed);
}
private void updateWithInvalidTransaction(
final Transaction transaction,
final ValidationResult<TransactionInvalidReason> validationResult) {
invalidTransactions.add(new TransactionValidationResult(transaction, validationResult));
}
public List<Transaction> getTransactions() {
return transactions;
}
@ -105,6 +151,30 @@ public class BlockTransactionSelector {
return cumulativeGasUsed;
}
public List<TransactionValidationResult> getInvalidTransactions() {
return invalidTransactions;
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TransactionSelectionResults that = (TransactionSelectionResults) o;
return cumulativeGasUsed == that.cumulativeGasUsed
&& transactions.equals(that.transactions)
&& receipts.equals(that.receipts)
&& invalidTransactions.equals(that.invalidTransactions);
}
@Override
public int hashCode() {
return Objects.hash(transactions, receipts, invalidTransactions, cumulativeGasUsed);
}
public String toTraceLog() {
return "cumulativeGasUsed="
+ cumulativeGasUsed
@ -162,7 +232,7 @@ public class BlockTransactionSelector {
traceLambda(
LOG, "Transaction pool content {}", () -> pendingTransactions.toTraceLog(false, false));
pendingTransactions.selectTransactions(
pendingTransaction -> evaluateTransaction(pendingTransaction));
pendingTransaction -> evaluateTransaction(pendingTransaction, false));
traceLambda(
LOG, "Transaction selection result result {}", transactionSelectionResult::toTraceLog);
return transactionSelectionResult;
@ -175,7 +245,7 @@ public class BlockTransactionSelector {
* @return The {@code TransactionSelectionResults} results of transaction evaluation.
*/
public TransactionSelectionResults evaluateTransactions(final List<Transaction> transactions) {
transactions.forEach(this::evaluateTransaction);
transactions.forEach(transaction -> evaluateTransaction(transaction, true));
return transactionSelectionResult;
}
@ -188,7 +258,8 @@ public class BlockTransactionSelector {
* the space remaining in the block.
*
*/
private TransactionSelectionResult evaluateTransaction(final Transaction transaction) {
private TransactionSelectionResult evaluateTransaction(
final Transaction transaction, final boolean reportFutureNonceTransactionsAsInvalid) {
if (isCancelled.get()) {
throw new CancellationException("Cancelled during transaction selection.");
}
@ -260,6 +331,11 @@ public class BlockTransactionSelector {
traceLambda(LOG, "Selected {} for block creation", transaction::toTraceLog);
updateTransactionResultTracking(transaction, effectiveResult);
} else {
final var isIncorrectNonce = isIncorrectNonce(effectiveResult.getValidationResult());
if (!isIncorrectNonce || reportFutureNonceTransactionsAsInvalid) {
transactionSelectionResult.updateWithInvalidTransaction(
transaction, effectiveResult.getValidationResult());
}
return transactionSelectionResultForInvalidResult(
transaction, effectiveResult.getValidationResult());
}
@ -270,9 +346,7 @@ public class BlockTransactionSelector {
final Transaction transaction,
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)) {
if (isIncorrectNonce(invalidReasonValidationResult)) {
traceLambda(
LOG,
"Incorrect nonce for transaction {} keeping it in the pool",
@ -335,6 +409,10 @@ public class BlockTransactionSelector {
gasUsedByTransaction);
}
private boolean isIncorrectNonce(final ValidationResult<TransactionInvalidReason> result) {
return result.getInvalidReason().equals(TransactionInvalidReason.INCORRECT_NONCE);
}
private TransactionProcessingResult publicResultForWhenWeHaveAPrivateTransaction(
final Transaction transaction) {
return TransactionProcessingResult.successful(

@ -22,6 +22,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.chain.MinedBlockObserver;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockBody;
@ -57,7 +59,8 @@ public class BlockMinerTest {
final PoWBlockCreator blockCreator = mock(PoWBlockCreator.class);
final Function<BlockHeader, PoWBlockCreator> blockCreatorSupplier =
(parentHeader) -> blockCreator;
when(blockCreator.createBlock(anyLong())).thenReturn(blockToCreate);
when(blockCreator.createBlock(anyLong()))
.thenReturn(new BlockCreationResult(blockToCreate, new TransactionSelectionResults()));
final BlockImporter blockImporter = mock(BlockImporter.class);
final ProtocolSpec protocolSpec = mock(ProtocolSpec.class);
@ -97,7 +100,8 @@ public class BlockMinerTest {
final PoWBlockCreator blockCreator = mock(PoWBlockCreator.class);
final Function<BlockHeader, PoWBlockCreator> blockCreatorSupplier =
(parentHeader) -> blockCreator;
when(blockCreator.createBlock(anyLong())).thenReturn(blockToCreate);
when(blockCreator.createBlock(anyLong()))
.thenReturn(new BlockCreationResult(blockToCreate, new TransactionSelectionResults()));
final BlockImporter blockImporter = mock(BlockImporter.class);
final ProtocolSpec protocolSpec = mock(ProtocolSpec.class);

@ -21,6 +21,8 @@ import org.hyperledger.besu.config.GenesisConfigOptions;
import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.blockcreation.BlockCreator.BlockCreationResult;
import org.hyperledger.besu.ethereum.blockcreation.BlockTransactionSelector.TransactionSelectionResults;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockHeaderBuilder;
import org.hyperledger.besu.ethereum.core.Difficulty;
@ -115,11 +117,14 @@ public class PoWBlockCreatorTest {
// A Hashrate should not exist in the block creator prior to creating a block
assertThat(blockCreator.getHashesPerSecond().isPresent()).isFalse();
final Block actualBlock = blockCreator.createBlock(BLOCK_1_TIMESTAMP);
final BlockCreationResult blockResult = blockCreator.createBlock(BLOCK_1_TIMESTAMP);
final Block actualBlock = blockResult.getBlock();
final Block expectedBlock = ValidationTestUtils.readBlock(1);
assertThat(actualBlock).isEqualTo(expectedBlock);
assertThat(blockCreator.getHashesPerSecond().isPresent()).isTrue();
assertThat(blockResult.getTransactionSelectionResults())
.isEqualTo(new TransactionSelectionResults());
}
@Test

@ -28,23 +28,27 @@ public interface BlockValidator {
public final Optional<BlockProcessingOutputs> blockProcessingOutputs;
public final Optional<String> errorMessage;
public final Optional<Throwable> cause;
public final boolean isValid;
public Result(final BlockProcessingOutputs blockProcessingOutputs) {
this.blockProcessingOutputs = Optional.of(blockProcessingOutputs);
this.errorMessage = Optional.empty();
this.cause = Optional.empty();
this.isValid = true;
}
public Result(final String errorMessage) {
this.blockProcessingOutputs = Optional.empty();
this.errorMessage = Optional.of(errorMessage);
this.cause = Optional.empty();
this.isValid = false;
}
public Result(final String errorMessage, final Throwable cause) {
this.blockProcessingOutputs = Optional.empty();
this.errorMessage = Optional.of(errorMessage);
this.cause = Optional.of(cause);
this.isValid = false;
}
}

@ -336,7 +336,8 @@ public class BonsaiSnapshotIsolationTests {
private Block forTransactions(final List<Transaction> transactions, final BlockHeader forHeader) {
return TestBlockCreator.forHeader(forHeader, protocolContext, protocolSchedule, sorter)
.createBlock(transactions, Collections.emptyList(), System.currentTimeMillis());
.createBlock(transactions, Collections.emptyList(), System.currentTimeMillis())
.getBlock();
}
private BlockProcessor.Result executeBlock(final MutableWorldState ws, final Block block) {

@ -74,7 +74,8 @@ public class TestMineBlocks implements JsonRpcMethod {
Wei.ZERO,
0.0,
blockchain.getChainHeadHeader());
final Block block = blockCreator.createBlock(retesethClock.instant().getEpochSecond());
final Block block =
blockCreator.createBlock(retesethClock.instant().getEpochSecond()).getBlock();
// advance clock so next mine won't hit the same timestamp
retesethClock.advanceSeconds(1);

Loading…
Cancel
Save