diff --git a/README.md b/README.md index 7882fefa8..c0a8b8ae1 100644 --- a/README.md +++ b/README.md @@ -75,7 +75,7 @@ After some processing, you will have the following artifacts in the target direc * an installer for Linux = multidoge-x.y.z-linux.jar To run MultiDoge from these artifacts you can follow the instructions [provided on the main MultiDoge -website](https://multidoge.org/help.html) +website](http://multidoge.org/help.html) ### MultiDoge contains cut down JREs so is a large clone diff --git a/authors.txt b/authors.txt index 0059665c1..6cb58b063 100644 --- a/authors.txt +++ b/authors.txt @@ -11,4 +11,4 @@ Internationalisation: --------------------- http://translate.multibit.org -Thanks to all the MultiBit localisers. \ No newline at end of file +Thanks to all the MultiBit localisers. diff --git a/pom.xml b/pom.xml index 3bc5dded1..2eeb9da02 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ - https://github.com/langerhans/multidoge + https://github.com/jim618/multibit @@ -61,7 +61,7 @@ https://oss.sonatype.org/content/groups/public - + bitcoinj-release @@ -76,7 +76,7 @@ - multidoge + multibit @@ -190,7 +190,7 @@ 256m false false - src/main/proguard/multidoge-exe.pro + src/main/proguard/multibit-exe.pro @@ -226,20 +226,20 @@ install.xml readme.txt Unix_shortcutSpec.xml - multidoge-protocol-handler.sh + multibit-protocol-handler.sh ${basedir}/src/main/resources/images installerLeft.png - multidoge48.png + multibit48.png src/main/resources - multidoge.checkpoints + multibit.checkpoints @@ -254,7 +254,7 @@ target - multidoge-exe.jar + multibit-exe.jar @@ -286,13 +286,13 @@ ${basedir}/src/main/resources/images installerLeft.png - multidoge.ico + multibit.ico src/main/resources - multidoge.checkpoints + multibit.checkpoints @@ -307,7 +307,7 @@ target - multidoge.exe + multibit.exe @@ -326,12 +326,12 @@ copy-resources - ${basedir}/target/MultiDoge.app + ${basedir}/target/MultiBit.app - src/app-resources/MultiDoge.app + src/app-resources/MultiBit.app @@ -343,14 +343,14 @@ copy-resources - ${basedir}/target/MultiDoge.app/Contents/Resources/Java + ${basedir}/target/MultiBit.app/Contents/Resources/Java ${basedir}/target/staging.linux - multidoge-exe.jar - multidoge.checkpoints + multibit-exe.jar + multibit.checkpoints release_notes.txt configuration.md COPYING @@ -421,39 +421,39 @@ - + + todir="${basedir}/target/MultiBit-mac" /> + line="-s /Applications ${basedir}/target/MultiBit-mac/Applications" /> + line="--sign 'Developer ID Application: James Burton' --force ${basedir}/target/MultiBit-mac/MultiBit.app" /> + line="--display --verbose=4 ${basedir}/target/MultiBit-mac/MultiBit.app" /> @@ -463,19 +463,19 @@ - - + + - + - + @@ -483,7 +483,7 @@ run - jsmooth-installer2exe-exe @@ -520,7 +520,7 @@ classpathref="jsmooth-classpathref" /> - + @@ -676,7 +676,7 @@ com.google - dogecoinj + bitcoinj ${bitcoinj.version} compile @@ -811,7 +811,7 @@ - 0.10.3-MB-ALICE + 0.10.2-MB-ALICE 1.10.0 diff --git a/src/main/java/org/multibit/network/MultiBitService.java b/src/main/java/org/multibit/network/MultiBitService.java index d8e4679b9..77f6a8632 100644 --- a/src/main/java/org/multibit/network/MultiBitService.java +++ b/src/main/java/org/multibit/network/MultiBitService.java @@ -15,17 +15,17 @@ */ package org.multibit.network; -import com.google.dogecoin.core.MultiBitBlockChain; -import com.google.dogecoin.core.*; -import com.google.dogecoin.core.Wallet.SendRequest; -import com.google.dogecoin.crypto.KeyCrypterException; -import com.google.dogecoin.discovery.DnsDiscovery; -import com.google.dogecoin.store.BlockStore; -import com.google.dogecoin.store.BlockStoreException; -import com.google.dogecoin.store.SPVBlockStore; -import com.google.common.util.concurrent.ListenableFuture; +import com.google.bitcoin.core.*; +import com.google.bitcoin.core.Wallet.SendRequest; +import com.google.bitcoin.crypto.KeyCrypterException; +import com.google.bitcoin.discovery.DnsDiscovery; +import com.google.bitcoin.discovery.IrcDiscovery; +import com.google.bitcoin.store.BlockStore; +import com.google.bitcoin.store.BlockStoreException; +import com.google.bitcoin.store.SPVBlockStore; import org.bitcoinj.wallet.Protos.Wallet.EncryptionType; import org.multibit.ApplicationDataDirectoryLocator; +import org.multibit.MultiBit; import org.multibit.controller.Controller; import org.multibit.controller.bitcoin.BitcoinController; import org.multibit.file.BackupManager; @@ -43,6 +43,7 @@ import org.slf4j.LoggerFactory; import org.spongycastle.crypto.params.KeyParameter; +import javax.swing.*; import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -53,664 +54,648 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; /** *

- * MultiBitService encapsulates the interaction with the dogecoin netork + * MultiBitService encapsulates the interaction with the bitcoin netork * including: o Peers o Block chain download o sending / receiving bitcoins - *

+ * * The testnet can be slow or flaky as it's a shared resource. You can use the * testnet in a box + * .net/projects/bitcoin/files/Bitcoin/testnet-in-a-box/">testnet in a box * to do everything purely locally. *

*/ public class MultiBitService { - private static final String TESTNET3_GENESIS_HASH = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"; + private static final String TESTNET3_GENESIS_HASH = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"; - private static final Logger log = LoggerFactory.getLogger(MultiBitService.class); + private static final Logger log = LoggerFactory.getLogger(MultiBitService.class); - public static final String MULTIBIT_PREFIX = "multidoge"; - public static final String TESTNET_PREFIX = "testnet"; - public static final String TESTNET3_PREFIX = "testnet3"; - public static final String SEPARATOR = "-"; + public static final int MAXIMUM_EXPECTED_LENGTH_OF_ALTERNATE_CHAIN = 6; - public static final String BLOCKCHAIN_SUFFIX = ".blockchain"; - public static final String SPV_BLOCKCHAIN_SUFFIX = ".spvchain"; - public static final String CHECKPOINTS_SUFFIX = ".checkpoints"; - public static final String WALLET_SUFFIX = ".wallet"; + public static final String MULTIBIT_PREFIX = "multibit"; + public static final String TESTNET_PREFIX = "testnet"; + public static final String TESTNET3_PREFIX = "testnet3"; + public static final String SEPARATOR = "-"; - public static final String IRC_CHANNEL_TEST = "#bitcoinTEST"; - public static final String IRC_CHANNEL_TESTNET3 = "#bitcoinTEST3"; + public static final String BLOCKCHAIN_SUFFIX = ".blockchain"; + public static final String SPV_BLOCKCHAIN_SUFFIX = ".spvchain"; + public static final String CHECKPOINTS_SUFFIX = ".checkpoints"; + public static final String WALLET_SUFFIX = ".wallet"; - public Logger logger = LoggerFactory.getLogger(MultiBitService.class.getName()); + public static final String IRC_CHANNEL_TEST = "#bitcoinTEST"; + public static final String IRC_CHANNEL_TESTNET3 = "#bitcoinTEST3"; - private MultiBitPeerGroup peerGroup; + static boolean restartListenerHasBeenAddedToPeerGroup = false; - private String blockchainFilename; + public Logger logger = LoggerFactory.getLogger(MultiBitService.class.getName()); - private MultiBitBlockChain blockChain; + private MultiBitPeerGroup peerGroup; - private BlockStore blockStore; + private String blockchainFilename; - private final Controller controller; - private final BitcoinController bitcoinController; + private MultiBitBlockChain blockChain; - private final NetworkParameters networkParameters; + private BlockStore blockStore; - private SecureRandom secureRandom = new SecureRandom(); + private final Controller controller; + private final BitcoinController bitcoinController; - private MultiBitCheckpointManager checkpointManager; - private String checkpointsFilename; + private final NetworkParameters networkParameters; - public static Date genesisBlockCreationDate; + private SecureRandom secureRandom = new SecureRandom(); + private MultiBitCheckpointManager checkpointManager; + private String checkpointsFilename; - static { - try { - java.text.SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - java.util.Calendar cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); - format.setCalendar(cal); - genesisBlockCreationDate = format.parse("2013-12-06 10:25:40"); - } catch (ParseException e) { - // Will never happen. - e.printStackTrace(); + public static Date genesisBlockCreationDate; + + + static { + try { + java.text.SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + java.util.Calendar cal = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); + format.setCalendar(cal); + genesisBlockCreationDate = format.parse("2009-01-03 18:15:05"); + } catch (ParseException e) { + // Will never happen. + e.printStackTrace(); + } } - } - /** - * @param bitcoinController BitcoinController - */ - public MultiBitService(BitcoinController bitcoinController) { - this.bitcoinController = bitcoinController; - this.controller = this.bitcoinController; + /** + * + * @param bitcoinController BitcoinController + */ + public MultiBitService(BitcoinController bitcoinController) { + this.bitcoinController = bitcoinController; + this.controller = this.bitcoinController; - if (controller == null) { - throw new IllegalStateException("controller cannot be null"); - } + if (controller == null) { + throw new IllegalStateException("controller cannot be null"); + } - if (controller.getModel() == null) { - throw new IllegalStateException("controller.getModel() cannot be null"); - } + if (controller.getModel() == null) { + throw new IllegalStateException("controller.getModel() cannot be null"); + } - if (controller.getApplicationDataDirectoryLocator() == null) { - throw new IllegalStateException("controller.getApplicationDataDirectoryLocator() cannot be null"); - } + if (controller.getApplicationDataDirectoryLocator() == null) { + throw new IllegalStateException("controller.getApplicationDataDirectoryLocator() cannot be null"); + } - if (this.bitcoinController.getFileHandler() == null) { - throw new IllegalStateException("controller.getFileHandler() cannot be null"); - } + if (this.bitcoinController.getFileHandler() == null) { + throw new IllegalStateException("controller.getFileHandler() cannot be null"); + } - networkParameters = this.bitcoinController.getModel().getNetworkParameters(); - log.debug("Network parameters = " + networkParameters); - - try { - // Load or create the blockStore.. - log.debug("Loading/ creating blockstore ..."); - blockStore = createBlockStore(null, false); - log.debug("Blockstore is '" + blockStore + "'"); - - log.debug("Creating blockchain ..."); - blockChain = new MultiBitBlockChain(networkParameters, blockStore); - log.debug("Created blockchain '" + blockChain + "' with height " + blockChain.getBestChainHeight()); - - log.debug("Creating peergroup ..."); - createNewPeerGroup(); - log.debug("Created peergroup '" + peerGroup + "'"); - - log.debug("Starting peergroup ..."); - peerGroup.start(); - log.debug("Started peergroup."); - } catch (BlockStoreException e) { - handleError(e); - } catch (FileHandlerException e) { - handleError(e); - } catch (Exception e) { - handleError(e); - } + networkParameters = this.bitcoinController.getModel().getNetworkParameters(); + log.debug("Network parameters = " + networkParameters); - FileInputStream stream = null; - try { - stream = new FileInputStream(checkpointsFilename); - checkpointManager = new MultiBitCheckpointManager(networkParameters, stream); - } catch (IOException e) { - log.error("Error creating checkpointManager " + e.getClass().getName() + " " + e.getMessage()); - } finally { - if (stream != null) { try { - stream.close(); + // Load or create the blockStore.. + log.debug("Loading/ creating blockstore ..."); + blockStore = createBlockStore(null, false); + log.debug("Blockstore is '" + blockStore + "'"); + + log.debug("Creating blockchain ..."); + blockChain = new MultiBitBlockChain(networkParameters, blockStore); + log.debug("Created blockchain '" + blockChain + "' with height " + blockChain.getBestChainHeight()); + + log.debug("Creating peergroup ..."); + createNewPeerGroup(); + log.debug("Created peergroup '" + peerGroup + "'"); + + log.debug("Starting peergroup ..."); + peerGroup.start(); + log.debug("Started peergroup."); + } catch (BlockStoreException e) { + handleError(e); + } catch (FileHandlerException e) { + handleError(e); + } catch (Exception e) { + handleError(e); + } + + FileInputStream stream = null; + try { + stream = new FileInputStream(checkpointsFilename); + checkpointManager = new MultiBitCheckpointManager(networkParameters, stream); } catch (IOException e) { - log.error("Error tidying up checkpointManager creation" + e.getClass().getName() + " " + e.getMessage()); + log.error("Error creating checkpointManager " + e.getClass().getName() + " " + e.getMessage()); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + log.error("Error tidying up checkpointManager creation" + e.getClass().getName() + " " + e.getMessage()); + } + } } - } - } - } - - private void handleError(Exception e) { - controller.setOnlineStatus(StatusEnum.ERROR); - MessageManager.INSTANCE.addMessage(new Message(controller.getLocaliser().getString( - "multiBitService.couldNotLoadBlockchain", - new Object[]{blockchainFilename, e.getClass().getName() + " " + e.getMessage()}))); - log.error("Error creating MultiBitService " + e.getClass().getName() + " " + e.getMessage()); - } - - private BlockStore createBlockStore(Date checkpointDate, boolean createNew) throws BlockStoreException, IOException { - BlockStore blockStore = null; - - String filePrefix = getFilePrefix(); - log.debug("filePrefix = " + filePrefix); - - if ("".equals(controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory())) { - blockchainFilename = filePrefix + SPV_BLOCKCHAIN_SUFFIX; - checkpointsFilename = filePrefix + CHECKPOINTS_SUFFIX; - } else { - blockchainFilename = controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory() + File.separator - + filePrefix + SPV_BLOCKCHAIN_SUFFIX; - checkpointsFilename = controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory() + File.separator - + filePrefix + CHECKPOINTS_SUFFIX; } - File blockStoreFile = new File(blockchainFilename); - boolean blockStoreCreatedNew = !blockStoreFile.exists(); - - // Ensure there is a checkpoints file. - File checkpointsFile = new File(checkpointsFilename); - if (!checkpointsFile.exists()) { - bitcoinController.getFileHandler().copyCheckpointsFromInstallationDirectory(checkpointsFilename); + private void handleError(Exception e) { + controller.setOnlineStatus(StatusEnum.ERROR); + MessageManager.INSTANCE.addMessage(new Message(controller.getLocaliser().getString( + "multiBitService.couldNotLoadBlockchain", + new Object[] { blockchainFilename, e.getClass().getName() + " " + e.getMessage() }))); + log.error("Error creating MultiBitService " + e.getClass().getName() + " " + e.getMessage()); } - // Use the larger of the installed checkpoints file and the user data checkpoint file (larger = more recent). - ApplicationDataDirectoryLocator applicationDataDirectoryLocator = new ApplicationDataDirectoryLocator(); - String installedCheckpointsFilename = applicationDataDirectoryLocator.getInstallationDirectory() + File.separator + MultiBitService.getFilePrefix() + MultiBitService.CHECKPOINTS_SUFFIX; - log.debug("Installed checkpoints file = '" + installedCheckpointsFilename + "'."); + private BlockStore createBlockStore(Date checkpointDate, boolean createNew) throws BlockStoreException, IOException { + BlockStore blockStore = null; - File installedCheckpointsFile = new File(installedCheckpointsFilename); - long sizeOfUserDataCheckpointsFile = 0; - if (checkpointsFile.exists()) { - sizeOfUserDataCheckpointsFile = checkpointsFile.length(); - } - if (installedCheckpointsFile.exists() && installedCheckpointsFile.length() > sizeOfUserDataCheckpointsFile) { - // The installed checkpoints file is longer (more checkpoints) so use that. - checkpointsFilename = installedCheckpointsFilename; - checkpointsFile = installedCheckpointsFile; - log.debug("Using installed checkpoints file as it is longer than user data checkpoints - " + installedCheckpointsFile.length() + " bytes versus " + sizeOfUserDataCheckpointsFile + " bytes."); - } else { - log.debug("Using user data checkpoints file as it is longer/same size as installed checkpoints - " + sizeOfUserDataCheckpointsFile + " bytes versus " + installedCheckpointsFile.length() + " bytes."); - } + String filePrefix = getFilePrefix(); + log.debug("filePrefix = " + filePrefix); - // If the spvBlockStore is to be created new - // or its size is 0 bytes delete the file so that it is recreated fresh (fix for issue 165). - if (createNew || blockStoreFile.length() == 0) { - // Garbage collect any closed references to the blockchainFile. - System.gc(); - blockStoreFile.setWritable(true); - boolean deletedOk = blockStoreFile.delete(); - log.debug("Deleting SPV block store '{}' from disk.1", blockchainFilename + ", deletedOk = " + deletedOk); - blockStoreCreatedNew = true; - } + if ("".equals(controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory())) { + blockchainFilename = filePrefix + SPV_BLOCKCHAIN_SUFFIX; + checkpointsFilename = filePrefix + CHECKPOINTS_SUFFIX; + } else { + blockchainFilename = controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory() + File.separator + + filePrefix + SPV_BLOCKCHAIN_SUFFIX; + checkpointsFilename = controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory() + File.separator + + filePrefix + CHECKPOINTS_SUFFIX; + } - log.debug("Opening / Creating SPV block store '{}' from disk", blockchainFilename); - try { - blockStore = new SPVBlockStore(networkParameters, blockStoreFile); - } catch (BlockStoreException bse) { - try { - log.error("Failed to open/ create SPV block store '{}' from disk", blockchainFilename); - // If the block store creation failed, delete the block store file and try again. - - // Garbage collect any closed references to the blockchainFile. - System.gc(); - blockStoreFile.setWritable(true); - boolean deletedOk = blockStoreFile.delete(); - log.debug("Deleting SPV block store '{}' from disk.2", blockchainFilename + ", deletedOk = " + deletedOk); - blockStoreCreatedNew = true; - - blockStore = new SPVBlockStore(networkParameters, blockStoreFile); - } catch (BlockStoreException bse2) { - bse2.printStackTrace(); - log.error("Unrecoverable failure in opening block store. This is bad."); - // Throw the exception so that it is indicated on the UI. - throw bse2; - } - } + File blockStoreFile = new File(blockchainFilename); + boolean blockStoreCreatedNew = !blockStoreFile.exists(); - // Load the existing checkpoint file and checkpoint from today. - if (blockStore != null && checkpointsFile.exists()) { - FileInputStream stream = null; - try { - stream = new FileInputStream(checkpointsFile); - if (checkpointDate == null) { - if (blockStoreCreatedNew) { - // Brand new block store - checkpoint from today. This - // will go back to the last checkpoint. - CheckpointManager.checkpoint(networkParameters, stream, blockStore, (new Date()).getTime() / 1000); - } + // Ensure there is a checkpoints file. + File checkpointsFile = new File(checkpointsFilename); + if (!checkpointsFile.exists()) { + bitcoinController.getFileHandler().copyCheckpointsFromInstallationDirectory(checkpointsFilename); + } + + // Use the larger of the installed checkpoints file and the user data checkpoint file (larger = more recent). + ApplicationDataDirectoryLocator applicationDataDirectoryLocator = new ApplicationDataDirectoryLocator(); + String installedCheckpointsFilename = applicationDataDirectoryLocator.getInstallationDirectory() + File.separator + MultiBitService.getFilePrefix() + MultiBitService.CHECKPOINTS_SUFFIX; + log.debug("Installed checkpoints file = '" + installedCheckpointsFilename + "'."); + + File installedCheckpointsFile = new File(installedCheckpointsFilename); + long sizeOfUserDataCheckpointsFile = 0; + if (checkpointsFile.exists()) { + sizeOfUserDataCheckpointsFile = checkpointsFile.length(); + } + if (installedCheckpointsFile.exists() && installedCheckpointsFile.length() > sizeOfUserDataCheckpointsFile) { + // The installed checkpoints file is longer (more checkpoints) so use that. + checkpointsFilename = installedCheckpointsFilename; + checkpointsFile = installedCheckpointsFile; + log.debug("Using installed checkpoints file as it is longer than user data checkpoints - " + installedCheckpointsFile.length() + " bytes versus " + sizeOfUserDataCheckpointsFile + " bytes."); } else { - // Use checkpoint date (block replay). - CheckpointManager.checkpoint(networkParameters, stream, blockStore, checkpointDate.getTime() / 1000); + log.debug("Using user data checkpoints file as it is longer/same size as installed checkpoints - " + sizeOfUserDataCheckpointsFile + " bytes versus " + installedCheckpointsFile.length() + " bytes."); } - } finally { - if (stream != null) { - stream.close(); - stream = null; + + // If the spvBlockStore is to be created new + // or its size is 0 bytes delete the file so that it is recreated fresh (fix for issue 165). + if (createNew || blockStoreFile.length() == 0) { + // Garbage collect any closed references to the blockchainFile. + System.gc(); + blockStoreFile.setWritable(true); + boolean deletedOk = blockStoreFile.delete(); + log.debug("Deleting SPV block store '{}' from disk.1", blockchainFilename + ", deletedOk = " + deletedOk); + blockStoreCreatedNew = true; } - } - } - return blockStore; - } - - public void createNewPeerGroup() { - peerGroup = new MultiBitPeerGroup(bitcoinController, networkParameters, blockChain); - peerGroup.setFastCatchupTimeSecs(0); // genesis block - peerGroup.setUserAgent("MultiBit", controller.getLocaliser().getVersionNumber()); - - boolean peersSpecified = false; - String singleNodeConnection = controller.getModel().getUserPreference(BitcoinModel.SINGLE_NODE_CONNECTION); - String peers = controller.getModel().getUserPreference(BitcoinModel.PEERS); - if (singleNodeConnection != null && !singleNodeConnection.equals("")) { - try { - peerGroup.addAddress(new PeerAddress(InetAddress.getByName(singleNodeConnection.trim()))); - peerGroup.setMaxConnections(1); - peersSpecified = true; - } catch (UnknownHostException e) { - log.error(e.getMessage(), e); - } - } else if (peers != null && !peers.equals("")) { - // Split using commas. - String[] peerList = peers.split(","); - if (peerList != null) { - int numberOfPeersAdded = 0; - - for (int i = 0; i < peerList.length; i++) { - try { - peerGroup.addAddress(new PeerAddress(InetAddress.getByName(peerList[i].trim()))); - numberOfPeersAdded++; - } catch (UnknownHostException e) { - log.error(e.getMessage(), e); - } + + log.debug("Opening / Creating SPV block store '{}' from disk", blockchainFilename); + try { + blockStore = new SPVBlockStore(networkParameters, blockStoreFile); + } catch (BlockStoreException bse) { + try { + log.error("Failed to open/ create SPV block store '{}' from disk", blockchainFilename); + // If the block store creation failed, delete the block store file and try again. + + // Garbage collect any closed references to the blockchainFile. + System.gc(); + blockStoreFile.setWritable(true); + boolean deletedOk = blockStoreFile.delete(); + log.debug("Deleting SPV block store '{}' from disk.2", blockchainFilename + ", deletedOk = " + deletedOk); + blockStoreCreatedNew = true; + + blockStore = new SPVBlockStore(networkParameters, blockStoreFile); + } catch (BlockStoreException bse2) { + bse2.printStackTrace(); + log.error("Unrecoverable failure in opening block store. This is bad."); + // Throw the exception so that it is indicated on the UI. + throw bse2; + } + } + + // Load the existing checkpoint file and checkpoint from today. + if (blockStore != null && checkpointsFile.exists()) { + FileInputStream stream = null; + try { + stream = new FileInputStream(checkpointsFile); + if (checkpointDate == null) { + if (blockStoreCreatedNew) { + // Brand new block store - checkpoint from today. This + // will go back to the last checkpoint. + CheckpointManager.checkpoint(networkParameters, stream, blockStore, (new Date()).getTime() / 1000); + } + } else { + // Use checkpoint date (block replay). + CheckpointManager.checkpoint(networkParameters, stream, blockStore, checkpointDate.getTime() / 1000); + } + } finally { + if (stream != null) { + stream.close(); + stream = null; + } + } } - peerGroup.setMaxConnections(numberOfPeersAdded); - peersSpecified = true; - } + return blockStore; } - if (!peersSpecified) { -/* // Use DNS for production, IRC for test. - if (TESTNET3_GENESIS_HASH.equals(bitcoinController.getModel().getNetworkParameters().getGenesisBlock().getHashAsString())) { - peerGroup.addPeerDiscovery(new IrcDiscovery(IRC_CHANNEL_TESTNET3)); - } else if (NetworkParameters.testNet().equals(bitcoinController.getModel().getNetworkParameters())) { - peerGroup.addPeerDiscovery(new IrcDiscovery(IRC_CHANNEL_TEST)); - } else { - peerGroup.addPeerDiscovery(new DnsDiscovery(networkParameters)); - }*/ - //DOGE: Only production for now. - peerGroup.addPeerDiscovery(new DnsDiscovery(networkParameters)); - } - // Add the controller as a PeerEventListener. - peerGroup.addEventListener(bitcoinController.getPeerEventListener()); - - // Add all existing wallets to the PeerGroup. - if (controller != null && controller.getModel() != null) { - List perWalletDataModels = bitcoinController.getModel().getPerWalletModelDataList(); - if (perWalletDataModels != null) { - Iterator iterator = perWalletDataModels.iterator(); - if (iterator != null) { - while (iterator.hasNext()) { - WalletData perWalletModelData = iterator.next(); - if (perWalletModelData != null && perWalletModelData.getWallet() != null) { - peerGroup.addWallet(perWalletModelData.getWallet()); + public void createNewPeerGroup() { + peerGroup = new MultiBitPeerGroup(bitcoinController, networkParameters, blockChain); + peerGroup.setFastCatchupTimeSecs(0); // genesis block + peerGroup.setUserAgent("MultiBit", controller.getLocaliser().getVersionNumber()); + + boolean peersSpecified = false; + String singleNodeConnection = controller.getModel().getUserPreference(BitcoinModel.SINGLE_NODE_CONNECTION); + String peers = controller.getModel().getUserPreference(BitcoinModel.PEERS); + if (singleNodeConnection != null && !singleNodeConnection.equals("")) { + try { + peerGroup.addAddress(new PeerAddress(InetAddress.getByName(singleNodeConnection.trim()))); + peerGroup.setMaxConnections(1); + peersSpecified = true; + } catch (UnknownHostException e) { + log.error(e.getMessage(), e); + } + } else if (peers != null && !peers.equals("")) { + // Split using commas. + String[] peerList = peers.split(","); + if (peerList != null) { + int numberOfPeersAdded = 0; + + for (int i = 0; i < peerList.length; i++) { + try { + peerGroup.addAddress(new PeerAddress(InetAddress.getByName(peerList[i].trim()))); + numberOfPeersAdded++; + } catch (UnknownHostException e) { + log.error(e.getMessage(), e); + } + } + peerGroup.setMaxConnections(numberOfPeersAdded); + peersSpecified = true; } - } } - } - } - } - - public static String getFilePrefix() { -/* BitcoinController bitcoinController = MultiBit.getBitcoinController(); - // testnet3 - if (TESTNET3_GENESIS_HASH.equals(bitcoinController.getModel().getNetworkParameters().getGenesisBlock().getHashAsString())) { - return MULTIBIT_PREFIX + SEPARATOR + TESTNET3_PREFIX; - } else if (NetworkParameters.testNet().equals(bitcoinController.getModel().getNetworkParameters())) { - return MULTIBIT_PREFIX + SEPARATOR + TESTNET_PREFIX; - } else {*/ - return MULTIBIT_PREFIX; - //} //TODO DOGE: No testnet... - } - - /** - * Initialize wallet from the wallet filename. - * - * @param walletFilename - * @return perWalletModelData - */ - public WalletData addWalletFromFilename(String walletFilename) throws IOException { - WalletData perWalletModelDataToReturn = null; - Wallet wallet = null; - - File walletFile = null; - boolean walletFileIsADirectory = false; - boolean newWalletCreated = false; - - if (walletFilename != null) { - walletFile = new File(walletFilename); - if (walletFile.isDirectory()) { - walletFileIsADirectory = true; - } else { - - perWalletModelDataToReturn = bitcoinController.getFileHandler().loadFromFile(walletFile); - if (perWalletModelDataToReturn != null) { - wallet = perWalletModelDataToReturn.getWallet(); + + if (!peersSpecified) { + // Use DNS for production, IRC for test. + if (TESTNET3_GENESIS_HASH.equals(bitcoinController.getModel().getNetworkParameters().getGenesisBlock().getHashAsString())) { + peerGroup.addPeerDiscovery(new IrcDiscovery(IRC_CHANNEL_TESTNET3)); + } else if (NetworkParameters.testNet().equals(bitcoinController.getModel().getNetworkParameters())) { + peerGroup.addPeerDiscovery(new IrcDiscovery(IRC_CHANNEL_TEST)); + } else { + peerGroup.addPeerDiscovery(new DnsDiscovery(networkParameters)); + } } + // Add the controller as a PeerEventListener. + peerGroup.addEventListener(bitcoinController.getPeerEventListener()); - } + // Add all existing wallets to the PeerGroup. + if (controller != null && controller.getModel() != null) { + List perWalletDataModels = bitcoinController.getModel().getPerWalletModelDataList(); + if (perWalletDataModels != null) { + Iterator iterator = perWalletDataModels.iterator(); + if (iterator != null) { + while(iterator.hasNext()) { + WalletData perWalletModelData = iterator.next(); + if (perWalletModelData != null && perWalletModelData.getWallet() != null) { + peerGroup.addWallet(perWalletModelData.getWallet()); + } + } + } + } + } } - if (walletFilename == null || walletFilename.equals("") || walletFileIsADirectory) { - // Use default wallet name - create if does not exist. - if ("".equals(controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory())) { - walletFilename = getFilePrefix() + WALLET_SUFFIX; - } else { - walletFilename = controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory() + File.separator - + getFilePrefix() + WALLET_SUFFIX; - } - - walletFile = new File(walletFilename); - - if (walletFile.exists()) { - // Wallet file exists with default name. - perWalletModelDataToReturn = bitcoinController.getFileHandler().loadFromFile(walletFile); - if (perWalletModelDataToReturn != null) { - wallet = perWalletModelDataToReturn.getWallet(); - newWalletCreated = true; + public static String getFilePrefix() { + BitcoinController bitcoinController = MultiBit.getBitcoinController(); + // testnet3 + if (TESTNET3_GENESIS_HASH.equals(bitcoinController.getModel().getNetworkParameters().getGenesisBlock().getHashAsString())) { + return MULTIBIT_PREFIX + SEPARATOR + TESTNET3_PREFIX; + } else if (NetworkParameters.testNet().equals(bitcoinController.getModel().getNetworkParameters())) { + return MULTIBIT_PREFIX + SEPARATOR + TESTNET_PREFIX; + } else { + return MULTIBIT_PREFIX; } - } else { - // Create a brand new wallet - by default unencrypted. - wallet = new Wallet(networkParameters); - ECKey newKey = new ECKey(); - wallet.addKey(newKey); + } - perWalletModelDataToReturn = bitcoinController.getModel().addWallet(bitcoinController, wallet, walletFile.getAbsolutePath()); + /** + * Initialize wallet from the wallet filename. + * + * @param walletFilename + * @return perWalletModelData + */ + public WalletData addWalletFromFilename(String walletFilename) throws IOException { + WalletData perWalletModelDataToReturn = null; + Wallet wallet = null; + + File walletFile = null; + boolean walletFileIsADirectory = false; + boolean newWalletCreated = false; + + if (walletFilename != null) { + walletFile = new File(walletFilename); + if (walletFile.isDirectory()) { + walletFileIsADirectory = true; + } else { + + perWalletModelDataToReturn = bitcoinController.getFileHandler().loadFromFile(walletFile); + if (perWalletModelDataToReturn != null) { + wallet = perWalletModelDataToReturn.getWallet(); + } - // Create a wallet info. - WalletInfoData walletInfo = new WalletInfoData(walletFile.getAbsolutePath(), wallet, MultiBitWalletVersion.PROTOBUF); - perWalletModelDataToReturn.setWalletInfo(walletInfo); + } + } - // Set a default description. - String defaultDescription = controller.getLocaliser().getString("createNewWalletSubmitAction.defaultDescription"); - perWalletModelDataToReturn.setWalletDescription(defaultDescription); + if (walletFilename == null || walletFilename.equals("") || walletFileIsADirectory) { + // Use default wallet name - create if does not exist. + if ("".equals(controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory())) { + walletFilename = getFilePrefix() + WALLET_SUFFIX; + } else { + walletFilename = controller.getApplicationDataDirectoryLocator().getApplicationDataDirectory() + File.separator + + getFilePrefix() + WALLET_SUFFIX; + } - try { - bitcoinController.getFileHandler().savePerWalletModelData(perWalletModelDataToReturn, true); + walletFile = new File(walletFilename); + + if (walletFile.exists()) { + // Wallet file exists with default name. + perWalletModelDataToReturn = bitcoinController.getFileHandler().loadFromFile(walletFile); + if (perWalletModelDataToReturn != null) { + wallet = perWalletModelDataToReturn.getWallet(); + newWalletCreated = true; + } + } else { + // Create a brand new wallet - by default unencrypted. + wallet = new Wallet(networkParameters); + ECKey newKey = new ECKey(); + wallet.addKey(newKey); + + perWalletModelDataToReturn = bitcoinController.getModel().addWallet(bitcoinController, wallet, walletFile.getAbsolutePath()); + + // Create a wallet info. + WalletInfoData walletInfo = new WalletInfoData(walletFile.getAbsolutePath(), wallet, MultiBitWalletVersion.PROTOBUF); + perWalletModelDataToReturn.setWalletInfo(walletInfo); + + // Set a default description. + String defaultDescription = controller.getLocaliser().getString("createNewWalletSubmitAction.defaultDescription"); + perWalletModelDataToReturn.setWalletDescription(defaultDescription); + + try { + bitcoinController.getFileHandler().savePerWalletModelData(perWalletModelDataToReturn, true); + + newWalletCreated = true; + + // Backup the wallet and wallet info. + BackupManager.INSTANCE.backupPerWalletModelData(bitcoinController.getFileHandler(), perWalletModelDataToReturn); + + } catch (WalletSaveException wse) { + log.error(wse.getClass().getCanonicalName() + " " + wse.getMessage()); + MessageManager.INSTANCE.addMessage(new Message(wse.getClass().getCanonicalName() + " " + wse.getMessage())); + } catch (WalletVersionException wve) { + log.error(wve.getClass().getCanonicalName() + " " + wve.getMessage()); + MessageManager.INSTANCE.addMessage(new Message(wve.getClass().getCanonicalName() + " " + wve.getMessage())); + } + } + } - newWalletCreated = true; + if (wallet != null) { + // Add the keys for this wallet to the address book as receiving + // addresses. + List keys = wallet.getKeychain(); + if (keys != null) { + if (!newWalletCreated) { + perWalletModelDataToReturn = bitcoinController.getModel().getPerWalletModelDataByWalletFilename(walletFilename); + } + if (perWalletModelDataToReturn != null) { + WalletInfoData walletInfo = perWalletModelDataToReturn.getWalletInfo(); + if (walletInfo != null) { + for (ECKey key : keys) { + if (key != null) { + Address address = key.toAddress(networkParameters); + walletInfo.addReceivingAddressOfKey(address); + } + } + } + } + } - // Backup the wallet and wallet info. - BackupManager.INSTANCE.backupPerWalletModelData(bitcoinController.getFileHandler(), perWalletModelDataToReturn); + // Add wallet to blockchain. + if (blockChain != null) { + blockChain.addWallet(wallet); + } else { + log.error("Could not add wallet '" + walletFilename + "' to the blockChain as the blockChain is missing.\n" + + "This is bad. MultiBit is currently looking for a blockChain at '" + blockchainFilename + "'"); + } - } catch (WalletSaveException wse) { - log.error(wse.getClass().getCanonicalName() + " " + wse.getMessage()); - MessageManager.INSTANCE.addMessage(new Message(wse.getClass().getCanonicalName() + " " + wse.getMessage())); - } catch (WalletVersionException wve) { - log.error(wve.getClass().getCanonicalName() + " " + wve.getMessage()); - MessageManager.INSTANCE.addMessage(new Message(wve.getClass().getCanonicalName() + " " + wve.getMessage())); + // Add wallet to peergroup. + if (peerGroup != null) { + peerGroup.addWallet(wallet); + peerGroup.addEventListener(bitcoinController.getPeerEventListener()); + } else { + log.error("Could not add wallet '" + walletFilename + "' to the peerGroup as the peerGroup is null. This is bad. "); + } + } - } + + return perWalletModelDataToReturn; } - if (wallet != null) { - // Add the keys for this wallet to the address book as receiving - // addresses. - List keys = wallet.getKeychain(); - if (keys != null) { - if (!newWalletCreated) { - perWalletModelDataToReturn = bitcoinController.getModel().getPerWalletModelDataByWalletFilename(walletFilename); - } - if (perWalletModelDataToReturn != null) { - WalletInfoData walletInfo = perWalletModelDataToReturn.getWalletInfo(); - if (walletInfo != null) { - for (ECKey key : keys) { - if (key != null) { - Address address = key.toAddress(networkParameters); - walletInfo.addReceivingAddressOfKey(address); - } + /** + * Create a new block store. + * @param dateToReplayFrom + * @return height tof new block chain after truncate. + * @throws IOException + * @throws BlockStoreException + */ + public int createNewBlockStoreForReplay(Date dateToReplayFrom) throws IOException, BlockStoreException { + log.debug("Loading/ creating blockstore ..."); + if (blockStore != null) { + try { + blockStore.close(); + blockStore = null; + } catch (NullPointerException npe) { + log.debug("NullPointerException on blockstore close"); } - } } - } - - // Add wallet to blockchain. - if (blockChain != null) { - blockChain.addWallet(wallet); - } else { - log.error("Could not add wallet '" + walletFilename + "' to the blockChain as the blockChain is missing.\n" - + "This is bad. MultiBit is currently looking for a blockChain at '" + blockchainFilename + "'"); - } - - // Add wallet to peergroup. - if (peerGroup != null) { - peerGroup.addWallet(wallet); - peerGroup.addEventListener(bitcoinController.getPeerEventListener()); - } else { - log.error("Could not add wallet '" + walletFilename + "' to the peerGroup as the peerGroup is null. This is bad. "); - } - } + // The CheckpointManager removes a week to cater for block header drift. + // Any date before genesis + 1 week gets adjusted accordingly. + Date genesisPlusOnwWeekAndASecond = new Date(MultiBitService.genesisBlockCreationDate.getTime() + (86400 * 7 + 1) * 1000); - return perWalletModelDataToReturn; - } - - /** - * Create a new block store. - * - * @param dateToReplayFrom The date to start the replay task from - * @return height tof new block chain after truncate. - * @throws IOException - * @throws BlockStoreException - */ - public int createNewBlockStoreForReplay(Date dateToReplayFrom) throws IOException, BlockStoreException { - log.debug("Loading/ creating blockstore ..."); - if (blockStore != null) { - try { - blockStore.close(); - blockStore = null; - } catch (NullPointerException npe) { - log.debug("NullPointerException on blockstore close"); - } + if (dateToReplayFrom != null) { + if (dateToReplayFrom.getTime() < genesisPlusOnwWeekAndASecond.getTime() ) { + dateToReplayFrom = genesisPlusOnwWeekAndASecond; + } + blockStore = createBlockStore(dateToReplayFrom, true); + } else { + blockStore = createBlockStore(genesisPlusOnwWeekAndASecond, true); + } + log.debug("Blockstore is '" + blockStore + "'"); + + log.debug("Creating blockchain ..."); + blockChain = new MultiBitBlockChain(bitcoinController.getModel().getNetworkParameters(), blockStore); + log.debug("Created blockchain '" + blockChain + "'"); + + // Hook up the wallets to the new blockchain. + if (blockChain != null) { + List perWalletModelDataList = bitcoinController.getModel().getPerWalletModelDataList(); + for (WalletData loopPerWalletModelData : perWalletModelDataList) { + if (loopPerWalletModelData.getWallet() != null) { + blockChain.addWallet(loopPerWalletModelData.getWallet()); + } + } + } + return blockChain.getBestChainHeight(); } - // The CheckpointManager removes a week to cater for block header drift. - // Any date before genesis + 1 week gets adjusted accordingly. - Date genesisPlusOnwWeekAndASecond = new Date(MultiBitService.genesisBlockCreationDate.getTime() + (86400 * 7 + 1) * 1000); - - if (dateToReplayFrom != null) { - if (dateToReplayFrom.getTime() < genesisPlusOnwWeekAndASecond.getTime()) { - dateToReplayFrom = genesisPlusOnwWeekAndASecond; - } - blockStore = createBlockStore(dateToReplayFrom, true); - } else { - blockStore = createBlockStore(genesisPlusOnwWeekAndASecond, true); + /** + * Download the block chain. + */ + public void downloadBlockChain() { + @SuppressWarnings("rawtypes") + SwingWorker worker = new SwingWorker() { + @Override + protected Object doInBackground() throws Exception { + logger.debug("Downloading blockchain"); + peerGroup.downloadBlockChain(); + return null; // return not used + } + }; + worker.execute(); } - log.debug("Blockstore is '" + blockStore + "'"); - - log.debug("Creating blockchain ..."); - blockChain = new MultiBitBlockChain(bitcoinController.getModel().getNetworkParameters(), blockStore); - log.debug("Created blockchain '" + blockChain + "'"); - - // Hook up the wallets to the new blockchain. - if (blockChain != null) { - List perWalletModelDataList = bitcoinController.getModel().getPerWalletModelDataList(); - for (WalletData loopPerWalletModelData : perWalletModelDataList) { - if (loopPerWalletModelData.getWallet() != null) { - blockChain.addWallet(loopPerWalletModelData.getWallet()); + + /** + * Send bitcoins from the active wallet. + * + * @return The sent transaction (may be null if there were insufficient + * funds for send) + * @throws KeyCrypterException + * @throws IOException + * @throws AddressFormatException + */ + + public Transaction sendCoins(WalletData perWalletModelData, SendRequest sendRequest, + CharSequence password) throws java.io.IOException, AddressFormatException, KeyCrypterException { + // Send the coins + + log.debug("MultiBitService#sendCoins - Just about to send coins"); + KeyParameter aesKey = null; + if (perWalletModelData.getWallet().getEncryptionType() != EncryptionType.UNENCRYPTED) { + aesKey = perWalletModelData.getWallet().getKeyCrypter().deriveKey(password); } - } - } - return blockChain.getBestChainHeight(); - } - - /** - * Send bitcoins from the active wallet. - * - * @return The sent transaction (may be null if there were insufficient - * funds for send) - * @throws KeyCrypterException - * @throws IOException - * @throws AddressFormatException - */ - - public Transaction sendCoins(WalletData perWalletModelData, SendRequest sendRequest, - CharSequence password) throws java.io.IOException, AddressFormatException, KeyCrypterException { - - // Ping the peers to check the dogecoin network connection - List connectedPeers = peerGroup.getConnectedPeers(); - boolean atLeastOnePingWorked = false; - if (connectedPeers != null) { - for (Peer peer : connectedPeers) { - - log.debug("Ping: {}", peer.getAddress().toString()); + sendRequest.aesKey = aesKey; + sendRequest.fee = BigInteger.ZERO; + sendRequest.feePerKb = BitcoinModel.SEND_FEE_PER_KB_DEFAULT; + + sendRequest.tx.getConfidence().addEventListener(perWalletModelData.getWallet().getTxConfidenceListener()); + // log.debug("Added txConfidenceListener " + txConfidenceListener + " to tx " + request.tx.getHashAsString() + ", identityHashCode = " + System.identityHashCode(request.tx)); try { - ListenableFuture result = peer.ping(); - result.get(4, TimeUnit.SECONDS); - atLeastOnePingWorked = true; - break; - } catch (ProtocolException e) { - log.warn("Peer '" + peer.getAddress().toString() + "' failed ping test. Message was " + e.getMessage()); - } catch (InterruptedException e) { - log.warn("Peer '" + peer.getAddress().toString() + "' failed ping test. Message was " + e.getMessage()); - } catch (ExecutionException e) { - log.warn("Peer '" + peer.getAddress().toString() + "' failed ping test. Message was " + e.getMessage()); - } catch (TimeoutException e) { - log.warn("Peer '" + peer.getAddress().toString() + "' failed ping test. Message was " + e.getMessage()); + // The transaction is already added to the wallet (in SendBitcoinConfirmAction) so here we just need + // to sign it, commit it and broadcast it. + perWalletModelData.getWallet().sign(sendRequest); + perWalletModelData.getWallet().commitTx(sendRequest.tx); + + // The tx has been committed to the pending pool by this point (via sendCoinsOffline -> commitTx), so it has + // a txConfidenceListener registered. Once the tx is broadcast the peers will update the memory pool with the + // count of seen peers, the memory pool will update the transaction confidence object, that will invoke the + // txConfidenceListener which will in turn invoke the wallets event listener onTransactionConfidenceChanged + // method. + peerGroup.broadcastTransaction(sendRequest.tx); + + log.debug("Sending transaction '" + Utils.bytesToHexString(sendRequest.tx.bitcoinSerialize()) + "'"); + } catch (VerificationException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); } - } - } - if (!atLeastOnePingWorked) { - throw new IllegalStateException("All peers failed ping test (check network)"); - } - - // Send the coins + Transaction sendTransaction = sendRequest.tx; + + log.debug("MultiBitService#sendCoins - Sent coins has completed"); + + assert sendTransaction != null; + // We should never try to send more coins than we have! + // throw an exception if sendTransaction is null - no money. + if (sendTransaction != null) { + log.debug("MultiBitService#sendCoins - Sent coins. Transaction hash is {}", sendTransaction.getHashAsString() + ", identityHashcode = " + System.identityHashCode(sendTransaction)); + + if (sendTransaction.getConfidence() != null) { + log.debug("Added bitcoinController " + System.identityHashCode(bitcoinController) + " as listener to tx = " + sendTransaction.getHashAsString()); + sendTransaction.getConfidence().addEventListener(bitcoinController); + } else { + log.debug("Cannot add bitcoinController as listener to tx = " + sendTransaction.getHashAsString() + " no transactionConfidence"); + } - log.debug("MultiBitService#sendCoins - Just about to send coins"); - KeyParameter aesKey = null; - if (perWalletModelData.getWallet().getEncryptionType() != EncryptionType.UNENCRYPTED) { - aesKey = perWalletModelData.getWallet().getKeyCrypter().deriveKey(password); - } - sendRequest.aesKey = aesKey; - sendRequest.fee = BigInteger.ZERO; - sendRequest.feePerKb = BitcoinModel.SEND_FEE_PER_KB_DEFAULT; - - sendRequest.tx.getConfidence().addEventListener(perWalletModelData.getWallet().getTxConfidenceListener()); - - try { - // The transaction is already added to the wallet (in SendBitcoinConfirmAction) so here we just need - // to sign it, commit it and broadcast it. - perWalletModelData.getWallet().sign(sendRequest); - perWalletModelData.getWallet().commitTx(sendRequest.tx); - - // The tx has been committed to the pending pool by this point (via sendCoinsOffline -> commitTx), so it has - // a txConfidenceListener registered. Once the tx is broadcast the peers will update the memory pool with the - // count of seen peers, the memory pool will update the transaction confidence object, that will invoke the - // txConfidenceListener which will in turn invoke the wallets event listener onTransactionConfidenceChanged - // method. - peerGroup.broadcastTransaction(sendRequest.tx); - - log.debug("Sending transaction '" + Utils.bytesToHexString(sendRequest.tx.bitcoinSerialize()) + "'"); - } catch (VerificationException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } + try { + bitcoinController.getFileHandler().savePerWalletModelData(perWalletModelData, false); + } catch (WalletSaveException wse) { + log.error(wse.getClass().getCanonicalName() + " " + wse.getMessage()); + MessageManager.INSTANCE.addMessage(new Message(wse.getClass().getCanonicalName() + " " + wse.getMessage())); + } catch (WalletVersionException wse) { + log.error(wse.getClass().getCanonicalName() + " " + wse.getMessage()); + MessageManager.INSTANCE.addMessage(new Message(wse.getClass().getCanonicalName() + " " + wse.getMessage())); + } - Transaction sendTransaction = sendRequest.tx; - - log.debug("MultiBitService#sendCoins - Sent coins has completed"); - - assert sendTransaction != null; - // We should never try to send more coins than we have! - // throw an exception if sendTransaction is null - no money. - if (sendTransaction != null) { - log.debug("MultiBitService#sendCoins - Sent coins. Transaction hash is {}", sendTransaction.getHashAsString() + ", identityHashcode = " + System.identityHashCode(sendTransaction)); - - if (sendTransaction.getConfidence() != null) { - log.debug("Added bitcoinController " + System.identityHashCode(bitcoinController) + " as listener to tx = " + sendTransaction.getHashAsString()); - sendTransaction.getConfidence().addEventListener(bitcoinController); - } else { - log.debug("Cannot add bitcoinController as listener to tx = " + sendTransaction.getHashAsString() + " no transactionConfidence"); - } - - try { - bitcoinController.getFileHandler().savePerWalletModelData(perWalletModelData, false); - } catch (WalletSaveException wse) { - log.error(wse.getClass().getCanonicalName() + " " + wse.getMessage()); - MessageManager.INSTANCE.addMessage(new Message(wse.getClass().getCanonicalName() + " " + wse.getMessage())); - } catch (WalletVersionException wse) { - log.error(wse.getClass().getCanonicalName() + " " + wse.getMessage()); - MessageManager.INSTANCE.addMessage(new Message(wse.getClass().getCanonicalName() + " " + wse.getMessage())); - } - - try { - // Notify other wallets of the send (it might be a send to or from them). - List perWalletModelDataList = bitcoinController.getModel().getPerWalletModelDataList(); - - if (perWalletModelDataList != null) { - for (WalletData loopPerWalletModelData : perWalletModelDataList) { - if (!perWalletModelData.getWalletFilename().equals(loopPerWalletModelData.getWalletFilename())) { - Wallet loopWallet = loopPerWalletModelData.getWallet(); - if (loopWallet.isPendingTransactionRelevant(sendTransaction)) { - // The loopPerWalletModelData is marked as dirty. - if (loopPerWalletModelData.getWalletInfo() != null) { - synchronized (loopPerWalletModelData.getWalletInfo()) { - loopPerWalletModelData.setDirty(true); - } - } else { - loopPerWalletModelData.setDirty(true); - } - if (loopWallet.getTransaction(sendTransaction.getHash()) == null) { - log.debug("MultiBit adding a new pending transaction for the wallet '" - + loopPerWalletModelData.getWalletDescription() + "'\n" + sendTransaction.toString()); - loopWallet.receivePending(sendTransaction, null); + try { + // Notify other wallets of the send (it might be a send to or from them). + List perWalletModelDataList = bitcoinController.getModel().getPerWalletModelDataList(); + + if (perWalletModelDataList != null) { + for (WalletData loopPerWalletModelData : perWalletModelDataList) { + if (!perWalletModelData.getWalletFilename().equals(loopPerWalletModelData.getWalletFilename())) { + Wallet loopWallet = loopPerWalletModelData.getWallet(); + if (loopWallet.isPendingTransactionRelevant(sendTransaction)) { + // The loopPerWalletModelData is marked as dirty. + if (loopPerWalletModelData.getWalletInfo() != null) { + synchronized (loopPerWalletModelData.getWalletInfo()) { + loopPerWalletModelData.setDirty(true); + } + } else { + loopPerWalletModelData.setDirty(true); + } + if (loopWallet.getTransaction(sendTransaction.getHash()) == null) { + log.debug("MultiBit adding a new pending transaction for the wallet '" + + loopPerWalletModelData.getWalletDescription() + "'\n" + sendTransaction.toString()); + loopWallet.receivePending(sendTransaction, null); + } + } + } + } } - } + } catch (ScriptException e) { + e.printStackTrace(); + } catch (VerificationException e) { + e.printStackTrace(); } - } } - } catch (ScriptException e) { - e.printStackTrace(); - } catch (VerificationException e) { - e.printStackTrace(); - } + return sendTransaction; } - return sendTransaction; - } - public PeerGroup getPeerGroup() { - return peerGroup; - } - - public MultiBitBlockChain getChain() { - return blockChain; - } + public PeerGroup getPeerGroup() { + return peerGroup; + } - public BlockStore getBlockStore() { - return blockStore; - } + public MultiBitBlockChain getChain() { + return blockChain; + } - public SecureRandom getSecureRandom() { - return secureRandom; - } + public BlockStore getBlockStore() { + return blockStore; + } - ; + public SecureRandom getSecureRandom() { + return secureRandom; + }; - public String getCheckpointsFilename() { - return checkpointsFilename; - } + public String getCheckpointsFilename() { + return checkpointsFilename; + } - public MultiBitCheckpointManager getCheckpointManager() { - return checkpointManager; - } -} \ No newline at end of file + public MultiBitCheckpointManager getCheckpointManager() { + return checkpointManager; + }; +} diff --git a/src/main/resources/i18n/fr/viewer.properties b/src/main/resources/i18n/fr/viewer.properties index f6e761776..163884eba 100755 --- a/src/main/resources/i18n/fr/viewer.properties +++ b/src/main/resources/i18n/fr/viewer.properties @@ -51,12 +51,12 @@ showPreferencesPanel.language.37=Serbe showPreferencesPanel.feeTitle=Frais de transaction showPreferencesPanel.feeLabel.text=Frais showPreferencesPanel.size.text={0} octets -showPreferencesPanel.couldNotUnderstandFee=MultiDoge ne pouvait comprendre les frais de \u00ab {0} \u00bb. Maintenir les frais de vieux. -showPreferencesPanel.aFeeMustBeSet=Vous devez d\u00e9finir un frais de transaction. Maintenir les frais de vieux. -showPreferencesPanel.feeCannotBeSmallerThanMinimumFee=La redevance doit \u00eatre au moins de 0,0001 DOGE. Maintenir les frais de vieux. +showPreferencesPanel.couldNotUnderstandFee=MultiDoge ne pouvait comprendre les frais de \u00ab {0} \u00bb. Maintien des anciens frais. +showPreferencesPanel.aFeeMustBeSet=Vous devez d\u00e9finir un frais de transaction. Maintien des anciens frais. +showPreferencesPanel.feeCannotBeSmallerThanMinimumFee=La redevance doit \u00eatre au moins de 0,0001 DOGE. Maintien des anciens frais. showPreferencesPanel.feeCannotBeGreaterThanMaximumFee=Les frais doivent \u00eatre inf\u00e9rieurs \u00e0 1 DOGE. V\u00e9rifiez votre s\u00e9parateur d\u00e9cimal. La valeur pr\u00e9c\u00e9dente a \u00e9t\u00e9 conserv\u00e9e. showPreferencesPanel.browserIntegrationTitle=Int\u00e9gration du navigateur web -showPreferencesPanel.browserIntegration.messageText=Qu'elle action souhaitez-vous lorsqu\u2019une demande de paiement de Dogecoin est cliqu\u00e9e dans le navigateur ? +showPreferencesPanel.browserIntegration.messageText=Qu'elle action souhaitez-vous faire lorsqu\u2019une demande de paiement de Dogecoin est cliqu\u00e9e dans le navigateur ? showPreferencesPanel.ignoreAll=Ignorer toutes les demandes de paiement de Dogecoin showPreferencesPanel.fillAutomatically=Remplissage automatique du formulaire de versement showPreferencesPanel.askEveryTime=Me demander \u00e0 chaque fois @@ -78,7 +78,7 @@ showPreferencesPanel.ticker.showSecondRow=Afficher la deuxi\u00e8me ligne showPreferencesPanel.ticker.exchange=March\u00e9 showPreferencesPanel.ticker.currency=Monnaie showPreferencesPanel.ticker.showBitcoinConvertedToFiat=Afficher les dogecoins convertis en monnaie fiduciaire -showPreferencesPanel.ticker.exchangeInformation=Le prix converti des dogecoin sera affich\u00e9 selon le dernier cours de cette devise. +showPreferencesPanel.ticker.exchangeInformation=Le prix converti des dogecoins sera affich\u00e9 selon le dernier cours de cette devise. showPreferencesPanel.oerLabel.text=App ID d'OpenExchangeRates showPreferencesPanel.oerLabel.tooltip=Le code d'acc\u00e8s App ID de OpenExchangeRates.org showPreferencesPanel.oerValidationError.text1=Vous avez entr\u00e9 un ID d'application non valide. @@ -97,7 +97,7 @@ multibit.userDataDirectory=Le r\u00e9pertoire de donn\u00e9es de l'utilisateur e multibit.installationDirectory=Le r\u00e9pertoire d'installation est \u00ab {0} \u00bb. multiBitFrame.title=Multibit multiBitFrame.balanceLabel=Balance -multiBitFrame.balanceLabel.tooltip=Balance y compris dogecoins non confirm\u00e9es et changement +multiBitFrame.balanceLabel.tooltip=Balance y compris des dogecoins non confirm\u00e9es et changement multiBitFrame.ticker.show.text=Afficher les taux de change multiBitFrame.ticker.hide.text=Masquer les taux de change multiBitFrame.statusBar.tooltip1=Messages. @@ -153,11 +153,11 @@ multiBitService.stoppingBitcoinNetworkConnection=D\u00e9connexion du r\u00e9seau multiBitService.couldNotLoadBlockchain=Impossible de charger la cha\u00eene de blocs \u00ab {0} \u00bb. L'erreur est \u00ab {1} \u00bb. multiBitService.replayingFromBlockCache=Relecture du cache local... -exitAction.text=Sortie +exitAction.text=Quitter exitAction.tooltip=Sortir de Multibit exitAction.mnemonicKey=X -openWalletAction.text=Ouvert portefeuille +openWalletAction.text=Ouvrir un portefeuille openWalletAction.tooltip=Ouvrir un portefeuille \u00e0 partir d'un fichier openWalletAction.mnemonicKey=O openWalletAction.walletOpenedSuccessfully=Porte-monnaie \u00ab {0} \u00bb ouvert avec succ\u00e8s @@ -173,10 +173,10 @@ openWalletView.title=Portefeuille ouvert saveWalletAsView.untitled=Sans titre -helpAboutAction.text=Sujet de MultiDoge -helpAboutAction.tooltip=Sujet de MultiDoge +helpAboutAction.text=\u00c0 propos de MultiDoge +helpAboutAction.tooltip=\u00c0 propos de MultiDoge helpAboutAction.mnemonicKey=S -helpAboutAction.messageBoxTitle=Sujet de MultiDoge +helpAboutAction.messageBoxTitle=\u00c0 propos de MultiDoge helpAboutAction.versionText=Version \: {0} showHelpContentsAction.text=Contenu de l'aide @@ -185,17 +185,17 @@ showHelpContentsAction.mnemonicKey=A helpContentsView.messageTitle=Contenu de l'aide -sendBitcoinAction.text=Envoyez Dogecoin -sendBitcoinAction.tooltip=Envoyer dogecoin +sendBitcoinAction.text=Envoyer des dogecoins +sendBitcoinAction.tooltip=Envoyer des dogecoins sendBitcoinAction.pleaseWait.tooltip=Veuillez patienter jusqu'\u00e0 ce que Multibit ait fini de se synchroniser avant d'envoyer sendBitcoinAction.mnemonicKey=E sendBitcoinConfirmAction.text=Envoyer -sendBitcoinConfirmAction.tooltip=Envoyer dogecoin +sendBitcoinConfirmAction.tooltip=Envoyer des dogecoins sendBitcoinConfirmAction.mnemonicKey=E sendBitcoinNowAction.sendingBitcoin=envoi de dogecoin... -sendBitcoinNowAction.bitcoinSentOk=Votre dogecoin ont \u00e9t\u00e9 envoy\u00e9 avec succ\u00e8s. +sendBitcoinNowAction.bitcoinSentOk=Vos dogecoin ont \u00e9t\u00e9 envoy\u00e9 avec succ\u00e8s. sendBitcoinNowAction.bitcoinSendFailed=\u00c9chec de l'envoi de votre dogecoin. sendBitcoinNowAction.pingFailure=Tous les pairs ont \u00e9chou\u00e9 au test de r\u00e9seau. V\u00e9rifiez votre connexion r\u00e9seau, puis red\u00e9marrez MultiDoge. sendBitcoinNowAction.thereWereInsufficientFundsForTheSend=Solde insuffisant pour effectuer votre versement. @@ -206,9 +206,9 @@ sendBitcoinConfirmView.message=Veuillez confirmer que vous souhaitez envoyer dog sendBitcoinConfirmView.title=Confirmer Envoyer Dogecoin sendBitcoinConfirmView.multibitMustBeOnline=MultiDoge doit \u00eatre en ligne et connect\u00e9 \u00e0 plus d'un pair pour envoyer des dogecoins. -receiveBitcoinAction.textShort=Requ\u00eate -receiveBitcoinAction.text=Requ\u00eate de Dogecoin -receiveBitcoinAction.tooltip=Faire une requ\u00eate de dogecoin \u00e0 quelqu'un +receiveBitcoinAction.textShort=Demander +receiveBitcoinAction.text=Demande de dogecoin +receiveBitcoinAction.tooltip=Demander des dogecoins receiveBitcoinAction.mnemonicKey=R showPreferencesAction.text=Pr\u00e9f\u00e9rences @@ -245,7 +245,7 @@ sendBitcoinPanel.showLess.text=Moins sendBitcoinPanel.showLess.tooltip=Masquer le panneau lat\u00e9ral sendBitcoinPanel.showLess.mnemonic=H -receiveBitcoinPanel.title=Recevez Dogecoin +receiveBitcoinPanel.title=Recevez des Dogecoin receiveBitcoinPanel.helpLabel1.message=Vous souhaitez recevoir des dogecoin. receiveBitcoinPanel.helpLabel2.message=Choisissez l'une de vos adresses de r\u00e9ception. receiveBitcoinPanel.helpLabel3.message=\u00c9ventuellement entrer une \u00e9tiquette et un montant. @@ -300,8 +300,8 @@ pasteAddressAction.text=Coller pasteAddressAction.tooltip=Collez l'adresse \u00e0 partir du presse-papiers pasteAddressAction.mnemonicKey=P -okBackToParentAction.text=D'accord -okBackToParentAction.tooltip=D'accord, fermer cette fen\u00eatre +okBackToParentAction.text=OK +okBackToParentAction.tooltip=OK, fermer cette fen\u00eatre okBackToParentAction.text.mnemonicKey=O cancelBackToParentAction.text=Annuler @@ -358,7 +358,7 @@ createNewWalletSubmitAction.defaultDescription=Description de votre portefeuille singleWalletPanel.dataHasChanged.text=Mises \u00e0 jour s'est arr\u00eat\u00e9. singleWalletPanel.dataHasChanged.tooltip.1=Un autre programme a chang\u00e9 ce portefeuille. singleWalletPanel.dataHasChanged.tooltip.2=Pour \u00e9viter des erreurs ce MultiDoge a cess\u00e9 de mises \u00e0 jour. -singleWalletPanel.dataHasChanged.backupFile=Fichier de sauvegarde est \u00ab {0} \u00bb. +singleWalletPanel.dataHasChanged.backupFile=Le fichier de sauvegarde est \u00ab {0} \u00bb. singleWalletPanel.twistyRightText=Cliquez ici pour afficher les d\u00e9tails du porte-monnaie singleWalletPanel.twistyDownText=Cliquez ici pour cacher les d\u00e9tails du porte-monnaie singleWalletPanel.type=Type \: @@ -408,7 +408,7 @@ showOpenUriViewAction.mnemonic=Y fontChooser.text=Choisissez la police d'affichage fontChooser.tooltip=Choisissez la police \u00e0 utiliser dans MultiDoge fontChooser.mnemonic=F -fontChooser.ok=D'accord +fontChooser.ok=OK fontChooser.cancel=Annuler fontChooser.selectFont=S\u00e9lectionnez la police fontChooser.fontName=Nom de police @@ -428,7 +428,7 @@ showExportPrivateKeysAction.text=Exporter des cl\u00e9s priv\u00e9es showExportPrivateKeysAction.text.camel=Exporter les cl\u00e9s priv\u00e9es showExportPrivateKeysAction.tooltip=Exporter les cl\u00e9s priv\u00e9es dans un fichier showExportPrivateKeysAction.mnemonic=X -showExportPrivateKeysAction.youMustSelectAnOutputFile=Vous devez donner le nom d'un fichier d'export +showExportPrivateKeysAction.youMustSelectAnOutputFile=Vous devez donner un nom pour le fichier d'export showExportPrivateKeysAction.privateKeysExportSuccess=Les cl\u00e9s priv\u00e9es ont \u00e9t\u00e9 export\u00e9es. showExportPrivateKeysAction.privateKeysExportFailure=\u00c9chec de l'exportation des cl\u00e9s priv\u00e9es. L'erreur \u00e9tait \u00ab {0} \u00bb. showExportPrivateKeysAction.enterPasswords=Entrez le mot de passe avec lequel vous voulez prot\u00e9ger le fichier d'exportation @@ -552,7 +552,7 @@ tickerTableModel.lastPrice=Dernier tickerTableModel.exchange=March\u00e9 tickerTablePanel.tooltip=Taux de change. -tickerTablePanel.tooltip.clickToConfigure=Cliquez pour Configurer. +tickerTablePanel.tooltip.clickToConfigure=Cliquez pour configurer. messagesPanel.text=Messages messagesPanel.tooltip=Afficher les messages @@ -597,7 +597,7 @@ changePasswordSubmitAction.text=Modifier le mot de passe changePasswordSubmitAction.tooltip=Changer le mot de passe du porte-monnaie changePasswordSubmitAction.mnemonic=C -removePasswordAction.text=Enlever le mot de passe +removePasswordAction.text=Supprimer le mot de passe removePasswordAction.tooltip=Supprimer le mot de passe du porte-monnaie removePasswordAction.mnemonic=R removePasswordPanel.text=Le porte-monnaie suivant ne sera plus prot\u00e9g\u00e9 par un mot de passe \: diff --git a/src/test/resources/privateKeys/test1-data/rolling-backup/test1-20131209212328.wallet b/src/test/resources/privateKeys/test1-data/rolling-backup/test1-20131209212328.wallet new file mode 100644 index 000000000..1b2c01bd1 Binary files /dev/null and b/src/test/resources/privateKeys/test1-data/rolling-backup/test1-20131209212328.wallet differ diff --git a/src/test/resources/privateKeys/test1.info b/src/test/resources/privateKeys/test1.info index be2626f4a..33c6d7a08 100644 --- a/src/test/resources/privateKeys/test1.info +++ b/src/test/resources/privateKeys/test1.info @@ -31,7 +31,7 @@ property,receiveAmount,0.05 property,sendAddress,1KqnxT4ERDMjue8GvCWsaCcxRcZPNZg399 property,receiveLabel,50%25%20of%20LoveBitcoins.org%20subs property,sendLabel,petty%20cash%201 +property,walletBackupFile,%2FUsers%2Fjim%2FIdeaProjects%2Fmultibit%2Fsrc%2Ftest%2Fresources%2FprivateKeys%2Ftest1-data%2Frolling-backup%2Ftest1-20131209212328.wallet property,receiveAddress,1NcfaCrfNTRMBhCrF8uw8W6U6sRWYAH6QK -property,walletBackupFile,%2FUsers%2Fjim%2FIdeaProjects%2Fmultibit%2Fsrc%2Ftest%2Fresources%2FprivateKeys%2Ftest1-data%2Frolling-backup%2Ftest1-20131209221532.wallet property,sendAmount,9.1464 property,openUriShowDialog,false diff --git a/src/test/resources/privateKeys/test1.key b/src/test/resources/privateKeys/test1.key index 11939691f..bd4f9b0ce 100644 --- a/src/test/resources/privateKeys/test1.key +++ b/src/test/resources/privateKeys/test1.key @@ -10,11 +10,11 @@ # Key createdAt is in UTC format as specified by ISO 8601 # e.g: 2011-12-31T16:42:00Z . The century, 'T' and 'Z' are mandatory # -6JfpcBZ6gUC8N4RBJpRUynnXECNRGt7bhk6wFJ4Xu8YCAQiMhhF 2011-10-07T15:58:17Z -6KizahApoJFMrU27w9oejH6KRP2k8TBhrN4y2kMHpwaowG3DAaD 2011-10-14T12:18:17Z -6JAWYG8hk85Qf3a4MkwE1zV4sZ9GfWNkvM1Y5iWGrzA8TfJ8J22 2011-10-14T12:18:17Z -6KFBADXajg8k1ZKcPMffJ4PHRxMwYmRwZLt7UmwaWPDTKUZpomi 2011-10-14T12:34:45Z -6Ko7ZLmpqmSAzDZnMTedvs2qim5eGkPijF8aaaZbjjAm4HccHkB 2011-10-14T13:02:17Z -6JbwL6nbpZS9NoWMtSkgZJCEKqaobUFbmj1BLGptNoN4FdyJuBD 2013-12-04T12:52:31Z -6KDwkVdDc1sJEACNAaNzJZDxw6HwuaZJ6YrMMioXdeYgWud71LQ 2013-12-04T12:52:31Z +5JMVKE697huLKSz27RoWNAoHkmtsmkqL6ZyhvoRe5ULZMk2YQoa 2011-10-07T15:58:17Z +5KQfHjhsEXxZoraxjmBg7f75wxZCdKuSFBwjiFiQ1HPB8bMCQEH 2011-10-14T12:18:17Z +5HrBFJfkBMnccS8uANKFQNVqQ8fjAP6VKAtJmDsP3KxVf2TkFYn 2011-10-14T12:18:17Z +5JvqsG4dAuqwxwtTBy3ggSQ3xXtQ3e9fxAktAHJggj1pWp3EbjH 2011-10-14T12:34:45Z +5KUnGPJsH19Nwc8dA52fKF3cFLc6md7T851MG5vhv4y8Fa3HEJp 2011-10-14T13:02:17Z +5JHc39KeFo9MLC5Ch48hwgCzrR7G6LyLAYsx1nBzZ9ARSxzk2S3 2013-12-04T12:52:31Z +5JucTYAG3FaWBYmCyBm1gwEjTfpQQTH2VNj83EAdozM3iKim3Za 2013-12-04T12:52:31Z # End of private keys diff --git a/src/test/resources/privateKeys/test1.wallet b/src/test/resources/privateKeys/test1.wallet index a2637698b..d43f1fb2f 100644 Binary files a/src/test/resources/privateKeys/test1.wallet and b/src/test/resources/privateKeys/test1.wallet differ