From cec25ce279a3b7bbad29d4ea3aed66e7a7a62b18 Mon Sep 17 00:00:00 2001 From: catbref Date: Wed, 28 Oct 2020 08:41:23 +0000 Subject: [PATCH] Add API call POST /peers/commonblock as debugging aid --- .../qortal/api/resource/PeersResource.java | 72 +++++++++++++++++++ .../org/qortal/controller/Synchronizer.java | 7 +- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/qortal/api/resource/PeersResource.java b/src/main/java/org/qortal/api/resource/PeersResource.java index 80cb5fa5..a66fef4a 100644 --- a/src/main/java/org/qortal/api/resource/PeersResource.java +++ b/src/main/java/org/qortal/api/resource/PeersResource.java @@ -8,6 +8,8 @@ import io.swagger.v3.oas.annotations.parameters.RequestBody; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -26,10 +28,17 @@ import org.qortal.api.ApiException; import org.qortal.api.ApiExceptionFactory; import org.qortal.api.Security; import org.qortal.api.model.ConnectedPeer; +import org.qortal.controller.Controller; +import org.qortal.controller.Synchronizer; +import org.qortal.controller.Synchronizer.SynchronizationResult; +import org.qortal.data.block.BlockSummaryData; import org.qortal.data.network.PeerData; import org.qortal.network.Network; +import org.qortal.network.Peer; import org.qortal.network.PeerAddress; import org.qortal.repository.DataException; +import org.qortal.repository.Repository; +import org.qortal.repository.RepositoryManager; import org.qortal.utils.ExecuteProduceConsume; import org.qortal.utils.NTP; @@ -260,4 +269,67 @@ public class PeersResource { } } + @POST + @Path("/commonblock") + @Operation( + summary = "Report common block with given peer.", + requestBody = @RequestBody( + required = true, + content = @Content( + mediaType = MediaType.TEXT_PLAIN, + schema = @Schema( + type = "string", example = "node2.qortal.org" + ) + ) + ), + responses = { + @ApiResponse( + description = "the block", + content = @Content( + array = @ArraySchema( + schema = @Schema( + implementation = BlockSummaryData.class + ) + ) + ) + ) + } + ) + @ApiErrors({ApiError.INVALID_DATA, ApiError.REPOSITORY_ISSUE}) + public List commonBlock(String targetPeerAddress) { + Security.checkApiCallAllowed(request); + + try { + // Try to resolve passed address to make things easier + PeerAddress peerAddress = PeerAddress.fromString(targetPeerAddress); + InetSocketAddress resolvedAddress = peerAddress.toSocketAddress(); + + List peers = Network.getInstance().getHandshakedPeers(); + Peer targetPeer = peers.stream().filter(peer -> peer.getResolvedAddress().equals(resolvedAddress)).findFirst().orElse(null); + + if (targetPeer == null) + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); + + try (final Repository repository = RepositoryManager.getRepository()) { + int ourInitialHeight = Controller.getInstance().getChainHeight(); + boolean force = true; + List peerBlockSummaries = new ArrayList<>(); + + SynchronizationResult findCommonBlockResult = Synchronizer.getInstance().fetchSummariesFromCommonBlock(repository, targetPeer, ourInitialHeight, force, peerBlockSummaries); + if (findCommonBlockResult != SynchronizationResult.OK) + return null; + + return peerBlockSummaries; + } + } catch (IllegalArgumentException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); + } catch (UnknownHostException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_DATA); + } catch (DataException e) { + throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.REPOSITORY_ISSUE, e); + } catch (InterruptedException e) { + return null; + } + } + } diff --git a/src/main/java/org/qortal/controller/Synchronizer.java b/src/main/java/org/qortal/controller/Synchronizer.java index 5af2030d..7aede4f2 100644 --- a/src/main/java/org/qortal/controller/Synchronizer.java +++ b/src/main/java/org/qortal/controller/Synchronizer.java @@ -175,7 +175,7 @@ public class Synchronizer { * @throws DataException * @throws InterruptedException */ - private SynchronizationResult fetchSummariesFromCommonBlock(Repository repository, Peer peer, int ourHeight, boolean force, List blockSummariesFromCommon) throws DataException, InterruptedException { + public SynchronizationResult fetchSummariesFromCommonBlock(Repository repository, Peer peer, int ourHeight, boolean force, List blockSummariesFromCommon) throws DataException, InterruptedException { // Start by asking for a few recent block hashes as this will cover a majority of reorgs // Failing that, back off exponentially int step = INITIAL_BLOCK_STEP; @@ -320,11 +320,12 @@ public class Synchronizer { BigInteger ourChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockSig, ourBlockSummaries); BigInteger peerChainWeight = Block.calcChainWeight(commonBlockHeight, commonBlockSig, peerBlockSummaries); + NumberFormat formatter = new DecimalFormat("0.###E0"); + LOGGER.debug(String.format("Our chain weight: %s, peer's chain weight: %s (higher is better)", formatter.format(ourChainWeight), formatter.format(peerChainWeight))); + // If our blockchain has greater weight then don't synchronize with peer if (ourChainWeight.compareTo(peerChainWeight) >= 0) { LOGGER.debug(String.format("Not synchronizing with peer %s as we have better blockchain", peer)); - NumberFormat formatter = new DecimalFormat("0.###E0"); - LOGGER.debug(String.format("Our chain weight: %s, peer's chain weight: %s (higher is better)", formatter.format(ourChainWeight), formatter.format(peerChainWeight))); return SynchronizationResult.INFERIOR_CHAIN; } }