diff --git a/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoinRPCException.java b/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoinRPCException.java new file mode 100644 index 00000000..58348991 --- /dev/null +++ b/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoinRPCException.java @@ -0,0 +1,7 @@ +package com.sparrowwallet.sparrow.net.cormorant.bitcoind; + +public class BitcoinRPCException extends RuntimeException { + public BitcoinRPCException(String message) { + super(message); + } +} diff --git a/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindClient.java b/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindClient.java index caede21d..fd5882bb 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindClient.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindClient.java @@ -49,6 +49,12 @@ public class BitcoindClient { private static final long PRUNED_RESCAN_TIMEGAP_MILLIS = 7200*1000; + //Error codes from https://github.com/bitcoin/bitcoin/blob/master/src/rpc/protocol.h + public static final int RPC_METHOD_NOT_FOUND = -32601; + public static final int RPC_WALLET_NOT_FOUND = -18; + + public static final String WALLET_ALREADY_LOADING_MESSAGE = "Wallet already loading."; + private final JsonRpcClient jsonRpcClient; private final Timer timer = new Timer(true); private final Store store = new Store(); @@ -140,21 +146,27 @@ public class BitcoindClient { tip = blockHeader.getBlockHeader(); } - ListWalletDirResult listWalletDirResult = getBitcoindService().listWalletDir(); - if(listWalletDirResult == null) { - throw new RuntimeException("Wallet support must be enabled in Bitcoin Core"); + List loadedWallets; + try { + loadedWallets = getBitcoindService().listWallets(); + legacyWalletExists = loadedWallets.contains(Bwt.DEFAULT_CORE_WALLET); + } catch(JsonRpcException e) { + if(e.getErrorMessage().getCode() == RPC_METHOD_NOT_FOUND) { + throw new BitcoinRPCException("Wallet support must be enabled in Bitcoin Core"); + } else { + throw e; + } } - boolean exists = listWalletDirResult.wallets().stream().anyMatch(walletDirResult -> walletDirResult.name().equals(CORE_WALLET_NAME)); - legacyWalletExists = listWalletDirResult.wallets().stream().anyMatch(walletDirResult -> walletDirResult.name().equals(Bwt.DEFAULT_CORE_WALLET)); - List loadedWallets = getBitcoindService().listWallets(); - boolean loaded = loadedWallets.contains(CORE_WALLET_NAME); - - if(!exists && !loaded) { - getBitcoindService().createWallet(CORE_WALLET_NAME, true, true, "", true, true, true, false); - } else { - if(!loaded) { + if(!loadedWallets.contains(CORE_WALLET_NAME)) { + try { getBitcoindService().loadWallet(CORE_WALLET_NAME, true); + } catch(JsonRpcException e) { + if(e.getErrorMessage().getCode() == RPC_WALLET_NOT_FOUND) { + getBitcoindService().createWallet(CORE_WALLET_NAME, true, true, "", true, true, true, false); + } else if(!WALLET_ALREADY_LOADING_MESSAGE.equals(e.getErrorMessage().getMessage())) { + throw e; + } } } @@ -186,12 +198,24 @@ public class BitcoindClient { .sorted(Comparator.comparingLong(o -> o.getBirthDate().getTime())).collect(Collectors.toList()); if(!prePruneWallets.isEmpty()) { pruneWarnedDescriptors.add(e.getDescriptor()); - Platform.runLater(() -> EventManager.get().post(new CormorantPruneStatusEvent("Error: Wallet birthday earlier than Bitcoin Core prune date", prePruneWallets.get(0), e.getRescanSince(), e.getPrunedDate(), legacyWalletExists))); + if(!legacyWalletExists) { + legacyWalletExists = checkLegacyWalletExists(); + } + Platform.runLater(() -> EventManager.get().post(new CormorantPruneStatusEvent("Error: Wallet birthday earlier than Bitcoin Core prune date", prePruneWallets.getFirst(), e.getRescanSince(), e.getPrunedDate(), legacyWalletExists))); } throw new ImportFailedException("Wallet birthday earlier than prune date"); } } + private boolean checkLegacyWalletExists() { + try { + getBitcoindService().loadWallet(Bwt.DEFAULT_CORE_WALLET); + return true; + } catch(Exception e) { + return false; + } + } + public void importWallet(Wallet wallet) throws ImportFailedException { //To avoid unnecessary rescans, get all related wallets importWallets(wallet.isMasterWallet() ? wallet.getAllWallets() : wallet.getMasterWallet().getAllWallets()); diff --git a/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindClientService.java b/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindClientService.java index a4739103..008d3c14 100644 --- a/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindClientService.java +++ b/src/main/java/com/sparrowwallet/sparrow/net/cormorant/bitcoind/BitcoindClientService.java @@ -73,6 +73,9 @@ public interface BitcoindClientService { @JsonRpcParam("passphrase") String passphrase, @JsonRpcParam("avoid_reuse") boolean avoidReuse, @JsonRpcParam("descriptors") boolean descriptors, @JsonRpcParam("load_on_startup") boolean loadOnStartup, @JsonRpcParam("external_signer") boolean externalSigner); + @JsonRpcMethod("loadwallet") + CreateLoadWalletResult loadWallet(@JsonRpcParam("filename") String name); + @JsonRpcMethod("loadwallet") CreateLoadWalletResult loadWallet(@JsonRpcParam("filename") String name, @JsonRpcParam("load_on_startup") boolean loadOnStartup);