mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-02-22 22:25:41 +01:00
Refactor listener interfaces.
Refactor listener interfaces into their own package. Split listener interfaces into smaller interfaces. Make abstract implementations actually abstract. Rearrange methods for adding listeners to put executor first.
This commit is contained in:
parent
bd080ac5e4
commit
ecbd021167
50 changed files with 862 additions and 359 deletions
|
@ -17,10 +17,14 @@
|
|||
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import org.bitcoinj.core.listeners.NewBestBlockListener;
|
||||
import org.bitcoinj.core.listeners.ReorganizeListener;
|
||||
import org.bitcoinj.core.listeners.TransactionReceivedInBlockListener;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.bitcoinj.utils.ListenerRegistration;
|
||||
import org.bitcoinj.utils.Threading;
|
||||
import org.bitcoinj.utils.VersionTally;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
|
@ -35,13 +39,12 @@ import java.util.concurrent.Executor;
|
|||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import static com.google.common.base.Preconditions.*;
|
||||
import org.bitcoinj.utils.VersionTally;
|
||||
|
||||
/**
|
||||
* <p>An AbstractBlockChain holds a series of {@link Block} objects, links them together, and knows how to verify that
|
||||
* the chain follows the rules of the {@link NetworkParameters} for this chain.</p>
|
||||
*
|
||||
* <p>It can be connected to a {@link Wallet}, and also {@link BlockChainListener}s that can receive transactions and
|
||||
* <p>It can be connected to a {@link Wallet}, and also {@link TransactionReceivedInBlockListener}s that can receive transactions and
|
||||
* notifications of re-organizations.</p>
|
||||
*
|
||||
* <p>An AbstractBlockChain implementation must be connected to a {@link BlockStore} implementation. The chain object
|
||||
|
@ -105,7 +108,9 @@ public abstract class AbstractBlockChain {
|
|||
private final Object chainHeadLock = new Object();
|
||||
|
||||
protected final NetworkParameters params;
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<BlockChainListener>> listeners;
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<NewBestBlockListener>> newBestBlockListeners;
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<ReorganizeListener>> reorganizeListeners;
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<TransactionReceivedInBlockListener>> transactionReceivedListeners;
|
||||
|
||||
// Holds a block header and, optionally, a list of tx hashes or block's transactions
|
||||
class OrphanBlock {
|
||||
|
@ -140,22 +145,28 @@ public abstract class AbstractBlockChain {
|
|||
private final VersionTally versionTally;
|
||||
|
||||
/** See {@link #AbstractBlockChain(Context, List, BlockStore)} */
|
||||
public AbstractBlockChain(NetworkParameters params, List<BlockChainListener> listeners,
|
||||
public AbstractBlockChain(NetworkParameters params, List<? extends Wallet> transactionReceivedListeners,
|
||||
BlockStore blockStore) throws BlockStoreException {
|
||||
this(Context.getOrCreate(params), listeners, blockStore);
|
||||
this(Context.getOrCreate(params), transactionReceivedListeners, blockStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a BlockChain connected to the given list of listeners (eg, wallets) and a store.
|
||||
*/
|
||||
public AbstractBlockChain(Context context, List<BlockChainListener> listeners,
|
||||
public AbstractBlockChain(Context context, List<? extends Wallet> wallets,
|
||||
BlockStore blockStore) throws BlockStoreException {
|
||||
this.blockStore = blockStore;
|
||||
chainHead = blockStore.getChainHead();
|
||||
log.info("chain head is at height {}:\n{}", chainHead.getHeight(), chainHead.getHeader());
|
||||
this.params = context.getParams();
|
||||
this.listeners = new CopyOnWriteArrayList<ListenerRegistration<BlockChainListener>>();
|
||||
for (BlockChainListener l : listeners) addListener(l, Threading.SAME_THREAD);
|
||||
|
||||
this.newBestBlockListeners = new CopyOnWriteArrayList<ListenerRegistration<NewBestBlockListener>>();
|
||||
this.reorganizeListeners = new CopyOnWriteArrayList<ListenerRegistration<ReorganizeListener>>();
|
||||
this.transactionReceivedListeners = new CopyOnWriteArrayList<ListenerRegistration<TransactionReceivedInBlockListener>>();
|
||||
for (NewBestBlockListener l : wallets) addNewBestBlockListener(Threading.SAME_THREAD, l);
|
||||
for (ReorganizeListener l : wallets) addReorganizeListener(Threading.SAME_THREAD, l);
|
||||
for (TransactionReceivedInBlockListener l : wallets) addTransactionReceivedListener(Threading.SAME_THREAD, l);
|
||||
|
||||
this.versionTally = new VersionTally(context.getParams());
|
||||
this.versionTally.initialize(blockStore, chainHead);
|
||||
}
|
||||
|
@ -167,7 +178,9 @@ public abstract class AbstractBlockChain {
|
|||
* wallets is not well tested!
|
||||
*/
|
||||
public void addWallet(Wallet wallet) {
|
||||
addListener(wallet, Threading.SAME_THREAD);
|
||||
addNewBestBlockListener(Threading.SAME_THREAD, wallet);
|
||||
addReorganizeListener(Threading.SAME_THREAD, wallet);
|
||||
addTransactionReceivedListener(Threading.SAME_THREAD, wallet);
|
||||
int walletHeight = wallet.getLastBlockSeenHeight();
|
||||
int chainHeight = getBestChainHeight();
|
||||
if (walletHeight != chainHeight) {
|
||||
|
@ -190,28 +203,72 @@ public abstract class AbstractBlockChain {
|
|||
|
||||
/** Removes a wallet from the chain. */
|
||||
public void removeWallet(Wallet wallet) {
|
||||
removeListener(wallet);
|
||||
removeNewBestBlockListener(wallet);
|
||||
removeReorganizeListener(wallet);
|
||||
removeTransactionReceivedListener(wallet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a generic {@link BlockChainListener} listener to the chain.
|
||||
* Adds a generic {@link NewBestBlockListener} listener to the chain.
|
||||
*/
|
||||
public void addListener(BlockChainListener listener) {
|
||||
addListener(listener, Threading.USER_THREAD);
|
||||
public final void addNewBestBlockListener(final NewBestBlockListener listener) {
|
||||
addNewBestBlockListener(Threading.USER_THREAD, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a generic {@link BlockChainListener} listener to the chain.
|
||||
* Adds a generic {@link TransactionReceivedInBlockListener} listener to the chain.
|
||||
*/
|
||||
public void addListener(BlockChainListener listener, Executor executor) {
|
||||
listeners.add(new ListenerRegistration<BlockChainListener>(listener, executor));
|
||||
public final void addNewBestBlockListener(Executor executor, final NewBestBlockListener listener) {
|
||||
newBestBlockListeners.add(new ListenerRegistration<NewBestBlockListener>(executor, listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@link BlockChainListener} from the chain.
|
||||
* Adds a generic {@link NewBestBlockListener} listener to the chain.
|
||||
*/
|
||||
public void removeListener(BlockChainListener listener) {
|
||||
ListenerRegistration.removeFromList(listener, listeners);
|
||||
public final void addReorganizeListener(final ReorganizeListener listener) {
|
||||
addReorganizeListener(Threading.USER_THREAD, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a generic {@link TransactionReceivedInBlockListener} listener to the chain.
|
||||
*/
|
||||
public final void addReorganizeListener(Executor executor, final ReorganizeListener listener) {
|
||||
reorganizeListeners.add(new ListenerRegistration<ReorganizeListener>(executor, listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a generic {@link TransactionReceivedInBlockListener} listener to the chain.
|
||||
*/
|
||||
public final void addTransactionReceivedListener(TransactionReceivedInBlockListener listener) {
|
||||
addTransactionReceivedListener(Threading.USER_THREAD, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a generic {@link TransactionReceivedInBlockListener} listener to the chain.
|
||||
*/
|
||||
public final void addTransactionReceivedListener(Executor executor, TransactionReceivedInBlockListener listener) {
|
||||
transactionReceivedListeners.add(new ListenerRegistration<TransactionReceivedInBlockListener>(executor, listener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@link NewBestBlockListener} from the chain.
|
||||
*/
|
||||
public void removeNewBestBlockListener(NewBestBlockListener listener) {
|
||||
ListenerRegistration.removeFromList(listener, newBestBlockListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@link ReorganizeListener} from the chain.
|
||||
*/
|
||||
public void removeReorganizeListener(ReorganizeListener listener) {
|
||||
ListenerRegistration.removeFromList(listener, reorganizeListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given {@link TransactionReceivedInBlockListener} from the chain.
|
||||
*/
|
||||
public void removeTransactionReceivedListener(TransactionReceivedInBlockListener listener) {
|
||||
ListenerRegistration.removeFromList(listener, transactionReceivedListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -542,12 +599,11 @@ public abstract class AbstractBlockChain {
|
|||
boolean first = true;
|
||||
Set<Sha256Hash> falsePositives = Sets.newHashSet();
|
||||
if (filteredTxHashList != null) falsePositives.addAll(filteredTxHashList);
|
||||
for (final ListenerRegistration<BlockChainListener> registration : listeners) {
|
||||
|
||||
for (final ListenerRegistration<TransactionReceivedInBlockListener> registration : transactionReceivedListeners) {
|
||||
if (registration.executor == Threading.SAME_THREAD) {
|
||||
informListenerForNewTransactions(block, newBlockType, filteredTxHashList, filteredTxn,
|
||||
newStoredBlock, first, registration.listener, falsePositives);
|
||||
if (newBlockType == NewBlockType.BEST_CHAIN)
|
||||
registration.listener.notifyNewBestBlock(newStoredBlock);
|
||||
} else {
|
||||
// Listener wants to be run on some other thread, so marshal it across here.
|
||||
final boolean notFirst = !first;
|
||||
|
@ -559,6 +615,29 @@ public abstract class AbstractBlockChain {
|
|||
Set<Sha256Hash> ignoredFalsePositives = Sets.newHashSet();
|
||||
informListenerForNewTransactions(block, newBlockType, filteredTxHashList, filteredTxn,
|
||||
newStoredBlock, notFirst, registration.listener, ignoredFalsePositives);
|
||||
} catch (VerificationException e) {
|
||||
log.error("Block chain listener threw exception: ", e);
|
||||
// Don't attempt to relay this back to the original peer thread if this was an async
|
||||
// listener invocation.
|
||||
// TODO: Make exception reporting a global feature and use it here.
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
for (final ListenerRegistration<NewBestBlockListener> registration : newBestBlockListeners) {
|
||||
if (registration.executor == Threading.SAME_THREAD) {
|
||||
if (newBlockType == NewBlockType.BEST_CHAIN)
|
||||
registration.listener.notifyNewBestBlock(newStoredBlock);
|
||||
} else {
|
||||
// Listener wants to be run on some other thread, so marshal it across here.
|
||||
final boolean notFirst = !first;
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (newBlockType == NewBlockType.BEST_CHAIN)
|
||||
registration.listener.notifyNewBestBlock(newStoredBlock);
|
||||
} catch (VerificationException e) {
|
||||
|
@ -580,7 +659,7 @@ public abstract class AbstractBlockChain {
|
|||
@Nullable List<Sha256Hash> filteredTxHashList,
|
||||
@Nullable Map<Sha256Hash, Transaction> filteredTxn,
|
||||
StoredBlock newStoredBlock, boolean first,
|
||||
BlockChainListener listener,
|
||||
TransactionReceivedInBlockListener listener,
|
||||
Set<Sha256Hash> falsePositives) throws VerificationException {
|
||||
if (block.transactions != null) {
|
||||
// If this is not the first wallet, ask for the transactions to be duplicated before being given
|
||||
|
@ -691,7 +770,7 @@ public abstract class AbstractBlockChain {
|
|||
// Now inform the listeners. This is necessary so the set of currently active transactions (that we can spend)
|
||||
// can be updated to take into account the re-organize. We might also have received new coins we didn't have
|
||||
// before and our previous spends might have been undone.
|
||||
for (final ListenerRegistration<BlockChainListener> registration : listeners) {
|
||||
for (final ListenerRegistration<ReorganizeListener> registration : reorganizeListeners) {
|
||||
if (registration.executor == Threading.SAME_THREAD) {
|
||||
// Short circuit the executor so we can propagate any exceptions.
|
||||
// TODO: Do we really need to do this or should it be irrelevant?
|
||||
|
@ -768,7 +847,7 @@ public abstract class AbstractBlockChain {
|
|||
}
|
||||
|
||||
private static void sendTransactionsToListener(StoredBlock block, NewBlockType blockType,
|
||||
BlockChainListener listener,
|
||||
TransactionReceivedInBlockListener listener,
|
||||
int relativityOffset,
|
||||
List<Transaction> transactions,
|
||||
boolean clone,
|
||||
|
@ -900,15 +979,15 @@ public abstract class AbstractBlockChain {
|
|||
*/
|
||||
public ListenableFuture<StoredBlock> getHeightFuture(final int height) {
|
||||
final SettableFuture<StoredBlock> result = SettableFuture.create();
|
||||
addListener(new AbstractBlockChainListener() {
|
||||
addNewBestBlockListener(Threading.SAME_THREAD, new NewBestBlockListener() {
|
||||
@Override
|
||||
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
|
||||
if (block.getHeight() >= height) {
|
||||
removeListener(this);
|
||||
removeNewBestBlockListener(this);
|
||||
result.set(block);
|
||||
}
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Default no-op implementation of {@link BlockChainListener}.
|
||||
*/
|
||||
public class AbstractBlockChainListener implements BlockChainListener {
|
||||
@Override
|
||||
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks) throws VerificationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveFromBlock(Transaction tx, StoredBlock block, BlockChain.NewBlockType blockType,
|
||||
int relativityOffset) throws VerificationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, BlockChain.NewBlockType blockType,
|
||||
int relativityOffset) throws VerificationException {
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ public class BlockChain extends AbstractBlockChain {
|
|||
* disk serialization (this is rare).</p>
|
||||
*/
|
||||
public BlockChain(Context context, Wallet wallet, BlockStore blockStore) throws BlockStoreException {
|
||||
this(context, new ArrayList<BlockChainListener>(), blockStore);
|
||||
this(context, new ArrayList<Wallet>(), blockStore);
|
||||
addWallet(wallet);
|
||||
}
|
||||
|
||||
|
@ -60,24 +60,24 @@ public class BlockChain extends AbstractBlockChain {
|
|||
* and receiving coins but rather, just want to explore the network data structures.
|
||||
*/
|
||||
public BlockChain(Context context, BlockStore blockStore) throws BlockStoreException {
|
||||
this(context, new ArrayList<BlockChainListener>(), blockStore);
|
||||
this(context, new ArrayList<Wallet>(), blockStore);
|
||||
}
|
||||
|
||||
/** See {@link #BlockChain(Context, BlockStore)} */
|
||||
public BlockChain(NetworkParameters params, BlockStore blockStore) throws BlockStoreException {
|
||||
this(params, new ArrayList<BlockChainListener>(), blockStore);
|
||||
this(params, new ArrayList<Wallet>(), blockStore);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a BlockChain connected to the given list of listeners and a store.
|
||||
*/
|
||||
public BlockChain(Context params, List<BlockChainListener> wallets, BlockStore blockStore) throws BlockStoreException {
|
||||
public BlockChain(Context params, List<? extends Wallet> wallets, BlockStore blockStore) throws BlockStoreException {
|
||||
super(params, wallets, blockStore);
|
||||
this.blockStore = blockStore;
|
||||
}
|
||||
|
||||
/** See {@link #BlockChain(Context, List, BlockStore)} */
|
||||
public BlockChain(NetworkParameters params, List<BlockChainListener> wallets, BlockStore blockStore) throws BlockStoreException {
|
||||
public BlockChain(NetworkParameters params, List<? extends Wallet> wallets, BlockStore blockStore) throws BlockStoreException {
|
||||
this(Context.getOrCreate(params), wallets, blockStore);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import org.bitcoinj.core.listeners.TransactionReceivedInBlockListener;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.Script.VerifyFlag;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
|
@ -61,7 +62,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
|||
* {@link Wallet#loadFromFile(java.io.File, WalletExtension...)}
|
||||
*/
|
||||
public FullPrunedBlockChain(Context context, Wallet wallet, FullPrunedBlockStore blockStore) throws BlockStoreException {
|
||||
this(context, new ArrayList<BlockChainListener>(), blockStore);
|
||||
this(context, new ArrayList<Wallet>(), blockStore);
|
||||
addWallet(wallet);
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
|||
* Constructs a block chain connected to the given store.
|
||||
*/
|
||||
public FullPrunedBlockChain(Context context, FullPrunedBlockStore blockStore) throws BlockStoreException {
|
||||
this(context, new ArrayList<BlockChainListener>(), blockStore);
|
||||
this(context, new ArrayList<Wallet>(), blockStore);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,7 +92,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
|||
/**
|
||||
* Constructs a block chain connected to the given list of wallets and a store.
|
||||
*/
|
||||
public FullPrunedBlockChain(Context context, List<BlockChainListener> listeners, FullPrunedBlockStore blockStore) throws BlockStoreException {
|
||||
public FullPrunedBlockChain(Context context, List<Wallet> listeners, FullPrunedBlockStore blockStore) throws BlockStoreException {
|
||||
super(context, listeners, blockStore);
|
||||
this.blockStore = blockStore;
|
||||
// Ignore upgrading for now
|
||||
|
@ -101,7 +102,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
|||
/**
|
||||
* See {@link #FullPrunedBlockChain(Context, List, FullPrunedBlockStore)}
|
||||
*/
|
||||
public FullPrunedBlockChain(NetworkParameters params, List<BlockChainListener> listeners,
|
||||
public FullPrunedBlockChain(NetworkParameters params, List<Wallet> listeners,
|
||||
FullPrunedBlockStore blockStore) throws BlockStoreException {
|
||||
this(Context.getOrCreate(params), listeners, blockStore);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,8 @@ package org.bitcoinj.core;
|
|||
|
||||
import com.google.common.base.*;
|
||||
import com.google.common.base.Objects;
|
||||
import org.bitcoinj.core.listeners.PeerConnectionEventListener;
|
||||
import org.bitcoinj.core.listeners.PeerDataEventListener;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.bitcoinj.utils.ListenerRegistration;
|
||||
|
@ -63,18 +65,19 @@ public class Peer extends PeerSocketHandler {
|
|||
// onPeerDisconnected should not be called directly by Peers when a PeerGroup is involved (we don't know the total
|
||||
// number of connected peers), thus we use a wrapper that PeerGroup can use to register listeners that wont get
|
||||
// onPeerDisconnected calls
|
||||
static class PeerListenerRegistration extends ListenerRegistration<PeerEventListener> {
|
||||
static class PeerConnectionListenerRegistration extends ListenerRegistration<PeerConnectionEventListener> {
|
||||
boolean callOnDisconnect = true;
|
||||
public PeerListenerRegistration(PeerEventListener listener, Executor executor) {
|
||||
super(listener, executor);
|
||||
public PeerConnectionListenerRegistration(PeerConnectionEventListener listener, Executor executor) {
|
||||
super(executor, listener);
|
||||
}
|
||||
|
||||
public PeerListenerRegistration(PeerEventListener listener, Executor executor, boolean callOnDisconnect) {
|
||||
public PeerConnectionListenerRegistration(PeerConnectionEventListener listener, Executor executor, boolean callOnDisconnect) {
|
||||
this(listener, executor);
|
||||
this.callOnDisconnect = callOnDisconnect;
|
||||
}
|
||||
}
|
||||
private final CopyOnWriteArrayList<PeerListenerRegistration> eventListeners;
|
||||
private final CopyOnWriteArrayList<PeerConnectionListenerRegistration> connectionEventListeners;
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<PeerDataEventListener>> dataEventListeners;
|
||||
// Whether to try and download blocks and transactions from this peer. Set to false by PeerGroup if not the
|
||||
// primary peer. This is to avoid redundant work and concurrency problems with downloading the same chain
|
||||
// in parallel.
|
||||
|
@ -212,7 +215,8 @@ public class Peer extends PeerSocketHandler {
|
|||
this.blockChain = chain; // Allowed to be null.
|
||||
this.vDownloadData = chain != null;
|
||||
this.getDataFutures = new CopyOnWriteArrayList<GetDataRequest>();
|
||||
this.eventListeners = new CopyOnWriteArrayList<PeerListenerRegistration>();
|
||||
this.connectionEventListeners = new CopyOnWriteArrayList<PeerConnectionListenerRegistration>();
|
||||
this.dataEventListeners = new CopyOnWriteArrayList<ListenerRegistration<PeerDataEventListener>>();
|
||||
this.getAddrFutures = new LinkedList<SettableFuture<AddressMessage>>();
|
||||
this.fastCatchupTimeSecs = params.getGenesisBlock().getTimeSeconds();
|
||||
this.isAcked = false;
|
||||
|
@ -246,8 +250,18 @@ public class Peer extends PeerSocketHandler {
|
|||
* {@link PeerEventListener#onPreMessageReceived(Peer, Message)} calls because those require that the listener
|
||||
* be added using {@link Threading#SAME_THREAD}, which requires the other addListener form.
|
||||
*/
|
||||
public void addEventListener(PeerEventListener listener) {
|
||||
addEventListener(listener, Threading.USER_THREAD);
|
||||
public void addConnectionEventListener(PeerConnectionEventListener listener) {
|
||||
addConnectionEventListener(Threading.USER_THREAD, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given object as an event listener that will be invoked on the user thread. Note that listeners
|
||||
* added this way will <b>not</b> receive {@link PeerEventListener#getData(Peer, GetDataMessage)} or
|
||||
* {@link PeerEventListener#onPreMessageReceived(Peer, Message)} calls because those require that the listener
|
||||
* be added using {@link Threading#SAME_THREAD}, which requires the other addListener form.
|
||||
*/
|
||||
public void addDataEventListener(PeerDataEventListener listener) {
|
||||
addDataEventListener(Threading.USER_THREAD, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -257,17 +271,32 @@ public class Peer extends PeerSocketHandler {
|
|||
* {@link PeerEventListener#onPreMessageReceived(Peer, Message)} calls because this class is not willing to cross
|
||||
* threads in order to get the results of those hook methods.
|
||||
*/
|
||||
public void addEventListener(PeerEventListener listener, Executor executor) {
|
||||
eventListeners.add(new PeerListenerRegistration(listener, executor));
|
||||
public void addConnectionEventListener(Executor executor, PeerConnectionEventListener listener) {
|
||||
connectionEventListeners.add(new PeerConnectionListenerRegistration(listener, executor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given object as an event listener that will be invoked by the given executor. Note that listeners
|
||||
* added using any other executor than {@link Threading#SAME_THREAD} will <b>not</b> receive
|
||||
* {@link PeerEventListener#getData(Peer, GetDataMessage)} or
|
||||
* {@link PeerEventListener#onPreMessageReceived(Peer, Message)} calls because this class is not willing to cross
|
||||
* threads in order to get the results of those hook methods.
|
||||
*/
|
||||
public void addDataEventListener(Executor executor, PeerDataEventListener listener) {
|
||||
dataEventListeners.add(new ListenerRegistration<PeerDataEventListener>(executor, listener));
|
||||
}
|
||||
|
||||
// Package-local version for PeerGroup
|
||||
void addEventListenerWithoutOnDisconnect(PeerEventListener listener, Executor executor) {
|
||||
eventListeners.add(new PeerListenerRegistration(listener, executor, false));
|
||||
void addConnectionEventListenerWithoutOnDisconnect(Executor executor, PeerConnectionEventListener listener) {
|
||||
connectionEventListeners.add(new PeerConnectionListenerRegistration(listener, executor, false));
|
||||
}
|
||||
|
||||
public boolean removeEventListener(PeerEventListener listener) {
|
||||
return ListenerRegistration.removeFromList(listener, eventListeners);
|
||||
public boolean removeConnectionEventListener(PeerConnectionEventListener listener) {
|
||||
return ListenerRegistration.removeFromList(listener, connectionEventListeners);
|
||||
}
|
||||
|
||||
public boolean removeDataEventListener(PeerDataEventListener listener) {
|
||||
return ListenerRegistration.removeFromList(listener, dataEventListeners);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -287,7 +316,7 @@ public class Peer extends PeerSocketHandler {
|
|||
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
for (final PeerListenerRegistration registration : eventListeners) {
|
||||
for (final PeerConnectionListenerRegistration registration : connectionEventListeners) {
|
||||
if (registration.callOnDisconnect)
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
|
@ -326,7 +355,7 @@ public class Peer extends PeerSocketHandler {
|
|||
protected void processMessage(Message m) throws Exception {
|
||||
// Allow event listeners to filter the message stream. Listeners are allowed to drop messages by
|
||||
// returning null.
|
||||
for (ListenerRegistration<PeerEventListener> registration : eventListeners) {
|
||||
for (ListenerRegistration<PeerDataEventListener> registration : dataEventListeners) {
|
||||
// Skip any listeners that are supposed to run in another thread as we don't want to block waiting
|
||||
// for it, which might cause circular deadlock.
|
||||
if (registration.executor == Threading.SAME_THREAD) {
|
||||
|
@ -382,7 +411,7 @@ public class Peer extends PeerSocketHandler {
|
|||
}
|
||||
isAcked = true;
|
||||
this.setTimeoutEnabled(false);
|
||||
for (final ListenerRegistration<PeerEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<PeerConnectionEventListener> registration : connectionEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -592,7 +621,7 @@ public class Peer extends PeerSocketHandler {
|
|||
private void processGetData(GetDataMessage getdata) {
|
||||
log.info("{}: Received getdata message: {}", getAddress(), getdata.toString());
|
||||
ArrayList<Message> items = new ArrayList<Message>();
|
||||
for (ListenerRegistration<PeerEventListener> registration : eventListeners) {
|
||||
for (ListenerRegistration<PeerDataEventListener> registration : dataEventListeners) {
|
||||
if (registration.executor != Threading.SAME_THREAD) continue;
|
||||
List<Message> listenerItems = registration.listener.getData(this, getdata);
|
||||
if (listenerItems == null) continue;
|
||||
|
@ -690,7 +719,7 @@ public class Peer extends PeerSocketHandler {
|
|||
}
|
||||
// Tell all listeners about this tx so they can decide whether to keep it or not. If no listener keeps a
|
||||
// reference around then the memory pool will forget about it after a while too because it uses weak references.
|
||||
for (final ListenerRegistration<PeerEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<PeerDataEventListener> registration : dataEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -1007,7 +1036,7 @@ public class Peer extends PeerSocketHandler {
|
|||
// since the time we first connected to the peer. However, it's weird and unexpected to receive a callback
|
||||
// with negative "blocks left" in this case, so we clamp to zero so the API user doesn't have to think about it.
|
||||
final int blocksLeft = Math.max(0, (int) vPeerVersionMessage.bestHeight - checkNotNull(blockChain).getBestChainHeight());
|
||||
for (final ListenerRegistration<PeerEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<PeerDataEventListener> registration : dataEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -1342,7 +1371,7 @@ public class Peer extends PeerSocketHandler {
|
|||
// chain even if the chain block count is lower.
|
||||
final int blocksLeft = getPeerBlockHeightDifference();
|
||||
if (blocksLeft >= 0) {
|
||||
for (final ListenerRegistration<PeerEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<PeerDataEventListener> registration : dataEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
|
|
@ -26,6 +26,13 @@ import com.google.common.util.concurrent.*;
|
|||
import com.squareup.okhttp.*;
|
||||
import com.subgraph.orchid.*;
|
||||
import net.jcip.annotations.*;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerConnectionEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerDataEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.listeners.DownloadProgressTracker;
|
||||
import org.bitcoinj.core.listeners.PeerConnectionEventListener;
|
||||
import org.bitcoinj.core.listeners.PeerDataEventListener;
|
||||
import org.bitcoinj.core.listeners.WalletEventListener;
|
||||
import org.bitcoinj.crypto.*;
|
||||
import org.bitcoinj.net.*;
|
||||
import org.bitcoinj.net.discovery.*;
|
||||
|
@ -109,9 +116,11 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
// The peer that has been selected for the purposes of downloading announced data.
|
||||
@GuardedBy("lock") private Peer downloadPeer;
|
||||
// Callback for events related to chain download.
|
||||
@Nullable @GuardedBy("lock") private PeerEventListener downloadListener;
|
||||
@Nullable @GuardedBy("lock") private PeerDataEventListener downloadListener;
|
||||
// Callbacks for events related to peer connection/disconnection
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<PeerEventListener>> peerEventListeners;
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<PeerConnectionEventListener>> peerConnectionEventListeners;
|
||||
// Callbacks for events related to peer data being received
|
||||
private final CopyOnWriteArrayList<ListenerRegistration<PeerDataEventListener>> peerDataEventListeners;
|
||||
// Peer discovery sources, will be polled occasionally if there aren't enough inactives.
|
||||
private final CopyOnWriteArraySet<PeerDiscovery> peerDiscoverers;
|
||||
// The version message to use for new connections.
|
||||
|
@ -137,7 +146,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
|
||||
// This event listener is added to every peer. It's here so when we announce transactions via an "inv", every
|
||||
// peer can fetch them.
|
||||
private final AbstractPeerEventListener peerListener = new AbstractPeerEventListener() {
|
||||
private final AbstractPeerDataEventListener peerListener = new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public List<Message> getData(Peer peer, GetDataMessage m) {
|
||||
return handleGetData(m);
|
||||
|
@ -158,7 +167,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
};
|
||||
|
||||
private int minBroadcastConnections = 0;
|
||||
private final AbstractWalletEventListener walletEventListener = new AbstractWalletEventListener() {
|
||||
private final WalletEventListener walletEventListener = new AbstractWalletEventListener() {
|
||||
@Override public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
|
||||
recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
|
||||
}
|
||||
|
@ -213,7 +222,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
// in broadcastTransaction.
|
||||
private final Set<TransactionBroadcast> runningBroadcasts;
|
||||
|
||||
private class PeerStartupListener extends AbstractPeerEventListener {
|
||||
private class PeerStartupListener extends AbstractPeerConnectionEventListener {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
handleNewPeer(peer);
|
||||
|
@ -226,7 +235,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
}
|
||||
}
|
||||
|
||||
private final PeerEventListener startupListener = new PeerStartupListener();
|
||||
private final PeerConnectionEventListener startupListener = new PeerStartupListener();
|
||||
|
||||
/**
|
||||
* The default Bloom filter false positive rate, which is selected to be extremely low such that you hardly ever
|
||||
|
@ -395,7 +404,8 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
pendingPeers = new CopyOnWriteArrayList<Peer>();
|
||||
channels = connectionManager;
|
||||
peerDiscoverers = new CopyOnWriteArraySet<PeerDiscovery>();
|
||||
peerEventListeners = new CopyOnWriteArrayList<ListenerRegistration<PeerEventListener>>();
|
||||
peerConnectionEventListeners = new CopyOnWriteArrayList<ListenerRegistration<PeerConnectionEventListener>>();
|
||||
peerDataEventListeners = new CopyOnWriteArrayList<ListenerRegistration<PeerDataEventListener>>();
|
||||
runningBroadcasts = Collections.synchronizedSet(new HashSet<TransactionBroadcast>());
|
||||
bloomFilterMerger = new FilterMerger(DEFAULT_BLOOM_FILTER_FP_RATE);
|
||||
}
|
||||
|
@ -668,29 +678,66 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
* </li>
|
||||
* </ol>
|
||||
*/
|
||||
public void addEventListener(PeerEventListener listener, Executor executor) {
|
||||
peerEventListeners.add(new ListenerRegistration<PeerEventListener>(checkNotNull(listener), executor));
|
||||
public void addConnectionEventListener(Executor executor, PeerConnectionEventListener listener) {
|
||||
peerConnectionEventListeners.add(new ListenerRegistration<PeerConnectionEventListener>(executor, checkNotNull(listener)));
|
||||
for (Peer peer : getConnectedPeers())
|
||||
peer.addEventListener(listener, executor);
|
||||
peer.addConnectionEventListener(executor, listener);
|
||||
for (Peer peer: getPendingPeers())
|
||||
peer.addEventListener(listener, executor);
|
||||
peer.addConnectionEventListener(executor, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Adds a listener that will be notified on the given executor when:</p>
|
||||
* <ol>
|
||||
* <li>New peers are connected to.</li>
|
||||
* <li>Peers are disconnected from.</li>
|
||||
* <li>A message is received by the download peer (there is always one peer which is elected as a peer which
|
||||
* will be used to retrieve data).
|
||||
* <li>Blocks are downloaded by the download peer.</li>
|
||||
* </li>
|
||||
* </ol>
|
||||
*/
|
||||
public void addDataEventListener(final Executor executor, final PeerDataEventListener listener) {
|
||||
peerDataEventListeners.add(new ListenerRegistration<PeerDataEventListener>(executor, checkNotNull(listener)));
|
||||
for (Peer peer : getConnectedPeers())
|
||||
peer.addDataEventListener(executor, listener);
|
||||
for (Peer peer: getPendingPeers())
|
||||
peer.addDataEventListener(executor, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link PeerGroup#addEventListener(PeerEventListener, java.util.concurrent.Executor)} but defaults
|
||||
* to running on the user thread.
|
||||
*/
|
||||
public void addEventListener(PeerEventListener listener) {
|
||||
addEventListener(listener, Threading.USER_THREAD);
|
||||
public void addConnectionEventListener(PeerConnectionEventListener listener) {
|
||||
addConnectionEventListener(Threading.USER_THREAD, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link PeerGroup#addEventListener(PeerEventListener, java.util.concurrent.Executor)} but defaults
|
||||
* to running on the user thread.
|
||||
*/
|
||||
public void addDataEventListener(PeerDataEventListener listener) {
|
||||
addDataEventListener(Threading.USER_THREAD, listener);
|
||||
}
|
||||
|
||||
/** The given event listener will no longer be called with events. */
|
||||
public boolean removeEventListener(PeerEventListener listener) {
|
||||
boolean result = ListenerRegistration.removeFromList(listener, peerEventListeners);
|
||||
public boolean removeConnectionEventListener(PeerConnectionEventListener listener) {
|
||||
boolean result = ListenerRegistration.removeFromList(listener, peerConnectionEventListeners);
|
||||
for (Peer peer : getConnectedPeers())
|
||||
peer.removeEventListener(listener);
|
||||
peer.removeConnectionEventListener(listener);
|
||||
for (Peer peer : getPendingPeers())
|
||||
peer.removeEventListener(listener);
|
||||
peer.removeConnectionEventListener(listener);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** The given event listener will no longer be called with events. */
|
||||
public boolean removeDataEventListener(PeerDataEventListener listener) {
|
||||
boolean result = ListenerRegistration.removeFromList(listener, peerDataEventListeners);
|
||||
for (Peer peer : getConnectedPeers())
|
||||
peer.removeDataEventListener(listener);
|
||||
for (Peer peer : getPendingPeers())
|
||||
peer.removeDataEventListener(listener);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -699,7 +746,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
* so it's generally not advised to use this - it exists for special purposes only.
|
||||
*/
|
||||
public void clearEventListeners() {
|
||||
peerEventListeners.clear();
|
||||
peerConnectionEventListeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -796,7 +843,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
addInactive(address);
|
||||
}
|
||||
final ImmutableSet<PeerAddress> peersDiscoveredSet = ImmutableSet.copyOf(addressList);
|
||||
for (final ListenerRegistration<PeerEventListener> registration : peerEventListeners /* COW */) {
|
||||
for (final ListenerRegistration<PeerConnectionEventListener> registration : peerConnectionEventListeners /* COW */) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -978,7 +1025,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
checkState(!wallets.contains(wallet));
|
||||
wallets.add(wallet);
|
||||
wallet.setTransactionBroadcaster(this);
|
||||
wallet.addEventListener(walletEventListener, Threading.SAME_THREAD);
|
||||
wallet.addEventListener(Threading.SAME_THREAD, walletEventListener);
|
||||
addPeerFilterProvider(wallet);
|
||||
for (Peer peer : peers) {
|
||||
peer.addWallet(wallet);
|
||||
|
@ -1216,7 +1263,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
ver.time = Utils.currentTimeSeconds();
|
||||
|
||||
Peer peer = new Peer(params, ver, address, chain, downloadTxDependencies);
|
||||
peer.addEventListener(startupListener, Threading.SAME_THREAD);
|
||||
peer.addConnectionEventListener(Threading.SAME_THREAD, startupListener);
|
||||
peer.setMinProtocolVersion(vMinRequiredProtocolVersion);
|
||||
pendingPeers.add(peer);
|
||||
|
||||
|
@ -1259,13 +1306,13 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
*
|
||||
* @param listener a listener for chain download events, may not be null
|
||||
*/
|
||||
public void startBlockChainDownload(PeerEventListener listener) {
|
||||
public void startBlockChainDownload(PeerDataEventListener listener) {
|
||||
lock.lock();
|
||||
try {
|
||||
if (downloadPeer != null && this.downloadListener != null)
|
||||
downloadPeer.removeEventListener(this.downloadListener);
|
||||
downloadPeer.removeDataEventListener(this.downloadListener);
|
||||
if (downloadPeer != null && listener != null)
|
||||
downloadPeer.addEventListener(listener);
|
||||
downloadPeer.addDataEventListener(listener);
|
||||
this.downloadListener = listener;
|
||||
// TODO: be more nuanced about which peer to download from. We can also try
|
||||
// downloading from multiple peers and handle the case when a new peer comes along
|
||||
|
@ -1323,17 +1370,20 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
}
|
||||
}
|
||||
// Make sure the peer knows how to upload transactions that are requested from us.
|
||||
peer.addEventListener(peerListener, Threading.SAME_THREAD);
|
||||
peer.addDataEventListener(Threading.SAME_THREAD, peerListener);
|
||||
// And set up event listeners for clients. This will allow them to find out about new transactions and blocks.
|
||||
for (ListenerRegistration<PeerEventListener> registration : peerEventListeners) {
|
||||
peer.addEventListenerWithoutOnDisconnect(registration.listener, registration.executor);
|
||||
for (ListenerRegistration<PeerConnectionEventListener> registration : peerConnectionEventListeners) {
|
||||
peer.addConnectionEventListenerWithoutOnDisconnect(registration.executor, registration.listener);
|
||||
}
|
||||
for (ListenerRegistration<PeerDataEventListener> registration : peerDataEventListeners) {
|
||||
peer.addDataEventListener(registration.executor, registration.listener);
|
||||
}
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
final int fNewSize = newSize;
|
||||
for (final ListenerRegistration<PeerEventListener> registration : peerEventListeners) {
|
||||
for (final ListenerRegistration<PeerConnectionEventListener> registration : peerConnectionEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -1382,14 +1432,14 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
if (downloadPeer != null) {
|
||||
log.info("Unsetting download peer: {}", downloadPeer);
|
||||
if (downloadListener != null)
|
||||
downloadPeer.removeEventListener(downloadListener);
|
||||
downloadPeer.removeDataEventListener(downloadListener);
|
||||
downloadPeer.setDownloadData(false);
|
||||
}
|
||||
downloadPeer = peer;
|
||||
if (downloadPeer != null) {
|
||||
log.info("Setting download peer: {}", downloadPeer);
|
||||
if (downloadListener != null)
|
||||
peer.addEventListener(downloadListener, Threading.SAME_THREAD);
|
||||
peer.addDataEventListener(Threading.SAME_THREAD, downloadListener);
|
||||
downloadPeer.setDownloadData(true);
|
||||
if (chain != null)
|
||||
downloadPeer.setDownloadParameters(fastCatchupTimeSecs, bloomFilterMerger.getLastFilter() != null);
|
||||
|
@ -1487,20 +1537,23 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
lock.unlock();
|
||||
}
|
||||
|
||||
peer.removeEventListener(peerListener);
|
||||
peer.removeDataEventListener(peerListener);
|
||||
for (Wallet wallet : wallets) {
|
||||
peer.removeWallet(wallet);
|
||||
}
|
||||
|
||||
final int fNumConnectedPeers = numConnectedPeers;
|
||||
for (final ListenerRegistration<PeerEventListener> registration : peerEventListeners) {
|
||||
for (ListenerRegistration<PeerDataEventListener> registration : peerDataEventListeners) {
|
||||
peer.removeDataEventListener(registration.listener);
|
||||
}
|
||||
for (final ListenerRegistration<PeerConnectionEventListener> registration : peerConnectionEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onPeerDisconnected(peer, fNumConnectedPeers);
|
||||
}
|
||||
});
|
||||
peer.removeEventListener(registration.listener);
|
||||
peer.removeConnectionEventListener(registration.listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1528,7 +1581,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
}
|
||||
}
|
||||
|
||||
private class ChainDownloadSpeedCalculator extends AbstractPeerEventListener implements Runnable {
|
||||
private class ChainDownloadSpeedCalculator extends AbstractPeerDataEventListener implements Runnable {
|
||||
private int blocksInLastSecond, txnsInLastSecond, origTxnsInLastSecond;
|
||||
private long bytesInLastSecond;
|
||||
|
||||
|
@ -1655,7 +1708,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
chainDownloadSpeedCalculator = new ChainDownloadSpeedCalculator();
|
||||
executor.scheduleAtFixedRate(chainDownloadSpeedCalculator, 1, 1, TimeUnit.SECONDS);
|
||||
}
|
||||
peer.addEventListener(chainDownloadSpeedCalculator, Threading.SAME_THREAD);
|
||||
peer.addDataEventListener(Threading.SAME_THREAD, chainDownloadSpeedCalculator);
|
||||
|
||||
// startBlockChainDownload will setDownloadData(true) on itself automatically.
|
||||
peer.startBlockChainDownload();
|
||||
|
@ -1691,13 +1744,13 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
return Futures.immediateFuture(foundPeers);
|
||||
}
|
||||
final SettableFuture<List<Peer>> future = SettableFuture.create();
|
||||
addEventListener(new AbstractPeerEventListener() {
|
||||
addConnectionEventListener(new AbstractPeerConnectionEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
final List<Peer> peers = findPeersOfAtLeastVersion(protocolVersion);
|
||||
if (peers.size() >= numPeers) {
|
||||
future.set(peers);
|
||||
removeEventListener(this);
|
||||
removeConnectionEventListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1735,13 +1788,13 @@ public class PeerGroup implements TransactionBroadcaster {
|
|||
if (foundPeers.size() >= numPeers)
|
||||
return Futures.immediateFuture(foundPeers);
|
||||
final SettableFuture<List<Peer>> future = SettableFuture.create();
|
||||
addEventListener(new AbstractPeerEventListener() {
|
||||
addConnectionEventListener(new AbstractPeerConnectionEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
final List<Peer> peers = findPeersWithServiceMask(mask);
|
||||
if (peers.size() >= numPeers) {
|
||||
future.set(peers);
|
||||
removeEventListener(this);
|
||||
removeConnectionEventListener(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -19,6 +19,8 @@ package org.bitcoinj.core;
|
|||
import com.google.common.annotations.*;
|
||||
import com.google.common.base.*;
|
||||
import com.google.common.util.concurrent.*;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerDataEventListener;
|
||||
import org.bitcoinj.core.listeners.PeerDataEventListener;
|
||||
import org.bitcoinj.utils.*;
|
||||
import org.slf4j.*;
|
||||
|
||||
|
@ -86,7 +88,7 @@ public class TransactionBroadcast {
|
|||
this.minConnections = minConnections;
|
||||
}
|
||||
|
||||
private PeerEventListener rejectionListener = new AbstractPeerEventListener() {
|
||||
private PeerDataEventListener rejectionListener = new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
||||
if (m instanceof RejectMessage) {
|
||||
|
@ -98,7 +100,7 @@ public class TransactionBroadcast {
|
|||
if (size > threshold) {
|
||||
log.warn("Threshold for considering broadcast rejected has been reached ({}/{})", size, threshold);
|
||||
future.setException(new RejectedTransactionException(tx, rejectMessage));
|
||||
peerGroup.removeEventListener(this);
|
||||
peerGroup.removeDataEventListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -107,7 +109,7 @@ public class TransactionBroadcast {
|
|||
};
|
||||
|
||||
public ListenableFuture<Transaction> broadcast() {
|
||||
peerGroup.addEventListener(rejectionListener, Threading.SAME_THREAD);
|
||||
peerGroup.addDataEventListener(Threading.SAME_THREAD, rejectionListener);
|
||||
log.info("Waiting for {} peers required for broadcast, we have {} ...", minConnections, peerGroup.getConnectedPeers().size());
|
||||
peerGroup.waitForPeers(minConnections).addListener(new EnoughAvailablePeers(), Threading.SAME_THREAD);
|
||||
return future;
|
||||
|
@ -159,7 +161,7 @@ public class TransactionBroadcast {
|
|||
// So we just have to assume we're done, at that point. This happens when we're not given
|
||||
// any peer discovery source and the user just calls connectTo() once.
|
||||
if (minConnections == 1) {
|
||||
peerGroup.removeEventListener(rejectionListener);
|
||||
peerGroup.removeDataEventListener(rejectionListener);
|
||||
future.set(tx);
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +197,7 @@ public class TransactionBroadcast {
|
|||
// We're done! It's important that the PeerGroup lock is not held (by this thread) at this
|
||||
// point to avoid triggering inversions when the Future completes.
|
||||
log.info("broadcastTransaction: {} complete", tx.getHash());
|
||||
peerGroup.removeEventListener(rejectionListener);
|
||||
peerGroup.removeDataEventListener(rejectionListener);
|
||||
conf.removeEventListener(this);
|
||||
future.set(tx); // RE-ENTRANCY POINT
|
||||
}
|
||||
|
|
|
@ -193,9 +193,9 @@ public class TransactionConfidence {
|
|||
* the best chain). If you want to know when the transaction gets buried under another block, consider using
|
||||
* a future from {@link #getDepthFuture(int)}.</p>
|
||||
*/
|
||||
public void addEventListener(Listener listener, Executor executor) {
|
||||
public void addEventListener(Executor executor, Listener listener) {
|
||||
checkNotNull(listener);
|
||||
listeners.addIfAbsent(new ListenerRegistration<Listener>(listener, executor));
|
||||
listeners.addIfAbsent(new ListenerRegistration<Listener>(executor, listener));
|
||||
pinnedConfidenceObjects.add(this);
|
||||
}
|
||||
|
||||
|
@ -210,7 +210,7 @@ public class TransactionConfidence {
|
|||
* confidence object to determine the new depth.</p>
|
||||
*/
|
||||
public void addEventListener(Listener listener) {
|
||||
addEventListener(listener, Threading.USER_THREAD);
|
||||
addEventListener(Threading.USER_THREAD, listener);
|
||||
}
|
||||
|
||||
public boolean removeEventListener(Listener listener) {
|
||||
|
@ -457,14 +457,14 @@ public class TransactionConfidence {
|
|||
if (getDepthInBlocks() >= depth) {
|
||||
result.set(this);
|
||||
}
|
||||
addEventListener(new Listener() {
|
||||
addEventListener(executor, new Listener() {
|
||||
@Override public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
if (getDepthInBlocks() >= depth) {
|
||||
removeEventListener(this);
|
||||
result.set(confidence);
|
||||
}
|
||||
}
|
||||
}, executor);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,12 @@ 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.TransactionConfidence.*;
|
||||
import org.bitcoinj.crypto.*;
|
||||
import org.bitcoinj.params.*;
|
||||
|
@ -85,7 +91,8 @@ import static com.google.common.base.Preconditions.*;
|
|||
* {@link Wallet#autosaveToFile(java.io.File, long, java.util.concurrent.TimeUnit, org.bitcoinj.wallet.WalletFiles.Listener)}
|
||||
* for more information about this.</p>
|
||||
*/
|
||||
public class Wallet extends BaseTaggableObject implements BlockChainListener, PeerFilterProvider, KeyBag, TransactionBag {
|
||||
public class Wallet extends BaseTaggableObject
|
||||
implements NewBestBlockListener, TransactionReceivedInBlockListener, PeerFilterProvider, KeyBag, TransactionBag, ReorganizeListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(Wallet.class);
|
||||
private static final int MINIMUM_BLOOM_DATA_LENGTH = 8;
|
||||
|
||||
|
@ -153,7 +160,8 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
private int lastBlockSeenHeight;
|
||||
private long lastBlockSeenTimeSecs;
|
||||
|
||||
private CopyOnWriteArrayList<ListenerRegistration<WalletEventListener>> eventListeners;
|
||||
private CopyOnWriteArrayList<ListenerRegistration<WalletChangeEventListener>> changeListeners;
|
||||
private CopyOnWriteArrayList<ListenerRegistration<WalletCoinEventListener>> coinListeners;
|
||||
|
||||
// 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.
|
||||
|
@ -273,7 +281,8 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
pending = new HashMap<Sha256Hash, Transaction>();
|
||||
dead = new HashMap<Sha256Hash, Transaction>();
|
||||
transactions = new HashMap<Sha256Hash, Transaction>();
|
||||
eventListeners = new CopyOnWriteArrayList<ListenerRegistration<WalletEventListener>>();
|
||||
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>();
|
||||
|
@ -2284,31 +2293,83 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
* like receiving money. Runs the listener methods in the user thread.
|
||||
*/
|
||||
public void addEventListener(WalletEventListener listener) {
|
||||
addEventListener(listener, Threading.USER_THREAD);
|
||||
addChangeEventListener(Threading.USER_THREAD, listener);
|
||||
addCoinEventListener(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 addChangeEventListener(WalletChangeEventListener listener) {
|
||||
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.
|
||||
*/
|
||||
public void addEventListener(WalletEventListener listener, Executor executor) {
|
||||
public void addChangeEventListener(Executor executor, WalletChangeEventListener listener) {
|
||||
// This is thread safe, so we don't need to take the lock.
|
||||
eventListeners.add(new ListenerRegistration<WalletEventListener>(listener, executor));
|
||||
changeListeners.add(new ListenerRegistration<WalletChangeEventListener>(executor, listener));
|
||||
keychain.addEventListener(listener, executor);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
// This is thread safe, so we don't need to take the lock.
|
||||
coinListeners.add(new ListenerRegistration<WalletCoinEventListener>(executor, 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 addEventListener(Executor executor, WalletEventListener listener) {
|
||||
addCoinEventListener(executor, listener);
|
||||
addChangeEventListener(executor, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
|
||||
* was never added.
|
||||
*/
|
||||
public boolean removeEventListener(WalletEventListener listener) {
|
||||
return removeChangeEventListener(listener) ||
|
||||
removeCoinEventListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given event listener object. Returns true if the listener was removed, false if that listener
|
||||
* was never added.
|
||||
*/
|
||||
public boolean removeChangeEventListener(WalletChangeEventListener listener) {
|
||||
keychain.removeEventListener(listener);
|
||||
return ListenerRegistration.removeFromList(listener, eventListeners);
|
||||
return ListenerRegistration.removeFromList(listener, changeListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
private void queueOnTransactionConfidenceChanged(final Transaction tx) {
|
||||
checkState(lock.isHeldByCurrentThread());
|
||||
for (final ListenerRegistration<WalletEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<WalletChangeEventListener> registration : changeListeners) {
|
||||
if (registration.executor == Threading.SAME_THREAD) {
|
||||
registration.listener.onTransactionConfidenceChanged(this, tx);
|
||||
} else {
|
||||
|
@ -2328,7 +2389,7 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
checkState(lock.isHeldByCurrentThread());
|
||||
checkState(onWalletChangedSuppressions >= 0);
|
||||
if (onWalletChangedSuppressions > 0) return;
|
||||
for (final ListenerRegistration<WalletEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<WalletChangeEventListener> registration : changeListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -2340,7 +2401,7 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
|
||||
protected void queueOnCoinsReceived(final Transaction tx, final Coin balance, final Coin newBalance) {
|
||||
checkState(lock.isHeldByCurrentThread());
|
||||
for (final ListenerRegistration<WalletEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<WalletCoinEventListener> registration : coinListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -2352,7 +2413,7 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
|
||||
protected void queueOnCoinsSent(final Transaction tx, final Coin prevBalance, final Coin newBalance) {
|
||||
checkState(lock.isHeldByCurrentThread());
|
||||
for (final ListenerRegistration<WalletEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<WalletCoinEventListener> registration : coinListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -2365,7 +2426,7 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
protected void queueOnReorganize() {
|
||||
checkState(lock.isHeldByCurrentThread());
|
||||
checkState(insideReorg);
|
||||
for (final ListenerRegistration<WalletEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<WalletChangeEventListener> registration : changeListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -2376,7 +2437,7 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
}
|
||||
|
||||
protected void queueOnScriptsChanged(final List<Script> scripts, final boolean isAddingScripts) {
|
||||
for (final ListenerRegistration<WalletEventListener> registration : eventListeners) {
|
||||
for (final ListenerRegistration<WalletChangeEventListener> registration : changeListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
@ -2479,7 +2540,7 @@ public class Wallet extends BaseTaggableObject implements BlockChainListener, Pe
|
|||
}
|
||||
// This is safe even if the listener has been added before, as TransactionConfidence ignores duplicate
|
||||
// registration requests. That makes the code in the wallet simpler.
|
||||
tx.getConfidence().addEventListener(txConfidenceListener, Threading.SAME_THREAD);
|
||||
tx.getConfidence().addEventListener(Threading.SAME_THREAD, txConfidenceListener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/**
|
||||
* Copyright 2011 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.Peer;
|
||||
import java.util.Set;
|
||||
import org.bitcoinj.core.PeerAddress;
|
||||
|
||||
/**
|
||||
* Convenience implementation of {@link PeerEventListener}.
|
||||
*/
|
||||
public abstract class AbstractPeerConnectionEventListener implements PeerConnectionEventListener {
|
||||
|
||||
@Override
|
||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* Copyright 2011 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.Block;
|
||||
import org.bitcoinj.core.FilteredBlock;
|
||||
import org.bitcoinj.core.GetDataMessage;
|
||||
import org.bitcoinj.core.Message;
|
||||
import org.bitcoinj.core.Peer;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import javax.annotation.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Convenience implementation of {@link PeerEventListener}.
|
||||
*/
|
||||
public abstract class AbstractPeerDataEventListener implements PeerDataEventListener {
|
||||
@Override
|
||||
public void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int blocksLeft) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChainDownloadStarted(Peer peer, int blocksLeft) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
||||
// Just pass the message right through for further processing.
|
||||
return m;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransaction(Peer peer, Transaction t) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Message> getData(Peer peer, GetDataMessage m) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -14,8 +14,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoinj.core;
|
||||
package org.bitcoinj.core.listeners;
|
||||
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.core.FilteredBlock;
|
||||
import org.bitcoinj.core.GetDataMessage;
|
||||
import org.bitcoinj.core.Message;
|
||||
import org.bitcoinj.core.PeerAddress;
|
||||
import org.bitcoinj.core.Peer;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import javax.annotation.*;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -23,11 +30,7 @@ import java.util.Set;
|
|||
/**
|
||||
* Convenience implementation of {@link PeerEventListener}.
|
||||
*/
|
||||
public class AbstractPeerEventListener implements PeerEventListener {
|
||||
@Override
|
||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
||||
}
|
||||
|
||||
public abstract class AbstractPeerEventListener extends AbstractPeerDataEventListener implements PeerConnectionEventListener {
|
||||
@Override
|
||||
public void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int blocksLeft) {
|
||||
}
|
||||
|
@ -36,14 +39,6 @@ public class AbstractPeerEventListener implements PeerEventListener {
|
|||
public void onChainDownloadStarted(Peer peer, int blocksLeft) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
||||
// Just pass the message right through for further processing.
|
||||
|
@ -58,4 +53,16 @@ public class AbstractPeerEventListener implements PeerEventListener {
|
|||
public List<Message> getData(Peer peer, GetDataMessage m) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
}
|
||||
}
|
|
@ -14,8 +14,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoinj.core;
|
||||
package org.bitcoinj.core.listeners;
|
||||
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.Wallet;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.wallet.AbstractKeyChainEventListener;
|
||||
|
|
@ -15,8 +15,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoinj.core;
|
||||
package org.bitcoinj.core.listeners;
|
||||
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.core.FilteredBlock;
|
||||
import org.bitcoinj.core.Peer;
|
||||
import org.bitcoinj.core.Utils;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -27,11 +31,11 @@ import java.util.Date;
|
|||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
/**
|
||||
* <p>An implementation of {@link AbstractPeerEventListener} that listens to chain download events and tracks progress
|
||||
* <p>An implementation of {@link AbstractPeerDataEventListener} that listens to chain download events and tracks progress
|
||||
* as a percentage. The default implementation prints progress to stdout, but you can subclass it and override the
|
||||
* progress method to update a GUI instead.</p>
|
||||
*/
|
||||
public class DownloadProgressTracker extends AbstractPeerEventListener {
|
||||
public class DownloadProgressTracker extends AbstractPeerDataEventListener {
|
||||
private static final Logger log = LoggerFactory.getLogger(DownloadProgressTracker.class);
|
||||
private int originalBlocksLeft = -1;
|
||||
private int lastPercent = 0;
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright 2011 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.StoredBlock;
|
||||
import org.bitcoinj.core.VerificationException;
|
||||
|
||||
/**
|
||||
* Listener interface for when a new block on the best chain is seen.
|
||||
*/
|
||||
public interface NewBestBlockListener {
|
||||
/**
|
||||
* Called when a new block on the best chain is seen, after relevant
|
||||
* transactions are extracted and sent to us via either
|
||||
* {@link ReceiveFromBlockListener#receiveFromBlock(Transaction, StoredBlock, org.bitcoinj.core.BlockChain.NewBlockType, int)}
|
||||
* or {@link TransactionIsInBlockListener#notifyTransactionIsInBlock(Sha256Hash, StoredBlock, org.bitcoinj.core.BlockChain.NewBlockType, int)}.
|
||||
* If this block is causing a re-organise to a new chain, this method is NOT
|
||||
* called even though the block may be the new best block: your reorganize
|
||||
* implementation is expected to do whatever would normally be done do for a
|
||||
* new best block in this case.
|
||||
*/
|
||||
void notifyNewBestBlock(final StoredBlock block) throws VerificationException;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* Copyright 2011 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.Peer;
|
||||
import org.bitcoinj.core.PeerAddress;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <p>Implementors can listen to events like blocks being downloaded/transactions being broadcast/connect/disconnects,
|
||||
* they can pre-filter messages before they are procesesed by a {@link Peer} or {@link PeerGroup}, and they can
|
||||
* provide transactions to remote peers when they ask for them.</p>
|
||||
*/
|
||||
public interface PeerConnectionEventListener {
|
||||
/**
|
||||
* <p>Called when peers are discovered, this happens at startup of {@link PeerGroup} or if we run out of
|
||||
* suitable {@link Peer}s to connect to.</p>
|
||||
*
|
||||
* @param peerAddresses the set of discovered {@link PeerAddress}es
|
||||
*/
|
||||
void onPeersDiscovered(Set<PeerAddress> peerAddresses);
|
||||
|
||||
/**
|
||||
* Called when a peer is connected. If this listener is registered to a {@link Peer} instead of a {@link PeerGroup},
|
||||
* peerCount will always be 1.
|
||||
*
|
||||
* @param peer
|
||||
* @param peerCount the total number of connected peers
|
||||
*/
|
||||
void onPeerConnected(Peer peer, int peerCount);
|
||||
|
||||
/**
|
||||
* Called when a peer is disconnected. Note that this won't be called if the listener is registered on a
|
||||
* {@link PeerGroup} and the group is in the process of shutting down. If this listener is registered to a
|
||||
* {@link Peer} instead of a {@link PeerGroup}, peerCount will always be 0. This handler can be called without
|
||||
* a corresponding invocation of onPeerConnected if the initial connection is never successful.
|
||||
*
|
||||
* @param peer
|
||||
* @param peerCount the total number of connected peers
|
||||
*/
|
||||
void onPeerDisconnected(Peer peer, int peerCount);
|
||||
}
|
|
@ -14,24 +14,23 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoinj.core;
|
||||
package org.bitcoinj.core.listeners;
|
||||
|
||||
import javax.annotation.*;
|
||||
import java.util.*;
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.core.FilteredBlock;
|
||||
import org.bitcoinj.core.GetDataMessage;
|
||||
import org.bitcoinj.core.Message;
|
||||
import org.bitcoinj.core.Peer;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Implementors can listen to events like blocks being downloaded/transactions being broadcast/connect/disconnects,
|
||||
* they can pre-filter messages before they are procesesed by a {@link Peer} or {@link PeerGroup}, and they can
|
||||
* provide transactions to remote peers when they ask for them.</p>
|
||||
*/
|
||||
public interface PeerEventListener {
|
||||
/**
|
||||
* <p>Called when peers are discovered, this happens at startup of {@link PeerGroup} or if we run out of
|
||||
* suitable {@link Peer}s to connect to.</p>
|
||||
*
|
||||
* @param peerAddresses the set of discovered {@link PeerAddress}es
|
||||
*/
|
||||
void onPeersDiscovered(Set<PeerAddress> peerAddresses);
|
||||
public interface PeerDataEventListener {
|
||||
|
||||
// TODO: Fix the Block/FilteredBlock type hierarchy so we can avoid the stupid typeless API here.
|
||||
/**
|
||||
|
@ -55,26 +54,6 @@ public interface PeerEventListener {
|
|||
*/
|
||||
void onChainDownloadStarted(Peer peer, int blocksLeft);
|
||||
|
||||
/**
|
||||
* Called when a peer is connected. If this listener is registered to a {@link Peer} instead of a {@link PeerGroup},
|
||||
* peerCount will always be 1.
|
||||
*
|
||||
* @param peer
|
||||
* @param peerCount the total number of connected peers
|
||||
*/
|
||||
void onPeerConnected(Peer peer, int peerCount);
|
||||
|
||||
/**
|
||||
* Called when a peer is disconnected. Note that this won't be called if the listener is registered on a
|
||||
* {@link PeerGroup} and the group is in the process of shutting down. If this listener is registered to a
|
||||
* {@link Peer} instead of a {@link PeerGroup}, peerCount will always be 0. This handler can be called without
|
||||
* a corresponding invocation of onPeerConnected if the initial connection is never successful.
|
||||
*
|
||||
* @param peer
|
||||
* @param peerCount the total number of connected peers
|
||||
*/
|
||||
void onPeerDisconnected(Peer peer, int peerCount);
|
||||
|
||||
/**
|
||||
* <p>Called when a message is received by a peer, before the message is processed. The returned message is
|
||||
* processed instead. Returning null will cause the message to be ignored by the Peer returning the same message
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2011 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 java.util.List;
|
||||
import org.bitcoinj.core.StoredBlock;
|
||||
import org.bitcoinj.core.VerificationException;
|
||||
|
||||
/**
|
||||
* Listener interface for when the best chain has changed.
|
||||
*/
|
||||
public interface ReorganizeListener {
|
||||
|
||||
/**
|
||||
* Called by the {@link BlockChain} when the best chain (representing total work done) has changed. In this case,
|
||||
* we need to go through our transactions and find out if any have become invalid. It's possible for our balance
|
||||
* to go down in this case: money we thought we had can suddenly vanish if the rest of the network agrees it
|
||||
* should be so.<p>
|
||||
*
|
||||
* The oldBlocks/newBlocks lists are ordered height-wise from top first to bottom last (i.e. newest blocks first).
|
||||
*/
|
||||
void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks,
|
||||
List<StoredBlock> newBlocks) throws VerificationException;
|
||||
}
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
/*
|
||||
* Copyright 2011 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
|
||||
* 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,
|
||||
|
@ -13,38 +13,20 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.bitcoinj.core.listeners;
|
||||
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import java.util.List;
|
||||
import org.bitcoinj.core.BlockChain;
|
||||
import org.bitcoinj.core.ScriptException;
|
||||
import org.bitcoinj.core.Sha256Hash;
|
||||
import org.bitcoinj.core.StoredBlock;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.VerificationException;
|
||||
|
||||
/**
|
||||
* Implementors can be connected to a {@link BlockChain} and have its methods called when various things
|
||||
* happen that modify the state of the chain, for example: new blocks being received, a re-org occurring, or the
|
||||
* best chain head changing.
|
||||
* Listener interface for when we receive a new block that contains a relevant
|
||||
* transaction.
|
||||
*/
|
||||
public interface BlockChainListener {
|
||||
/**
|
||||
* Called when a new block on the best chain is seen, after relevant transactions are extracted and sent to
|
||||
* us via either {@link #receiveFromBlock(Transaction, StoredBlock, org.bitcoinj.core.BlockChain.NewBlockType, int)}
|
||||
* or {@link #notifyTransactionIsInBlock(Sha256Hash, StoredBlock, org.bitcoinj.core.BlockChain.NewBlockType, int)}.
|
||||
* If this block is causing a re-organise to a new chain, this method is NOT called even though the block may be
|
||||
* the new best block: your reorganize implementation is expected to do whatever would normally be done do for a new
|
||||
* best block in this case.
|
||||
*/
|
||||
void notifyNewBestBlock(StoredBlock block) throws VerificationException;
|
||||
|
||||
/**
|
||||
* Called by the {@link BlockChain} when the best chain (representing total work done) has changed. In this case,
|
||||
* we need to go through our transactions and find out if any have become invalid. It's possible for our balance
|
||||
* to go down in this case: money we thought we had can suddenly vanish if the rest of the network agrees it
|
||||
* should be so.<p>
|
||||
*
|
||||
* The oldBlocks/newBlocks lists are ordered height-wise from top first to bottom last (i.e. newest blocks first).
|
||||
*/
|
||||
void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks,
|
||||
List<StoredBlock> newBlocks) throws VerificationException;
|
||||
|
||||
public interface TransactionReceivedInBlockListener {
|
||||
/**
|
||||
* <p>Called by the {@link BlockChain} when we receive a new block that contains a relevant transaction.</p>
|
||||
*
|
||||
|
@ -61,7 +43,6 @@ public interface BlockChainListener {
|
|||
void receiveFromBlock(Transaction tx, StoredBlock block,
|
||||
BlockChain.NewBlockType blockType,
|
||||
int relativityOffset) throws VerificationException;
|
||||
|
||||
/**
|
||||
* <p>Called by the {@link BlockChain} when we receive a new {@link FilteredBlock} that contains the given
|
||||
* transaction hash in its merkle tree.</p>
|
|
@ -14,8 +14,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoinj.core;
|
||||
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;
|
||||
|
||||
|
@ -25,40 +27,7 @@ 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 WalletEventListener extends KeyChainEventListener {
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* This is called when a transaction is seen that sends coins <b>from</b> this wallet, either
|
||||
* because it was broadcast across the network or because a block was received. This may at first glance seem
|
||||
* useless, because in the common case you already know about such transactions because you created them with
|
||||
* the Wallets createSend/sendCoins methods. However when you have a wallet containing only keys, and you wish
|
||||
* to replay the block chain to fill it with transactions, it's useful to find out when a transaction is discovered
|
||||
* that sends coins from the wallet.<p>
|
||||
*
|
||||
* It's safe to modify the wallet from inside this callback, but if you're replaying the block chain you should
|
||||
* be careful to avoid such modifications. Otherwise your changes may be overridden by new data from the chain.
|
||||
*
|
||||
* @param wallet The wallet object that this callback relates to (that sent the coins).
|
||||
* @param tx The transaction that sent the coins to someone else.
|
||||
* @param prevBalance The wallets balance before this transaction was seen.
|
||||
* @param newBalance The wallets balance after this transaction was seen. This is the 'estimated' balance.
|
||||
*/
|
||||
void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
|
||||
|
||||
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>
|
|
@ -0,0 +1,64 @@
|
|||
/**
|
||||
* 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;
|
||||
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);
|
||||
|
||||
/**
|
||||
* This is called when a transaction is seen that sends coins <b>from</b> this wallet, either
|
||||
* because it was broadcast across the network or because a block was received. This may at first glance seem
|
||||
* useless, because in the common case you already know about such transactions because you created them with
|
||||
* the Wallets createSend/sendCoins methods. However when you have a wallet containing only keys, and you wish
|
||||
* to replay the block chain to fill it with transactions, it's useful to find out when a transaction is discovered
|
||||
* that sends coins from the wallet.<p>
|
||||
*
|
||||
* It's safe to modify the wallet from inside this callback, but if you're replaying the block chain you should
|
||||
* be careful to avoid such modifications. Otherwise your changes may be overridden by new data from the chain.
|
||||
*
|
||||
* @param wallet The wallet object that this callback relates to (that sent the coins).
|
||||
* @param tx The transaction that sent the coins to someone else.
|
||||
* @param prevBalance The wallets balance before this transaction was seen.
|
||||
* @param newBalance The wallets balance after this transaction was seen. This is the 'estimated' balance.
|
||||
*/
|
||||
void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* <p>Common interface for wallet changes and transactions. For fine-grain
|
||||
* events please use the super-interfaces.</p>
|
||||
*/
|
||||
public interface WalletEventListener extends WalletChangeEventListener, WalletCoinEventListener {
|
||||
}
|
|
@ -19,13 +19,16 @@ package org.bitcoinj.jni;
|
|||
import org.bitcoinj.core.*;
|
||||
|
||||
import java.util.List;
|
||||
import org.bitcoinj.core.listeners.NewBestBlockListener;
|
||||
import org.bitcoinj.core.listeners.ReorganizeListener;
|
||||
import org.bitcoinj.core.listeners.TransactionReceivedInBlockListener;
|
||||
|
||||
/**
|
||||
* 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 NativeBlockChainListener implements BlockChainListener {
|
||||
public class NativeBlockChainListener implements NewBestBlockListener, ReorganizeListener, TransactionReceivedInBlockListener {
|
||||
public long ptr;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
package org.bitcoinj.jni;
|
||||
|
||||
import org.bitcoinj.core.listeners.PeerConnectionEventListener;
|
||||
import org.bitcoinj.core.listeners.PeerDataEventListener;
|
||||
import org.bitcoinj.core.*;
|
||||
|
||||
import javax.annotation.*;
|
||||
|
@ -27,7 +29,7 @@ import java.util.Set;
|
|||
* this class using JNI on the native side, thus several instances of this can point to different actual
|
||||
* native implementations.
|
||||
*/
|
||||
public class NativePeerEventListener implements PeerEventListener {
|
||||
public class NativePeerEventListener implements PeerConnectionEventListener, PeerDataEventListener {
|
||||
public long ptr;
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
package org.bitcoinj.jni;
|
||||
|
||||
import org.bitcoinj.core.listeners.WalletEventListener;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.ECKey;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.Wallet;
|
||||
import org.bitcoinj.core.WalletEventListener;
|
||||
import org.bitcoinj.script.Script;
|
||||
|
||||
import java.util.List;
|
||||
|
|
|
@ -20,6 +20,8 @@ package org.bitcoinj.kits;
|
|||
import com.google.common.collect.*;
|
||||
import com.google.common.util.concurrent.*;
|
||||
import com.subgraph.orchid.*;
|
||||
import org.bitcoinj.core.listeners.DownloadProgressTracker;
|
||||
import org.bitcoinj.core.listeners.PeerDataEventListener;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.net.discovery.*;
|
||||
import org.bitcoinj.params.*;
|
||||
|
@ -74,7 +76,7 @@ public class WalletAppKit extends AbstractIdleService {
|
|||
|
||||
protected boolean useAutoSave = true;
|
||||
protected PeerAddress[] peerAddresses;
|
||||
protected PeerEventListener downloadListener;
|
||||
protected PeerDataEventListener downloadListener;
|
||||
protected boolean autoStop = true;
|
||||
protected InputStream checkpoints;
|
||||
protected boolean blockingStartup = true;
|
||||
|
@ -133,7 +135,7 @@ public class WalletAppKit extends AbstractIdleService {
|
|||
* {@link org.bitcoinj.core.DownloadProgressTracker} is a good choice. This has no effect unless setBlockingStartup(false) has been called
|
||||
* too, due to some missing implementation code.
|
||||
*/
|
||||
public WalletAppKit setDownloadListener(PeerEventListener listener) {
|
||||
public WalletAppKit setDownloadListener(PeerDataEventListener listener) {
|
||||
this.downloadListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
@ -339,7 +341,7 @@ public class WalletAppKit extends AbstractIdleService {
|
|||
@Override
|
||||
public void onSuccess(@Nullable Object result) {
|
||||
completeExtensionInitiations(vPeerGroup);
|
||||
final PeerEventListener l = downloadListener == null ? new DownloadProgressTracker() : downloadListener;
|
||||
final PeerDataEventListener l = downloadListener == null ? new DownloadProgressTracker() : downloadListener;
|
||||
vPeerGroup.startBlockChainDownload(l);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
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;
|
||||
|
@ -172,7 +173,7 @@ public class PaymentChannelClientState {
|
|||
if (storedChannel != null && storedChannel.close != null) {
|
||||
watchCloseConfirmations();
|
||||
}
|
||||
wallet.addEventListener(new AbstractWalletEventListener() {
|
||||
wallet.addEventListener(Threading.SAME_THREAD, new AbstractWalletEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
synchronized (PaymentChannelClientState.this) {
|
||||
|
@ -188,7 +189,7 @@ public class PaymentChannelClientState {
|
|||
}
|
||||
}
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
}
|
||||
|
||||
private void watchCloseConfirmations() {
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
|
||||
package org.bitcoinj.testing;
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractPeerConnectionEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerDataEventListener;
|
||||
import org.bitcoinj.core.listeners.PeerDataEventListener;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.net.*;
|
||||
import org.bitcoinj.params.UnitTestParams;
|
||||
|
@ -147,7 +150,7 @@ public class TestWithNetworkConnections {
|
|||
checkArgument(versionMessage.hasBlockChain());
|
||||
final AtomicBoolean doneConnecting = new AtomicBoolean(false);
|
||||
final Thread thisThread = Thread.currentThread();
|
||||
peer.addEventListener(new AbstractPeerEventListener() {
|
||||
peer.addConnectionEventListener(new AbstractPeerConnectionEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer p, int peerCount) {
|
||||
synchronized (doneConnecting) {
|
||||
|
@ -205,7 +208,7 @@ public class TestWithNetworkConnections {
|
|||
private void inboundPongAndWait(final InboundMessageQueuer p, final long nonce) throws Exception {
|
||||
// Receive a ping (that the Peer doesn't see) and wait for it to get through the socket
|
||||
final SettableFuture<Void> pongReceivedFuture = SettableFuture.create();
|
||||
PeerEventListener listener = new AbstractPeerEventListener() {
|
||||
PeerDataEventListener listener = new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer p, Message m) {
|
||||
if (m instanceof Pong && ((Pong) m).getNonce() == nonce) {
|
||||
|
@ -215,10 +218,10 @@ public class TestWithNetworkConnections {
|
|||
return m;
|
||||
}
|
||||
};
|
||||
p.peer.addEventListener(listener, Threading.SAME_THREAD);
|
||||
p.peer.addDataEventListener(Threading.SAME_THREAD, listener);
|
||||
inbound(p, new Pong(nonce));
|
||||
pongReceivedFuture.get();
|
||||
p.peer.removeEventListener(listener);
|
||||
p.peer.removeDataEventListener(listener);
|
||||
}
|
||||
|
||||
protected void pingAndWait(final InboundMessageQueuer p) throws Exception {
|
||||
|
|
|
@ -28,7 +28,7 @@ public class ListenerRegistration<T> {
|
|||
public final T listener;
|
||||
public final Executor executor;
|
||||
|
||||
public ListenerRegistration(T listener, Executor executor) {
|
||||
public ListenerRegistration(Executor executor, T listener) {
|
||||
this.listener = checkNotNull(listener);
|
||||
this.executor = checkNotNull(executor);
|
||||
}
|
||||
|
|
|
@ -406,7 +406,7 @@ public class BasicKeyChain implements EncryptableKeyChain {
|
|||
|
||||
@Override
|
||||
public void addEventListener(KeyChainEventListener listener, Executor executor) {
|
||||
listeners.add(new ListenerRegistration<KeyChainEventListener>(listener, executor));
|
||||
listeners.add(new ListenerRegistration<KeyChainEventListener>(executor, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,10 +21,10 @@ import com.google.common.base.Preconditions;
|
|||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import com.google.common.util.concurrent.Uninterruptibles;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerEventListener;
|
||||
import org.bitcoinj.net.NioClient;
|
||||
import org.bitcoinj.params.RegTestParams;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
import org.bitcoinj.store.FullPrunedBlockStore;
|
||||
import org.bitcoinj.store.H2FullPrunedBlockStore;
|
||||
import org.bitcoinj.store.MemoryBlockStore;
|
||||
import org.bitcoinj.utils.BlockFileLoader;
|
||||
|
@ -94,7 +94,7 @@ public class BitcoindComparisonTool {
|
|||
final Set<Sha256Hash> blocksPendingSend = Collections.synchronizedSet(new HashSet<Sha256Hash>());
|
||||
final AtomicInteger unexpectedInvs = new AtomicInteger(0);
|
||||
final SettableFuture<Void> connectedFuture = SettableFuture.create();
|
||||
bitcoind.addEventListener(new AbstractPeerEventListener() {
|
||||
final AbstractPeerEventListener listener = new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
if (!peer.getPeerVersionMessage().subVer.contains("Satoshi")) {
|
||||
|
@ -203,7 +203,9 @@ public class BitcoindComparisonTool {
|
|||
}
|
||||
return m;
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
};
|
||||
bitcoind.addConnectionEventListener(Threading.SAME_THREAD, listener);
|
||||
bitcoind.addDataEventListener(Threading.SAME_THREAD, listener);
|
||||
|
||||
|
||||
bitcoindChainHead = params.getGenesisBlock().getHash();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
|
||||
import org.bitcoinj.params.UnitTestParams;
|
||||
import org.bitcoinj.store.MemoryBlockStore;
|
||||
|
@ -556,12 +557,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.addEventListener(Threading.SAME_THREAD, new AbstractWalletEventListener() {
|
||||
@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();
|
||||
|
@ -600,12 +601,12 @@ public class ChainSplitTest {
|
|||
Transaction fodder = wallet.createSend(new ECKey().toAddress(unitTestParams), FIFTY_COINS);
|
||||
wallet.commitTx(fodder);
|
||||
final AtomicBoolean fodderIsDead = new AtomicBoolean(false);
|
||||
fodder.getConfidence().addEventListener(new TransactionConfidence.Listener() {
|
||||
fodder.getConfidence().addEventListener(Threading.SAME_THREAD, new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
fodderIsDead.set(confidence.getConfidenceType() == ConfidenceType.DEAD);
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
|
||||
// Fork like this:
|
||||
//
|
||||
|
|
|
@ -20,6 +20,9 @@ package org.bitcoinj.core;
|
|||
import com.google.common.collect.*;
|
||||
import com.google.common.net.*;
|
||||
import com.google.common.util.concurrent.*;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerConnectionEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerDataEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerEventListener;
|
||||
import org.bitcoinj.net.discovery.*;
|
||||
import org.bitcoinj.testing.*;
|
||||
import org.bitcoinj.utils.*;
|
||||
|
@ -43,7 +46,7 @@ import static org.junit.Assert.*;
|
|||
public class PeerGroupTest extends TestWithPeerGroup {
|
||||
private BlockingQueue<Peer> connectedPeers;
|
||||
private BlockingQueue<Peer> disconnectedPeers;
|
||||
private PeerEventListener listener;
|
||||
private AbstractPeerEventListener listener;
|
||||
private Map<Peer, AtomicInteger> peerToMessageCount;
|
||||
|
||||
@Parameterized.Parameters
|
||||
|
@ -97,7 +100,8 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
@Test
|
||||
public void listener() throws Exception {
|
||||
peerGroup.start();
|
||||
peerGroup.addEventListener(listener);
|
||||
peerGroup.addConnectionEventListener(listener);
|
||||
peerGroup.addDataEventListener(listener);
|
||||
|
||||
// Create a couple of peers.
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
|
@ -117,8 +121,10 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
disconnectedPeers.take();
|
||||
assertEquals(0, disconnectedPeers.size());
|
||||
|
||||
assertTrue(peerGroup.removeEventListener(listener));
|
||||
assertFalse(peerGroup.removeEventListener(listener));
|
||||
assertTrue(peerGroup.removeConnectionEventListener(listener));
|
||||
assertFalse(peerGroup.removeConnectionEventListener(listener));
|
||||
assertTrue(peerGroup.removeDataEventListener(listener));
|
||||
assertFalse(peerGroup.removeDataEventListener(listener));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -174,7 +180,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
peerGroup.addPeerDiscovery(createPeerDiscovery(96, 200));
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(3, 300));
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(1, 400));
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
peerGroup.addConnectionEventListener(new AbstractPeerConnectionEventListener() {
|
||||
@Override
|
||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
||||
assertEquals(99, peerAddresses.size());
|
||||
|
@ -284,7 +290,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
assertNull(outbound(p2));
|
||||
// Peer 1 goes away, peer 2 becomes the download peer and thus queries the remote mempool.
|
||||
final SettableFuture<Void> p1CloseFuture = SettableFuture.create();
|
||||
peerOf(p1).addEventListener(new AbstractPeerEventListener() {
|
||||
peerOf(p1).addConnectionEventListener(new AbstractPeerConnectionEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
p1CloseFuture.set(null);
|
||||
|
@ -313,7 +319,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
Block b3 = FakeTxBuilder.makeSolvedTestBlock(b2);
|
||||
|
||||
// Expect a zero hash getblocks on p1. This is how the process starts.
|
||||
peerGroup.startBlockChainDownload(new AbstractPeerEventListener() {
|
||||
peerGroup.startBlockChainDownload(new AbstractPeerDataEventListener() {
|
||||
});
|
||||
GetBlocksMessage getblocks = (GetBlocksMessage) outbound(p1);
|
||||
assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash());
|
||||
|
@ -341,12 +347,12 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
|
||||
final Transaction[] event = new Transaction[1];
|
||||
final TransactionConfidence[] confEvent = new TransactionConfidence[1];
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
peerGroup.addDataEventListener(Threading.SAME_THREAD, new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public void onTransaction(Peer peer, Transaction t) {
|
||||
event[0] = t;
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
|
@ -489,7 +495,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
|
||||
final SettableFuture<Void> peerConnectedFuture = SettableFuture.create();
|
||||
final SettableFuture<Void> peerDisconnectedFuture = SettableFuture.create();
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
peerGroup.addConnectionEventListener(Threading.SAME_THREAD, new AbstractPeerConnectionEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
peerConnectedFuture.set(null);
|
||||
|
@ -499,7 +505,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
peerDisconnectedFuture.set(null);
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
// connect to peer but don't do handshake
|
||||
long start = System.currentTimeMillis(); // before connection so we don't get elapsed < timeout
|
||||
connectPeerWithoutVersionExchange(0);
|
||||
|
@ -524,7 +530,8 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
|||
new InetSocketAddress("localhost", 2001),
|
||||
new InetSocketAddress("localhost", 2002)
|
||||
);
|
||||
peerGroup.addEventListener(listener);
|
||||
peerGroup.addConnectionEventListener(listener);
|
||||
peerGroup.addDataEventListener(listener);
|
||||
peerGroup.addPeerDiscovery(new PeerDiscovery() {
|
||||
@Override
|
||||
public InetSocketAddress[] getPeers(long unused, TimeUnit unused2) throws PeerDiscoveryException {
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
package org.bitcoinj.core;
|
||||
|
||||
import com.google.common.collect.*;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerConnectionEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerDataEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.listeners.PeerConnectionEventListener;
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
import org.bitcoinj.testing.FakeTxBuilder;
|
||||
import org.bitcoinj.testing.InboundMessageQueuer;
|
||||
|
@ -103,10 +107,11 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
@Test
|
||||
public void testAddEventListener() throws Exception {
|
||||
connect();
|
||||
PeerEventListener listener = new AbstractPeerEventListener();
|
||||
peer.addEventListener(listener);
|
||||
assertTrue(peer.removeEventListener(listener));
|
||||
assertFalse(peer.removeEventListener(listener));
|
||||
PeerConnectionEventListener listener = new AbstractPeerConnectionEventListener() {
|
||||
};
|
||||
peer.addConnectionEventListener(listener);
|
||||
assertTrue(peer.removeConnectionEventListener(listener));
|
||||
assertFalse(peer.removeConnectionEventListener(listener));
|
||||
}
|
||||
|
||||
// Check that it runs through the event loop and shut down correctly
|
||||
|
@ -313,7 +318,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
connect();
|
||||
// Round-trip a ping so that we never see the response verack if we attach too quick
|
||||
pingAndWait(writeTarget);
|
||||
peer.addEventListener(new AbstractPeerEventListener() {
|
||||
peer.addDataEventListener(Threading.SAME_THREAD, new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public synchronized Message onPreMessageReceived(Peer p, Message m) {
|
||||
if (p != peer)
|
||||
|
@ -336,7 +341,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
if (newValue != 3 || p != peer || !block.equals(b2) || blocksLeft != OTHER_PEER_CHAIN_HEIGHT - 2)
|
||||
fail.set(true);
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
long height = peer.getBestHeight();
|
||||
|
||||
inbound(writeTarget, inv);
|
||||
|
@ -367,13 +372,13 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
|
||||
connect();
|
||||
fail.set(true);
|
||||
peer.addEventListener(new AbstractPeerEventListener() {
|
||||
peer.addDataEventListener(Threading.SAME_THREAD, new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public void onChainDownloadStarted(Peer p, int blocksLeft) {
|
||||
if (p == peer && blocksLeft == 108)
|
||||
fail.set(false);
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
peer.startBlockChainDownload();
|
||||
|
||||
List<Sha256Hash> expectedLocator = new ArrayList<Sha256Hash>();
|
||||
|
@ -544,12 +549,12 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
ECKey to = new ECKey();
|
||||
|
||||
final Transaction[] onTx = new Transaction[1];
|
||||
peer.addEventListener(new AbstractPeerEventListener() {
|
||||
peer.addDataEventListener(Threading.SAME_THREAD, new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public void onTransaction(Peer peer1, Transaction t) {
|
||||
onTx[0] = t;
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
|
||||
// Make some fake transactions in the following graph:
|
||||
// t1 -> t2 -> [t5]
|
||||
|
@ -746,7 +751,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
// Set up the connection with an old version.
|
||||
final SettableFuture<Void> connectedFuture = SettableFuture.create();
|
||||
final SettableFuture<Void> disconnectedFuture = SettableFuture.create();
|
||||
peer.addEventListener(new AbstractPeerEventListener() {
|
||||
peer.addConnectionEventListener(new AbstractPeerConnectionEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
connectedFuture.set(null);
|
||||
|
@ -856,7 +861,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
|||
};
|
||||
connect(); // Writes out a verack+version.
|
||||
final SettableFuture<Void> peerDisconnected = SettableFuture.create();
|
||||
writeTarget.peer.addEventListener(new AbstractPeerEventListener() {
|
||||
writeTarget.peer.addConnectionEventListener(new AbstractPeerConnectionEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer p, int peerCount) {
|
||||
peerDisconnected.set(null);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.bitcoinj.core;
|
||||
|
||||
import com.google.common.util.concurrent.*;
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.params.*;
|
||||
import org.bitcoinj.testing.*;
|
||||
import org.bitcoinj.utils.*;
|
||||
|
|
|
@ -57,12 +57,12 @@ public class TxConfidenceTableTest {
|
|||
table.seen(hash, address1);
|
||||
assertEquals(1, tx.getConfidence().numBroadcastPeers());
|
||||
final int[] seen = new int[1];
|
||||
tx.getConfidence().addEventListener(new TransactionConfidence.Listener() {
|
||||
tx.getConfidence().addEventListener(Threading.SAME_THREAD, new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
seen[0] = confidence.numBroadcastPeers();
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
tx = null;
|
||||
System.gc();
|
||||
table.seen(hash, address2);
|
||||
|
@ -72,12 +72,12 @@ public class TxConfidenceTableTest {
|
|||
@Test
|
||||
public void events() throws Exception {
|
||||
final TransactionConfidence.Listener.ChangeReason[] run = new TransactionConfidence.Listener.ChangeReason[1];
|
||||
tx1.getConfidence().addEventListener(new TransactionConfidence.Listener() {
|
||||
tx1.getConfidence().addEventListener(Threading.SAME_THREAD, new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
run[0] = reason;
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
table.seen(tx1.getHash(), address1);
|
||||
assertEquals(TransactionConfidence.Listener.ChangeReason.SEEN_PEERS, run[0]);
|
||||
run[0] = null;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.bitcoinj.core;
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.listeners.WalletCoinEventListener;
|
||||
import org.bitcoinj.core.Wallet.SendRequest;
|
||||
import org.bitcoinj.crypto.*;
|
||||
import org.bitcoinj.script.Script;
|
||||
|
@ -409,11 +411,16 @@ public class WalletTest extends TestWithWallet {
|
|||
|
||||
private static void broadcastAndCommit(Wallet wallet, Transaction t) throws Exception {
|
||||
final LinkedList<Transaction> txns = Lists.newLinkedList();
|
||||
wallet.addEventListener(new AbstractWalletEventListener() {
|
||||
wallet.addCoinEventListener(new WalletCoinEventListener() {
|
||||
@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(InetAddress.getByAddress(new byte[]{1,2,3,4})));
|
||||
|
@ -782,8 +789,8 @@ public class WalletTest extends TestWithWallet {
|
|||
dead.add(confidence);
|
||||
}
|
||||
};
|
||||
send2.getConfidence().addEventListener(listener, Threading.SAME_THREAD);
|
||||
send3.getConfidence().addEventListener(listener, Threading.SAME_THREAD);
|
||||
send2.getConfidence().addEventListener(Threading.SAME_THREAD, listener);
|
||||
send3.getConfidence().addEventListener(Threading.SAME_THREAD, listener);
|
||||
// Double spend!
|
||||
sendMoneyToWallet(send1, AbstractBlockChain.NewBlockType.BEST_CHAIN);
|
||||
// Back to having one coin.
|
||||
|
@ -934,13 +941,18 @@ 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.addEventListener(new AbstractWalletEventListener() {
|
||||
wallet.addCoinEventListener(new WalletCoinEventListener() {
|
||||
@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;
|
||||
|
@ -2535,20 +2547,30 @@ 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.addEventListener(new AbstractWalletEventListener() {
|
||||
wallet.addCoinEventListener(new WalletCoinEventListener() {
|
||||
@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.addEventListener(new AbstractWalletEventListener() {
|
||||
wallet.addCoinEventListener(new WalletCoinEventListener() {
|
||||
@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);
|
||||
|
@ -2993,12 +3015,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.addEventListener(Threading.SAME_THREAD, new AbstractWalletEventListener() {
|
||||
@Override
|
||||
public void onKeysAdded(List<ECKey> k) {
|
||||
keys.addAll(k);
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
wallet.freshReceiveKey();
|
||||
assertEquals(1, keys.size());
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package org.bitcoinj.store;
|
||||
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.core.Transaction.Purpose;
|
||||
import org.bitcoinj.core.TransactionConfidence.ConfidenceType;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
package org.bitcoinj.examples;
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractPeerEventListener;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.kits.WalletAppKit;
|
||||
import org.bitcoinj.params.RegTestParams;
|
||||
|
@ -45,13 +46,15 @@ public class DoubleSpend {
|
|||
Transaction tx1 = kit.wallet().createSend(Address.fromBase58(params, "muYPFNCv7KQEG2ZLM7Z3y96kJnNyXJ53wm"), CENT);
|
||||
Transaction tx2 = kit.wallet().createSend(Address.fromBase58(params, "muYPFNCv7KQEG2ZLM7Z3y96kJnNyXJ53wm"), CENT.add(SATOSHI.multiply(10)));
|
||||
final Peer peer = kit.peerGroup().getConnectedPeers().get(0);
|
||||
peer.addEventListener(new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
||||
System.err.println("Got a message!" + m.getClass().getSimpleName() + ": " + m);
|
||||
return m;
|
||||
peer.addDataEventListener(Threading.SAME_THREAD,
|
||||
new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
||||
System.err.println("Got a message!" + m.getClass().getSimpleName() + ": " + m);
|
||||
return m;
|
||||
}
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
);
|
||||
peer.sendMessage(tx1);
|
||||
peer.sendMessage(tx2);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.bitcoinj.examples;
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.crypto.KeyCrypterException;
|
||||
import org.bitcoinj.kits.WalletAppKit;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
package org.bitcoinj.examples;
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.kits.WalletAppKit;
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package org.bitcoinj.examples;
|
||||
|
||||
import org.bitcoinj.core.AbstractPeerEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerEventListener;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Peer;
|
||||
import org.bitcoinj.core.PeerGroup;
|
||||
|
@ -67,7 +67,7 @@ public class PeerMonitor {
|
|||
peerGroup.setUserAgent("PeerMonitor", "1.0");
|
||||
peerGroup.setMaxConnections(4);
|
||||
peerGroup.addPeerDiscovery(new DnsDiscovery(params));
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
peerGroup.addConnectionEventListener(new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(final Peer peer, int peerCount) {
|
||||
refreshUI();
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
package org.bitcoinj.examples;
|
||||
|
||||
import org.bitcoinj.core.AbstractPeerEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerEventListener;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Peer;
|
||||
import org.bitcoinj.core.PeerAddress;
|
||||
|
@ -84,7 +84,7 @@ public class PrintPeers {
|
|||
final Peer peer = new Peer(params, new VersionMessage(params, 0), null, new PeerAddress(address));
|
||||
final SettableFuture<Void> future = SettableFuture.create();
|
||||
// Once the connection has completed version handshaking ...
|
||||
peer.addEventListener(new AbstractPeerEventListener() {
|
||||
peer.addConnectionEventListener(new AbstractPeerEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer p, int peerCount) {
|
||||
// Check the chain height it claims to have.
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.bitcoinj.examples;
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
import org.bitcoinj.store.BlockStore;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
package org.bitcoinj.examples;
|
||||
|
||||
import org.bitcoinj.core.listeners.DownloadProgressTracker;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.net.discovery.DnsDiscovery;
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
package org.bitcoinj.tools;
|
||||
|
||||
import org.bitcoinj.core.listeners.NewBestBlockListener;
|
||||
import org.bitcoinj.core.*;
|
||||
import org.bitcoinj.params.MainNetParams;
|
||||
import org.bitcoinj.params.RegTestParams;
|
||||
|
@ -120,7 +121,7 @@ public class BuildCheckpoints {
|
|||
final long timeAgo = now - (86400 * options.valueOf(daysFlag));
|
||||
System.out.println("Checkpointing up to " + Utils.dateTimeFormat(timeAgo * 1000));
|
||||
|
||||
chain.addListener(new AbstractBlockChainListener() {
|
||||
chain.addNewBestBlockListener(Threading.SAME_THREAD, new NewBestBlockListener() {
|
||||
@Override
|
||||
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
|
||||
int height = block.getHeight();
|
||||
|
@ -130,7 +131,7 @@ public class BuildCheckpoints {
|
|||
checkpoints.put(height, block);
|
||||
}
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
});
|
||||
|
||||
peerGroup.start();
|
||||
peerGroup.downloadBlockChain();
|
||||
|
|
|
@ -50,6 +50,9 @@ import joptsimple.OptionSet;
|
|||
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;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -751,7 +754,7 @@ public class WalletTool {
|
|||
break;
|
||||
|
||||
case BLOCK:
|
||||
peers.addEventListener(new AbstractPeerEventListener() {
|
||||
peers.addDataEventListener(new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public void onBlocksDownloaded(Peer peer, Block block, @Nullable FilteredBlock filteredBlock, int blocksLeft) {
|
||||
// Check if we already ran. This can happen if a block being received triggers download of more
|
||||
|
|
|
@ -20,7 +20,7 @@ package org.bitcoinj.tools;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bitcoinj.core.AbstractPeerEventListener;
|
||||
import org.bitcoinj.core.listeners.AbstractPeerDataEventListener;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Peer;
|
||||
import org.bitcoinj.core.PeerGroup;
|
||||
|
@ -49,7 +49,7 @@ public class WatchMempool {
|
|||
PeerGroup peerGroup = new PeerGroup(PARAMS);
|
||||
peerGroup.setMaxConnections(32);
|
||||
peerGroup.addPeerDiscovery(new DnsDiscovery(PARAMS));
|
||||
peerGroup.addEventListener(new AbstractPeerEventListener() {
|
||||
peerGroup.addDataEventListener(new AbstractPeerDataEventListener() {
|
||||
@Override
|
||||
public void onTransaction(Peer peer, Transaction tx) {
|
||||
Result result = DefaultRiskAnalysis.FACTORY.create(null, tx, NO_DEPS).analyze();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package wallettemplate;
|
||||
|
||||
import org.bitcoinj.core.listeners.DownloadProgressTracker;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.DownloadProgressTracker;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
import com.subgraph.orchid.TorClient;
|
||||
import com.subgraph.orchid.TorInitializationListener;
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package wallettemplate.utils;
|
||||
|
||||
import org.bitcoinj.core.listeners.AbstractWalletEventListener;
|
||||
import org.bitcoinj.core.listeners.DownloadProgressTracker;
|
||||
import org.bitcoinj.core.*;
|
||||
import javafx.application.Platform;
|
||||
import javafx.beans.property.ReadOnlyDoubleProperty;
|
||||
|
@ -26,13 +28,15 @@ public class BitcoinUIModel {
|
|||
}
|
||||
|
||||
public void setWallet(Wallet wallet) {
|
||||
wallet.addEventListener(new AbstractWalletEventListener() {
|
||||
@Override
|
||||
public void onWalletChanged(Wallet wallet) {
|
||||
super.onWalletChanged(wallet);
|
||||
update(wallet);
|
||||
wallet.addEventListener(Platform::runLater,
|
||||
new AbstractWalletEventListener() {
|
||||
@Override
|
||||
public void onWalletChanged(Wallet wallet) {
|
||||
super.onWalletChanged(wallet);
|
||||
update(wallet);
|
||||
}
|
||||
}
|
||||
}, Platform::runLater);
|
||||
);
|
||||
update(wallet);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue