remove dependency on local BTC node

Co-authored-by: premek <1145361+premek@users.noreply.github.com>
This commit is contained in:
woodser 2022-01-05 20:18:25 -05:00
parent 1b78be689a
commit 9059974725
13 changed files with 143 additions and 161 deletions

View File

@ -12,7 +12,7 @@ localnet:
mkdir -p .localnet mkdir -p .localnet
nodes: localnet nodes: localnet
./scripts/xmr_btc_deps.sh ./scripts/haveno_deps.sh
haveno: haveno:
./gradlew build ./gradlew build

View File

@ -117,7 +117,7 @@ public class Config {
// Default values for certain options // Default values for certain options
public static final int UNSPECIFIED_PORT = -1; public static final int UNSPECIFIED_PORT = -1;
public static final String DEFAULT_REGTEST_HOST = "localhost"; public static final String DEFAULT_REGTEST_HOST = "none";
public static final int DEFAULT_NUM_CONNECTIONS_FOR_BTC = 9; // down from BitcoinJ default of 12 public static final int DEFAULT_NUM_CONNECTIONS_FOR_BTC = 9; // down from BitcoinJ default of 12
static final String DEFAULT_CONFIG_FILE_NAME = "bisq.properties"; static final String DEFAULT_CONFIG_FILE_NAME = "bisq.properties";

View File

@ -85,6 +85,7 @@ public class AppStartupState {
p2pNetworkAndWalletInitialized.subscribe((observable, oldValue, newValue) -> { p2pNetworkAndWalletInitialized.subscribe((observable, oldValue, newValue) -> {
if (newValue) { if (newValue) {
applicationFullyInitialized.set(true); applicationFullyInitialized.set(true);
log.info("Application fully initialized");
} }
}); });
} }

View File

@ -0,0 +1,25 @@
package bisq.core.btc.setup;
import bisq.common.UserThread;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import java.util.Date;
class DownloadListener {
private final DoubleProperty percentage = new SimpleDoubleProperty(-1);
protected void progress(double percentage, int blocksLeft, Date date) {
UserThread.execute(() -> this.percentage.set(percentage / 100d));
}
protected void doneDownload() {
UserThread.execute(() -> this.percentage.set(1d));
}
public ReadOnlyDoubleProperty percentageProperty() {
return percentage;
}
}

View File

@ -151,7 +151,7 @@ public class WalletConfig extends AbstractIdleService {
protected volatile File vBtcWalletFile; protected volatile File vBtcWalletFile;
protected PeerAddress[] peerAddresses; protected PeerAddress[] peerAddresses;
protected DownloadProgressTracker downloadListener; protected DownloadListener downloadListener;
protected InputStream checkpoints; protected InputStream checkpoints;
protected String userAgent, version; protected String userAgent, version;
@Nullable @Nullable
@ -234,7 +234,7 @@ public class WalletConfig extends AbstractIdleService {
* If you want to learn about the sync process, you can provide a listener here. For instance, a * If you want to learn about the sync process, you can provide a listener here. For instance, a
* {@link DownloadProgressTracker} is a good choice. * {@link DownloadProgressTracker} is a good choice.
*/ */
public WalletConfig setDownloadListener(DownloadProgressTracker listener) { public WalletConfig setDownloadListener(DownloadListener listener) {
this.downloadListener = listener; this.downloadListener = listener;
return this; return this;
} }
@ -388,7 +388,8 @@ public class WalletConfig extends AbstractIdleService {
System.out.println("Monero wallet uri: " + vXmrWallet.getRpcConnection().getUri()); System.out.println("Monero wallet uri: " + vXmrWallet.getRpcConnection().getUri());
// vXmrWallet.rescanSpent(); // vXmrWallet.rescanSpent();
// vXmrWallet.rescanBlockchain(); // vXmrWallet.rescanBlockchain();
vXmrWallet.sync(); vXmrWallet.sync(); // blocking
downloadListener.doneDownload();
vXmrWallet.save(); vXmrWallet.save();
System.out.println("Loaded wallet balance: " + vXmrWallet.getBalance(0)); System.out.println("Loaded wallet balance: " + vXmrWallet.getBalance(0));
System.out.println("Loaded wallet unlocked balance: " + vXmrWallet.getUnlockedBalance(0)); System.out.println("Loaded wallet unlocked balance: " + vXmrWallet.getUnlockedBalance(0));
@ -471,7 +472,7 @@ public class WalletConfig extends AbstractIdleService {
@Override @Override
public void onSuccess(@Nullable Object result) { public void onSuccess(@Nullable Object result) {
//completeExtensionInitiations(vPeerGroup); //completeExtensionInitiations(vPeerGroup);
DownloadProgressTracker tracker = downloadListener == null ? new DownloadProgressTracker() : downloadListener; DownloadProgressTracker tracker = new DownloadProgressTracker();
vPeerGroup.startBlockChainDownload(tracker); vPeerGroup.startBlockChainDownload(tracker);
} }

View File

@ -45,11 +45,9 @@ import org.bitcoinj.core.Address;
import org.bitcoinj.core.BlockChain; import org.bitcoinj.core.BlockChain;
import org.bitcoinj.core.Context; import org.bitcoinj.core.Context;
import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Peer;
import org.bitcoinj.core.PeerAddress; import org.bitcoinj.core.PeerAddress;
import org.bitcoinj.core.PeerGroup; import org.bitcoinj.core.PeerGroup;
import org.bitcoinj.core.RejectMessage; import org.bitcoinj.core.RejectMessage;
import org.bitcoinj.core.listeners.DownloadProgressTracker;
import org.bitcoinj.utils.Threading; import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.DeterministicSeed; import org.bitcoinj.wallet.DeterministicSeed;
import org.bitcoinj.wallet.Wallet; import org.bitcoinj.wallet.Wallet;
@ -65,15 +63,15 @@ import com.google.common.util.concurrent.Service;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javafx.beans.property.BooleanProperty; import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty; import javafx.beans.property.IntegerProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.ObjectProperty; import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyObjectProperty; import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleObjectProperty;
import java.net.InetAddress; import java.net.InetAddress;
@ -85,7 +83,6 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -103,6 +100,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import monero.daemon.MoneroDaemon; import monero.daemon.MoneroDaemon;
import monero.daemon.model.MoneroDaemonConnection;
import monero.wallet.MoneroWallet; import monero.wallet.MoneroWallet;
// Setup wallets and use WalletConfig for BitcoinJ wiring. // Setup wallets and use WalletConfig for BitcoinJ wiring.
@ -112,6 +110,8 @@ import monero.wallet.MoneroWallet;
public class WalletsSetup { public class WalletsSetup {
public static final String PRE_SEGWIT_WALLET_BACKUP = "pre_segwit_haveno_BTC.wallet.backup"; public static final String PRE_SEGWIT_WALLET_BACKUP = "pre_segwit_haveno_BTC.wallet.backup";
private static final int MIN_BROADCAST_CONNECTIONS = 2;
private static final long DAEMON_POLL_INTERVAL_SECONDS = 20;
@Getter @Getter
public final BooleanProperty walletsSetupFailed = new SimpleBooleanProperty(); public final BooleanProperty walletsSetupFailed = new SimpleBooleanProperty();
@ -135,9 +135,8 @@ public class WalletsSetup {
private final int walletRpcBindPort; private final int walletRpcBindPort;
private final int socks5DiscoverMode; private final int socks5DiscoverMode;
private final IntegerProperty numPeers = new SimpleIntegerProperty(0); private final IntegerProperty numPeers = new SimpleIntegerProperty(0);
private final IntegerProperty chainHeight = new SimpleIntegerProperty(0); private final LongProperty chainHeight = new SimpleLongProperty(0);
private final ObjectProperty<Peer> blocksDownloadedFromPeer = new SimpleObjectProperty<>(); private final ObjectProperty<List<MoneroDaemonConnection>> peerConnections = new SimpleObjectProperty<>();
private final ObjectProperty<List<Peer>> connectedPeers = new SimpleObjectProperty<>();
private final DownloadListener downloadListener = new DownloadListener(); private final DownloadListener downloadListener = new DownloadListener();
private final List<Runnable> setupCompletedHandlers = new ArrayList<>(); private final List<Runnable> setupCompletedHandlers = new ArrayList<>();
public final BooleanProperty shutDownComplete = new SimpleBooleanProperty(); public final BooleanProperty shutDownComplete = new SimpleBooleanProperty();
@ -220,19 +219,11 @@ public class WalletsSetup {
if (preferences.getBitcoinNodes() != null && !preferences.getBitcoinNodes().isEmpty()) if (preferences.getBitcoinNodes() != null && !preferences.getBitcoinNodes().isEmpty())
peerGroup.setAddPeersFromAddressMessage(false); peerGroup.setAddPeersFromAddressMessage(false);
peerGroup.addConnectedEventListener((peer, peerCount) -> { UserThread.runPeriodically(() -> {
// We get called here on our user thread peerConnections.set(getPeerConnections());
numPeers.set(peerCount); numPeers.set(peerConnections.get().size());
connectedPeers.set(peerGroup.getConnectedPeers()); chainHeight.set(vXmrDaemon.getHeight());
}); }, DAEMON_POLL_INTERVAL_SECONDS);
peerGroup.addDisconnectedEventListener((peer, peerCount) -> {
// We get called here on our user thread
numPeers.set(peerCount);
connectedPeers.set(peerGroup.getConnectedPeers());
});
peerGroup.addBlocksDownloadedEventListener((peer, block, filteredBlock, blocksLeft) -> {
blocksDownloadedFromPeer.set(peer);
});
// Need to be Threading.SAME_THREAD executor otherwise BitcoinJ will skip that listener // Need to be Threading.SAME_THREAD executor otherwise BitcoinJ will skip that listener
peerGroup.addPreMessageReceivedEventListener(Threading.SAME_THREAD, (peer, message) -> { peerGroup.addPreMessageReceivedEventListener(Threading.SAME_THREAD, (peer, message) -> {
@ -247,16 +238,11 @@ public class WalletsSetup {
return message; return message;
}); });
chain.addNewBestBlockListener(block -> {
UserThread.execute(() -> {
connectedPeers.set(peerGroup.getConnectedPeers());
chainHeight.set(block.getHeight());
});
});
// Map to user thread // Map to user thread
UserThread.execute(() -> { UserThread.execute(() -> {
chainHeight.set(chain.getBestChainHeight()); peerConnections.set(getPeerConnections());
numPeers.set(peerConnections.get().size());
chainHeight.set(vXmrDaemon.getHeight());
addressEntryList.onWalletReady(walletConfig.btcWallet()); addressEntryList.onWalletReady(walletConfig.btcWallet());
xmrAddressEntryList.onWalletReady(walletConfig.getXmrWallet()); xmrAddressEntryList.onWalletReady(walletConfig.getXmrWallet());
timeoutTimer.stop(); timeoutTimer.stop();
@ -266,6 +252,12 @@ public class WalletsSetup {
// onSetupCompleted in walletAppKit is not the called on the last invocations, so we add a bit of delay // onSetupCompleted in walletAppKit is not the called on the last invocations, so we add a bit of delay
UserThread.runAfter(resultHandler::handleResult, 100, TimeUnit.MILLISECONDS); UserThread.runAfter(resultHandler::handleResult, 100, TimeUnit.MILLISECONDS);
} }
private List<MoneroDaemonConnection> getPeerConnections() {
return vXmrDaemon.getConnections().stream()
.filter(peerConnection -> peerConnection.getPeer().isOnline())
.collect(Collectors.toList());
}
}; };
walletConfig.setSocks5Proxy(socks5Proxy); walletConfig.setSocks5Proxy(socks5Proxy);
walletConfig.setConfig(config); walletConfig.setConfig(config);
@ -401,11 +393,10 @@ public class WalletsSetup {
} }
private void configPeerNodes(@Nullable Socks5Proxy proxy) { private void configPeerNodes(@Nullable Socks5Proxy proxy) {
BtcNodesSetupPreferences btcNodesSetupPreferences = new BtcNodesSetupPreferences(preferences); walletConfig.setMinBroadcastConnections(MIN_BROADCAST_CONNECTIONS);
BtcNodesSetupPreferences btcNodesSetupPreferences = new BtcNodesSetupPreferences(preferences);
List<BtcNode> nodes = btcNodesSetupPreferences.selectPreferredNodes(btcNodes); List<BtcNode> nodes = btcNodesSetupPreferences.selectPreferredNodes(btcNodes);
int minBroadcastConnections = btcNodesSetupPreferences.calculateMinBroadcastConnections(nodes);
walletConfig.setMinBroadcastConnections(minBroadcastConnections);
BtcNodesRepository repository = new BtcNodesRepository(nodes); BtcNodesRepository repository = new BtcNodesRepository(nodes);
boolean isUseClearNodesWithProxies = (useAllProvidedNodes || btcNodesSetupPreferences.isUseCustomNodes()); boolean isUseClearNodesWithProxies = (useAllProvidedNodes || btcNodesSetupPreferences.isUseCustomNodes());
@ -515,18 +506,14 @@ public class WalletsSetup {
return numPeers; return numPeers;
} }
public ReadOnlyObjectProperty<List<Peer>> connectedPeersProperty() { public ReadOnlyObjectProperty<List<MoneroDaemonConnection>> peerConnectionsProperty() {
return connectedPeers; return peerConnections;
} }
public ReadOnlyIntegerProperty chainHeightProperty() { public LongProperty chainHeightProperty() {
return chainHeight; return chainHeight;
} }
public ReadOnlyObjectProperty<Peer> blocksDownloadedFromPeerProperty() {
return blocksDownloadedFromPeer;
}
public ReadOnlyDoubleProperty downloadPercentageProperty() { public ReadOnlyDoubleProperty downloadPercentageProperty() {
return downloadListener.percentageProperty(); return downloadListener.percentageProperty();
} }
@ -536,8 +523,9 @@ public class WalletsSetup {
} }
public boolean isChainHeightSyncedWithinTolerance() { public boolean isChainHeightSyncedWithinTolerance() {
int peersChainHeight = PeerGroup.getMostCommonChainHeight(connectedPeers.get()); Long peersChainHeight = walletConfig.vXmrDaemon.getSyncInfo().getTargetHeight();
int bestChainHeight = walletConfig.chain().getBestChainHeight(); if (peersChainHeight == 0) return true; // monero-daemon-rpc sync_info's target_height returns 0 when node is fully synced
long bestChainHeight = chainHeight.get();
if (Math.abs(peersChainHeight - bestChainHeight) <= 3) { if (Math.abs(peersChainHeight - bestChainHeight) <= 3) {
return true; return true;
} }
@ -566,28 +554,4 @@ public class WalletsSetup {
return walletConfig.getMinBroadcastConnections(); return walletConfig.getMinBroadcastConnections();
} }
///////////////////////////////////////////////////////////////////////////////////////////
// Inner classes
///////////////////////////////////////////////////////////////////////////////////////////
private static class DownloadListener extends DownloadProgressTracker {
private final DoubleProperty percentage = new SimpleDoubleProperty(-1);
@Override
protected void progress(double percentage, int blocksLeft, Date date) {
super.progress(percentage, blocksLeft, date);
UserThread.execute(() -> this.percentage.set(percentage / 100d));
}
@Override
protected void doneDownload() {
super.doneDownload();
UserThread.execute(() -> this.percentage.set(1d));
}
public ReadOnlyDoubleProperty percentageProperty() {
return percentage;
}
}
} }

View File

@ -81,7 +81,7 @@ public class XmrTxProofService implements AssetTxProofService {
private final Map<String, XmrTxProofRequestsPerTrade> servicesByTradeId = new HashMap<>(); private final Map<String, XmrTxProofRequestsPerTrade> servicesByTradeId = new HashMap<>();
private AutoConfirmSettings autoConfirmSettings; private AutoConfirmSettings autoConfirmSettings;
private final Map<String, ChangeListener<Trade.State>> tradeStateListenerMap = new HashMap<>(); private final Map<String, ChangeListener<Trade.State>> tradeStateListenerMap = new HashMap<>();
private ChangeListener<Number> btcPeersListener, btcBlockListener; private ChangeListener<Number> xmrPeersListener, xmrBlockListener;
private BootstrapListener bootstrapListener; private BootstrapListener bootstrapListener;
private MonadicBinding<Boolean> p2pNetworkAndWalletReady; private MonadicBinding<Boolean> p2pNetworkAndWalletReady;
private ChangeListener<Boolean> p2pNetworkAndWalletReadyListener; private ChangeListener<Boolean> p2pNetworkAndWalletReadyListener;
@ -126,12 +126,12 @@ public class XmrTxProofService implements AssetTxProofService {
// onAllServicesInitialized is called once we have received the initial data but we want to have our // onAllServicesInitialized is called once we have received the initial data but we want to have our
// hidden service published and upDatedDataResponse received before we start. // hidden service published and upDatedDataResponse received before we start.
BooleanProperty isP2pBootstrapped = isP2pBootstrapped(); BooleanProperty isP2pBootstrapped = isP2pBootstrapped();
BooleanProperty hasSufficientBtcPeers = hasSufficientBtcPeers(); BooleanProperty hasSufficientXmrPeers = hasSufficientXmrPeers();
BooleanProperty isBtcBlockDownloadComplete = isBtcBlockDownloadComplete(); BooleanProperty isXmrBlockDownloadComplete = isXmrBlockDownloadComplete();
if (isP2pBootstrapped.get() && hasSufficientBtcPeers.get() && isBtcBlockDownloadComplete.get()) { if (isP2pBootstrapped.get() && hasSufficientXmrPeers.get() && isXmrBlockDownloadComplete.get()) {
onP2pNetworkAndWalletReady(); onP2pNetworkAndWalletReady();
} else { } else {
p2pNetworkAndWalletReady = EasyBind.combine(isP2pBootstrapped, hasSufficientBtcPeers, isBtcBlockDownloadComplete, p2pNetworkAndWalletReady = EasyBind.combine(isP2pBootstrapped, hasSufficientXmrPeers, isXmrBlockDownloadComplete,
(bootstrapped, sufficientPeers, downloadComplete) -> (bootstrapped, sufficientPeers, downloadComplete) ->
bootstrapped && sufficientPeers && downloadComplete); bootstrapped && sufficientPeers && downloadComplete);
@ -287,34 +287,34 @@ public class XmrTxProofService implements AssetTxProofService {
// Startup checks // Startup checks
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
private BooleanProperty isBtcBlockDownloadComplete() { private BooleanProperty isXmrBlockDownloadComplete() {
BooleanProperty result = new SimpleBooleanProperty(); BooleanProperty result = new SimpleBooleanProperty();
if (walletsSetup.isDownloadComplete()) { if (walletsSetup.isDownloadComplete()) {
result.set(true); result.set(true);
} else { } else {
btcBlockListener = (observable, oldValue, newValue) -> { xmrBlockListener = (observable, oldValue, newValue) -> {
if (walletsSetup.isDownloadComplete()) { if (walletsSetup.isDownloadComplete()) {
walletsSetup.downloadPercentageProperty().removeListener(btcBlockListener); walletsSetup.downloadPercentageProperty().removeListener(xmrBlockListener);
result.set(true); result.set(true);
} }
}; };
walletsSetup.downloadPercentageProperty().addListener(btcBlockListener); walletsSetup.downloadPercentageProperty().addListener(xmrBlockListener);
} }
return result; return result;
} }
private BooleanProperty hasSufficientBtcPeers() { private BooleanProperty hasSufficientXmrPeers() {
BooleanProperty result = new SimpleBooleanProperty(); BooleanProperty result = new SimpleBooleanProperty();
if (walletsSetup.hasSufficientPeersForBroadcast()) { if (walletsSetup.hasSufficientPeersForBroadcast()) {
result.set(true); result.set(true);
} else { } else {
btcPeersListener = (observable, oldValue, newValue) -> { xmrPeersListener = (observable, oldValue, newValue) -> {
if (walletsSetup.hasSufficientPeersForBroadcast()) { if (walletsSetup.hasSufficientPeersForBroadcast()) {
walletsSetup.numPeersProperty().removeListener(btcPeersListener); walletsSetup.numPeersProperty().removeListener(xmrPeersListener);
result.set(true); result.set(true);
} }
}; };
walletsSetup.numPeersProperty().addListener(btcPeersListener); walletsSetup.numPeersProperty().addListener(xmrPeersListener);
} }
return result; return result;
} }

View File

@ -17,28 +17,28 @@
package bisq.desktop.main.settings.network; package bisq.desktop.main.settings.network;
import org.bitcoinj.core.Peer; import monero.daemon.model.MoneroDaemonConnection;
public class BitcoinNetworkListItem { public class MoneroNetworkListItem {
private final Peer peer; private final MoneroDaemonConnection peerConnection;
public BitcoinNetworkListItem(Peer peer) { public MoneroNetworkListItem(MoneroDaemonConnection peerConnection) {
this.peer = peer; this.peerConnection = peerConnection;
} }
public String getOnionAddress() { public String getOnionAddress() {
return peer.getAddress().toString(); return peerConnection.getPeer().getHost() + ":" + peerConnection.getPeer().getPort();
} }
public String getVersion() { public String getVersion() {
return String.valueOf(peer.getPeerVersionMessage().clientVersion); return "";
} }
public String getSubVersion() { public String getSubVersion() {
return peer.getPeerVersionMessage().subVer; return "";
} }
public String getHeight() { public String getHeight() {
return String.valueOf(peer.getBestHeight()); return String.valueOf(peerConnection.getHeight());
} }
} }

View File

@ -46,24 +46,24 @@
<TitledGroupBg fx:id="btcHeader" GridPane.rowSpan="5"/> <TitledGroupBg fx:id="btcHeader" GridPane.rowSpan="5"/>
<VBox GridPane.rowIndex="0" GridPane.hgrow="ALWAYS" GridPane.vgrow="SOMETIMES"> <VBox GridPane.rowIndex="0" GridPane.hgrow="ALWAYS" GridPane.vgrow="SOMETIMES">
<AutoTooltipLabel fx:id="bitcoinPeersLabel" styleClass="small-text"/> <AutoTooltipLabel fx:id="bitcoinPeersLabel" styleClass="small-text"/>
<TableView fx:id="bitcoinPeersTableView"> <TableView fx:id="moneroPeersTableView">
<columns> <columns>
<TableColumn fx:id="bitcoinPeerAddressColumn" minWidth="220"> <TableColumn fx:id="moneroPeerAddressColumn" minWidth="220">
<cellValueFactory> <cellValueFactory>
<PropertyValueFactory property="onionAddress"/> <PropertyValueFactory property="onionAddress"/>
</cellValueFactory> </cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn fx:id="bitcoinPeerVersionColumn" minWidth="80" maxWidth="90"> <TableColumn fx:id="moneroPeerVersionColumn" minWidth="80" maxWidth="90">
<cellValueFactory> <cellValueFactory>
<PropertyValueFactory property="version"/> <PropertyValueFactory property="version"/>
</cellValueFactory> </cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn fx:id="bitcoinPeerSubVersionColumn" minWidth="180" maxWidth="180"> <TableColumn fx:id="moneroPeerSubVersionColumn" minWidth="180" maxWidth="180">
<cellValueFactory> <cellValueFactory>
<PropertyValueFactory property="subVersion"/> <PropertyValueFactory property="subVersion"/>
</cellValueFactory> </cellValueFactory>
</TableColumn> </TableColumn>
<TableColumn fx:id="bitcoinPeerHeightColumn" minWidth="80" maxWidth="80"> <TableColumn fx:id="moneroPeerHeightColumn" minWidth="80" maxWidth="80">
<cellValueFactory> <cellValueFactory>
<PropertyValueFactory property="height"/> <PropertyValueFactory property="height"/>
</cellValueFactory> </cellValueFactory>

View File

@ -45,8 +45,6 @@ import bisq.network.p2p.network.Statistic;
import bisq.common.ClockWatcher; import bisq.common.ClockWatcher;
import bisq.common.UserThread; import bisq.common.UserThread;
import org.bitcoinj.core.PeerGroup;
import javax.inject.Inject; import javax.inject.Inject;
import javafx.fxml.FXML; import javafx.fxml.FXML;
@ -73,11 +71,14 @@ import javafx.collections.FXCollections;
import javafx.collections.ObservableList; import javafx.collections.ObservableList;
import javafx.collections.transformation.SortedList; import javafx.collections.transformation.SortedList;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static javafx.beans.binding.Bindings.createStringBinding; import static javafx.beans.binding.Bindings.createStringBinding;
import monero.daemon.model.MoneroDaemonConnection;
@FxmlView @FxmlView
public class NetworkSettingsView extends ActivatableView<GridPane, Void> { public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
@ -98,13 +99,13 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
@FXML @FXML
TableView<P2pNetworkListItem> p2pPeersTableView; TableView<P2pNetworkListItem> p2pPeersTableView;
@FXML @FXML
TableView<BitcoinNetworkListItem> bitcoinPeersTableView; TableView<MoneroNetworkListItem> moneroPeersTableView;
@FXML @FXML
TableColumn<P2pNetworkListItem, String> onionAddressColumn, connectionTypeColumn, creationDateColumn, TableColumn<P2pNetworkListItem, String> onionAddressColumn, connectionTypeColumn, creationDateColumn,
roundTripTimeColumn, sentBytesColumn, receivedBytesColumn, peerTypeColumn; roundTripTimeColumn, sentBytesColumn, receivedBytesColumn, peerTypeColumn;
@FXML @FXML
TableColumn<BitcoinNetworkListItem, String> bitcoinPeerAddressColumn, bitcoinPeerVersionColumn, TableColumn<MoneroNetworkListItem, String> moneroPeerAddressColumn, moneroPeerVersionColumn,
bitcoinPeerSubVersionColumn, bitcoinPeerHeightColumn; moneroPeerSubVersionColumn, moneroPeerHeightColumn;
@FXML @FXML
Label reSyncSPVChainLabel; Label reSyncSPVChainLabel;
@FXML @FXML
@ -122,13 +123,12 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
private final ObservableList<P2pNetworkListItem> p2pNetworkListItems = FXCollections.observableArrayList(); private final ObservableList<P2pNetworkListItem> p2pNetworkListItems = FXCollections.observableArrayList();
private final SortedList<P2pNetworkListItem> p2pSortedList = new SortedList<>(p2pNetworkListItems); private final SortedList<P2pNetworkListItem> p2pSortedList = new SortedList<>(p2pNetworkListItems);
private final ObservableList<BitcoinNetworkListItem> bitcoinNetworkListItems = FXCollections.observableArrayList(); private final ObservableList<MoneroNetworkListItem> moneroNetworkListItems = FXCollections.observableArrayList();
private final SortedList<BitcoinNetworkListItem> bitcoinSortedList = new SortedList<>(bitcoinNetworkListItems); private final SortedList<MoneroNetworkListItem> moneroSortedList = new SortedList<>(moneroNetworkListItems);
private Subscription numP2PPeersSubscription; private Subscription numP2PPeersSubscription;
private Subscription bitcoinPeersSubscription; private Subscription moneroPeersSubscription;
private Subscription bitcoinBlockHeightSubscription; private Subscription moneroBlockHeightSubscription;
private Subscription bitcoinBlocksDownloadedSubscription;
private Subscription nodeAddressSubscription; private Subscription nodeAddressSubscription;
private ChangeListener<Boolean> btcNodesInputTextFieldFocusListener; private ChangeListener<Boolean> btcNodesInputTextFieldFocusListener;
private ToggleGroup bitcoinPeersToggleGroup; private ToggleGroup bitcoinPeersToggleGroup;
@ -156,6 +156,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
this.clockWatcher = clockWatcher; this.clockWatcher = clockWatcher;
} }
@Override
public void initialize() { public void initialize() {
btcHeader.setText(Res.get("settings.net.btcHeader")); btcHeader.setText(Res.get("settings.net.btcHeader"));
p2pHeader.setText(Res.get("settings.net.p2pHeader")); p2pHeader.setText(Res.get("settings.net.p2pHeader"));
@ -164,11 +165,11 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
bitcoinPeersLabel.setText(Res.get("settings.net.bitcoinPeersLabel")); bitcoinPeersLabel.setText(Res.get("settings.net.bitcoinPeersLabel"));
useTorForBtcJCheckBox.setText(Res.get("settings.net.useTorForBtcJLabel")); useTorForBtcJCheckBox.setText(Res.get("settings.net.useTorForBtcJLabel"));
bitcoinNodesLabel.setText(Res.get("settings.net.bitcoinNodesLabel")); bitcoinNodesLabel.setText(Res.get("settings.net.bitcoinNodesLabel"));
bitcoinPeerAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.onionAddressColumn"))); moneroPeerAddressColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.onionAddressColumn")));
bitcoinPeerAddressColumn.getStyleClass().add("first-column"); moneroPeerAddressColumn.getStyleClass().add("first-column");
bitcoinPeerVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.versionColumn"))); moneroPeerVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.versionColumn")));
bitcoinPeerSubVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.subVersionColumn"))); moneroPeerSubVersionColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.subVersionColumn")));
bitcoinPeerHeightColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.heightColumn"))); moneroPeerHeightColumn.setGraphic(new AutoTooltipLabel(Res.get("settings.net.heightColumn")));
localhostBtcNodeInfoLabel.setText(Res.get("settings.net.localhostBtcNodeInfo")); localhostBtcNodeInfoLabel.setText(Res.get("settings.net.localhostBtcNodeInfo"));
useProvidedNodesRadio.setText(Res.get("settings.net.useProvidedNodesRadio")); useProvidedNodesRadio.setText(Res.get("settings.net.useProvidedNodesRadio"));
useCustomNodesRadio.setText(Res.get("settings.net.useCustomNodesRadio")); useCustomNodesRadio.setText(Res.get("settings.net.useCustomNodesRadio"));
@ -196,12 +197,12 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
GridPane.setMargin(p2PPeersLabel, new Insets(4, 0, 0, 0)); GridPane.setMargin(p2PPeersLabel, new Insets(4, 0, 0, 0));
GridPane.setValignment(p2PPeersLabel, VPos.TOP); GridPane.setValignment(p2PPeersLabel, VPos.TOP);
bitcoinPeersTableView.setMinHeight(180); moneroPeersTableView.setMinHeight(180);
bitcoinPeersTableView.setPrefHeight(180); moneroPeersTableView.setPrefHeight(180);
bitcoinPeersTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY); moneroPeersTableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
bitcoinPeersTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData"))); moneroPeersTableView.setPlaceholder(new AutoTooltipLabel(Res.get("table.placeholder.noData")));
bitcoinPeersTableView.getSortOrder().add(bitcoinPeerAddressColumn); moneroPeersTableView.getSortOrder().add(moneroPeerAddressColumn);
bitcoinPeerAddressColumn.setSortType(TableColumn.SortType.ASCENDING); moneroPeerAddressColumn.setSortType(TableColumn.SortType.ASCENDING);
p2pPeersTableView.setMinHeight(180); p2pPeersTableView.setMinHeight(180);
@ -290,14 +291,11 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
reSyncSPVChainButton.setOnAction(event -> GUIUtil.reSyncSPVChain(preferences)); reSyncSPVChainButton.setOnAction(event -> GUIUtil.reSyncSPVChain(preferences));
bitcoinPeersSubscription = EasyBind.subscribe(walletsSetup.connectedPeersProperty(), moneroPeersSubscription = EasyBind.subscribe(walletsSetup.peerConnectionsProperty(),
connectedPeers -> updateBitcoinPeersTable()); this::updateMoneroPeersTable);
bitcoinBlocksDownloadedSubscription = EasyBind.subscribe(walletsSetup.blocksDownloadedFromPeerProperty(), moneroBlockHeightSubscription = EasyBind.subscribe(walletsSetup.chainHeightProperty(),
peer -> updateBitcoinPeersTable()); this::updateChainHeightTextField);
bitcoinBlockHeightSubscription = EasyBind.subscribe(walletsSetup.chainHeightProperty(),
chainHeight -> updateBitcoinPeersTable());
nodeAddressSubscription = EasyBind.subscribe(p2PService.getNetworkNode().nodeAddressProperty(), nodeAddressSubscription = EasyBind.subscribe(p2PService.getNetworkNode().nodeAddressProperty(),
nodeAddress -> onionAddress.setText(nodeAddress == null ? nodeAddress -> onionAddress.setText(nodeAddress == null ?
@ -317,8 +315,8 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
Statistic.numTotalReceivedMessagesPerSecProperty().get()), Statistic.numTotalReceivedMessagesPerSecProperty().get()),
Statistic.numTotalReceivedMessagesPerSecProperty())); Statistic.numTotalReceivedMessagesPerSecProperty()));
bitcoinSortedList.comparatorProperty().bind(bitcoinPeersTableView.comparatorProperty()); moneroSortedList.comparatorProperty().bind(moneroPeersTableView.comparatorProperty());
bitcoinPeersTableView.setItems(bitcoinSortedList); moneroPeersTableView.setItems(moneroSortedList);
p2pSortedList.comparatorProperty().bind(p2pPeersTableView.comparatorProperty()); p2pSortedList.comparatorProperty().bind(p2pPeersTableView.comparatorProperty());
p2pPeersTableView.setItems(p2pSortedList); p2pPeersTableView.setItems(p2pSortedList);
@ -340,14 +338,11 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
if (nodeAddressSubscription != null) if (nodeAddressSubscription != null)
nodeAddressSubscription.unsubscribe(); nodeAddressSubscription.unsubscribe();
if (bitcoinPeersSubscription != null) if (moneroPeersSubscription != null)
bitcoinPeersSubscription.unsubscribe(); moneroPeersSubscription.unsubscribe();
if (bitcoinBlockHeightSubscription != null) if (moneroBlockHeightSubscription != null)
bitcoinBlockHeightSubscription.unsubscribe(); moneroBlockHeightSubscription.unsubscribe();
if (bitcoinBlocksDownloadedSubscription != null)
bitcoinBlocksDownloadedSubscription.unsubscribe();
if (numP2PPeersSubscription != null) if (numP2PPeersSubscription != null)
numP2PPeersSubscription.unsubscribe(); numP2PPeersSubscription.unsubscribe();
@ -355,7 +350,7 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
sentDataTextField.textProperty().unbind(); sentDataTextField.textProperty().unbind();
receivedDataTextField.textProperty().unbind(); receivedDataTextField.textProperty().unbind();
bitcoinSortedList.comparatorProperty().unbind(); moneroSortedList.comparatorProperty().unbind();
p2pSortedList.comparatorProperty().unbind(); p2pSortedList.comparatorProperty().unbind();
p2pPeersTableView.getItems().forEach(P2pNetworkListItem::cleanup); p2pPeersTableView.getItems().forEach(P2pNetworkListItem::cleanup);
btcNodesInputTextField.focusedProperty().removeListener(btcNodesInputTextFieldFocusListener); btcNodesInputTextField.focusedProperty().removeListener(btcNodesInputTextFieldFocusListener);
@ -485,14 +480,17 @@ public class NetworkSettingsView extends ActivatableView<GridPane, Void> {
.collect(Collectors.toList())); .collect(Collectors.toList()));
} }
private void updateBitcoinPeersTable() { private void updateMoneroPeersTable(List<MoneroDaemonConnection> peerConnections) {
bitcoinNetworkListItems.clear(); moneroNetworkListItems.clear();
bitcoinNetworkListItems.setAll(walletsSetup.getPeerGroup().getConnectedPeers().stream() moneroNetworkListItems.setAll(peerConnections.stream()
.map(BitcoinNetworkListItem::new) .map(MoneroNetworkListItem::new)
.collect(Collectors.toList())); .collect(Collectors.toList()));
}
private void updateChainHeightTextField(Number chainHeight) {
chainHeightTextField.textProperty().setValue(Res.get("settings.net.chainHeight", chainHeightTextField.textProperty().setValue(Res.get("settings.net.chainHeight",
walletsSetup.chainHeightProperty().get(), null,
PeerGroup.getMostCommonChainHeight(walletsSetup.connectedPeersProperty().get()))); chainHeight));
} }
} }

View File

@ -11,22 +11,15 @@ On Ubuntu: `sudo apt install make wget git git-lfs openjdk-11-jdk`. The Bitcoin
1. Download this repository: `git clone https://github.com/haveno-dex/haveno.git` 1. Download this repository: `git clone https://github.com/haveno-dex/haveno.git`
2. Navigate to the root of the repository (`cd haveno`) and build the repository: run `make` in the terminal and wait until the process is completed (this will also download and verify the Monero and Bitcoin binaries). 2. Navigate to the root of the repository (`cd haveno`) and build the repository: run `make` in the terminal and wait until the process is completed (this will also download and verify the Monero and Bitcoin binaries).
## 3. Run Bitcoin ## 3. Connect to Monero stagenet
Run each of these commands in their own terminal window: The quickest way to get a Monero stagenet running is by connecting to our own shared instance (3a) so you won't have to do anything except mine coins for testing (step 5). If you prefer to have total control over the testing instance, you might prefer running your own private Monero stagenet (3b).
1. Run Bitcoin: `make bitcoind` ### 3a. Join our shared stagenet
2. Create bitcoin blocks: `make btc-blocks` (after running the command, this terminal window can be closed)
## 4. Connect to Monero stagenet
The quickest way to get a Monero stagenet running is by connecting to our own shared instance (4a) so you won't have to do anything except mine coins for testing (step 6). If you prefer to have total control over the testing instance, you might prefer running your own private Monero stagenet (4b).
### 4a. Join our shared stagenet
Run `make monero-shared` Run `make monero-shared`
### 4b. Run your own private stagenet ### 3b. Run your own private stagenet
1. In a new terminal window run `make monero-private1`; 1. In a new terminal window run `make monero-private1`;
1. In a new terminal window run `make monero-private2`; 1. In a new terminal window run `make monero-private2`;
@ -34,7 +27,7 @@ Run `make monero-shared`
`start_mining 56k9Yra1pxwcTYzqKcnLip8mymSQdEfA6V7476W9XhSiHPp1hAboo1F6na7kxTxwvXU6JjDQtu8VJdGj9FEcjkxGJfsyyah 1` `start_mining 56k9Yra1pxwcTYzqKcnLip8mymSQdEfA6V7476W9XhSiHPp1hAboo1F6na7kxTxwvXU6JjDQtu8VJdGj9FEcjkxGJfsyyah 1`
## 5. Deploy ## 4. Deploy
If you are a *screen* user, simply run `make deploy`. This command will open all needed Haveno instances (seednode, Alice, Bob, arbitrator) using *screen*. If this is the first time launching the arbitrator desktop application, register the arbitrator and mediator as explained in steps `5.3.1` and `5.3.2`. If you are a *screen* user, simply run `make deploy`. This command will open all needed Haveno instances (seednode, Alice, Bob, arbitrator) using *screen*. If this is the first time launching the arbitrator desktop application, register the arbitrator and mediator as explained in steps `5.3.1` and `5.3.2`.
@ -48,14 +41,14 @@ If you don't use *screen*, open 4 terminal windows and run in each one of them:
4. `make alice-desktop` or if you want to run Alice as a daemon: `make alice-daemon` 4. `make alice-desktop` or if you want to run Alice as a daemon: `make alice-daemon`
5. `make bob-desktop` or if you want to run Bob as a daemon: `make bob-daemon` 5. `make bob-desktop` or if you want to run Bob as a daemon: `make bob-daemon`
## 6. Fund your wallets ## 5. Fund your wallets
When running Alice and Bob, you'll see a Monero address prompted in the terminal. Send stagenet XMR to the addresses of both Alice and Bob to be able to initiate a trade. When running Alice and Bob, you'll see a Monero address prompted in the terminal. Send stagenet XMR to the addresses of both Alice and Bob to be able to initiate a trade.
You can fund the two wallets by mining some stagenet XMR coins to those addresses. To do so, open a terminal where you ran monerod and run: `start_mining ADDRESS 1`. You can fund the two wallets by mining some stagenet XMR coins to those addresses. To do so, open a terminal where you ran monerod and run: `start_mining ADDRESS 1`.
monerod will start mining stagenet coins on your device using one thread. Replace `ADDRESS` with the address of Alice first, and then Bob's. monerod will start mining stagenet coins on your device using one thread. Replace `ADDRESS` with the address of Alice first, and then Bob's. Run `stop_mining` to stop mining.
## 7. Start testing ## 6. Start testing
You are all set. Now that everything is running and your wallets are funded, you can create test trades between Alice and Bob. Remember to mine a few blocks after opening and accepting the test trade so the transaction will be confirmed. You are all set. Now that everything is running and your wallets are funded, you can create test trades between Alice and Bob. Remember to mine a few blocks after opening and accepting the test trade so the transaction will be confirmed.

View File

@ -97,7 +97,7 @@ while true; do
cd .localnet cd .localnet
if ! is_linux && ! is_mac; then if ! is_linux && ! is_mac; then
bins_deps=("bitcoind" "bitcoin-cli" "monerod" "monero-wallet-rpc") bins_deps=("monerod" "monero-wallet-rpc") # "bitcoind" "bitcoin-cli"
for i in ${bins_deps[@]}; do for i in ${bins_deps[@]}; do
[ -f "$i" ] || { echo "${i} not found."; echo "Dependencies are installed automatically only on Linux and Mac. Please manually install bitcoind, bitcoin-cli, monerod, and monero-wallet-rpc executables into haveno/.localnet/ before running make."; exit 1; } [ -f "$i" ] || { echo "${i} not found."; echo "Dependencies are installed automatically only on Linux and Mac. Please manually install bitcoind, bitcoin-cli, monerod, and monero-wallet-rpc executables into haveno/.localnet/ before running make."; exit 1; }
@ -106,6 +106,6 @@ while true; do
fi fi
dw_monero dw_monero
dw_bitcoin # dw_bitcoin
exit 0 exit 0
done done