From 8bdc35a32e430dc76e5e6800a0d839fb71bebb58 Mon Sep 17 00:00:00 2001 From: Sean Gilligan Date: Sun, 5 Mar 2023 14:54:26 -0800 Subject: [PATCH] Wallet: migrate `fromWatchingKeyB58()` and `fromSpendingKeyB58()` methods to `java.time` API --- .../main/java/org/bitcoinj/wallet/Wallet.java | 68 ++++++++++++++++--- .../store/WalletProtobufSerializerTest.java | 17 ++--- .../java/org/bitcoinj/wallet/WalletTest.java | 5 +- .../org/bitcoinj/wallettool/WalletTool.java | 3 +- 4 files changed, 72 insertions(+), 21 deletions(-) diff --git a/core/src/main/java/org/bitcoinj/wallet/Wallet.java b/core/src/main/java/org/bitcoinj/wallet/Wallet.java index d481648ec..40a5216a5 100644 --- a/core/src/main/java/org/bitcoinj/wallet/Wallet.java +++ b/core/src/main/java/org/bitcoinj/wallet/Wallet.java @@ -114,6 +114,7 @@ import java.math.BigInteger; import java.math.RoundingMode; import java.nio.ByteBuffer; import java.time.Duration; +import java.time.Instant; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -389,15 +390,39 @@ public class Wallet extends BaseTaggableObject return new Wallet(params, KeyChainGroup.builder(params).addChain(chain).build()); } + /** + * Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given watching key. The + * account path is specified. + * @param params The network + * @param watchKeyB58 The key in base58 notation + * @param creationTime creation time of the key (if unknown use {@link #fromWatchingKeyB58(NetworkParameters, String)} + * @return a new wallet + */ + public static Wallet fromWatchingKeyB58(NetworkParameters params, String watchKeyB58, Instant creationTime) { + final DeterministicKey watchKey = DeterministicKey.deserializeB58(null, watchKeyB58, params.network()); + watchKey.setCreationTimeSeconds(creationTime.getEpochSecond()); + return fromWatchingKey(params, watchKey, outputScriptTypeFromB58(params, watchKeyB58)); + } + /** * Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given watching key. The - * account path is specified. The key is specified in base58 notation and the creation time of the key. If you don't - * know the creation time, you can pass {@link DeterministicHierarchy#BIP32_STANDARDISATION_TIME_SECS}. + * account path is specified. They key's creation time will be set to {@link DeterministicHierarchy#BIP32_STANDARDISATION_TIME_SECS} + * @param params The network + * @param watchKeyB58 The key in base58 notation + * @return a new wallet */ + public static Wallet fromWatchingKeyB58(NetworkParameters params, String watchKeyB58) { + return fromWatchingKeyB58(params, watchKeyB58, Instant.ofEpochSecond(DeterministicHierarchy.BIP32_STANDARDISATION_TIME_SECS)); + } + + /** + * @deprecated Use {@link #fromWatchingKeyB58(NetworkParameters, String, Instant)} or {@link #fromWatchingKeyB58(NetworkParameters, String)} + */ + @Deprecated public static Wallet fromWatchingKeyB58(NetworkParameters params, String watchKeyB58, long creationTimeSeconds) { - final DeterministicKey watchKey = DeterministicKey.deserializeB58(null, watchKeyB58, params); - watchKey.setCreationTimeSeconds(creationTimeSeconds); - return fromWatchingKey(params, watchKey, outputScriptTypeFromB58(params, watchKeyB58)); + return (creationTimeSeconds == 0) + ? fromWatchingKeyB58(params, watchKeyB58) + : fromWatchingKeyB58(params, watchKeyB58, Instant.ofEpochSecond(creationTimeSeconds)); } /** @@ -413,15 +438,38 @@ public class Wallet extends BaseTaggableObject /** * Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given spending key. - * The key is specified in base58 notation and the creation time of the key. If you don't know the creation time, - * you can pass {@link DeterministicHierarchy#BIP32_STANDARDISATION_TIME_SECS}. + * @param params The network + * @param spendingKeyB58 The key in base58 notation + * @param creationTime creation time of the key (if unknown use {@link #fromWatchingKeyB58(NetworkParameters, String)} + * @return a new wallet */ - public static Wallet fromSpendingKeyB58(NetworkParameters params, String spendingKeyB58, long creationTimeSeconds) { - final DeterministicKey spendKey = DeterministicKey.deserializeB58(null, spendingKeyB58, params); - spendKey.setCreationTimeSeconds(creationTimeSeconds); + public static Wallet fromSpendingKeyB58(NetworkParameters params, String spendingKeyB58, Instant creationTime) { + final DeterministicKey spendKey = DeterministicKey.deserializeB58(null, spendingKeyB58, params.network()); + spendKey.setCreationTimeSeconds(creationTime.getEpochSecond()); return fromSpendingKey(params, spendKey, outputScriptTypeFromB58(params, spendingKeyB58)); } + /** + * Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given spending key. + * They key's creation time will be set to {@link DeterministicHierarchy#BIP32_STANDARDISATION_TIME_SECS}. + * @param params The network + * @param spendingKeyB58 The key in base58 notation + * @return a new wallet + */ + public static Wallet fromSpendingKeyB58(NetworkParameters params, String spendingKeyB58) { + return fromSpendingKeyB58(params, spendingKeyB58, Instant.ofEpochSecond(DeterministicHierarchy.BIP32_STANDARDISATION_TIME_SECS)); + } + + /** + * @deprecated Use {@link #fromSpendingKeyB58(NetworkParameters, String, Instant)} or {@link #fromSpendingKeyB58(NetworkParameters, String)} + */ + @Deprecated + public static Wallet fromSpendingKeyB58(NetworkParameters params, String spendingKeyB58, long creationTimeSeconds) { + return (creationTimeSeconds == 0) + ? fromSpendingKeyB58(params, spendingKeyB58) + : fromSpendingKeyB58(params, spendingKeyB58, Instant.ofEpochSecond(creationTimeSeconds)); + } + /** * Creates a wallet that tracks payments to and from the HD key hierarchy rooted by the given spending key. This HAS * to be an account key as returned by {@link DeterministicKeyChain#getWatchingKey()}. diff --git a/core/src/test/java/org/bitcoinj/store/WalletProtobufSerializerTest.java b/core/src/test/java/org/bitcoinj/store/WalletProtobufSerializerTest.java index e563ae772..f2f8e39e0 100644 --- a/core/src/test/java/org/bitcoinj/store/WalletProtobufSerializerTest.java +++ b/core/src/test/java/org/bitcoinj/store/WalletProtobufSerializerTest.java @@ -66,6 +66,7 @@ import java.io.ByteArrayOutputStream; import java.math.BigInteger; import java.net.InetAddress; import java.security.SecureRandom; +import java.time.Instant; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; @@ -347,17 +348,17 @@ public class WalletProtobufSerializerTest { @Test public void testRoundTripWatchingWallet() throws Exception { final String xpub = "tpubD9LrDvFDrB6wYNhbR2XcRRaT4yCa37TjBR3YthBQvrtEwEq6CKeEXUs3TppQd38rfxmxD1qLkC99iP3vKcKwLESSSYdFAftbrpuhSnsw6XM"; - final long creationTimeSeconds = 1457019819; - Wallet wallet = Wallet.fromWatchingKeyB58(TESTNET, xpub, creationTimeSeconds); + final Instant creationTime = Instant.ofEpochSecond(1457019819); + Wallet wallet = Wallet.fromWatchingKeyB58(TESTNET, xpub, creationTime); Wallet wallet2 = roundTrip(wallet); Wallet wallet3 = roundTrip(wallet2); assertEquals(xpub, wallet.getWatchingKey().serializePubB58(TESTNET.network())); - assertEquals(creationTimeSeconds, wallet.getWatchingKey().getCreationTimeSeconds()); - assertEquals(creationTimeSeconds, wallet2.getWatchingKey().getCreationTimeSeconds()); - assertEquals(creationTimeSeconds, wallet3.getWatchingKey().getCreationTimeSeconds()); - assertEquals(creationTimeSeconds, wallet.getEarliestKeyCreationTime()); - assertEquals(creationTimeSeconds, wallet2.getEarliestKeyCreationTime()); - assertEquals(creationTimeSeconds, wallet3.getEarliestKeyCreationTime()); + assertEquals(creationTime.getEpochSecond(), wallet.getWatchingKey().getCreationTimeSeconds()); + assertEquals(creationTime.getEpochSecond(), wallet2.getWatchingKey().getCreationTimeSeconds()); + assertEquals(creationTime.getEpochSecond(), wallet3.getWatchingKey().getCreationTimeSeconds()); + assertEquals(creationTime.getEpochSecond(), wallet.getEarliestKeyCreationTime()); + assertEquals(creationTime.getEpochSecond(), wallet2.getEarliestKeyCreationTime()); + assertEquals(creationTime.getEpochSecond(), wallet3.getEarliestKeyCreationTime()); } @Test diff --git a/core/src/test/java/org/bitcoinj/wallet/WalletTest.java b/core/src/test/java/org/bitcoinj/wallet/WalletTest.java index 5d0087222..0a0af31ea 100644 --- a/core/src/test/java/org/bitcoinj/wallet/WalletTest.java +++ b/core/src/test/java/org/bitcoinj/wallet/WalletTest.java @@ -81,6 +81,7 @@ import java.io.File; import java.math.BigInteger; import java.net.InetAddress; import java.security.SecureRandom; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -1614,7 +1615,7 @@ public class WalletTest extends TestWithWallet { public void watchingWalletWithCreationTime() { DeterministicKey watchKey = wallet.getWatchingKey(); String serialized = watchKey.serializePubB58(TESTNET.network()); - Wallet watchingWallet = Wallet.fromWatchingKeyB58(TESTNET, serialized, 1415282801); + Wallet watchingWallet = Wallet.fromWatchingKeyB58(TESTNET, serialized, Instant.ofEpochSecond(1415282801)); DeterministicKey key2 = watchingWallet.freshReceiveKey(); assertEquals(myKey, key2); @@ -3290,7 +3291,7 @@ public class WalletTest extends TestWithWallet { public void watchingMarriedWallet() throws Exception { DeterministicKey watchKey = wallet.getWatchingKey(); String serialized = watchKey.serializePubB58(TESTNET.network()); - Wallet wallet = Wallet.fromWatchingKeyB58(TESTNET, serialized, 0); + Wallet wallet = Wallet.fromWatchingKeyB58(TESTNET, serialized); blockStore = new MemoryBlockStore(TESTNET); chain = new BlockChain(TESTNET, wallet, blockStore); diff --git a/wallettool/src/main/java/org/bitcoinj/wallettool/WalletTool.java b/wallettool/src/main/java/org/bitcoinj/wallettool/WalletTool.java index c7254e184..961eab733 100644 --- a/wallettool/src/main/java/org/bitcoinj/wallettool/WalletTool.java +++ b/wallettool/src/main/java/org/bitcoinj/wallettool/WalletTool.java @@ -90,6 +90,7 @@ import java.nio.charset.StandardCharsets; import java.security.SecureRandom; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.Date; @@ -1096,7 +1097,7 @@ public class WalletTool implements Callable { } wallet = Wallet.fromSeed(params, seed, outputScriptType, keyChainGroupStructure); } else if (watchKeyStr != null) { - wallet = Wallet.fromWatchingKeyB58(params, watchKeyStr, creationTimeSecs); + wallet = Wallet.fromWatchingKeyB58(params, watchKeyStr, Instant.ofEpochSecond(creationTimeSecs)); } else { wallet = Wallet.createDeterministic(params, outputScriptType, keyChainGroupStructure); }