From 42601c44f23c5ae265c16c2e704a9e124b13abb7 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 16 Sep 2019 12:50:28 +0300 Subject: [PATCH 01/40] rework filters to use less mocking Signed-off-by: Ratan Rai Sur --- .../logs/LogsSubscriptionServiceTest.java | 446 ++++++++++++------ .../ethereum/core/BlockDataGenerator.java | 22 +- 2 files changed, 313 insertions(+), 155 deletions(-) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index 4f0caf009f6..fd4cfc3b633 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -14,249 +14,387 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.logs; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.refEq; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.hyperledger.besu.crypto.SECP256K1.KeyPair; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.FilterParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogResult; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; -import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; -import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; -import org.hyperledger.besu.ethereum.chain.Blockchain; +import org.hyperledger.besu.ethereum.api.query.TopicsParameter; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; -import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider; import org.hyperledger.besu.ethereum.core.Log; +import org.hyperledger.besu.ethereum.core.LogTopic; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.core.TransactionTestFixture; -import org.hyperledger.besu.util.bytes.BytesValue; +import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.Optional; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.Stream; import com.google.common.collect.Lists; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentMatchers; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @RunWith(MockitoJUnitRunner.class) public class LogsSubscriptionServiceTest { - private final KeyPair keyPair = KeyPair.generate(); - private final BlockHeaderTestFixture blockHeaderTestFixture = new BlockHeaderTestFixture(); - private final TransactionTestFixture txTestFixture = new TransactionTestFixture(); + private final BlockDataGenerator gen = new BlockDataGenerator(1); + private final WorldStateArchive worldStateArchive = + InMemoryStorageProvider.createInMemoryWorldStateArchive(); + private final MutableBlockchain blockchain = + InMemoryStorageProvider.createInMemoryBlockchain(gen.genesisBlock()); + private BlockchainQueries blockchainQueries = + new BlockchainQueries(blockchain, worldStateArchive); private LogsSubscriptionService logsSubscriptionService; + private final AtomicLong nextSubscriptionId = new AtomicLong(); @Mock private SubscriptionManager subscriptionManager; - @Mock private BlockchainQueries blockchainQueries; - @Mock private Blockchain blockchain; @Before public void before() { logsSubscriptionService = new LogsSubscriptionService(subscriptionManager, blockchainQueries); + blockchain.observeBlockAdded(logsSubscriptionService); } @Test - public void shouldSendLogMessageWhenBlockAddedEventHasAddedTransactionsMatchingSubscription() { - final Address address = Address.fromHexString("0x0"); - final LogsSubscription subscription = createSubscription(address); - final Transaction transaction = createTransaction(); - final Log log = createLog(address); - final LogResult expectedLogResult = createLogResult(transaction, log, false); + public void singleMatchingLogEvent() { + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); - logsSubscriptionService.onBlockAdded(createBlockAddedEvent(transaction, null), blockchain); + final int txIndex = 1; + final int logIndex = 1; + final Log targetLog = receipts.get(txIndex).getLogs().get(logIndex); - verify(subscriptionManager) - .sendMessage( - ArgumentMatchers.eq(subscription.getSubscriptionId()), refEq(expectedLogResult)); - } + final LogsSubscription subscription = createSubscription(targetLog.getLogger()); + registerSubscriptions(subscription); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); - @Test - public void shouldSendLogMessageWhenBlockAddedEventHasRemovedTransactionsMatchingSubscription() { - final Address address = Address.fromHexString("0x0"); - final LogsSubscription subscription = createSubscription(address); - final Transaction transaction = createTransaction(); - final Log log = createLog(address); - final LogResult expectedLogResult = createLogResult(transaction, log, true); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager).sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); - logsSubscriptionService.onBlockAdded(createBlockAddedEvent(null, transaction), blockchain); + final List logResults = captor.getAllValues(); - verify(subscriptionManager) - .sendMessage( - ArgumentMatchers.eq(subscription.getSubscriptionId()), refEq(expectedLogResult)); + assertThat(logResults.size()).isEqualTo(1); + final LogResult result = logResults.get(0); + assertLogResultMatches(result, block, receipts, txIndex, logIndex, false); } @Test - public void shouldSendMessageForAllLogsMatchingSubscription() { - final Address address = Address.fromHexString("0x0"); - final Log log = createLog(address); - final LogsSubscription subscription = createSubscription(address); - final List addedTransactions = createTransactionsWithLog(log); - final List removedTransactions = createTransactionsWithLog(log); + public void singleMatchingLogEmittedThenRemovedInReorg() { + // Create block that emits an event + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); + + final int txIndex = 1; + final int logIndex = 1; + final Log targetLog = receipts.get(txIndex).getLogs().get(logIndex); + + final LogsSubscription subscription = createSubscription(targetLog.getLogger()); + registerSubscriptions(subscription); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + // Cause a reorg that removes the block which emitted an event + BlockHeader parentHeader = blockchain.getGenesisBlock().getHeader(); + while (!blockchain.getChainHeadHash().equals(parentHeader.getHash())) { + final BlockWithReceipts newBlock = generateBlock(parentHeader, 2, 0, 0); + parentHeader = newBlock.getBlock().getHeader(); + blockchain.appendBlock(newBlock.getBlock(), newBlock.getReceipts()); + } - logsSubscriptionService.onBlockAdded( - createBlockAddedEvent(addedTransactions, removedTransactions), blockchain); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(2)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); - final int totalOfLogs = addedTransactions.size() + removedTransactions.size(); + final List logResults = captor.getAllValues(); - verify(subscriptionManager, times(totalOfLogs)) - .sendMessage(ArgumentMatchers.eq(subscription.getSubscriptionId()), any()); + assertThat(logResults.size()).isEqualTo(2); + final LogResult firstLog = logResults.get(0); + assertLogResultMatches(firstLog, block, receipts, txIndex, logIndex, false); + final LogResult secondLog = logResults.get(1); + assertLogResultMatches(secondLog, block, receipts, txIndex, logIndex, true); } @Test - public void shouldSendLogMessageToAllMatchingSubscriptions() { - final Address address = Address.fromHexString("0x0"); - final List subscriptions = createSubscriptions(address); - final Transaction transaction = createTransaction(); - final Log log = createLog(address); - final LogResult expectedLogResult = createLogResult(transaction, log, false); + public void singleMatchingLogEmittedThenMovedInReorg() { + // Create block that emits an event + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); + + final int txIndex = 1; + final int logIndex = 1; + final Log targetLog = receipts.get(txIndex).getLogs().get(logIndex); + + final LogsSubscription subscription = createSubscription(targetLog.getLogger()); + registerSubscriptions(subscription); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + // Cause a reorg that removes the block which emitted an event + BlockHeader parentHeader = blockchain.getGenesisBlock().getHeader(); + while (!blockchain.getChainHeadHash().equals(parentHeader.getHash())) { + final BlockWithReceipts newBlock = generateBlock(parentHeader, 2, 0, 0); + parentHeader = newBlock.getBlock().getHeader(); + blockchain.appendBlock(newBlock.getBlock(), newBlock.getReceipts()); + } + + // Now add another block that re-emits the target log + final BlockWithReceipts newBlockWithLog = generateBlock(1, () -> Arrays.asList(targetLog)); + blockchain.appendBlock(newBlockWithLog.getBlock(), newBlockWithLog.getReceipts()); + // Sanity check + assertThat(blockchain.getChainHeadHash()).isEqualTo(newBlockWithLog.getBlock().getHash()); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(3)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); + + final List logResults = captor.getAllValues(); + + assertThat(logResults.size()).isEqualTo(3); + final LogResult originalLog = logResults.get(0); + assertLogResultMatches(originalLog, block, receipts, txIndex, logIndex, false); + final LogResult removedLog = logResults.get(1); + assertLogResultMatches(removedLog, block, receipts, txIndex, logIndex, true); + final LogResult updatedLog = logResults.get(1); + assertLogResultMatches( + updatedLog, newBlockWithLog.getBlock(), newBlockWithLog.getReceipts(), 0, 0, false); + } + + @Test + public void multipleMatchingLogsEmitted() { + final Log targetLog = gen.log(); + final Log otherLog = gen.log(); + final List logs = Arrays.asList(targetLog, otherLog); + + final LogsSubscription subscription = createSubscription(targetLog.getLogger()); + registerSubscriptions(subscription); + + // Generate blocks with multiple logs matching subscription + final int txCount = 2; + final List targetBlocks = new ArrayList<>(); + for (int i = 0; i < 2; i++) { + final BlockWithReceipts blockWithReceipts = generateBlock(txCount, () -> logs); + targetBlocks.add(blockWithReceipts); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + // Add another block with unrelated logs + final BlockWithReceipts otherBlock = generateBlock(txCount, 2, 2); + blockchain.appendBlock(otherBlock.getBlock(), otherBlock.getReceipts()); + } - logsSubscriptionService.onBlockAdded(createBlockAddedEvent(transaction, null), blockchain); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(targetBlocks.size() * txCount)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); + final List logResults = captor.getAllValues(); + + // Verify all logs are emitted + assertThat(logResults.size()).isEqualTo(targetBlocks.size() * txCount); + for (int i = 0; i < targetBlocks.size(); i++) { + final BlockWithReceipts targetBlock = targetBlocks.get(i); + for (int j = 0; j < txCount; j++) { + final int resultIndex = i * txCount + j; + assertLogResultMatches( + logResults.get(resultIndex), + targetBlock.getBlock(), + targetBlock.getReceipts(), + j, + 0, + false); + } + } + } - verify(subscriptionManager, times(subscriptions.size())) - .sendMessage(any(), refEq(expectedLogResult)); + @Test + public void multipleSubscriptionsForSingleMatchingLog() { + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + final Block block = blockWithReceipts.getBlock(); + final List receipts = blockWithReceipts.getReceipts(); + + final int txIndex = 1; + final int logIndex = 1; + final Log targetLog = receipts.get(txIndex).getLogs().get(logIndex); + + final List subscriptions = + Stream.generate(() -> createSubscription(targetLog.getLogger())) + .limit(3) + .collect(Collectors.toList()); + registerSubscriptions(subscriptions); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); + + for (LogsSubscription subscription : subscriptions) { + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); + + final List logResults = captor.getAllValues(); + + assertThat(logResults.size()).isEqualTo(1); + final LogResult result = logResults.get(0); + assertLogResultMatches(result, block, receipts, txIndex, logIndex, false); + } } @Test - public void shouldNotSendLogMessageWhenBlockAddedEventHasNoTransactions() { + public void noLogsEmitted() { final Address address = Address.fromHexString("0x0"); - createSubscription(address); + final LogsSubscription subscription = createSubscription(address); + registerSubscriptions(subscription); - logsSubscriptionService.onBlockAdded( - createBlockAddedEvent(Collections.emptyList(), Collections.emptyList()), blockchain); + final BlockWithReceipts blockWithReceipts = generateBlock(2, 0, 0); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); - verify(subscriptionManager).subscriptionsOfType(any(), any()); - verify(subscriptionManager, times(0)).sendMessage(any(), any()); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(0)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); } @Test - public void shouldNotSendLogMessageWhenLogsDoNotMatchAnySubscription() { - createSubscription(Address.fromHexString("0x0")); - final Transaction transaction = createTransaction(); - final Log log = createLog(Address.fromHexString("0x1")); - createLogResult(transaction, log, false); + public void noMatchingLogsEmitted() { + final Address address = Address.fromHexString("0x0"); + final LogsSubscription subscription = createSubscription(address); + registerSubscriptions(subscription); - logsSubscriptionService.onBlockAdded(createBlockAddedEvent(transaction, null), blockchain); + final BlockWithReceipts blockWithReceipts = generateBlock(2, 2, 2); + blockchain.appendBlock(blockWithReceipts.getBlock(), blockWithReceipts.getReceipts()); - verify(subscriptionManager).subscriptionsOfType(any(), any()); - verify(subscriptionManager, times(0)).sendMessage(any(), any()); + final ArgumentCaptor captor = ArgumentCaptor.forClass(LogResult.class); + verify(subscriptionManager, times(0)) + .sendMessage(eq(subscription.getSubscriptionId()), captor.capture()); } - private Transaction createTransaction() { - return txTestFixture.createTransaction(keyPair); + private void assertLogResultMatches( + final LogResult result, + final Block block, + final List receipts, + final int txIndex, + final int logIndex, + final boolean isRemoved) { + final Transaction expectedTransaction = block.getBody().getTransactions().get(txIndex); + final Log expectedLog = receipts.get(txIndex).getLogs().get(logIndex); + + assertThat(result.getLogIndex()).isEqualTo(Quantity.create(logIndex)); + assertThat(result.getTransactionIndex()).isEqualTo(Quantity.create(txIndex)); + assertThat(result.getBlockNumber()).isEqualTo(Quantity.create(block.getHeader().getNumber())); + assertThat(result.getBlockHash()).isEqualTo(block.getHash().toString()); + assertThat(result.getTransactionHash()).isEqualTo(expectedTransaction.getHash().toString()); + assertThat(result.getAddress()).isEqualTo(expectedLog.getLogger().toString()); + assertThat(result.getData()).isEqualTo(expectedLog.getData().toString()); + assertThat(result.getTopics()) + .isEqualTo( + expectedLog.getTopics().stream().map(LogTopic::toString).collect(Collectors.toList())); + assertThat(result.isRemoved()).isEqualTo(isRemoved); } - private Log createLog(final Address address) { - return new Log(address, BytesValue.EMPTY, Collections.emptyList()); + private BlockWithReceipts generateBlock( + final int txCount, final int logsPerTx, final int topicsPerLog) { + final BlockHeader parent = blockchain.getChainHeadHeader(); + return generateBlock(parent, txCount, () -> gen.logs(logsPerTx, topicsPerLog)); } - private LogsSubscription createSubscription(final Address address) { - final FilterParameter filterParameter = - new FilterParameter(null, null, Lists.newArrayList(address.toString()), null, null); - final LogsSubscription logsSubscription = new LogsSubscription(1L, "conn", filterParameter); - when(subscriptionManager.subscriptionsOfType(any(), any())) - .thenReturn(Lists.newArrayList(logsSubscription)); - return logsSubscription; + private BlockWithReceipts generateBlock( + final BlockHeader parentHeader, + final int txCount, + final int logsPerTx, + final int topicsPerLog) { + return generateBlock(parentHeader, txCount, () -> gen.logs(logsPerTx, topicsPerLog)); } - private List createSubscriptions(final Address address) { - final List subscriptions = new ArrayList<>(); - for (long i = 0; i < 3; i++) { - final FilterParameter filterParameter = - new FilterParameter(null, null, Lists.newArrayList(address.toString()), null, null); - subscriptions.add(new LogsSubscription(i, "conn", filterParameter)); - } - when(subscriptionManager.subscriptionsOfType(any(), any())) - .thenReturn(Lists.newArrayList(subscriptions)); - return subscriptions; + private BlockWithReceipts generateBlock( + final int txCount, final Supplier> logsSupplier) { + final BlockHeader parent = blockchain.getChainHeadHeader(); + return generateBlock(parent, txCount, logsSupplier); } - private LogResult createLogResult( - final Transaction transaction, final Log log, final boolean removed) { - final TransactionReceiptWithMetadata txReceiptWithMetadata = - createTransactionWithLog(transaction, log); - final LogWithMetadata logWithMetadata = createLogWithMetadata(txReceiptWithMetadata, removed); - return new LogResult(logWithMetadata); - } + private BlockWithReceipts generateBlock( + final BlockHeader parentHeader, final int txCount, final Supplier> logsSupplier) { + final List receipts = new ArrayList<>(); + final List logs = new ArrayList<>(); + final BlockOptions blockOptions = BlockOptions.create(); + for (int i = 0; i < txCount; i++) { + final Transaction tx = gen.transaction(); + final TransactionReceipt receipt = gen.receipt(logsSupplier.get()); + + receipts.add(receipt); + receipt.getLogs().forEach(logs::add); + blockOptions.addTransaction(tx); + } - private TransactionReceiptWithMetadata createTransactionWithLog( - final Transaction transaction, final Log log) { - final BlockHeader blockHeader = blockHeaderTestFixture.buildHeader(); - final TransactionReceipt transactionReceipt = - new TransactionReceipt(Hash.ZERO, 1L, Lists.newArrayList(log), Optional.empty()); - final TransactionReceiptWithMetadata transactionReceiptWithMetadata = - TransactionReceiptWithMetadata.create( - transactionReceipt, - transaction, - transaction.getHash(), - 0, - 1L, - blockHeader.getHash(), - blockHeader.getNumber()); + blockOptions.setParentHash(parentHeader.getHash()); + blockOptions.setBlockNumber(parentHeader.getNumber() + 1L); + final Block block = gen.block(blockOptions); - when(blockchainQueries.transactionReceiptByTransactionHash(eq(transaction.getHash()))) - .thenReturn(Optional.of(transactionReceiptWithMetadata)); + return new BlockWithReceipts(block, receipts); + } - return transactionReceiptWithMetadata; + private LogsSubscription createSubscription(final Address address) { + return createSubscription(Arrays.asList(address), Collections.emptyList()); } - private BlockAddedEvent createBlockAddedEvent( - final Transaction addedTransaction, final Transaction removedTransaction) { - final Block block = mock(Block.class); - return BlockAddedEvent.createForChainReorg( - block, - addedTransaction != null ? Lists.newArrayList(addedTransaction) : Collections.emptyList(), - removedTransaction != null - ? Lists.newArrayList(removedTransaction) - : Collections.emptyList()); + private LogsSubscription createSubscription( + final List
addresses, final List> logTopics) { + // TODO: FilterParameter constructor should work with proper types instead of Strings + final List addressStrings = + addresses.stream().map(Address::toString).collect(Collectors.toList()); + final List> topicStrings = + logTopics.stream() + .map(topics -> topics.stream().map(LogTopic::toString).collect(Collectors.toList())) + .collect(Collectors.toList()); + + final FilterParameter filterParameter = + new FilterParameter(null, null, addressStrings, new TopicsParameter(topicStrings), null); + final LogsSubscription logsSubscription = + new LogsSubscription(nextSubscriptionId.incrementAndGet(), "conn", filterParameter); + return logsSubscription; } - private BlockAddedEvent createBlockAddedEvent( - final List addedTransactions, final List removedTransactions) { - final Block block = mock(Block.class); - return BlockAddedEvent.createForChainReorg( - block, - addedTransactions != null ? Lists.newArrayList(addedTransactions) : Collections.emptyList(), - removedTransactions != null - ? Lists.newArrayList(removedTransactions) - : Collections.emptyList()); + private void registerSubscriptions(final LogsSubscription... subscriptions) { + registerSubscriptions(Arrays.asList(subscriptions)); } - private List createTransactionsWithLog(final Log log) { - final ArrayList transactions = - Lists.newArrayList(createTransaction(), createTransaction(), createTransaction()); - transactions.forEach(tx -> createTransactionWithLog(tx, log)); - return transactions; + private void registerSubscriptions(final List subscriptions) { + when(subscriptionManager.subscriptionsOfType(any(), any())) + .thenReturn(Lists.newArrayList(subscriptions)); } - private LogWithMetadata createLogWithMetadata( - final TransactionReceiptWithMetadata transactionReceiptWithMetadata, final boolean removed) { - return new LogWithMetadata( - 0, - transactionReceiptWithMetadata.getBlockNumber(), - transactionReceiptWithMetadata.getBlockHash(), - transactionReceiptWithMetadata.getTransactionHash(), - transactionReceiptWithMetadata.getTransactionIndex(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(0).getLogger(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(0).getData(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(0).getTopics(), - removed); + private static class BlockWithReceipts { + private final Block block; + private final List receipts; + + public BlockWithReceipts(final Block block, final List receipts) { + this.block = block; + this.receipts = receipts; + } + + public Block getBlock() { + return block; + } + + public List getReceipts() { + return receipts; + } } } diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java index a15d0fe7485..415f049c808 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java @@ -41,7 +41,9 @@ import java.util.OptionalLong; import java.util.Random; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.util.stream.Stream; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; @@ -352,6 +354,10 @@ public TransactionReceipt receipt() { return receipt(positiveLong()); } + public TransactionReceipt receipt(final List logs) { + return new TransactionReceipt(hash(), positiveLong(), logs, Optional.empty()); + } + public UInt256 storageKey() { return uint256(); } @@ -368,8 +374,22 @@ public List receipts(final Block block) { return receipts; } + public List logs(final int logsCount, final int topicsPerLog) { + return Stream.generate(() -> log(topicsPerLog)).limit(logsCount).collect(Collectors.toList()); + } + public Log log() { - return new Log(address(), bytesValue(5 + random.nextInt(10)), Collections.emptyList()); + return log(0); + } + + public Log log(final int topicCount) { + final List topics = + Stream.generate(this::logTopic).limit(topicCount).collect(Collectors.toList()); + return new Log(address(), bytesValue(5 + random.nextInt(10)), topics); + } + + private LogTopic logTopic() { + return LogTopic.create(bytesValue(LogTopic.SIZE)); } private Bytes32 bytes32() { From 7bac2c498c411e3473ab9a5c5461541981a2c0d1 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 16 Sep 2019 17:21:26 +0300 Subject: [PATCH 02/40] use checkArgument Signed-off-by: Ratan Rai Sur --- .../hyperledger/besu/ethereum/chain/DefaultBlockchain.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 9bb8c1f05a9..a8f5a747f1c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -225,9 +225,7 @@ public synchronized void appendBlock(final Block block, final List Date: Mon, 16 Sep 2019 19:28:45 +0300 Subject: [PATCH 03/40] move LogWithMetadata to core Signed-off-by: Ratan Rai Sur --- .../besu/ethereum/api/graphql/GraphQLDataFetchers.java | 2 +- .../graphql/internal/pojoadapter/BlockAdapterBase.java | 2 +- .../api/graphql/internal/pojoadapter/LogAdapter.java | 2 +- .../graphql/internal/pojoadapter/TransactionAdapter.java | 2 +- .../api/jsonrpc/internal/filter/FilterManager.java | 2 +- .../ethereum/api/jsonrpc/internal/filter/LogFilter.java | 2 +- .../jsonrpc/internal/methods/EthGetFilterChanges.java | 2 +- .../api/jsonrpc/internal/methods/EthGetFilterLogs.java | 2 +- .../ethereum/api/jsonrpc/internal/results/LogResult.java | 2 +- .../api/jsonrpc/internal/results/LogsResult.java | 2 +- .../subscription/logs/LogsSubscriptionService.java | 2 +- .../besu/ethereum/api/query/BlockchainQueries.java | 1 + .../internal/filter/FilterManagerLogFilterTest.java | 2 +- .../internal/methods/EthGetFilterChangesTest.java | 2 +- .../jsonrpc/internal/methods/EthGetFilterLogsTest.java | 2 +- .../besu/ethereum/api/query/BlockchainQueriesTest.java | 1 + .../hyperledger/besu/ethereum/chain/BlockAddedEvent.java | 9 +++++++++ .../hyperledger/besu/ethereum/core}/LogWithMetadata.java | 5 +---- 18 files changed, 26 insertions(+), 18 deletions(-) rename ethereum/{api/src/main/java/org/hyperledger/besu/ethereum/api/query => core/src/main/java/org/hyperledger/besu/ethereum/core}/LogWithMetadata.java (93%) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java index e6e282cfd0e..df1105274a8 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/GraphQLDataFetchers.java @@ -25,7 +25,6 @@ import org.hyperledger.besu.ethereum.api.graphql.internal.response.GraphQLError; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; @@ -33,6 +32,7 @@ import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Synchronizer; import org.hyperledger.besu.ethereum.core.Transaction; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java index ef042002818..00d4c21b779 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/BlockAdapterBase.java @@ -17,13 +17,13 @@ import org.hyperledger.besu.ethereum.api.graphql.GraphQLDataFetcherContext; import org.hyperledger.besu.ethereum.api.query.BlockWithMetadata; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.ethereum.core.WorldState; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java index ac459a80cdc..697d6b6e718 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java @@ -15,10 +15,10 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.util.bytes.Bytes32; import org.hyperledger.besu.util.bytes.BytesValue; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java index 0454904a4c0..d612b97ed1a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java @@ -15,11 +15,11 @@ package org.hyperledger.besu.ethereum.api.graphql.internal.pojoadapter; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManager.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManager.java index f832cb6b965..f51ac4b539c 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManager.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManager.java @@ -18,11 +18,11 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogFilter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogFilter.java index 2125f851730..54b5c40daee 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogFilter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/LogFilter.java @@ -15,8 +15,8 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.api.query.LogsQuery; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java index 8b54704ba4b..620335f0e72 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChanges.java @@ -23,8 +23,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.List; import java.util.stream.Collectors; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java index 3c654844be0..f251e7f9630 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogs.java @@ -23,7 +23,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.List; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java index 1d4885d69eb..29d6d2802ec 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java @@ -14,8 +14,8 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.core.LogTopic; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogsResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogsResult.java index aa7ca1e3ac0..c27722627aa 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogsResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogsResult.java @@ -14,7 +14,7 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.ArrayList; import java.util.List; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java index 38adb86e3da..84d868c9f83 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java @@ -18,12 +18,12 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Log; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import java.util.List; import java.util.Optional; diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 7b86891fbc0..2c4609b1256 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -24,6 +24,7 @@ import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.MutableWorldState; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java index 25904f3c170..ee59ea15104 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java @@ -28,13 +28,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.api.query.LogsQuery; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; import org.hyperledger.besu.util.bytes.BytesValue; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java index 1c60d3d920d..7b640376d10 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterChangesTest.java @@ -31,9 +31,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.util.bytes.BytesValue; import java.util.List; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java index e3a673a3308..c543108cba4 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthGetFilterLogsTest.java @@ -29,9 +29,9 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogsResult; -import org.hyperledger.besu.ethereum.api.query.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.util.bytes.BytesValue; import java.util.ArrayList; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java index 4ff416d8db0..23e446b13ff 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueriesTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.Wei; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java index b19713e2e9c..c1779a041c2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.chain; import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import java.util.Collections; @@ -27,6 +28,14 @@ public class BlockAddedEvent { private final List removedTransactions; private final EventType eventType; + public List getRemovedLogsWithMetadata() { + return null; + } + + public List getAddedLogsWithMetadata() { + return null; + } + public enum EventType { HEAD_ADVANCED, FORK, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java similarity index 93% rename from ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/LogWithMetadata.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index be4bd2e5c92..75caac0fbd7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -14,11 +14,8 @@ * SPDX-License-Identifier: Apache-2.0 * */ -package org.hyperledger.besu.ethereum.api.query; +package org.hyperledger.besu.ethereum.core; -import org.hyperledger.besu.ethereum.core.Address; -import org.hyperledger.besu.ethereum.core.Hash; -import org.hyperledger.besu.ethereum.core.LogTopic; import org.hyperledger.besu.util.bytes.BytesValue; import java.util.List; From 5169788d3bf5eca9dbf327bd1b6a8ab2e4b2e5b1 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Tue, 17 Sep 2019 18:00:39 +0300 Subject: [PATCH 04/40] use getOrThrow Signed-off-by: Ratan Rai Sur --- .../besu/ethereum/chain/DefaultBlockchain.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index a8f5a747f1c..4cd64d9f723 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -259,13 +259,12 @@ private UInt256 calculateTotalDifficulty(final Block block) { return block.getHeader().getDifficulty(); } - final Optional maybeParentId = - blockchainStorage.getTotalDifficulty(block.getHeader().getParentHash()); - if (!maybeParentId.isPresent()) { - throw new IllegalStateException("Blockchain is missing total difficulty data."); - } - final UInt256 parentTd = maybeParentId.get(); - return block.getHeader().getDifficulty().plus(parentTd); + final UInt256 parentId = + blockchainStorage + .getTotalDifficulty(block.getHeader().getParentHash()) + .orElseThrow( + () -> new IllegalStateException("Blockchain is missing total difficulty data.")); + return block.getHeader().getDifficulty().plus(parentId); } private BlockAddedEvent updateCanonicalChainData( From 4ad7d1f8c1de2d0bda45ffbbea7b199a985215ae Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Tue, 17 Sep 2019 18:18:39 +0300 Subject: [PATCH 05/40] move BlockWithReceipts to core Signed-off-by: Ratan Rai Sur --- .../logs/LogsSubscriptionServiceTest.java | 18 +----------------- .../besu/ethereum/core}/BlockWithReceipts.java | 11 +++-------- .../sync/fastsync/DownloadReceiptsStep.java | 1 + .../sync/fastsync/FastImportBlocksStep.java | 1 + .../fastsync/DownloadReceiptsStepTest.java | 1 + .../fastsync/FastImportBlocksStepTest.java | 1 + 6 files changed, 8 insertions(+), 25 deletions(-) rename ethereum/{eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync => core/src/main/java/org/hyperledger/besu/ethereum/core}/BlockWithReceipts.java (82%) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index fd4cfc3b633..c43e0f31cc3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.InMemoryStorageProvider; import org.hyperledger.besu.ethereum.core.Log; import org.hyperledger.besu.ethereum.core.LogTopic; @@ -380,21 +381,4 @@ private void registerSubscriptions(final List subscriptions) { .thenReturn(Lists.newArrayList(subscriptions)); } - private static class BlockWithReceipts { - private final Block block; - private final List receipts; - - public BlockWithReceipts(final Block block, final List receipts) { - this.block = block; - this.receipts = receipts; - } - - public Block getBlock() { - return block; - } - - public List getReceipts() { - return receipts; - } - } } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/BlockWithReceipts.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java similarity index 82% rename from ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/BlockWithReceipts.java rename to ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java index 6b96a8dd254..ae642b065ad 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/BlockWithReceipts.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java @@ -12,23 +12,18 @@ * * SPDX-License-Identifier: Apache-2.0 */ -package org.hyperledger.besu.ethereum.eth.sync.fastsync; - -import org.hyperledger.besu.ethereum.core.Block; -import org.hyperledger.besu.ethereum.core.BlockHeader; -import org.hyperledger.besu.ethereum.core.Hash; -import org.hyperledger.besu.ethereum.core.TransactionReceipt; +package org.hyperledger.besu.ethereum.core; import java.util.List; import java.util.Objects; import com.google.common.base.MoreObjects; -class BlockWithReceipts { +public class BlockWithReceipts { private final Block block; private final List receipts; - BlockWithReceipts(final Block block, final List receipts) { + public BlockWithReceipts(final Block block, final List receipts) { this.block = block; this.receipts = receipts; } diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java index 996dcdcb91a..cd57de371dd 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStep.java @@ -19,6 +19,7 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthContext; import org.hyperledger.besu.ethereum.eth.sync.tasks.GetReceiptsForHeadersTask; diff --git a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStep.java b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStep.java index e2559b3c17c..5179bd788cb 100644 --- a/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStep.java +++ b/ethereum/eth/src/main/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStep.java @@ -16,6 +16,7 @@ import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy; import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java index 7cf995155b4..8740413e312 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/DownloadReceiptsStepTest.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.eth.manager.EthProtocolManager; diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStepTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStepTest.java index f5cc2bf5336..c054aaf3e4a 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStepTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/fastsync/FastImportBlocksStepTest.java @@ -28,6 +28,7 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockImporter; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.eth.sync.ValidationPolicy; import org.hyperledger.besu.ethereum.eth.sync.tasks.exceptions.InvalidBlockException; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; From b87cc5cbfba0105c2d51c07c7a2eedccb186a1cb Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 19 Sep 2019 00:05:17 +0300 Subject: [PATCH 06/40] thread logs with metadata through `DefaultBlockchain` into the `BlockAddedEvent`s Signed-off-by: Ratan Rai Sur --- .../logs/LogsSubscriptionServiceTest.java | 1 - .../besu/ethereum/chain/BlockAddedEvent.java | 52 ++++++++++++++----- .../ethereum/chain/DefaultBlockchain.java | 51 +++++++++++++++--- .../besu/ethereum/core/BlockWithReceipts.java | 24 +++++++++ 4 files changed, 105 insertions(+), 23 deletions(-) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index c43e0f31cc3..85fa8f00560 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -380,5 +380,4 @@ private void registerSubscriptions(final List subscriptions) { when(subscriptionManager.subscriptionsOfType(any(), any())) .thenReturn(Lists.newArrayList(subscriptions)); } - } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java index c1779a041c2..5237c9303eb 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java @@ -27,14 +27,8 @@ public class BlockAddedEvent { private final List addedTransactions; private final List removedTransactions; private final EventType eventType; - - public List getRemovedLogsWithMetadata() { - return null; - } - - public List getAddedLogsWithMetadata() { - return null; - } + private List addedLogsWithMetadata; + private List removedLogsWithMetadata; public enum EventType { HEAD_ADVANCED, @@ -46,29 +40,51 @@ private BlockAddedEvent( final EventType eventType, final Block block, final List addedTransactions, - final List removedTransactions) { + final List removedTransactions, + final List addedLogsWithMetadata, + final List removedLogsWithMetadata) { this.eventType = eventType; this.block = block; this.addedTransactions = addedTransactions; this.removedTransactions = removedTransactions; + this.addedLogsWithMetadata = addedLogsWithMetadata; + this.removedLogsWithMetadata = removedLogsWithMetadata; } - public static BlockAddedEvent createForHeadAdvancement(final Block block) { + public static BlockAddedEvent createForHeadAdvancement( + final Block block, final List addedLogsWithMetadata) { return new BlockAddedEvent( - EventType.HEAD_ADVANCED, block, block.getBody().getTransactions(), Collections.emptyList()); + EventType.HEAD_ADVANCED, + block, + block.getBody().getTransactions(), + Collections.emptyList(), + addedLogsWithMetadata, + Collections.emptyList()); } public static BlockAddedEvent createForChainReorg( final Block block, final List addedTransactions, - final List removedTransactions) { + final List removedTransactions, + final List addedLogsWithMetadata, + final List removedLogsWithMetadata) { return new BlockAddedEvent( - EventType.CHAIN_REORG, block, addedTransactions, removedTransactions); + EventType.CHAIN_REORG, + block, + addedTransactions, + removedTransactions, + addedLogsWithMetadata, + removedLogsWithMetadata); } public static BlockAddedEvent createForFork(final Block block) { return new BlockAddedEvent( - EventType.FORK, block, Collections.emptyList(), Collections.emptyList()); + EventType.FORK, + block, + Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList(), + Collections.emptyList()); } public Block getBlock() { @@ -90,4 +106,12 @@ public List getAddedTransactions() { public List getRemovedTransactions() { return removedTransactions; } + + public List getAddedLogsWithMetadata() { + return addedLogsWithMetadata; + } + + public List getRemovedLogsWithMetadata() { + return removedLogsWithMetadata; + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 4cd64d9f723..3d398e7e79d 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -22,7 +22,9 @@ import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockBody; import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.metrics.BesuMetricCategory; @@ -34,6 +36,7 @@ import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -227,12 +230,14 @@ public synchronized void appendBlock(final Block block, final List receipts) { + private BlockAddedEvent appendBlockHelper(final BlockWithReceipts blockWithReceipts) { + final var block = blockWithReceipts.getBlock(); + final var receipts = blockWithReceipts.getReceipts(); final Hash hash = block.getHash(); final UInt256 td = calculateTotalDifficulty(block); @@ -244,7 +249,8 @@ private BlockAddedEvent appendBlockHelper( updater.putTotalDifficulty(hash, td); // Update canonical chain data - final BlockAddedEvent blockAddedEvent = updateCanonicalChainData(updater, block, td); + final BlockAddedEvent blockAddedEvent = + updateCanonicalChainData(updater, blockWithReceipts, td); updater.commit(); if (blockAddedEvent.isNewCanonicalHead()) { @@ -269,8 +275,9 @@ private UInt256 calculateTotalDifficulty(final Block block) { private BlockAddedEvent updateCanonicalChainData( final BlockchainStorage.Updater updater, - final Block newBlock, + final BlockWithReceipts blockWithReceipts, final UInt256 totalDifficulty) { + final var newBlock = blockWithReceipts.getBlock(); final Hash chainHead = blockchainStorage.getChainHead().orElse(null); if (newBlock.getHeader().getNumber() != BlockHeader.GENESIS_BLOCK_NUMBER && chainHead == null) { throw new IllegalStateException("Blockchain is missing chain head."); @@ -283,7 +290,8 @@ private BlockAddedEvent updateCanonicalChainData( updater.putBlockHash(newBlock.getHeader().getNumber(), newBlockHash); updater.setChainHead(newBlockHash); indexTransactionForBlock(updater, newBlockHash, newBlock.getBody().getTransactions()); - return BlockAddedEvent.createForHeadAdvancement(newBlock); + return BlockAddedEvent.createForHeadAdvancement( + newBlock, blockWithReceipts.getLogsWithMetadata(false)); } else if (totalDifficulty.compareTo(blockchainStorage.getTotalDifficulty(chainHead).get()) > 0) { // New block represents a chain reorganization @@ -325,9 +333,11 @@ private BlockAddedEvent handleChainReorg( // Update chain head updater.setChainHead(newChain.getHash()); - // Track transactions to be added and removed + // Track transactions and logs to be added and removed final Map> newTransactions = new HashMap<>(); final List removedTransactions = new ArrayList<>(); + final List addedLogsWithMetadata = new ArrayList<>(); + final List removedLogsWithMetadata = new ArrayList<>(); while (newChain.getNumber() > oldChain.getNumber()) { // If new chain is longer than old chain, walk back until we meet the old chain by number @@ -339,6 +349,7 @@ private BlockAddedEvent handleChainReorg( ? newChainHead.getBody().getTransactions() : blockchainStorage.getBlockBody(blockHash).get().getTransactions(); newTransactions.put(blockHash, newTxs); + addAddedLogsWithMetadata(addedLogsWithMetadata, newChain); newChain = blockchainStorage.getBlockHeader(newChain.getParentHash()).get(); } @@ -349,6 +360,7 @@ private BlockAddedEvent handleChainReorg( updater.removeBlockHash(oldChain.getNumber()); removedTransactions.addAll( blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); + addRemovedLogsWithMetadata(removedLogsWithMetadata, oldChain); oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); } @@ -364,6 +376,8 @@ private BlockAddedEvent handleChainReorg( ? newChainHead.getBody().getTransactions() : blockchainStorage.getBlockBody(newBlockHash).get().getTransactions(); newTransactions.put(newBlockHash, newTxs); + addAddedLogsWithMetadata(addedLogsWithMetadata, newChain); + addRemovedLogsWithMetadata(removedLogsWithMetadata, oldChain); removedTransactions.addAll( blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); @@ -392,7 +406,9 @@ private BlockAddedEvent handleChainReorg( return BlockAddedEvent.createForChainReorg( newChainHead, newTransactions.values().stream().flatMap(Collection::stream).collect(toList()), - removedTransactions); + removedTransactions, + addedLogsWithMetadata, + removedLogsWithMetadata); } @Override @@ -494,6 +510,25 @@ private boolean blockIsConnected(final Block block) { return blockchainStorage.getBlockHeader(block.getHeader().getParentHash()).isPresent(); } + private void addAddedLogsWithMetadata( + final List logsWithMetadata, final BlockHeader blockHeader) { + logsWithMetadata.addAll(getBlockWithReceipts(blockHeader).getLogsWithMetadata(false)); + } + + private void addRemovedLogsWithMetadata( + final List logsWithMetadata, final BlockHeader blockHeader) { + // the logs have to be reverse chronological so reverse them before adding to the collection + final var logs = getBlockWithReceipts(blockHeader).getLogsWithMetadata(true); + Collections.reverse(logs); + logsWithMetadata.addAll(logs); + } + + private BlockWithReceipts getBlockWithReceipts(final BlockHeader blockHeader) { + return new BlockWithReceipts( + new Block(blockHeader, blockchainStorage.getBlockBody(blockHeader.getHash()).get()), + blockchainStorage.getTransactionReceipts(blockHeader.getHash()).get()); + } + @Override public long observeBlockAdded(final BlockAddedObserver observer) { checkNotNull(observer); diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java index ae642b065ad..4910cd68425 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.ethereum.core; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -72,4 +73,27 @@ public String toString() { .add("receipts", receipts) .toString(); } + + public List getLogsWithMetadata(final boolean removed) { + final var logsWithMetadata = new ArrayList(); + final var block = getBlock(); + for (int txi = 0; txi < receipts.size(); ++txi) { + final var currentReceipt = receipts.get(txi); + for (int li = 0; li < currentReceipt.getLogs().size(); ++li) { + final var currentLog = currentReceipt.getLogs().get(li); + logsWithMetadata.add( + new LogWithMetadata( + li, + block.getHeader().getNumber(), + block.getHash(), + block.getBody().getTransactions().get(txi).hash(), + txi, + currentLog.getLogger(), + currentLog.getData(), + currentLog.getTopics(), + removed)); + } + } + return logsWithMetadata; + } } From a561e25fbf742de8f3de84e98a35ce96c12ecc26 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Tue, 1 Oct 2019 16:00:54 +0300 Subject: [PATCH 07/40] reorder Signed-off-by: Ratan Rai Sur --- .../hyperledger/besu/ethereum/chain/DefaultBlockchain.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 3d398e7e79d..4cb1ce2e18f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -376,10 +376,10 @@ private BlockAddedEvent handleChainReorg( ? newChainHead.getBody().getTransactions() : blockchainStorage.getBlockBody(newBlockHash).get().getTransactions(); newTransactions.put(newBlockHash, newTxs); - addAddedLogsWithMetadata(addedLogsWithMetadata, newChain); - addRemovedLogsWithMetadata(removedLogsWithMetadata, oldChain); removedTransactions.addAll( blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); + addAddedLogsWithMetadata(addedLogsWithMetadata, newChain); + addRemovedLogsWithMetadata(removedLogsWithMetadata, oldChain); newChain = blockchainStorage.getBlockHeader(newChain.getParentHash()).get(); oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); From 8639ed403bfc6d5f186b86fc2a1b6833ce0a3aac Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Tue, 1 Oct 2019 16:48:56 +0300 Subject: [PATCH 08/40] make tests compile Signed-off-by: Ratan Rai Sur --- .../ibft/blockcreation/IbftMiningCoordinatorTest.java | 4 +++- .../internal/filter/FilterManagerLogFilterTest.java | 6 +++++- .../api/jsonrpc/internal/filter/FilterManagerTest.java | 4 +++- .../NewBlockHeadersSubscriptionServiceTest.java | 3 ++- .../blockcreation/AbstractMiningCoordinatorTest.java | 9 ++++++--- .../besu/ethereum/eth/sync/TrailingPeerLimiterTest.java | 7 +++++-- 6 files changed, 24 insertions(+), 9 deletions(-) diff --git a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java index 32f04c03c74..06f85037180 100644 --- a/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java +++ b/consensus/ibft/src/test/java/org/hyperledger/besu/consensus/ibft/blockcreation/IbftMiningCoordinatorTest.java @@ -29,6 +29,7 @@ import org.hyperledger.besu.ethereum.core.Wei; import org.hyperledger.besu.util.bytes.BytesValue; +import java.util.Collections; import java.util.concurrent.TimeUnit; import org.assertj.core.util.Lists; @@ -85,7 +86,8 @@ public void setsTheExtraData() { @Test public void addsNewChainHeadEventWhenNewCanonicalHeadBlockEventReceived() throws Exception { - BlockAddedEvent headAdvancement = BlockAddedEvent.createForHeadAdvancement(block); + BlockAddedEvent headAdvancement = + BlockAddedEvent.createForHeadAdvancement(block, Collections.emptyList()); ibftMiningCoordinator.onBlockAdded(headAdvancement, blockChain); assertThat(eventQueue.size()).isEqualTo(1); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java index ee59ea15104..b50486d5ed5 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java @@ -33,6 +33,7 @@ import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Address; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; @@ -145,8 +146,11 @@ public void shouldClearLogsAfterGettingLogChanges() { } private void recordNewBlockEvent() { + final var gen = new BlockDataGenerator(); + final var block = gen.block(); filterManager.recordBlockEvent( - BlockAddedEvent.createForHeadAdvancement(new BlockDataGenerator().block()), + BlockAddedEvent.createForHeadAdvancement( + block, new BlockWithReceipts(block, gen.receipts(block)).getLogsWithMetadata(false)), blockchainQueries.getBlockchain()); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java index 500abbe188e..31e12ee6fda 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerTest.java @@ -31,6 +31,7 @@ import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import java.util.Collections; import java.util.List; import java.util.Optional; @@ -232,7 +233,8 @@ private Hash appendBlockToBlockchain() { new BlockDataGenerator.BlockOptions().setBlockNumber(blockNumber).setParentHash(parentHash); currentBlock = blockGenerator.block(options); filterManager.recordBlockEvent( - BlockAddedEvent.createForHeadAdvancement(currentBlock), blockchainQueries.getBlockchain()); + BlockAddedEvent.createForHeadAdvancement(currentBlock, Collections.emptyList()), + blockchainQueries.getBlockchain()); return currentBlock.getHash(); } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java index dde8e560b58..681b8b50cfd 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/blockheaders/NewBlockHeadersSubscriptionServiceTest.java @@ -174,7 +174,8 @@ private void simulateAddingBlockOnCanonicalChain() { final BlockBody blockBody = new BlockBody(Collections.emptyList(), Collections.emptyList()); final Block testBlock = new Block(blockHeader, blockBody); newBlockHeadersSubscriptionService.onBlockAdded( - BlockAddedEvent.createForHeadAdvancement(testBlock), blockchainQueries.getBlockchain()); + BlockAddedEvent.createForHeadAdvancement(testBlock, Collections.emptyList()), + blockchainQueries.getBlockchain()); verify(blockchainQueries, times(1)).getBlockchain(); } diff --git a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java index ac558966abf..a5cce67ec44 100644 --- a/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java +++ b/ethereum/blockcreation/src/test/java/org/hyperledger/besu/ethereum/blockcreation/AbstractMiningCoordinatorTest.java @@ -96,7 +96,8 @@ public void shouldNotStartWhenBlockAddedAndOutOfSync() { when(syncState.isInSync()).thenReturn(false); miningCoordinator.enable(); - miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); verifyNoMoreInteractions(minerExecutor, blockMiner); } @@ -106,7 +107,8 @@ public void shouldRestartMiningWhenBlockAddedAndInSync() { when(syncState.isInSync()).thenReturn(true); miningCoordinator.enable(); - miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); verify(blockMiner).cancel(); verify(minerExecutor, times(2)).startAsyncMining(any(), any()); @@ -124,7 +126,8 @@ public void shouldNotStartMiningWhenBecomingInSyncIfMinerNotEnabled() { @Test public void shouldNotStartMiningWhenBlockAddedAndInSyncIfMinerNotEnabled() { when(syncState.isInSync()).thenReturn(true); - miningCoordinator.onBlockAdded(BlockAddedEvent.createForHeadAdvancement(BLOCK), blockchain); + miningCoordinator.onBlockAdded( + BlockAddedEvent.createForHeadAdvancement(BLOCK, Collections.emptyList()), blockchain); verifyNoMoreInteractions(minerExecutor, blockMiner); } diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java index 9ec9369b8bc..ddd136c2f70 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/TrailingPeerLimiterTest.java @@ -35,6 +35,7 @@ import org.hyperledger.besu.util.uint.UInt256; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.junit.Before; @@ -116,7 +117,8 @@ public void shouldRecheckTrailingPeersWhenBlockAddedThatIsMultipleOf100() { BlockAddedEvent.createForHeadAdvancement( new Block( new BlockHeaderTestFixture().number(500).buildHeader(), - new BlockBody(emptyList(), emptyList()))); + new BlockBody(emptyList(), emptyList())), + Collections.emptyList()); trailingPeerLimiter.onBlockAdded(blockAddedEvent, blockchain); assertDisconnections(ethPeer1); @@ -132,7 +134,8 @@ public void shouldNotRecheckTrailingPeersWhenBlockAddedIsNotAMultipleOf100() { BlockAddedEvent.createForHeadAdvancement( new Block( new BlockHeaderTestFixture().number(599).buildHeader(), - new BlockBody(emptyList(), emptyList()))); + new BlockBody(emptyList(), emptyList())), + Collections.emptyList()); trailingPeerLimiter.onBlockAdded(blockAddedEvent, blockchain); assertDisconnections(); From 8293dc250e3016f2e5aff4adb1b4bd55ebc364f1 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Tue, 1 Oct 2019 23:27:06 +0300 Subject: [PATCH 09/40] wip: wire `LogSubscriptionService to use new event Signed-off-by: Ratan Rai Sur --- .../org/hyperledger/besu/RunnerBuilder.java | 10 +- .../internal/pojoadapter/LogAdapter.java | 2 +- .../jsonrpc/internal/results/LogResult.java | 2 +- .../logs/LogsSubscriptionService.java | 91 ++++--------------- .../logs/LogsSubscriptionServiceTest.java | 7 +- .../besu/ethereum/core/LogWithMetadata.java | 8 +- 6 files changed, 29 insertions(+), 91 deletions(-) diff --git a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java index 5c4455a1f00..94fac0a9911 100644 --- a/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java +++ b/besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java @@ -453,8 +453,7 @@ public Runner build() { final SubscriptionManager subscriptionManager = createSubscriptionManager(vertx, transactionPool); - createLogsSubscriptionService( - context.getBlockchain(), context.getWorldStateArchive(), subscriptionManager); + createLogsSubscriptionService(context.getBlockchain(), subscriptionManager); createNewBlockHeadersSubscriptionService( context.getBlockchain(), context.getWorldStateArchive(), subscriptionManager); @@ -621,12 +620,9 @@ private SubscriptionManager createSubscriptionManager( } private void createLogsSubscriptionService( - final Blockchain blockchain, - final WorldStateArchive worldStateArchive, - final SubscriptionManager subscriptionManager) { + final Blockchain blockchain, final SubscriptionManager subscriptionManager) { final LogsSubscriptionService logsSubscriptionService = - new LogsSubscriptionService( - subscriptionManager, new BlockchainQueries(blockchain, worldStateArchive)); + new LogsSubscriptionService(subscriptionManager); blockchain.observeBlockAdded(logsSubscriptionService); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java index 697d6b6e718..f160dc2f129 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/LogAdapter.java @@ -70,6 +70,6 @@ public Optional getAccount(final DataFetchingEnvironment environ return query .getWorldState(blockNumber) - .map(ws -> new AccountAdapter(ws.get(logWithMetadata.getAddress()))); + .map(ws -> new AccountAdapter(ws.get(logWithMetadata.getLogger()))); } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java index 29d6d2802ec..e252211bd55 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/LogResult.java @@ -53,7 +53,7 @@ public LogResult(final LogWithMetadata logWithMetadata) { this.blockHash = logWithMetadata.getBlockHash().toString(); this.transactionHash = logWithMetadata.getTransactionHash().toString(); this.transactionIndex = Quantity.create(logWithMetadata.getTransactionIndex()); - this.address = logWithMetadata.getAddress().toString(); + this.address = logWithMetadata.getLogger().toString(); this.data = logWithMetadata.getData().toString(); this.topics = new ArrayList<>(logWithMetadata.getTopics().size()); this.removed = logWithMetadata.isRemoved(); diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java index 84d868c9f83..c0ac84f3e2a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java @@ -22,92 +22,35 @@ import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.Blockchain; -import org.hyperledger.besu.ethereum.core.Log; -import org.hyperledger.besu.ethereum.core.LogWithMetadata; -import java.util.List; -import java.util.Optional; +import java.util.stream.Stream; public class LogsSubscriptionService implements BlockAddedObserver { private final SubscriptionManager subscriptionManager; - private final BlockchainQueries blockchainQueries; - public LogsSubscriptionService( - final SubscriptionManager subscriptionManager, final BlockchainQueries blockchainQueries) { + public LogsSubscriptionService(final SubscriptionManager subscriptionManager) { this.subscriptionManager = subscriptionManager; - this.blockchainQueries = blockchainQueries; } @Override - public void onBlockAdded(final BlockAddedEvent event, final Blockchain blockchain) { - final List logsSubscriptions = + public void onBlockAdded(final BlockAddedEvent event, final Blockchain __) { + final var logsSubscriptions = subscriptionManager.subscriptionsOfType(SubscriptionType.LOGS, LogsSubscription.class); - if (logsSubscriptions.isEmpty()) { - return; - } - - event.getAddedTransactions().stream() - .map(tx -> blockchainQueries.transactionReceiptByTransactionHash(tx.getHash())) - .filter(Optional::isPresent) - .map(Optional::get) - .forEachOrdered( - receiptWithMetadata -> { - final List logs = receiptWithMetadata.getReceipt().getLogs(); - sendLogsToMatchingSubscriptions(logs, logsSubscriptions, receiptWithMetadata, false); - }); - - event.getRemovedTransactions().stream() - .map(tx -> blockchainQueries.transactionReceiptByTransactionHash(tx.getHash())) - .filter(Optional::isPresent) - .map(Optional::get) + // Get removed and added logs, with removed always first + Stream.concat( + event.getRemovedLogsWithMetadata().stream(), event.getAddedLogsWithMetadata().stream()) .forEachOrdered( - receiptWithMetadata -> { - final List logs = receiptWithMetadata.getReceipt().getLogs(); - sendLogsToMatchingSubscriptions(logs, logsSubscriptions, receiptWithMetadata, true); - }); - } - - private void sendLogsToMatchingSubscriptions( - final List logs, - final List logsSubscriptions, - final TransactionReceiptWithMetadata receiptWithMetadata, - final boolean removed) { - for (int logIndex = 0; logIndex < logs.size(); logIndex++) { - for (final LogsSubscription subscription : logsSubscriptions) { - if (subscription.getLogsQuery().matches(logs.get(logIndex))) { - sendLogToSubscription(receiptWithMetadata, removed, logIndex, subscription); - } - } - } - } - - private void sendLogToSubscription( - final TransactionReceiptWithMetadata receiptWithMetadata, - final boolean removed, - final int logIndex, - final LogsSubscription subscription) { - final LogWithMetadata logWithMetaData = logWithMetadata(logIndex, receiptWithMetadata, removed); - subscriptionManager.sendMessage( - subscription.getSubscriptionId(), new LogResult(logWithMetaData)); - } - - // @formatter:off - private LogWithMetadata logWithMetadata( - final int logIndex, - final TransactionReceiptWithMetadata transactionReceiptWithMetadata, - final boolean removed) { - return new LogWithMetadata( - logIndex, - transactionReceiptWithMetadata.getBlockNumber(), - transactionReceiptWithMetadata.getBlockHash(), - transactionReceiptWithMetadata.getTransactionHash(), - transactionReceiptWithMetadata.getTransactionIndex(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(logIndex).getLogger(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(logIndex).getData(), - transactionReceiptWithMetadata.getReceipt().getLogs().get(logIndex).getTopics(), - removed); + logWithMetadata -> + logsSubscriptions.stream() + .filter( + logsSubscription -> + logsSubscription.getLogsQuery().matches(logWithMetadata)) + .forEach( + logsSubscription -> + subscriptionManager.sendMessage( + logsSubscription.getSubscriptionId(), + new LogResult(logWithMetadata)))); } - // @formatter:on } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index 85fa8f00560..f1dad780068 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -39,7 +39,6 @@ import org.hyperledger.besu.ethereum.core.LogTopic; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; -import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive; import java.util.ArrayList; import java.util.Arrays; @@ -62,12 +61,8 @@ public class LogsSubscriptionServiceTest { private final BlockDataGenerator gen = new BlockDataGenerator(1); - private final WorldStateArchive worldStateArchive = - InMemoryStorageProvider.createInMemoryWorldStateArchive(); private final MutableBlockchain blockchain = InMemoryStorageProvider.createInMemoryBlockchain(gen.genesisBlock()); - private BlockchainQueries blockchainQueries = - new BlockchainQueries(blockchain, worldStateArchive); private LogsSubscriptionService logsSubscriptionService; private final AtomicLong nextSubscriptionId = new AtomicLong(); @@ -76,7 +71,7 @@ public class LogsSubscriptionServiceTest { @Before public void before() { - logsSubscriptionService = new LogsSubscriptionService(subscriptionManager, blockchainQueries); + logsSubscriptionService = new LogsSubscriptionService(subscriptionManager); blockchain.observeBlockAdded(logsSubscriptionService); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index 75caac0fbd7..520fe0f2cc1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -22,7 +22,7 @@ import com.google.common.base.MoreObjects; -public class LogWithMetadata { +public class LogWithMetadata extends Log { private final int logIndex; private final long blockNumber; @@ -44,6 +44,7 @@ public LogWithMetadata( final BytesValue data, final List topics, final boolean removed) { + super(address, data, topics); this.logIndex = logIndex; this.blockNumber = blockNumber; this.blockHash = blockHash; @@ -77,14 +78,17 @@ public int getTransactionIndex() { return transactionIndex; } - public Address getAddress() { + @Override + public Address getLogger() { return address; } + @Override public BytesValue getData() { return data; } + @Override public List getTopics() { return topics; } From 57ad75aed0e446beca087a2b448e9f8a0f204d3e Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 2 Oct 2019 01:11:19 +0300 Subject: [PATCH 10/40] cont: thread BlockWithReceipts further into call stack because new chain blocks are not persisted Signed-off-by: Ratan Rai Sur --- .../ethereum/chain/DefaultBlockchain.java | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 4cb1ce2e18f..fac9a5fda39 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -295,7 +295,7 @@ private BlockAddedEvent updateCanonicalChainData( } else if (totalDifficulty.compareTo(blockchainStorage.getTotalDifficulty(chainHead).get()) > 0) { // New block represents a chain reorganization - return handleChainReorg(updater, newBlock); + return handleChainReorg(updater, blockWithReceipts); } else { // New block represents a fork return handleFork(updater, newBlock); @@ -325,10 +325,11 @@ private BlockAddedEvent handleFork(final BlockchainStorage.Updater updater, fina } private BlockAddedEvent handleChainReorg( - final BlockchainStorage.Updater updater, final Block newChainHead) { + final BlockchainStorage.Updater updater, final BlockWithReceipts newChainHeadWithReceipts) { + final Block newChainHead = newChainHeadWithReceipts.getBlock(); final Hash oldChainHead = blockchainStorage.getChainHead().get(); BlockHeader oldChain = blockchainStorage.getBlockHeader(oldChainHead).get(); - BlockHeader newChain = newChainHead.getHeader(); + BlockHeader newChain = newChainHeadWithReceipts.getHeader(); // Update chain head updater.setChainHead(newChain.getHash()); @@ -345,11 +346,11 @@ private BlockAddedEvent handleChainReorg( final Hash blockHash = newChain.getHash(); updater.putBlockHash(newChain.getNumber(), blockHash); final List newTxs = - blockHash.equals(newChainHead.getHash()) + blockHash.equals(newChainHeadWithReceipts.getHash()) ? newChainHead.getBody().getTransactions() : blockchainStorage.getBlockBody(blockHash).get().getTransactions(); newTransactions.put(blockHash, newTxs); - addAddedLogsWithMetadata(addedLogsWithMetadata, newChain); + addAddedLogsWithMetadata(addedLogsWithMetadata, newChainHeadWithReceipts); newChain = blockchainStorage.getBlockHeader(newChain.getParentHash()).get(); } @@ -360,7 +361,7 @@ private BlockAddedEvent handleChainReorg( updater.removeBlockHash(oldChain.getNumber()); removedTransactions.addAll( blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); - addRemovedLogsWithMetadata(removedLogsWithMetadata, oldChain); + addRemovedLogsWithMetadata(removedLogsWithMetadata, getBlockWithReceipts(oldChain).get()); oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); } @@ -372,14 +373,14 @@ private BlockAddedEvent handleChainReorg( // Collect transaction to be updated final List newTxs = - newBlockHash.equals(newChainHead.getHash()) + newBlockHash.equals(newChainHeadWithReceipts.getHash()) ? newChainHead.getBody().getTransactions() : blockchainStorage.getBlockBody(newBlockHash).get().getTransactions(); newTransactions.put(newBlockHash, newTxs); removedTransactions.addAll( blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); - addAddedLogsWithMetadata(addedLogsWithMetadata, newChain); - addRemovedLogsWithMetadata(removedLogsWithMetadata, oldChain); + addAddedLogsWithMetadata(addedLogsWithMetadata, newChainHeadWithReceipts); + addRemovedLogsWithMetadata(removedLogsWithMetadata, getBlockWithReceipts(oldChain).get()); newChain = blockchainStorage.getBlockHeader(newChain.getParentHash()).get(); oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); @@ -400,7 +401,9 @@ private BlockAddedEvent handleChainReorg( forks.add(oldChainHead); // Remove new chain head's parent if it was tracked as a fork final Optional parentFork = - forks.stream().filter(f -> f.equals(newChainHead.getHeader().getParentHash())).findAny(); + forks.stream() + .filter(f -> f.equals(newChainHeadWithReceipts.getHeader().getParentHash())) + .findAny(); parentFork.ifPresent(forks::remove); updater.setForkHeads(forks); return BlockAddedEvent.createForChainReorg( @@ -420,12 +423,11 @@ public boolean rewindToBlock(final long blockNumber) { final BlockchainStorage.Updater updater = blockchainStorage.updater(); try { - final Optional oldBlockHeader = - blockchainStorage.getBlockHeader(blockHash.get()); - final Optional oldBlockBody = blockchainStorage.getBlockBody(blockHash.get()); - final Block block = new Block(oldBlockHeader.get(), oldBlockBody.get()); + final BlockHeader oldBlockHeader = blockchainStorage.getBlockHeader(blockHash.get()).get(); + final BlockWithReceipts blockWithReceipts = getBlockWithReceipts(oldBlockHeader).get(); + final Block block = blockWithReceipts.getBlock(); - handleChainReorg(updater, block); + handleChainReorg(updater, blockWithReceipts); updater.commit(); updateCacheForNewCanonicalHead(block, calculateTotalDifficulty(block)); @@ -511,22 +513,27 @@ private boolean blockIsConnected(final Block block) { } private void addAddedLogsWithMetadata( - final List logsWithMetadata, final BlockHeader blockHeader) { - logsWithMetadata.addAll(getBlockWithReceipts(blockHeader).getLogsWithMetadata(false)); + final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { + logsWithMetadata.addAll(blockWithReceipts.getLogsWithMetadata(false)); } private void addRemovedLogsWithMetadata( - final List logsWithMetadata, final BlockHeader blockHeader) { + final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { // the logs have to be reverse chronological so reverse them before adding to the collection - final var logs = getBlockWithReceipts(blockHeader).getLogsWithMetadata(true); + final var logs = blockWithReceipts.getLogsWithMetadata(true); Collections.reverse(logs); logsWithMetadata.addAll(logs); } - private BlockWithReceipts getBlockWithReceipts(final BlockHeader blockHeader) { - return new BlockWithReceipts( - new Block(blockHeader, blockchainStorage.getBlockBody(blockHeader.getHash()).get()), - blockchainStorage.getTransactionReceipts(blockHeader.getHash()).get()); + private Optional getBlockWithReceipts(final BlockHeader blockHeader) { + return blockchainStorage + .getBlockBody(blockHeader.getHash()) + .map(body -> new Block(blockHeader, body)) + .flatMap( + block -> + blockchainStorage + .getTransactionReceipts(blockHeader.getHash()) + .map(receipts -> new BlockWithReceipts(block, receipts))); } @Override From bd2c76b4adf8b6357e74e53a9fd2a35a20a9d7f9 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 2 Oct 2019 02:57:06 +0300 Subject: [PATCH 11/40] singleton list Signed-off-by: Ratan Rai Sur --- .../subscription/logs/LogsSubscriptionServiceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index f1dad780068..afd8cb3b8ae 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -159,7 +159,8 @@ public void singleMatchingLogEmittedThenMovedInReorg() { } // Now add another block that re-emits the target log - final BlockWithReceipts newBlockWithLog = generateBlock(1, () -> Arrays.asList(targetLog)); + final BlockWithReceipts newBlockWithLog = + generateBlock(1, () -> Collections.singletonList(targetLog)); blockchain.appendBlock(newBlockWithLog.getBlock(), newBlockWithLog.getReceipts()); // Sanity check assertThat(blockchain.getChainHeadHash()).isEqualTo(newBlockWithLog.getBlock().getHash()); From 45be5ec261759087cc9d1651d8306b200070b51c Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 2 Oct 2019 03:02:30 +0300 Subject: [PATCH 12/40] assertThat Signed-off-by: Ratan Rai Sur --- .../subscription/logs/LogsSubscriptionServiceTest.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index afd8cb3b8ae..159aa7ca54e 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -94,7 +94,7 @@ public void singleMatchingLogEvent() { final List logResults = captor.getAllValues(); - assertThat(logResults.size()).isEqualTo(1); + assertThat(logResults).hasSize(1); final LogResult result = logResults.get(0); assertLogResultMatches(result, block, receipts, txIndex, logIndex, false); } @@ -128,7 +128,7 @@ public void singleMatchingLogEmittedThenRemovedInReorg() { final List logResults = captor.getAllValues(); - assertThat(logResults.size()).isEqualTo(2); + assertThat(logResults).hasSize(2); final LogResult firstLog = logResults.get(0); assertLogResultMatches(firstLog, block, receipts, txIndex, logIndex, false); final LogResult secondLog = logResults.get(1); @@ -171,7 +171,7 @@ public void singleMatchingLogEmittedThenMovedInReorg() { final List logResults = captor.getAllValues(); - assertThat(logResults.size()).isEqualTo(3); + assertThat(logResults).hasSize(3); final LogResult originalLog = logResults.get(0); assertLogResultMatches(originalLog, block, receipts, txIndex, logIndex, false); final LogResult removedLog = logResults.get(1); @@ -209,7 +209,7 @@ public void multipleMatchingLogsEmitted() { final List logResults = captor.getAllValues(); // Verify all logs are emitted - assertThat(logResults.size()).isEqualTo(targetBlocks.size() * txCount); + assertThat(logResults).hasSize(targetBlocks.size() * txCount); for (int i = 0; i < targetBlocks.size(); i++) { final BlockWithReceipts targetBlock = targetBlocks.get(i); for (int j = 0; j < txCount; j++) { @@ -249,7 +249,7 @@ public void multipleSubscriptionsForSingleMatchingLog() { final List logResults = captor.getAllValues(); - assertThat(logResults.size()).isEqualTo(1); + assertThat(logResults).hasSize(1); final LogResult result = logResults.get(0); assertLogResultMatches(result, block, receipts, txIndex, logIndex, false); } From bc28ce10846ae6f5806a27a7106bc73e3d7498dc Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 2 Oct 2019 04:06:08 +0300 Subject: [PATCH 13/40] implement the chronological ordering of `LogWithMetadata` with `Comparable` Signed-off-by: Ratan Rai Sur --- .../besu/ethereum/chain/DefaultBlockchain.java | 10 ++++++---- .../besu/ethereum/core/LogWithMetadata.java | 11 ++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index fac9a5fda39..ec50dc05108 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -386,6 +386,11 @@ private BlockAddedEvent handleChainReorg( oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); } + // We must provide the removed logs in reverse-chronological order and the added logs in + // chronological order + Collections.sort(addedLogsWithMetadata); + Collections.sort(removedLogsWithMetadata, Collections.reverseOrder(LogWithMetadata::compareTo)); + // Update indexed transactions newTransactions.forEach( (blockHash, transactionsInBlock) -> { @@ -519,10 +524,7 @@ private void addAddedLogsWithMetadata( private void addRemovedLogsWithMetadata( final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { - // the logs have to be reverse chronological so reverse them before adding to the collection - final var logs = blockWithReceipts.getLogsWithMetadata(true); - Collections.reverse(logs); - logsWithMetadata.addAll(logs); + logsWithMetadata.addAll(blockWithReceipts.getLogsWithMetadata(true)); } private Optional getBlockWithReceipts(final BlockHeader blockHeader) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index 520fe0f2cc1..e94726c7106 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -18,11 +18,12 @@ import org.hyperledger.besu.util.bytes.BytesValue; +import java.util.Comparator; import java.util.List; import com.google.common.base.MoreObjects; -public class LogWithMetadata extends Log { +public class LogWithMetadata extends Log implements Comparable { private final int logIndex; private final long blockNumber; @@ -111,4 +112,12 @@ public String toString() { .add("removed", removed) .toString(); } + + @Override + public int compareTo(final LogWithMetadata other) { + return Comparator.comparingLong(LogWithMetadata::getBlockNumber) + .thenComparingInt(LogWithMetadata::getTransactionIndex) + .thenComparingInt(LogWithMetadata::getLogIndex) + .compare(this, other); + } } From 7d26d115da6119bd3bc4dd2d1dc6c673da793934 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 2 Oct 2019 05:14:09 +0300 Subject: [PATCH 14/40] clean up reorg Signed-off-by: Ratan Rai Sur --- .../ethereum/chain/DefaultBlockchain.java | 82 +++++++++++-------- 1 file changed, 50 insertions(+), 32 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index ec50dc05108..660d40db5a7 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -326,13 +326,13 @@ private BlockAddedEvent handleFork(final BlockchainStorage.Updater updater, fina private BlockAddedEvent handleChainReorg( final BlockchainStorage.Updater updater, final BlockWithReceipts newChainHeadWithReceipts) { - final Block newChainHead = newChainHeadWithReceipts.getBlock(); - final Hash oldChainHead = blockchainStorage.getChainHead().get(); - BlockHeader oldChain = blockchainStorage.getBlockHeader(oldChainHead).get(); - BlockHeader newChain = newChainHeadWithReceipts.getHeader(); + final Block newChainHeadBlock = newChainHeadWithReceipts.getBlock(); + final Block oldChainHeadBlock = getChainHeadBlock(); + BlockHeader currentOldChainHeader = oldChainHeadBlock.getHeader(); + BlockHeader currentNewChainHeader = newChainHeadBlock.getHeader(); // Update chain head - updater.setChainHead(newChain.getHash()); + updater.setChainHead(newChainHeadBlock.getHash()); // Track transactions and logs to be added and removed final Map> newTransactions = new HashMap<>(); @@ -340,50 +340,68 @@ private BlockAddedEvent handleChainReorg( final List addedLogsWithMetadata = new ArrayList<>(); final List removedLogsWithMetadata = new ArrayList<>(); - while (newChain.getNumber() > oldChain.getNumber()) { + while (currentNewChainHeader.getNumber() > currentOldChainHeader.getNumber()) { // If new chain is longer than old chain, walk back until we meet the old chain by number // adding indexing for new chain along the way. - final Hash blockHash = newChain.getHash(); - updater.putBlockHash(newChain.getNumber(), blockHash); + final Hash blockHash = currentNewChainHeader.getHash(); + updater.putBlockHash(currentNewChainHeader.getNumber(), blockHash); final List newTxs = - blockHash.equals(newChainHeadWithReceipts.getHash()) - ? newChainHead.getBody().getTransactions() - : blockchainStorage.getBlockBody(blockHash).get().getTransactions(); + blockchainStorage + .getBlockBody(blockHash) + .map(BlockBody::getTransactions) + // If it's not in storage, it must be the new chain head + .orElseGet(() -> newChainHeadBlock.getBody().getTransactions()); newTransactions.put(blockHash, newTxs); - addAddedLogsWithMetadata(addedLogsWithMetadata, newChainHeadWithReceipts); - newChain = blockchainStorage.getBlockHeader(newChain.getParentHash()).get(); + addAddedLogsWithMetadata( + addedLogsWithMetadata, + getBlockWithReceipts(currentNewChainHeader).orElse(newChainHeadWithReceipts)); + + currentNewChainHeader = + blockchainStorage.getBlockHeader(currentNewChainHeader.getParentHash()).get(); } - while (oldChain.getNumber() > newChain.getNumber()) { + while (currentOldChainHeader.getNumber() > currentNewChainHeader.getNumber()) { // If oldChain is longer than new chain, walk back until we meet the new chain by number, // updating as we go. - updater.removeBlockHash(oldChain.getNumber()); + updater.removeBlockHash(currentOldChainHeader.getNumber()); removedTransactions.addAll( - blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); - addRemovedLogsWithMetadata(removedLogsWithMetadata, getBlockWithReceipts(oldChain).get()); + blockchainStorage.getBlockBody(currentOldChainHeader.getHash()).get().getTransactions()); + + addRemovedLogsWithMetadata( + removedLogsWithMetadata, getBlockWithReceipts(currentOldChainHeader).get()); - oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); + currentOldChainHeader = + blockchainStorage.getBlockHeader(currentOldChainHeader.getParentHash()).get(); } - while (!oldChain.getHash().equals(newChain.getHash())) { + while (!currentOldChainHeader.getHash().equals(currentNewChainHeader.getHash())) { // Walk back until we meet the common ancestor between the two chains, updating as we go. - final Hash newBlockHash = newChain.getHash(); - updater.putBlockHash(newChain.getNumber(), newBlockHash); + final Hash newBlockHash = currentNewChainHeader.getHash(); + updater.putBlockHash(currentNewChainHeader.getNumber(), newBlockHash); // Collect transaction to be updated final List newTxs = - newBlockHash.equals(newChainHeadWithReceipts.getHash()) - ? newChainHead.getBody().getTransactions() - : blockchainStorage.getBlockBody(newBlockHash).get().getTransactions(); + blockchainStorage + .getBlockBody(newBlockHash) + .map(BlockBody::getTransactions) + // If it's not in storage, it must be the new chain head + .orElseGet(() -> newChainHeadBlock.getBody().getTransactions()); + newTransactions.put(newBlockHash, newTxs); removedTransactions.addAll( - blockchainStorage.getBlockBody(oldChain.getHash()).get().getTransactions()); - addAddedLogsWithMetadata(addedLogsWithMetadata, newChainHeadWithReceipts); - addRemovedLogsWithMetadata(removedLogsWithMetadata, getBlockWithReceipts(oldChain).get()); - - newChain = blockchainStorage.getBlockHeader(newChain.getParentHash()).get(); - oldChain = blockchainStorage.getBlockHeader(oldChain.getParentHash()).get(); + blockchainStorage.getBlockBody(currentOldChainHeader.getHash()).get().getTransactions()); + + addAddedLogsWithMetadata( + addedLogsWithMetadata, + getBlockWithReceipts(currentNewChainHeader).orElse(newChainHeadWithReceipts)); + addRemovedLogsWithMetadata( + removedLogsWithMetadata, getBlockWithReceipts(currentOldChainHeader).get()); + + currentNewChainHeader = + blockchainStorage.getBlockHeader(currentNewChainHeader.getParentHash()).get(); + currentOldChainHeader = + blockchainStorage.getBlockHeader(currentOldChainHeader.getParentHash()).get(); } // We must provide the removed logs in reverse-chronological order and the added logs in @@ -403,7 +421,7 @@ private BlockAddedEvent handleChainReorg( // Update tracked forks final Collection forks = blockchainStorage.getForkHeads(); // Old head is now a fork - forks.add(oldChainHead); + forks.add(oldChainHeadBlock.getHash()); // Remove new chain head's parent if it was tracked as a fork final Optional parentFork = forks.stream() @@ -412,7 +430,7 @@ private BlockAddedEvent handleChainReorg( parentFork.ifPresent(forks::remove); updater.setForkHeads(forks); return BlockAddedEvent.createForChainReorg( - newChainHead, + newChainHeadBlock, newTransactions.values().stream().flatMap(Collection::stream).collect(toList()), removedTransactions, addedLogsWithMetadata, From ca86acc49a0413ff450a407ee0118ca17f1561a6 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 2 Oct 2019 18:31:59 +0300 Subject: [PATCH 15/40] fix bug in test Signed-off-by: Ratan Rai Sur --- .../subscription/logs/LogsSubscriptionServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index 159aa7ca54e..d102d7d0826 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -176,7 +176,7 @@ public void singleMatchingLogEmittedThenMovedInReorg() { assertLogResultMatches(originalLog, block, receipts, txIndex, logIndex, false); final LogResult removedLog = logResults.get(1); assertLogResultMatches(removedLog, block, receipts, txIndex, logIndex, true); - final LogResult updatedLog = logResults.get(1); + final LogResult updatedLog = logResults.get(2); assertLogResultMatches( updatedLog, newBlockWithLog.getBlock(), newBlockWithLog.getReceipts(), 0, 0, false); } From ad6d114642b8027be8bb2b36b34118ec8eddec0d Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 13:35:26 +0100 Subject: [PATCH 16/40] remove unnecessary separation between (added|removed)LogsWithMetadata Signed-off-by: Ratan Rai Sur --- .../logs/LogsSubscriptionService.java | 9 ++--- .../besu/ethereum/chain/BlockAddedEvent.java | 33 +++++-------------- .../ethereum/chain/DefaultBlockchain.java | 19 +++++------ .../besu/ethereum/core/LogWithMetadata.java | 18 +++++++--- 4 files changed, 34 insertions(+), 45 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java index c0ac84f3e2a..d95779ccac7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java @@ -23,8 +23,6 @@ import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.Blockchain; -import java.util.stream.Stream; - public class LogsSubscriptionService implements BlockAddedObserver { private final SubscriptionManager subscriptionManager; @@ -38,10 +36,9 @@ public void onBlockAdded(final BlockAddedEvent event, final Blockchain __) { final var logsSubscriptions = subscriptionManager.subscriptionsOfType(SubscriptionType.LOGS, LogsSubscription.class); - // Get removed and added logs, with removed always first - Stream.concat( - event.getRemovedLogsWithMetadata().stream(), event.getAddedLogsWithMetadata().stream()) - .forEachOrdered( + event + .getLogsWithMetadata() + .forEach( logWithMetadata -> logsSubscriptions.stream() .filter( diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java index 5237c9303eb..9a4573452c3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/BlockAddedEvent.java @@ -27,8 +27,7 @@ public class BlockAddedEvent { private final List addedTransactions; private final List removedTransactions; private final EventType eventType; - private List addedLogsWithMetadata; - private List removedLogsWithMetadata; + private List logsWithMetadata; public enum EventType { HEAD_ADVANCED, @@ -41,40 +40,31 @@ private BlockAddedEvent( final Block block, final List addedTransactions, final List removedTransactions, - final List addedLogsWithMetadata, - final List removedLogsWithMetadata) { + final List logsWithMetadata) { this.eventType = eventType; this.block = block; this.addedTransactions = addedTransactions; this.removedTransactions = removedTransactions; - this.addedLogsWithMetadata = addedLogsWithMetadata; - this.removedLogsWithMetadata = removedLogsWithMetadata; + this.logsWithMetadata = logsWithMetadata; } public static BlockAddedEvent createForHeadAdvancement( - final Block block, final List addedLogsWithMetadata) { + final Block block, final List logsWithMetadata) { return new BlockAddedEvent( EventType.HEAD_ADVANCED, block, block.getBody().getTransactions(), Collections.emptyList(), - addedLogsWithMetadata, - Collections.emptyList()); + logsWithMetadata); } public static BlockAddedEvent createForChainReorg( final Block block, final List addedTransactions, final List removedTransactions, - final List addedLogsWithMetadata, - final List removedLogsWithMetadata) { + final List logsWithMetadata) { return new BlockAddedEvent( - EventType.CHAIN_REORG, - block, - addedTransactions, - removedTransactions, - addedLogsWithMetadata, - removedLogsWithMetadata); + EventType.CHAIN_REORG, block, addedTransactions, removedTransactions, logsWithMetadata); } public static BlockAddedEvent createForFork(final Block block) { @@ -83,7 +73,6 @@ public static BlockAddedEvent createForFork(final Block block) { block, Collections.emptyList(), Collections.emptyList(), - Collections.emptyList(), Collections.emptyList()); } @@ -107,11 +96,7 @@ public List getRemovedTransactions() { return removedTransactions; } - public List getAddedLogsWithMetadata() { - return addedLogsWithMetadata; - } - - public List getRemovedLogsWithMetadata() { - return removedLogsWithMetadata; + public List getLogsWithMetadata() { + return logsWithMetadata; } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 660d40db5a7..5752191c324 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -337,8 +337,7 @@ private BlockAddedEvent handleChainReorg( // Track transactions and logs to be added and removed final Map> newTransactions = new HashMap<>(); final List removedTransactions = new ArrayList<>(); - final List addedLogsWithMetadata = new ArrayList<>(); - final List removedLogsWithMetadata = new ArrayList<>(); + final List logsWithMetadata = new ArrayList<>(); while (currentNewChainHeader.getNumber() > currentOldChainHeader.getNumber()) { // If new chain is longer than old chain, walk back until we meet the old chain by number @@ -354,7 +353,7 @@ private BlockAddedEvent handleChainReorg( newTransactions.put(blockHash, newTxs); addAddedLogsWithMetadata( - addedLogsWithMetadata, + logsWithMetadata, getBlockWithReceipts(currentNewChainHeader).orElse(newChainHeadWithReceipts)); currentNewChainHeader = @@ -369,7 +368,7 @@ private BlockAddedEvent handleChainReorg( blockchainStorage.getBlockBody(currentOldChainHeader.getHash()).get().getTransactions()); addRemovedLogsWithMetadata( - removedLogsWithMetadata, getBlockWithReceipts(currentOldChainHeader).get()); + logsWithMetadata, getBlockWithReceipts(currentOldChainHeader).get()); currentOldChainHeader = blockchainStorage.getBlockHeader(currentOldChainHeader.getParentHash()).get(); @@ -393,10 +392,10 @@ private BlockAddedEvent handleChainReorg( blockchainStorage.getBlockBody(currentOldChainHeader.getHash()).get().getTransactions()); addAddedLogsWithMetadata( - addedLogsWithMetadata, + logsWithMetadata, getBlockWithReceipts(currentNewChainHeader).orElse(newChainHeadWithReceipts)); addRemovedLogsWithMetadata( - removedLogsWithMetadata, getBlockWithReceipts(currentOldChainHeader).get()); + logsWithMetadata, getBlockWithReceipts(currentOldChainHeader).get()); currentNewChainHeader = blockchainStorage.getBlockHeader(currentNewChainHeader.getParentHash()).get(); @@ -404,10 +403,9 @@ private BlockAddedEvent handleChainReorg( blockchainStorage.getBlockHeader(currentOldChainHeader.getParentHash()).get(); } - // We must provide the removed logs in reverse-chronological order and the added logs in + // Sorts logs with removed logs in reverse-chronological order and the added logs in // chronological order - Collections.sort(addedLogsWithMetadata); - Collections.sort(removedLogsWithMetadata, Collections.reverseOrder(LogWithMetadata::compareTo)); + Collections.sort(logsWithMetadata); // Update indexed transactions newTransactions.forEach( @@ -433,8 +431,7 @@ private BlockAddedEvent handleChainReorg( newChainHeadBlock, newTransactions.values().stream().flatMap(Collection::stream).collect(toList()), removedTransactions, - addedLogsWithMetadata, - removedLogsWithMetadata); + logsWithMetadata); } @Override diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index e94726c7106..c7267e828f6 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -115,9 +115,19 @@ public String toString() { @Override public int compareTo(final LogWithMetadata other) { - return Comparator.comparingLong(LogWithMetadata::getBlockNumber) - .thenComparingInt(LogWithMetadata::getTransactionIndex) - .thenComparingInt(LogWithMetadata::getLogIndex) - .compare(this, other); + // here chronology is block chronology, not real time chronology. + final var chronologicalOrder = + Comparator.comparingLong(LogWithMetadata::getBlockNumber) + .thenComparingInt(LogWithMetadata::getTransactionIndex) + .thenComparingInt(LogWithMetadata::getLogIndex); + + final int removedCompare = Boolean.compare(this.removed, other.isRemoved()); + if (removedCompare != 0) { // sort removed logs (true) before added logs (false) + return -removedCompare; + } else if (removed) { // if we're sorting removed logs, reverse chronological + return chronologicalOrder.reversed().compare(this, other); + } else { // if we're sorting added logs, chronological + return chronologicalOrder.compare(this, other); + } } } From 64d14d93dd4f00231ed24a27cf16659681121884 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 17:08:02 +0100 Subject: [PATCH 17/40] use Deque instead of sorting Signed-off-by: Ratan Rai Sur --- .../ethereum/chain/DefaultBlockchain.java | 20 +++++++++--------- .../besu/ethereum/core/LogWithMetadata.java | 21 +------------------ 2 files changed, 11 insertions(+), 30 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 5752191c324..8a18e358937 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -34,9 +34,10 @@ import org.hyperledger.besu.util.bytes.BytesValues; import org.hyperledger.besu.util.uint.UInt256; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; +import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -337,7 +338,7 @@ private BlockAddedEvent handleChainReorg( // Track transactions and logs to be added and removed final Map> newTransactions = new HashMap<>(); final List removedTransactions = new ArrayList<>(); - final List logsWithMetadata = new ArrayList<>(); + final Deque logsWithMetadata = new ArrayDeque<>(); while (currentNewChainHeader.getNumber() > currentOldChainHeader.getNumber()) { // If new chain is longer than old chain, walk back until we meet the old chain by number @@ -403,10 +404,6 @@ private BlockAddedEvent handleChainReorg( blockchainStorage.getBlockHeader(currentOldChainHeader.getParentHash()).get(); } - // Sorts logs with removed logs in reverse-chronological order and the added logs in - // chronological order - Collections.sort(logsWithMetadata); - // Update indexed transactions newTransactions.forEach( (blockHash, transactionsInBlock) -> { @@ -431,7 +428,7 @@ private BlockAddedEvent handleChainReorg( newChainHeadBlock, newTransactions.values().stream().flatMap(Collection::stream).collect(toList()), removedTransactions, - logsWithMetadata); + new ArrayList<>(logsWithMetadata)); } @Override @@ -533,13 +530,16 @@ private boolean blockIsConnected(final Block block) { } private void addAddedLogsWithMetadata( - final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { + final Deque logsWithMetadata, final BlockWithReceipts blockWithReceipts) { logsWithMetadata.addAll(blockWithReceipts.getLogsWithMetadata(false)); } private void addRemovedLogsWithMetadata( - final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { - logsWithMetadata.addAll(blockWithReceipts.getLogsWithMetadata(true)); + final Deque logsWithMetadata, final BlockWithReceipts blockWithReceipts) { + final var newLogsWithMetadata = blockWithReceipts.getLogsWithMetadata(true); + for (int i = newLogsWithMetadata.size() - 1; i >= 0; i--) { + logsWithMetadata.addFirst(newLogsWithMetadata.get(i)); + } } private Optional getBlockWithReceipts(final BlockHeader blockHeader) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index c7267e828f6..520fe0f2cc1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -18,12 +18,11 @@ import org.hyperledger.besu.util.bytes.BytesValue; -import java.util.Comparator; import java.util.List; import com.google.common.base.MoreObjects; -public class LogWithMetadata extends Log implements Comparable { +public class LogWithMetadata extends Log { private final int logIndex; private final long blockNumber; @@ -112,22 +111,4 @@ public String toString() { .add("removed", removed) .toString(); } - - @Override - public int compareTo(final LogWithMetadata other) { - // here chronology is block chronology, not real time chronology. - final var chronologicalOrder = - Comparator.comparingLong(LogWithMetadata::getBlockNumber) - .thenComparingInt(LogWithMetadata::getTransactionIndex) - .thenComparingInt(LogWithMetadata::getLogIndex); - - final int removedCompare = Boolean.compare(this.removed, other.isRemoved()); - if (removedCompare != 0) { // sort removed logs (true) before added logs (false) - return -removedCompare; - } else if (removed) { // if we're sorting removed logs, reverse chronological - return chronologicalOrder.reversed().compare(this, other); - } else { // if we're sorting added logs, chronological - return chronologicalOrder.compare(this, other); - } - } } From 271a2aee57c7f806fc8c83a45463596c26a373be Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 17:21:06 +0100 Subject: [PATCH 18/40] fix typo and remove abbrev. Signed-off-by: Ratan Rai Sur --- .../hyperledger/besu/ethereum/chain/DefaultBlockchain.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 8a18e358937..f4676750c9c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -266,12 +266,12 @@ private UInt256 calculateTotalDifficulty(final Block block) { return block.getHeader().getDifficulty(); } - final UInt256 parentId = + final UInt256 parentTargetDifficulty = blockchainStorage .getTotalDifficulty(block.getHeader().getParentHash()) .orElseThrow( () -> new IllegalStateException("Blockchain is missing total difficulty data.")); - return block.getHeader().getDifficulty().plus(parentId); + return block.getHeader().getDifficulty().plus(parentTargetDifficulty); } private BlockAddedEvent updateCanonicalChainData( From fa097806820a61593d7347b95d4ee78aee07ae4a Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 20:53:24 +0100 Subject: [PATCH 19/40] typo Signed-off-by: Ratan Rai Sur --- .../hyperledger/besu/ethereum/chain/DefaultBlockchain.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index f4676750c9c..b0f2057625b 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -266,12 +266,12 @@ private UInt256 calculateTotalDifficulty(final Block block) { return block.getHeader().getDifficulty(); } - final UInt256 parentTargetDifficulty = + final UInt256 parentTotalDifficulty = blockchainStorage .getTotalDifficulty(block.getHeader().getParentHash()) .orElseThrow( () -> new IllegalStateException("Blockchain is missing total difficulty data.")); - return block.getHeader().getDifficulty().plus(parentTargetDifficulty); + return block.getHeader().getDifficulty().plus(parentTotalDifficulty); } private BlockAddedEvent updateCanonicalChainData( From 33c94039ada14b2e7e4173c19d54ec21b75f0836 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 21:01:14 +0100 Subject: [PATCH 20/40] remove var Signed-off-by: Ratan Rai Sur --- .../subscription/logs/LogsSubscriptionService.java | 2 +- .../internal/filter/FilterManagerLogFilterTest.java | 4 ++-- .../besu/ethereum/chain/DefaultBlockchain.java | 8 ++++---- .../hyperledger/besu/ethereum/core/BlockWithReceipts.java | 8 ++++---- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java index d95779ccac7..e39a0ef59aa 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java @@ -33,7 +33,7 @@ public LogsSubscriptionService(final SubscriptionManager subscriptionManager) { @Override public void onBlockAdded(final BlockAddedEvent event, final Blockchain __) { - final var logsSubscriptions = + final List logsSubscriptions = subscriptionManager.subscriptionsOfType(SubscriptionType.LOGS, LogsSubscription.class); event diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java index b50486d5ed5..9001c2579cc 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java @@ -146,8 +146,8 @@ public void shouldClearLogsAfterGettingLogChanges() { } private void recordNewBlockEvent() { - final var gen = new BlockDataGenerator(); - final var block = gen.block(); + final BlockDataGenerator gen = new BlockDataGenerator(); + final Block block = gen.block(); filterManager.recordBlockEvent( BlockAddedEvent.createForHeadAdvancement( block, new BlockWithReceipts(block, gen.receipts(block)).getLogsWithMetadata(false)), diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index b0f2057625b..f31f43d9e82 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -237,8 +237,8 @@ public synchronized void appendBlock(final Block block, final List receipts = blockWithReceipts.getReceipts(); final Hash hash = block.getHash(); final UInt256 td = calculateTotalDifficulty(block); @@ -278,7 +278,7 @@ private BlockAddedEvent updateCanonicalChainData( final BlockchainStorage.Updater updater, final BlockWithReceipts blockWithReceipts, final UInt256 totalDifficulty) { - final var newBlock = blockWithReceipts.getBlock(); + final Block newBlock = blockWithReceipts.getBlock(); final Hash chainHead = blockchainStorage.getChainHead().orElse(null); if (newBlock.getHeader().getNumber() != BlockHeader.GENESIS_BLOCK_NUMBER && chainHead == null) { throw new IllegalStateException("Blockchain is missing chain head."); @@ -536,7 +536,7 @@ private void addAddedLogsWithMetadata( private void addRemovedLogsWithMetadata( final Deque logsWithMetadata, final BlockWithReceipts blockWithReceipts) { - final var newLogsWithMetadata = blockWithReceipts.getLogsWithMetadata(true); + final List newLogsWithMetadata = blockWithReceipts.getLogsWithMetadata(true); for (int i = newLogsWithMetadata.size() - 1; i >= 0; i--) { logsWithMetadata.addFirst(newLogsWithMetadata.get(i)); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java index 4910cd68425..afddc96f1aa 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java @@ -75,12 +75,12 @@ public String toString() { } public List getLogsWithMetadata(final boolean removed) { - final var logsWithMetadata = new ArrayList(); - final var block = getBlock(); + final List logsWithMetadata = new ArrayList(); + final Block block = getBlock(); for (int txi = 0; txi < receipts.size(); ++txi) { - final var currentReceipt = receipts.get(txi); + final TransactionReceipt currentReceipt = receipts.get(txi); for (int li = 0; li < currentReceipt.getLogs().size(); ++li) { - final var currentLog = currentReceipt.getLogs().get(li); + final Log currentLog = currentReceipt.getLogs().get(li); logsWithMetadata.add( new LogWithMetadata( li, From a955f8415d7c4503b681b45ac22eae1a045ab5aa Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 21:26:21 +0100 Subject: [PATCH 21/40] override `getChainHeadBlock` Signed-off-by: Ratan Rai Sur --- .../hyperledger/besu/ethereum/chain/DefaultBlockchain.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index f31f43d9e82..c500f54b89f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -175,6 +175,11 @@ public BlockHeader getChainHeadHeader() { return chainHeader; } + @Override + public Block getChainHeadBlock() { + return new Block(chainHeader, blockchainStorage.getBlockBody(chainHeader.getHash()).get()); + } + @Override public Optional getBlockHeader(final long blockNumber) { return blockchainStorage.getBlockHash(blockNumber).flatMap(blockchainStorage::getBlockHeader); From b7d4f1586c22d8197899d35a27d4e2b2d1e37eb8 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 22:01:31 +0100 Subject: [PATCH 22/40] base reorg iteration off of `BlockWithReceipt`s Signed-off-by: Ratan Rai Sur --- .../ethereum/chain/DefaultBlockchain.java | 97 ++++++++----------- 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index c500f54b89f..5ec2a689b3c 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -332,81 +332,57 @@ private BlockAddedEvent handleFork(final BlockchainStorage.Updater updater, fina private BlockAddedEvent handleChainReorg( final BlockchainStorage.Updater updater, final BlockWithReceipts newChainHeadWithReceipts) { - final Block newChainHeadBlock = newChainHeadWithReceipts.getBlock(); - final Block oldChainHeadBlock = getChainHeadBlock(); - BlockHeader currentOldChainHeader = oldChainHeadBlock.getHeader(); - BlockHeader currentNewChainHeader = newChainHeadBlock.getHeader(); + BlockWithReceipts oldChainWithReceipts = getBlockWithReceipts(chainHeader).get(); + BlockWithReceipts currentOldChainWithReceipts = oldChainWithReceipts; + BlockWithReceipts currentNewChainWithReceipts = newChainHeadWithReceipts; // Update chain head - updater.setChainHead(newChainHeadBlock.getHash()); + updater.setChainHead(currentNewChainWithReceipts.getHeader().getHash()); // Track transactions and logs to be added and removed final Map> newTransactions = new HashMap<>(); final List removedTransactions = new ArrayList<>(); final Deque logsWithMetadata = new ArrayDeque<>(); - while (currentNewChainHeader.getNumber() > currentOldChainHeader.getNumber()) { + while (currentNewChainWithReceipts.getNumber() > currentOldChainWithReceipts.getNumber()) { // If new chain is longer than old chain, walk back until we meet the old chain by number // adding indexing for new chain along the way. - final Hash blockHash = currentNewChainHeader.getHash(); - updater.putBlockHash(currentNewChainHeader.getNumber(), blockHash); - final List newTxs = - blockchainStorage - .getBlockBody(blockHash) - .map(BlockBody::getTransactions) - // If it's not in storage, it must be the new chain head - .orElseGet(() -> newChainHeadBlock.getBody().getTransactions()); - newTransactions.put(blockHash, newTxs); - - addAddedLogsWithMetadata( - logsWithMetadata, - getBlockWithReceipts(currentNewChainHeader).orElse(newChainHeadWithReceipts)); - - currentNewChainHeader = - blockchainStorage.getBlockHeader(currentNewChainHeader.getParentHash()).get(); + final Hash blockHash = currentNewChainWithReceipts.getHash(); + updater.putBlockHash(currentNewChainWithReceipts.getNumber(), blockHash); + + newTransactions.put( + blockHash, currentNewChainWithReceipts.getBlock().getBody().getTransactions()); + addAddedLogsWithMetadata(logsWithMetadata, currentNewChainWithReceipts); + + currentNewChainWithReceipts = getParentBlockWithReceipts(currentNewChainWithReceipts); } - while (currentOldChainHeader.getNumber() > currentNewChainHeader.getNumber()) { + while (currentOldChainWithReceipts.getNumber() > currentNewChainWithReceipts.getNumber()) { // If oldChain is longer than new chain, walk back until we meet the new chain by number, // updating as we go. - updater.removeBlockHash(currentOldChainHeader.getNumber()); - removedTransactions.addAll( - blockchainStorage.getBlockBody(currentOldChainHeader.getHash()).get().getTransactions()); + updater.removeBlockHash(currentOldChainWithReceipts.getNumber()); - addRemovedLogsWithMetadata( - logsWithMetadata, getBlockWithReceipts(currentOldChainHeader).get()); + removedTransactions.addAll( + currentOldChainWithReceipts.getBlock().getBody().getTransactions()); + addRemovedLogsWithMetadata(logsWithMetadata, currentOldChainWithReceipts); - currentOldChainHeader = - blockchainStorage.getBlockHeader(currentOldChainHeader.getParentHash()).get(); + currentOldChainWithReceipts = getParentBlockWithReceipts(currentOldChainWithReceipts); } - while (!currentOldChainHeader.getHash().equals(currentNewChainHeader.getHash())) { + while (!currentOldChainWithReceipts.getHash().equals(currentNewChainWithReceipts.getHash())) { // Walk back until we meet the common ancestor between the two chains, updating as we go. - final Hash newBlockHash = currentNewChainHeader.getHash(); - updater.putBlockHash(currentNewChainHeader.getNumber(), newBlockHash); - - // Collect transaction to be updated - final List newTxs = - blockchainStorage - .getBlockBody(newBlockHash) - .map(BlockBody::getTransactions) - // If it's not in storage, it must be the new chain head - .orElseGet(() -> newChainHeadBlock.getBody().getTransactions()); - - newTransactions.put(newBlockHash, newTxs); + final Hash newBlockHash = currentNewChainWithReceipts.getHash(); + updater.putBlockHash(currentNewChainWithReceipts.getNumber(), newBlockHash); + + newTransactions.put( + newBlockHash, currentNewChainWithReceipts.getBlock().getBody().getTransactions()); removedTransactions.addAll( - blockchainStorage.getBlockBody(currentOldChainHeader.getHash()).get().getTransactions()); - - addAddedLogsWithMetadata( - logsWithMetadata, - getBlockWithReceipts(currentNewChainHeader).orElse(newChainHeadWithReceipts)); - addRemovedLogsWithMetadata( - logsWithMetadata, getBlockWithReceipts(currentOldChainHeader).get()); - - currentNewChainHeader = - blockchainStorage.getBlockHeader(currentNewChainHeader.getParentHash()).get(); - currentOldChainHeader = - blockchainStorage.getBlockHeader(currentOldChainHeader.getParentHash()).get(); + currentOldChainWithReceipts.getBlock().getBody().getTransactions()); + addAddedLogsWithMetadata(logsWithMetadata, currentNewChainWithReceipts); + addRemovedLogsWithMetadata(logsWithMetadata, currentOldChainWithReceipts); + + currentNewChainWithReceipts = getParentBlockWithReceipts(currentNewChainWithReceipts); + currentOldChainWithReceipts = getParentBlockWithReceipts(currentOldChainWithReceipts); } // Update indexed transactions @@ -421,7 +397,7 @@ private BlockAddedEvent handleChainReorg( // Update tracked forks final Collection forks = blockchainStorage.getForkHeads(); // Old head is now a fork - forks.add(oldChainHeadBlock.getHash()); + forks.add(oldChainWithReceipts.getHash()); // Remove new chain head's parent if it was tracked as a fork final Optional parentFork = forks.stream() @@ -430,7 +406,7 @@ private BlockAddedEvent handleChainReorg( parentFork.ifPresent(forks::remove); updater.setForkHeads(forks); return BlockAddedEvent.createForChainReorg( - newChainHeadBlock, + newChainHeadWithReceipts.getBlock(), newTransactions.values().stream().flatMap(Collection::stream).collect(toList()), removedTransactions, new ArrayList<>(logsWithMetadata)); @@ -558,6 +534,13 @@ private Optional getBlockWithReceipts(final BlockHeader block .map(receipts -> new BlockWithReceipts(block, receipts))); } + private BlockWithReceipts getParentBlockWithReceipts(final BlockWithReceipts blockWithReceipts) { + return blockchainStorage + .getBlockHeader(blockWithReceipts.getHeader().getParentHash()) + .flatMap(this::getBlockWithReceipts) + .get(); + } + @Override public long observeBlockAdded(final BlockAddedObserver observer) { checkNotNull(observer); From 733e39632ac45328d6923f60de76728ead7e646d Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 22:09:05 +0100 Subject: [PATCH 23/40] move `List` logic from `BlockWithReceipts` to `LogWithMetadata` Signed-off-by: Ratan Rai Sur --- .../ethereum/chain/DefaultBlockchain.java | 8 +++++-- .../besu/ethereum/core/BlockWithReceipts.java | 24 ------------------- .../besu/ethereum/core/LogWithMetadata.java | 24 +++++++++++++++++++ 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 5ec2a689b3c..ebb0fceb853 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -512,12 +512,16 @@ private boolean blockIsConnected(final Block block) { private void addAddedLogsWithMetadata( final Deque logsWithMetadata, final BlockWithReceipts blockWithReceipts) { - logsWithMetadata.addAll(blockWithReceipts.getLogsWithMetadata(false)); + logsWithMetadata.addAll( + LogWithMetadata.generate( + blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), false)); } private void addRemovedLogsWithMetadata( final Deque logsWithMetadata, final BlockWithReceipts blockWithReceipts) { - final List newLogsWithMetadata = blockWithReceipts.getLogsWithMetadata(true); + final List newLogsWithMetadata = + LogWithMetadata.generate( + blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), true); for (int i = newLogsWithMetadata.size() - 1; i >= 0; i--) { logsWithMetadata.addFirst(newLogsWithMetadata.get(i)); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java index afddc96f1aa..ae642b065ad 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/BlockWithReceipts.java @@ -14,7 +14,6 @@ */ package org.hyperledger.besu.ethereum.core; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -73,27 +72,4 @@ public String toString() { .add("receipts", receipts) .toString(); } - - public List getLogsWithMetadata(final boolean removed) { - final List logsWithMetadata = new ArrayList(); - final Block block = getBlock(); - for (int txi = 0; txi < receipts.size(); ++txi) { - final TransactionReceipt currentReceipt = receipts.get(txi); - for (int li = 0; li < currentReceipt.getLogs().size(); ++li) { - final Log currentLog = currentReceipt.getLogs().get(li); - logsWithMetadata.add( - new LogWithMetadata( - li, - block.getHeader().getNumber(), - block.getHash(), - block.getBody().getTransactions().get(txi).hash(), - txi, - currentLog.getLogger(), - currentLog.getData(), - currentLog.getTopics(), - removed)); - } - } - return logsWithMetadata; - } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index 520fe0f2cc1..27ba1a67229 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.util.bytes.BytesValue; +import java.util.ArrayList; import java.util.List; import com.google.common.base.MoreObjects; @@ -56,6 +57,29 @@ public LogWithMetadata( this.removed = removed; } + public static List generate( + final Block block, final List receipts, final boolean removed) { + final List logsWithMetadata = new ArrayList<>(); + for (int txi = 0; txi < receipts.size(); ++txi) { + final TransactionReceipt currentReceipt = receipts.get(txi); + for (int li = 0; li < currentReceipt.getLogs().size(); ++li) { + final Log currentLog = currentReceipt.getLogs().get(li); + logsWithMetadata.add( + new LogWithMetadata( + li, + block.getHeader().getNumber(), + block.getHash(), + block.getBody().getTransactions().get(txi).hash(), + txi, + currentLog.getLogger(), + currentLog.getData(), + currentLog.getTopics(), + removed)); + } + } + return logsWithMetadata; + } + // The index of this log within the entire ordered list of logs associated with the block this log // belongs to. public int getLogIndex() { From 2a853a23e8b929afe2d09ec5f0766e43d5269f92 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 3 Oct 2019 22:22:01 +0100 Subject: [PATCH 24/40] imports and stuff Signed-off-by: Ratan Rai Sur --- .../websocket/subscription/logs/LogsSubscriptionService.java | 2 ++ .../jsonrpc/internal/filter/FilterManagerLogFilterTest.java | 4 ++-- .../hyperledger/besu/ethereum/chain/DefaultBlockchain.java | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java index e39a0ef59aa..812eeda60e3 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java @@ -23,6 +23,8 @@ import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.Blockchain; +import java.util.List; + public class LogsSubscriptionService implements BlockAddedObserver { private final SubscriptionManager subscriptionManager; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java index 9001c2579cc..e62079b7f04 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/FilterManagerLogFilterTest.java @@ -32,8 +32,8 @@ import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.core.Block; import org.hyperledger.besu.ethereum.core.BlockDataGenerator; -import org.hyperledger.besu.ethereum.core.BlockWithReceipts; import org.hyperledger.besu.ethereum.core.Hash; import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; @@ -150,7 +150,7 @@ private void recordNewBlockEvent() { final Block block = gen.block(); filterManager.recordBlockEvent( BlockAddedEvent.createForHeadAdvancement( - block, new BlockWithReceipts(block, gen.receipts(block)).getLogsWithMetadata(false)), + block, LogWithMetadata.generate(block, gen.receipts(block), false)), blockchainQueries.getBlockchain()); } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index ebb0fceb853..4a806ad1a7f 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -297,7 +297,9 @@ private BlockAddedEvent updateCanonicalChainData( updater.setChainHead(newBlockHash); indexTransactionForBlock(updater, newBlockHash, newBlock.getBody().getTransactions()); return BlockAddedEvent.createForHeadAdvancement( - newBlock, blockWithReceipts.getLogsWithMetadata(false)); + newBlock, + LogWithMetadata.generate( + blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), false)); } else if (totalDifficulty.compareTo(blockchainStorage.getTotalDifficulty(chainHead).get()) > 0) { // New block represents a chain reorganization From 575fac6b05c29c798701d93d4b1daab66bfd172f Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 14 Oct 2019 11:17:50 +0900 Subject: [PATCH 25/40] functional style Signed-off-by: Ratan Rai Sur --- .../ethereum/chain/DefaultBlockchain.java | 32 +++++++------------ 1 file changed, 11 insertions(+), 21 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 4a806ad1a7f..ef1a4d3280a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -138,21 +138,11 @@ public static Blockchain create( private static boolean validateStorageNonEmpty(final BlockchainStorage blockchainStorage) { // Run a few basic checks to make sure data looks available and consistent - final Optional maybeHead = blockchainStorage.getChainHead(); - if (maybeHead.isEmpty()) { - return false; - } - final Optional genesisHash = - blockchainStorage.getBlockHash(BlockHeader.GENESIS_BLOCK_NUMBER); - if (genesisHash.isEmpty()) { - return false; - } - final Optional td = blockchainStorage.getTotalDifficulty(maybeHead.get()); - if (td.isEmpty()) { - return false; - } - - return true; + return blockchainStorage + .getChainHead() + .flatMap(blockchainStorage::getTotalDifficulty) + .isPresent() + && blockchainStorage.getBlockHash(BlockHeader.GENESIS_BLOCK_NUMBER).isPresent(); } @Override @@ -320,11 +310,11 @@ private BlockAddedEvent handleFork(final BlockchainStorage.Updater updater, fina final Collection forkHeads = blockchainStorage.getForkHeads(); // Check to see if this block advances any existing fork. - final Hash parentHash = fork.getHeader().getParentHash(); - final Optional parent = - forkHeads.stream().filter(head -> head.equals(parentHash)).findAny(); // This block will replace its parent - parent.ifPresent(forkHeads::remove); + forkHeads.stream() + .filter(head -> head.equals(fork.getHeader().getParentHash())) + .findFirst() + .ifPresent(forkHeads::remove); forkHeads.add(fork.getHash()); @@ -473,7 +463,7 @@ private void setGenesis(final Block genesisBlock) { genesisBlock.getHeader().getNumber() == BlockHeader.GENESIS_BLOCK_NUMBER, "Invalid genesis block."); final Optional maybeHead = blockchainStorage.getChainHead(); - if (!maybeHead.isPresent()) { + if (maybeHead.isEmpty()) { // Initialize blockchain store with genesis block. final BlockchainStorage.Updater updater = blockchainStorage.updater(); final Hash hash = genesisBlock.getHash(); @@ -487,7 +477,7 @@ private void setGenesis(final Block genesisBlock) { } else { // Verify genesis block is consistent with stored blockchain. final Optional genesisHash = getBlockHashByNumber(BlockHeader.GENESIS_BLOCK_NUMBER); - if (!genesisHash.isPresent()) { + if (genesisHash.isEmpty()) { throw new IllegalStateException("Blockchain is missing genesis block data."); } if (!genesisHash.get().equals(genesisBlock.getHash())) { From 08d7c1cafe0c844e410a9b6f2bc02111fa5d9d4a Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 14 Oct 2019 12:21:36 +0900 Subject: [PATCH 26/40] cleanup Signed-off-by: Ratan Rai Sur --- .../hyperledger/besu/ethereum/chain/DefaultBlockchain.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index ef1a4d3280a..dd82b64fb82 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -511,11 +511,10 @@ private void addAddedLogsWithMetadata( private void addRemovedLogsWithMetadata( final Deque logsWithMetadata, final BlockWithReceipts blockWithReceipts) { - final List newLogsWithMetadata = + for (final LogWithMetadata logWithMetadata : LogWithMetadata.generate( - blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), true); - for (int i = newLogsWithMetadata.size() - 1; i >= 0; i--) { - logsWithMetadata.addFirst(newLogsWithMetadata.get(i)); + blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), true)) { + logsWithMetadata.addFirst(logWithMetadata); } } From 7cd9ddd3acd94d866477fb0a11283cffbe7e6db8 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 14 Oct 2019 16:16:14 +0900 Subject: [PATCH 27/40] add tests for log ordering Signed-off-by: Ratan Rai Sur --- .../ethereum/core/BlockDataGenerator.java | 14 ++++---- .../ethereum/chain/DefaultBlockchainTest.java | 32 ++++++++++++++++++- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java index 415f049c808..ef6b3e4785d 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java @@ -35,6 +35,7 @@ import java.time.temporal.ChronoUnit; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -486,7 +487,7 @@ public static class BlockOptions { private Optional parentHash = Optional.empty(); private Optional stateRoot = Optional.empty(); private Optional difficulty = Optional.empty(); - private Optional> transactions = Optional.empty(); + private List transactions = new ArrayList<>(); private Optional extraData = Optional.empty(); private Optional blockHeaderFunctions = Optional.empty(); @@ -495,7 +496,7 @@ public static BlockOptions create() { } public List getTransactions(final List defaultValue) { - return transactions.orElse(defaultValue); + return transactions.isEmpty() ? defaultValue : transactions; } public long getBlockNumber(final long defaultValue) { @@ -523,13 +524,14 @@ public BlockHeaderFunctions getBlockHeaderFunctions(final BlockHeaderFunctions d } public BlockOptions addTransaction(final Transaction... tx) { - if (!transactions.isPresent()) { - transactions = Optional.of(new ArrayList<>()); - } - transactions.get().addAll(Arrays.asList(tx)); + transactions.addAll(Arrays.asList(tx)); return this; } + public BlockOptions addTransaction(final Collection txs) { + return addTransaction(txs.toArray(new Transaction[] {})); + } + public BlockOptions setBlockNumber(final long blockNumber) { this.blockNumber = OptionalLong.of(blockNumber); return this; diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java index 51259868973..e26e7e01bba 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.core.LogWithMetadata; import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.mainnet.MainnetBlockHeaderFunctions; @@ -38,6 +39,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; +import com.google.common.collect.Lists; import org.junit.Test; public class DefaultBlockchainTest { @@ -156,9 +158,16 @@ public void appendBlock() { final BlockDataGenerator.BlockOptions options = new BlockDataGenerator.BlockOptions() .setBlockNumber(1L) + .addTransaction(gen.transactions(5)) .setParentHash(genesisBlock.getHash()); final Block newBlock = gen.block(options); final List receipts = gen.receipts(newBlock); + blockchain.observeBlockAdded( + ((event, blockchain1) -> + assertThat(event.getLogsWithMetadata()) + .containsExactly( + LogWithMetadata.generate(newBlock, receipts, false) + .toArray(new LogWithMetadata[] {})))); blockchain.appendBlock(newBlock, receipts); assertBlockIsHead(blockchain, newBlock); @@ -226,15 +235,25 @@ public void createSmallChain() { public void appendBlockWithReorgToChainAtEqualHeight() { final BlockDataGenerator gen = new BlockDataGenerator(1); - // Setup an initial blockchain + // Setup final int chainLength = 3; final List chain = gen.blockSequence(chainLength); final List> blockReceipts = chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + ((event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata()))); + List expectedLogsWithMetadata = new ArrayList<>(); + + // Add initial blocks for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } assertThat(blockchain.getForks()).isEmpty(); final Block originalHead = chain.get(chainLength - 1); @@ -267,6 +286,15 @@ public void appendBlockWithReorgToChainAtEqualHeight() { assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); } + // LogWithMetadata reflecting removal of originalHead's logs + final List removedLogs = + Lists.reverse( + LogWithMetadata.generate( + originalHead, blockchain.getTxReceipts(originalHead.getHash()).get(), true)); + expectedLogsWithMetadata.addAll(removedLogs); + // LogWithMetadata reflecting addition of originalHead's logs + expectedLogsWithMetadata.addAll(LogWithMetadata.generate(fork, forkReceipts, false)); + assertBlockIsHead(blockchain, fork); assertTotalDifficultiesAreConsistent(blockchain, fork); // Old chain head should now be tracked as a fork. @@ -277,6 +305,8 @@ public void appendBlockWithReorgToChainAtEqualHeight() { for (int i = commonAncestor + 1; i < chainLength; i++) { assertThat(blockchain.blockIsOnCanonicalChain(chain.get(i).getHash())).isFalse(); } + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test From f37f6273d698831018581f8a303b2af839e2d38d Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 14 Oct 2019 16:22:39 +0900 Subject: [PATCH 28/40] imports Signed-off-by: Ratan Rai Sur --- .../websocket/subscription/logs/LogsSubscriptionService.java | 2 -- .../subscription/logs/LogsSubscriptionServiceTest.java | 1 - 2 files changed, 3 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java index 812eeda60e3..b4f49d323f7 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionService.java @@ -17,8 +17,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogResult; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.request.SubscriptionType; -import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; -import org.hyperledger.besu.ethereum.api.query.TransactionReceiptWithMetadata; import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; import org.hyperledger.besu.ethereum.chain.BlockAddedObserver; import org.hyperledger.besu.ethereum.chain.Blockchain; diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java index d102d7d0826..3bb25154e7d 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/websocket/subscription/logs/LogsSubscriptionServiceTest.java @@ -25,7 +25,6 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.LogResult; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity; import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.subscription.SubscriptionManager; -import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.api.query.TopicsParameter; import org.hyperledger.besu.ethereum.chain.MutableBlockchain; import org.hyperledger.besu.ethereum.core.Address; From 3b6f6134d90093cf0ecbbd2de188b6820396a09b Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 21 Oct 2019 10:13:12 -0400 Subject: [PATCH 29/40] make it compile after rebase Signed-off-by: Ratan Rai Sur --- .../org/hyperledger/besu/ethereum/core/LogWithMetadata.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index 27ba1a67229..e3b1102f97a 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -69,7 +69,7 @@ public static List generate( li, block.getHeader().getNumber(), block.getHash(), - block.getBody().getTransactions().get(txi).hash(), + block.getBody().getTransactions().get(txi).getHash(), txi, currentLog.getLogger(), currentLog.getData(), From de24d3e55e0c25e7201ccaacf675c31d738a4422 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 21 Oct 2019 10:53:20 -0400 Subject: [PATCH 30/40] consolidate LogWithMetadata creation Signed-off-by: Ratan Rai Sur --- .../pojoadapter/TransactionAdapter.java | 8 +- .../ethereum/api/query/BlockchainQueries.java | 96 ++++--------------- .../besu/ethereum/core/LogWithMetadata.java | 49 +++++++--- 3 files changed, 55 insertions(+), 98 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java index d612b97ed1a..0f36359fd75 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/graphql/internal/pojoadapter/TransactionAdapter.java @@ -167,13 +167,13 @@ public Optional getCreatedContract(final DataFetchingEnvironment public List getLogs(final DataFetchingEnvironment environment) { final BlockchainQueries query = getBlockchainQueries(environment); final Hash hash = transactionWithMetadata.getTransaction().getHash(); - final Optional tranRpt = + final Optional maybeTransactionReceiptWithMetadata = query.transactionReceiptByTransactionHash(hash); final List results = new ArrayList<>(); - if (tranRpt.isPresent()) { + if (maybeTransactionReceiptWithMetadata.isPresent()) { final List logs = - BlockchainQueries.generateLogWithMetadataForTransaction( - tranRpt.get().getReceipt(), + LogWithMetadata.generate( + maybeTransactionReceiptWithMetadata.get().getReceipt(), transactionWithMetadata.getBlockNumber().get(), transactionWithMetadata.getBlockHash().get(), hash, diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 2c4609b1256..4135100dfbc 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -35,10 +35,13 @@ import org.hyperledger.besu.util.uint.UInt256; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.IntStream; import com.google.common.collect.Lists; @@ -489,95 +492,30 @@ public List matchingLogs( } List matchingLogs = Lists.newArrayList(); for (long blockNumber = fromBlockNumber; blockNumber <= toBlockNumber; blockNumber++) { - final Hash blockhash = blockchain.getBlockHashByNumber(blockNumber).get(); - final boolean logHasBeenRemoved = !blockchain.blockIsOnCanonicalChain(blockhash); - final List receipts = blockchain.getTxReceipts(blockhash).get(); - final List transaction = - blockchain.getBlockBody(blockhash).get().getTransactions(); - matchingLogs = - generateLogWithMetadata( - receipts, - blockNumber, - query, - blockhash, - matchingLogs, - transaction, - logHasBeenRemoved); + final Hash blockHash = blockchain.getBlockHashByNumber(blockNumber).get(); + matchingLogs.addAll(matchingLogs(blockHash, query)); } return matchingLogs; } public List matchingLogs(final Hash blockhash, final LogsQuery query) { - final List matchingLogs = Lists.newArrayList(); Optional blockHeader = blockchain.getBlockHeader(blockhash); - if (!blockHeader.isPresent()) { - return matchingLogs; + if (blockHeader.isEmpty()) { + return Collections.emptyList(); } final List receipts = blockchain.getTxReceipts(blockhash).get(); - final List transaction = + final List transactions = blockchain.getBlockBody(blockhash).get().getTransactions(); final long number = blockHeader.get().getNumber(); - final boolean logHasBeenRemoved = !blockchain.blockIsOnCanonicalChain(blockhash); - return generateLogWithMetadata( - receipts, number, query, blockhash, matchingLogs, transaction, logHasBeenRemoved); - } - - public static List generateLogWithMetadataForTransaction( - final TransactionReceipt receipt, - final long number, - final Hash blockhash, - final Hash transactionHash, - final int transactionIndex, - final boolean removed) { - - final List logs = new ArrayList<>(); - for (int logIndex = 0; logIndex < receipt.getLogs().size(); ++logIndex) { - - final LogWithMetadata logWithMetaData = - new LogWithMetadata( - logIndex, - number, - blockhash, - transactionHash, - transactionIndex, - receipt.getLogs().get(logIndex).getLogger(), - receipt.getLogs().get(logIndex).getData(), - receipt.getLogs().get(logIndex).getTopics(), - removed); - logs.add(logWithMetaData); - } - - return logs; - } - - private List generateLogWithMetadata( - final List receipts, - final long number, - final LogsQuery query, - final Hash blockhash, - final List matchingLogs, - final List transaction, - final boolean removed) { - for (int transactionIndex = 0; transactionIndex < receipts.size(); ++transactionIndex) { - final TransactionReceipt receipt = receipts.get(transactionIndex); - for (int logIndex = 0; logIndex < receipt.getLogs().size(); ++logIndex) { - if (query.matches(receipt.getLogs().get(logIndex))) { - final LogWithMetadata logWithMetaData = - new LogWithMetadata( - logIndex, - number, - blockhash, - transaction.get(transactionIndex).getHash(), - transactionIndex, - receipts.get(transactionIndex).getLogs().get(logIndex).getLogger(), - receipts.get(transactionIndex).getLogs().get(logIndex).getData(), - receipts.get(transactionIndex).getLogs().get(logIndex).getTopics(), - removed); - matchingLogs.add(logWithMetaData); - } - } - } - return matchingLogs; + final boolean removed = !blockchain.blockIsOnCanonicalChain(blockhash); + return IntStream.range(0, receipts.size()) + .mapToObj( + i -> + LogWithMetadata.generate( + receipts.get(i), number, blockhash, transactions.get(i).getHash(), i, removed)) + .flatMap(Collection::stream) + .filter(query::matches) + .collect(Collectors.toList()); } /** diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index e3b1102f97a..79a616f22a3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -57,25 +57,44 @@ public LogWithMetadata( this.removed = removed; } + public static List generate( + final TransactionReceipt receipt, + final long number, + final Hash blockHash, + final Hash transactionHash, + final int transactionIndex, + final boolean removed) { + + final List logs = new ArrayList<>(); + for (int logIndex = 0; logIndex < receipt.getLogs().size(); ++logIndex) { + logs.add( + new LogWithMetadata( + logIndex, + number, + blockHash, + transactionHash, + transactionIndex, + receipt.getLogs().get(logIndex).getLogger(), + receipt.getLogs().get(logIndex).getData(), + receipt.getLogs().get(logIndex).getTopics(), + removed)); + } + + return logs; + } + public static List generate( final Block block, final List receipts, final boolean removed) { final List logsWithMetadata = new ArrayList<>(); for (int txi = 0; txi < receipts.size(); ++txi) { - final TransactionReceipt currentReceipt = receipts.get(txi); - for (int li = 0; li < currentReceipt.getLogs().size(); ++li) { - final Log currentLog = currentReceipt.getLogs().get(li); - logsWithMetadata.add( - new LogWithMetadata( - li, - block.getHeader().getNumber(), - block.getHash(), - block.getBody().getTransactions().get(txi).getHash(), - txi, - currentLog.getLogger(), - currentLog.getData(), - currentLog.getTopics(), - removed)); - } + logsWithMetadata.addAll( + generate( + receipts.get(txi), + block.getHeader().getNumber(), + block.getHash(), + block.getBody().getTransactions().get(txi).getHash(), + txi, + removed)); } return logsWithMetadata; } From 4ceefca8840b5b88b61fc8df01bffbfd7a9aa2a1 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 21 Oct 2019 11:11:15 -0400 Subject: [PATCH 31/40] functional style Signed-off-by: Ratan Rai Sur --- .../ethereum/api/query/BlockchainQueries.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 4135100dfbc..b5d429027ff 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -38,12 +38,12 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.IntStream; - -import com.google.common.collect.Lists; +import java.util.stream.LongStream; public class BlockchainQueries { @@ -487,32 +487,31 @@ public Optional transactionReceiptByTransactionH */ public List matchingLogs( final long fromBlockNumber, final long toBlockNumber, final LogsQuery query) { - if (fromBlockNumber > toBlockNumber || toBlockNumber > headBlockNumber()) { - return Lists.newArrayList(); - } - List matchingLogs = Lists.newArrayList(); - for (long blockNumber = fromBlockNumber; blockNumber <= toBlockNumber; blockNumber++) { - final Hash blockHash = blockchain.getBlockHashByNumber(blockNumber).get(); - matchingLogs.addAll(matchingLogs(blockHash, query)); + try { + return LongStream.rangeClosed(fromBlockNumber, toBlockNumber) + .mapToObj(i -> matchingLogs(blockchain.getBlockHashByNumber(i).get(), query)) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } catch (NoSuchElementException nsee) { + return Collections.emptyList(); } - return matchingLogs; } - public List matchingLogs(final Hash blockhash, final LogsQuery query) { - Optional blockHeader = blockchain.getBlockHeader(blockhash); + public List matchingLogs(final Hash blockHash, final LogsQuery query) { + Optional blockHeader = blockchain.getBlockHeader(blockHash); if (blockHeader.isEmpty()) { return Collections.emptyList(); } - final List receipts = blockchain.getTxReceipts(blockhash).get(); + final List receipts = blockchain.getTxReceipts(blockHash).get(); final List transactions = - blockchain.getBlockBody(blockhash).get().getTransactions(); + blockchain.getBlockBody(blockHash).get().getTransactions(); final long number = blockHeader.get().getNumber(); - final boolean removed = !blockchain.blockIsOnCanonicalChain(blockhash); + final boolean removed = !blockchain.blockIsOnCanonicalChain(blockHash); return IntStream.range(0, receipts.size()) .mapToObj( i -> LogWithMetadata.generate( - receipts.get(i), number, blockhash, transactions.get(i).getHash(), i, removed)) + receipts.get(i), number, blockHash, transactions.get(i).getHash(), i, removed)) .flatMap(Collection::stream) .filter(query::matches) .collect(Collectors.toList()); From 31e2fe7a20c25cec0e0ae6f0bc00b4c80d530fa1 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Mon, 21 Oct 2019 12:47:10 -0400 Subject: [PATCH 32/40] remove parens Signed-off-by: Ratan Rai Sur --- .../hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java index e26e7e01bba..047f09ab567 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java @@ -246,7 +246,7 @@ public void appendBlockWithReorgToChainAtEqualHeight() { // Listen to block events and add the Logs here List logsWithMetadata = new ArrayList<>(); blockchain.observeBlockAdded( - ((event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata()))); + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); List expectedLogsWithMetadata = new ArrayList<>(); // Add initial blocks From e4b026663accc6667da8637292188c81a94836fe Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Tue, 22 Oct 2019 10:44:43 -0400 Subject: [PATCH 33/40] wip: more tests Signed-off-by: Ratan Rai Sur --- .../ethereum/chain/DefaultBlockchainTest.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java index 047f09ab567..8495e27bd31 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java @@ -320,8 +320,15 @@ public void appendBlockWithReorgToShorterChain() { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } final Block originalHead = chain.get(originalChainLength - 1); @@ -394,6 +401,19 @@ public void appendBlockWithReorgToShorterChain() { for (final Transaction tx : removedTransactions) { assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); } + // LogWithMetadata reflecting removal of logs + for (int i = originalChainLength - 1; i >= forkStart; i--) { + final Block currentBlock = chain.get(i); + expectedLogsWithMetadata.addAll( + Lists.reverse( + LogWithMetadata.generate( + currentBlock, blockchain.getTxReceipts(currentBlock.getHash()).get(), true))); + } + // LogWithMetadata reflecting addition of logs + for (int i = 0; i < forkBlocks.size(); i++) { + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(forkBlocks.get(i), forkReceipts.get(i), false)); + } // Check that blockNumber index for previous chain head has been removed assertThat(blockchain.getBlockHashByNumber(originalChainLength - 1)).isNotPresent(); @@ -405,6 +425,8 @@ public void appendBlockWithReorgToShorterChain() { for (int i = commonAncestor + 1; i < originalChainLength; i++) { assertThat(blockchain.blockIsOnCanonicalChain(chain.get(i).getHash())).isFalse(); } + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test From 8b76d6e9485e1980ce281e35cc16b263d89e8470 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Tue, 22 Oct 2019 11:46:22 -0400 Subject: [PATCH 34/40] testing and bugfix Signed-off-by: Ratan Rai Sur --- .../ethereum/chain/DefaultBlockchain.java | 33 ++++++------ .../besu/ethereum/core/LogWithMetadata.java | 21 +++++++- .../ethereum/chain/DefaultBlockchainTest.java | 51 +++++++++++++++++++ 3 files changed, 89 insertions(+), 16 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index dd82b64fb82..4f6a6ba2889 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -34,10 +34,8 @@ import org.hyperledger.besu.util.bytes.BytesValues; import org.hyperledger.besu.util.uint.UInt256; -import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; -import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -45,8 +43,11 @@ import java.util.NoSuchElementException; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Lists; public class DefaultBlockchain implements MutableBlockchain { @@ -334,7 +335,8 @@ private BlockAddedEvent handleChainReorg( // Track transactions and logs to be added and removed final Map> newTransactions = new HashMap<>(); final List removedTransactions = new ArrayList<>(); - final Deque logsWithMetadata = new ArrayDeque<>(); + final List addedLogsWithMetadata = new ArrayList<>(); + final List removedLogsWithMetadata = new ArrayList<>(); while (currentNewChainWithReceipts.getNumber() > currentOldChainWithReceipts.getNumber()) { // If new chain is longer than old chain, walk back until we meet the old chain by number @@ -344,7 +346,7 @@ private BlockAddedEvent handleChainReorg( newTransactions.put( blockHash, currentNewChainWithReceipts.getBlock().getBody().getTransactions()); - addAddedLogsWithMetadata(logsWithMetadata, currentNewChainWithReceipts); + addAddedLogsWithMetadata(addedLogsWithMetadata, currentNewChainWithReceipts); currentNewChainWithReceipts = getParentBlockWithReceipts(currentNewChainWithReceipts); } @@ -356,7 +358,7 @@ private BlockAddedEvent handleChainReorg( removedTransactions.addAll( currentOldChainWithReceipts.getBlock().getBody().getTransactions()); - addRemovedLogsWithMetadata(logsWithMetadata, currentOldChainWithReceipts); + addRemovedLogsWithMetadata(removedLogsWithMetadata, currentOldChainWithReceipts); currentOldChainWithReceipts = getParentBlockWithReceipts(currentOldChainWithReceipts); } @@ -370,8 +372,8 @@ private BlockAddedEvent handleChainReorg( newBlockHash, currentNewChainWithReceipts.getBlock().getBody().getTransactions()); removedTransactions.addAll( currentOldChainWithReceipts.getBlock().getBody().getTransactions()); - addAddedLogsWithMetadata(logsWithMetadata, currentNewChainWithReceipts); - addRemovedLogsWithMetadata(logsWithMetadata, currentOldChainWithReceipts); + addAddedLogsWithMetadata(addedLogsWithMetadata, currentNewChainWithReceipts); + addRemovedLogsWithMetadata(removedLogsWithMetadata, currentOldChainWithReceipts); currentNewChainWithReceipts = getParentBlockWithReceipts(currentNewChainWithReceipts); currentOldChainWithReceipts = getParentBlockWithReceipts(currentOldChainWithReceipts); @@ -401,7 +403,8 @@ private BlockAddedEvent handleChainReorg( newChainHeadWithReceipts.getBlock(), newTransactions.values().stream().flatMap(Collection::stream).collect(toList()), removedTransactions, - new ArrayList<>(logsWithMetadata)); + Stream.concat(removedLogsWithMetadata.stream(), addedLogsWithMetadata.stream()) + .collect(Collectors.toUnmodifiableList())); } @Override @@ -503,19 +506,19 @@ private boolean blockIsConnected(final Block block) { } private void addAddedLogsWithMetadata( - final Deque logsWithMetadata, final BlockWithReceipts blockWithReceipts) { + final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { logsWithMetadata.addAll( + 0, LogWithMetadata.generate( blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), false)); } private void addRemovedLogsWithMetadata( - final Deque logsWithMetadata, final BlockWithReceipts blockWithReceipts) { - for (final LogWithMetadata logWithMetadata : - LogWithMetadata.generate( - blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), true)) { - logsWithMetadata.addFirst(logWithMetadata); - } + final List logsWithMetadata, final BlockWithReceipts blockWithReceipts) { + logsWithMetadata.addAll( + Lists.reverse( + LogWithMetadata.generate( + blockWithReceipts.getBlock(), blockWithReceipts.getReceipts(), true))); } private Optional getBlockWithReceipts(final BlockHeader blockHeader) { diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index 79a616f22a3..1404d042452 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -19,11 +19,12 @@ import org.hyperledger.besu.util.bytes.BytesValue; import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import com.google.common.base.MoreObjects; -public class LogWithMetadata extends Log { +public class LogWithMetadata extends Log implements Comparable { private final int logIndex; private final long blockNumber; @@ -140,6 +141,24 @@ public boolean isRemoved() { return removed; } + @Override + public int compareTo(final LogWithMetadata other) { + // here chronology is block chronology, not real time chronology. + final var chronologicalOrder = + Comparator.comparingLong(LogWithMetadata::getBlockNumber) + .thenComparingInt(LogWithMetadata::getTransactionIndex) + .thenComparingInt(LogWithMetadata::getLogIndex); + + final int removedCompare = Boolean.compare(this.removed, other.isRemoved()); + if (removedCompare != 0) { // sort removed logs (true) before added logs (false) + return -removedCompare; + } else if (removed) { // if we're sorting removed logs, reverse chronological + return chronologicalOrder.reversed().compare(this, other); + } else { // if we're sorting added logs, chronological + return chronologicalOrder.compare(this, other); + } + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java index 8495e27bd31..7ec4c028fb2 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchainTest.java @@ -440,8 +440,15 @@ public void appendBlockWithReorgToLongerChain() { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } final Block originalHead = chain.get(originalChainLength - 1); @@ -508,6 +515,19 @@ public void appendBlockWithReorgToLongerChain() { for (final Transaction tx : removedTransactions) { assertThat(blockchain.getTransactionByHash(tx.getHash())).isNotPresent(); } + // LogWithMetadata reflecting removal of logs + for (int i = originalChainLength - 1; i >= forkStart; i--) { + final Block currentBlock = chain.get(i); + expectedLogsWithMetadata.addAll( + Lists.reverse( + LogWithMetadata.generate( + currentBlock, blockchain.getTxReceipts(currentBlock.getHash()).get(), true))); + } + // LogWithMetadata reflecting addition of logs + for (int i = 0; i < forkBlocks.size(); i++) { + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(forkBlocks.get(i), forkReceipts.get(i), false)); + } // Old chain head should now be tracked as a fork. forks = blockchain.getForks(); assertThat(forks.size()).isEqualTo(1); @@ -516,6 +536,8 @@ public void appendBlockWithReorgToLongerChain() { for (int i = commonAncestor + 1; i < originalChainLength; i++) { assertThat(blockchain.blockIsOnCanonicalChain(chain.get(i).getHash())).isFalse(); } + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test @@ -529,8 +551,15 @@ public void reorgWithOverlappingTransactions() { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } final Transaction overlappingTx = chain.get(chainLength - 1).getBody().getTransactions().get(0); @@ -569,6 +598,18 @@ public void reorgWithOverlappingTransactions() { assertThat(actualTransaction).isNotPresent(); } } + // LogWithMetadata reflecting removal of logs + for (int i = chainLength - 1; i >= forkBlock; i--) { + final Block currentBlock = chain.get(i); + expectedLogsWithMetadata.addAll( + Lists.reverse( + LogWithMetadata.generate( + currentBlock, blockchain.getTxReceipts(currentBlock.getHash()).get(), true))); + } + // LogWithMetadata reflecting addition of logs + expectedLogsWithMetadata.addAll(LogWithMetadata.generate(fork, forkReceipts, false)); + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test @@ -621,8 +662,15 @@ public void appendBlockForFork() { chain.stream().map(gen::receipts).collect(Collectors.toList()); final KeyValueStorage kvStore = new InMemoryKeyValueStorage(); final DefaultBlockchain blockchain = createMutableBlockchain(kvStore, chain.get(0)); + // Listen to block events and add the Logs here + List logsWithMetadata = new ArrayList<>(); + blockchain.observeBlockAdded( + (event, __) -> logsWithMetadata.addAll(event.getLogsWithMetadata())); + List expectedLogsWithMetadata = new ArrayList<>(); for (int i = 1; i < chain.size(); i++) { blockchain.appendBlock(chain.get(i), blockReceipts.get(i)); + expectedLogsWithMetadata.addAll( + LogWithMetadata.generate(chain.get(i), blockReceipts.get(i), false)); } final Block originalHead = chain.get(originalChainLength - 1); @@ -690,6 +738,9 @@ public void appendBlockForFork() { // Head should not have changed assertBlockIsHead(blockchain, originalHead); + // We should only have the log events from when we initially created the chain. None from forks. + assertThat(logsWithMetadata) + .containsExactly(expectedLogsWithMetadata.toArray(new LogWithMetadata[] {})); } @Test From 257e1d69b9548f388d709292d9bcb5d5b2c6b216 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Tue, 22 Oct 2019 12:38:17 -0400 Subject: [PATCH 35/40] remove comparison Signed-off-by: Ratan Rai Sur --- .../besu/ethereum/core/LogWithMetadata.java | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java index 1404d042452..79a616f22a3 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/LogWithMetadata.java @@ -19,12 +19,11 @@ import org.hyperledger.besu.util.bytes.BytesValue; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; import com.google.common.base.MoreObjects; -public class LogWithMetadata extends Log implements Comparable { +public class LogWithMetadata extends Log { private final int logIndex; private final long blockNumber; @@ -141,24 +140,6 @@ public boolean isRemoved() { return removed; } - @Override - public int compareTo(final LogWithMetadata other) { - // here chronology is block chronology, not real time chronology. - final var chronologicalOrder = - Comparator.comparingLong(LogWithMetadata::getBlockNumber) - .thenComparingInt(LogWithMetadata::getTransactionIndex) - .thenComparingInt(LogWithMetadata::getLogIndex); - - final int removedCompare = Boolean.compare(this.removed, other.isRemoved()); - if (removedCompare != 0) { // sort removed logs (true) before added logs (false) - return -removedCompare; - } else if (removed) { // if we're sorting removed logs, reverse chronological - return chronologicalOrder.reversed().compare(this, other); - } else { // if we're sorting added logs, chronological - return chronologicalOrder.compare(this, other); - } - } - @Override public String toString() { return MoreObjects.toStringHelper(this) From e02f37e79105ce9e96fded7dd64ad75339ed2475 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 23 Oct 2019 09:57:07 -0400 Subject: [PATCH 36/40] findAny Signed-off-by: Ratan Rai Sur --- .../org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java index 4f6a6ba2889..713d7184350 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/chain/DefaultBlockchain.java @@ -314,7 +314,7 @@ private BlockAddedEvent handleFork(final BlockchainStorage.Updater updater, fina // This block will replace its parent forkHeads.stream() .filter(head -> head.equals(fork.getHeader().getParentHash())) - .findFirst() + .findAny() .ifPresent(forkHeads::remove); forkHeads.add(fork.getHash()); From d481a0b85cda8a7a216cdbb9e845f4f851754428 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 23 Oct 2019 10:03:09 -0400 Subject: [PATCH 37/40] final Signed-off-by: Ratan Rai Sur --- .../hyperledger/besu/ethereum/api/query/BlockchainQueries.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index b5d429027ff..04937ad99d0 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -498,7 +498,7 @@ public List matchingLogs( } public List matchingLogs(final Hash blockHash, final LogsQuery query) { - Optional blockHeader = blockchain.getBlockHeader(blockHash); + final Optional blockHeader = blockchain.getBlockHeader(blockHash); if (blockHeader.isEmpty()) { return Collections.emptyList(); } From 0e2a40227595d1334c417d9e6e33e5534dcd21d7 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Wed, 23 Oct 2019 10:07:52 -0400 Subject: [PATCH 38/40] bytesValue size range Signed-off-by: Ratan Rai Sur --- .../ethereum/core/BlockDataGenerator.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java index ef6b3e4785d..f58a4b38dff 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/BlockDataGenerator.java @@ -386,7 +386,7 @@ public Log log() { public Log log(final int topicCount) { final List topics = Stream.generate(this::logTopic).limit(topicCount).collect(Collectors.toList()); - return new Log(address(), bytesValue(5 + random.nextInt(10)), topics); + return new Log(address(), bytesValue(5, 15), topics); } private LogTopic logTopic() { @@ -401,6 +401,18 @@ public BytesValue bytesValue(final int size) { return BytesValue.wrap(bytes(size)); } + public BytesValue bytesValue() { + return bytesValue(1, 20); + } + + public BytesValue bytesValue(final int minSize, final int maxSize) { + checkArgument(minSize >= 0); + checkArgument(maxSize >= 0); + checkArgument(maxSize > minSize); + final int size = random.nextInt(maxSize - minSize) + minSize; + return BytesValue.wrap(bytes(size)); + } + /** * Creates a UInt256 with a value that fits within maxByteSize * @@ -433,18 +445,6 @@ public LogsBloomFilter logsBloom() { return new LogsBloomFilter(BytesValue.of(bytes(LogsBloomFilter.BYTE_SIZE))); } - public BytesValue bytesValue() { - return bytesValue(1, 20); - } - - public BytesValue bytesValue(final int minSize, final int maxSize) { - checkArgument(minSize >= 0); - checkArgument(maxSize >= 0); - checkArgument(maxSize > minSize); - final int size = random.nextInt(maxSize - minSize) + minSize; - return BytesValue.wrap(bytes(size)); - } - private byte[] bytes(final int size) { return bytes(size, 0); } From 64675cdad31e1180e991a0c26158accbaf844fb4 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 24 Oct 2019 10:10:53 -0400 Subject: [PATCH 39/40] return up to to block in query matching Signed-off-by: Ratan Rai Sur --- .../ethereum/api/query/BlockchainQueries.java | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java index 04937ad99d0..331eeb76edd 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/query/BlockchainQueries.java @@ -38,7 +38,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.NoSuchElementException; import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -487,14 +486,12 @@ public Optional transactionReceiptByTransactionH */ public List matchingLogs( final long fromBlockNumber, final long toBlockNumber, final LogsQuery query) { - try { - return LongStream.rangeClosed(fromBlockNumber, toBlockNumber) - .mapToObj(i -> matchingLogs(blockchain.getBlockHashByNumber(i).get(), query)) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - } catch (NoSuchElementException nsee) { - return Collections.emptyList(); - } + return LongStream.rangeClosed(fromBlockNumber, toBlockNumber) + .mapToObj(blockchain::getBlockHashByNumber) + .takeWhile(Optional::isPresent) + .flatMap(Optional::stream) + .flatMap(hash -> matchingLogs(hash, query).stream()) + .collect(Collectors.toList()); } public List matchingLogs(final Hash blockHash, final LogsQuery query) { From ac9524681a87871fad6dfc967e41583003ada063 Mon Sep 17 00:00:00 2001 From: Ratan Rai Sur Date: Thu, 24 Oct 2019 10:58:26 -0400 Subject: [PATCH 40/40] fix toBlock spec test Signed-off-by: Ratan Rai Sur --- .../eth/eth_getLogs_toBlockOutOfRange.json | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_toBlockOutOfRange.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_toBlockOutOfRange.json index fbbe13dcde1..22cbf3e71e1 100644 --- a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_toBlockOutOfRange.json +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_getLogs_toBlockOutOfRange.json @@ -3,17 +3,40 @@ "id": 406, "jsonrpc": "2.0", "method": "eth_getLogs", - "params": [{ - "fromBlock": "0x17", - "toBlock": "0x21", - "address": [], - "topics": [["0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", null]] - }] + "params": [ + { + "fromBlock": "0x20", + "toBlock": "0x21", + "address": [], + "topics": [ + [ + "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + null + ] + ] + } + ] }, "response": { "jsonrpc": "2.0", "id": 406, - "result" : [] + "result": [ + { + "logIndex": "0x0", + "removed": false, + "blockNumber": "0x20", + "blockHash": "0x71d59849ddd98543bdfbe8548f5eed559b07b8aaf196369f39134500eab68e53", + "transactionHash": "0xcef53f2311d7c80e9086d661e69ac11a5f3d081e28e02a9ba9b66749407ac310", + "transactionIndex": "0x0", + "address": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe9000000000000000000000000000000000000000000000000000000000000002a", + "topics": [ + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x000000000000000000000000a94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" + ] + } + ] }, "statusCode": 200 } \ No newline at end of file