-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Check BTC node config without IO overhead #4081
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -46,6 +46,7 @@ | |||||||||||||||
import org.bitcoinj.core.NetworkParameters; | ||||||||||||||||
import org.bitcoinj.core.Peer; | ||||||||||||||||
import org.bitcoinj.core.PeerAddress; | ||||||||||||||||
import org.bitcoinj.core.VersionMessage; | ||||||||||||||||
import org.bitcoinj.core.PeerGroup; | ||||||||||||||||
import org.bitcoinj.core.RejectMessage; | ||||||||||||||||
import org.bitcoinj.core.listeners.DownloadProgressTracker; | ||||||||||||||||
|
@@ -91,10 +92,12 @@ | |||||||||||||||
import java.util.List; | ||||||||||||||||
import java.util.Set; | ||||||||||||||||
import java.util.concurrent.TimeUnit; | ||||||||||||||||
import java.util.function.Consumer; | ||||||||||||||||
import java.util.concurrent.TimeoutException; | ||||||||||||||||
import java.util.stream.Collectors; | ||||||||||||||||
|
||||||||||||||||
import lombok.Getter; | ||||||||||||||||
import lombok.Setter; | ||||||||||||||||
import lombok.extern.slf4j.Slf4j; | ||||||||||||||||
|
||||||||||||||||
import org.jetbrains.annotations.NotNull; | ||||||||||||||||
|
@@ -141,6 +144,10 @@ public class WalletsSetup { | |||||||||||||||
private final boolean useAllProvidedNodes; | ||||||||||||||||
private WalletConfig walletConfig; | ||||||||||||||||
|
||||||||||||||||
@Setter | ||||||||||||||||
@Nullable | ||||||||||||||||
private Consumer<String> displayUserBtcNodeMisconfigurationHandler; | ||||||||||||||||
|
||||||||||||||||
/////////////////////////////////////////////////////////////////////////////////////////// | ||||||||||||||||
// Constructor | ||||||||||||||||
/////////////////////////////////////////////////////////////////////////////////////////// | ||||||||||||||||
|
@@ -215,6 +222,10 @@ protected void onSetupCompleted() { | |||||||||||||||
if (preferences.getBitcoinNodes() != null && !preferences.getBitcoinNodes().isEmpty()) | ||||||||||||||||
peerGroup.setAddPeersFromAddressMessage(false); | ||||||||||||||||
|
||||||||||||||||
peerGroup.addVersionMessageReceivedEventListener((peer, versionMessage) -> { | ||||||||||||||||
UserThread.execute(() -> handleConfiguration(peer, versionMessage)); | ||||||||||||||||
}); | ||||||||||||||||
|
||||||||||||||||
peerGroup.addConnectedEventListener((peer, peerCount) -> { | ||||||||||||||||
// We get called here on our user thread | ||||||||||||||||
numPeers.set(peerCount); | ||||||||||||||||
|
@@ -409,6 +420,64 @@ private void configPeerNodes(@Nullable Socks5Proxy proxy) { | |||||||||||||||
networkConfig.proposePeers(peers); | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
/////////////////////////////////////////////////////////////////////////////////////////// | ||||||||||||||||
// Peer configuration check | ||||||||||||||||
/////////////////////////////////////////////////////////////////////////////////////////// | ||||||||||||||||
|
||||||||||||||||
/* Provided a Peer and its VersionMessage, will check and handle Peer's advertised | ||||||||||||||||
* configuration. The VersionMessage is provided separately, because it is not | ||||||||||||||||
* always available and this is meant to be called from a listener that is triggered | ||||||||||||||||
* when the VersionMessage becomes available. | ||||||||||||||||
*/ | ||||||||||||||||
private void handleConfiguration(Peer peer, VersionMessage versionMessage) { | ||||||||||||||||
var wellConfigured = isWellConfigured(versionMessage); | ||||||||||||||||
if (wellConfigured) { | ||||||||||||||||
log.info("Peer well configured: {}", peer); | ||||||||||||||||
} else { | ||||||||||||||||
Comment on lines
+434
to
+436
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Redundant
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you don't remove the |
||||||||||||||||
log.error("Peer _badly_ configured (pruning and/or bloom filters disabled): {}", peer); | ||||||||||||||||
var usingLocalNode = localBitcoinNode.shouldBeUsed(); | ||||||||||||||||
var usingCustomNodes = | ||||||||||||||||
BtcNodes.BitcoinNodesOption.CUSTOM.ordinal() == preferences.getBitcoinNodesOptionOrdinal(); | ||||||||||||||||
if (usingLocalNode || usingCustomNodes) { | ||||||||||||||||
displayUserBtcNodeMisconfigurationHandler.accept(peer.toString()); | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
private static boolean isWellConfigured(VersionMessage versionMessage) { | ||||||||||||||||
var notPruning = versionMessage.hasBlockChain(); | ||||||||||||||||
var supportsAndAllowsBloomFilters = | ||||||||||||||||
isBloomFilteringSupportedAndEnabled(versionMessage); | ||||||||||||||||
return notPruning && supportsAndAllowsBloomFilters; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
/** | ||||||||||||||||
* Method backported from upstream bitcoinj: at the time of writing, our version is | ||||||||||||||||
* not BIP111-aware. Source routines and data can be found in bitcoinj under: | ||||||||||||||||
* core/src/main/java/org/bitcoinj/core/VersionMessage.java | ||||||||||||||||
* and core/src/main/java/org/bitcoinj/core/NetworkParameters.java | ||||||||||||||||
*/ | ||||||||||||||||
@SuppressWarnings("UnnecessaryLocalVariable") | ||||||||||||||||
private static boolean isBloomFilteringSupportedAndEnabled(VersionMessage versionMessage) { | ||||||||||||||||
// A service bit that denotes whether the peer supports BIP37 bloom filters or | ||||||||||||||||
// not. The service bit is defined in BIP111. | ||||||||||||||||
int NODE_BLOOM = 1 << 2; | ||||||||||||||||
|
||||||||||||||||
int BLOOM_FILTERS_BIP37_PROTOCOL_VERSION = 70000; | ||||||||||||||||
var whenBloomFiltersWereIntroduced = BLOOM_FILTERS_BIP37_PROTOCOL_VERSION; | ||||||||||||||||
|
||||||||||||||||
int BLOOM_FILTERS_BIP111_PROTOCOL_VERSION = 70011; | ||||||||||||||||
var whenBloomFiltersWereDisabledByDefault = BLOOM_FILTERS_BIP111_PROTOCOL_VERSION; | ||||||||||||||||
|
||||||||||||||||
int clientVersion = versionMessage.clientVersion; | ||||||||||||||||
long localServices = versionMessage.localServices; | ||||||||||||||||
|
||||||||||||||||
if (clientVersion >= whenBloomFiltersWereIntroduced | ||||||||||||||||
&& clientVersion < whenBloomFiltersWereDisabledByDefault) | ||||||||||||||||
return true; | ||||||||||||||||
|
||||||||||||||||
return (localServices & NODE_BLOOM) == NODE_BLOOM; | ||||||||||||||||
} | ||||||||||||||||
|
||||||||||||||||
/////////////////////////////////////////////////////////////////////////////////////////// | ||||||||||||||||
// Backup | ||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A temp variable is not necessary imo, the method call is already very concise and readable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A variable defining the condition is a style I use (and propagate) and, even if the called method is descriptive as well, I still use it. One reason is consistency of style. Another, the if statement doesn't care that the node being well configured is predicated on the version message (that's an implemenation detail), so there's no reason to put that in the if statement. I would be against your suggestion, because it optimizes for terseness at the cost of readability.