From 78383f98f49b0e9f8ee9d072a4712b9b307ad586 Mon Sep 17 00:00:00 2001
From: Mike Hearn
Override this to return wallet extensions if any are necessary.
* @@ -217,24 +237,36 @@ public class WalletAppKit extends AbstractIdleService { throw new IOException("Could not create named directory."); } } + log.info("Starting up with directory = {}", directory); try { File chainFile = new File(directory, filePrefix + ".spvchain"); boolean chainFileExists = chainFile.exists(); vWalletFile = new File(directory, filePrefix + ".wallet"); - boolean shouldReplayWallet = vWalletFile.exists() && !chainFileExists; - + boolean shouldReplayWallet = (vWalletFile.exists() && !chainFileExists) || restoreFromSeed != null; vStore = new SPVBlockStore(params, chainFile); - if (!chainFileExists && checkpoints != null) { - // Ugly hack! We have to create the wallet once here to learn the earliest key time, and then throw it - // away. The reason is that wallet extensions might need access to peergroups/chains/etc so we have to - // create the wallet later, but we need to know the time early here before we create the BlockChain - // object. + if ((!chainFileExists || restoreFromSeed != null) && checkpoints != null) { + // Initialize the chain file with a checkpoint to speed up first-run sync. long time = Long.MAX_VALUE; - if (vWalletFile.exists()) { - FileInputStream stream = new FileInputStream(vWalletFile); - final WalletProtobufSerializer serializer = new WalletProtobufSerializer(); - final Wallet wallet = serializer.readWallet(params, null, WalletProtobufSerializer.parseToProto(stream)); - time = wallet.getEarliestKeyCreationTime(); + if (restoreFromSeed != null) { + time = restoreFromSeed.getCreationTimeSeconds(); + if (chainFileExists) { + log.info("Deleting the chain file in preparation from restore."); + vStore.close(); + if (!chainFile.delete()) + throw new Exception("Failed to delete chain file in preparation for restore."); + vStore = new SPVBlockStore(params, chainFile); + } + } else { + // Ugly hack! We have to create the wallet once here to learn the earliest key time, and then throw it + // away. The reason is that wallet extensions might need access to peergroups/chains/etc so we have to + // create the wallet later, but we need to know the time early here before we create the BlockChain + // object. + if (vWalletFile.exists()) { + FileInputStream stream = new FileInputStream(vWalletFile); + final WalletProtobufSerializer serializer = new WalletProtobufSerializer(); + final Wallet wallet = serializer.readWallet(params, null, WalletProtobufSerializer.parseToProto(stream)); + time = wallet.getEarliestKeyCreationTime(); + } } CheckpointManager.checkpoint(params, checkpoints, vStore, time); } @@ -242,6 +274,9 @@ public class WalletAppKit extends AbstractIdleService { vPeerGroup = createPeerGroup(); if (this.userAgent != null) vPeerGroup.setUserAgent(userAgent, version); + + maybeMoveOldWalletOutOfTheWay(); + if (vWalletFile.exists()) { FileInputStream walletStream = new FileInputStream(vWalletFile); try { @@ -261,7 +296,7 @@ public class WalletAppKit extends AbstractIdleService { walletStream.close(); } } else { - vWallet = walletFactory != null ? walletFactory.create(params, new KeyChainGroup(params)) : new Wallet(params); + vWallet = createWallet(); vWallet.freshReceiveKey(); for (WalletExtension e : provideWalletExtensions()) { vWallet.addExtension(e); @@ -312,6 +347,35 @@ public class WalletAppKit extends AbstractIdleService { } } + protected Wallet createWallet() { + KeyChainGroup kcg; + if (restoreFromSeed != null) + kcg = new KeyChainGroup(params, restoreFromSeed); + else + kcg = new KeyChainGroup(params); + if (walletFactory != null) { + return walletFactory.create(params, kcg); + } else { + return new Wallet(params, kcg); // default + } + } + + private void maybeMoveOldWalletOutOfTheWay() { + if (restoreFromSeed == null) return; + if (!vWalletFile.exists()) return; + int counter = 1; + File newName; + do { + newName = new File(vWalletFile.getParent(), "Backup " + counter + " for " + vWalletFile.getName()); + counter++; + } while (newName.exists()); + log.info("Renaming old wallet file {} to {}", vWalletFile, newName); + if (!vWalletFile.renameTo(newName)) { + // This should not happen unless something is really messed up. + throw new RuntimeException("Failed to rename wallet for restore"); + } + } + protected PeerGroup createPeerGroup() throws TimeoutException { if (useTor) { return PeerGroup.newWithTor(params, vChain, new TorClient());