cormorant: avoid calling listwalletdir rpc on initialization due to extremely slow response on windows

This commit is contained in:
Craig Raw 2025-04-18 09:43:57 +02:00
parent 71ac72e9f6
commit 94d15c09e6
3 changed files with 47 additions and 13 deletions

View file

@ -0,0 +1,7 @@
package com.sparrowwallet.sparrow.net.cormorant.bitcoind;
public class BitcoinRPCException extends RuntimeException {
public BitcoinRPCException(String message) {
super(message);
}
}

View file

@ -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");
}
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<String> loadedWallets = getBitcoindService().listWallets();
boolean loaded = loadedWallets.contains(CORE_WALLET_NAME);
if(!exists && !loaded) {
getBitcoindService().createWallet(CORE_WALLET_NAME, true, true, "", true, true, true, false);
List<String> 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 {
if(!loaded) {
throw e;
}
}
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());

View file

@ -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);