Show connected Bitcoin network peer info

This commit is contained in:
Devin Bileck 2019-06-02 23:52:11 -07:00
parent 2178dbdc68
commit c8cb7fff1e
No known key found for this signature in database
GPG key ID: 38750B26EA8B8C93
5 changed files with 164 additions and 47 deletions

View file

@ -122,6 +122,8 @@ public class WalletsSetup {
private final File walletDir;
private final int socks5DiscoverMode;
private final IntegerProperty numPeers = new SimpleIntegerProperty(0);
private final IntegerProperty chainHeight = new SimpleIntegerProperty(0);
private final ObjectProperty<Peer> blocksDownloadedFromPeer = new SimpleObjectProperty<>();
private final ObjectProperty<List<Peer>> connectedPeers = new SimpleObjectProperty<>();
private final DownloadListener downloadListener = new DownloadListener();
private final List<Runnable> setupCompletedHandlers = new ArrayList<>();
@ -200,6 +202,7 @@ public class WalletsSetup {
super.onSetupCompleted();
final PeerGroup peerGroup = walletConfig.peerGroup();
final BlockChain chain = walletConfig.chain();
// We don't want to get our node white list polluted with nodes from AddressMessage calls.
if (preferences.getBitcoinNodes() != null && !preferences.getBitcoinNodes().isEmpty())
@ -215,6 +218,13 @@ public class WalletsSetup {
numPeers.set(peerCount);
connectedPeers.set(peerGroup.getConnectedPeers());
});
peerGroup.addBlocksDownloadedEventListener((peer, block, filteredBlock, blocksLeft) -> {
blocksDownloadedFromPeer.set(peer);
});
chain.addNewBestBlockListener(block -> {
connectedPeers.set(peerGroup.getConnectedPeers());
chainHeight.set(block.getHeight());
});
// Map to user thread
UserThread.execute(() -> {
@ -429,6 +439,14 @@ public class WalletsSetup {
return connectedPeers;
}
public ReadOnlyIntegerProperty chainHeightProperty() {
return chainHeight;
}
public ReadOnlyObjectProperty<Peer> blocksDownloadedFromPeerProperty() {
return blocksDownloadedFromPeer;
}
public ReadOnlyDoubleProperty downloadPercentageProperty() {
return downloadListener.percentageProperty();
}

View file

@ -1060,6 +1060,10 @@ settings.net.receivedBytesColumn=Received
settings.net.peerTypeColumn=Peer type
settings.net.openTorSettingsButton=Open Tor settings
settings.net.versionColumn=Version
settings.net.subVersionColumn=Subversion
settings.net.heightColumn=Height
settings.net.needRestart=You need to restart the application to apply that change.\nDo you want to do that now?
settings.net.notKnownYet=Not known yet...
settings.net.sentReceived=Sent: {0}, received: {1}

View file

@ -0,0 +1,44 @@
/*
* This file is part of Bisq.
*
* Bisq is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* Bisq is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
* License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Bisq. If not, see <http://www.gnu.org/licenses/>.
*/
package bisq.desktop.main.settings.network;
import org.bitcoinj.core.Peer;
public class BitcoinNetworkListItem {
private final Peer peer;
public BitcoinNetworkListItem(Peer peer) {
this.peer = peer;
}
public String getOnionAddress() {
return peer.getAddress().toString();
}
public String getVersion() {
return String.valueOf(peer.getPeerVersionMessage().clientVersion);
}
public String getSubVersion() {
return peer.getPeerVersionMessage().subVer;
}
public String getHeight() {
return String.valueOf(peer.getBestHeight());
}
}

View file

@ -21,7 +21,6 @@
<?import bisq.desktop.components.AutoTooltipCheckBox?>
<?import bisq.desktop.components.AutoTooltipLabel?>
<?import bisq.desktop.components.AutoTooltipRadioButton?>
<?import bisq.desktop.components.BisqTextArea?>
<?import bisq.desktop.components.BisqTextField?>
<?import bisq.desktop.components.InputTextField?>
<?import bisq.desktop.components.TitledGroupBg?>
@ -45,12 +44,34 @@
</padding>
<TitledGroupBg fx:id="btcHeader" GridPane.rowSpan="5"/>
<BisqTextArea fx:id="bitcoinPeersTextArea" GridPane.rowIndex="0" GridPane.hgrow="ALWAYS"
GridPane.vgrow="SOMETIMES" editable="false" focusTraversable="false" labelFloat="true">
<GridPane.margin>
<Insets top="25"/>
</GridPane.margin>
</BisqTextArea>
<VBox GridPane.rowIndex="0" GridPane.hgrow="ALWAYS" GridPane.vgrow="SOMETIMES">
<AutoTooltipLabel fx:id="bitcoinPeersLabel" styleClass="small-text"/>
<TableView fx:id="bitcoinPeersTableView">
<columns>
<TableColumn fx:id="bitcoinPeerAddressColumn" minWidth="220">
<cellValueFactory>
<PropertyValueFactory property="onionAddress"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="bitcoinPeerVersionColumn" minWidth="80" maxWidth="90">
<cellValueFactory>
<PropertyValueFactory property="version"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="bitcoinPeerSubVersionColumn" minWidth="180" maxWidth="180">
<cellValueFactory>
<PropertyValueFactory property="subVersion"/>
</cellValueFactory>
</TableColumn>
<TableColumn fx:id="bitcoinPeerHeightColumn" minWidth="80" maxWidth="80">
<cellValueFactory>
<PropertyValueFactory property="height"/>
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
<AutoTooltipLabel fx:id="localhostBtcNodeInfoLabel" styleClass="small-text"/>
</VBox>
<AutoTooltipCheckBox fx:id="useTorForBtcJCheckBox" GridPane.rowIndex="1"/>
@ -91,7 +112,7 @@
<VBox GridPane.rowIndex="6" GridPane.hgrow="ALWAYS" GridPane.vgrow="SOMETIMES">
<AutoTooltipLabel fx:id="p2PPeersLabel" styleClass="small-text"/>
<TableView fx:id="tableView">
<TableView fx:id="p2pPeersTableView">
<columns>
<TableColumn fx:id="onionAddressColumn" minWidth="220">
<cellValueFactory>

View file

@ -44,8 +44,6 @@ import bisq.network.p2p.network.Statistic;
import bisq.common.ClockWatcher;
import bisq.common.UserThread;
import org.bitcoinj.core.Peer;
import javax.inject.Inject;
import javafx.fxml.FXML;
@ -55,7 +53,6 @@ import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
@ -73,7 +70,6 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@ -83,25 +79,28 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
@FXML
TitledGroupBg p2pHeader, btcHeader;
@FXML
Label btcNodesLabel, bitcoinNodesLabel;
Label btcNodesLabel, bitcoinNodesLabel, localhostBtcNodeInfoLabel;
@FXML
InputTextField btcNodesInputTextField;
@FXML
TextField onionAddress, totalTrafficTextField;
@FXML
TextArea bitcoinPeersTextArea;
@FXML
Label p2PPeersLabel;
Label p2PPeersLabel, bitcoinPeersLabel;
@FXML
CheckBox useTorForBtcJCheckBox;
@FXML
RadioButton useProvidedNodesRadio, useCustomNodesRadio, usePublicNodesRadio;
@FXML
TableView<P2pNetworkListItem> tableView;
TableView<P2pNetworkListItem> p2pPeersTableView;
@FXML
TableView<BitcoinNetworkListItem> bitcoinPeersTableView;
@FXML
TableColumn<P2pNetworkListItem, String> onionAddressColumn, connectionTypeColumn, creationDateColumn,
roundTripTimeColumn, sentBytesColumn, receivedBytesColumn, peerTypeColumn;
@FXML
TableColumn<BitcoinNetworkListItem, String> bitcoinPeerAddressColumn, bitcoinPeerVersionColumn,
bitcoinPeerSubVersionColumn, bitcoinPeerHeightColumn;
@FXML
Label reSyncSPVChainLabel;
@FXML
AutoTooltipButton reSyncSPVChainButton, openTorSettingsButton;
@ -116,11 +115,16 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
private final WalletsSetup walletsSetup;
private final P2PService p2PService;
private final ObservableList<P2pNetworkListItem> networkListItems = FXCollections.observableArrayList();
private final SortedList<P2pNetworkListItem> sortedList = new SortedList<>(networkListItems);
private final ObservableList<P2pNetworkListItem> p2pNetworkListItems = FXCollections.observableArrayList();
private final SortedList<P2pNetworkListItem> p2pSortedList = new SortedList<>(p2pNetworkListItems);
private final ObservableList<BitcoinNetworkListItem> bitcoinNetworkListItems = FXCollections.observableArrayList();
private final SortedList<BitcoinNetworkListItem> bitcoinSortedList = new SortedList<>(bitcoinNetworkListItems);
private Subscription numP2PPeersSubscription;
private Subscription bitcoinPeersSubscription;
private Subscription bitcoinBlockHeightSubscription;
private Subscription bitcoinBlocksDownloadedSubscription;
private Subscription nodeAddressSubscription;
private ChangeListener<Boolean> btcNodesInputTextFieldFocusListener;
private ToggleGroup bitcoinPeersToggleGroup;
@ -156,9 +160,18 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
p2pHeader.setText(Res.get("settings.net.p2pHeader"));
onionAddress.setPromptText(Res.get("settings.net.onionAddressLabel"));
btcNodesLabel.setText(Res.get("settings.net.btcNodesLabel"));
bitcoinPeersTextArea.setPromptText(Res.get("settings.net.bitcoinPeersLabel"));
bitcoinPeersLabel.setText(Res.get("settings.net.bitcoinPeersLabel"));
useTorForBtcJCheckBox.setText(Res.get("settings.net.useTorForBtcJLabel"));
bitcoinNodesLabel.setText(Res.get("settings.net.bitcoinNodesLabel"));
bitcoinPeerAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.onionAddressColumn")));
bitcoinPeerAddressColumn.getStyleClass().add("first-column");
bitcoinPeerVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.versionColumn")));
bitcoinPeerSubVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.subVersionColumn")));
bitcoinPeerHeightColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.heightColumn")));
localhostBtcNodeInfoLabel.setText(Res.get("settings.net.localhostBtcNodeInfo"));
if (!bisqEnvironment.isBitcoinLocalhostNodeRunning()) {
localhostBtcNodeInfoLabel.setVisible(false);
}
useProvidedNodesRadio.setText(Res.get("settings.net.useProvidedNodesRadio"));
useCustomNodesRadio.setText(Res.get("settings.net.useCustomNodesRadio"));
usePublicNodesRadio.setText(Res.get("settings.net.usePublicNodesRadio"));
@ -177,16 +190,25 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
peerTypeColumn.getStyleClass().add("last-column");
openTorSettingsButton.updateText(Res.get("settings.net.openTorSettingsButton"));
GridPane.setMargin(bitcoinPeersLabel, new Insets(4, 0, 0, 0));
GridPane.setValignment(bitcoinPeersLabel, VPos.TOP);
GridPane.setMargin(p2PPeersLabel, new Insets(4, 0, 0, 0));
GridPane.setValignment(p2PPeersLabel, VPos.TOP);
bitcoinPeersTextArea.setPrefRowCount(4);
bitcoinPeersTableView.setMinHeight(180);
bitcoinPeersTableView.setPrefHeight(180);
bitcoinPeersTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
bitcoinPeersTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
bitcoinPeersTableView.getSortOrder().add(bitcoinPeerAddressColumn);
bitcoinPeerAddressColumn.setSortType(TableColumn.SortType.ASCENDING);
tableView.setMinHeight(180);
tableView.setPrefHeight(180);
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
tableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
tableView.getSortOrder().add(creationDateColumn);
p2pPeersTableView.setMinHeight(180);
p2pPeersTableView.setPrefHeight(180);
p2pPeersTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
p2pPeersTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
p2pPeersTableView.getSortOrder().add(creationDateColumn);
creationDateColumn.setSortType(TableColumn.SortType.ASCENDING);
bitcoinPeersToggleGroup = new ToggleGroup();
@ -267,7 +289,13 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
reSyncSPVChainButton.setOnAction(event -> GUIUtil.reSyncSPVChain(walletsSetup, preferences));
bitcoinPeersSubscription = EasyBind.subscribe(walletsSetup.connectedPeersProperty(),
connectedPeers -> updateBitcoinPeersTextArea());
connectedPeers -> updateBitcoinPeersTable());
bitcoinBlocksDownloadedSubscription = EasyBind.subscribe(walletsSetup.blocksDownloadedFromPeerProperty(),
peer -> updateBitcoinPeersTable());
bitcoinBlockHeightSubscription = EasyBind.subscribe(walletsSetup.chainHeightProperty(),
chainHeight -> updateBitcoinPeersTable());
nodeAddressSubscription = EasyBind.subscribe(p2PService.getNetworkNode().nodeAddressProperty(),
nodeAddress -> onionAddress.setText(nodeAddress == null ?
@ -280,8 +308,11 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
BSFormatter.formatBytes((long) sent),
BSFormatter.formatBytes((long) received))));
sortedList.comparatorProperty().bind(tableView.comparatorProperty());
tableView.setItems(sortedList);
bitcoinSortedList.comparatorProperty().bind(bitcoinPeersTableView.comparatorProperty());
bitcoinPeersTableView.setItems(bitcoinSortedList);
p2pSortedList.comparatorProperty().bind(p2pPeersTableView.comparatorProperty());
p2pPeersTableView.setItems(p2pSortedList);
btcNodesInputTextField.setText(preferences.getBitcoinNodes());
btcNodesInputTextField.setPromptText(Res.get("settings.net.ips"));
@ -305,13 +336,20 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
if (bitcoinPeersSubscription != null)
bitcoinPeersSubscription.unsubscribe();
if (bitcoinBlockHeightSubscription != null)
bitcoinBlockHeightSubscription.unsubscribe();
if (bitcoinBlocksDownloadedSubscription != null)
bitcoinBlocksDownloadedSubscription.unsubscribe();
if (numP2PPeersSubscription != null)
numP2PPeersSubscription.unsubscribe();
totalTrafficTextField.textProperty().unbind();
sortedList.comparatorProperty().unbind();
tableView.getItems().forEach(P2pNetworkListItem::cleanup);
bitcoinSortedList.comparatorProperty().unbind();
p2pSortedList.comparatorProperty().unbind();
p2pPeersTableView.getItems().forEach(P2pNetworkListItem::cleanup);
btcNodesInputTextField.focusedProperty().removeListener(btcNodesInputTextFieldFocusListener);
btcNodesInputTextField.textProperty().removeListener(btcNodesInputTextFieldListener);
@ -422,26 +460,18 @@ public class NetworkSettingsView extends ActivatableViewAndModel<GridPane, Activ
}
private void updateP2PTable() {
tableView.getItems().forEach(P2pNetworkListItem::cleanup);
networkListItems.clear();
networkListItems.setAll(p2PService.getNetworkNode().getAllConnections().stream()
p2pPeersTableView.getItems().forEach(P2pNetworkListItem::cleanup);
p2pNetworkListItems.clear();
p2pNetworkListItems.setAll(p2PService.getNetworkNode().getAllConnections().stream()
.map(connection -> new P2pNetworkListItem(connection, clockWatcher, formatter))
.collect(Collectors.toList()));
}
private void updateBitcoinPeersTextArea() {
bitcoinPeersTextArea.clear();
List<Peer> peerList = walletsSetup.connectedPeersProperty().get();
if (peerList != null) {
peerList.stream().forEach(e -> {
if (bitcoinPeersTextArea.getText().length() > 0)
bitcoinPeersTextArea.appendText("\n");
bitcoinPeersTextArea.appendText(e.toString());
});
}
if (bisqEnvironment.isBitcoinLocalhostNodeRunning())
bitcoinPeersTextArea.appendText("\n\n" + Res.get("settings.net.localhostBtcNodeInfo"));
private void updateBitcoinPeersTable() {
bitcoinNetworkListItems.clear();
bitcoinNetworkListItems.setAll(walletsSetup.getPeerGroup().getConnectedPeers().stream()
.map(BitcoinNetworkListItem::new)
.collect(Collectors.toList()));
}
}