diff --git a/core/src/main/java/bisq/core/btc/nodes/BtcNodeConverter.java b/core/src/main/java/bisq/core/btc/nodes/BtcNodeConverter.java index 7740b17e35..ce94e16d34 100644 --- a/core/src/main/java/bisq/core/btc/nodes/BtcNodeConverter.java +++ b/core/src/main/java/bisq/core/btc/nodes/BtcNodeConverter.java @@ -55,8 +55,7 @@ class BtcNodeConverter { PeerAddress convertOnionHost(BtcNode node) { // no DNS lookup for onion addresses String onionAddress = Objects.requireNonNull(node.getOnionAddress()); - PeerAddress result = new PeerAddress(onionAddress, node.getPort()); - return result; + return new PeerAddress(onionAddress, node.getPort()); } @Nullable @@ -69,7 +68,7 @@ class BtcNodeConverter { if (address != null) { result = create(address, port); } else { - log.warn("Lookup failed, no address for node", node); + log.warn("Lookup failed, no address for node {}", node); } } return result; @@ -85,7 +84,7 @@ class BtcNodeConverter { if (address != null) { result = create(proxy, address, port); } else { - log.warn("Lookup failed, no address for node", node); + log.warn("Lookup failed, no address for node {}", node); } } return result; diff --git a/core/src/main/java/bisq/core/btc/setup/BisqKeyChainFactory.java b/core/src/main/java/bisq/core/btc/setup/BisqKeyChainFactory.java index 5c31e0d64c..7c576a3c84 100644 --- a/core/src/main/java/bisq/core/btc/setup/BisqKeyChainFactory.java +++ b/core/src/main/java/bisq/core/btc/setup/BisqKeyChainFactory.java @@ -26,7 +26,6 @@ import org.bitcoinj.wallet.DeterministicKeyChain; import org.bitcoinj.wallet.DeterministicSeed; import org.bitcoinj.wallet.KeyChainGroupStructure; import org.bitcoinj.wallet.Protos; -import org.bitcoinj.wallet.UnreadableWalletException; import com.google.common.collect.ImmutableList; @@ -63,12 +62,12 @@ public class BisqKeyChainFactory extends DefaultKeyChainFactory { } @Override - public DeterministicKeyChain makeWatchingKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicKey accountKey, boolean isFollowingKey, boolean isMarried, Script.ScriptType outputScriptType) throws UnreadableWalletException { + public DeterministicKeyChain makeWatchingKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicKey accountKey, boolean isFollowingKey, boolean isMarried, Script.ScriptType outputScriptType) { throw new UnsupportedOperationException("Bisq is not supposed to use this"); } @Override - public DeterministicKeyChain makeSpendingKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicKey accountKey, boolean isMarried, Script.ScriptType outputScriptType) throws UnreadableWalletException { + public DeterministicKeyChain makeSpendingKeyChain(Protos.Key key, Protos.Key firstSubKey, DeterministicKey accountKey, boolean isMarried, Script.ScriptType outputScriptType) { throw new UnsupportedOperationException("Bisq is not supposed to use this"); } } diff --git a/core/src/main/java/bisq/core/btc/setup/WalletConfig.java b/core/src/main/java/bisq/core/btc/setup/WalletConfig.java index 13f18dd4f7..48d1d9e922 100644 --- a/core/src/main/java/bisq/core/btc/setup/WalletConfig.java +++ b/core/src/main/java/bisq/core/btc/setup/WalletConfig.java @@ -20,6 +20,7 @@ package bisq.core.btc.setup; import bisq.core.btc.nodes.LocalBitcoinNode; import bisq.core.btc.nodes.ProxySocketFactory; import bisq.core.btc.wallet.BisqRiskAnalysis; + import bisq.common.config.Config; import com.google.common.collect.*; @@ -54,9 +55,7 @@ import static com.google.common.base.Preconditions.*; /** *

Utility class that wraps the boilerplate needed to set up a new SPV bitcoinj app. Instantiate it with a directory * and file prefix, optionally configure a few things, then use startAsync and optionally awaitRunning. The object will - * construct and configure a {@link BlockChain}, {@link SPVBlockStore}, {@link Wallet} and {@link PeerGroup}. Depending - * on the value of the blockingStartup property, startup will be considered complete once the block chain has fully - * synchronized, so it can take a while.

+ * construct and configure a {@link BlockChain}, {@link SPVBlockStore}, {@link Wallet} and {@link PeerGroup}.

* *

To add listeners and modify the objects that are constructed, you can either do that by overriding the * {@link #onSetupCompleted()} method (which will run on a background thread) and make your changes there, @@ -92,16 +91,12 @@ public class WalletConfig extends AbstractIdleService { protected volatile File vBtcWalletFile; protected volatile File vBsqWalletFile; - protected boolean useAutoSave = true; protected PeerAddress[] peerAddresses; protected DownloadProgressTracker downloadListener; - protected boolean autoStop = true; protected InputStream checkpoints; - protected boolean blockingStartup = true; protected String userAgent, version; protected WalletProtobufSerializer.WalletFactory walletFactory; @Nullable protected DeterministicSeed restoreFromSeed; - @Nullable protected DeterministicKey restoreFromKey; @Nullable protected PeerDiscovery discovery; protected volatile Context context; @@ -124,8 +119,7 @@ public class WalletConfig extends AbstractIdleService { /** * Creates a new WalletConfig, with the given {@link Context}. Files will be stored in the given directory. */ - public WalletConfig(Context context, - File directory, String filePrefix) { + private WalletConfig(Context context, File directory, String filePrefix) { this.context = context; this.params = checkNotNull(context.getParams()); this.directory = checkDir(directory); @@ -170,29 +164,15 @@ public class WalletConfig extends AbstractIdleService { return setPeerNodes(new PeerAddress(params, localHost, params.getPort())); } - /** If true, the wallet will save itself to disk automatically whenever it changes. */ - public WalletConfig setAutoSave(boolean value) { - checkState(state() == State.NEW, "Cannot call after startup"); - useAutoSave = value; - return this; - } - /** * If you want to learn about the sync process, you can provide a listener here. For instance, a - * {@link DownloadProgressTracker} is a good choice. This has no effect unless setBlockingStartup(false) has been called - * too, due to some missing implementation code. + * {@link DownloadProgressTracker} is a good choice. */ public WalletConfig setDownloadListener(DownloadProgressTracker listener) { this.downloadListener = listener; return this; } - /** If true, will register a shutdown hook to stop the library. Defaults to true. */ - public WalletConfig setAutoStop(boolean autoStop) { - this.autoStop = autoStop; - return this; - } - /** * If set, the file is expected to contain a checkpoints file calculated with BuildCheckpoints. It makes initial * block sync faster for new users - please refer to the documentation on the bitcoinj website @@ -205,17 +185,6 @@ public class WalletConfig extends AbstractIdleService { return this; } - /** - * If true (the default) then the startup of this service won't be considered complete until the network has been - * brought up, peer connections established and the block chain synchronised. Therefore {@link #awaitRunning()} can - * potentially take a very long time. If false, then startup is considered complete once the network activity - * begins and peer connections/block chain sync will continue in the background. - */ - public WalletConfig setBlockingStartup(boolean blockingStartup) { - this.blockingStartup = blockingStartup; - return this; - } - /** * Sets the string that will appear in the subver field of the version message. * @param userAgent A short string that should be the name of your app, e.g. "My Wallet" @@ -227,14 +196,6 @@ public class WalletConfig extends AbstractIdleService { return this; } - /** - * Sets a wallet factory which will be used when the kit creates a new wallet. - */ - public WalletConfig setWalletFactory(WalletProtobufSerializer.WalletFactory walletFactory) { - this.walletFactory = walletFactory; - return this; - } - /** * If a seed is set here then any existing wallet that matches the file name will be renamed to a backup name, * the chain file will be deleted, and the wallet object will be instantiated with the given seed instead of @@ -248,19 +209,6 @@ public class WalletConfig extends AbstractIdleService { return this; } - /** - * If an account key is set here then any existing wallet that matches the file name will be renamed to a backup name, - * the chain file will be deleted, and the wallet object will be instantiated with the given key instead of - * a fresh seed being created. This is intended for restoring a wallet from an account key. To implement restore - * you would shut down the existing appkit, if any, then recreate it with the key given by the user, then start - * up the new kit. The next time your app starts it should work as normal (that is, don't keep calling this each - * time). - */ - public WalletConfig restoreWalletFromKey(DeterministicKey accountKey) { - this.restoreFromKey = accountKey; - return this; - } - /** * Sets the peer discovery class to use. If none is provided then DNS is used, which is a reasonable default. */ @@ -269,16 +217,6 @@ public class WalletConfig extends AbstractIdleService { return this; } - /** - *

Override this to return wallet extensions if any are necessary.

- * - *

When this is called, chain(), store(), and peerGroup() will return the created objects, however they are not - * initialized/started.

- */ - protected List provideWalletExtensions() throws Exception { - return ImmutableList.of(); - } - /** * This method is invoked on a background thread after all objects are initialised, but before the peer group * or block chain download is started. You can tweak the objects configuration here. @@ -287,49 +225,17 @@ public class WalletConfig extends AbstractIdleService { // Meant to be overridden by subclasses } - /** - * Tests to see if the spvchain file has an operating system file lock on it. Useful for checking if your app - * is already running. If another copy of your app is running and you start the appkit anyway, an exception will - * be thrown during the startup process. Returns false if the chain file does not exist or is a directory. - */ - public boolean isChainFileLocked() throws IOException { - RandomAccessFile file2 = null; - try { - File file = new File(directory, filePrefix + ".spvchain"); - if (!file.exists()) - return false; - if (file.isDirectory()) - return false; - file2 = new RandomAccessFile(file, "rw"); - FileLock lock = file2.getChannel().tryLock(); - if (lock == null) - return true; - lock.release(); - return false; - } finally { - if (file2 != null) - file2.close(); - } - } - @Override protected void startUp() throws Exception { // Runs in a separate thread. Context.propagate(context); - // bitcoinj's WalletAppKit creates the wallet directory if it was not created already, - // but WalletConfig should not do that. - // if (!directory.exists()) { - // if (!directory.mkdirs()) { - // throw new IOException("Could not create directory " + directory.getAbsolutePath()); - // } - // } log.info("Starting up with directory = {}", directory); try { File chainFile = new File(directory, filePrefix + ".spvchain"); boolean chainFileExists = chainFile.exists(); String btcPrefix = "_BTC"; vBtcWalletFile = new File(directory, filePrefix + btcPrefix + ".wallet"); - boolean shouldReplayWallet = (vBtcWalletFile.exists() && !chainFileExists) || restoreFromSeed != null || restoreFromKey != null; + boolean shouldReplayWallet = (vBtcWalletFile.exists() && !chainFileExists) || restoreFromSeed != null; vBtcWallet = createOrLoadWallet(shouldReplayWallet, vBtcWalletFile, false); vBtcWallet.allowSpendingUnconfirmedTransactions(); vBtcWallet.setRiskAnalyzer(new BisqRiskAnalysis.Analyzer()); @@ -341,8 +247,8 @@ public class WalletConfig extends AbstractIdleService { // Initiate Bitcoin network objects (block store, blockchain and peer group) vStore = new SPVBlockStore(params, chainFile); - if (!chainFileExists || restoreFromSeed != null || restoreFromKey != null) { - if (checkpoints == null && !Utils.isAndroidRuntime()) { + if (!chainFileExists || restoreFromSeed != null) { + if (checkpoints == null) { checkpoints = CheckpointManager.openStream(params); } @@ -355,12 +261,6 @@ public class WalletConfig extends AbstractIdleService { log.info("Clearing the chain file in preparation for restore."); vStore.clear(); } - } else if (restoreFromKey != null) { - time = restoreFromKey.getCreationTimeSeconds(); - if (chainFileExists) { - log.info("Clearing the chain file in preparation for restore."); - vStore.clear(); - } } else { time = vBtcWallet.getEarliestKeyCreationTime(); } @@ -398,32 +298,20 @@ public class WalletConfig extends AbstractIdleService { vPeerGroup.addWallet(vBsqWallet); onSetupCompleted(); - if (blockingStartup) { - vPeerGroup.start(); - // Make sure we shut down cleanly. - installShutdownHook(); - //completeExtensionInitiations(vPeerGroup); + Futures.addCallback((ListenableFuture) vPeerGroup.startAsync(), new FutureCallback() { + @Override + public void onSuccess(@Nullable Object result) { + //completeExtensionInitiations(vPeerGroup); + DownloadProgressTracker tracker = downloadListener == null ? new DownloadProgressTracker() : downloadListener; + vPeerGroup.startBlockChainDownload(tracker); + } - // TODO: Be able to use the provided download listener when doing a blocking startup. - final DownloadProgressTracker listener = new DownloadProgressTracker(); - vPeerGroup.startBlockChainDownload(listener); - listener.await(); - } else { - Futures.addCallback((ListenableFuture) vPeerGroup.startAsync(), new FutureCallback() { - @Override - public void onSuccess(@Nullable Object result) { - //completeExtensionInitiations(vPeerGroup); - final DownloadProgressTracker l = downloadListener == null ? new DownloadProgressTracker() : downloadListener; - vPeerGroup.startBlockChainDownload(l); - } + @Override + public void onFailure(Throwable t) { + throw new RuntimeException(t); - @Override - public void onFailure(Throwable t) { - throw new RuntimeException(t); - - } - }, MoreExecutors.directExecutor()); - } + } + }, MoreExecutors.directExecutor()); } catch (BlockStoreException e) { throw new IOException(e); } @@ -439,9 +327,6 @@ public class WalletConfig extends AbstractIdleService { } else { wallet = createWallet(isBsqWallet); wallet.freshReceiveKey(); - for (WalletExtension e : provideWalletExtensions()) { - wallet.addExtension(e); - } // Currently the only way we can be sure that an extension is aware of its containing wallet is by // deserializing the extension (see WalletExtension#deserializeWalletExtension(Wallet, byte[])) @@ -450,9 +335,7 @@ public class WalletConfig extends AbstractIdleService { wallet = loadWallet(false, walletFile, isBsqWallet); } - if (useAutoSave) { - this.setupAutoSave(wallet, walletFile); - } + this.setupAutoSave(wallet, walletFile); return wallet; } @@ -465,8 +348,7 @@ public class WalletConfig extends AbstractIdleService { Wallet wallet; FileInputStream walletStream = new FileInputStream(walletFile); try { - List extensions = provideWalletExtensions(); - WalletExtension[] extArray = extensions.toArray(new WalletExtension[extensions.size()]); + WalletExtension[] extArray = new WalletExtension[]{}; Protos.Wallet proto = WalletProtobufSerializer.parseToProto(walletStream); final WalletProtobufSerializer serializer; if (walletFactory != null) @@ -492,8 +374,6 @@ public class WalletConfig extends AbstractIdleService { KeyChainGroup.Builder kcg = KeyChainGroup.builder(params, structure); if (restoreFromSeed != null) { kcg.fromSeed(restoreFromSeed, preferredOutputScriptType).build(); - } else if (restoreFromKey != null) { - kcg.addChain(DeterministicKeyChain.builder().spend(restoreFromKey).outputScriptType(preferredOutputScriptType).build()); } else { // new wallet if (!isBsqWallet) { @@ -512,7 +392,7 @@ public class WalletConfig extends AbstractIdleService { } private void maybeMoveOldWalletOutOfTheWay(File walletFile) { - if (restoreFromSeed == null && restoreFromKey == null) return; + if (restoreFromSeed == null) return; if (!walletFile.exists()) return; int counter = 1; File newName; @@ -527,23 +407,6 @@ public class WalletConfig extends AbstractIdleService { } } - /* - * As soon as the transaction broadcaster han been created we will pass it to the - * payment channel extensions - */ - // private void completeExtensionInitiations(TransactionBroadcaster transactionBroadcaster) { - // StoredPaymentChannelClientStates clientStoredChannels = (StoredPaymentChannelClientStates) - // vWallet.getExtensions().get(StoredPaymentChannelClientStates.class.getName()); - // if(clientStoredChannels != null) { - // clientStoredChannels.setTransactionBroadcaster(transactionBroadcaster); - // } - // StoredPaymentChannelServerStates serverStoredChannels = (StoredPaymentChannelServerStates) - // vWallet.getExtensions().get(StoredPaymentChannelServerStates.class.getName()); - // if(serverStoredChannels != null) { - // serverStoredChannels.setTransactionBroadcaster(transactionBroadcaster); - // } - // } - private PeerGroup createPeerGroup() { PeerGroup peerGroup; // no proxy case. @@ -573,19 +436,6 @@ public class WalletConfig extends AbstractIdleService { return peerGroup; } - private void installShutdownHook() { - if (autoStop) Runtime.getRuntime().addShutdownHook(new Thread("WalletConfig ShutdownHook") { - @Override public void run() { - try { - WalletConfig.this.stopAsync(); - WalletConfig.this.awaitTerminated(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - }); - } - @Override protected void shutDown() throws Exception { // Runs in a separate thread. diff --git a/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java b/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java index 1f3cc0aab3..e94e65bbea 100644 --- a/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java +++ b/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java @@ -249,7 +249,7 @@ public class WalletsSetup { UserThread.execute(() -> { addressEntryList.onWalletReady(walletConfig.btcWallet()); timeoutTimer.stop(); - setupCompletedHandlers.stream().forEach(Runnable::run); + setupCompletedHandlers.forEach(Runnable::run); }); // onSetupCompleted in walletAppKit is not the called on the last invocations, so we add a bit of delay @@ -307,11 +307,12 @@ public class WalletsSetup { } } - walletConfig.setDownloadListener(downloadListener) - .setBlockingStartup(false); + walletConfig.setDownloadListener(downloadListener); // If seed is non-null it means we are restoring from backup. - walletConfig.restoreWalletFromSeed(seed); + if (seed != null) { + walletConfig.restoreWalletFromSeed(seed); + } walletConfig.addListener(new Service.Listener() { @Override diff --git a/core/src/main/java/bisq/core/btc/wallet/BtcWalletService.java b/core/src/main/java/bisq/core/btc/wallet/BtcWalletService.java index d75e4f273b..bb92c92187 100644 --- a/core/src/main/java/bisq/core/btc/wallet/BtcWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/BtcWalletService.java @@ -123,7 +123,7 @@ public class BtcWalletService extends WalletService { @Override void encryptWallet(KeyCrypterScrypt keyCrypterScrypt, KeyParameter key) { super.encryptWallet(keyCrypterScrypt, key); - addressEntryList.getAddressEntriesAsListImmutable().stream().forEach(e -> { + addressEntryList.getAddressEntriesAsListImmutable().forEach(e -> { DeterministicKey keyPair = e.getKeyPair(); if (keyPair.isEncrypted()) e.setDeterministicKey(keyPair.encrypt(keyCrypterScrypt, key)); @@ -134,7 +134,7 @@ public class BtcWalletService extends WalletService { @Override String getWalletAsString(boolean includePrivKeys) { StringBuilder sb = new StringBuilder(); - getAddressEntryListAsImmutableList().stream().forEach(e -> sb.append(e.toString()).append("\n")); + getAddressEntryListAsImmutableList().forEach(e -> sb.append(e.toString()).append("\n")); return "Address entry list:\n" + sb.toString() + "\n\n" + diff --git a/core/src/main/java/bisq/core/btc/wallet/WalletService.java b/core/src/main/java/bisq/core/btc/wallet/WalletService.java index 65a41e51a7..a8d825049a 100644 --- a/core/src/main/java/bisq/core/btc/wallet/WalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/WalletService.java @@ -38,8 +38,6 @@ import org.bitcoinj.core.Context; import org.bitcoinj.core.ECKey; import org.bitcoinj.core.InsufficientMoneyException; import org.bitcoinj.core.NetworkParameters; -import org.bitcoinj.core.listeners.TransactionConfidenceEventListener; -import org.bitcoinj.script.ScriptException; import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Transaction; import org.bitcoinj.core.TransactionConfidence; @@ -47,12 +45,14 @@ import org.bitcoinj.core.TransactionInput; import org.bitcoinj.core.TransactionOutput; import org.bitcoinj.core.VerificationException; import org.bitcoinj.core.listeners.NewBestBlockListener; +import org.bitcoinj.core.listeners.TransactionConfidenceEventListener; import org.bitcoinj.crypto.DeterministicKey; import org.bitcoinj.crypto.KeyCrypter; import org.bitcoinj.crypto.KeyCrypterScrypt; import org.bitcoinj.crypto.TransactionSignature; import org.bitcoinj.script.Script; import org.bitcoinj.script.ScriptChunk; +import org.bitcoinj.script.ScriptException; import org.bitcoinj.script.ScriptPattern; import org.bitcoinj.signers.TransactionSigner; import org.bitcoinj.utils.Threading; @@ -106,7 +106,6 @@ public abstract class WalletService { protected final Preferences preferences; protected final FeeService feeService; protected final NetworkParameters params; - @SuppressWarnings("deprecation") protected final BisqWalletListener walletEventListener = new BisqWalletListener(); protected final CopyOnWriteArraySet addressConfidenceListeners = new CopyOnWriteArraySet<>(); protected final CopyOnWriteArraySet txConfidenceListeners = new CopyOnWriteArraySet<>(); diff --git a/core/src/main/java/bisq/core/dao/governance/proposal/BaseProposalFactory.java b/core/src/main/java/bisq/core/dao/governance/proposal/BaseProposalFactory.java index 2ed73422e0..53c2967feb 100644 --- a/core/src/main/java/bisq/core/dao/governance/proposal/BaseProposalFactory.java +++ b/core/src/main/java/bisq/core/dao/governance/proposal/BaseProposalFactory.java @@ -74,7 +74,7 @@ public abstract class BaseProposalFactory { R proposal = createProposalWithoutTxId(); proposalValidator.validateDataFields(proposal); Transaction transaction = createTransaction(proposal); - final Proposal proposalWithTxId = proposal.cloneProposalAndAddTxId(transaction.getTxId().toString()); + Proposal proposalWithTxId = proposal.cloneProposalAndAddTxId(transaction.getTxId().toString()); return new ProposalWithTransaction(proposalWithTxId, transaction); } diff --git a/core/src/main/java/bisq/core/trade/Trade.java b/core/src/main/java/bisq/core/trade/Trade.java index 4f0f900a38..26140812ab 100644 --- a/core/src/main/java/bisq/core/trade/Trade.java +++ b/core/src/main/java/bisq/core/trade/Trade.java @@ -952,7 +952,8 @@ public abstract class Trade implements Tradable, Model { log.debug("We set the start for the trade period to {}. Trade started at: {}. Block got mined at: {}", new Date(startTime), new Date(tradeTime), new Date(blockTime)); } else { - log.debug("depositTx not confirmed yet. We don't start counting remaining trade period yet. txId={}", depositTx.getTxId().toString()); + log.debug("depositTx not confirmed yet. We don't start counting remaining trade period yet. txId={}", + depositTx.getTxId().toString()); startTime = now; } } else { diff --git a/desktop/src/main/java/bisq/desktop/main/overlays/windows/SelectDepositTxWindow.java b/desktop/src/main/java/bisq/desktop/main/overlays/windows/SelectDepositTxWindow.java index aa50f23ab8..c736c02476 100644 --- a/desktop/src/main/java/bisq/desktop/main/overlays/windows/SelectDepositTxWindow.java +++ b/desktop/src/main/java/bisq/desktop/main/overlays/windows/SelectDepositTxWindow.java @@ -104,7 +104,9 @@ public class SelectDepositTxWindow extends Overlay { }); transactionsComboBox.setItems(FXCollections.observableArrayList(transactions)); transactionsComboBox.setOnAction(event -> { - selectHandlerOptional.get().accept(transactionsComboBox.getSelectionModel().getSelectedItem()); + if (selectHandlerOptional.isPresent()) { + selectHandlerOptional.get().accept(transactionsComboBox.getSelectionModel().getSelectedItem()); + } hide(); }); }