From d9916ec985a3558b09d4a1bbb4d2046d84b66a02 Mon Sep 17 00:00:00 2001 From: Adrian Sutton Date: Thu, 17 Jan 2019 12:49:05 +1000 Subject: [PATCH] Support responding to GetNodeData requests. --- .../protocol/Istanbul64ProtocolManager.java | 4 +- .../ethereum/db/WorldStateArchive.java | 7 ++ .../KeyValueStorageWorldStateStorage.java | 5 ++ .../worldstate/WorldStateStorage.java | 2 + .../eth/manager/EthProtocolManager.java | 16 ++++- .../ethereum/eth/manager/EthServer.java | 19 ++++-- .../eth/manager/EthProtocolManagerTest.java | 63 +++++++++++------ .../manager/EthProtocolManagerTestUtil.java | 21 ++++-- .../ethereum/eth/manager/EthServerTest.java | 68 +++++++++++++++++++ .../eth/manager/RespondingEthPeer.java | 9 ++- .../ethtaskutils/AbstractMessageTaskTest.java | 4 +- .../eth/sync/BlockPropagationManagerTest.java | 3 +- .../eth/sync/ChainHeadTrackerTest.java | 11 +-- .../ethereum/eth/sync/DownloaderTest.java | 3 +- ...neCommonAncestorTaskParameterizedTest.java | 6 +- .../DetermineCommonAncestorTaskTest.java | 7 +- .../ethereum/eth/transactions/TestNode.java | 2 +- .../controller/CliquePantheonController.java | 1 + .../IbftLegacyPantheonController.java | 2 + .../controller/IbftPantheonController.java | 1 + .../controller/MainnetPantheonController.java | 1 + 21 files changed, 208 insertions(+), 47 deletions(-) create mode 100644 ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthServerTest.java diff --git a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/protocol/Istanbul64ProtocolManager.java b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/protocol/Istanbul64ProtocolManager.java index ecbd355d51..76e5e53c33 100644 --- a/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/protocol/Istanbul64ProtocolManager.java +++ b/consensus/ibftlegacy/src/main/java/tech/pegasys/pantheon/consensus/ibftlegacy/protocol/Istanbul64ProtocolManager.java @@ -13,6 +13,7 @@ package tech.pegasys.pantheon.consensus.ibftlegacy.protocol; import tech.pegasys.pantheon.ethereum.chain.Blockchain; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; import tech.pegasys.pantheon.ethereum.eth.EthProtocol; import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManager; import tech.pegasys.pantheon.ethereum.p2p.api.Message; @@ -27,11 +28,12 @@ public class Istanbul64ProtocolManager extends EthProtocolManager { public Istanbul64ProtocolManager( final Blockchain blockchain, + final WorldStateArchive worldStateArchive, final int networkId, final boolean fastSyncEnabled, final int syncWorkers, final int txWorkers) { - super(blockchain, networkId, fastSyncEnabled, syncWorkers, txWorkers); + super(blockchain, worldStateArchive, networkId, fastSyncEnabled, syncWorkers, txWorkers); } @Override diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/WorldStateArchive.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/WorldStateArchive.java index 4a13c62417..b5a1bf14ec 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/WorldStateArchive.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/db/WorldStateArchive.java @@ -18,6 +18,9 @@ import tech.pegasys.pantheon.ethereum.trie.MerklePatriciaTrie; import tech.pegasys.pantheon.ethereum.worldstate.DefaultMutableWorldState; import tech.pegasys.pantheon.ethereum.worldstate.WorldStateStorage; +import tech.pegasys.pantheon.util.bytes.BytesValue; + +import java.util.Optional; public class WorldStateArchive { private final WorldStateStorage storage; @@ -42,4 +45,8 @@ public WorldState get() { public MutableWorldState getMutable() { return getMutable(EMPTY_ROOT_HASH); } + + public Optional getNodeData(final Hash hash) { + return storage.getNodeData(hash); + } } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorage.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorage.java index df51c05bd7..b300ece3b0 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorage.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/storage/keyvalue/KeyValueStorageWorldStateStorage.java @@ -43,6 +43,11 @@ public Optional getAccountStorageTrieNode(final Bytes32 nodeHash) { return keyValueStorage.get(nodeHash); } + @Override + public Optional getNodeData(final Hash hash) { + return keyValueStorage.get(hash); + } + @Override public Updater updater() { return new Updater(keyValueStorage.startTransaction()); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/WorldStateStorage.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/WorldStateStorage.java index 8ddf806692..ac2a30af90 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/WorldStateStorage.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/WorldStateStorage.java @@ -26,6 +26,8 @@ public interface WorldStateStorage { Optional getAccountStorageTrieNode(Bytes32 nodeHash); + Optional getNodeData(Hash hash); + Updater updater(); interface Updater { diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManager.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManager.java index ff0d8044d8..29c01be113 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManager.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManager.java @@ -18,6 +18,7 @@ import tech.pegasys.pantheon.ethereum.chain.MinedBlockObserver; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.Hash; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; import tech.pegasys.pantheon.ethereum.eth.EthProtocol; import tech.pegasys.pantheon.ethereum.eth.messages.EthPV62; import tech.pegasys.pantheon.ethereum.eth.messages.NewBlockMessage; @@ -65,6 +66,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { EthProtocolManager( final Blockchain blockchain, + final WorldStateArchive worldStateArchive, final int networkId, final boolean fastSyncEnabled, final int requestLimit, @@ -83,11 +85,12 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { ethContext = new EthContext(getSupportedProtocol(), ethPeers, ethMessages, scheduler); // Set up request handlers - new EthServer(blockchain, ethMessages, requestLimit); + new EthServer(blockchain, worldStateArchive, ethMessages, requestLimit); } EthProtocolManager( final Blockchain blockchain, + final WorldStateArchive worldStateArchive, final int networkId, final boolean fastSyncEnabled, final int syncWorkers, @@ -95,6 +98,7 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { final int requestLimit) { this( blockchain, + worldStateArchive, networkId, fastSyncEnabled, requestLimit, @@ -103,11 +107,19 @@ public class EthProtocolManager implements ProtocolManager, MinedBlockObserver { public EthProtocolManager( final Blockchain blockchain, + final WorldStateArchive worldStateArchive, final int networkId, final boolean fastSyncEnabled, final int syncWorkers, final int txWorkers) { - this(blockchain, networkId, fastSyncEnabled, syncWorkers, txWorkers, DEFAULT_REQUEST_LIMIT); + this( + blockchain, + worldStateArchive, + networkId, + fastSyncEnabled, + syncWorkers, + txWorkers, + DEFAULT_REQUEST_LIMIT); } public EthContext ethContext() { diff --git a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthServer.java b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthServer.java index 7125c01139..f74fc18282 100644 --- a/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthServer.java +++ b/ethereum/eth/src/main/java/tech/pegasys/pantheon/ethereum/eth/manager/EthServer.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; import tech.pegasys.pantheon.ethereum.eth.messages.BlockBodiesMessage; import tech.pegasys.pantheon.ethereum.eth.messages.BlockHeadersMessage; import tech.pegasys.pantheon.ethereum.eth.messages.EthPV62; @@ -47,11 +48,17 @@ class EthServer { private static final Logger LOG = LogManager.getLogger(); private final Blockchain blockchain; + private final WorldStateArchive worldStateArchive; private final EthMessages ethMessages; private final int requestLimit; - EthServer(final Blockchain blockchain, final EthMessages ethMessages, final int requestLimit) { + EthServer( + final Blockchain blockchain, + final WorldStateArchive worldStateArchive, + final EthMessages ethMessages, + final int requestLimit) { this.blockchain = blockchain; + this.worldStateArchive = worldStateArchive; this.ethMessages = ethMessages; this.requestLimit = requestLimit; this.setupListeners(); @@ -106,7 +113,8 @@ private void handleGetReceipts(final EthMessage message) { private void handleGetNodeData(final EthMessage message) { LOG.trace("Responding to GET_NODE_DATA request"); try { - final MessageData response = constructGetNodeDataResponse(message.getData(), requestLimit); + final MessageData response = + constructGetNodeDataResponse(worldStateArchive, message.getData(), requestLimit); message.getPeer().send(response); } catch (final RLPException e) { message.getPeer().disconnect(DisconnectReason.BREACH_OF_PROTOCOL); @@ -195,7 +203,9 @@ static MessageData constructGetReceiptsResponse( } static MessageData constructGetNodeDataResponse( - final MessageData message, final int requestLimit) { + final WorldStateArchive worldStateArchive, + final MessageData message, + final int requestLimit) { final GetNodeDataMessage getNodeDataMessage = GetNodeDataMessage.readFrom(message); final Iterable hashes = getNodeDataMessage.hashes(); @@ -206,7 +216,8 @@ static MessageData constructGetNodeDataResponse( break; } count++; - // TODO: Lookup node data and add it to the list + + worldStateArchive.getNodeData(hash).ifPresent(nodeData::add); } return NodeDataMessage.create(nodeData); } diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java index c99019e251..13f1e57b15 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTest.java @@ -97,7 +97,8 @@ public static void setup() { @Test public void disconnectOnUnsolicitedMessage() { - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final MessageData messageData = BlockHeadersMessage.create(Collections.singletonList(blockchain.getBlockHeader(1).get())); final MockPeerConnection peer = setupPeer(ethManager, (cap, msg, conn) -> {}); @@ -108,7 +109,8 @@ public void disconnectOnUnsolicitedMessage() { @Test public void disconnectOnFailureToSendStatusMessage() { - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final MessageData messageData = BlockHeadersMessage.create(Collections.singletonList(blockchain.getBlockHeader(1).get())); final MockPeerConnection peer = @@ -120,7 +122,8 @@ public void disconnectOnFailureToSendStatusMessage() { @Test public void disconnectOnWrongChainId() { - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final MessageData messageData = BlockHeadersMessage.create(Collections.singletonList(blockchain.getBlockHeader(1).get())); final MockPeerConnection peer = @@ -143,7 +146,8 @@ public void disconnectOnWrongChainId() { @Test public void disconnectOnWrongGenesisHash() { - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final MessageData messageData = BlockHeadersMessage.create(Collections.singletonList(blockchain.getBlockHeader(1).get())); final MockPeerConnection peer = @@ -166,7 +170,8 @@ public void disconnectOnWrongGenesisHash() { @Test(expected = ConditionTimeoutException.class) public void doNotDisconnectOnValidMessage() { - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final MessageData messageData = GetBlockBodiesMessage.create(Collections.singletonList(gen.hash())); final MockPeerConnection peer = setupPeer(ethManager, (cap, msg, conn) -> {}); @@ -181,7 +186,8 @@ public void doNotDisconnectOnValidMessage() { @Test public void respondToGetHeaders() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final long startBlock = 5L; final int blockCount = 5; final MessageData messageData = @@ -213,7 +219,8 @@ public void respondToGetHeadersWithinLimits() throws ExecutionException, Interru final CompletableFuture done = new CompletableFuture<>(); final int limit = 5; try (final EthProtocolManager ethManager = - new EthProtocolManager(blockchain, 1, true, 1, 1, limit)) { + new EthProtocolManager( + blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1, limit)) { final long startBlock = 5L; final int blockCount = 10; final MessageData messageData = @@ -243,7 +250,8 @@ public void respondToGetHeadersWithinLimits() throws ExecutionException, Interru @Test public void respondToGetHeadersReversed() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final long endBlock = 10L; final int blockCount = 5; final MessageData messageData = GetBlockHeadersMessage.create(endBlock, blockCount, 0, true); @@ -272,7 +280,8 @@ public void respondToGetHeadersReversed() throws ExecutionException, Interrupted @Test public void respondToGetHeadersWithSkip() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final long startBlock = 5L; final int blockCount = 5; final int skip = 1; @@ -304,7 +313,8 @@ public void respondToGetHeadersWithSkip() throws ExecutionException, Interrupted public void respondToGetHeadersReversedWithSkip() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final long endBlock = 10L; final int blockCount = 5; final int skip = 1; @@ -357,7 +367,8 @@ private MockPeerConnection setupPeerWithoutStatusExchange( @Test public void respondToGetHeadersPartial() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final long startBlock = blockchain.getChainHeadBlockNumber() - 1L; final int blockCount = 5; final MessageData messageData = @@ -387,7 +398,8 @@ public void respondToGetHeadersPartial() throws ExecutionException, InterruptedE @Test public void respondToGetHeadersEmpty() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final long startBlock = blockchain.getChainHeadBlockNumber() + 1; final int blockCount = 5; final MessageData messageData = @@ -414,7 +426,8 @@ public void respondToGetHeadersEmpty() throws ExecutionException, InterruptedExc @Test public void respondToGetBodies() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { // Setup blocks query final long startBlock = blockchain.getChainHeadBlockNumber() - 5; final int blockCount = 2; @@ -458,7 +471,8 @@ public void respondToGetBodiesWithinLimits() throws ExecutionException, Interrup final CompletableFuture done = new CompletableFuture<>(); final int limit = 5; try (final EthProtocolManager ethManager = - new EthProtocolManager(blockchain, 1, true, 1, 1, limit)) { + new EthProtocolManager( + blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1, limit)) { // Setup blocks query final int blockCount = 10; final long startBlock = blockchain.getChainHeadBlockNumber() - blockCount; @@ -500,7 +514,8 @@ public void respondToGetBodiesWithinLimits() throws ExecutionException, Interrup @Test public void respondToGetBodiesPartial() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { // Setup blocks query final long expectedBlockNumber = blockchain.getChainHeadBlockNumber() - 1; final BlockHeader header = blockchain.getBlockHeader(expectedBlockNumber).get(); @@ -536,7 +551,8 @@ public void respondToGetBodiesPartial() throws ExecutionException, InterruptedEx @Test public void respondToGetReceipts() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { // Setup blocks query final long startBlock = blockchain.getChainHeadBlockNumber() - 5; final int blockCount = 2; @@ -579,7 +595,8 @@ public void respondToGetReceiptsWithinLimits() throws ExecutionException, Interr final CompletableFuture done = new CompletableFuture<>(); final int limit = 5; try (final EthProtocolManager ethManager = - new EthProtocolManager(blockchain, 1, true, 1, 1, limit)) { + new EthProtocolManager( + blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1, limit)) { // Setup blocks query final int blockCount = 10; final long startBlock = blockchain.getChainHeadBlockNumber() - blockCount; @@ -620,7 +637,8 @@ public void respondToGetReceiptsWithinLimits() throws ExecutionException, Interr @Test public void respondToGetReceiptsPartial() throws ExecutionException, InterruptedException { final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { // Setup blocks query final long blockNumber = blockchain.getChainHeadBlockNumber() - 5; final BlockHeader header = blockchain.getBlockHeader(blockNumber).get(); @@ -655,7 +673,8 @@ public void respondToGetReceiptsPartial() throws ExecutionException, Interrupted @Test public void newBlockMinedSendsNewBlockMessageToAllPeers() { - final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1); + final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1); // Define handler to validate response final PeerSendHandler onSend = mock(PeerSendHandler.class); @@ -718,7 +737,8 @@ public void shouldSuccessfullyRespondToGetHeadersRequestLessThanZero() blockchain.appendBlock(block, receipts); final CompletableFuture done = new CompletableFuture<>(); - try (final EthProtocolManager ethManager = new EthProtocolManager(blockchain, 1, true, 1, 1)) { + try (final EthProtocolManager ethManager = + new EthProtocolManager(blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, 1)) { final long startBlock = 1L; final int requestedBlockCount = 13; final int receivedBlockCount = 2; @@ -774,7 +794,8 @@ public void transactionMessagesGoToTheCorrectExecutor() { final TransactionsMessage transactionMessage = TransactionsMessage.readFrom(raw); try (final EthProtocolManager ethManager = - new EthProtocolManager(blockchain, 1, true, 1, ethScheduler)) { + new EthProtocolManager( + blockchain, protocolContext.getWorldStateArchive(), 1, true, 1, ethScheduler)) { // Create a transaction pool. This has a side effect of registring a listener for the // transactions message. diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTestUtil.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTestUtil.java index effb5cea2b..d3b65c92fc 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTestUtil.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthProtocolManagerTestUtil.java @@ -13,11 +13,13 @@ package tech.pegasys.pantheon.ethereum.eth.manager; import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryBlockchain; +import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive; import tech.pegasys.pantheon.config.GenesisConfigFile; import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.chain.ChainHead; import tech.pegasys.pantheon.ethereum.chain.GenesisState; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; import tech.pegasys.pantheon.ethereum.eth.EthProtocol; import tech.pegasys.pantheon.ethereum.eth.manager.DeterministicEthScheduler.TimeoutPolicy; import tech.pegasys.pantheon.ethereum.mainnet.MainnetProtocolSchedule; @@ -30,15 +32,23 @@ public class EthProtocolManagerTestUtil { public static EthProtocolManager create( - final Blockchain blockchain, final TimeoutPolicy timeoutPolicy) { + final Blockchain blockchain, + final WorldStateArchive worldStateArchive, + final TimeoutPolicy timeoutPolicy) { final int networkId = 1; final EthScheduler ethScheduler = new DeterministicEthScheduler(timeoutPolicy); return new EthProtocolManager( - blockchain, networkId, false, EthProtocolManager.DEFAULT_REQUEST_LIMIT, ethScheduler); + blockchain, + worldStateArchive, + networkId, + false, + EthProtocolManager.DEFAULT_REQUEST_LIMIT, + ethScheduler); } - public static EthProtocolManager create(final Blockchain blockchain) { - return create(blockchain, () -> false); + public static EthProtocolManager create( + final Blockchain blockchain, final WorldStateArchive worldStateArchive) { + return create(blockchain, worldStateArchive, () -> false); } public static EthProtocolManager create() { @@ -47,7 +57,8 @@ public static EthProtocolManager create() { final GenesisConfigFile config = GenesisConfigFile.mainnet(); final GenesisState genesisState = GenesisState.fromConfig(config, protocolSchedule); final Blockchain blockchain = createInMemoryBlockchain(genesisState.getBlock()); - return create(blockchain); + final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); + return create(blockchain, worldStateArchive); } public static void broadcastMessage( diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthServerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthServerTest.java new file mode 100644 index 0000000000..2761e7f67a --- /dev/null +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/EthServerTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.eth.manager; + +import static java.util.Arrays.asList; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import tech.pegasys.pantheon.ethereum.chain.Blockchain; +import tech.pegasys.pantheon.ethereum.core.Hash; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; +import tech.pegasys.pantheon.ethereum.eth.messages.GetNodeDataMessage; +import tech.pegasys.pantheon.ethereum.eth.messages.NodeDataMessage; +import tech.pegasys.pantheon.util.bytes.BytesValue; + +import java.util.Optional; + +import org.junit.Before; +import org.junit.Test; + +public class EthServerTest { + + private static final BytesValue VALUE1 = BytesValue.of(1); + private static final BytesValue VALUE2 = BytesValue.of(2); + private static final BytesValue VALUE3 = BytesValue.of(3); + private static final Hash HASH1 = Hash.hash(VALUE1); + private static final Hash HASH2 = Hash.hash(VALUE2); + private static final Hash HASH3 = Hash.hash(VALUE3); + private final Blockchain blockchain = mock(Blockchain.class); + private final WorldStateArchive worldStateArchive = mock(WorldStateArchive.class); + private final EthPeer ethPeer = mock(EthPeer.class); + private final EthMessages ethMessages = new EthMessages(); + + @Before + public void setUp() { + new EthServer(blockchain, worldStateArchive, ethMessages, 2); + } + + @Test + public void shouldRespondToNodeDataRequests() throws Exception { + when(worldStateArchive.getNodeData(HASH1)).thenReturn(Optional.of(VALUE1)); + when(worldStateArchive.getNodeData(HASH2)).thenReturn(Optional.of(VALUE2)); + ethMessages.dispatch(new EthMessage(ethPeer, GetNodeDataMessage.create(asList(HASH1, HASH2)))); + + verify(ethPeer).send(NodeDataMessage.create(asList(VALUE1, VALUE2))); + } + + @Test + public void shouldLimitNumberOfResponsesToNodeDataRequests() throws Exception { + when(worldStateArchive.getNodeData(HASH1)).thenReturn(Optional.of(VALUE1)); + when(worldStateArchive.getNodeData(HASH2)).thenReturn(Optional.of(VALUE2)); + ethMessages.dispatch( + new EthMessage(ethPeer, GetNodeDataMessage.create(asList(HASH1, HASH2, HASH3)))); + + verify(ethPeer).send(NodeDataMessage.create(asList(VALUE1, VALUE2))); + } +} diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/RespondingEthPeer.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/RespondingEthPeer.java index 68e7b8e795..303e9165a6 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/RespondingEthPeer.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/RespondingEthPeer.java @@ -13,6 +13,7 @@ package tech.pegasys.pantheon.ethereum.eth.manager; import static com.google.common.base.Preconditions.checkArgument; +import static tech.pegasys.pantheon.ethereum.core.InMemoryStorageProvider.createInMemoryWorldStateArchive; import tech.pegasys.pantheon.ethereum.chain.Blockchain; import tech.pegasys.pantheon.ethereum.core.BlockBody; @@ -20,6 +21,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.Hash; import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; import tech.pegasys.pantheon.ethereum.eth.EthProtocol; import tech.pegasys.pantheon.ethereum.eth.messages.BlockBodiesMessage; import tech.pegasys.pantheon.ethereum.eth.messages.BlockHeadersMessage; @@ -177,6 +179,11 @@ public boolean hasOutstandingRequests() { } public static Responder blockchainResponder(final Blockchain blockchain) { + return blockchainResponder(blockchain, createInMemoryWorldStateArchive()); + } + + public static Responder blockchainResponder( + final Blockchain blockchain, final WorldStateArchive worldStateArchive) { return (cap, msg) -> { MessageData response = null; switch (msg.getCode()) { @@ -190,7 +197,7 @@ public static Responder blockchainResponder(final Blockchain blockchain) { response = EthServer.constructGetReceiptsResponse(blockchain, msg, 200); break; case EthPV63.GET_NODE_DATA: - response = EthServer.constructGetNodeDataResponse(msg, 200); + response = EthServer.constructGetNodeDataResponse(worldStateArchive, msg, 200); break; } return Optional.ofNullable(response); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java index b3671c3cb1..59661a924c 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/manager/ethtaskutils/AbstractMessageTaskTest.java @@ -69,7 +69,9 @@ public void setupTest() { peerCountToTimeout = new AtomicInteger(0); ethProtocolManager = EthProtocolManagerTestUtil.create( - blockchain, () -> peerCountToTimeout.getAndDecrement() > 0 || peersDoTimeout.get()); + blockchain, + protocolContext.getWorldStateArchive(), + () -> peerCountToTimeout.getAndDecrement() > 0 || peersDoTimeout.get()); ethContext = ethProtocolManager.ethContext(); } diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java index 57d8e74bbf..0c411d043f 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/BlockPropagationManagerTest.java @@ -86,7 +86,8 @@ public void setup() { blockchain, tempProtocolContext.getWorldStateArchive(), tempProtocolContext.getConsensusState()); - ethProtocolManager = EthProtocolManagerTestUtil.create(blockchain); + ethProtocolManager = + EthProtocolManagerTestUtil.create(blockchain, blockchainUtil.getWorldArchive()); syncConfig = SynchronizerConfiguration.builder() .blockPropagationRange(-3, 5) diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/ChainHeadTrackerTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/ChainHeadTrackerTest.java index d310658fe6..03bb7f633c 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/ChainHeadTrackerTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/ChainHeadTrackerTest.java @@ -36,7 +36,7 @@ public class ChainHeadTrackerTest { private final BlockchainSetupUtil blockchainSetupUtil = BlockchainSetupUtil.forTesting(); private final MutableBlockchain blockchain = blockchainSetupUtil.getBlockchain(); private final EthProtocolManager ethProtocolManager = - EthProtocolManagerTestUtil.create(blockchain); + EthProtocolManagerTestUtil.create(blockchain, blockchainSetupUtil.getWorldArchive()); private final RespondingEthPeer respondingPeer = RespondingEthPeer.create( ethProtocolManager, @@ -57,7 +57,8 @@ public class ChainHeadTrackerTest { @Test public void shouldRequestHeaderChainHeadWhenNewPeerConnects() { final Responder responder = - RespondingEthPeer.blockchainResponder(blockchainSetupUtil.getBlockchain()); + RespondingEthPeer.blockchainResponder( + blockchainSetupUtil.getBlockchain(), blockchainSetupUtil.getWorldArchive()); chainHeadTracker.onPeerConnected(respondingPeer.getEthPeer()); assertThat(chainHeadState().getEstimatedHeight()).isZero(); @@ -71,7 +72,8 @@ public void shouldRequestHeaderChainHeadWhenNewPeerConnects() { @Test public void shouldIgnoreHeadersIfChainHeadHasAlreadyBeenUpdatedWhileWaiting() { final Responder responder = - RespondingEthPeer.blockchainResponder(blockchainSetupUtil.getBlockchain()); + RespondingEthPeer.blockchainResponder( + blockchainSetupUtil.getBlockchain(), blockchainSetupUtil.getWorldArchive()); chainHeadTracker.onPeerConnected(respondingPeer.getEthPeer()); // Change the hash of the current known head @@ -85,7 +87,8 @@ public void shouldIgnoreHeadersIfChainHeadHasAlreadyBeenUpdatedWhileWaiting() { @Test public void shouldCheckTrialingPeerLimits() { final Responder responder = - RespondingEthPeer.blockchainResponder(blockchainSetupUtil.getBlockchain()); + RespondingEthPeer.blockchainResponder( + blockchainSetupUtil.getBlockchain(), blockchainSetupUtil.getWorldArchive()); chainHeadTracker.onPeerConnected(respondingPeer.getEthPeer()); assertThat(chainHeadState().getEstimatedHeight()).isZero(); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/DownloaderTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/DownloaderTest.java index 61635ab2d5..0d4e169531 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/DownloaderTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/DownloaderTest.java @@ -80,7 +80,8 @@ public void setupTest() { protocolSchedule = localBlockchainSetup.getProtocolSchedule(); protocolContext = localBlockchainSetup.getProtocolContext(); - ethProtocolManager = EthProtocolManagerTestUtil.create(localBlockchain); + ethProtocolManager = + EthProtocolManagerTestUtil.create(localBlockchain, localBlockchainSetup.getWorldArchive()); ethContext = ethProtocolManager.ethContext(); syncState = new SyncState(protocolContext.getBlockchain(), ethContext.getEthPeers()); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java index f37cd624cf..e4a22080a5 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskParameterizedTest.java @@ -23,6 +23,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; import tech.pegasys.pantheon.ethereum.eth.manager.EthContext; import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManager; import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManagerTestUtil; @@ -138,8 +139,9 @@ public void searchesAgainstNetwork() { remoteBlockchain.appendBlock(remoteBlock, remoteReceipts); } + final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); final EthProtocolManager ethProtocolManager = - EthProtocolManagerTestUtil.create(localBlockchain); + EthProtocolManagerTestUtil.create(localBlockchain, worldStateArchive); final RespondingEthPeer.Responder responder = RespondingEthPeer.blockchainResponder(remoteBlockchain); @@ -152,7 +154,7 @@ public void searchesAgainstNetwork() { final EthContext ethContext = ethProtocolManager.ethContext(); final ProtocolContext protocolContext = - new ProtocolContext<>(localBlockchain, createInMemoryWorldStateArchive(), null); + new ProtocolContext<>(localBlockchain, worldStateArchive, null); final EthTask task = DetermineCommonAncestorTask.create( diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java index e5f25e7ef7..f70a386738 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/tasks/DetermineCommonAncestorTaskTest.java @@ -29,6 +29,7 @@ import tech.pegasys.pantheon.ethereum.core.BlockDataGenerator; import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.TransactionReceipt; +import tech.pegasys.pantheon.ethereum.db.WorldStateArchive; import tech.pegasys.pantheon.ethereum.eth.manager.EthContext; import tech.pegasys.pantheon.ethereum.eth.manager.EthPeer; import tech.pegasys.pantheon.ethereum.eth.manager.EthProtocolManager; @@ -73,10 +74,10 @@ public class DetermineCommonAncestorTaskTest { public void setup() { genesisBlock = blockDataGenerator.genesisBlock(); localBlockchain = createInMemoryBlockchain(genesisBlock); - ethProtocolManager = EthProtocolManagerTestUtil.create(localBlockchain); + final WorldStateArchive worldStateArchive = createInMemoryWorldStateArchive(); + ethProtocolManager = EthProtocolManagerTestUtil.create(localBlockchain, worldStateArchive); ethContext = ethProtocolManager.ethContext(); - protocolContext = - new ProtocolContext<>(localBlockchain, createInMemoryWorldStateArchive(), null); + protocolContext = new ProtocolContext<>(localBlockchain, worldStateArchive, null); } @Test diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java index 6ddcaacee3..27cd3357a9 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/transactions/TestNode.java @@ -103,7 +103,7 @@ public TestNode( final ProtocolContext protocolContext = new ProtocolContext<>(blockchain, worldStateArchive, null); final EthProtocolManager ethProtocolManager = - new EthProtocolManager(blockchain, 1, false, 1, 1); + new EthProtocolManager(blockchain, worldStateArchive, 1, false, 1, 1); final NetworkRunner networkRunner = NetworkRunner.builder() diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java index bc54a4079c..0dd83cf220 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/CliquePantheonController.java @@ -146,6 +146,7 @@ public static PantheonController init( final EthProtocolManager ethProtocolManager = new EthProtocolManager( protocolContext.getBlockchain(), + protocolContext.getWorldStateArchive(), networkId, fastSyncEnabled, syncConfig.downloaderParallelism(), diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java index c6b371cc79..895fb51732 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftLegacyPantheonController.java @@ -143,6 +143,7 @@ public static PantheonController init( ethProtocolManager = new Istanbul64ProtocolManager( protocolContext.getBlockchain(), + protocolContext.getWorldStateArchive(), networkId, fastSyncEnabled, syncConfig.downloaderParallelism(), @@ -152,6 +153,7 @@ public static PantheonController init( ethProtocolManager = new EthProtocolManager( protocolContext.getBlockchain(), + protocolContext.getWorldStateArchive(), networkId, fastSyncEnabled, syncConfig.downloaderParallelism(), diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java index b4974940d2..c30a216e10 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/IbftPantheonController.java @@ -163,6 +163,7 @@ public static PantheonController init( final EthProtocolManager ethProtocolManager = new EthProtocolManager( protocolContext.getBlockchain(), + protocolContext.getWorldStateArchive(), networkId, fastSyncEnabled, syncConfig.downloaderParallelism(), diff --git a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java index 20c332332b..9e2b09498a 100644 --- a/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java +++ b/pantheon/src/main/java/tech/pegasys/pantheon/controller/MainnetPantheonController.java @@ -113,6 +113,7 @@ public static PantheonController init( final EthProtocolManager ethProtocolManager = new EthProtocolManager( protocolContext.getBlockchain(), + protocolContext.getWorldStateArchive(), genesisConfig .getConfigOptions() .getChainId()