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 099fd0ad75..2493e43794 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,15 +107,17 @@ public class FullNode extends BsqNode { @Override protected void startParseBlocks() { - requestChainHeadHeightAndParseBlocks(getStartBlockHeight()); - } - - @Override - protected void startReOrgFromLastSnapshot() { - super.startReOrgFromLastSnapshot(); - int startBlockHeight = getStartBlockHeight(); - rpcService.requestChainHeadHeight(chainHeight -> parseBlocksOnHeadHeight(startBlockHeight, chainHeight), + + 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); } @@ -194,12 +196,6 @@ public class FullNode extends BsqNode { 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; @@ -221,7 +217,9 @@ public class FullNode extends BsqNode { 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); } } 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 a7c6f0730e..6466b67568 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 @@ public class LiteNode extends BsqNode { liteNodeNetworkService.requestBlocks(getStartBlockHeight()); } - @Override - protected void startReOrgFromLastSnapshot() { - super.startReOrgFromLastSnapshot(); - - int startBlockHeight = getStartBlockHeight(); - liteNodeNetworkService.reset(); - liteNodeNetworkService.requestBlocks(startBlockHeight); - } - /////////////////////////////////////////////////////////////////////////////////////////// // Private @@ -252,7 +243,7 @@ public class LiteNode extends BsqNode { doParseBlock(block); runDelayedBatchProcessing(blocks, resultHandler); } catch (RequiredReorgFromSnapshotException e) { - resultHandler.run(); + log.warn("Interrupt batch processing because if a blockchain reorg. {}", e.toString()); } }); } diff --git a/seednode/src/main/java/bisq/seednode/SeedNodeMain.java b/seednode/src/main/java/bisq/seednode/SeedNodeMain.java index 5bfb17ceff..9841b88ca6 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.Cookie; 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 bisq.common.handlers.ResultHandler; 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,11 +113,28 @@ public class SeedNodeMain extends ExecutableForAppWithP2p { 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 protected void startApplication() { Cookie cookie = injector.getInstance(User.class).getCookie(); @@ -197,6 +219,11 @@ public class SeedNodeMain extends ExecutableForAppWithP2p { } + private void gracefulShutDown() { + gracefulShutDown(() -> { + }); + } + @Override public void gracefulShutDown(ResultHandler resultHandler) { seedNode.shutDown();