/** * Copyright 2013 multibit.org * * Licensed under the MIT license (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://opensource.org/licenses/mit-license.php * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.multibit.network; import java.io.File; import java.io.IOException; import java.math.BigInteger; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.TimeZone; import junit.framework.TestCase; import org.junit.Before; import org.junit.Test; import org.multibit.ApplicationDataDirectoryLocator; import org.multibit.Constants; import org.multibit.Localiser; import org.multibit.CreateControllers; import org.multibit.controller.bitcoin.BitcoinController; import org.multibit.file.FileHandler; import org.multibit.model.bitcoin.WalletData; import org.multibit.model.bitcoin.WalletInfoData; import org.multibit.store.MultiBitWalletVersion; import org.multibit.viewsystem.simple.SimpleViewSystem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.bitcoin.core.DumpedPrivateKey; import com.google.bitcoin.core.ECKey; import com.google.bitcoin.core.NetworkParameters; import com.google.bitcoin.core.Wallet; import com.google.bitcoin.core.Wallet.BalanceType; public class ReplayManagerTest extends TestCase { private static final Logger log = LoggerFactory.getLogger(ReplayManagerTest.class); private BitcoinController controller; private Localiser localiser; private File multiBitDirectory; // The address for this private key is "1N4qu8a6NwBrxM5PvSoFh4qe6QSWmG6Xds". private static final String REPLAY1_PRIVATE_KEY = "5Jsokwg1ypfCPgJXv4vnhW11YWSp4anh9UbHoCZFZdwAnEpU69u"; private static final String START_OF_REPLAY_PERIOD = "2012-09-03T10:00:00Z"; private static final BigInteger BALANCE_AT_START = BigInteger.ZERO; private SimpleDateFormat formatter; private SimpleViewSystem simpleViewSystem; @Before public void setUp() throws Exception { multiBitDirectory = createMultiBitRuntime(); // Set the application data directory to be the one we just created. ApplicationDataDirectoryLocator applicationDataDirectoryLocator = new ApplicationDataDirectoryLocator(multiBitDirectory); // Create MultiBit controller final CreateControllers.Controllers controllers = CreateControllers.createControllers(applicationDataDirectoryLocator); controller = controllers.bitcoinController; log.debug("Creating Bitcoin service"); // Create the MultiBitService that connects to the bitcoin network. MultiBitService multiBitService = new MultiBitService(controller); controller.setMultiBitService(multiBitService); // Add the simple view system (no Swing). simpleViewSystem = new SimpleViewSystem(); controllers.coreController.registerViewSystem(simpleViewSystem); log.debug("Waiting for peer connection. . . "); while (!simpleViewSystem.isOnline()) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } log.debug("Now online."); } @Test public void testReplayManagerSyncSingleWallet() throws Exception { // Get the system property runFunctionalTest to see if the functional // tests need running. String runFunctionalTests = System.getProperty(Constants.RUN_FUNCTIONAL_TESTS_PARAMETER); if (Boolean.TRUE.toString().equalsIgnoreCase(runFunctionalTests)) { // Date format is UTC with century, T time separator and Z for UTC // timezone. formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH); formatter.setTimeZone(TimeZone.getTimeZone("UTC")); // Initialise replay manager ReplayManager replayManager = ReplayManager.INSTANCE; assertNotNull(replayManager); replayManager.initialise(controller, true); String replayWalletPath = multiBitDirectory.getAbsolutePath() + File.separator + "replay.wallet"; // Create a new wallet. Wallet replayWallet = new Wallet(NetworkParameters.prodNet()); // Add in the replay key. DumpedPrivateKey replayDumpedPrivateKey = new DumpedPrivateKey(NetworkParameters.prodNet(), REPLAY1_PRIVATE_KEY); ECKey replayKey = replayDumpedPrivateKey.getKey(); replayKey.setCreationTimeSeconds(formatter.parse(START_OF_REPLAY_PERIOD).getTime() / 1000); log.debug("replayPrivateKey getCreationTimeSeconds = " + replayKey.getCreationTimeSeconds()); replayWallet.addKey(replayKey); WalletData perWalletModelData = new WalletData(); perWalletModelData.setWalletInfo(new WalletInfoData(replayWalletPath, replayWallet, MultiBitWalletVersion.PROTOBUF)); perWalletModelData.setWallet(replayWallet); perWalletModelData.setWalletFilename(replayWalletPath); perWalletModelData.setWalletDescription("testReplayManagerSyncSingleWallet test"); controller.getModel().getPerWalletModelDataList().add(perWalletModelData); log.debug("Replay wallet before replay = \n" + replayWallet.toString()); assertEquals(BALANCE_AT_START, replayWallet.getBalance()); log.debug("Replaying blockchain"); // Create a ReplayTask to replay the replay wallet from the // START_OF_REPLAY_PERIOD. List<WalletData> perWalletModelDataList = new ArrayList<WalletData>(); perWalletModelDataList.add(perWalletModelData); ReplayTask replayTask = new ReplayTask(perWalletModelDataList, formatter.parse(START_OF_REPLAY_PERIOD), ReplayTask.UNKNOWN_START_HEIGHT); replayManager.offerReplayTask(replayTask); // Run for a while. log.debug("Twiddling thumbs for 60 seconds ..."); Thread.sleep(60000); log.debug("... 60 seconds later."); // Check the wallet - there should be some transactions in there. if (replayWallet.getTransactions(true).size() > 0) { // We are done. } else { // Run for a while longer. log.debug("Twiddling thumbs for another 60 seconds ..."); Thread.sleep(60000); log.debug("... 60 seconds later."); if (replayWallet.getTransactions(true).size() > 0) { // We are done. } else { if (simpleViewSystem.getNumberOfBlocksDownloaded() > 0) { // Well it tried but probably got a slow connection - // give it a pass. } else { fail("No blocks were downloaded on replay"); } } } // Print out replay wallet after replay. log.debug("Replay wallet after replay = \n" + replayWallet); } else { log.debug("Not running functional test: ReplayManagerTest#testReplayManagerSyncSingleWallet. Add '-DrunFunctionalTests=true' to run"); } } /** * Create a working, portable runtime of MultiBit in a temporary directory. * * @return the temporary directory the multibit runtime has been created in */ private File createMultiBitRuntime() throws IOException { File multiBitDirectory = FileHandler.createTempDirectory("multibit"); String multiBitDirectoryPath = multiBitDirectory.getAbsolutePath(); System.out.println("Building MultiBit runtime in : " + multiBitDirectory.getAbsolutePath()); // Create an empty multibit.properties. File multibitProperties = new File(multiBitDirectoryPath + File.separator + "multibit.properties"); multibitProperties.createNewFile(); multibitProperties.deleteOnExit(); // Copy in the checkpoints and blockchain stored in git - this is in // source/main/resources/. File multibitBlockcheckpoints = new File(multiBitDirectoryPath + File.separator + "multibit.checkpoints"); FileHandler.copyFile(new File("./src/main/resources/multibit.checkpoints"), multibitBlockcheckpoints); multibitBlockcheckpoints.deleteOnExit(); return multiBitDirectory; } }