KeyChainGroup: New CurrentKeyChangeEventListener that fires when a current key and/or address changes.

This also changes wallet-template to make use of the new listener for updating its current address in the UI.
This commit is contained in:
Andreas Schildbach 2019-05-14 21:34:27 +02:00
parent 4d0987930a
commit ab2fb2f9cf
4 changed files with 103 additions and 4 deletions

View File

@ -30,6 +30,7 @@ import org.bitcoinj.crypto.*;
import org.bitcoinj.script.*;
import org.bitcoinj.script.Script.ScriptType;
import org.bitcoinj.utils.*;
import org.bitcoinj.wallet.listeners.CurrentKeyChangeEventListener;
import org.bitcoinj.wallet.listeners.KeyChainEventListener;
import org.slf4j.*;
import org.bouncycastle.crypto.params.*;
@ -194,6 +195,8 @@ public class KeyChainGroup implements KeyBag {
private int lookaheadSize = -1;
private int lookaheadThreshold = -1;
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(NetworkParameters params) {
return new KeyChainGroup(params, new BasicKeyChain(), null, -1, -1, null, null);
@ -274,6 +277,7 @@ public class KeyChainGroup implements KeyBag {
chains.add(chain);
currentKeys.clear();
currentAddresses.clear();
queueOnCurrentKeyChanged();
}
/**
@ -571,6 +575,7 @@ public class KeyChainGroup implements KeyBag {
if (entry.getValue() != null && entry.getValue().equals(address)) {
log.info("Marking P2SH address as used: {}", address);
currentAddresses.put(entry.getKey(), freshAddress(entry.getKey()));
queueOnCurrentKeyChanged();
return;
}
}
@ -584,6 +589,7 @@ public class KeyChainGroup implements KeyBag {
if (entry.getValue() != null && entry.getValue().equals(key)) {
log.info("Marking key as used: {}", key);
currentKeys.put(entry.getKey(), freshKey(entry.getKey()));
queueOnCurrentKeyChanged();
return;
}
}
@ -805,6 +811,37 @@ public class KeyChainGroup implements KeyBag {
return basic.removeEventListener(listener);
}
/** Removes a listener for events that are run when a current key and/or address changes. */
public void addCurrentKeyChangeEventListener(CurrentKeyChangeEventListener listener) {
addCurrentKeyChangeEventListener(listener, Threading.USER_THREAD);
}
/**
* Adds a listener for events that are run when a current key and/or address changes, on the given
* executor.
*/
public void addCurrentKeyChangeEventListener(CurrentKeyChangeEventListener listener, Executor executor) {
checkNotNull(listener);
currentKeyChangeListeners.add(new ListenerRegistration<>(listener, executor));
}
/** Removes a listener for events that are run when a current key and/or address changes. */
public boolean removeCurrentKeyChangeEventListener(CurrentKeyChangeEventListener listener) {
checkNotNull(listener);
return ListenerRegistration.removeFromList(listener, currentKeyChangeListeners);
}
private void queueOnCurrentKeyChanged() {
for (final ListenerRegistration<CurrentKeyChangeEventListener> registration : currentKeyChangeListeners) {
registration.executor.execute(new Runnable() {
@Override
public void run() {
registration.listener.onCurrentKeyChanged();
}
});
}
}
/** Returns a list of key protobufs obtained by merging the chains. */
public List<Protos.Key> serializeToProtobuf() {
List<Protos.Key> result;

View File

@ -62,6 +62,7 @@ import org.bitcoinj.signers.*;
import org.bitcoinj.utils.*;
import org.bitcoinj.wallet.Protos.Wallet.*;
import org.bitcoinj.wallet.WalletTransaction.*;
import org.bitcoinj.wallet.listeners.CurrentKeyChangeEventListener;
import org.bitcoinj.wallet.listeners.KeyChainEventListener;
import org.bitcoinj.wallet.listeners.ScriptsChangeEventListener;
import org.bitcoinj.wallet.listeners.WalletChangeEventListener;
@ -2789,6 +2790,22 @@ public class Wallet extends BaseTaggableObject
keyChainGroup.addEventListener(listener, executor);
}
/**
* Adds an event listener object. Methods on this object are called when a current key and/or address
* changes. The listener is executed in the user thread.
*/
public void addCurrentKeyChangeEventListener(CurrentKeyChangeEventListener listener) {
keyChainGroup.addCurrentKeyChangeEventListener(listener);
}
/**
* Adds an event listener object. Methods on this object are called when a current key and/or address
* changes. The listener is executed by the given executor.
*/
public void addCurrentKeyChangeEventListener(Executor executor, CurrentKeyChangeEventListener listener) {
keyChainGroup.addCurrentKeyChangeEventListener(listener, executor);
}
/**
* Adds an event listener object. Methods on this object are called when something interesting happens,
* like receiving money. Runs the listener methods in the user thread.
@ -2872,6 +2889,14 @@ public class Wallet extends BaseTaggableObject
return keyChainGroup.removeEventListener(listener);
}
/**
* Removes the given event listener object. Returns true if the listener was removed, false if that
* listener was never added.
*/
public boolean removeCurrentKeyChangeEventListener(CurrentKeyChangeEventListener listener) {
return keyChainGroup.removeCurrentKeyChangeEventListener(listener);
}
/**
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
* was never added.

View File

@ -0,0 +1,26 @@
/*
* Copyright by the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.bitcoinj.wallet.listeners;
import org.bitcoinj.wallet.KeyChainGroup;
public interface CurrentKeyChangeEventListener {
/**
* Called by {@link KeyChainGroup} whenever a current key and/or address changes.
*/
void onCurrentKeyChanged();
}

View File

@ -20,6 +20,7 @@ import org.bitcoinj.core.Address;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.listeners.DownloadProgressTracker;
import org.bitcoinj.wallet.Wallet;
import org.bitcoinj.wallet.listeners.CurrentKeyChangeEventListener;
import org.bitcoinj.wallet.listeners.WalletChangeEventListener;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyDoubleProperty;
@ -48,15 +49,25 @@ public class BitcoinUIModel {
public final void setWallet(Wallet wallet) {
wallet.addChangeEventListener(Platform::runLater, new WalletChangeEventListener() {
@Override
public void onWalletChanged(Wallet wallet) {
update(wallet);
public void onWalletChanged(Wallet w) {
updateBalance(wallet);
}
});
update(wallet);
wallet.addCurrentKeyChangeEventListener(Platform::runLater, new CurrentKeyChangeEventListener() {
@Override
public void onCurrentKeyChanged() {
updateAddress(wallet);
}
});
updateBalance(wallet);
updateAddress(wallet);
}
private void update(Wallet wallet) {
private void updateBalance(Wallet wallet) {
balance.set(wallet.getBalance());
}
private void updateAddress(Wallet wallet) {
address.set(wallet.currentReceiveAddress());
}