diff --git a/core/src/main/java/bisq/core/api/CoreWalletsService.java b/core/src/main/java/bisq/core/api/CoreWalletsService.java index 78d71ccb08..4ab6ff282a 100644 --- a/core/src/main/java/bisq/core/api/CoreWalletsService.java +++ b/core/src/main/java/bisq/core/api/CoreWalletsService.java @@ -581,7 +581,8 @@ class CoreWalletsService { if (btcWalletService.getAesKey() == null || bsqWalletService.getAesKey() == null) { KeyParameter aesKey = new KeyParameter(tempAesKey.getKey()); walletsManager.setAesKey(aesKey); - walletsSetup.getWalletConfig().maybeAddSegwitKeychain(walletsSetup.getWalletConfig().btcWallet(), aesKey); + walletsSetup.getWalletConfig().maybeAddSegwitKeychain(walletsSetup.getWalletConfig().btcWallet(), aesKey, false); + walletsSetup.getWalletConfig().maybeAddSegwitKeychain(walletsSetup.getWalletConfig().bsqWallet(), aesKey, true); } } diff --git a/core/src/main/java/bisq/core/app/BisqSetup.java b/core/src/main/java/bisq/core/app/BisqSetup.java index de6db2c2ba..d83f2af614 100644 --- a/core/src/main/java/bisq/core/app/BisqSetup.java +++ b/core/src/main/java/bisq/core/app/BisqSetup.java @@ -424,7 +424,9 @@ public class BisqSetup { requestWalletPasswordHandler.accept(aesKey -> { walletsManager.setAesKey(aesKey); walletsSetup.getWalletConfig().maybeAddSegwitKeychain(walletsSetup.getWalletConfig().btcWallet(), - aesKey); + aesKey, false); + walletsSetup.getWalletConfig().maybeAddSegwitKeychain(walletsSetup.getWalletConfig().bsqWallet(), + aesKey, true); if (getResyncSpvSemaphore()) { if (showFirstPopupIfResyncSPVRequestedHandler != null) showFirstPopupIfResyncSPVRequestedHandler.run(); diff --git a/core/src/main/java/bisq/core/btc/setup/BisqKeyChainGroupStructure.java b/core/src/main/java/bisq/core/btc/setup/BisqKeyChainGroupStructure.java index 66ec8b7cea..a1a23b49e0 100644 --- a/core/src/main/java/bisq/core/btc/setup/BisqKeyChainGroupStructure.java +++ b/core/src/main/java/bisq/core/btc/setup/BisqKeyChainGroupStructure.java @@ -47,15 +47,14 @@ public class BisqKeyChainGroupStructure implements KeyChainGroupStructure { new ChildNumber(142, true), ChildNumber.ZERO_HARDENED); - // We don't use segwit for BSQ - // public static final ImmutableList BIP44_BSQ_SEGWIT_ACCOUNT_PATH = ImmutableList.of( - // new ChildNumber(44, true), - // new ChildNumber(142, true), - // ChildNumber.ONE_HARDENED); + public static final ImmutableList BIP44_BSQ_SEGWIT_ACCOUNT_PATH = ImmutableList.of( + new ChildNumber(44, true), + new ChildNumber(142, true), + ChildNumber.ONE_HARDENED); - private boolean isBsqWallet; + private final boolean isBsqWallet; - public BisqKeyChainGroupStructure (boolean isBsqWallet) { + public BisqKeyChainGroupStructure(boolean isBsqWallet) { this.isBsqWallet = isBsqWallet; } @@ -72,8 +71,7 @@ public class BisqKeyChainGroupStructure implements KeyChainGroupStructure { if (outputScriptType == null || outputScriptType == Script.ScriptType.P2PKH) return BIP44_BSQ_NON_SEGWIT_ACCOUNT_PATH; else if (outputScriptType == Script.ScriptType.P2WPKH) - //return BIP44_BSQ_SEGWIT_ACCOUNT_PATH; - throw new IllegalArgumentException(outputScriptType.toString()); + return BIP44_BSQ_SEGWIT_ACCOUNT_PATH; else throw new IllegalArgumentException(outputScriptType.toString()); } 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 bd260c13d8..afa52f8482 100644 --- a/core/src/main/java/bisq/core/btc/setup/WalletConfig.java +++ b/core/src/main/java/bisq/core/btc/setup/WalletConfig.java @@ -57,6 +57,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import javafx.beans.binding.BooleanExpression; import javafx.beans.property.BooleanProperty; import javafx.beans.property.SimpleBooleanProperty; @@ -143,7 +144,11 @@ public class WalletConfig extends AbstractIdleService { @Setter private int minBroadcastConnections; @Getter - private BooleanProperty migratedWalletToSegwit = new SimpleBooleanProperty(false); + private BooleanProperty migratedWalletToBtcSegwit = new SimpleBooleanProperty(false); + @Getter + private BooleanProperty migratedWalletToBsqSegwit = new SimpleBooleanProperty(false); + @Getter + private BooleanExpression migratedWalletToSegwit = migratedWalletToBtcSegwit.and(migratedWalletToBsqSegwit); /** * Creates a new WalletConfig, with a newly created {@link Context}. Files will be stored in the given directory. @@ -406,15 +411,13 @@ public class WalletConfig extends AbstractIdleService { wallet = serializer.readWallet(params, extArray, proto); if (shouldReplayWallet) wallet.reset(); - if (!isBsqWallet) { - maybeAddSegwitKeychain(wallet, null); - } + maybeAddSegwitKeychain(wallet, null, isBsqWallet); } return wallet; } protected Wallet createWallet(boolean isBsqWallet) { - Script.ScriptType preferredOutputScriptType = isBsqWallet ? Script.ScriptType.P2PKH : Script.ScriptType.P2WPKH; + Script.ScriptType preferredOutputScriptType = Script.ScriptType.P2WPKH; KeyChainGroupStructure structure = new BisqKeyChainGroupStructure(isBsqWallet); KeyChainGroup.Builder kcgBuilder = KeyChainGroup.builder(params, structure); if (restoreFromSeed != null) { @@ -545,21 +548,29 @@ public class WalletConfig extends AbstractIdleService { return directory; } - public void maybeAddSegwitKeychain(Wallet wallet, KeyParameter aesKey) { - if (BisqKeyChainGroupStructure.BIP44_BTC_NON_SEGWIT_ACCOUNT_PATH.equals(wallet.getActiveKeyChain().getAccountPath())) { + public void maybeAddSegwitKeychain(Wallet wallet, KeyParameter aesKey, boolean isBsqWallet) { + var nonSegwitAccountPath = isBsqWallet + ? BisqKeyChainGroupStructure.BIP44_BSQ_NON_SEGWIT_ACCOUNT_PATH + : BisqKeyChainGroupStructure.BIP44_BTC_NON_SEGWIT_ACCOUNT_PATH; + var preSegwitBackupFilename = isBsqWallet + ? WalletsSetup.PRE_SEGWIT_BSQ_WALLET_BACKUP + : WalletsSetup.PRE_SEGWIT_BTC_WALLET_BACKUP; + var walletFilename = isBsqWallet ? "bisq_BSQ.wallet" : "bisq_BTC.wallet"; + + if (nonSegwitAccountPath.equals(wallet.getActiveKeyChain().getAccountPath())) { if (wallet.isEncrypted() && aesKey == null) { // wait for the aesKey to be set and this method to be invoked again. return; } // Do a backup of the wallet - File backup = new File(directory, WalletsSetup.PRE_SEGWIT_WALLET_BACKUP); + File backup = new File(directory, preSegwitBackupFilename); try { - FileUtil.copyFile(new File(directory, "bisq_BTC.wallet"), backup); + FileUtil.copyFile(new File(directory, walletFilename), backup); } catch (IOException e) { log.error(e.toString(), e); } - // Btc wallet does not have a native segwit keychain, we should add one. + // Wallet does not have a native segwit keychain, we should add one. DeterministicSeed seed = wallet.getKeyChainSeed(); if (aesKey != null) { // If wallet is encrypted, decrypt the seed. @@ -568,7 +579,7 @@ public class WalletConfig extends AbstractIdleService { } DeterministicKeyChain nativeSegwitKeyChain = DeterministicKeyChain.builder().seed(seed) .outputScriptType(Script.ScriptType.P2WPKH) - .accountPath(new BisqKeyChainGroupStructure(false).accountPathFor(Script.ScriptType.P2WPKH)).build(); + .accountPath(new BisqKeyChainGroupStructure(isBsqWallet).accountPathFor(Script.ScriptType.P2WPKH)).build(); if (aesKey != null) { // If wallet is encrypted, encrypt the new keychain. KeyCrypter keyCrypter = wallet.getKeyCrypter(); @@ -576,7 +587,11 @@ public class WalletConfig extends AbstractIdleService { } wallet.addAndActivateHDChain(nativeSegwitKeyChain); } - migratedWalletToSegwit.set(true); + if (isBsqWallet) { + migratedWalletToBsqSegwit.set(true); + } else { + migratedWalletToBtcSegwit.set(true); + } } public boolean stateStartingOrRunning() { 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 fad4ac3051..e6cba879a6 100644 --- a/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java +++ b/core/src/main/java/bisq/core/btc/setup/WalletsSetup.java @@ -109,7 +109,8 @@ import static com.google.common.base.Preconditions.checkNotNull; @Slf4j public class WalletsSetup { - public static final String PRE_SEGWIT_WALLET_BACKUP = "pre_segwit_bisq_BTC.wallet.backup"; + public static final String PRE_SEGWIT_BTC_WALLET_BACKUP = "pre_segwit_bisq_BTC.wallet.backup"; + public static final String PRE_SEGWIT_BSQ_WALLET_BACKUP = "pre_segwit_bisq_BSQ.wallet.backup"; @Getter public final BooleanProperty walletsSetupFailed = new SimpleBooleanProperty(); @@ -427,12 +428,14 @@ public class WalletsSetup { e.printStackTrace(); } - File segwitBackup = new File(walletDir, PRE_SEGWIT_WALLET_BACKUP); - try { - FileUtil.deleteFileIfExists(segwitBackup); - } catch (IOException e) { - log.error(e.toString(), e); - } + List.of(PRE_SEGWIT_BTC_WALLET_BACKUP, PRE_SEGWIT_BSQ_WALLET_BACKUP).forEach(filename -> { + File segwitBackup = new File(walletDir, filename); + try { + FileUtil.deleteFileIfExists(segwitBackup); + } catch (IOException e) { + log.error(e.toString(), e); + } + }); } diff --git a/core/src/main/java/bisq/core/btc/wallet/BsqWalletService.java b/core/src/main/java/bisq/core/btc/wallet/BsqWalletService.java index 945ecd08ed..c2f5d039da 100644 --- a/core/src/main/java/bisq/core/btc/wallet/BsqWalletService.java +++ b/core/src/main/java/bisq/core/btc/wallet/BsqWalletService.java @@ -42,7 +42,6 @@ import org.bitcoinj.core.AddressFormatException; import org.bitcoinj.core.BlockChain; import org.bitcoinj.core.Coin; import org.bitcoinj.core.InsufficientMoneyException; -import org.bitcoinj.core.LegacyAddress; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Transaction; @@ -50,6 +49,7 @@ import org.bitcoinj.core.TransactionConfidence; import org.bitcoinj.core.TransactionInput; import org.bitcoinj.core.TransactionOutPoint; import org.bitcoinj.core.TransactionOutput; +import org.bitcoinj.script.Script; import org.bitcoinj.script.ScriptException; import org.bitcoinj.wallet.CoinSelection; import org.bitcoinj.wallet.CoinSelector; @@ -807,12 +807,13 @@ public class BsqWalletService extends WalletService implements DaoStateListener // Addresses /////////////////////////////////////////////////////////////////////////////////////////// - private LegacyAddress getChangeAddress() { + private Address getChangeAddress() { return getUnusedAddress(); } - public LegacyAddress getUnusedAddress() { - return (LegacyAddress) wallet.getIssuedReceiveAddresses().stream() + public Address getUnusedAddress() { + return wallet.getIssuedReceiveAddresses().stream() + .filter(address -> Script.ScriptType.P2WPKH.equals(address.getOutputScriptType())) .filter(this::isAddressUnused) .findAny() .orElse(wallet.freshReceiveAddress());