diff --git a/application/src/main/java/bisq/application/DefaultApplicationService.java b/application/src/main/java/bisq/application/DefaultApplicationService.java index 7ca25ec782..075d0451aa 100644 --- a/application/src/main/java/bisq/application/DefaultApplicationService.java +++ b/application/src/main/java/bisq/application/DefaultApplicationService.java @@ -82,8 +82,8 @@ public enum State { public DefaultApplicationService(String[] args) { super("default", args); - bitcoinWalletService = new BitcoinWalletService(persistenceService, config.getBaseDir(), config.isBitcoindRegtest()); - liquidWalletService = new LiquidWalletService(persistenceService, config.getBaseDir(), config.isElementsdRegtest()); + bitcoinWalletService = new BitcoinWalletService(persistenceService, config.isBitcoindRegtest()); + liquidWalletService = new LiquidWalletService(persistenceService, config.isElementsdRegtest()); securityService = new SecurityService(persistenceService); diff --git a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/AbstractBitcoindWalletService.java b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/AbstractBitcoindWalletService.java index bcd68ccb45..2c325bcfa7 100644 --- a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/AbstractBitcoindWalletService.java +++ b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/AbstractBitcoindWalletService.java @@ -34,8 +34,6 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import java.io.File; -import java.nio.file.Path; import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -61,7 +59,7 @@ public static Optional getOptionalRegtestConfig(boolean isRegtest, in private final String currencyCode; protected final Optional optionalRpcConfig; - protected final Path walletsDataDir; + protected final String walletName; @Getter protected final Observable observableBalanceAsCoin; @@ -72,10 +70,10 @@ public static Optional getOptionalRegtestConfig(boolean isRegtest, in public AbstractBitcoindWalletService(String currencyCode, Optional optionalRpcConfig, - Path walletsDataDir) { + String walletName) { this.currencyCode = currencyCode; this.optionalRpcConfig = optionalRpcConfig; - this.walletsDataDir = walletsDataDir; + this.walletName = walletName; observableBalanceAsCoin = new Observable<>(Coin.of(0, currencyCode)); } @@ -87,7 +85,6 @@ public AbstractBitcoindWalletService(String currencyCode, @Override public CompletableFuture initialize() { log.info("initialize"); - createWalletsDataDirIfNotExisting(); boolean isSuccess = verifyRpcConfigAndCreateWallet(optionalRpcConfig); // No cmd line arguments passed, so try to use saved configuration @@ -135,7 +132,7 @@ public CompletableFuture initializeWallet(RpcConfig rpcConfig, Optional initializeZmqListeners(zmqConnection, receiveAddresses); this.zmqConnection = Optional.of(zmqConnection); - log.info("Successfully created/loaded wallet at {}", walletsDataDir); + log.info("Successfully created/loaded wallet at {}", walletName); updateBalance(); @@ -230,17 +227,6 @@ protected Wallet getWalletOrThrowException() { protected abstract T createWallet(RpcConfig rpcConfig); - private void createWalletsDataDirIfNotExisting() { - File dataDir = walletsDataDir.toFile(); - if (!dataDir.exists()) { - boolean isSuccess = walletsDataDir.toFile().mkdirs(); - if (!isSuccess) { - throw new WalletNotInitializedException("Couldn't create wallets data dir: " + - dataDir.getAbsolutePath()); - } - } - } - private boolean verifyRpcConfigAndCreateWallet(Optional optionalRpcConfig) { if (optionalRpcConfig.isEmpty()) return false; diff --git a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/BitcoinWallet.java b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/BitcoinWallet.java index 209aae5859..472893fb3b 100644 --- a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/BitcoinWallet.java +++ b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/BitcoinWallet.java @@ -31,7 +31,6 @@ import lombok.Getter; import java.net.MalformedURLException; -import java.nio.file.Path; import java.util.List; import java.util.Optional; @@ -45,7 +44,7 @@ public class BitcoinWallet implements Wallet, ZmqWallet { @Getter private final ZmqConnection zmqConnection; - public BitcoinWallet(Path walletPath, + public BitcoinWallet(String walletName, RpcConfig rpcConfig, BitcoindDaemon daemon, ObservableSet receiveAddresses, @@ -54,7 +53,7 @@ public BitcoinWallet(Path walletPath, this.zmqConnection = zmqConnection; try { - wallet = new BitcoindWallet(daemon, rpcConfig, walletPath); + wallet = new BitcoindWallet(daemon, rpcConfig, walletName); } catch (MalformedURLException e) { throw new WalletInitializationFailedException("Couldn't initialize BitcoinWalletService", e); } diff --git a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/BitcoinWalletService.java b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/BitcoinWalletService.java index 2c5a092230..7a1c8d9542 100644 --- a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/BitcoinWalletService.java +++ b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/BitcoinWalletService.java @@ -23,8 +23,6 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import java.io.File; -import java.nio.file.Path; import java.util.Optional; @Slf4j @@ -36,15 +34,14 @@ public class BitcoinWalletService extends AbstractBitcoindWalletService persistence; public BitcoinWalletService(PersistenceService persistenceService, - String baseDir, boolean isRegtest) { - super("BTC", getOptionalRegtestConfig(isRegtest, 18443), Path.of(baseDir + File.separator + "wallets")); + super("BTC", getOptionalRegtestConfig(isRegtest, 18443), "bisq_bitcoind_default_wallet"); persistence = persistenceService.getOrCreatePersistence(this, persistableStore); } @Override protected BitcoinWallet createWallet(RpcConfig rpcConfig) { - return WalletFactory.createBitcoinWallet(rpcConfig, walletsDataDir, persistableStore); + return WalletFactory.createBitcoinWallet(rpcConfig, walletName, persistableStore); } diff --git a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/WalletFactory.java b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/WalletFactory.java index 8aa8e35819..b61a76180d 100644 --- a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/WalletFactory.java +++ b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/WalletFactory.java @@ -31,13 +31,11 @@ public class WalletFactory { public static BitcoinWallet createBitcoinWallet(RpcConfig rpcConfig, - Path walletsDataDir, + String walletName, BitcoinWalletStore bitcoinWalletStore) { - Path bitcoindDataDir = walletsDataDir.resolve("bitcoind"); // directory name for bitcoind wallet - BitcoindDaemon daemon = createBitcoindDaemon(rpcConfig); ZmqConnection zmqConnection = initializeBitcoindZeroMq(daemon); - return new BitcoinWallet(bitcoindDataDir, rpcConfig, daemon, bitcoinWalletStore.getReceiveAddresses(), zmqConnection); + return new BitcoinWallet(walletName, rpcConfig, daemon, bitcoinWalletStore.getReceiveAddresses(), zmqConnection); } private static BitcoindDaemon createBitcoindDaemon(RpcConfig rpcConfig) { diff --git a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/rpc/BitcoindDaemon.java b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/rpc/BitcoindDaemon.java index bf136f5243..02243e0d5f 100644 --- a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/rpc/BitcoindDaemon.java +++ b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/rpc/BitcoindDaemon.java @@ -23,10 +23,10 @@ import bisq.wallets.bitcoind.rpc.responses.BitcoindGetZmqNotificationsResponse; import bisq.wallets.core.RpcConfig; import bisq.wallets.core.exceptions.InvalidRpcCredentialsException; +import bisq.wallets.core.exceptions.RpcCallFailureException; import bisq.wallets.core.rpc.DaemonRpcClient; import bisq.wallets.core.rpc.RpcClientFactory; -import java.nio.file.Path; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -38,21 +38,23 @@ public BitcoindDaemon(DaemonRpcClient rpcClient) { this.rpcClient = rpcClient; } - public void createOrLoadWallet(Path walletPath, Optional passphrase) { - createOrLoadWallet(walletPath, passphrase, false, false); + public void createOrLoadWallet(String walletName, Optional passphrase) { + createOrLoadWallet(walletName, passphrase, false, false); } - public void createOrLoadWatchOnlyWallet(Path walletPath) { - createOrLoadWallet(walletPath, Optional.empty(), true, true); + public void createOrLoadWatchOnlyWallet(String walletName) { + createOrLoadWallet(walletName, Optional.empty(), true, true); } - private void createOrLoadWallet(Path walletPath, Optional passphrase, boolean disablePrivateKeys, boolean blank) { - if (!doesWalletExist(walletPath)) { - createWallet(walletPath, passphrase.orElse(""), disablePrivateKeys, blank); - } else { - List loadedWallets = listWallets(); - if (!loadedWallets.contains(walletPath.toString())) { - loadWallet(walletPath); + private void createOrLoadWallet(String walletName, Optional passphrase, boolean disablePrivateKeys, boolean blank) { + try { + createWallet(walletName, passphrase.orElse(""), disablePrivateKeys, blank); + } catch (RpcCallFailureException e) { + if (doesWalletExist(e)) { + List loadedWallets = listWallets(); + if (!loadedWallets.contains(walletName)) { + loadWallet(walletName); + } } } } @@ -124,9 +126,8 @@ public void stop() { rpcClient.invokeAndValidate(rpcCall); } - public void unloadWallet(Path walletPath) { - String absoluteWalletPath = walletPath.toAbsolutePath().toString(); - var request = new BitcoindUnloadWalletRpcCall.Request(absoluteWalletPath); + public void unloadWallet(String walletName) { + var request = new BitcoindUnloadWalletRpcCall.Request(walletName); var rpcCall = new BitcoindUnloadWalletRpcCall(request); rpcClient.invokeAndValidate(rpcCall); } @@ -141,13 +142,13 @@ public static boolean verifyRpcConfig(RpcConfig rpcConfig) { } } - private boolean doesWalletExist(Path walletPath) { - return walletPath.toFile().exists(); + private boolean doesWalletExist(RpcCallFailureException e) { + return e.getCause().getMessage().contains("Database already exists."); } - private void createWallet(Path walletPath, String passphrase, boolean disablePrivateKeys, boolean blank) { + private void createWallet(String walletName, String passphrase, boolean disablePrivateKeys, boolean blank) { var request = BitcoindCreateWalletRpcCall.Request.builder() - .walletName(walletPath.toAbsolutePath().toString()) + .walletName(walletName) .disablePrivateKeys(disablePrivateKeys) .blank(blank) .passphrase(passphrase) @@ -157,9 +158,8 @@ private void createWallet(Path walletPath, String passphrase, boolean disablePri rpcClient.invokeAndValidate(rpcCall); } - private void loadWallet(Path walletPath) { - String absoluteWalletPath = walletPath.toAbsolutePath().toString(); - var request = new BitcoindLoadWalletRpcCall.Request(absoluteWalletPath); + private void loadWallet(String walletName) { + var request = new BitcoindLoadWalletRpcCall.Request(walletName); var rpcCall = new BitcoindLoadWalletRpcCall(request); rpcClient.invokeAndValidate(rpcCall); } diff --git a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/rpc/BitcoindWallet.java b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/rpc/BitcoindWallet.java index f7790f2591..7c5575328a 100644 --- a/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/rpc/BitcoindWallet.java +++ b/wallets/bitcoind/src/main/java/bisq/wallets/bitcoind/rpc/BitcoindWallet.java @@ -28,7 +28,6 @@ import bisq.wallets.core.rpc.WalletRpcClient; import java.net.MalformedURLException; -import java.nio.file.Path; import java.util.Arrays; import java.util.List; import java.util.Map; @@ -41,19 +40,19 @@ public class BitcoindWallet { private final BitcoindDaemon daemon; private final WalletRpcClient rpcClient; - public BitcoindWallet(BitcoindDaemon daemon, RpcConfig rpcConfig, Path walletPath) throws MalformedURLException { + public BitcoindWallet(BitcoindDaemon daemon, RpcConfig rpcConfig, String walletName) throws MalformedURLException { this.daemon = daemon; - this.rpcClient = RpcClientFactory.createWalletRpcClient(rpcConfig, walletPath); + this.rpcClient = RpcClientFactory.createWalletRpcClient(rpcConfig, walletName); } public void initialize(Optional passphrase) { - Path walletPath = rpcClient.getWalletPath(); - daemon.createOrLoadWallet(walletPath, passphrase); + String walletName = rpcClient.getWalletName(); + daemon.createOrLoadWallet(walletName, passphrase); } public void shutdown() { - Path walletPath = rpcClient.getWalletPath(); - daemon.unloadWallet(walletPath); + String walletName = rpcClient.getWalletName(); + daemon.unloadWallet(walletName); } public BitcoindAddOrCreateMultiSigAddressResponse createMultiSig(int nRequired, List keys) { diff --git a/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindCreateWalletNameDocumentationIntegrationTests.java b/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindCreateWalletNameDocumentationIntegrationTests.java new file mode 100644 index 0000000000..b00da21599 --- /dev/null +++ b/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindCreateWalletNameDocumentationIntegrationTests.java @@ -0,0 +1,97 @@ +/* + * 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 . + */ + +package bisq.wallets.bitcoind; + +import bisq.wallets.bitcoind.regtest.BitcoindExtension; +import bisq.wallets.bitcoind.rpc.BitcoindDaemon; +import bisq.wallets.bitcoind.rpc.calls.BitcoindCreateWalletRpcCall; +import bisq.wallets.core.RpcConfig; +import bisq.wallets.core.rpc.DaemonRpcClient; +import bisq.wallets.core.rpc.RpcClientFactory; +import bisq.wallets.regtest.AbstractRegtestSetup; +import bisq.wallets.regtest.bitcoind.BitcoindRegtestSetup; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.OS; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(BitcoindExtension.class) +public class BitcoindCreateWalletNameDocumentationIntegrationTests { + private final Path dataDir; + private final DaemonRpcClient rpcClient; + private final BitcoindDaemon daemon; + + public BitcoindCreateWalletNameDocumentationIntegrationTests(BitcoindRegtestSetup regtestSetup) { + this.dataDir = regtestSetup.getDataDir(); + this.daemon = regtestSetup.getDaemon(); + RpcConfig rpcConfig = regtestSetup.getRpcConfig(); + this.rpcClient = RpcClientFactory.createDaemonRpcClient(rpcConfig); + } + + @Test + @EnabledOnOs({OS.MAC, OS.LINUX}) + void createWalletWithAbsolutePath(@TempDir Path walletPath) { + String walletName = walletPath.toAbsolutePath().toString(); + var request = BitcoindCreateWalletRpcCall.Request.builder() + .walletName(walletName) + .passphrase(AbstractRegtestSetup.WALLET_PASSPHRASE) + .build(); + + var rpcCall = new BitcoindCreateWalletRpcCall(request); + rpcClient.invokeAndValidate(rpcCall); + + File walletFile = walletPath.resolve("wallet.dat") + .toFile(); + assertThat(walletFile).exists(); + + daemon.unloadWallet(walletName); + } + + @Test + @EnabledOnOs({OS.MAC, OS.LINUX}) + void createWalletWithRelativePath() throws IOException { + File bitcoindWalletsDir = dataDir.resolve("regtest") + .resolve("wallets") + .toFile(); + Path newWalletDir = Files.createTempDirectory(bitcoindWalletsDir.toPath(), "bisq_"); + + String walletName = newWalletDir.getFileName() + "/b"; + var request = BitcoindCreateWalletRpcCall.Request.builder() + .walletName(walletName) + .passphrase(AbstractRegtestSetup.WALLET_PASSPHRASE) + .build(); + + var rpcCall = new BitcoindCreateWalletRpcCall(request); + rpcClient.invokeAndValidate(rpcCall); + + File expectedWalletFile = newWalletDir.resolve("b") + .resolve("wallet.dat") + .toFile(); + assertThat(expectedWalletFile).exists(); + + daemon.unloadWallet(walletName); + } +} diff --git a/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindCreateWalletNameIntegrationTests.java b/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindCreateWalletNameIntegrationTests.java new file mode 100644 index 0000000000..fbf4a2580f --- /dev/null +++ b/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindCreateWalletNameIntegrationTests.java @@ -0,0 +1,64 @@ +/* + * 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 . + */ + +package bisq.wallets.bitcoind; + +import bisq.wallets.bitcoind.regtest.BitcoindExtension; +import bisq.wallets.bitcoind.rpc.BitcoindDaemon; +import bisq.wallets.regtest.AbstractRegtestSetup; +import bisq.wallets.regtest.bitcoind.BitcoindRegtestSetup; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(BitcoindExtension.class) +public class BitcoindCreateWalletNameIntegrationTests { + private final BitcoindDaemon daemon; + + public BitcoindCreateWalletNameIntegrationTests(BitcoindRegtestSetup regtestSetup) { + this.daemon = regtestSetup.getDaemon(); + } + + @Test + void createWallet() { + String walletName = "My_awesome_wallet_creation"; + daemon.createOrLoadWallet(walletName, Optional.of(AbstractRegtestSetup.WALLET_PASSPHRASE)); + + List loadedWallets = daemon.listWallets(); + assertThat(loadedWallets).contains(walletName); + + daemon.unloadWallet(walletName); + } + + @Test + void loadWallet() { + String walletName = "My_awesome_wallet_loading"; + daemon.createOrLoadWallet(walletName, Optional.of(AbstractRegtestSetup.WALLET_PASSPHRASE)); + daemon.unloadWallet(walletName); + + daemon.createOrLoadWallet(walletName, Optional.of(AbstractRegtestSetup.WALLET_PASSPHRASE)); + + List loadedWallets = daemon.listWallets(); + assertThat(loadedWallets).contains(walletName); + + daemon.unloadWallet(walletName); + } +} diff --git a/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindPsbtMultiSigIntegrationTests.java b/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindPsbtMultiSigIntegrationTests.java index 862af2ed4c..0df4ee7aec 100644 --- a/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindPsbtMultiSigIntegrationTests.java +++ b/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindPsbtMultiSigIntegrationTests.java @@ -17,7 +17,6 @@ package bisq.wallets.bitcoind; -import bisq.common.util.FileUtils; import bisq.wallets.bitcoind.regtest.BitcoindExtension; import bisq.wallets.bitcoind.rpc.BitcoindDaemon; import bisq.wallets.bitcoind.rpc.BitcoindWallet; @@ -30,9 +29,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import java.io.IOException; import java.net.MalformedURLException; -import java.nio.file.Path; import java.util.Collections; import java.util.List; import java.util.Map; @@ -47,9 +44,8 @@ public class BitcoindPsbtMultiSigIntegrationTests { private final RpcConfig rpcConfig; private final BitcoindDaemon daemon; private final BitcoindWallet minerWallet; - private final Path watchOnlyWalletDataDir = FileUtils.createTempDir(); - public BitcoindPsbtMultiSigIntegrationTests(BitcoindRegtestSetup regtestSetup) throws IOException { + public BitcoindPsbtMultiSigIntegrationTests(BitcoindRegtestSetup regtestSetup) { this.regtestSetup = regtestSetup; this.rpcConfig = regtestSetup.getRpcConfig(); this.daemon = regtestSetup.getDaemon(); @@ -68,9 +64,9 @@ public void psbtMultiSigTest() throws MalformedURLException, InterruptedExceptio String bobXPub = getWalletXPub(bobWallet); String charlieXPub = getWalletXPub(charlieWallet); - BitcoindWallet aliceWatchOnlyWallet = createWatchOnlyDescriptorWallet(watchOnlyWalletDataDir, "alice"); - BitcoindWallet bobWatchOnlyWallet = createWatchOnlyDescriptorWallet(watchOnlyWalletDataDir, "bob"); - BitcoindWallet charlieWatchOnlyWallet = createWatchOnlyDescriptorWallet(watchOnlyWalletDataDir, "charlie"); + BitcoindWallet aliceWatchOnlyWallet = createWatchOnlyDescriptorWallet("alice"); + BitcoindWallet bobWatchOnlyWallet = createWatchOnlyDescriptorWallet("bob"); + BitcoindWallet charlieWatchOnlyWallet = createWatchOnlyDescriptorWallet("charlie"); String receiveDescriptor = "wsh(sortedmulti(2," + aliceXPub + "/0/*," + @@ -161,10 +157,10 @@ private String getWalletXPub(BitcoindWallet wallet) { return xPub.split("]")[1].split("/")[0]; } - private BitcoindWallet createWatchOnlyDescriptorWallet(Path tmpDir, String walletName) throws MalformedURLException { - Path walletPath = tmpDir.resolve(walletName + "_watch_only_descriptor_wallet"); - daemon.createOrLoadWatchOnlyWallet(walletPath); - return new BitcoindWallet(daemon, rpcConfig, walletPath); + private BitcoindWallet createWatchOnlyDescriptorWallet(String walletPrefix) throws MalformedURLException { + String walletName = walletPrefix + "_watch_only_descriptor_wallet"; + daemon.createOrLoadWatchOnlyWallet(walletName); + return new BitcoindWallet(daemon, rpcConfig, walletName); } private String appendChecksumToDescriptor(String descriptor) { diff --git a/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindWalletCreationAndListIntegrationTests.java b/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindWalletCreationAndListIntegrationTests.java index a3377927c5..693a2603c5 100644 --- a/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindWalletCreationAndListIntegrationTests.java +++ b/wallets/bitcoind/src/test/java/bisq/wallets/bitcoind/BitcoindWalletCreationAndListIntegrationTests.java @@ -17,7 +17,6 @@ package bisq.wallets.bitcoind; -import bisq.common.util.FileUtils; import bisq.wallets.bitcoind.regtest.BitcoindExtension; import bisq.wallets.bitcoind.rpc.BitcoindDaemon; import bisq.wallets.bitcoind.rpc.BitcoindWallet; @@ -25,7 +24,6 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import java.io.IOException; import java.nio.file.Path; import java.util.List; import java.util.Optional; @@ -36,10 +34,12 @@ @ExtendWith(BitcoindExtension.class) public class BitcoindWalletCreationAndListIntegrationTests { + private final Path dataDir; private final BitcoindDaemon daemon; private final BitcoindWallet minerWallet; public BitcoindWalletCreationAndListIntegrationTests(BitcoindRegtestSetup regtestSetup) { + this.dataDir = regtestSetup.getDataDir(); this.daemon = regtestSetup.getDaemon(); this.minerWallet = regtestSetup.getMinerWallet(); } @@ -50,24 +50,28 @@ public void createFreshWallet() { } @Test - public void loadWalletIfExisting() throws IOException { - Path tmpDir = FileUtils.createTempDir(); - Path walletFilePath = tmpDir.resolve("wallet"); + public void loadWalletIfExisting() { + String walletName = "wallet"; + + Path walletFilePath = dataDir.resolve("regtest") + .resolve("wallets") + .resolve(walletName) + .resolve("wallet.dat"); assertThat(walletFilePath).doesNotExist(); // Create Wallet - daemon.createOrLoadWallet(walletFilePath, Optional.of(BitcoindRegtestSetup.WALLET_PASSPHRASE)); + daemon.createOrLoadWallet(walletName, Optional.of(BitcoindRegtestSetup.WALLET_PASSPHRASE)); assertThat(walletFilePath).exists(); // Unload and reload existing wallet - daemon.unloadWallet(walletFilePath); - daemon.createOrLoadWallet(walletFilePath, Optional.of(BitcoindRegtestSetup.WALLET_PASSPHRASE)); + daemon.unloadWallet(walletName); + daemon.createOrLoadWallet(walletName, Optional.of(BitcoindRegtestSetup.WALLET_PASSPHRASE)); assertThat(minerWallet.getBalance()) .isZero(); // Cleanup, otherwise other tests don't start on a clean state. - daemon.unloadWallet(walletFilePath); + daemon.unloadWallet(walletName); } @Test diff --git a/wallets/core/src/main/java/bisq/wallets/core/rpc/RpcClientFactory.java b/wallets/core/src/main/java/bisq/wallets/core/rpc/RpcClientFactory.java index efc7a635cd..ca751c2232 100644 --- a/wallets/core/src/main/java/bisq/wallets/core/rpc/RpcClientFactory.java +++ b/wallets/core/src/main/java/bisq/wallets/core/rpc/RpcClientFactory.java @@ -24,7 +24,6 @@ import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; import java.util.HashMap; import java.util.Map; import java.util.Optional; @@ -41,9 +40,9 @@ public static DaemonRpcClient createDaemonRpcClient(RpcConfig rpcConfig) { } } - public static WalletRpcClient createWalletRpcClient(RpcConfig rpcConfig, Path walletPath) { + public static WalletRpcClient createWalletRpcClient(RpcConfig rpcConfig, String walletName) { try { - var urlSuffix = "/wallet/" + walletPath.toAbsolutePath(); + var urlSuffix = "/wallet/" + walletName; return new WalletRpcClient( createJsonRpcClientWithUrlSuffix(rpcConfig, Optional.of(urlSuffix)) ); diff --git a/wallets/core/src/main/java/bisq/wallets/core/rpc/WalletRpcClient.java b/wallets/core/src/main/java/bisq/wallets/core/rpc/WalletRpcClient.java index 0d92e02b40..6c47b3ae7b 100644 --- a/wallets/core/src/main/java/bisq/wallets/core/rpc/WalletRpcClient.java +++ b/wallets/core/src/main/java/bisq/wallets/core/rpc/WalletRpcClient.java @@ -22,7 +22,7 @@ import bisq.wallets.core.rpc.call.WalletRpcCall; import com.googlecode.jsonrpc4j.JsonRpcHttpClient; -import java.nio.file.Path; +import java.util.Arrays; public class WalletRpcClient extends AbstractRpcClient { @@ -50,12 +50,11 @@ private void validateRpcCall(RpcCall rpcCall, R response) { } } - public Path getWalletPath() { - // URL looks like: http://127.0.0.1:45775/wallet//tmp/2035361932108224852/miner_wallet - String filePart = walletJsonRpcClient.getServiceUrl().getFile(); - int startIndex = "/wallet/".length(); - String walletPath = filePart.substring(startIndex); - return Path.of(walletPath); + public String getWalletName() { + // URL looks like: http://127.0.0.1:45775/wallet/miner_wallet + // fileUrl: "wallet/miner_wallet" + String fileUrl = walletJsonRpcClient.getServiceUrl().getFile(); + String[] urlParts = fileUrl.split("/"); + return urlParts[urlParts.length - 1]; } - } diff --git a/wallets/electrum/src/test/java/bisq/wallets/electrum/regtest/electrum/WindowsElectrumRegtestSetup.java b/wallets/electrum/src/test/java/bisq/wallets/electrum/regtest/electrum/WindowsElectrumRegtestSetup.java index 46b0ae8b40..d1fdf5be36 100644 --- a/wallets/electrum/src/test/java/bisq/wallets/electrum/regtest/electrum/WindowsElectrumRegtestSetup.java +++ b/wallets/electrum/src/test/java/bisq/wallets/electrum/regtest/electrum/WindowsElectrumRegtestSetup.java @@ -47,7 +47,7 @@ public WindowsElectrumRegtestSetup() throws IOException { public WindowsElectrumRegtestSetup(boolean doCreateWallet) throws IOException { RpcConfig bitcoindRpcConfig = createBitcoindRpcConfigFromEnvironmentVars(); Path tmpDirPath = FileUtils.createTempDir(); - this.remoteBitcoind = new RemoteBitcoind(tmpDirPath, bitcoindRpcConfig, true); + this.remoteBitcoind = new RemoteBitcoind(bitcoindRpcConfig, true); RpcConfig electrumXRpcConfig = createElectrumXRpcConfigFromEnvironmentVars(); this.electrumRegtest = new ElectrumRegtest( diff --git a/wallets/elementsd/src/main/java/bisq/wallets/elementsd/LiquidWallet.java b/wallets/elementsd/src/main/java/bisq/wallets/elementsd/LiquidWallet.java index bd4c34b5cc..af91564c3c 100644 --- a/wallets/elementsd/src/main/java/bisq/wallets/elementsd/LiquidWallet.java +++ b/wallets/elementsd/src/main/java/bisq/wallets/elementsd/LiquidWallet.java @@ -33,7 +33,7 @@ import java.util.Optional; public class LiquidWallet implements Wallet, ZmqWallet { - private final Path walletPath; + private final String walletName; private final ElementsdDaemon daemon; private final ElementsdWallet wallet; @@ -44,12 +44,12 @@ public class LiquidWallet implements Wallet, ZmqWallet { @Getter private final ZmqConnection zmqConnection; - public LiquidWallet(Path walletPath, + public LiquidWallet(String walletName, ElementsdDaemon daemon, ElementsdWallet wallet, LiquidWalletStore liquidWalletStore, ZmqConnection zmqConnection) { - this.walletPath = walletPath; + this.walletName = walletName; this.daemon = daemon; this.wallet = wallet; this.liquidWalletStore = liquidWalletStore; @@ -58,12 +58,12 @@ public LiquidWallet(Path walletPath, @Override public void initialize(Optional walletPassphrase) { - daemon.createOrLoadWallet(walletPath, walletPassphrase); + daemon.createOrLoadWallet(walletName, walletPassphrase); } @Override public void shutdown() { - daemon.unloadWallet(walletPath); + daemon.unloadWallet(walletName); } @Override diff --git a/wallets/elementsd/src/main/java/bisq/wallets/elementsd/LiquidWalletService.java b/wallets/elementsd/src/main/java/bisq/wallets/elementsd/LiquidWalletService.java index eb42fb793f..266dd2387c 100644 --- a/wallets/elementsd/src/main/java/bisq/wallets/elementsd/LiquidWalletService.java +++ b/wallets/elementsd/src/main/java/bisq/wallets/elementsd/LiquidWalletService.java @@ -24,8 +24,6 @@ import lombok.Getter; import lombok.extern.slf4j.Slf4j; -import java.io.File; -import java.nio.file.Path; import java.util.Optional; @Slf4j @@ -37,15 +35,14 @@ public class LiquidWalletService extends AbstractBitcoindWalletService persistence; public LiquidWalletService(PersistenceService persistenceService, - String baseDir, boolean isRegtest) { - super("L-BTC", getOptionalRegtestConfig(isRegtest, 7040), Path.of(baseDir + File.separator + "wallets")); + super("L-BTC", getOptionalRegtestConfig(isRegtest, 7040), "bisq_elements_default_wallet"); persistence = persistenceService.getOrCreatePersistence(this, persistableStore); } @Override protected LiquidWallet createWallet(RpcConfig rpcConfig) { - return WalletFactory.createLiquidWallet(rpcConfig, walletsDataDir, persistableStore); + return WalletFactory.createLiquidWallet(rpcConfig, walletName, persistableStore); } @Override diff --git a/wallets/elementsd/src/main/java/bisq/wallets/elementsd/WalletFactory.java b/wallets/elementsd/src/main/java/bisq/wallets/elementsd/WalletFactory.java index 8307934e4c..a3a6c17a89 100644 --- a/wallets/elementsd/src/main/java/bisq/wallets/elementsd/WalletFactory.java +++ b/wallets/elementsd/src/main/java/bisq/wallets/elementsd/WalletFactory.java @@ -26,21 +26,17 @@ import bisq.wallets.elementsd.rpc.ElementsdDaemon; import bisq.wallets.elementsd.rpc.ElementsdWallet; -import java.nio.file.Path; import java.util.List; public class WalletFactory { public static LiquidWallet createLiquidWallet(RpcConfig rpcConfig, - Path walletsDataDir, + String walletName, LiquidWalletStore liquidWalletStore) { - Path walletDir = walletsDataDir.resolve("elementsd"); // directory name for bitcoind wallet - ElementsdDaemon elementsdDaemon = createElementsdDaemon(rpcConfig); - ElementsdWallet elementsdWallet = createElementsdWallet(rpcConfig, walletDir); + ElementsdWallet elementsdWallet = createElementsdWallet(rpcConfig, walletName); ZmqConnection zmqConnection = initializeElementsdZeroMq(elementsdDaemon, elementsdWallet); - - return new LiquidWallet(walletDir, elementsdDaemon, elementsdWallet, liquidWalletStore, zmqConnection); + return new LiquidWallet(walletName, elementsdDaemon, elementsdWallet, liquidWalletStore, zmqConnection); } private static ElementsdDaemon createElementsdDaemon(RpcConfig rpcConfig) { @@ -48,8 +44,8 @@ private static ElementsdDaemon createElementsdDaemon(RpcConfig rpcConfig) { return new ElementsdDaemon(rpcClient); } - private static ElementsdWallet createElementsdWallet(RpcConfig rpcConfig, Path walletPath) { - WalletRpcClient rpcClient = RpcClientFactory.createWalletRpcClient(rpcConfig, walletPath); + private static ElementsdWallet createElementsdWallet(RpcConfig rpcConfig, String walletName) { + WalletRpcClient rpcClient = RpcClientFactory.createWalletRpcClient(rpcConfig, walletName); return new ElementsdWallet(rpcClient); } diff --git a/wallets/elementsd/src/main/java/bisq/wallets/elementsd/rpc/ElementsdDaemon.java b/wallets/elementsd/src/main/java/bisq/wallets/elementsd/rpc/ElementsdDaemon.java index d76c03e73f..b1fda3cf15 100644 --- a/wallets/elementsd/src/main/java/bisq/wallets/elementsd/rpc/ElementsdDaemon.java +++ b/wallets/elementsd/src/main/java/bisq/wallets/elementsd/rpc/ElementsdDaemon.java @@ -38,8 +38,8 @@ public ElementsdDaemon(DaemonRpcClient rpcClient) { bitcoindDaemon = new BitcoindDaemon(rpcClient); } - public void createOrLoadWallet(Path walletPath, Optional passphrase) { - bitcoindDaemon.createOrLoadWallet(walletPath, passphrase); + public void createOrLoadWallet(String walletName, Optional passphrase) { + bitcoindDaemon.createOrLoadWallet(walletName, passphrase); } public ElementsdDecodeRawTransactionResponse decodeRawTransaction(String txInHex) { @@ -77,7 +77,7 @@ public void stop() { rpcClient.invokeAndValidate(rpcCall); } - public void unloadWallet(Path walletPath) { - bitcoindDaemon.unloadWallet(walletPath); + public void unloadWallet(String walletName) { + bitcoindDaemon.unloadWallet(walletName); } } diff --git a/wallets/elementsd/src/test/java/bisq/wallets/elementsd/ElementsdWalletCreationAndListIntegrationTests.java b/wallets/elementsd/src/test/java/bisq/wallets/elementsd/ElementsdWalletCreationAndListIntegrationTests.java index adf66fd2c7..07660b5a08 100644 --- a/wallets/elementsd/src/test/java/bisq/wallets/elementsd/ElementsdWalletCreationAndListIntegrationTests.java +++ b/wallets/elementsd/src/test/java/bisq/wallets/elementsd/ElementsdWalletCreationAndListIntegrationTests.java @@ -17,13 +17,9 @@ package bisq.wallets.elementsd; -import bisq.common.util.FileUtils; import bisq.wallets.regtest.bitcoind.BitcoindRegtestSetup; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import java.io.IOException; -import java.nio.file.Path; import java.util.List; import java.util.Optional; @@ -31,13 +27,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class ElementsdWalletCreationAndListIntegrationTests extends SharedElementsdInstanceTests { - private Path walletFilePath; - - @BeforeEach - void setUp() throws IOException { - Path tmpDir = FileUtils.createTempDir(); - walletFilePath = tmpDir.resolve("wallet"); - } @Test public void createFreshWallet() { @@ -47,21 +36,20 @@ public void createFreshWallet() { @Test public void loadWalletIfExisting() { - assertThat(walletFilePath).doesNotExist(); + String walletName = "My_new_shiny_wallet"; // Create Wallet - elementsdDaemon.createOrLoadWallet(walletFilePath, Optional.of(BitcoindRegtestSetup.WALLET_PASSPHRASE)); - assertThat(walletFilePath).exists(); + elementsdDaemon.createOrLoadWallet(walletName, Optional.of(BitcoindRegtestSetup.WALLET_PASSPHRASE)); // Unload and reload existing wallet - elementsdDaemon.unloadWallet(walletFilePath); - elementsdDaemon.createOrLoadWallet(walletFilePath, Optional.of(BitcoindRegtestSetup.WALLET_PASSPHRASE)); + elementsdDaemon.unloadWallet(walletName); + elementsdDaemon.createOrLoadWallet(walletName, Optional.of(BitcoindRegtestSetup.WALLET_PASSPHRASE)); assertThat(elementsdMinerWallet.getLBtcBalance()) .isZero(); // Cleanup, otherwise other tests don't start on a clean state. - elementsdDaemon.unloadWallet(walletFilePath); + elementsdDaemon.unloadWallet(walletName); } @Test diff --git a/wallets/elementsd/src/test/java/bisq/wallets/elementsd/regtest/ElementsdRegtestSetup.java b/wallets/elementsd/src/test/java/bisq/wallets/elementsd/regtest/ElementsdRegtestSetup.java index b753011cd1..bd48ef706d 100644 --- a/wallets/elementsd/src/test/java/bisq/wallets/elementsd/regtest/ElementsdRegtestSetup.java +++ b/wallets/elementsd/src/test/java/bisq/wallets/elementsd/regtest/ElementsdRegtestSetup.java @@ -54,7 +54,7 @@ public class ElementsdRegtestSetup extends AbstractRegtestSetup loadedWalletPaths; + private final Set loadedWalletPaths; @Getter private ZmqListeners zmqMinerListeners; @@ -125,20 +125,15 @@ public String sendBtcAndMineOneBlock(ElementsdWallet senderWallet, } public ElementsdWallet createNewWallet(String walletName) { - Path receiverWalletPath = tmpDirPath.resolve(walletName); - return createNewWallet(receiverWalletPath); - } - - public ElementsdWallet createNewWallet(Path walletPath) { - if (loadedWalletPaths.contains(walletPath)) { - throw new IllegalStateException("Cannot create wallet '" + walletPath.toAbsolutePath() + + if (loadedWalletPaths.contains(walletName)) { + throw new IllegalStateException("Cannot create wallet '" + walletName + "'. It exists already."); } - daemon.createOrLoadWallet(walletPath, Optional.of(WALLET_PASSPHRASE)); - loadedWalletPaths.add(walletPath); + daemon.createOrLoadWallet(walletName, Optional.of(WALLET_PASSPHRASE)); + loadedWalletPaths.add(walletName); - return newWallet(walletPath); + return newWallet(walletName); } public Optional filterUtxosByTxId( @@ -172,9 +167,9 @@ private ElementsdDaemon createDaemon() { return new ElementsdDaemon(rpcClient); } - private ElementsdWallet newWallet(Path walletPath) { + private ElementsdWallet newWallet(String walletName) { RpcConfig walletRpcConfig = elementsdConfig.elementsdRpcConfig(); - WalletRpcClient rpcClient = RpcClientFactory.createWalletRpcClient(walletRpcConfig, walletPath); + WalletRpcClient rpcClient = RpcClientFactory.createWalletRpcClient(walletRpcConfig, walletName); return new ElementsdWallet(rpcClient); } diff --git a/wallets/regtest/src/main/java/bisq/wallets/regtest/bitcoind/BitcoindRegtestSetup.java b/wallets/regtest/src/main/java/bisq/wallets/regtest/bitcoind/BitcoindRegtestSetup.java index 1348406a15..1ae3494128 100644 --- a/wallets/regtest/src/main/java/bisq/wallets/regtest/bitcoind/BitcoindRegtestSetup.java +++ b/wallets/regtest/src/main/java/bisq/wallets/regtest/bitcoind/BitcoindRegtestSetup.java @@ -52,7 +52,7 @@ public BitcoindRegtestSetup(boolean doMineInitialRegtestBlocks) throws IOExcepti super(); rpcConfig = createRpcConfig(); bitcoindProcess = createBitcoindProcess(); - remoteBitcoind = new RemoteBitcoind(tmpDirPath, rpcConfig, doMineInitialRegtestBlocks); + remoteBitcoind = new RemoteBitcoind(rpcConfig, doMineInitialRegtestBlocks); } @Override @@ -123,6 +123,10 @@ private BitcoindRegtestProcess createBitcoindProcess() { ); } + public Path getDataDir() { + return bitcoindProcess.getDataDir(); + } + public BitcoindDaemon getDaemon() { return remoteBitcoind.getDaemon(); } diff --git a/wallets/regtest/src/main/java/bisq/wallets/regtest/bitcoind/RemoteBitcoind.java b/wallets/regtest/src/main/java/bisq/wallets/regtest/bitcoind/RemoteBitcoind.java index d319d4487b..19e4620713 100644 --- a/wallets/regtest/src/main/java/bisq/wallets/regtest/bitcoind/RemoteBitcoind.java +++ b/wallets/regtest/src/main/java/bisq/wallets/regtest/bitcoind/RemoteBitcoind.java @@ -31,9 +31,7 @@ import bisq.wallets.process.BisqProcess; import lombok.Getter; -import java.io.File; import java.net.MalformedURLException; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -43,7 +41,6 @@ public class RemoteBitcoind implements BisqProcess { - private final Path tmpDirPath; private final RpcConfig rpcConfig; @Getter private final BitcoindDaemon daemon; @@ -56,14 +53,12 @@ public class RemoteBitcoind implements BisqProcess { private final List loadedWallets = new ArrayList<>(); private ZmqConnection bitcoindZeroMq; - public RemoteBitcoind(Path tmpDirPath, - RpcConfig rpcConfig, + public RemoteBitcoind(RpcConfig rpcConfig, boolean doMineInitialRegtestBlocks) throws MalformedURLException { - this.tmpDirPath = tmpDirPath; this.rpcConfig = rpcConfig; this.daemon = createBitcoindDaemon(); this.doMineInitialRegtestBlocks = doMineInitialRegtestBlocks; - this.minerWallet = createNewWallet("miner_wallet"); + this.minerWallet = new BitcoindWallet(daemon, rpcConfig, "miner_wallet"); this.blockMiner = new BitcoindRegtestBlockMiner(daemon, minerWallet, zmqListeners); } @@ -86,7 +81,7 @@ public void shutdown() { } public BitcoindWallet createAndInitializeNewWallet(String walletName) throws MalformedURLException { - var bitcoindWallet = createNewWallet(walletName); + var bitcoindWallet = new BitcoindWallet(daemon, rpcConfig, walletName); bitcoindWallet.initialize(Optional.of(WALLET_PASSPHRASE)); return bitcoindWallet; } @@ -127,20 +122,6 @@ private BitcoindDaemon createBitcoindDaemon() { return new BitcoindDaemon(rpcClient); } - private BitcoindWallet createNewWallet(String walletName) throws MalformedURLException { - Path walletPath = tmpDirPath.resolve(walletName); - checkWhetherWalletExist(walletPath); - return new BitcoindWallet(daemon, rpcConfig, walletPath); - } - - private void checkWhetherWalletExist(Path walletPath) { - File walletFile = walletPath.toFile(); - if (walletFile.exists()) { - throw new IllegalStateException("Cannot create wallet '" + walletPath.toAbsolutePath() + - "'. It exists already."); - } - } - private void initializeZmqListeners() { var bitcoindRawTxProcessor = new BitcoindRawTxProcessor(daemon, zmqListeners); var bitcoindZmqTopicProcessors = new ZmqTopicProcessors(bitcoindRawTxProcessor, zmqListeners);