Added block add event. (#637)

Added block reorg event.
Added revert reason to both events.
Added TransactionReceipt.

Signed-off-by: David Mechler <david.mechler@consensys.net>
pull/642/head
David Mechler 5 years ago committed by GitHub
parent 31246f8937
commit 061e24a5f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 62
      besu/src/main/java/org/hyperledger/besu/services/BesuEventsImpl.java
  2. 127
      besu/src/test/java/org/hyperledger/besu/services/BesuEventsImplTest.java
  3. 3
      consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java
  4. 4
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/AutoTransactionLogBloomCachingService.java
  5. 5
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java
  6. 3
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java
  7. 24
      ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java
  8. 16
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java
  9. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/ChainReorgObserver.java
  10. 10
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java
  11. 7
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/TransactionReceipt.java
  12. 2
      ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java
  13. 2
      plugin-api/build.gradle
  14. 42
      plugin-api/src/main/java/org/hyperledger/besu/plugin/data/AddedBlockContext.java
  15. 58
      plugin-api/src/main/java/org/hyperledger/besu/plugin/data/TransactionReceipt.java
  16. 53
      plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuEvents.java

@ -22,9 +22,11 @@ import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.LogTopic; import org.hyperledger.besu.ethereum.core.LogTopic;
import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.LogWithMetadata;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.eth.sync.BlockBroadcaster; import org.hyperledger.besu.ethereum.eth.sync.BlockBroadcaster;
import org.hyperledger.besu.ethereum.eth.sync.state.SyncState; import org.hyperledger.besu.ethereum.eth.sync.state.SyncState;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import org.hyperledger.besu.plugin.data.AddedBlockContext;
import org.hyperledger.besu.plugin.data.Address; import org.hyperledger.besu.plugin.data.Address;
import org.hyperledger.besu.plugin.data.BlockHeader; import org.hyperledger.besu.plugin.data.BlockHeader;
import org.hyperledger.besu.plugin.data.PropagatedBlockContext; import org.hyperledger.besu.plugin.data.PropagatedBlockContext;
@ -66,6 +68,38 @@ public class BesuEventsImpl implements BesuEvents {
blockBroadcaster.unsubscribePropagateNewBlocks(listenerIdentifier); blockBroadcaster.unsubscribePropagateNewBlocks(listenerIdentifier);
} }
@Override
public long addBlockAddedListener(final BlockAddedListener listener) {
return blockchain.observeBlockAdded(
(event, chain) ->
listener.onBlockAdded(
blockAddedContext(
event.getBlock()::getHeader,
event.getBlock()::getBody,
event::getTransactionReceipts)));
}
@Override
public void removeBlockAddedListener(final long listenerIdentifier) {
blockchain.removeObserver(listenerIdentifier);
}
@Override
public long addBlockReorgListener(final BlockReorgListener listener) {
return blockchain.observeChainReorg(
(blockWithReceipts, chain) ->
listener.onBlockReorg(
blockAddedContext(
blockWithReceipts::getHeader,
blockWithReceipts.getBlock()::getBody,
blockWithReceipts::getReceipts)));
}
@Override
public void removeBlockReorgListener(final long listenerIdentifier) {
blockchain.removeObserver(listenerIdentifier);
}
@Override @Override
public long addTransactionAddedListener(final TransactionAddedListener listener) { public long addTransactionAddedListener(final TransactionAddedListener listener) {
return transactionPool.subscribePendingTransactions(listener::onTransactionAdded); return transactionPool.subscribePendingTransactions(listener::onTransactionAdded);
@ -109,11 +143,7 @@ public class BesuEventsImpl implements BesuEvents {
.collect(toUnmodifiableList()); .collect(toUnmodifiableList());
final List<List<LogTopic>> besuTopics = final List<List<LogTopic>> besuTopics =
topics.stream() topics.stream()
.map( .map(subList -> subList.stream().map(LogTopic::wrap).collect(toUnmodifiableList()))
subList ->
subList.stream()
.map(bytes -> LogTopic.wrap(bytes))
.collect(toUnmodifiableList()))
.collect(toUnmodifiableList()); .collect(toUnmodifiableList());
final LogsQuery logsQuery = new LogsQuery(besuAddresses, besuTopics); final LogsQuery logsQuery = new LogsQuery(besuAddresses, besuTopics);
@ -152,4 +182,26 @@ public class BesuEventsImpl implements BesuEvents {
} }
}; };
} }
private static AddedBlockContext blockAddedContext(
final Supplier<BlockHeader> blockHeaderSupplier,
final Supplier<BlockBody> blockBodySupplier,
final Supplier<List<TransactionReceipt>> transactionReceiptsSupplier) {
return new AddedBlockContext() {
@Override
public BlockHeader getBlockHeader() {
return blockHeaderSupplier.get();
}
@Override
public BlockBody getBlockBody() {
return blockBodySupplier.get();
}
@Override
public List<TransactionReceipt> getTransactionReceipts() {
return transactionReceiptsSupplier.get();
}
};
}
} }

@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.core.BlockBody;
import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
import org.hyperledger.besu.ethereum.core.Difficulty; import org.hyperledger.besu.ethereum.core.Difficulty;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.core.TransactionTestFixture; import org.hyperledger.besu.ethereum.core.TransactionTestFixture;
import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.Wei;
import org.hyperledger.besu.ethereum.core.WorldState; import org.hyperledger.besu.ethereum.core.WorldState;
@ -50,6 +51,7 @@ import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage; import org.hyperledger.besu.ethereum.storage.keyvalue.KeyValueStoragePrefixedKeyBlockchainStorage;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem;
import org.hyperledger.besu.plugin.data.AddedBlockContext;
import org.hyperledger.besu.plugin.data.LogWithMetadata; import org.hyperledger.besu.plugin.data.LogWithMetadata;
import org.hyperledger.besu.plugin.data.PropagatedBlockContext; import org.hyperledger.besu.plugin.data.PropagatedBlockContext;
import org.hyperledger.besu.plugin.data.SyncStatus; import org.hyperledger.besu.plugin.data.SyncStatus;
@ -228,6 +230,131 @@ public class BesuEventsImplTest {
serviceImpl.removeBlockPropagatedListener(5L); serviceImpl.removeBlockPropagatedListener(5L);
} }
@Test
public void addedBlockEventFiresAfterSubscribe() {
final AtomicReference<AddedBlockContext> result = new AtomicReference<>();
serviceImpl.addBlockAddedListener(result::set);
assertThat(result.get()).isNull();
final var block =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash()));
List<TransactionReceipt> transactionReceipts = gen.receipts(block);
blockchain.appendBlock(block, transactionReceipts);
assertThat(result.get()).isNotNull();
assertThat(result.get().getBlockHeader()).isEqualTo(block.getHeader());
assertThat(result.get().getTransactionReceipts()).isEqualTo(transactionReceipts);
}
@Test
public void addedBlockEventDoesNotFireAfterUnsubscribe() {
final AtomicReference<AddedBlockContext> result = new AtomicReference<>();
final long id = serviceImpl.addBlockAddedListener(result::set);
assertThat(result.get()).isNull();
serviceImpl.removeBlockAddedListener(id);
result.set(null);
final var block =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash()));
blockchain.appendBlock(block, gen.receipts(block));
assertThat(result.get()).isNull();
}
@Test
public void additionWithoutSubscriptionsCompletes() {
final var block =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash()));
blockchain.appendBlock(block, gen.receipts(block));
}
@Test
public void addedBlockEventUselessUnsubscribesCompletes() {
serviceImpl.removeBlockAddedListener(5);
serviceImpl.removeBlockAddedListener(5L);
}
@Test
public void reorgedBlockEventFiresAfterSubscribe() {
final AtomicReference<AddedBlockContext> result = new AtomicReference<>();
serviceImpl.addBlockReorgListener(result::set);
assertThat(result.get()).isNull();
final var block =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash())
.setBlockNumber(blockchain.getGenesisBlock().getHeader().getNumber() + 1));
blockchain.appendBlock(block, gen.receipts(block));
assertThat(result.get()).isNull();
final var reorgBlock =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash())
.setBlockNumber(blockchain.getGenesisBlock().getHeader().getNumber() + 2));
List<TransactionReceipt> transactionReceipts = gen.receipts(reorgBlock);
blockchain.appendBlock(reorgBlock, transactionReceipts);
assertThat(result.get()).isNotNull();
assertThat(result.get().getBlockHeader()).isEqualTo(reorgBlock.getHeader());
assertThat(result.get().getTransactionReceipts()).isEqualTo(transactionReceipts);
}
@Test
public void reorgedBlockEventDoesNotFireAfterUnsubscribe() {
final AtomicReference<AddedBlockContext> result = new AtomicReference<>();
final long id = serviceImpl.addBlockReorgListener(result::set);
assertThat(result.get()).isNull();
serviceImpl.removeBlockReorgListener(id);
result.set(null);
final var block =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash())
.setBlockNumber(blockchain.getGenesisBlock().getHeader().getNumber() + 1));
blockchain.appendBlock(block, gen.receipts(block));
assertThat(result.get()).isNull();
final var reorgBlock =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash())
.setBlockNumber(blockchain.getGenesisBlock().getHeader().getNumber() + 1));
blockchain.appendBlock(reorgBlock, gen.receipts(reorgBlock));
assertThat(result.get()).isNull();
}
@Test
public void reorgWithoutSubscriptionsCompletes() {
final var block =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash())
.setBlockNumber(blockchain.getGenesisBlock().getHeader().getNumber() + 1));
blockchain.appendBlock(block, gen.receipts(block));
final var reorgBlock =
gen.block(
new BlockDataGenerator.BlockOptions()
.setParentHash(blockchain.getGenesisBlock().getHash())
.setBlockNumber(blockchain.getGenesisBlock().getHeader().getNumber() + 1));
List<TransactionReceipt> transactionReceipts = gen.receipts(reorgBlock);
blockchain.appendBlock(reorgBlock, transactionReceipts);
}
@Test
public void reorgedBlockEventUselessUnsubscribesCompletes() {
serviceImpl.removeBlockReorgListener(5);
serviceImpl.removeBlockReorgListener(5L);
}
@Test @Test
public void transactionAddedEventFiresAfterSubscribe() { public void transactionAddedEventFiresAfterSubscribe() {
final AtomicReference<Transaction> result = new AtomicReference<>(); final AtomicReference<Transaction> result = new AtomicReference<>();

@ -103,7 +103,8 @@ public class IbftMiningCoordinatorTest {
@Test @Test
public void addsNewChainHeadEventWhenNewCanonicalHeadBlockEventReceived() throws Exception { public void addsNewChainHeadEventWhenNewCanonicalHeadBlockEventReceived() throws Exception {
BlockAddedEvent headAdvancement = BlockAddedEvent headAdvancement =
BlockAddedEvent.createForHeadAdvancement(block, Collections.emptyList()); BlockAddedEvent.createForHeadAdvancement(
block, Collections.emptyList(), Collections.emptyList());
ibftMiningCoordinator.onBlockAdded(headAdvancement, blockChain); ibftMiningCoordinator.onBlockAdded(headAdvancement, blockChain);
assertThat(eventQueue.size()).isEqualTo(1); assertThat(eventQueue.size()).isEqualTo(1);

@ -58,9 +58,9 @@ public class AutoTransactionLogBloomCachingService {
chainReorgSubscriptionId = chainReorgSubscriptionId =
OptionalLong.of( OptionalLong.of(
blockchain.observeChainReorg( blockchain.observeChainReorg(
(header, __) -> (blockWithReceipts, __) ->
transactionLogBloomCacher.cacheLogsBloomForBlockHeader( transactionLogBloomCacher.cacheLogsBloomForBlockHeader(
header, Optional.empty(), true))); blockWithReceipts.getHeader(), Optional.empty(), true)));
transactionLogBloomCacher transactionLogBloomCacher
.getScheduler() .getScheduler()

@ -37,6 +37,7 @@ import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.LogWithMetadata;
import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@ -149,7 +150,9 @@ public class FilterManagerLogFilterTest {
final Block block = gen.block(); final Block block = gen.block();
filterManager.recordBlockEvent( filterManager.recordBlockEvent(
BlockAddedEvent.createForHeadAdvancement( BlockAddedEvent.createForHeadAdvancement(
block, LogWithMetadata.generate(block, gen.receipts(block), false)), block,
LogWithMetadata.generate(block, gen.receipts(block), false),
Collections.emptyList()),
blockchainQueries.getBlockchain()); blockchainQueries.getBlockchain());
} }

@ -233,7 +233,8 @@ public class FilterManagerTest {
new BlockDataGenerator.BlockOptions().setBlockNumber(blockNumber).setParentHash(parentHash); new BlockDataGenerator.BlockOptions().setBlockNumber(blockNumber).setParentHash(parentHash);
currentBlock = blockGenerator.block(options); currentBlock = blockGenerator.block(options);
filterManager.recordBlockEvent( filterManager.recordBlockEvent(
BlockAddedEvent.createForHeadAdvancement(currentBlock, Collections.emptyList()), BlockAddedEvent.createForHeadAdvancement(
currentBlock, Collections.emptyList(), Collections.emptyList()),
blockchainQueries.getBlockchain()); blockchainQueries.getBlockchain());
return currentBlock.getHash(); return currentBlock.getHash();
} }

@ -106,7 +106,9 @@ public class AbstractMiningCoordinatorTest {
miningCoordinator.start(); miningCoordinator.start();
miningCoordinator.onBlockAdded( miningCoordinator.onBlockAdded(
BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); BlockAddedEvent.createForHeadAdvancement(
BLOCK, Collections.emptyList(), Collections.emptyList()),
blockchain);
verifyNoMoreInteractions(minerExecutor, blockMiner); verifyNoMoreInteractions(minerExecutor, blockMiner);
} }
@ -118,7 +120,9 @@ public class AbstractMiningCoordinatorTest {
miningCoordinator.start(); miningCoordinator.start();
miningCoordinator.onBlockAdded( miningCoordinator.onBlockAdded(
BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); BlockAddedEvent.createForHeadAdvancement(
BLOCK, Collections.emptyList(), Collections.emptyList()),
blockchain);
verify(blockMiner).cancel(); verify(blockMiner).cancel();
verify(minerExecutor, times(2)).startAsyncMining(any(), any(), any()); verify(minerExecutor, times(2)).startAsyncMining(any(), any(), any());
@ -175,7 +179,9 @@ public class AbstractMiningCoordinatorTest {
miningCoordinator.start(); miningCoordinator.start();
when(syncState.isInSync()).thenReturn(true); when(syncState.isInSync()).thenReturn(true);
miningCoordinator.onBlockAdded( miningCoordinator.onBlockAdded(
BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); BlockAddedEvent.createForHeadAdvancement(
BLOCK, Collections.emptyList(), Collections.emptyList()),
blockchain);
verifyNoMoreInteractions(minerExecutor, blockMiner); verifyNoMoreInteractions(minerExecutor, blockMiner);
} }
@ -185,7 +191,9 @@ public class AbstractMiningCoordinatorTest {
miningCoordinator.enable(); miningCoordinator.enable();
when(syncState.isInSync()).thenReturn(true); when(syncState.isInSync()).thenReturn(true);
miningCoordinator.onBlockAdded( miningCoordinator.onBlockAdded(
BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); BlockAddedEvent.createForHeadAdvancement(
BLOCK, Collections.emptyList(), Collections.emptyList()),
blockchain);
verifyNoMoreInteractions(minerExecutor, blockMiner); verifyNoMoreInteractions(minerExecutor, blockMiner);
} }
@ -198,7 +206,9 @@ public class AbstractMiningCoordinatorTest {
when(syncState.isInSync()).thenReturn(true); when(syncState.isInSync()).thenReturn(true);
miningCoordinator.onBlockAdded( miningCoordinator.onBlockAdded(
BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); BlockAddedEvent.createForHeadAdvancement(
BLOCK, Collections.emptyList(), Collections.emptyList()),
blockchain);
verifyNoMoreInteractions(minerExecutor, blockMiner); verifyNoMoreInteractions(minerExecutor, blockMiner);
} }
@ -213,7 +223,9 @@ public class AbstractMiningCoordinatorTest {
when(syncState.isInSync()).thenReturn(true); when(syncState.isInSync()).thenReturn(true);
miningCoordinator.onBlockAdded( miningCoordinator.onBlockAdded(
BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); BlockAddedEvent.createForHeadAdvancement(
BLOCK, Collections.emptyList(), Collections.emptyList()),
blockchain);
verifyNoMoreInteractions(minerExecutor, blockMiner); verifyNoMoreInteractions(minerExecutor, blockMiner);
} }

@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.Hash;
import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.LogWithMetadata;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -27,6 +28,7 @@ public class BlockAddedEvent {
private final Block block; private final Block block;
private final List<Transaction> addedTransactions; private final List<Transaction> addedTransactions;
private final List<Transaction> removedTransactions; private final List<Transaction> removedTransactions;
private final List<TransactionReceipt> transactionReceipts;
private final EventType eventType; private final EventType eventType;
private final List<LogWithMetadata> logsWithMetadata; private final List<LogWithMetadata> logsWithMetadata;
private final Hash commonAncestorHash; private final Hash commonAncestorHash;
@ -42,23 +44,28 @@ public class BlockAddedEvent {
final Block block, final Block block,
final List<Transaction> addedTransactions, final List<Transaction> addedTransactions,
final List<Transaction> removedTransactions, final List<Transaction> removedTransactions,
final List<TransactionReceipt> transactionReceipts,
final List<LogWithMetadata> logsWithMetadata, final List<LogWithMetadata> logsWithMetadata,
final Hash commonAncestorHash) { final Hash commonAncestorHash) {
this.eventType = eventType; this.eventType = eventType;
this.block = block; this.block = block;
this.addedTransactions = addedTransactions; this.addedTransactions = addedTransactions;
this.removedTransactions = removedTransactions; this.removedTransactions = removedTransactions;
this.transactionReceipts = transactionReceipts;
this.logsWithMetadata = logsWithMetadata; this.logsWithMetadata = logsWithMetadata;
this.commonAncestorHash = commonAncestorHash; this.commonAncestorHash = commonAncestorHash;
} }
public static BlockAddedEvent createForHeadAdvancement( public static BlockAddedEvent createForHeadAdvancement(
final Block block, final List<LogWithMetadata> logsWithMetadata) { final Block block,
final List<LogWithMetadata> logsWithMetadata,
final List<TransactionReceipt> transactionReceipts) {
return new BlockAddedEvent( return new BlockAddedEvent(
EventType.HEAD_ADVANCED, EventType.HEAD_ADVANCED,
block, block,
block.getBody().getTransactions(), block.getBody().getTransactions(),
Collections.emptyList(), Collections.emptyList(),
transactionReceipts,
logsWithMetadata, logsWithMetadata,
block.getHeader().getParentHash()); block.getHeader().getParentHash());
} }
@ -67,6 +74,7 @@ public class BlockAddedEvent {
final Block block, final Block block,
final List<Transaction> addedTransactions, final List<Transaction> addedTransactions,
final List<Transaction> removedTransactions, final List<Transaction> removedTransactions,
final List<TransactionReceipt> transactionReceipts,
final List<LogWithMetadata> logsWithMetadata, final List<LogWithMetadata> logsWithMetadata,
final Hash commonAncestorHash) { final Hash commonAncestorHash) {
return new BlockAddedEvent( return new BlockAddedEvent(
@ -74,6 +82,7 @@ public class BlockAddedEvent {
block, block,
addedTransactions, addedTransactions,
removedTransactions, removedTransactions,
transactionReceipts,
logsWithMetadata, logsWithMetadata,
commonAncestorHash); commonAncestorHash);
} }
@ -85,6 +94,7 @@ public class BlockAddedEvent {
Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(), Collections.emptyList(),
Collections.emptyList(),
block.getHeader().getParentHash()); block.getHeader().getParentHash());
} }
@ -108,6 +118,10 @@ public class BlockAddedEvent {
return removedTransactions; return removedTransactions;
} }
public List<TransactionReceipt> getTransactionReceipts() {
return transactionReceipts;
}
public List<LogWithMetadata> getLogsWithMetadata() { public List<LogWithMetadata> getLogsWithMetadata() {
return logsWithMetadata; return logsWithMetadata;
} }

@ -14,9 +14,9 @@
*/ */
package org.hyperledger.besu.ethereum.chain; package org.hyperledger.besu.ethereum.chain;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockWithReceipts;
public interface ChainReorgObserver { public interface ChainReorgObserver {
void onBlockAdded(BlockHeader blockHeader, Blockchain blockchain); void onBlockAdded(BlockWithReceipts blockWithReceipts, Blockchain blockchain);
} }

@ -288,7 +288,8 @@ public class DefaultBlockchain implements MutableBlockchain {
return BlockAddedEvent.createForHeadAdvancement( return BlockAddedEvent.createForHeadAdvancement(
newBlock, newBlock,
LogWithMetadata.generate( LogWithMetadata.generate(
blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), false)); blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), false),
blockWithReceipts.getReceipts());
} else if (totalDifficulty.compareTo(blockchainStorage.getTotalDifficulty(chainHead).get()) } else if (totalDifficulty.compareTo(blockchainStorage.getTotalDifficulty(chainHead).get())
> 0) { > 0) {
// New block represents a chain reorganization // New block represents a chain reorganization
@ -345,7 +346,7 @@ public class DefaultBlockchain implements MutableBlockchain {
newTransactions.put( newTransactions.put(
blockHash, currentNewChainWithReceipts.getBlock().getBody().getTransactions()); blockHash, currentNewChainWithReceipts.getBlock().getBody().getTransactions());
addAddedLogsWithMetadata(addedLogsWithMetadata, currentNewChainWithReceipts); addAddedLogsWithMetadata(addedLogsWithMetadata, currentNewChainWithReceipts);
notifyChainReorgBlockAdded(currentNewChainWithReceipts.getHeader()); notifyChainReorgBlockAdded(currentNewChainWithReceipts);
currentNewChainWithReceipts = getParentBlockWithReceipts(currentNewChainWithReceipts); currentNewChainWithReceipts = getParentBlockWithReceipts(currentNewChainWithReceipts);
} }
@ -401,6 +402,7 @@ public class DefaultBlockchain implements MutableBlockchain {
newChainHeadWithReceipts.getBlock(), newChainHeadWithReceipts.getBlock(),
newTransactions.values().stream().flatMap(Collection::stream).collect(toList()), newTransactions.values().stream().flatMap(Collection::stream).collect(toList()),
removedTransactions, removedTransactions,
newChainHeadWithReceipts.getReceipts(),
Stream.concat(removedLogsWithMetadata.stream(), addedLogsWithMetadata.stream()) Stream.concat(removedLogsWithMetadata.stream(), addedLogsWithMetadata.stream())
.collect(Collectors.toUnmodifiableList()), .collect(Collectors.toUnmodifiableList()),
currentNewChainWithReceipts.getBlock().getHash()); currentNewChainWithReceipts.getBlock().getHash());
@ -569,7 +571,7 @@ public class DefaultBlockchain implements MutableBlockchain {
blockAddedObservers.forEach(observer -> observer.onBlockAdded(event, this)); blockAddedObservers.forEach(observer -> observer.onBlockAdded(event, this));
} }
private void notifyChainReorgBlockAdded(final BlockHeader blockHeader) { private void notifyChainReorgBlockAdded(final BlockWithReceipts blockWithReceipts) {
blockReorgObservers.forEach(observer -> observer.onBlockAdded(blockHeader, this)); blockReorgObservers.forEach(observer -> observer.onBlockAdded(blockWithReceipts, this));
} }
} }

@ -37,7 +37,7 @@ import org.apache.tuweni.bytes.Bytes;
* formats: logs, logs bloom, and cumulative gas used in the block. The TransactionReceiptType * formats: logs, logs bloom, and cumulative gas used in the block. The TransactionReceiptType
* attribute is the best way to check which format has been used. * attribute is the best way to check which format has been used.
*/ */
public class TransactionReceipt { public class TransactionReceipt implements org.hyperledger.besu.plugin.data.TransactionReceipt {
private static final int NONEXISTENT = -1; private static final int NONEXISTENT = -1;
@ -228,6 +228,7 @@ public class TransactionReceipt {
* *
* @return the total amount of gas consumed in the block after the transaction has been processed * @return the total amount of gas consumed in the block after the transaction has been processed
*/ */
@Override
public long getCumulativeGasUsed() { public long getCumulativeGasUsed() {
return cumulativeGasUsed; return cumulativeGasUsed;
} }
@ -237,6 +238,7 @@ public class TransactionReceipt {
* *
* @return the logs generated by the transaction * @return the logs generated by the transaction
*/ */
@Override
public List<Log> getLogs() { public List<Log> getLogs() {
return logs; return logs;
} }
@ -246,6 +248,7 @@ public class TransactionReceipt {
* *
* @return the logs bloom filter for the logs generated by the transaction * @return the logs bloom filter for the logs generated by the transaction
*/ */
@Override
public LogsBloomFilter getBloomFilter() { public LogsBloomFilter getBloomFilter() {
return bloomFilter; return bloomFilter;
} }
@ -255,6 +258,7 @@ public class TransactionReceipt {
* *
* @return the status code if the transaction receipt is status-encoded; otherwise {@code -1} * @return the status code if the transaction receipt is status-encoded; otherwise {@code -1}
*/ */
@Override
public int getStatus() { public int getStatus() {
return status; return status;
} }
@ -263,6 +267,7 @@ public class TransactionReceipt {
return transactionReceiptType; return transactionReceiptType;
} }
@Override
public Optional<Bytes> getRevertReason() { public Optional<Bytes> getRevertReason() {
return revertReason; return revertReason;
} }

@ -118,6 +118,7 @@ public class TrailingPeerLimiterTest {
new Block( new Block(
new BlockHeaderTestFixture().number(500).buildHeader(), new BlockHeaderTestFixture().number(500).buildHeader(),
new BlockBody(emptyList(), emptyList())), new BlockBody(emptyList(), emptyList())),
Collections.emptyList(),
Collections.emptyList()); Collections.emptyList());
trailingPeerLimiter.onBlockAdded(blockAddedEvent, blockchain); trailingPeerLimiter.onBlockAdded(blockAddedEvent, blockchain);
@ -135,6 +136,7 @@ public class TrailingPeerLimiterTest {
new Block( new Block(
new BlockHeaderTestFixture().number(599).buildHeader(), new BlockHeaderTestFixture().number(599).buildHeader(),
new BlockBody(emptyList(), emptyList())), new BlockBody(emptyList(), emptyList())),
Collections.emptyList(),
Collections.emptyList()); Collections.emptyList());
trailingPeerLimiter.onBlockAdded(blockAddedEvent, blockchain); trailingPeerLimiter.onBlockAdded(blockAddedEvent, blockchain);

@ -65,7 +65,7 @@ Calculated : ${currentHash}
tasks.register('checkAPIChanges', FileStateChecker) { tasks.register('checkAPIChanges', FileStateChecker) {
description = "Checks that the API for the Plugin-API project does not change without deliberate thought" description = "Checks that the API for the Plugin-API project does not change without deliberate thought"
files = sourceSets.main.allJava.files files = sourceSets.main.allJava.files
knownHash = 'xsbRG+RsUybzMTULPcsLugarMHFTU7ohQBKw44x2/zQ=' knownHash = 'fL4EQBDRXnw1hiUIUMscLxRG/uWznpZSNJGSIp9+mFo='
} }
check.dependsOn('checkAPIChanges') check.dependsOn('checkAPIChanges')

@ -0,0 +1,42 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.plugin.data;
import java.util.List;
/** The minimum set of data for a AddedBlockContext. */
public interface AddedBlockContext {
/**
* A {@link BlockHeader} object.
*
* @return A {@link BlockHeader}
*/
BlockHeader getBlockHeader();
/**
* A {@link BlockHeader} object.
*
* @return A {@link BlockHeader}
*/
BlockBody getBlockBody();
/**
* A list of transaction receipts for the added block.
*
* @return A List of {@link TransactionReceipt}
*/
List<? extends TransactionReceipt> getTransactionReceipts();
}

@ -0,0 +1,58 @@
/*
* Copyright ConsenSys AG.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
* specific language governing permissions and limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
package org.hyperledger.besu.plugin.data;
import java.util.List;
import java.util.Optional;
import org.apache.tuweni.bytes.Bytes;
/** A transaction receipt, containing information pertaining a transaction execution. */
public interface TransactionReceipt {
/**
* Returns the total amount of gas consumed in the block after the transaction has been processed.
*
* @return the total amount of gas consumed in the block after the transaction has been processed
*/
long getCumulativeGasUsed();
/**
* Returns the logs generated by the transaction.
*
* @return the logs generated by the transaction
*/
List<? extends Log> getLogs();
/**
* Returns the Bytes for the logs generated by the transaction
*
* @return the Bytes for the logs generated by the transaction
*/
Bytes getBloomFilter();
/**
* Returns the status code for the status-encoded transaction receipt
*
* @return the status code if the transaction receipt is status-encoded; otherwise {@code -1}
*/
int getStatus();
/**
* Returns the ABI-encoded revert reason for the failed transaction (if applicable)
*
* @return the ABI-encoded revert reason for the failed transaction (if applicable)
*/
Optional<Bytes> getRevertReason();
}

@ -14,6 +14,7 @@
*/ */
package org.hyperledger.besu.plugin.services; package org.hyperledger.besu.plugin.services;
import org.hyperledger.besu.plugin.data.AddedBlockContext;
import org.hyperledger.besu.plugin.data.Address; import org.hyperledger.besu.plugin.data.Address;
import org.hyperledger.besu.plugin.data.LogWithMetadata; import org.hyperledger.besu.plugin.data.LogWithMetadata;
import org.hyperledger.besu.plugin.data.PropagatedBlockContext; import org.hyperledger.besu.plugin.data.PropagatedBlockContext;
@ -57,6 +58,36 @@ public interface BesuEvents {
*/ */
void removeBlockPropagatedListener(long listenerIdentifier); void removeBlockPropagatedListener(long listenerIdentifier);
/**
* Add a listener watching for new blocks added.
*
* @param blockAddedListener The listener that will accept the Block object as the event.
* @return an id to be used as an identifier when de-registering the event.
*/
long addBlockAddedListener(BlockAddedListener blockAddedListener);
/**
* Remove the block added listener from besu notifications.
*
* @param listenerIdentifier The id that was returned from addBlockAddedListener;
*/
void removeBlockAddedListener(long listenerIdentifier);
/**
* Add a listener watching for new reorg blocks added.
*
* @param blockReorgListener The listener that will accept the reorg Block object as the event.
* @return an id to be used as an identifier when de-registering the event.
*/
long addBlockReorgListener(BlockReorgListener blockReorgListener);
/**
* Remove the block reorg listener from besu notifications.
*
* @param listenerIdentifier The id that was returned from addBlockReorgListener;
*/
void removeBlockReorgListener(long listenerIdentifier);
/** /**
* Add a listener watching new transactions added to the node. * Add a listener watching new transactions added to the node.
* *
@ -138,6 +169,28 @@ public interface BesuEvents {
void onBlockPropagated(PropagatedBlockContext propagatedBlockContext); void onBlockPropagated(PropagatedBlockContext propagatedBlockContext);
} }
/** The listener interface for receiving new block added events. */
interface BlockAddedListener {
/**
* Invoked when a new block has been evaluated and validated.
*
* @param addedBlockContext block being added.
*/
void onBlockAdded(AddedBlockContext addedBlockContext);
}
/** The listener interface for receiving new block reorg events. */
interface BlockReorgListener {
/**
* Invoked when a reorg block has been evaluated and validated.
*
* @param addedBlockContext reorg block being added.
*/
void onBlockReorg(AddedBlockContext addedBlockContext);
}
/** The listener interface for receiving new transaction added events. */ /** The listener interface for receiving new transaction added events. */
interface TransactionAddedListener { interface TransactionAddedListener {

Loading…
Cancel
Save