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
Add local Bitcoin node configuration detection #3982
Merged
sqrrm
merged 20 commits into
bisq-network:master
from
dmos62:local-btc-node-configuration-check
Feb 27, 2020
Merged
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
f895da4
Add local Bitcoin node configuration detection
dmos62 18478d9
Downgrade Optional usage to Java 10
dmos62 74c946a
Remove defunct test suite
dmos62 daa1b0b
Minor changes to satisfy Codacy or clarify why it fails
dmos62 e6dea3d
Improve marking that method is empty
dmos62 65177fc
Fix unchecked usage of LocalBitcoinNode.isUsable()
dmos62 08cd31b
Silence NioClient and NioClientManager loggers
dmos62 7848836
Formating changes
dmos62 0bbbe8c
Perform checks automatically on first query
dmos62 aceb608
Reorder methods
dmos62 6b4878a
Centralize some of local BTC node logic
dmos62 2a57ecd
Fix failing test
dmos62 6dec780
Minor requested changes (github batch)
dmos62 a92b6ad
Minor requested changes (non-github batch)
dmos62 30578bf
Have detection work on other network modes
dmos62 fdaced4
Changes to Background information popup
dmos62 b93ca2b
Polish formatting
cbeams c1a99cc
Polish LocalBitcoinNode method names and visibility
cbeams 57b7041
Remove unnecessary LOCAL_BITCOIN_NODE_PORT constant
cbeams 85e4515
Remove reference to removed constant
dmos62 File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,13 +36,10 @@ | |
|
||
/** | ||
* Detects whether a Bitcoin node is running on localhost and whether it is well | ||
* configured (meaning it's not pruning and has bloom filters enabled). The class is | ||
* split into methods that perform relevant checks and cache the result (methods that | ||
* start with "check"), and methods that query that cache (methods that start with "is"). | ||
* The querying methods return an Optional<Boolean>, whose emptiness shows if the | ||
* relevant check is pending, and whose contents show the result of the check. Method/s | ||
* starting with "safeIs" are provided to be used where the calling code was not | ||
* refactored to handle Optionals (see {@code LocalBitcoinNode#handleUnsafeQuery}). | ||
* configured (meaning it's not pruning and has bloom filters enabled). The public | ||
* methods automatically trigger detection and (if detected) configuration checks, | ||
* and cache the results, and consequent queries to `LocalBitcoinNode` will always | ||
* return the cached results. | ||
* @see bisq.common.config.Config#ignoreLocalBtcNode | ||
*/ | ||
@Singleton | ||
|
@@ -54,8 +51,9 @@ public class LocalBitcoinNode { | |
private static final int CONNECTION_TIMEOUT = 5000; | ||
|
||
private final int port; | ||
private Optional<Boolean> detected = Optional.empty(); | ||
private Optional<Boolean> wellConfigured = Optional.empty(); | ||
|
||
private Boolean detected; | ||
private Boolean wellConfigured; | ||
|
||
@Inject | ||
public LocalBitcoinNode(@Named(LOCAL_BITCOIN_NODE_PORT) int port) { | ||
|
@@ -132,38 +130,41 @@ private static boolean isBloomFilteringSupportedAndEnabled(VersionMessage versio | |
return (localServices & NODE_BLOOM) == NODE_BLOOM; | ||
} | ||
|
||
/** | ||
* Initiates detection and configuration checks. The results are cached so that the | ||
* public methods isUsable, isDetected, isWellConfigured don't trigger a recheck. | ||
/* Performs checks that the query methods might be interested in. | ||
*/ | ||
private void performChecks() { | ||
checkUsable(); | ||
} | ||
|
||
/* Initiates detection and configuration checks. The results are cached so that the | ||
* public methods isUsable, isDetected, etc. don't trigger a recheck. | ||
*/ | ||
public boolean checkUsable() { | ||
private void checkUsable() { | ||
var optionalVersionMessage = attemptHandshakeForVersionMessage(); | ||
handleHandshakeAttempt(optionalVersionMessage); | ||
// We know that the Optional/s will be populated by the end of the checks. | ||
return isUsable().get(); | ||
} | ||
|
||
private void handleHandshakeAttempt(Optional<VersionMessage> optionalVersionMessage) { | ||
if (!optionalVersionMessage.isPresent()) { | ||
detected = Optional.of(false); | ||
wellConfigured = Optional.of(false); | ||
detected = false; | ||
wellConfigured = false; | ||
log.info("No local Bitcoin node detected on port {}," | ||
+ " or the connection was prematurely closed" | ||
dmos62 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
+ " (before a version messages could be coerced)", | ||
dmos62 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
port); | ||
} else { | ||
detected = Optional.of(true); | ||
detected = true; | ||
log.info("Local Bitcoin node detected on port {}", port); | ||
|
||
var versionMessage = optionalVersionMessage.get(); | ||
var configurationCheckResult = checkWellConfigured(versionMessage); | ||
|
||
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. Blank line |
||
if (configurationCheckResult) { | ||
wellConfigured = Optional.of(true); | ||
wellConfigured = true; | ||
log.info("Local Bitcoin node found to be well configured" | ||
+ " (not pruning and allows bloom filters)"); | ||
} else { | ||
wellConfigured = Optional.of(false); | ||
wellConfigured = false; | ||
log.info("Local Bitcoin node badly configured" | ||
+ " (it is pruning and/or bloom filters are disabled)"); | ||
} | ||
|
@@ -293,82 +294,49 @@ public void onPeerDisconnected(Peer peer, int peerCount) { | |
} | ||
|
||
/** | ||
* Returns an optional that, in case it is not empty, shows whether or not the | ||
* local node was fit for usage at the time the checks were performed called, | ||
* meaning it's been detected and its configuration satisfied our checks; or, in | ||
* the case that it is empty, it signifies that the checks have not yet completed. | ||
* Returns whether or not a local Bitcion node was detected and was well configured | ||
* at the time the checks were performed. All checks are triggered in case they have | ||
* not been performed. | ||
*/ | ||
public Optional<Boolean> isUsable() { | ||
public boolean isUsable() { | ||
// If a node is found to be well configured, it implies that it was also detected, | ||
// so this is query is enough to show if the relevant checks were performed and if | ||
// their results are positive. | ||
return isWellConfigured(); | ||
} | ||
|
||
/** | ||
* Returns an Optional<Boolean> that, when not empty, tells you whether the local node | ||
* was detected, but misconfigured. | ||
* Returns whether the local node was detected, but misconfigured. Combination of | ||
* methods isDetected and isWellConfigured. | ||
*/ | ||
public Optional<Boolean> isDetectedButMisconfigured() { | ||
return isDetected().flatMap(goodDetect -> | ||
isWellConfigured().map(goodConfig -> | ||
goodDetect && !goodConfig | ||
)); | ||
public boolean isDetectedButMisconfigured() { | ||
return isDetected() && !isWellConfigured(); | ||
} | ||
|
||
/** | ||
* Returns an optional, which is empty in case detection has not yet completed, or | ||
* which contains a Boolean, in case detection has been performed, which signifies | ||
* whether or not a Bitcoin node was running on localhost at the time the checks were | ||
* performed. No further monitoring is performed, so if the node goes up or down in | ||
* the meantime, this method will continue to return its original value. See | ||
* {@code MainViewModel#setupBtcNumPeersWatcher} to understand how disconnection and | ||
* reconnection of the local Bitcoin node is actually handled. | ||
* Returns whether a local Bitcoin node was detected. All checks are triggered in case | ||
* they have not been performed. No further monitoring is performed, so if the node | ||
* goes up or down in the meantime, this method will continue to return its original | ||
* value. See {@code MainViewModel#setupBtcNumPeersWatcher} to understand how | ||
* disconnection and reconnection of the local Bitcoin node is actually handled. | ||
*/ | ||
public Optional<Boolean> isDetected() { | ||
public boolean isDetected() { | ||
if (detected == null) { | ||
performChecks(); | ||
} | ||
return detected; | ||
} | ||
|
||
/** | ||
* Returns an optional whose emptiness signifies whether or not configuration checks | ||
* have been performed, and its Boolean contents whether the local node's | ||
* configuration satisfied our checks at the time they were performed. We check if the | ||
* local node is not pruning and has bloom filters enabled. | ||
* Returns whether the local node's configuration satisfied our checks at the time | ||
* they were performed. All checks are triggered in case they have not been performed. | ||
* We check if the local node is not pruning and has bloom filters enabled. | ||
*/ | ||
public Optional<Boolean> isWellConfigured() { | ||
public boolean isWellConfigured() { | ||
if (wellConfigured == null) { | ||
performChecks(); | ||
} | ||
return wellConfigured; | ||
} | ||
|
||
/** | ||
* A "safe" variant, which, in case LocalBitcoinNode checks were | ||
* not performed, reverts to legacy behaviour and logs an error message. See | ||
* {@code LocalBitcoinNode#handleUnsafeQuery}. | ||
*/ | ||
public boolean safeIsUsable() { | ||
return handleUnsafeQuery(isUsable()); | ||
} | ||
|
||
private boolean handleUnsafeQuery(Optional<Boolean> opt) { | ||
return opt.orElseGet(() -> { | ||
/* Returning false when checks haven't been performed yet is what the behaviour | ||
* was before we switched to using Optionals. More specifically, the only query | ||
* method at the time, isDetected(), would return false in such a case. We are | ||
* relatively confident that the previous behaviour doesn't cause fatal bugs, | ||
* so, in case LocalBitcoinNode is queried too early, we revert to it, instead | ||
* of letting Optional.empty().get() throw an exception. The advantage over | ||
* plain booleans then is that we can log the below error message (with | ||
* stacktrace). | ||
*/ | ||
var whenChecksNotFinished = false; | ||
|
||
var throwable = new Throwable("LocalBitcoinNode was queried before it was ready"); | ||
|
||
log.error("Unexpectedly queried LocalBitcoinNode before its checks were performed." | ||
+ " This should never happen." | ||
+ " Please report this on Bisq's issue tracker, including the following stacktrace:", | ||
throwable); | ||
|
||
return whenChecksNotFinished; | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Add a check to prevent possible NullPointerException.