From 450800d101f17198bcd77cefc9dca81182b6b182 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Wed, 10 Nov 2021 13:04:21 +0100 Subject: [PATCH 1/4] Remove startReOrgFromLastSnapshot methods in LiteNode and FullNode The custom implementations triggered to repeat requests but we shut down the seed node in case of a reorg and for desktops we request the user to shutdown. --- core/src/main/java/bisq/core/dao/node/full/FullNode.java | 9 --------- core/src/main/java/bisq/core/dao/node/lite/LiteNode.java | 9 --------- 2 files changed, 18 deletions(-) diff --git a/core/src/main/java/bisq/core/dao/node/full/FullNode.java b/core/src/main/java/bisq/core/dao/node/full/FullNode.java index 099fd0ad751..1ca0dcbce32 100644 --- a/core/src/main/java/bisq/core/dao/node/full/FullNode.java +++ b/core/src/main/java/bisq/core/dao/node/full/FullNode.java @@ -110,15 +110,6 @@ protected void startParseBlocks() { requestChainHeadHeightAndParseBlocks(getStartBlockHeight()); } - @Override - protected void startReOrgFromLastSnapshot() { - super.startReOrgFromLastSnapshot(); - - int startBlockHeight = getStartBlockHeight(); - rpcService.requestChainHeadHeight(chainHeight -> parseBlocksOnHeadHeight(startBlockHeight, chainHeight), - this::handleError); - } - @Override protected void onP2PNetworkReady() { super.onP2PNetworkReady(); diff --git a/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java b/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java index a7c6f0730e1..22fd5689929 100644 --- a/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java +++ b/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java @@ -185,15 +185,6 @@ protected void startParseBlocks() { liteNodeNetworkService.requestBlocks(getStartBlockHeight()); } - @Override - protected void startReOrgFromLastSnapshot() { - super.startReOrgFromLastSnapshot(); - - int startBlockHeight = getStartBlockHeight(); - liteNodeNetworkService.reset(); - liteNodeNetworkService.requestBlocks(startBlockHeight); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Private From 42500c03705870defab35b1ca6399e7431b8bfc2 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Wed, 10 Nov 2021 17:36:49 +0100 Subject: [PATCH 2/4] Do not call resultHandler in case of a RequiredReorgFromSnapshotException We trigger a resync from resources if there is a reorg and don't want to continue to request blocks --- core/src/main/java/bisq/core/dao/node/lite/LiteNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java b/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java index 22fd5689929..6466b675680 100644 --- a/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java +++ b/core/src/main/java/bisq/core/dao/node/lite/LiteNode.java @@ -243,7 +243,7 @@ private void runDelayedBatchProcessing(List blocks, Runnable resultHan doParseBlock(block); runDelayedBatchProcessing(blocks, resultHandler); } catch (RequiredReorgFromSnapshotException e) { - resultHandler.run(); + log.warn("Interrupt batch processing because if a blockchain reorg. {}", e.toString()); } }); } From 0edccd9fe145848ac4faf57409bbfddfe00609e6 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Wed, 10 Nov 2021 17:41:58 +0100 Subject: [PATCH 3/4] Only call parseBlocksOnHeadHeight if our latest block from persistance is below the chain height of btc core. With the new handling of dao state hashblocks it can be the we have persisted the latest block up to the chain height. Before that change we only had the last snapshot which was at least 20 blocks back persisted. We want to avoid to get caught in a retry loop at parseBlocksOnHeadHeight so we filter out that case just at the caller. At parseBlocksOnHeadHeight we inline the requestChainHeadHeightAndParseBlocks method as it is not used by other callers anymore. This case that we request a block but our local btc core chain hight is below that might be some edge case when we had a synced dao blocks but we btc core is resyncing... --- .../bisq/core/dao/node/full/FullNode.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/bisq/core/dao/node/full/FullNode.java b/core/src/main/java/bisq/core/dao/node/full/FullNode.java index 1ca0dcbce32..2493e437948 100644 --- a/core/src/main/java/bisq/core/dao/node/full/FullNode.java +++ b/core/src/main/java/bisq/core/dao/node/full/FullNode.java @@ -107,7 +107,18 @@ public void shutDown() { @Override protected void startParseBlocks() { - requestChainHeadHeightAndParseBlocks(getStartBlockHeight()); + int startBlockHeight = getStartBlockHeight(); + + log.info("startParseBlocks: startBlockHeight={}", startBlockHeight); + rpcService.requestChainHeadHeight(chainHeight -> { + // If our persisted block is equal to the chain height we have startBlockHeight 1 block higher, + // so we do not call parseBlocksOnHeadHeight + log.info("startParseBlocks: chainHeight={}", chainHeight); + if (startBlockHeight <= chainHeight) { + parseBlocksOnHeadHeight(startBlockHeight, chainHeight); + } + }, + this::handleError); } @Override @@ -185,12 +196,6 @@ private void parseBlocksIfNewBlockAvailable(int chainHeight) { this::handleError); } - private void requestChainHeadHeightAndParseBlocks(int startBlockHeight) { - log.info("requestChainHeadHeightAndParseBlocks with startBlockHeight={}", startBlockHeight); - rpcService.requestChainHeadHeight(chainHeight -> parseBlocksOnHeadHeight(startBlockHeight, chainHeight), - this::handleError); - } - private void parseBlocksOnHeadHeight(int startBlockHeight, int chainHeight) { if (startBlockHeight <= chainHeight) { blocksToParseInBatch = chainHeight - startBlockHeight; @@ -212,7 +217,9 @@ private void parseBlocksOnHeadHeight(int startBlockHeight, int chainHeight) { log.warn("We are trying to start with a block which is above the chain height of Bitcoin Core. " + "We need probably wait longer until Bitcoin Core has fully synced. " + "We try again after a delay of 1 min."); - UserThread.runAfter(() -> requestChainHeadHeightAndParseBlocks(startBlockHeight), 60); + UserThread.runAfter(() -> rpcService.requestChainHeadHeight(chainHeight1 -> + parseBlocksOnHeadHeight(startBlockHeight, chainHeight1), + this::handleError), 60); } } From 6f51793d1bd059c979d08dbc3c5231e41b84ddf9 Mon Sep 17 00:00:00 2001 From: chimp1984 Date: Wed, 10 Nov 2021 18:31:53 +0100 Subject: [PATCH 4/4] Add deterministic delay for seed node shutdown at reorg We shut down with a deterministic delay per seed to avoid that all seeds shut down at the same time in case of a reorg. We use 30 sec. as distance delay between the seeds to be on the safe side. We have 12 seeds so that's 6 minutes. --- .../main/java/bisq/seednode/SeedNodeMain.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java index 080aff96d21..cea8390e84e 100644 --- a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java +++ b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java @@ -25,9 +25,11 @@ import bisq.core.user.CookieKey; import bisq.core.user.User; +import bisq.network.p2p.NodeAddress; import bisq.network.p2p.P2PService; import bisq.network.p2p.P2PServiceListener; import bisq.network.p2p.peers.PeerManager; +import bisq.network.p2p.seed.SeedNodeRepository; import bisq.common.Timer; import bisq.common.UserThread; @@ -42,6 +44,9 @@ import com.google.inject.Key; import com.google.inject.name.Names; +import java.util.ArrayList; +import java.util.List; + import lombok.extern.slf4j.Slf4j; @Slf4j @@ -108,9 +113,26 @@ protected void applyInjector() { seedNode.setInjector(injector); if (DevEnv.isDaoActivated()) { - injector.getInstance(DaoStateSnapshotService.class).setDaoRequiresRestartHandler(() -> gracefulShutDown(() -> { - })); + injector.getInstance(DaoStateSnapshotService.class).setDaoRequiresRestartHandler( + // We shut down with a deterministic delay per seed to avoid that all seeds shut down at the + // same time in case of a reorg. We use 30 sec. as distance delay between the seeds to be on the + // safe side. We have 12 seeds so that's 6 minutes. + () -> UserThread.runAfter(this::gracefulShutDown, 1 + (getMyIndex() * 30L)) + ); + } + } + + private int getMyIndex() { + P2PService p2PService = injector.getInstance(P2PService.class); + SeedNodeRepository seedNodeRepository = injector.getInstance(SeedNodeRepository.class); + List seedNodes = new ArrayList<>(seedNodeRepository.getSeedNodeAddresses()); + NodeAddress myAddress = p2PService.getAddress(); + for (int i = 0; i < seedNodes.size(); i++) { + if (seedNodes.get(i).equals(myAddress)) { + return i; + } } + return 0; } @Override @@ -197,6 +219,11 @@ private void setupConnectionLossCheck() { } + private void gracefulShutDown() { + gracefulShutDown(() -> { + }); + } + @Override public void gracefulShutDown(ResultHandler resultHandler) { seedNode.shutDown();