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

@ -85,6 +85,7 @@ public class AppStartupState {
p2pNetworkAndWalletInitialized.subscribe((observable, oldValue, newValue) -> {
if (newValue) {
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 PeerAddress[] peerAddresses;
protected DownloadProgressTracker downloadListener;
protected DownloadListener downloadListener;
protected InputStream checkpoints;
protected String userAgent, version;
@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
* {@link DownloadProgressTracker} is a good choice.
*/
public WalletConfig setDownloadListener(DownloadProgressTracker listener) {
public WalletConfig setDownloadListener(DownloadListener listener) {
this.downloadListener = listener;
return this;
}
@ -388,7 +388,8 @@ public class WalletConfig extends AbstractIdleService {
System.out.println("Monero wallet uri: " + vXmrWallet.getRpcConnection().getUri());
// vXmrWallet.rescanSpent();
// vXmrWallet.rescanBlockchain();
vXmrWallet.sync();
vXmrWallet.sync(); // blocking
downloadListener.doneDownload();
vXmrWallet.save();
System.out.println("Loaded wallet balance: " + vXmrWallet.getBalance(0));
System.out.println("Loaded wallet unlocked balance: " + vXmrWallet.getUnlockedBalance(0));
@ -471,7 +472,7 @@ public class WalletConfig extends AbstractIdleService {
@Override
public void onSuccess(@Nullable Object result) {
//completeExtensionInitiations(vPeerGroup);
DownloadProgressTracker tracker = downloadListener == null ? new DownloadProgressTracker() : downloadListener;
DownloadProgressTracker tracker = new DownloadProgressTracker();
vPeerGroup.startBlockChainDownload(tracker);
}

View file

@ -45,11 +45,9 @@ import org.bitcoinj.core.Address;
import org.bitcoinj.core.BlockChain;
import org.bitcoinj.core.Context;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Peer;
import org.bitcoinj.core.PeerAddress;
import org.bitcoinj.core.PeerGroup;
import org.bitcoinj.core.RejectMessage;
import org.bitcoinj.core.listeners.DownloadProgressTracker;
import org.bitcoinj.utils.Threading;
import org.bitcoinj.wallet.DeterministicSeed;
import org.bitcoinj.wallet.Wallet;
@ -65,15 +63,15 @@ import com.google.common.util.concurrent.Service;
import org.apache.commons.lang3.StringUtils;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.LongProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyIntegerProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleLongProperty;
import javafx.beans.property.SimpleObjectProperty;
import java.net.InetAddress;
@ -85,7 +83,6 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -103,6 +100,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import monero.daemon.MoneroDaemon;
import monero.daemon.model.MoneroDaemonConnection;
import monero.wallet.MoneroWallet;
// Setup wallets and use WalletConfig for BitcoinJ wiring.
@ -112,6 +110,8 @@ import monero.wallet.MoneroWallet;
public class WalletsSetup {
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
public final BooleanProperty walletsSetupFailed = new SimpleBooleanProperty();
@ -135,9 +135,8 @@ public class WalletsSetup {
private final int walletRpcBindPort;
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 LongProperty chainHeight = new SimpleLongProperty(0);
private final ObjectProperty<List<MoneroDaemonConnection>> peerConnections = new SimpleObjectProperty<>();
private final DownloadListener downloadListener = new DownloadListener();
private final List<Runnable> setupCompletedHandlers = new ArrayList<>();
public final BooleanProperty shutDownComplete = new SimpleBooleanProperty();
@ -220,19 +219,11 @@ public class WalletsSetup {
if (preferences.getBitcoinNodes() != null && !preferences.getBitcoinNodes().isEmpty())
peerGroup.setAddPeersFromAddressMessage(false);
peerGroup.addConnectedEventListener((peer, peerCount) -> {
// We get called here on our user thread
numPeers.set(peerCount);
connectedPeers.set(peerGroup.getConnectedPeers());
});
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);
});
UserThread.runPeriodically(() -> {
peerConnections.set(getPeerConnections());
numPeers.set(peerConnections.get().size());
chainHeight.set(vXmrDaemon.getHeight());
}, DAEMON_POLL_INTERVAL_SECONDS);
// Need to be Threading.SAME_THREAD executor otherwise BitcoinJ will skip that listener
peerGroup.addPreMessageReceivedEventListener(Threading.SAME_THREAD, (peer, message) -> {
@ -247,16 +238,11 @@ public class WalletsSetup {
return message;
});
chain.addNewBestBlockListener(block -> {
UserThread.execute(() -> {
connectedPeers.set(peerGroup.getConnectedPeers());
chainHeight.set(block.getHeight());
});
});
// Map to user thread
UserThread.execute(() -> {
chainHeight.set(chain.getBestChainHeight());
peerConnections.set(getPeerConnections());
numPeers.set(peerConnections.get().size());
chainHeight.set(vXmrDaemon.getHeight());
addressEntryList.onWalletReady(walletConfig.btcWallet());
xmrAddressEntryList.onWalletReady(walletConfig.getXmrWallet());
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
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.setConfig(config);
@ -401,11 +393,10 @@ public class WalletsSetup {
}
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);
int minBroadcastConnections = btcNodesSetupPreferences.calculateMinBroadcastConnections(nodes);
walletConfig.setMinBroadcastConnections(minBroadcastConnections);
BtcNodesRepository repository = new BtcNodesRepository(nodes);
boolean isUseClearNodesWithProxies = (useAllProvidedNodes || btcNodesSetupPreferences.isUseCustomNodes());
@ -515,18 +506,14 @@ public class WalletsSetup {
return numPeers;
}
public ReadOnlyObjectProperty<List<Peer>> connectedPeersProperty() {
return connectedPeers;
public ReadOnlyObjectProperty<List<MoneroDaemonConnection>> peerConnectionsProperty() {
return peerConnections;
}
public ReadOnlyIntegerProperty chainHeightProperty() {
public LongProperty chainHeightProperty() {
return chainHeight;
}
public ReadOnlyObjectProperty<Peer> blocksDownloadedFromPeerProperty() {
return blocksDownloadedFromPeer;
}
public ReadOnlyDoubleProperty downloadPercentageProperty() {
return downloadListener.percentageProperty();
}
@ -536,8 +523,9 @@ public class WalletsSetup {
}
public boolean isChainHeightSyncedWithinTolerance() {
int peersChainHeight = PeerGroup.getMostCommonChainHeight(connectedPeers.get());
int bestChainHeight = walletConfig.chain().getBestChainHeight();
Long peersChainHeight = walletConfig.vXmrDaemon.getSyncInfo().getTargetHeight();
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) {
return true;
}
@ -566,28 +554,4 @@ public class WalletsSetup {
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 AutoConfirmSettings autoConfirmSettings;
private final Map<String, ChangeListener<Trade.State>> tradeStateListenerMap = new HashMap<>();
private ChangeListener<Number> btcPeersListener, btcBlockListener;
private ChangeListener<Number> xmrPeersListener, xmrBlockListener;
private BootstrapListener bootstrapListener;
private MonadicBinding<Boolean> p2pNetworkAndWalletReady;
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
// hidden service published and upDatedDataResponse received before we start.
BooleanProperty isP2pBootstrapped = isP2pBootstrapped();
BooleanProperty hasSufficientBtcPeers = hasSufficientBtcPeers();
BooleanProperty isBtcBlockDownloadComplete = isBtcBlockDownloadComplete();
if (isP2pBootstrapped.get() && hasSufficientBtcPeers.get() && isBtcBlockDownloadComplete.get()) {
BooleanProperty hasSufficientXmrPeers = hasSufficientXmrPeers();
BooleanProperty isXmrBlockDownloadComplete = isXmrBlockDownloadComplete();
if (isP2pBootstrapped.get() && hasSufficientXmrPeers.get() && isXmrBlockDownloadComplete.get()) {
onP2pNetworkAndWalletReady();
} else {
p2pNetworkAndWalletReady = EasyBind.combine(isP2pBootstrapped, hasSufficientBtcPeers, isBtcBlockDownloadComplete,
p2pNetworkAndWalletReady = EasyBind.combine(isP2pBootstrapped, hasSufficientXmrPeers, isXmrBlockDownloadComplete,
(bootstrapped, sufficientPeers, downloadComplete) ->
bootstrapped && sufficientPeers && downloadComplete);
@ -287,34 +287,34 @@ public class XmrTxProofService implements AssetTxProofService {
// Startup checks
///////////////////////////////////////////////////////////////////////////////////////////
private BooleanProperty isBtcBlockDownloadComplete() {
private BooleanProperty isXmrBlockDownloadComplete() {
BooleanProperty result = new SimpleBooleanProperty();
if (walletsSetup.isDownloadComplete()) {
result.set(true);
} else {
btcBlockListener = (observable, oldValue, newValue) -> {
xmrBlockListener = (observable, oldValue, newValue) -> {
if (walletsSetup.isDownloadComplete()) {
walletsSetup.downloadPercentageProperty().removeListener(btcBlockListener);
walletsSetup.downloadPercentageProperty().removeListener(xmrBlockListener);
result.set(true);
}
};
walletsSetup.downloadPercentageProperty().addListener(btcBlockListener);
walletsSetup.downloadPercentageProperty().addListener(xmrBlockListener);
}
return result;
}
private BooleanProperty hasSufficientBtcPeers() {
private BooleanProperty hasSufficientXmrPeers() {
BooleanProperty result = new SimpleBooleanProperty();
if (walletsSetup.hasSufficientPeersForBroadcast()) {
result.set(true);
} else {
btcPeersListener = (observable, oldValue, newValue) -> {
xmrPeersListener = (observable, oldValue, newValue) -> {
if (walletsSetup.hasSufficientPeersForBroadcast()) {
walletsSetup.numPeersProperty().removeListener(btcPeersListener);
walletsSetup.numPeersProperty().removeListener(xmrPeersListener);
result.set(true);
}
};
walletsSetup.numPeersProperty().addListener(btcPeersListener);
walletsSetup.numPeersProperty().addListener(xmrPeersListener);
}
return result;
}