From 5f2029e21b6441db663beb5109b7c28c0266ed0e Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Sun, 18 Sep 2011 20:54:23 +0000 Subject: [PATCH] Introduce a mock clock, use it to improve the getRecentTransactions unit tests. Fix a seconds/milliseconds confusion pointed out by Andreas. Resolves issue 43. --- src/com/google/bitcoin/core/PeerAddress.java | 2 +- src/com/google/bitcoin/core/Transaction.java | 4 ++-- src/com/google/bitcoin/core/Utils.java | 20 +++++++++++++++++++ src/com/google/bitcoin/core/Wallet.java | 3 +-- tests/com/google/bitcoin/core/TestUtils.java | 2 +- tests/com/google/bitcoin/core/WalletTest.java | 11 +++++----- 6 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/com/google/bitcoin/core/PeerAddress.java b/src/com/google/bitcoin/core/PeerAddress.java index 77c79906..4d0e85a1 100644 --- a/src/com/google/bitcoin/core/PeerAddress.java +++ b/src/com/google/bitcoin/core/PeerAddress.java @@ -71,7 +71,7 @@ public class PeerAddress extends Message { @Override public void bitcoinSerializeToStream(OutputStream stream) throws IOException { if (protocolVersion >= 31402) { - int secs = (int)(new Date().getTime() / 1000); + int secs = (int)(Utils.now().getTime() / 1000); uint32ToByteStreamLE(secs, stream); } uint64ToByteStreamLE(services, stream); // nServices. diff --git a/src/com/google/bitcoin/core/Transaction.java b/src/com/google/bitcoin/core/Transaction.java index d501b1f4..5b08157d 100644 --- a/src/com/google/bitcoin/core/Transaction.java +++ b/src/com/google/bitcoin/core/Transaction.java @@ -149,7 +149,7 @@ public class Transaction extends Message implements Serializable { */ void addBlockAppearance(StoredBlock block, boolean bestChain) { if (bestChain && updatedAt == null) { - updatedAt = new Date(block.getHeader().getTimeSeconds()); + updatedAt = new Date(block.getHeader().getTimeSeconds() * 1000); } if (appearsIn == null) { appearsIn = new HashSet(); @@ -247,7 +247,7 @@ public class Transaction extends Message implements Serializable { for (StoredBlock b : appearsIn) { earliestTimeSecs = Math.min(b.getHeader().getTimeSeconds(), earliestTimeSecs); } - updatedAt = new Date(earliestTimeSecs); + updatedAt = new Date(earliestTimeSecs * 1000); } return updatedAt; } diff --git a/src/com/google/bitcoin/core/Utils.java b/src/com/google/bitcoin/core/Utils.java index 53398392..38d27288 100644 --- a/src/com/google/bitcoin/core/Utils.java +++ b/src/com/google/bitcoin/core/Utils.java @@ -24,6 +24,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Date; /** * A collection of various utility methods that are helpful for working with the BitCoin protocol. @@ -238,4 +239,23 @@ public class Utils { if (size >= 3) bytes[6] = (byte) ((compact >> 0) & 0xFF); return decodeMPI(bytes); } + + /** If non-null, overrides the return value of now(). */ + public static Date mockTime; + + /** Advances (or rewinds) the mock clock by the given number of seconds. */ + public static Date rollMockClock(int seconds) { + if (mockTime == null) + mockTime = new Date(); + mockTime = new Date(mockTime.getTime() + (seconds * 1000)); + return mockTime; + } + + /** Returns the current time, or a mocked out equivalent. */ + public static Date now() { + if (mockTime != null) + return mockTime; + else + return new Date(); + } } diff --git a/src/com/google/bitcoin/core/Wallet.java b/src/com/google/bitcoin/core/Wallet.java index 516e388f..6582370d 100644 --- a/src/com/google/bitcoin/core/Wallet.java +++ b/src/com/google/bitcoin/core/Wallet.java @@ -431,8 +431,7 @@ public class Wallet implements Serializable { connectedOutput.markAsSpent(input); maybeMoveTxToSpent(connectedTx, "spent tx"); } - // Refresh the timestamp. - tx.updatedAt = new Date(); + tx.updatedAt = Utils.now(); // Add to the pending pool. It'll be moved out once we receive this transaction on the best chain. pending.put(tx.getHash(), tx); } diff --git a/tests/com/google/bitcoin/core/TestUtils.java b/tests/com/google/bitcoin/core/TestUtils.java index 018b4de9..fa24ce7c 100644 --- a/tests/com/google/bitcoin/core/TestUtils.java +++ b/tests/com/google/bitcoin/core/TestUtils.java @@ -65,7 +65,7 @@ public class TestUtils { public static BlockPair createFakeBlock(NetworkParameters params, BlockStore blockStore, Transaction... transactions) { - return createFakeBlock(params, blockStore, System.currentTimeMillis() / 1000, transactions); + return createFakeBlock(params, blockStore, Utils.now().getTime() / 1000, transactions); } public static Block makeSolvedTestBlock(NetworkParameters params, diff --git a/tests/com/google/bitcoin/core/WalletTest.java b/tests/com/google/bitcoin/core/WalletTest.java index 7efc8d34..847a1d09 100644 --- a/tests/com/google/bitcoin/core/WalletTest.java +++ b/tests/com/google/bitcoin/core/WalletTest.java @@ -276,15 +276,15 @@ public class WalletTest { @Test public void transactionsList() throws Exception { // Check the wallet can give us an ordered list of all received transactions. - long time = System.currentTimeMillis() / 1000; + Utils.rollMockClock(0); // Receive a coin. Transaction tx1 = createFakeTx(params, Utils.toNanoCoins(1, 0), myAddress); - StoredBlock b1 = createFakeBlock(params, blockStore, time, tx1).storedBlock; + StoredBlock b1 = createFakeBlock(params, blockStore, tx1).storedBlock; wallet.receive(tx1, b1, BlockChain.NewBlockType.BEST_CHAIN); // Receive half a coin 10 minutes later. - time += 60 * 10; + Utils.rollMockClock(60 * 10); Transaction tx2 = createFakeTx(params, Utils.toNanoCoins(0, 5), myAddress); - StoredBlock b2 = createFakeBlock(params, blockStore, time, tx1).storedBlock; + StoredBlock b2 = createFakeBlock(params, blockStore, tx1).storedBlock; wallet.receive(tx2, b2, BlockChain.NewBlockType.BEST_CHAIN); // Check we got them back in order. List transactions = wallet.getTransactionsByTime(); @@ -296,7 +296,8 @@ public class WalletTest { assertEquals(1, transactions.size()); assertEquals(tx2, transactions.get(0)); - // Create a spend. + // Create a spend five minutes later. + Utils.rollMockClock(60 * 5); Transaction tx3 = wallet.createSend(new ECKey().toAddress(params), Utils.toNanoCoins(0, 5)); // Does not appear in list yet. assertEquals(2, wallet.getTransactionsByTime().size());