KeyChainGroup: migrate to Network from NetworkParameters

This commit is contained in:
Andreas Schildbach 2023-04-19 12:54:19 +02:00
parent 3e7761c81c
commit e7017bfc2f
10 changed files with 98 additions and 81 deletions

View file

@ -508,7 +508,7 @@ public class WalletAppKit extends AbstractIdleService implements Closeable {
}
protected Wallet createWallet() {
KeyChainGroup.Builder kcg = KeyChainGroup.builder(params, structure);
KeyChainGroup.Builder kcg = KeyChainGroup.builder(network, structure);
if (restoreFromSeed != null)
kcg.fromSeed(restoreFromSeed, preferredOutputScriptType);
else if (restoreFromKey != null)

View file

@ -20,6 +20,7 @@ package org.bitcoinj.wallet;
import com.google.protobuf.ByteString;
import org.bitcoinj.base.BitcoinNetwork;
import org.bitcoinj.base.Address;
import org.bitcoinj.base.Network;
import org.bitcoinj.base.internal.TimeUtils;
import org.bitcoinj.crypto.AesKey;
import org.bitcoinj.core.BloomFilter;
@ -90,16 +91,16 @@ import static org.bitcoinj.base.internal.Preconditions.checkState;
public class KeyChainGroup implements KeyBag {
/**
* Builder for {@link KeyChainGroup}. Use {@link KeyChainGroup#builder(NetworkParameters)} to acquire an instance.
* Builder for {@link KeyChainGroup}. Use {@link KeyChainGroup#builder(Network)} to acquire an instance.
*/
public static class Builder {
private final NetworkParameters params;
private final Network network;
private final KeyChainGroupStructure structure;
private final List<DeterministicKeyChain> chains = new LinkedList<>();
private int lookaheadSize = -1, lookaheadThreshold = -1;
private Builder(NetworkParameters params, KeyChainGroupStructure structure) {
this.params = params;
private Builder(Network network, KeyChainGroupStructure structure) {
this.network = network;
this.structure = structure;
}
@ -133,16 +134,16 @@ public class KeyChainGroup implements KeyBag {
if (outputScriptType == ScriptType.P2PKH) {
DeterministicKeyChain chain = DeterministicKeyChain.builder().seed(seed)
.outputScriptType(ScriptType.P2PKH)
.accountPath(structure.accountPathFor(ScriptType.P2PKH, params)).build();
.accountPath(structure.accountPathFor(ScriptType.P2PKH, network)).build();
this.chains.clear();
this.chains.add(chain);
} else if (outputScriptType == ScriptType.P2WPKH) {
DeterministicKeyChain fallbackChain = DeterministicKeyChain.builder().seed(seed)
.outputScriptType(ScriptType.P2PKH)
.accountPath(structure.accountPathFor(ScriptType.P2PKH, params)).build();
.accountPath(structure.accountPathFor(ScriptType.P2PKH, network)).build();
DeterministicKeyChain defaultChain = DeterministicKeyChain.builder().seed(seed)
.outputScriptType(ScriptType.P2WPKH)
.accountPath(structure.accountPathFor(ScriptType.P2WPKH, params)).build();
.accountPath(structure.accountPathFor(ScriptType.P2WPKH, network)).build();
this.chains.clear();
this.chains.add(fallbackChain);
this.chains.add(defaultChain);
@ -166,16 +167,16 @@ public class KeyChainGroup implements KeyBag {
if (outputScriptType == ScriptType.P2PKH) {
DeterministicKeyChain chain = DeterministicKeyChain.builder().spend(accountKey)
.outputScriptType(ScriptType.P2PKH)
.accountPath(structure.accountPathFor(ScriptType.P2PKH, params)).build();
.accountPath(structure.accountPathFor(ScriptType.P2PKH, network)).build();
this.chains.clear();
this.chains.add(chain);
} else if (outputScriptType == ScriptType.P2WPKH) {
DeterministicKeyChain fallbackChain = DeterministicKeyChain.builder().spend(accountKey)
.outputScriptType(ScriptType.P2PKH)
.accountPath(structure.accountPathFor(ScriptType.P2PKH, params)).build();
.accountPath(structure.accountPathFor(ScriptType.P2PKH, network)).build();
DeterministicKeyChain defaultChain = DeterministicKeyChain.builder().spend(accountKey)
.outputScriptType(ScriptType.P2WPKH)
.accountPath(structure.accountPathFor(ScriptType.P2WPKH, params)).build();
.accountPath(structure.accountPathFor(ScriptType.P2WPKH, network)).build();
this.chains.clear();
this.chains.add(fallbackChain);
this.chains.add(defaultChain);
@ -223,14 +224,14 @@ public class KeyChainGroup implements KeyBag {
}
public KeyChainGroup build() {
return new KeyChainGroup(params, null, chains, lookaheadSize, lookaheadThreshold, null, null);
return new KeyChainGroup(network, null, chains, lookaheadSize, lookaheadThreshold, null, null);
}
}
private static final Logger log = LoggerFactory.getLogger(KeyChainGroup.class);
private BasicKeyChain basic;
private final NetworkParameters params;
private final Network network;
// Keychains for deterministically derived keys.
protected final @Nullable LinkedList<DeterministicKeyChain> chains;
// currentKeys is used for normal, non-multisig/married wallets. currentAddresses is used when we're handing out
@ -244,22 +245,40 @@ public class KeyChainGroup implements KeyBag {
private final CopyOnWriteArrayList<ListenerRegistration<CurrentKeyChangeEventListener>> currentKeyChangeListeners = new CopyOnWriteArrayList<>();
/** Creates a keychain group with just a basic chain. No deterministic chains will be created automatically. */
public static KeyChainGroup createBasic(Network network) {
return new KeyChainGroup(network, new BasicKeyChain(), null, -1, -1, null, null);
}
/** @deprecated use {@link #createBasic(Network)} */
@Deprecated
public static KeyChainGroup createBasic(NetworkParameters params) {
return new KeyChainGroup(params, new BasicKeyChain(), null, -1, -1, null, null);
return createBasic(params.network());
}
public static KeyChainGroup.Builder builder(Network network) {
return new Builder(network, KeyChainGroupStructure.BIP32);
}
/** @deprecated use {@link #builder(Network)} */
@Deprecated
public static KeyChainGroup.Builder builder(NetworkParameters params) {
return new Builder(params, KeyChainGroupStructure.BIP32);
return builder(params.network());
}
public static KeyChainGroup.Builder builder(Network network, KeyChainGroupStructure structure) {
return new Builder(network, structure);
}
/** @deprecated use {@link #builder(Network, KeyChainGroupStructure)} */
@Deprecated
public static KeyChainGroup.Builder builder(NetworkParameters params, KeyChainGroupStructure structure) {
return new Builder(params, structure);
return builder(params.network(), structure);
}
private KeyChainGroup(NetworkParameters params, @Nullable BasicKeyChain basicKeyChain,
private KeyChainGroup(Network network, @Nullable BasicKeyChain basicKeyChain,
@Nullable List<DeterministicKeyChain> chains, int lookaheadSize, int lookaheadThreshold,
@Nullable EnumMap<KeyChain.KeyPurpose, DeterministicKey> currentKeys, @Nullable KeyCrypter crypter) {
this.params = params;
this.network = network;
this.basic = basicKeyChain == null ? new BasicKeyChain() : basicKeyChain;
if (chains != null) {
if (lookaheadSize > -1)
@ -287,7 +306,7 @@ public class KeyChainGroup implements KeyBag {
for (Map.Entry<KeyChain.KeyPurpose, DeterministicKey> entry : this.currentKeys.entrySet()) {
Address address = ScriptBuilder
.createP2SHOutputScript(getActiveKeyChain().getRedeemData(entry.getValue()).redeemScript)
.getToAddress(params.network());
.getToAddress(network);
currentAddresses.put(entry.getKey(), address);
}
}
@ -376,7 +395,7 @@ public class KeyChainGroup implements KeyBag {
}
return current;
} else if (outputScriptType == ScriptType.P2PKH || outputScriptType == ScriptType.P2WPKH) {
return currentKey(purpose).toAddress(outputScriptType, params.network());
return currentKey(purpose).toAddress(outputScriptType, network);
} else {
throw new IllegalStateException(chain.getOutputScriptType().toString());
}
@ -428,7 +447,7 @@ public class KeyChainGroup implements KeyBag {
*/
public Address freshAddress(KeyChain.KeyPurpose purpose, ScriptType outputScriptType, @Nullable Instant keyRotationTime) {
DeterministicKeyChain chain = getActiveKeyChain(outputScriptType, keyRotationTime);
return chain.getKey(purpose).toAddress(outputScriptType, params.network());
return chain.getKey(purpose).toAddress(outputScriptType, network);
}
/** @deprecated use {@link #freshAddress(KeyChain.KeyPurpose, ScriptType, Instant)} */
@ -447,13 +466,13 @@ public class KeyChainGroup implements KeyBag {
if (chain.isMarried()) {
Script outputScript = chain.freshOutputScript(purpose);
checkState(ScriptPattern.isP2SH(outputScript)); // Only handle P2SH for now
Address freshAddress = LegacyAddress.fromScriptHash(params.network(),
Address freshAddress = LegacyAddress.fromScriptHash(network,
ScriptPattern.extractHashFromP2SH(outputScript));
maybeLookaheadScripts();
currentAddresses.put(purpose, freshAddress);
return freshAddress;
} else if (outputScriptType == ScriptType.P2PKH || outputScriptType == ScriptType.P2WPKH) {
return freshKey(purpose).toAddress(outputScriptType, params.network());
return freshKey(purpose).toAddress(outputScriptType, network);
} else {
throw new IllegalStateException(chain.getOutputScriptType().toString());
}
@ -968,11 +987,11 @@ public class KeyChainGroup implements KeyBag {
.collect(Collectors.toList());
}
static KeyChainGroup fromProtobufUnencrypted(NetworkParameters params, List<Protos.Key> keys) throws UnreadableWalletException {
return fromProtobufUnencrypted(params, keys, new DefaultKeyChainFactory());
static KeyChainGroup fromProtobufUnencrypted(Network network, List<Protos.Key> keys) throws UnreadableWalletException {
return fromProtobufUnencrypted(network, keys, new DefaultKeyChainFactory());
}
public static KeyChainGroup fromProtobufUnencrypted(NetworkParameters params, List<Protos.Key> keys, KeyChainFactory factory) throws UnreadableWalletException {
public static KeyChainGroup fromProtobufUnencrypted(Network network, List<Protos.Key> keys, KeyChainFactory factory) throws UnreadableWalletException {
BasicKeyChain basicKeyChain = BasicKeyChain.fromProtobufUnencrypted(keys);
List<DeterministicKeyChain> chains = DeterministicKeyChain.fromProtobuf(keys, null, factory);
int lookaheadSize = -1, lookaheadThreshold = -1;
@ -984,14 +1003,14 @@ public class KeyChainGroup implements KeyBag {
currentKeys = createCurrentKeysMap(chains);
}
extractFollowingKeychains(chains);
return new KeyChainGroup(params, basicKeyChain, chains, lookaheadSize, lookaheadThreshold, currentKeys, null);
return new KeyChainGroup(network, basicKeyChain, chains, lookaheadSize, lookaheadThreshold, currentKeys, null);
}
static KeyChainGroup fromProtobufEncrypted(NetworkParameters params, List<Protos.Key> keys, KeyCrypter crypter) throws UnreadableWalletException {
return fromProtobufEncrypted(params, keys, crypter, new DefaultKeyChainFactory());
static KeyChainGroup fromProtobufEncrypted(Network network, List<Protos.Key> keys, KeyCrypter crypter) throws UnreadableWalletException {
return fromProtobufEncrypted(network, keys, crypter, new DefaultKeyChainFactory());
}
public static KeyChainGroup fromProtobufEncrypted(NetworkParameters params, List<Protos.Key> keys, KeyCrypter crypter, KeyChainFactory factory) throws UnreadableWalletException {
public static KeyChainGroup fromProtobufEncrypted(Network network, List<Protos.Key> keys, KeyCrypter crypter, KeyChainFactory factory) throws UnreadableWalletException {
Objects.requireNonNull(crypter);
BasicKeyChain basicKeyChain = BasicKeyChain.fromProtobufEncrypted(keys, crypter);
List<DeterministicKeyChain> chains = DeterministicKeyChain.fromProtobuf(keys, crypter, factory);
@ -1004,7 +1023,7 @@ public class KeyChainGroup implements KeyBag {
currentKeys = createCurrentKeysMap(chains);
}
extractFollowingKeychains(chains);
return new KeyChainGroup(params, basicKeyChain, chains, lookaheadSize, lookaheadThreshold, currentKeys, crypter);
return new KeyChainGroup(network, basicKeyChain, chains, lookaheadSize, lookaheadThreshold, currentKeys, crypter);
}
/**
@ -1134,10 +1153,10 @@ public class KeyChainGroup implements KeyBag {
public String toString(boolean includeLookahead, boolean includePrivateKeys, @Nullable AesKey aesKey) {
final StringBuilder builder = new StringBuilder();
if (basic != null)
builder.append(basic.toString(includePrivateKeys, aesKey, params.network()));
builder.append(basic.toString(includePrivateKeys, aesKey, network));
if (chains != null)
for (DeterministicKeyChain chain : chains)
builder.append(chain.toString(includeLookahead, includePrivateKeys, aesKey, params.network())).append('\n');
builder.append(chain.toString(includeLookahead, includePrivateKeys, aesKey, network)).append('\n');
return builder.toString();
}

View file

@ -343,7 +343,7 @@ public class Wallet extends BaseTaggableObject
* @return A new empty wallet
*/
public static Wallet createDeterministic(Network network, ScriptType outputScriptType, KeyChainGroupStructure keyChainGroupStructure) {
return new Wallet(network, KeyChainGroup.builder(NetworkParameters.of(network), keyChainGroupStructure).fromRandom(outputScriptType).build());
return new Wallet(network, KeyChainGroup.builder(network, keyChainGroupStructure).fromRandom(outputScriptType).build());
}
/**
@ -351,7 +351,7 @@ public class Wallet extends BaseTaggableObject
*/
@Deprecated
public static Wallet createDeterministic(NetworkParameters params, ScriptType outputScriptType, KeyChainGroupStructure keyChainGroupStructure) {
return new Wallet(params.network(), KeyChainGroup.builder(params, keyChainGroupStructure).fromRandom(outputScriptType).build());
return new Wallet(params.network(), KeyChainGroup.builder(params.network(), keyChainGroupStructure).fromRandom(outputScriptType).build());
}
/**
@ -360,7 +360,7 @@ public class Wallet extends BaseTaggableObject
* @param network network wallet will operate on
*/
public static Wallet createBasic(Network network) {
return new Wallet(network, KeyChainGroup.createBasic(NetworkParameters.of(network)));
return new Wallet(network, KeyChainGroup.createBasic(network));
}
/**
@ -400,7 +400,7 @@ public class Wallet extends BaseTaggableObject
*/
public static Wallet fromSeed(Network network, DeterministicSeed seed, ScriptType outputScriptType,
KeyChainGroupStructure structure) {
return new Wallet(network, KeyChainGroup.builder(NetworkParameters.of(network), structure).fromSeed(seed, outputScriptType).build());
return new Wallet(network, KeyChainGroup.builder(network, structure).fromSeed(seed, outputScriptType).build());
}
/**
@ -423,7 +423,7 @@ public class Wallet extends BaseTaggableObject
List<ChildNumber> accountPath) {
DeterministicKeyChain chain = DeterministicKeyChain.builder().seed(seed).outputScriptType(outputScriptType)
.accountPath(accountPath).build();
return new Wallet(network, KeyChainGroup.builder(NetworkParameters.of(network)).addChain(chain).build());
return new Wallet(network, KeyChainGroup.builder(network).addChain(chain).build());
}
/**
@ -443,7 +443,7 @@ public class Wallet extends BaseTaggableObject
ScriptType outputScriptType) {
DeterministicKeyChain chain = DeterministicKeyChain.builder().watch(watchKey).outputScriptType(outputScriptType)
.build();
return new Wallet(network, KeyChainGroup.builder(NetworkParameters.of(network)).addChain(chain).build());
return new Wallet(network, KeyChainGroup.builder(network).addChain(chain).build());
}
/**
@ -515,7 +515,7 @@ public class Wallet extends BaseTaggableObject
ScriptType outputScriptType) {
DeterministicKeyChain chain = DeterministicKeyChain.builder().spend(spendKey).outputScriptType(outputScriptType)
.build();
return new Wallet(network, KeyChainGroup.builder(NetworkParameters.of(network)).addChain(chain).build());
return new Wallet(network, KeyChainGroup.builder(network).addChain(chain).build());
}
/**
@ -526,7 +526,7 @@ public class Wallet extends BaseTaggableObject
ScriptType outputScriptType) {
DeterministicKeyChain chain = DeterministicKeyChain.builder().spend(spendKey).outputScriptType(outputScriptType)
.build();
return new Wallet(params.network(), KeyChainGroup.builder(params).addChain(chain).build());
return new Wallet(params.network(), KeyChainGroup.builder(params.network()).addChain(chain).build());
}
/**
@ -595,7 +595,7 @@ public class Wallet extends BaseTaggableObject
accountKey.clearCreationTime();
DeterministicKeyChain chain = DeterministicKeyChain.builder().spend(accountKey)
.outputScriptType(outputScriptType).build();
return new Wallet(network, KeyChainGroup.builder(NetworkParameters.of(network)).addChain(chain).build());
return new Wallet(network, KeyChainGroup.builder(network).addChain(chain).build());
}
/**
@ -5749,7 +5749,7 @@ public class Wallet extends BaseTaggableObject
log.info(
"All deterministic chains are currently rotating and we have no random keys, creating fresh {} chain: backup required after this.",
preferredScriptType);
KeyChainGroup newChains = KeyChainGroup.builder(params, structure).fromRandom(preferredScriptType)
KeyChainGroup newChains = KeyChainGroup.builder(network, structure).fromRandom(preferredScriptType)
.build();
if (keyChainGroup.isEncrypted()) {
if (aesKey == null)
@ -5772,7 +5772,7 @@ public class Wallet extends BaseTaggableObject
log.info(
"No non-rotating random keys available, generating entirely new {} tree: backup required after this.",
preferredScriptType);
KeyChainGroup newChains = KeyChainGroup.builder(params, structure).fromRandom(preferredScriptType)
KeyChainGroup newChains = KeyChainGroup.builder(network, structure).fromRandom(preferredScriptType)
.build();
if (keyChainGroup.isEncrypted()) {
if (aesKey == null)

View file

@ -499,9 +499,9 @@ public class WalletProtobufSerializer {
if (walletProto.hasEncryptionParameters()) {
Protos.ScryptParameters encryptionParameters = walletProto.getEncryptionParameters();
final KeyCrypterScrypt keyCrypter = new KeyCrypterScrypt(encryptionParameters);
keyChainGroup = KeyChainGroup.fromProtobufEncrypted(params, walletProto.getKeyList(), keyCrypter, keyChainFactory);
keyChainGroup = KeyChainGroup.fromProtobufEncrypted(params.network(), walletProto.getKeyList(), keyCrypter, keyChainFactory);
} else {
keyChainGroup = KeyChainGroup.fromProtobufUnencrypted(params, walletProto.getKeyList(), keyChainFactory);
keyChainGroup = KeyChainGroup.fromProtobufUnencrypted(params.network(), walletProto.getKeyList(), keyChainFactory);
}
Wallet wallet = factory.create(params.network(), keyChainGroup);

View file

@ -85,7 +85,7 @@ public class BloomFilterTest {
Address addr = privKey.getKey().toAddress(ScriptType.P2PKH, BitcoinNetwork.MAINNET);
assertEquals("17Wx1GQfyPTNWpQMHrTwRSMTCAonSiZx9e", addr.toString());
KeyChainGroup group = KeyChainGroup.builder(MAINNET).build();
KeyChainGroup group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).build();
// Add a random key which happens to have been used in a recent generation
group.importKeys(ECKey.fromPublicOnly(privKey.getKey()), ECKey.fromPublicOnly(ByteUtils.parseHex("03cb219f69f1b49468bd563239a86667e74a06fcba69ac50a08a5cbc42a5808e99")));
Wallet wallet = new Wallet(BitcoinNetwork.MAINNET, group);

View file

@ -109,7 +109,7 @@ public class WalletProtobufSerializerTest {
myKey = new ECKey();
myKey.setCreationTime(Instant.ofEpochSecond(123456789L));
myAddress = myKey.toAddress(ScriptType.P2PKH, BitcoinNetwork.TESTNET);
myWallet = new Wallet(BitcoinNetwork.TESTNET, KeyChainGroup.builder(TESTNET).fromRandom(ScriptType.P2PKH).build());
myWallet = new Wallet(BitcoinNetwork.TESTNET, KeyChainGroup.builder(BitcoinNetwork.TESTNET).fromRandom(ScriptType.P2PKH).build());
myWallet.importKey(myKey);
mScriptCreationTime = TimeUtils.currentTime().minusSeconds(1234);
myWallet.addWatchedAddress(myWatchedKey.toAddress(ScriptType.P2PKH, BitcoinNetwork.TESTNET), mScriptCreationTime);

View file

@ -657,7 +657,7 @@ public class DeterministicKeyChainTest {
DeterministicKey accountKey = HDKeyDerivation.deriveChildKey(coinLevelKey, new ChildNumber(0, true));
accountKey = accountKey.dropParent();
accountKey.setCreationTime(watchingKey.creationTime().get());
KeyChainGroup group = KeyChainGroup.builder(NetworkParameters.of(network)).addChain(DeterministicKeyChain.builder().spend(accountKey)
KeyChainGroup group = KeyChainGroup.builder(network).addChain(DeterministicKeyChain.builder().spend(accountKey)
.outputScriptType(bip44chain.getOutputScriptType()).build()).build();
DeterministicKeyChain fromMasterKeyChain = group.getActiveKeyChain();
assertEquals(BIP44_COIN_1_ACCOUNT_ZERO_PATH, fromMasterKeyChain.getAccountPath());

View file

@ -23,7 +23,6 @@ import org.bitcoinj.base.internal.TimeUtils;
import org.bitcoinj.crypto.AesKey;
import org.bitcoinj.core.BloomFilter;
import org.bitcoinj.crypto.ECKey;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.base.Sha256Hash;
import org.bitcoinj.crypto.DeterministicKey;
import org.bitcoinj.crypto.KeyCrypterException;
@ -60,7 +59,6 @@ public class KeyChainGroupTest {
// Number of initial keys in this tests HD wallet, including interior keys.
private static final int INITIAL_KEYS = 4;
private static final int LOOKAHEAD_SIZE = 5;
private static final NetworkParameters MAINNET = MainNetParams.get();
private static final String XPUB = "xpub68KFnj3bqUx1s7mHejLDBPywCAKdJEu1b49uniEEn2WSbHmZ7xbLqFTjJbtx1LUcAt1DwhoqWHmo2s5WMJp6wi38CiF2hYD49qVViKVvAoi";
private static final byte[] ENTROPY = Sha256Hash.hash("don't use a string seed like this in real life".getBytes());
private static final KeyCrypterScrypt KEY_CRYPTER = new KeyCrypterScrypt(2);
@ -73,7 +71,7 @@ public class KeyChainGroupTest {
public void setup() {
BriefLogFormatter.init();
TimeUtils.setMockClock();
group = KeyChainGroup.builder(MAINNET).lookaheadSize(LOOKAHEAD_SIZE).fromRandom(ScriptType.P2PKH)
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).lookaheadSize(LOOKAHEAD_SIZE).fromRandom(ScriptType.P2PKH)
.build();
group.getActiveKeyChain(); // Force create a chain.
@ -82,7 +80,7 @@ public class KeyChainGroupTest {
@Test
public void createDeterministic_P2PKH() {
KeyChainGroup kcg = KeyChainGroup.builder(MAINNET).fromRandom(ScriptType.P2PKH).build();
KeyChainGroup kcg = KeyChainGroup.builder(BitcoinNetwork.MAINNET).fromRandom(ScriptType.P2PKH).build();
// check default
Address address = kcg.currentAddress(KeyPurpose.RECEIVE_FUNDS);
assertEquals(ScriptType.P2PKH, address.getOutputScriptType());
@ -90,7 +88,7 @@ public class KeyChainGroupTest {
@Test
public void createDeterministic_P2WPKH() {
KeyChainGroup kcg = KeyChainGroup.builder(MAINNET).fromRandom(ScriptType.P2WPKH).build();
KeyChainGroup kcg = KeyChainGroup.builder(BitcoinNetwork.MAINNET).fromRandom(ScriptType.P2WPKH).build();
// check default
Address address = kcg.currentAddress(KeyPurpose.RECEIVE_FUNDS);
assertEquals(ScriptType.P2WPKH, address.getOutputScriptType());
@ -101,7 +99,7 @@ public class KeyChainGroupTest {
private KeyChainGroup createMarriedKeyChainGroup() {
DeterministicKeyChain chain = createMarriedKeyChain();
KeyChainGroup group = KeyChainGroup.builder(MAINNET).lookaheadSize(LOOKAHEAD_SIZE).addChain(chain).build();
KeyChainGroup group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).lookaheadSize(LOOKAHEAD_SIZE).addChain(chain).build();
group.getActiveKeyChain();
return group;
}
@ -334,7 +332,7 @@ public class KeyChainGroupTest {
@Test
public void encryptionWhilstEmpty() {
group = KeyChainGroup.builder(MAINNET).lookaheadSize(5).fromRandom(ScriptType.P2PKH).build();
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).lookaheadSize(5).fromRandom(ScriptType.P2PKH).build();
group.encrypt(KEY_CRYPTER, AES_KEY);
assertTrue(group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS).isEncrypted());
final ECKey key = group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
@ -447,7 +445,7 @@ public class KeyChainGroupTest {
public void serialization() throws Exception {
int initialKeys = INITIAL_KEYS + group.getActiveKeyChain().getAccountPath().size() - 1;
assertEquals(initialKeys + 1 /* for the seed */, group.serializeToProtobuf().size());
group = KeyChainGroup.fromProtobufUnencrypted(MAINNET, group.serializeToProtobuf());
group = KeyChainGroup.fromProtobufUnencrypted(BitcoinNetwork.MAINNET, group.serializeToProtobuf());
group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
DeterministicKey key1 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
DeterministicKey key2 = group.freshKey(KeyChain.KeyPurpose.CHANGE);
@ -458,20 +456,20 @@ public class KeyChainGroupTest {
List<Protos.Key> protoKeys2 = group.serializeToProtobuf();
assertEquals(initialKeys + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 2, protoKeys2.size());
group = KeyChainGroup.fromProtobufUnencrypted(MAINNET, protoKeys1);
group = KeyChainGroup.fromProtobufUnencrypted(BitcoinNetwork.MAINNET, protoKeys1);
assertEquals(initialKeys + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 1, protoKeys1.size());
assertTrue(group.hasKey(key1));
assertTrue(group.hasKey(key2));
assertEquals(key2, group.currentKey(KeyChain.KeyPurpose.CHANGE));
assertEquals(key1, group.currentKey(KeyChain.KeyPurpose.RECEIVE_FUNDS));
group = KeyChainGroup.fromProtobufUnencrypted(MAINNET, protoKeys2);
group = KeyChainGroup.fromProtobufUnencrypted(BitcoinNetwork.MAINNET, protoKeys2);
assertEquals(initialKeys + ((LOOKAHEAD_SIZE + 1) * 2) + 1 /* for the seed */ + 2, protoKeys2.size());
assertTrue(group.hasKey(key1));
assertTrue(group.hasKey(key2));
group.encrypt(KEY_CRYPTER, AES_KEY);
List<Protos.Key> protoKeys3 = group.serializeToProtobuf();
group = KeyChainGroup.fromProtobufEncrypted(MAINNET, protoKeys3, KEY_CRYPTER);
group = KeyChainGroup.fromProtobufEncrypted(BitcoinNetwork.MAINNET, protoKeys3, KEY_CRYPTER);
assertTrue(group.isEncrypted());
assertTrue(group.checkPassword("password"));
group.decrypt(AES_KEY);
@ -481,14 +479,14 @@ public class KeyChainGroupTest {
@Test
public void serializeWatching() throws Exception {
group = KeyChainGroup.builder(MAINNET).lookaheadSize(LOOKAHEAD_SIZE).addChain(DeterministicKeyChain.builder()
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).lookaheadSize(LOOKAHEAD_SIZE).addChain(DeterministicKeyChain.builder()
.watch(watchingAccountKey).outputScriptType(ScriptType.P2PKH).build()).build();
group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
group.freshKey(KeyChain.KeyPurpose.CHANGE);
group.getBloomFilterElementCount(); // Force lookahead.
List<Protos.Key> protoKeys1 = group.serializeToProtobuf();
assertEquals(3 + (group.getLookaheadSize() + group.getLookaheadThreshold() + 1) * 2, protoKeys1.size());
group = KeyChainGroup.fromProtobufUnencrypted(MAINNET, protoKeys1);
group = KeyChainGroup.fromProtobufUnencrypted(BitcoinNetwork.MAINNET, protoKeys1);
assertEquals(3 + (group.getLookaheadSize() + group.getLookaheadThreshold() + 1) * 2, group.serializeToProtobuf().size());
}
@ -500,7 +498,7 @@ public class KeyChainGroupTest {
assertEquals(2, group.getActiveKeyChain().getSigsRequiredToSpend());
List<Protos.Key> protoKeys = group.serializeToProtobuf();
KeyChainGroup group2 = KeyChainGroup.fromProtobufUnencrypted(MAINNET, protoKeys);
KeyChainGroup group2 = KeyChainGroup.fromProtobufUnencrypted(BitcoinNetwork.MAINNET, protoKeys);
assertTrue(group2.isMarried());
assertEquals(2, group.getActiveKeyChain().getSigsRequiredToSpend());
Address address2 = group2.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS);
@ -518,7 +516,7 @@ public class KeyChainGroupTest {
public void constructFromSeed() {
ECKey key1 = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
final DeterministicSeed seed = Objects.requireNonNull(group.getActiveKeyChain().getSeed());
KeyChainGroup group2 = KeyChainGroup.builder(MAINNET).lookaheadSize(5)
KeyChainGroup group2 = KeyChainGroup.builder(BitcoinNetwork.MAINNET).lookaheadSize(5)
.addChain(DeterministicKeyChain.builder().seed(seed).outputScriptType(ScriptType.P2PKH).build())
.build();
ECKey key2 = group2.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
@ -530,7 +528,7 @@ public class KeyChainGroupTest {
DeterministicSeed seed = DeterministicSeed.ofEntropy(ENTROPY, "");
DeterministicKeyChain chain1 = DeterministicKeyChain.builder().seed(seed)
.accountPath(DeterministicKeyChain.ACCOUNT_ZERO_PATH).outputScriptType(ScriptType.P2PKH).build();
group = KeyChainGroup.builder(MAINNET).addChain(chain1).build();
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).addChain(chain1).build();
assertEquals("1M5T5k9yKtGWRtWYMjQtGx3K2sshrABzCT", group.currentAddress(KeyPurpose.RECEIVE_FUNDS).toString());
final DeterministicKeyChain chain2 = DeterministicKeyChain.builder().seed(seed)
@ -549,7 +547,7 @@ public class KeyChainGroupTest {
@Test(expected = DeterministicUpgradeRequiredException.class)
public void deterministicUpgradeRequired() {
// Check that if we try to use HD features in a KCG that only has random keys, we get an exception.
group = KeyChainGroup.builder(MAINNET).build();
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).build();
group.importKeys(new ECKey(), new ECKey());
assertTrue(group.isDeterministicUpgradeRequired(ScriptType.P2PKH, null));
assertTrue(group.isDeterministicUpgradeRequired(ScriptType.P2WPKH, null));
@ -558,7 +556,7 @@ public class KeyChainGroupTest {
@Test
public void deterministicUpgradeUnencrypted() throws Exception {
group = KeyChainGroup.builder(MAINNET).fromRandom(ScriptType.P2PKH).lookaheadSize(LOOKAHEAD_SIZE).build();
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).fromRandom(ScriptType.P2PKH).lookaheadSize(LOOKAHEAD_SIZE).build();
List<Protos.Key> protobufs = group.serializeToProtobuf();
group.upgradeToDeterministic(ScriptType.P2PKH, KeyChainGroupStructure.BIP32, null, null);
@ -569,7 +567,7 @@ public class KeyChainGroupTest {
DeterministicSeed seed1 = group.getActiveKeyChain().getSeed();
assertNotNull(seed1);
group = KeyChainGroup.fromProtobufUnencrypted(MAINNET, protobufs);
group = KeyChainGroup.fromProtobufUnencrypted(BitcoinNetwork.MAINNET, protobufs);
group.upgradeToDeterministic(ScriptType.P2PKH, KeyChainGroupStructure.BIP32, null, null); // Should give same result as last time.
assertFalse(group.isEncrypted());
assertFalse(group.isDeterministicUpgradeRequired(ScriptType.P2PKH, null));
@ -582,7 +580,7 @@ public class KeyChainGroupTest {
@Test
public void deterministicUpgradeEncrypted() throws Exception {
group = KeyChainGroup.builder(MAINNET).fromRandom(ScriptType.P2PKH).build();
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).fromRandom(ScriptType.P2PKH).build();
group.encrypt(KEY_CRYPTER, AES_KEY);
assertTrue(group.isEncrypted());
assertFalse(group.isDeterministicUpgradeRequired(ScriptType.P2PKH, null));
@ -605,7 +603,7 @@ public class KeyChainGroupTest {
@Test
public void isNotWatching() {
group = KeyChainGroup.builder(MAINNET).fromRandom(ScriptType.P2PKH).build();
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).fromRandom(ScriptType.P2PKH).build();
final ECKey key = ECKey.fromPrivate(BigInteger.TEN);
group.importKeys(key);
assertFalse(group.isWatching());
@ -613,7 +611,7 @@ public class KeyChainGroupTest {
@Test
public void isWatching() {
group = KeyChainGroup.builder(MAINNET)
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET)
.addChain(DeterministicKeyChain.builder().watch(DeterministicKey.deserializeB58(
"xpub69bjfJ91ikC5ghsqsVDHNq2dRGaV2HHVx7Y9LXi27LN9BWWAXPTQr4u8U3wAtap8bLdHdkqPpAcZmhMS5SnrMQC4ccaoBccFhh315P4UYzo",
BitcoinNetwork.MAINNET)).outputScriptType(ScriptType.P2PKH).build())
@ -625,13 +623,13 @@ public class KeyChainGroupTest {
@Test(expected = IllegalStateException.class)
public void isWatchingNoKeys() {
group = KeyChainGroup.builder(MAINNET).build();
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).build();
group.isWatching();
}
@Test(expected = IllegalStateException.class)
public void isWatchingMixedKeys() {
group = KeyChainGroup.builder(MAINNET)
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET)
.addChain(DeterministicKeyChain.builder().watch(DeterministicKey.deserializeB58(
"xpub69bjfJ91ikC5ghsqsVDHNq2dRGaV2HHVx7Y9LXi27LN9BWWAXPTQr4u8U3wAtap8bLdHdkqPpAcZmhMS5SnrMQC4ccaoBccFhh315P4UYzo",
BitcoinNetwork.MAINNET)).outputScriptType(ScriptType.P2PKH).build())
@ -643,7 +641,7 @@ public class KeyChainGroupTest {
@Test
public void segwitKeyChainGroup() throws Exception {
group = KeyChainGroup.builder(MAINNET).lookaheadSize(LOOKAHEAD_SIZE)
group = KeyChainGroup.builder(BitcoinNetwork.MAINNET).lookaheadSize(LOOKAHEAD_SIZE)
.addChain(DeterministicKeyChain.builder().entropy(ENTROPY, TimeUtils.currentTime()).outputScriptType(ScriptType.P2WPKH)
.accountPath(DeterministicKeyChain.ACCOUNT_ONE_PATH).build())
.build();
@ -653,7 +651,7 @@ public class KeyChainGroupTest {
assertEquals("bc1qw8sf3mwuwn74qnhj83gjg0cwkk78fun2pxl9t2", group.currentAddress(KeyPurpose.CHANGE).toString());
// round-trip through protobuf
group = KeyChainGroup.fromProtobufUnencrypted(MAINNET, group.serializeToProtobuf());
group = KeyChainGroup.fromProtobufUnencrypted(BitcoinNetwork.MAINNET, group.serializeToProtobuf());
assertEquals(ScriptType.P2WPKH, group.getActiveKeyChain().getOutputScriptType());
assertEquals("bc1qhcurdec849thpjjp3e27atvya43gy2snrechd9",
group.currentAddress(KeyPurpose.RECEIVE_FUNDS).toString());
@ -667,7 +665,7 @@ public class KeyChainGroupTest {
assertEquals("bc1qw8sf3mwuwn74qnhj83gjg0cwkk78fun2pxl9t2", group.currentAddress(KeyPurpose.CHANGE).toString());
// round-trip encrypted again, then dectypt
group = KeyChainGroup.fromProtobufEncrypted(MAINNET, group.serializeToProtobuf(), KEY_CRYPTER);
group = KeyChainGroup.fromProtobufEncrypted(BitcoinNetwork.MAINNET, group.serializeToProtobuf(), KEY_CRYPTER);
group.decrypt(AES_KEY);
assertEquals(ScriptType.P2WPKH, group.getActiveKeyChain().getOutputScriptType());
assertEquals("bc1qhcurdec849thpjjp3e27atvya43gy2snrechd9",
@ -677,7 +675,7 @@ public class KeyChainGroupTest {
@Test
public void onlyBasicKeyEncryptionAndDecryption() {
group = KeyChainGroup.createBasic(MAINNET);
group = KeyChainGroup.createBasic(BitcoinNetwork.MAINNET);
final ECKey key = ECKey.fromPrivate(BigInteger.TEN);
group.importKeys(key);
group.encrypt(KEY_CRYPTER, AES_KEY);

View file

@ -220,7 +220,7 @@ public class WalletTest extends TestWithWallet {
@Test
public void encryptDecryptWalletWithArbitraryPathAndScriptType() throws Exception {
final byte[] ENTROPY = Sha256Hash.hash("don't use a string seed like this in real life".getBytes());
KeyChainGroup keyChainGroup = KeyChainGroup.builder(TESTNET)
KeyChainGroup keyChainGroup = KeyChainGroup.builder(BitcoinNetwork.TESTNET)
.addChain(DeterministicKeyChain.builder().seed(DeterministicSeed.ofEntropy(ENTROPY, "", Instant.ofEpochSecond(1389353062L)))
.outputScriptType(ScriptType.P2WPKH)
.accountPath(DeterministicKeyChain.BIP44_ACCOUNT_ZERO_PATH).build())
@ -3220,7 +3220,7 @@ public class WalletTest extends TestWithWallet {
@Test
public void keyEvents() {
// Check that we can register an event listener, generate some keys and the callbacks are invoked properly.
wallet = new Wallet(BitcoinNetwork.TESTNET, KeyChainGroup.builder(TESTNET).fromRandom(ScriptType.P2PKH).build());
wallet = new Wallet(BitcoinNetwork.TESTNET, KeyChainGroup.builder(BitcoinNetwork.TESTNET).fromRandom(ScriptType.P2PKH).build());
final List<ECKey> keys = new LinkedList<>();
wallet.addKeyChainEventListener(Threading.SAME_THREAD, keys::addAll);
wallet.freshReceiveKey();
@ -3504,7 +3504,7 @@ public class WalletTest extends TestWithWallet {
.outputScriptType(ScriptType.P2PKH).build();
DeterministicKeyChain p2wpkhChain = DeterministicKeyChain.builder().random(new SecureRandom())
.outputScriptType(ScriptType.P2WPKH).build();
KeyChainGroup kcg = KeyChainGroup.builder(TESTNET).addChain(p2pkhChain).addChain(p2wpkhChain).build();
KeyChainGroup kcg = KeyChainGroup.builder(BitcoinNetwork.TESTNET).addChain(p2pkhChain).addChain(p2wpkhChain).build();
Wallet wallet = new Wallet(BitcoinNetwork.TESTNET, kcg);
// Set up one key from each chain.

View file

@ -111,7 +111,7 @@ public class TestWithNetworkConnections {
// Allow subclasses to override the wallet object with their own.
if (wallet == null) {
// Reduce the number of keys we need to work with to speed up these tests.
KeyChainGroup kcg = KeyChainGroup.builder(UNITTEST).lookaheadSize(4).lookaheadThreshold(2)
KeyChainGroup kcg = KeyChainGroup.builder(UNITTEST.network()).lookaheadSize(4).lookaheadThreshold(2)
.fromRandom(ScriptType.P2PKH).build();
wallet = new Wallet(UNITTEST.network(), kcg);
address = wallet.freshReceiveAddress(ScriptType.P2PKH);