3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-14 11:15:51 +00:00

Split wallet events into single method interfaces

This commit is contained in:
Ross Nicoll 2016-01-31 21:24:40 +00:00 committed by Andreas Schildbach
parent 8841371922
commit aca39ee9de
28 changed files with 753 additions and 244 deletions

View File

@ -43,6 +43,7 @@ import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import static com.google.common.base.Preconditions.*;
import org.bitcoinj.wallet.KeyChainEventListener;
/**
* <p>Runs a set of connections to the P2P network, brings up connections to replace disconnected nodes and manages
@ -166,15 +167,19 @@ public class PeerGroup implements TransactionBroadcaster {
};
private int minBroadcastConnections = 0;
private final WalletEventListener walletEventListener = new AbstractWalletEventListener() {
private final ScriptsChangeEventListener walletScriptEventListener = new ScriptsChangeEventListener() {
@Override public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
}
};
private final KeyChainEventListener walletKeyEventListener = new KeyChainEventListener() {
@Override public void onKeysAdded(List<ECKey> keys) {
recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
}
};
private final WalletCoinsReceivedEventListener walletCoinsReceivedEventListener = new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
// We received a relevant transaction. We MAY need to recalculate and resend the Bloom filter, but only
@ -1084,7 +1089,9 @@ public class PeerGroup implements TransactionBroadcaster {
checkState(!wallets.contains(wallet));
wallets.add(wallet);
wallet.setTransactionBroadcaster(this);
wallet.addEventListener(walletEventListener, Threading.SAME_THREAD);
wallet.addCoinsReceivedEventListener(Threading.SAME_THREAD, walletCoinsReceivedEventListener);
wallet.addKeyChainEventListener(Threading.SAME_THREAD, walletKeyEventListener);
wallet.addScriptChangeEventListener(Threading.SAME_THREAD, walletScriptEventListener);
addPeerFilterProvider(wallet);
for (Peer peer : peers) {
peer.addWallet(wallet);
@ -1154,7 +1161,9 @@ public class PeerGroup implements TransactionBroadcaster {
public void removeWallet(Wallet wallet) {
wallets.remove(checkNotNull(wallet));
peerFilterProviders.remove(wallet);
wallet.removeEventListener(walletEventListener);
wallet.removeCoinsReceivedEventListener(walletCoinsReceivedEventListener);
wallet.removeKeyChainEventListener(walletKeyEventListener);
wallet.removeScriptChangeEventListener(walletScriptEventListener);
wallet.setTransactionBroadcaster(null);
for (Peer peer : peers) {
peer.removeWallet(wallet);

View File

@ -25,12 +25,7 @@ import com.google.common.util.concurrent.*;
import com.google.protobuf.*;
import net.jcip.annotations.*;
import org.bitcoin.protocols.payments.Protos.*;
import org.bitcoinj.core.listeners.NewBestBlockListener;
import org.bitcoinj.core.listeners.ReorganizeListener;
import org.bitcoinj.core.listeners.TransactionReceivedInBlockListener;
import org.bitcoinj.core.listeners.WalletEventListener;
import org.bitcoinj.core.listeners.WalletChangeEventListener;
import org.bitcoinj.core.listeners.WalletCoinEventListener;
import org.bitcoinj.core.listeners.*;
import org.bitcoinj.core.TransactionConfidence.*;
import org.bitcoinj.crypto.*;
import org.bitcoinj.script.*;
@ -160,8 +155,18 @@ public class Wallet extends BaseTaggableObject
private int lastBlockSeenHeight;
private long lastBlockSeenTimeSecs;
private CopyOnWriteArrayList<ListenerRegistration<WalletChangeEventListener>> changeListeners;
private CopyOnWriteArrayList<ListenerRegistration<WalletCoinEventListener>> coinListeners;
private final CopyOnWriteArrayList<ListenerRegistration<WalletChangeEventListener>> changeListeners
= new CopyOnWriteArrayList<ListenerRegistration<WalletChangeEventListener>>();
private final CopyOnWriteArrayList<ListenerRegistration<WalletCoinsReceivedEventListener>> coinsReceivedListeners
= new CopyOnWriteArrayList<ListenerRegistration<WalletCoinsReceivedEventListener>>();
private final CopyOnWriteArrayList<ListenerRegistration<WalletCoinsSentEventListener>> coinsSentListeners
= new CopyOnWriteArrayList<ListenerRegistration<WalletCoinsSentEventListener>>();
private final CopyOnWriteArrayList<ListenerRegistration<WalletReorganizeEventListener>> reorganizeListeners
= new CopyOnWriteArrayList<ListenerRegistration<WalletReorganizeEventListener>>();
private final CopyOnWriteArrayList<ListenerRegistration<ScriptsChangeEventListener>> scriptChangeListeners
= new CopyOnWriteArrayList<ListenerRegistration<ScriptsChangeEventListener>>();
private final CopyOnWriteArrayList<ListenerRegistration<TransactionConfidenceEventListener>> transactionConfidenceListeners
= new CopyOnWriteArrayList<ListenerRegistration<TransactionConfidenceEventListener>>();
// A listener that relays confidence changes from the transaction confidence object to the wallet event listener,
// as a convenience to API users so they don't have to register on every transaction themselves.
@ -281,8 +286,6 @@ public class Wallet extends BaseTaggableObject
pending = new HashMap<Sha256Hash, Transaction>();
dead = new HashMap<Sha256Hash, Transaction>();
transactions = new HashMap<Sha256Hash, Transaction>();
changeListeners = new CopyOnWriteArrayList<ListenerRegistration<WalletChangeEventListener>>();
coinListeners = new CopyOnWriteArrayList<ListenerRegistration<WalletCoinEventListener>>();
extensions = new HashMap<String, WalletExtension>();
// Use a linked hash map to ensure ordering of event listeners is correct.
confidenceChanged = new LinkedHashMap<Transaction, TransactionConfidence.Listener.ChangeReason>();
@ -2435,7 +2438,24 @@ public class Wallet extends BaseTaggableObject
*/
public void addEventListener(WalletEventListener listener) {
addChangeEventListener(Threading.USER_THREAD, listener);
addCoinEventListener(Threading.USER_THREAD, listener);
addCoinsReceivedEventListener(Threading.USER_THREAD, listener);
addCoinsSentEventListener(Threading.USER_THREAD, listener);
addKeyChainEventListener(Threading.USER_THREAD, listener);
addReorganizeEventListener(Threading.USER_THREAD, listener);
addScriptChangeEventListener(Threading.USER_THREAD, listener);
addTransactionConfidenceEventListener(Threading.USER_THREAD, listener);
}
/** Use the more specific listener methods instead */
@Deprecated
public void addEventListener(WalletEventListener listener, Executor executor) {
addCoinsReceivedEventListener(executor, listener);
addCoinsSentEventListener(executor, listener);
addChangeEventListener(executor, listener);
addKeyChainEventListener(executor, listener);
addReorganizeEventListener(executor, listener);
addScriptChangeEventListener(executor, listener);
addTransactionConfidenceEventListener(executor, listener);
}
/**
@ -2446,14 +2466,6 @@ public class Wallet extends BaseTaggableObject
addChangeEventListener(Threading.USER_THREAD, listener);
}
/**
* 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.
*/
public void addCoinEventListener(WalletCoinEventListener listener) {
addCoinEventListener(Threading.USER_THREAD, listener);
}
/**
* Adds an event listener object. Methods on this object are called when something interesting happens,
* like receiving money. The listener is executed by the given executor.
@ -2461,32 +2473,122 @@ public class Wallet extends BaseTaggableObject
public void addChangeEventListener(Executor executor, WalletChangeEventListener listener) {
// This is thread safe, so we don't need to take the lock.
changeListeners.add(new ListenerRegistration<WalletChangeEventListener>(listener, executor));
}
/**
* Adds an event listener object called when coins are received.
* Runs the listener methods in the user thread.
*/
public void addCoinsReceivedEventListener(WalletCoinsReceivedEventListener listener) {
addCoinsReceivedEventListener(Threading.USER_THREAD, listener);
}
/**
* Adds an event listener object called when coins are received.
* The listener is executed by the given executor.
*/
public void addCoinsReceivedEventListener(Executor executor, WalletCoinsReceivedEventListener listener) {
// This is thread safe, so we don't need to take the lock.
coinsReceivedListeners.add(new ListenerRegistration<WalletCoinsReceivedEventListener>(listener, executor));
}
/**
* Adds an event listener object called when coins are sent.
* Runs the listener methods in the user thread.
*/
public void addCoinsSentEventListener(WalletCoinsSentEventListener listener) {
addCoinsSentEventListener(Threading.USER_THREAD, listener);
}
/**
* Adds an event listener object called when coins are sent.
* The listener is executed by the given executor.
*/
public void addCoinsSentEventListener(Executor executor, WalletCoinsSentEventListener listener) {
// This is thread safe, so we don't need to take the lock.
coinsSentListeners.add(new ListenerRegistration<WalletCoinsSentEventListener>(listener, executor));
}
/**
* Adds an event listener object. Methods on this object are called when keys are
* added. The listener is executed in the user thread.
*/
public void addKeyChainEventListener(KeyChainEventListener listener) {
keyChainGroup.addEventListener(listener, Threading.USER_THREAD);
}
/**
* Adds an event listener object. Methods on this object are called when keys are
* added. The listener is executed by the given executor.
*/
public void addKeyChainEventListener(Executor executor, KeyChainEventListener listener) {
keyChainGroup.addEventListener(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.
*/
public void addReorganizeEventListener(WalletReorganizeEventListener listener) {
addReorganizeEventListener(Threading.USER_THREAD, listener);
}
/**
* Adds an event listener object. Methods on this object are called when something interesting happens,
* like receiving money. The listener is executed by the given executor.
*/
public void addCoinEventListener(Executor executor, WalletCoinEventListener listener) {
public void addReorganizeEventListener(Executor executor, WalletReorganizeEventListener listener) {
// This is thread safe, so we don't need to take the lock.
coinListeners.add(new ListenerRegistration<WalletCoinEventListener>(listener, executor));
reorganizeListeners.add(new ListenerRegistration<WalletReorganizeEventListener>(listener, executor));
}
/** Use the more specific listener methods instead */
@Deprecated
public void addEventListener(WalletEventListener listener, Executor executor) {
addCoinEventListener(executor, listener);
addChangeEventListener(executor, listener);
/**
* Adds an event listener object. Methods on this object are called when scripts
* watched by this wallet change. Runs the listener methods in the user thread.
*/
public void addScriptsChangeEventListener(ScriptsChangeEventListener listener) {
addScriptChangeEventListener(Threading.USER_THREAD, listener);
}
/**
* Adds an event listener object. Methods on this object are called when scripts
* watched by this wallet change. The listener is executed by the given executor.
*/
public void addScriptChangeEventListener(Executor executor, ScriptsChangeEventListener listener) {
// This is thread safe, so we don't need to take the lock.
scriptChangeListeners.add(new ListenerRegistration<ScriptsChangeEventListener>(listener, executor));
}
/**
* Adds an event listener object. Methods on this object are called when confidence
* of a transaction changes. Runs the listener methods in the user thread.
*/
public void addTransactionConfidenceEventListener(TransactionConfidenceEventListener listener) {
addTransactionConfidenceEventListener(Threading.USER_THREAD, listener);
}
/**
* Adds an event listener object. Methods on this object are called when confidence
* of a transaction changes. The listener is executed by the given executor.
*/
public void addTransactionConfidenceEventListener(Executor executor, TransactionConfidenceEventListener listener) {
// This is thread safe, so we don't need to take the lock.
transactionConfidenceListeners.add(new ListenerRegistration<TransactionConfidenceEventListener>(listener, executor));
}
/**
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
* was never added.
* @deprecated use the fine-grain event listeners instead.
*/
@Deprecated
public boolean removeEventListener(WalletEventListener listener) {
return removeChangeEventListener(listener) ||
removeCoinEventListener(listener);
removeCoinsReceivedEventListener(listener) ||
removeCoinsSentEventListener(listener) ||
removeKeyChainEventListener(listener) ||
removeReorganizeEventListener(listener) ||
removeTransactionConfidenceEventListener(listener);
}
/**
@ -2494,7 +2596,6 @@ public class Wallet extends BaseTaggableObject
* was never added.
*/
public boolean removeChangeEventListener(WalletChangeEventListener listener) {
keyChainGroup.removeEventListener(listener);
return ListenerRegistration.removeFromList(listener, changeListeners);
}
@ -2502,13 +2603,53 @@ public class Wallet extends BaseTaggableObject
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
* was never added.
*/
public boolean removeCoinEventListener(WalletCoinEventListener listener) {
return ListenerRegistration.removeFromList(listener, coinListeners);
public boolean removeCoinsReceivedEventListener(WalletCoinsReceivedEventListener listener) {
return ListenerRegistration.removeFromList(listener, coinsReceivedListeners);
}
/**
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
* was never added.
*/
public boolean removeCoinsSentEventListener(WalletCoinsSentEventListener listener) {
return ListenerRegistration.removeFromList(listener, coinsSentListeners);
}
/**
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
* was never added.
*/
public boolean removeKeyChainEventListener(KeyChainEventListener listener) {
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 removeReorganizeEventListener(WalletReorganizeEventListener listener) {
return ListenerRegistration.removeFromList(listener, reorganizeListeners);
}
/**
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
* was never added.
*/
public boolean removeScriptChangeEventListener(ScriptsChangeEventListener listener) {
return ListenerRegistration.removeFromList(listener, scriptChangeListeners);
}
/**
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
* was never added.
*/
public boolean removeTransactionConfidenceEventListener(TransactionConfidenceEventListener listener) {
return ListenerRegistration.removeFromList(listener, transactionConfidenceListeners);
}
private void queueOnTransactionConfidenceChanged(final Transaction tx) {
checkState(lock.isHeldByCurrentThread());
for (final ListenerRegistration<WalletChangeEventListener> registration : changeListeners) {
for (final ListenerRegistration<TransactionConfidenceEventListener> registration : transactionConfidenceListeners) {
if (registration.executor == Threading.SAME_THREAD) {
registration.listener.onTransactionConfidenceChanged(this, tx);
} else {
@ -2540,7 +2681,7 @@ public class Wallet extends BaseTaggableObject
protected void queueOnCoinsReceived(final Transaction tx, final Coin balance, final Coin newBalance) {
checkState(lock.isHeldByCurrentThread());
for (final ListenerRegistration<WalletCoinEventListener> registration : coinListeners) {
for (final ListenerRegistration<WalletCoinsReceivedEventListener> registration : coinsReceivedListeners) {
registration.executor.execute(new Runnable() {
@Override
public void run() {
@ -2552,7 +2693,7 @@ public class Wallet extends BaseTaggableObject
protected void queueOnCoinsSent(final Transaction tx, final Coin prevBalance, final Coin newBalance) {
checkState(lock.isHeldByCurrentThread());
for (final ListenerRegistration<WalletCoinEventListener> registration : coinListeners) {
for (final ListenerRegistration<WalletCoinsSentEventListener> registration : coinsSentListeners) {
registration.executor.execute(new Runnable() {
@Override
public void run() {
@ -2565,7 +2706,7 @@ public class Wallet extends BaseTaggableObject
protected void queueOnReorganize() {
checkState(lock.isHeldByCurrentThread());
checkState(insideReorg);
for (final ListenerRegistration<WalletChangeEventListener> registration : changeListeners) {
for (final ListenerRegistration<WalletReorganizeEventListener> registration : reorganizeListeners) {
registration.executor.execute(new Runnable() {
@Override
public void run() {
@ -2576,7 +2717,7 @@ public class Wallet extends BaseTaggableObject
}
protected void queueOnScriptsChanged(final List<Script> scripts, final boolean isAddingScripts) {
for (final ListenerRegistration<WalletChangeEventListener> registration : changeListeners) {
for (final ListenerRegistration<ScriptsChangeEventListener> registration : scriptChangeListeners) {
registration.executor.execute(new Runnable() {
@Override
public void run() {

View File

@ -65,6 +65,9 @@ public abstract class AbstractWalletEventListener extends AbstractKeyChainEventL
onChange();
}
/**
* Default method called on change events.
*/
public void onChange() {
}
}

View File

@ -0,0 +1,35 @@
/**
* Copyright 2013 Google Inc.
*
* 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.core.listeners;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.script.Script;
import java.util.List;
/**
* <p>Implementors are called when the contents of the wallet changes, for instance due to receiving/sending money
* or a block chain re-organize. It may be convenient to derive from {@link AbstractWalletEventListener} instead.</p>
*/
public interface ScriptsChangeEventListener {
/**
* Called whenever a new watched script is added to the wallet.
*
* @param isAddingScripts will be true if added scripts, false if removed scripts.
*/
void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts);
}

View File

@ -0,0 +1,50 @@
/**
* Copyright 2013 Google Inc.
*
* 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.core.listeners;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Wallet;
/**
* <p>Implementors are called when confidence of a transaction changes.</p>
*/
public interface TransactionConfidenceEventListener {
/**
* <p>Called when a transaction changes its confidence level. You can also attach event listeners to
* the individual transactions, if you don't care about all of them. Usually you would save the wallet to disk after
* receiving this callback unless you already set up autosaving.</p>
*
* <p>You should pay attention to this callback in case a transaction becomes <i>dead</i>, that is, a transaction
* you believed to be active (send or receive) becomes overridden by the network. This can happen if</p>
*
* <ol>
* <li>You are sharing keys between wallets and accidentally create/broadcast a double spend.</li>
* <li>Somebody is attacking the network and reversing transactions, ie, the user is a victim of fraud.</li>
* <li>A bug: for example you create a transaction, broadcast it but fail to commit it. The {@link Wallet}
* will then re-use the same outputs when creating the next spend.</li>
* </ol><p>
*
* <p>To find if the transaction is dead, you can use <tt>tx.getConfidence().getConfidenceType() ==
* TransactionConfidence.ConfidenceType.DEAD</tt>. If it is, you should notify the user
* in some way so they know the thing they bought may not arrive/the thing they sold should not be dispatched.</p>
*
* <p>Note that this callback will be invoked for every transaction in the wallet, for every new block that is
* received (because the depth has changed). <b>If you want to update a UI view from the contents of the wallet
* it is more efficient to use onWalletChanged instead.</b></p>
*/
void onTransactionConfidenceChanged(Wallet wallet, Transaction tx);
}

View File

@ -16,56 +16,13 @@
package org.bitcoinj.core.listeners;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.script.Script;
import org.bitcoinj.wallet.KeyChainEventListener;
import java.util.List;
/**
* <p>Implementors are called when the contents of the wallet changes, for instance due to receiving/sending money
* or a block chain re-organize. It may be convenient to derive from {@link AbstractWalletEventListener} instead.</p>
*/
public interface WalletChangeEventListener extends KeyChainEventListener {
// TODO: Finish onReorganize to be more useful.
/**
* <p>This is called when a block is received that triggers a block chain re-organization.</p>
*
* <p>A re-organize means that the consensus (chain) of the network has diverged and now changed from what we
* believed it was previously. Usually this won't matter because the new consensus will include all our old
* transactions assuming we are playing by the rules. However it's theoretically possible for our balance to
* change in arbitrary ways, most likely, we could lose some money we thought we had.</p>
*
* <p>It is safe to use methods of wallet whilst inside this callback.</p>
*/
void onReorganize(Wallet wallet);
/**
* <p>Called when a transaction changes its confidence level. You can also attach event listeners to
* the individual transactions, if you don't care about all of them. Usually you would save the wallet to disk after
* receiving this callback unless you already set up autosaving.</p>
*
* <p>You should pay attention to this callback in case a transaction becomes <i>dead</i>, that is, a transaction
* you believed to be active (send or receive) becomes overridden by the network. This can happen if</p>
*
* <ol>
* <li>You are sharing keys between wallets and accidentally create/broadcast a double spend.</li>
* <li>Somebody is attacking the network and reversing transactions, ie, the user is a victim of fraud.</li>
* <li>A bug: for example you create a transaction, broadcast it but fail to commit it. The {@link Wallet}
* will then re-use the same outputs when creating the next spend.</li>
* </ol><p>
*
* <p>To find if the transaction is dead, you can use <tt>tx.getConfidence().getConfidenceType() ==
* TransactionConfidence.ConfidenceType.DEAD</tt>. If it is, you should notify the user
* in some way so they know the thing they bought may not arrive/the thing they sold should not be dispatched.</p>
*
* <p>Note that this callback will be invoked for every transaction in the wallet, for every new block that is
* received (because the depth has changed). <b>If you want to update a UI view from the contents of the wallet
* it is more efficient to use onWalletChanged instead.</b></p>
*/
void onTransactionConfidenceChanged(Wallet wallet, Transaction tx);
public interface WalletChangeEventListener {
/**
* <p>Designed for GUI applications to refresh their transaction lists. This callback is invoked in the following
* situations:</p>
@ -85,11 +42,4 @@ public interface WalletChangeEventListener extends KeyChainEventListener {
* rather than one per transaction per block. Note that this is <b>not</b> called when a key is added. </p>
*/
void onWalletChanged(Wallet wallet);
/**
* Called whenever a new watched script is added to the wallet.
*
* @param isAddingScripts will be true if added scripts, false if removed scripts.
*/
void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts);
}

View File

@ -0,0 +1,42 @@
/**
* Copyright 2013 Google Inc.
*
* 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.core.listeners;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Wallet;
/**
* <p>Implementors are called when the contents of the wallet changes, for instance due to receiving/sending money
* or a block chain re-organize. It may be convenient to derive from {@link AbstractWalletEventListener} instead.</p>
*/
public interface WalletCoinsReceivedEventListener {
/**
* This is called when a transaction is seen that sends coins <b>to</b> this wallet, either because it
* was broadcast across the network or because a block was received. If a transaction is seen when it was broadcast,
* onCoinsReceived won't be called again when a block containing it is received. If you want to know when such a
* transaction receives its first confirmation, register a {@link TransactionConfidence} event listener using
* the object retrieved via {@link org.bitcoinj.core.Transaction#getConfidence()}. It's safe to modify the
* wallet in this callback, for example, by spending the transaction just received.
*
* @param wallet The wallet object that received the coins
* @param tx The transaction which sent us the coins.
* @param prevBalance Balance before the coins were received.
* @param newBalance Current balance of the wallet. This is the 'estimated' balance.
*/
void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
}

View File

@ -19,30 +19,12 @@ package org.bitcoinj.core.listeners;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.script.Script;
import org.bitcoinj.wallet.KeyChainEventListener;
import java.util.List;
/**
* <p>Implementors are called when the contents of the wallet changes, for instance due to receiving/sending money
* or a block chain re-organize. It may be convenient to derive from {@link AbstractWalletEventListener} instead.</p>
*/
public interface WalletCoinEventListener {
/**
* This is called when a transaction is seen that sends coins <b>to</b> this wallet, either because it
* was broadcast across the network or because a block was received. If a transaction is seen when it was broadcast,
* onCoinsReceived won't be called again when a block containing it is received. If you want to know when such a
* transaction receives its first confirmation, register a {@link TransactionConfidence} event listener using
* the object retrieved via {@link org.bitcoinj.core.Transaction#getConfidence()}. It's safe to modify the
* wallet in this callback, for example, by spending the transaction just received.
*
* @param wallet The wallet object that received the coins
* @param tx The transaction which sent us the coins.
* @param prevBalance Balance before the coins were received.
* @param newBalance Current balance of the wallet. This is the 'estimated' balance.
*/
void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
public interface WalletCoinsSentEventListener {
/**
* This is called when a transaction is seen that sends coins <b>from</b> this wallet, either

View File

@ -16,9 +16,16 @@
package org.bitcoinj.core.listeners;
import org.bitcoinj.wallet.KeyChainEventListener;
/**
* <p>Common interface for wallet changes and transactions. For fine-grain
* events please use the super-interfaces.</p>
* <p>Common interface for wallet changes and transactions.</p>
* @deprecated Use the superinterfaces directly instead.
*/
public interface WalletEventListener extends WalletChangeEventListener, WalletCoinEventListener {
@Deprecated
public interface WalletEventListener extends
KeyChainEventListener, WalletChangeEventListener,
WalletCoinsReceivedEventListener, WalletCoinsSentEventListener,
WalletReorganizeEventListener, ScriptsChangeEventListener,
TransactionConfidenceEventListener {
}

View File

@ -0,0 +1,38 @@
/**
* Copyright 2013 Google Inc.
*
* 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.core.listeners;
import org.bitcoinj.core.Wallet;
/**
* <p>Implementors are called when the wallet is reorganized.</p>
*/
public interface WalletReorganizeEventListener {
// TODO: Finish onReorganize to be more useful.
/**
* <p>This is called when a block is received that triggers a block chain re-organization.</p>
*
* <p>A re-organize means that the consensus (chain) of the network has diverged and now changed from what we
* believed it was previously. Usually this won't matter because the new consensus will include all our old
* transactions assuming we are playing by the rules. However it's theoretically possible for our balance to
* change in arbitrary ways, most likely, we could lose some money we thought we had.</p>
*
* <p>It is safe to use methods of wallet whilst inside this callback.</p>
*/
void onReorganize(Wallet wallet);
}

View File

@ -0,0 +1,34 @@
/**
* Copyright 2013 Google Inc.
*
* 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.jni;
import org.bitcoinj.wallet.KeyChainEventListener;
import org.bitcoinj.core.ECKey;
import java.util.List;
/**
* An event listener that relays events to a native C++ object. A pointer to that object is stored in
* this class using JNI on the native side, thus several instances of this can point to different actual
* native implementations.
*/
public class NativeKeyChainEventListener implements KeyChainEventListener {
public long ptr;
@Override
public native void onKeysAdded(List<ECKey> keys);
}

View File

@ -0,0 +1,35 @@
/**
* Copyright 2013 Google Inc.
*
* 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.jni;
import org.bitcoinj.core.listeners.ScriptsChangeEventListener;
import org.bitcoinj.core.Wallet;
import org.bitcoinj.script.Script;
import java.util.List;
/**
* An event listener that relays events to a native C++ object. A pointer to that object is stored in
* this class using JNI on the native side, thus several instances of this can point to different actual
* native implementations.
*/
public class NativeScriptsChangeEventListener implements ScriptsChangeEventListener {
public long ptr;
@Override
public native void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts);
}

View File

@ -0,0 +1,33 @@
/**
* Copyright 2013 Google Inc.
*
* 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.jni;
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Wallet;
/**
* An event listener that relays events to a native C++ object. A pointer to that object is stored in
* this class using JNI on the native side, thus several instances of this can point to different actual
* native implementations.
*/
public class NativeTransactionConfidenceEventListener implements TransactionConfidenceEventListener {
public long ptr;
@Override
public native void onTransactionConfidenceChanged(Wallet wallet, Transaction tx);
}

View File

@ -0,0 +1,32 @@
/**
* Copyright 2013 Google Inc.
*
* 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.jni;
import org.bitcoinj.core.listeners.WalletChangeEventListener;
import org.bitcoinj.core.Wallet;
/**
* An event listener that relays events to a native C++ object. A pointer to that object is stored in
* this class using JNI on the native side, thus several instances of this can point to different actual
* native implementations.
*/
public class NativeWalletChangeEventListener implements WalletChangeEventListener {
public long ptr;
@Override
public native void onWalletChanged(Wallet wallet);
}

View File

@ -0,0 +1,34 @@
/**
* Copyright 2013 Google Inc.
*
* 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.jni;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Wallet;
/**
* An event listener that relays events to a native C++ object. A pointer to that object is stored in
* this class using JNI on the native side, thus several instances of this can point to different actual
* native implementations.
*/
public class NativeWalletCoinsReceivedEventListener implements WalletCoinsReceivedEventListener {
public long ptr;
@Override
public native void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
}

View File

@ -0,0 +1,34 @@
/**
* Copyright 2013 Google Inc.
*
* 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.jni;
import org.bitcoinj.core.listeners.WalletCoinsSentEventListener;
import org.bitcoinj.core.Coin;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.Wallet;
/**
* An event listener that relays events to a native C++ object. A pointer to that object is stored in
* this class using JNI on the native side, thus several instances of this can point to different actual
* native implementations.
*/
public class NativeWalletCoinsSentEventListener implements WalletCoinsSentEventListener {
public long ptr;
@Override
public native void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
}

View File

@ -0,0 +1,32 @@
/**
* Copyright 2013 Google Inc.
*
* 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.jni;
import org.bitcoinj.core.listeners.WalletReorganizeEventListener;
import org.bitcoinj.core.Wallet;
/**
* An event listener that relays events to a native C++ object. A pointer to that object is stored in
* this class using JNI on the native side, thus several instances of this can point to different actual
* native implementations.
*/
public class NativeWalletReorganizeEventListener implements WalletReorganizeEventListener {
public long ptr;
@Override
public native void onReorganize(Wallet wallet);
}

View File

@ -16,7 +16,6 @@
package org.bitcoinj.protocols.channels;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.*;
import org.bitcoinj.crypto.TransactionSignature;
import org.bitcoinj.script.Script;
@ -37,6 +36,7 @@ import javax.annotation.Nullable;
import java.util.List;
import static com.google.common.base.Preconditions.*;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
/**
* <p>A payment channel is a method of sending money to someone such that the amount of money you send can be adjusted
@ -173,7 +173,7 @@ public class PaymentChannelClientState {
if (storedChannel != null && storedChannel.close != null) {
watchCloseConfirmations();
}
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(Threading.SAME_THREAD, new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
synchronized (PaymentChannelClientState.this) {
@ -189,7 +189,7 @@ public class PaymentChannelClientState {
}
}
}
}, Threading.SAME_THREAD);
});
}
private void watchCloseConfirmations() {

View File

@ -17,7 +17,10 @@
package org.bitcoinj.core;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.listeners.WalletChangeEventListener;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.core.listeners.WalletReorganizeEventListener;
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
import org.bitcoinj.params.UnitTestParams;
import org.bitcoinj.store.MemoryBlockStore;
@ -76,11 +79,13 @@ public class ChainSplitTest {
// (receiving coins). Checking that we understand reversed spends is in testForking2.
final AtomicBoolean reorgHappened = new AtomicBoolean();
final AtomicInteger walletChanged = new AtomicInteger();
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addReorganizeEventListener(new WalletReorganizeEventListener() {
@Override
public void onReorganize(Wallet wallet) {
reorgHappened.set(true);
}
});
wallet.addChangeEventListener(new WalletChangeEventListener() {
@Override
public void onWalletChanged(Wallet wallet) {
@ -297,10 +302,9 @@ public class ChainSplitTest {
// double spend on the new best chain.
final boolean[] eventCalled = new boolean[1];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
super.onTransactionConfidenceChanged(wallet, tx);
if (tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.DEAD)
eventCalled[0] = true;
}
@ -338,7 +342,7 @@ public class ChainSplitTest {
// double spend on the new best chain.
final Transaction[] eventDead = new Transaction[1];
final Transaction[] eventReplacement = new Transaction[1];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
if (tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.DEAD) {
@ -400,7 +404,7 @@ public class ChainSplitTest {
// Check that as the chain forks and re-orgs, the confidence data associated with each transaction is
// maintained correctly.
final ArrayList<Transaction> txns = new ArrayList<Transaction>(3);
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
txns.add(tx);
@ -558,12 +562,12 @@ public class ChainSplitTest {
// transactions would be. Also check that a dead coinbase on a sidechain is resurrected if the sidechain
// becomes the best chain once more. Finally, check that dependent transactions are killed recursively.
final ArrayList<Transaction> txns = new ArrayList<Transaction>(3);
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(Threading.SAME_THREAD, new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
txns.add(tx);
}
}, Threading.SAME_THREAD);
});
Block b1 = unitTestParams.getGenesisBlock().createNextBlock(someOtherGuy);
final ECKey coinsTo2 = wallet.freshReceiveKey();

View File

@ -527,7 +527,7 @@ public class PeerTest extends TestWithNetworkConnections {
// Check that if we request dependency download to be disabled and receive a relevant tx, things work correctly.
Transaction tx = FakeTxBuilder.createFakeTx(params, COIN, address);
final Transaction[] result = new Transaction[1];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
result[0] = tx;
@ -644,7 +644,7 @@ public class PeerTest extends TestWithNetworkConnections {
ECKey key = wallet.freshReceiveKey();
peer.addWallet(wallet);
final Transaction[] vtx = new Transaction[1];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
vtx[0] = tx;
@ -696,7 +696,7 @@ public class PeerTest extends TestWithNetworkConnections {
wallet.setAcceptRiskyTransactions(shouldAccept);
peer.addWallet(wallet);
final Transaction[] vtx = new Transaction[1];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
vtx[0] = tx;
@ -775,7 +775,7 @@ public class PeerTest extends TestWithNetworkConnections {
@Test
public void exceptionListener() throws Exception {
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
throw new NullPointerException("boo!");

View File

@ -18,7 +18,7 @@
package org.bitcoinj.core;
import com.google.common.util.concurrent.*;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
import org.bitcoinj.testing.*;
import org.bitcoinj.utils.*;
import org.junit.*;
@ -198,7 +198,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
// Check that the wallet informs us of changes in confidence as the transaction ripples across the network.
final Transaction[] transactions = new Transaction[1];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
transactions[0] = tx;

View File

@ -17,8 +17,10 @@
package org.bitcoinj.core;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.listeners.WalletCoinEventListener;
import org.bitcoinj.core.listeners.WalletChangeEventListener;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.core.listeners.WalletCoinsSentEventListener;
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
import org.bitcoinj.core.Wallet.SendRequest;
import org.bitcoinj.crypto.*;
@ -412,16 +414,11 @@ public class WalletTest extends TestWithWallet {
private static void broadcastAndCommit(Wallet wallet, Transaction t) throws Exception {
final LinkedList<Transaction> txns = Lists.newLinkedList();
wallet.addCoinEventListener(new WalletCoinEventListener() {
wallet.addCoinsSentEventListener(new WalletCoinsSentEventListener() {
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
txns.add(tx);
}
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
// Ignore
}
});
t.getConfidence().markBroadcastBy(new PeerAddress(params, InetAddress.getByAddress(new byte[]{1,2,3,4})));
@ -559,26 +556,27 @@ public class WalletTest extends TestWithWallet {
final Coin[] bigints = new Coin[4];
final Transaction[] txn = new Transaction[2];
final LinkedList<Transaction> confTxns = new LinkedList<Transaction>();
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
super.onCoinsReceived(wallet, tx, prevBalance, newBalance);
bigints[0] = prevBalance;
bigints[1] = newBalance;
txn[0] = tx;
}
});
wallet.addCoinsSentEventListener(new WalletCoinsSentEventListener() {
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
super.onCoinsSent(wallet, tx, prevBalance, newBalance);
bigints[2] = prevBalance;
bigints[3] = newBalance;
txn[1] = tx;
}
});
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
super.onTransactionConfidenceChanged(wallet, tx);
confTxns.add(tx);
}
});
@ -813,17 +811,18 @@ public class WalletTest extends TestWithWallet {
final Transaction[] eventDead = new Transaction[1];
final Transaction[] eventReplacement = new Transaction[1];
final int[] eventWalletChanged = new int[1];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
super.onTransactionConfidenceChanged(wallet, tx);
if (tx.getConfidence().getConfidenceType() ==
TransactionConfidence.ConfidenceType.DEAD) {
eventDead[0] = tx;
eventReplacement[0] = tx.getConfidence().getOverridingTransaction();
}
}
});
wallet.addChangeEventListener(new WalletChangeEventListener() {
@Override
public void onWalletChanged(Wallet wallet) {
eventWalletChanged[0]++;
@ -1277,7 +1276,7 @@ public class WalletTest extends TestWithWallet {
final boolean[] flags = new boolean[2];
final Transaction[] notifiedTx = new Transaction[1];
final int[] walletChanged = new int[1];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
// Check we got the expected transaction.
@ -1289,7 +1288,9 @@ public class WalletTest extends TestWithWallet {
flags[1] = tx.isPending();
notifiedTx[0] = tx;
}
});
wallet.addChangeEventListener(new WalletChangeEventListener() {
@Override
public void onWalletChanged(Wallet wallet) {
walletChanged[0]++;
@ -1345,18 +1346,13 @@ public class WalletTest extends TestWithWallet {
// Check that if we receive a pending tx we did not send, it updates our spent flags correctly.
final Transaction[] txn = new Transaction[1];
final Coin[] bigints = new Coin[2];
wallet.addCoinEventListener(new WalletCoinEventListener() {
wallet.addCoinsSentEventListener(new WalletCoinsSentEventListener() {
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
txn[0] = tx;
bigints[0] = prevBalance;
bigints[1] = newBalance;
}
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
// Do nothing
}
});
// Receive some coins.
Coin nanos = COIN;
@ -1399,15 +1395,16 @@ public class WalletTest extends TestWithWallet {
t2.addInput(doubleSpentOut);
final Transaction[] called = new Transaction[2];
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
called[0] = tx;
}
});
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
super.onTransactionConfidenceChanged(wallet, tx);
if (tx.getConfidence().getConfidenceType() ==
TransactionConfidence.ConfidenceType.DEAD) {
called[0] = tx;
@ -2951,30 +2948,20 @@ public class WalletTest extends TestWithWallet {
@Test
public void exceptionsDoNotBlockAllListeners() throws Exception {
// Check that if a wallet listener throws an exception, the others still run.
wallet.addCoinEventListener(new WalletCoinEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
log.info("onCoinsReceived 1");
throw new RuntimeException("barf");
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
// Do nothing
}
});
final AtomicInteger flag = new AtomicInteger();
wallet.addCoinEventListener(new WalletCoinEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
log.info("onCoinsReceived 2");
flag.incrementAndGet();
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
// Do nothing
}
});
sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN);
@ -3419,12 +3406,12 @@ public class WalletTest extends TestWithWallet {
// Check that we can register an event listener, generate some keys and the callbacks are invoked properly.
wallet = new Wallet(params);
final List<ECKey> keys = Lists.newLinkedList();
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addKeyChainEventListener(Threading.SAME_THREAD, new KeyChainEventListener() {
@Override
public void onKeysAdded(List<ECKey> k) {
keys.addAll(k);
}
}, Threading.SAME_THREAD);
});
wallet.freshReceiveKey();
assertEquals(1, keys.size());
}

View File

@ -17,7 +17,7 @@
package org.bitcoinj.store;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.core.*;
import org.bitcoinj.core.Transaction.Purpose;
import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
@ -212,7 +212,7 @@ public class WalletProtobufSerializerTest {
BlockChain chain = new BlockChain(params, myWallet, new MemoryBlockStore(params));
final ArrayList<Transaction> txns = new ArrayList<Transaction>(2);
myWallet.addEventListener(new AbstractWalletEventListener() {
myWallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
txns.add(tx);

View File

@ -17,7 +17,6 @@
package org.bitcoinj.examples;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.*;
import org.bitcoinj.crypto.KeyCrypterException;
import org.bitcoinj.kits.WalletAppKit;
@ -32,6 +31,7 @@ import com.google.common.util.concurrent.MoreExecutors;
import java.io.File;
import static com.google.common.base.Preconditions.checkNotNull;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
/**
* ForwardingService demonstrates basic usage of the library. It sits on the network and when it receives coins, simply
@ -79,7 +79,7 @@ public class ForwardingService {
kit.awaitRunning();
// We want to know when we receive money.
kit.wallet().addEventListener(new AbstractWalletEventListener() {
kit.wallet().addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet w, Transaction tx, Coin prevBalance, Coin newBalance) {
// Runs in the dedicated "user thread" (see bitcoinj docs for more info on this).

View File

@ -14,7 +14,6 @@
package org.bitcoinj.examples;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.*;
import org.bitcoinj.kits.WalletAppKit;
import org.bitcoinj.params.TestNet3Params;
@ -22,6 +21,11 @@ import org.bitcoinj.script.Script;
import java.io.File;
import java.util.List;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.core.listeners.WalletCoinsSentEventListener;
import org.bitcoinj.core.listeners.ScriptsChangeEventListener;
import org.bitcoinj.core.listeners.TransactionConfidenceEventListener;
import org.bitcoinj.wallet.KeyChainEventListener;
/**
* The following example shows how to use the by bitcoinj provided WalletAppKit.
@ -57,9 +61,43 @@ public class Kit {
kit.startAsync();
kit.awaitRunning();
// To observe wallet events (like coins received) we implement a EventListener class that extends the AbstractWalletEventListener bitcoinj then calls the different functions from the EventListener class
WalletListener wListener = new WalletListener();
kit.wallet().addEventListener(wListener);
kit.wallet().addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
System.out.println("-----> coins resceived: " + tx.getHashAsString());
System.out.println("received: " + tx.getValue(wallet));
}
});
kit.wallet().addCoinsSentEventListener(new WalletCoinsSentEventListener() {
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
System.out.println("coins sent");
}
});
kit.wallet().addKeyChainEventListener(new KeyChainEventListener() {
@Override
public void onKeysAdded(List<ECKey> keys) {
System.out.println("new key added");
}
});
kit.wallet().addScriptsChangeEventListener(new ScriptsChangeEventListener() {
@Override
public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
System.out.println("new script added");
}
});
kit.wallet().addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
System.out.println("-----> confidence changed: " + tx.getHashAsString());
TransactionConfidence confidence = tx.getConfidence();
System.out.println("new block depth: " + confidence.getDepthInBlocks());
}
});
// Ready to run. The kit syncs the blockchain and our wallet event listener gets notified when something happens.
// To test everything we create and print a fresh receiving address. Send some coins to that address and see if everything works.
@ -71,44 +109,4 @@ public class Kit {
//kit.awaitTerminated();
}
// The Wallet event listener its implementations get called on wallet changes.
static class WalletListener extends AbstractWalletEventListener {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
System.out.println("-----> coins resceived: " + tx.getHashAsString());
System.out.println("received: " + tx.getValue(wallet));
}
@Override
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
System.out.println("-----> confidence changed: " + tx.getHashAsString());
TransactionConfidence confidence = tx.getConfidence();
System.out.println("new block depth: " + confidence.getDepthInBlocks());
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
System.out.println("coins sent");
}
@Override
public void onReorganize(Wallet wallet) {
}
@Override
public void onWalletChanged(Wallet wallet) {
}
@Override
public void onKeysAdded(List<ECKey> keys) {
System.out.println("new key added");
}
@Override
public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
System.out.println("new script added");
}
}
}

View File

@ -17,13 +17,13 @@
package org.bitcoinj.examples;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.*;
import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.store.BlockStore;
import org.bitcoinj.store.MemoryBlockStore;
import java.io.File;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
/**
* RefreshWallet loads a wallet, then processes the block chain to update the transaction pools within it.
@ -42,7 +42,7 @@ public class RefreshWallet {
final PeerGroup peerGroup = new PeerGroup(params, chain);
peerGroup.startAsync();
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public synchronized void onCoinsReceived(Wallet w, Transaction tx, Coin prevBalance, Coin newBalance) {
System.out.println("\nReceived tx " + tx.getHashAsString());

View File

@ -49,7 +49,6 @@ import joptsimple.OptionSpec;
import joptsimple.util.DateConverter;
import org.bitcoinj.core.listeners.AbstractPeerDataEventListener;
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
import org.bitcoinj.core.listeners.DownloadProgressTracker;
import org.bitcoinj.wallet.MarriedKeyChain;
import org.bitcoinj.wallet.Protos;
@ -78,6 +77,10 @@ import java.util.logging.LogManager;
import static org.bitcoinj.core.Coin.parseCoin;
import static com.google.common.base.Preconditions.checkNotNull;
import org.bitcoinj.core.listeners.WalletChangeEventListener;
import org.bitcoinj.core.listeners.WalletCoinsReceivedEventListener;
import org.bitcoinj.core.listeners.WalletCoinsSentEventListener;
import org.bitcoinj.core.listeners.WalletReorganizeEventListener;
/**
* A command line tool for manipulating wallets and working with Bitcoin.
@ -1109,25 +1112,20 @@ public class WalletTool {
break;
case WALLET_TX:
wallet.addEventListener(new AbstractWalletEventListener() {
private void handleTx(Transaction tx) {
System.out.println(tx.getHashAsString());
latch.countDown(); // Wake up main thread.
}
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
// Runs in a peer thread.
super.onCoinsReceived(wallet, tx, prevBalance, newBalance);
handleTx(tx);
System.out.println(tx.getHashAsString());
latch.countDown(); // Wake up main thread.
}
});
wallet.addCoinsSentEventListener(new WalletCoinsSentEventListener() {
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance,
Coin newBalance) {
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
// Runs in a peer thread.
super.onCoinsSent(wallet, tx, prevBalance, newBalance);
handleTx(tx);
System.out.println(tx.getHashAsString());
latch.countDown(); // Wake up main thread.
}
});
break;
@ -1151,18 +1149,11 @@ public class WalletTool {
latch.countDown();
break;
}
wallet.addEventListener(new AbstractWalletEventListener() {
@Override
public synchronized void onChange() {
super.onChange();
saveWallet(walletFile);
Coin balance = wallet.getBalance(Wallet.BalanceType.ESTIMATED);
if (condition.matchBitcoins(balance)) {
System.out.println(balance.toFriendlyString());
latch.countDown();
}
}
});
final WalletEventListener listener = new WalletEventListener(latch);
wallet.addCoinsReceivedEventListener(listener);
wallet.addCoinsSentEventListener(listener);
wallet.addChangeEventListener(listener);
wallet.addReorganizeEventListener(listener);
break;
}
@ -1474,4 +1465,42 @@ public class WalletTool {
System.out.println("Clearing creation time.");
seed.setCreationTimeSeconds(creationTime);
}
static synchronized void onChange(final CountDownLatch latch) {
saveWallet(walletFile);
Coin balance = wallet.getBalance(Wallet.BalanceType.ESTIMATED);
if (condition.matchBitcoins(balance)) {
System.out.println(balance.toFriendlyString());
latch.countDown();
}
}
private static class WalletEventListener implements WalletChangeEventListener, WalletCoinsReceivedEventListener,
WalletCoinsSentEventListener, WalletReorganizeEventListener {
private final CountDownLatch latch;
private WalletEventListener(final CountDownLatch latch) {
this.latch = latch;
}
@Override
public void onWalletChanged(Wallet wallet) {
onChange(latch);
}
@Override
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
onChange(latch);
}
@Override
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
onChange(latch);
}
@Override
public void onReorganize(Wallet wallet) {
onChange(latch);
}
}
}

View File

@ -10,6 +10,7 @@ import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import java.util.Date;
import org.bitcoinj.core.listeners.WalletChangeEventListener;
/**
* A class that exposes relevant bitcoin stuff as JavaFX bindable properties.
@ -28,13 +29,12 @@ public class BitcoinUIModel {
}
public final void setWallet(Wallet wallet) {
wallet.addEventListener(new AbstractWalletEventListener() {
wallet.addChangeEventListener(Platform::runLater, new WalletChangeEventListener() {
@Override
public void onWalletChanged(Wallet wallet) {
super.onWalletChanged(wallet);
update(wallet);
}
}, Platform::runLater);
});
update(wallet);
}