mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-01-19 05:33:44 +01:00
apply "Anonmyous type can be replaced with lambda" refactoring
This commit is contained in:
parent
7d1d7ecd09
commit
a31cbe0470
@ -661,20 +661,17 @@ public abstract class AbstractBlockChain {
|
||||
} 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 {
|
||||
// We can't do false-positive handling when executing on another thread
|
||||
Set<Sha256Hash> ignoredFalsePositives = new HashSet<>();
|
||||
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.
|
||||
}
|
||||
registration.executor.execute(() -> {
|
||||
try {
|
||||
// We can't do false-positive handling when executing on another thread
|
||||
Set<Sha256Hash> ignoredFalsePositives = new HashSet<>();
|
||||
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.
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -687,18 +684,15 @@ public abstract class AbstractBlockChain {
|
||||
registration.listener.notifyNewBestBlock(newStoredBlock);
|
||||
} else {
|
||||
// Listener wants to be run on some other thread, so marshal it across here.
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (newBlockType == NewBlockType.BEST_CHAIN)
|
||||
registration.listener.notifyNewBestBlock(newStoredBlock);
|
||||
} 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.
|
||||
}
|
||||
registration.executor.execute(() -> {
|
||||
try {
|
||||
if (newBlockType == NewBlockType.BEST_CHAIN)
|
||||
registration.listener.notifyNewBestBlock(newStoredBlock);
|
||||
} 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.
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -830,14 +824,11 @@ public abstract class AbstractBlockChain {
|
||||
// TODO: Do we really need to do this or should it be irrelevant?
|
||||
registration.listener.reorganize(splitPoint, oldBlocks, newBlocks);
|
||||
} else {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
registration.listener.reorganize(splitPoint, oldBlocks, newBlocks);
|
||||
} catch (VerificationException e) {
|
||||
log.error("Block chain listener threw exception during reorg", e);
|
||||
}
|
||||
registration.executor.execute(() -> {
|
||||
try {
|
||||
registration.listener.reorganize(splitPoint, oldBlocks, newBlocks);
|
||||
} catch (VerificationException e) {
|
||||
log.error("Block chain listener threw exception during reorg", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -232,12 +232,7 @@ public class Peer extends PeerSocketHandler {
|
||||
this.wallets = new CopyOnWriteArrayList<>();
|
||||
this.context = Context.get();
|
||||
|
||||
this.versionHandshakeFuture.addListener(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
versionHandshakeComplete();
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
this.versionHandshakeFuture.addListener(() -> versionHandshakeComplete(), Threading.SAME_THREAD);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -388,12 +383,7 @@ public class Peer extends PeerSocketHandler {
|
||||
@Override
|
||||
public void connectionClosed() {
|
||||
for (final ListenerRegistration<PeerDisconnectedEventListener> registration : disconnectedEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onPeerDisconnected(Peer.this, 0);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onPeerDisconnected(Peer.this, 0));
|
||||
}
|
||||
}
|
||||
|
||||
@ -573,12 +563,7 @@ public class Peer extends PeerSocketHandler {
|
||||
log.debug("{}: Handshake complete.", this);
|
||||
setTimeoutEnabled(false);
|
||||
for (final ListenerRegistration<PeerConnectedEventListener> registration : connectedEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onPeerConnected(Peer.this, 1);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onPeerConnected(Peer.this, 1));
|
||||
}
|
||||
// We check min version after onPeerConnected as channel.close() will
|
||||
// call onPeerDisconnected, and we should probably call onPeerConnected first.
|
||||
@ -802,12 +787,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<OnTransactionBroadcastListener> registration : onTransactionEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onTransaction(Peer.this, tx);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onTransaction(Peer.this, tx));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1122,12 +1102,7 @@ public class Peer extends PeerSocketHandler {
|
||||
// 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<BlocksDownloadedEventListener> registration : blocksDownloadedEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onBlocksDownloaded(Peer.this, block, fb, blocksLeft);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onBlocksDownloaded(Peer.this, block, fb, blocksLeft));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1460,12 +1435,7 @@ public class Peer extends PeerSocketHandler {
|
||||
final int blocksLeft = getPeerBlockHeightDifference();
|
||||
if (blocksLeft >= 0) {
|
||||
for (final ListenerRegistration<ChainDownloadStartedEventListener> registration : chainDownloadStartedEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onChainDownloadStarted(Peer.this, blocksLeft);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onChainDownloadStarted(Peer.this, blocksLeft));
|
||||
}
|
||||
// When we just want as many blocks as possible, we can set the target hash to zero.
|
||||
lock.lock();
|
||||
@ -1737,24 +1707,21 @@ public class Peer extends PeerSocketHandler {
|
||||
}
|
||||
// Ping/pong to wait for blocks that are still being streamed to us to finish being downloaded and
|
||||
// discarded.
|
||||
ping().addListener(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
lock.lock();
|
||||
checkNotNull(awaitingFreshFilter);
|
||||
GetDataMessage getdata = new GetDataMessage(params);
|
||||
for (Sha256Hash hash : awaitingFreshFilter)
|
||||
getdata.addFilteredBlock(hash);
|
||||
awaitingFreshFilter = null;
|
||||
lock.unlock();
|
||||
ping().addListener(() -> {
|
||||
lock.lock();
|
||||
checkNotNull(awaitingFreshFilter);
|
||||
GetDataMessage getdata = new GetDataMessage(params);
|
||||
for (Sha256Hash hash : awaitingFreshFilter)
|
||||
getdata.addFilteredBlock(hash);
|
||||
awaitingFreshFilter = null;
|
||||
lock.unlock();
|
||||
|
||||
log.info("Restarting chain download");
|
||||
sendMessage(getdata);
|
||||
// TODO: This bizarre ping-after-getdata hack probably isn't necessary.
|
||||
// It's to ensure we know when the end of a filtered block stream of txns is, but we should just be
|
||||
// able to match txns with the merkleblock. Ask Matt why it's written this way.
|
||||
sendMessage(new Ping((long) (Math.random() * Long.MAX_VALUE)));
|
||||
}
|
||||
log.info("Restarting chain download");
|
||||
sendMessage(getdata);
|
||||
// TODO: This bizarre ping-after-getdata hack probably isn't necessary.
|
||||
// It's to ensure we know when the end of a filtered block stream of txns is, but we should just be
|
||||
// able to match txns with the merkleblock. Ask Matt why it's written this way.
|
||||
sendMessage(new Ping((long) (Math.random() * Long.MAX_VALUE)));
|
||||
}, Threading.SAME_THREAD);
|
||||
} finally {
|
||||
lock.unlock();
|
||||
|
@ -169,31 +169,13 @@ public class PeerGroup implements TransactionBroadcaster {
|
||||
private final PeerListener peerListener = new PeerListener();
|
||||
|
||||
private int minBroadcastConnections = 0;
|
||||
private final ScriptsChangeEventListener walletScriptsEventListener = new ScriptsChangeEventListener() {
|
||||
@Override public void onScriptsChanged(Wallet wallet, List<Script> scripts, boolean isAddingScripts) {
|
||||
recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
|
||||
}
|
||||
};
|
||||
private final ScriptsChangeEventListener walletScriptsEventListener = (wallet, scripts, isAddingScripts) -> recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
|
||||
|
||||
private final KeyChainEventListener walletKeyEventListener = new KeyChainEventListener() {
|
||||
@Override public void onKeysAdded(List<ECKey> keys) {
|
||||
recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
|
||||
}
|
||||
};
|
||||
private final KeyChainEventListener walletKeyEventListener = keys -> recalculateFastCatchupAndFilter(FilterRecalculateMode.SEND_IF_CHANGED);
|
||||
|
||||
private final WalletCoinsReceivedEventListener walletCoinsReceivedEventListener = new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
onCoinsReceivedOrSent(wallet, tx);
|
||||
}
|
||||
};
|
||||
private final WalletCoinsReceivedEventListener walletCoinsReceivedEventListener = (wallet, tx, prevBalance, newBalance) -> onCoinsReceivedOrSent(wallet, tx);
|
||||
|
||||
private final WalletCoinsSentEventListener walletCoinsSentEventListener = new WalletCoinsSentEventListener() {
|
||||
@Override
|
||||
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
onCoinsReceivedOrSent(wallet, tx);
|
||||
}
|
||||
};
|
||||
private final WalletCoinsSentEventListener walletCoinsSentEventListener = (wallet, tx, prevBalance, newBalance) -> onCoinsReceivedOrSent(wallet, tx);
|
||||
|
||||
private void onCoinsReceivedOrSent(Wallet wallet, Transaction tx) {
|
||||
// We received a relevant transaction. We MAY need to recalculate and resend the Bloom filter, but only
|
||||
@ -395,12 +377,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
||||
);
|
||||
// Hack: jam the executor so jobs just queue up until the user calls start() on us. For example, adding a wallet
|
||||
// results in a bloom filter recalc being queued, but we don't want to do that until we're actually started.
|
||||
result.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Uninterruptibles.awaitUninterruptibly(executorStartupLatch);
|
||||
}
|
||||
});
|
||||
result.execute(() -> Uninterruptibles.awaitUninterruptibly(executorStartupLatch));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -995,12 +972,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
||||
}
|
||||
final ImmutableSet<PeerAddress> peersDiscoveredSet = ImmutableSet.copyOf(addressList);
|
||||
for (final ListenerRegistration<PeerDiscoveredEventListener> registration : peerDiscoveredEventListeners /* COW */) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onPeersDiscovered(peersDiscoveredSet);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onPeersDiscovered(peersDiscoveredSet));
|
||||
}
|
||||
}
|
||||
watch.stop();
|
||||
@ -1063,18 +1035,15 @@ public class PeerGroup implements TransactionBroadcaster {
|
||||
vUsedUp = true;
|
||||
executorStartupLatch.countDown();
|
||||
// We do blocking waits during startup, so run on the executor thread.
|
||||
return executor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
log.info("Starting ...");
|
||||
channels.startAsync();
|
||||
channels.awaitRunning();
|
||||
triggerConnections();
|
||||
setupPinging();
|
||||
} catch (Throwable e) {
|
||||
log.error("Exception when starting up", e); // The executor swallows exceptions :(
|
||||
}
|
||||
return executor.submit(() -> {
|
||||
try {
|
||||
log.info("Starting ...");
|
||||
channels.startAsync();
|
||||
channels.awaitRunning();
|
||||
triggerConnections();
|
||||
setupPinging();
|
||||
} catch (Throwable e) {
|
||||
log.error("Exception when starting up", e); // The executor swallows exceptions :(
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -1087,25 +1056,22 @@ public class PeerGroup implements TransactionBroadcaster {
|
||||
public ListenableFuture stopAsync() {
|
||||
checkState(vRunning);
|
||||
vRunning = false;
|
||||
ListenableFuture future = executor.submit(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
log.info("Stopping ...");
|
||||
Stopwatch watch = Stopwatch.createStarted();
|
||||
// The log output this creates can be useful.
|
||||
setDownloadPeer(null);
|
||||
// Blocking close of all sockets.
|
||||
channels.stopAsync();
|
||||
channels.awaitTerminated();
|
||||
for (PeerDiscovery peerDiscovery : peerDiscoverers) {
|
||||
peerDiscovery.shutdown();
|
||||
}
|
||||
vRunning = false;
|
||||
log.info("Stopped, took {}.", watch);
|
||||
} catch (Throwable e) {
|
||||
log.error("Exception when shutting down", e); // The executor swallows exceptions :(
|
||||
ListenableFuture future = executor.submit(() -> {
|
||||
try {
|
||||
log.info("Stopping ...");
|
||||
Stopwatch watch = Stopwatch.createStarted();
|
||||
// The log output this creates can be useful.
|
||||
setDownloadPeer(null);
|
||||
// Blocking close of all sockets.
|
||||
channels.stopAsync();
|
||||
channels.awaitTerminated();
|
||||
for (PeerDiscovery peerDiscovery : peerDiscoverers) {
|
||||
peerDiscovery.shutdown();
|
||||
}
|
||||
vRunning = false;
|
||||
log.info("Stopped, took {}.", watch);
|
||||
} catch (Throwable e) {
|
||||
log.error("Exception when shutting down", e); // The executor swallows exceptions :(
|
||||
}
|
||||
});
|
||||
executor.shutdown();
|
||||
@ -1571,12 +1537,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
||||
|
||||
final int fNewSize = newSize;
|
||||
for (final ListenerRegistration<PeerConnectedEventListener> registration : peerConnectedEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onPeerConnected(peer, fNewSize);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onPeerConnected(peer, fNewSize));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1587,26 +1548,23 @@ public class PeerGroup implements TransactionBroadcaster {
|
||||
if (getPingIntervalMsec() <= 0)
|
||||
return; // Disabled.
|
||||
|
||||
vPingTask = executor.scheduleAtFixedRate(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (getPingIntervalMsec() <= 0) {
|
||||
ListenableScheduledFuture<?> task = vPingTask;
|
||||
if (task != null) {
|
||||
task.cancel(false);
|
||||
vPingTask = null;
|
||||
}
|
||||
return; // Disabled.
|
||||
vPingTask = executor.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
if (getPingIntervalMsec() <= 0) {
|
||||
ListenableScheduledFuture<?> task = vPingTask;
|
||||
if (task != null) {
|
||||
task.cancel(false);
|
||||
vPingTask = null;
|
||||
}
|
||||
for (Peer peer : getConnectedPeers()) {
|
||||
if (peer.getPeerVersionMessage().clientVersion < params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.PONG))
|
||||
continue;
|
||||
peer.ping();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error("Exception in ping loop", e); // The executor swallows exceptions :(
|
||||
return; // Disabled.
|
||||
}
|
||||
for (Peer peer : getConnectedPeers()) {
|
||||
if (peer.getPeerVersionMessage().clientVersion < params.getProtocolVersionNum(NetworkParameters.ProtocolVersion.PONG))
|
||||
continue;
|
||||
peer.ping();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
log.error("Exception in ping loop", e); // The executor swallows exceptions :(
|
||||
}
|
||||
}, getPingIntervalMsec(), getPingIntervalMsec(), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
@ -1745,12 +1703,7 @@ public class PeerGroup implements TransactionBroadcaster {
|
||||
for (ListenerRegistration<OnTransactionBroadcastListener> registration : peersTransactionBroadastEventListeners)
|
||||
peer.removeOnTransactionBroadcastListener(registration.listener);
|
||||
for (final ListenerRegistration<PeerDisconnectedEventListener> registration : peerDisconnectedEventListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onPeerDisconnected(peer, fNumConnectedPeers);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onPeerDisconnected(peer, fNumConnectedPeers));
|
||||
peer.removeDisconnectedEventListener(registration.listener);
|
||||
}
|
||||
}
|
||||
|
@ -71,30 +71,24 @@ public class Transaction extends ChildMessage {
|
||||
* A comparator that can be used to sort transactions by their updateTime field. The ordering goes from most recent
|
||||
* into the past.
|
||||
*/
|
||||
public static final Comparator<Transaction> SORT_TX_BY_UPDATE_TIME = new Comparator<Transaction>() {
|
||||
@Override
|
||||
public int compare(final Transaction tx1, final Transaction tx2) {
|
||||
final long time1 = tx1.getUpdateTime().getTime();
|
||||
final long time2 = tx2.getUpdateTime().getTime();
|
||||
final int updateTimeComparison = -(Long.compare(time1, time2));
|
||||
//If time1==time2, compare by tx hash to make comparator consistent with equals
|
||||
return updateTimeComparison != 0 ? updateTimeComparison : tx1.getTxId().compareTo(tx2.getTxId());
|
||||
}
|
||||
public static final Comparator<Transaction> SORT_TX_BY_UPDATE_TIME = (tx1, tx2) -> {
|
||||
final long time1 = tx1.getUpdateTime().getTime();
|
||||
final long time2 = tx2.getUpdateTime().getTime();
|
||||
final int updateTimeComparison = -(Long.compare(time1, time2));
|
||||
//If time1==time2, compare by tx hash to make comparator consistent with equals
|
||||
return updateTimeComparison != 0 ? updateTimeComparison : tx1.getTxId().compareTo(tx2.getTxId());
|
||||
};
|
||||
/** A comparator that can be used to sort transactions by their chain height. */
|
||||
public static final Comparator<Transaction> SORT_TX_BY_HEIGHT = new Comparator<Transaction>() {
|
||||
@Override
|
||||
public int compare(final Transaction tx1, final Transaction tx2) {
|
||||
final TransactionConfidence confidence1 = tx1.getConfidence();
|
||||
final int height1 = confidence1.getConfidenceType() == ConfidenceType.BUILDING
|
||||
? confidence1.getAppearedAtChainHeight() : Block.BLOCK_HEIGHT_UNKNOWN;
|
||||
final TransactionConfidence confidence2 = tx2.getConfidence();
|
||||
final int height2 = confidence2.getConfidenceType() == ConfidenceType.BUILDING
|
||||
? confidence2.getAppearedAtChainHeight() : Block.BLOCK_HEIGHT_UNKNOWN;
|
||||
final int heightComparison = -(Integer.compare(height1, height2));
|
||||
//If height1==height2, compare by tx hash to make comparator consistent with equals
|
||||
return heightComparison != 0 ? heightComparison : tx1.getTxId().compareTo(tx2.getTxId());
|
||||
}
|
||||
public static final Comparator<Transaction> SORT_TX_BY_HEIGHT = (tx1, tx2) -> {
|
||||
final TransactionConfidence confidence1 = tx1.getConfidence();
|
||||
final int height1 = confidence1.getConfidenceType() == ConfidenceType.BUILDING
|
||||
? confidence1.getAppearedAtChainHeight() : Block.BLOCK_HEIGHT_UNKNOWN;
|
||||
final TransactionConfidence confidence2 = tx2.getConfidence();
|
||||
final int height2 = confidence2.getConfidenceType() == ConfidenceType.BUILDING
|
||||
? confidence2.getAppearedAtChainHeight() : Block.BLOCK_HEIGHT_UNKNOWN;
|
||||
final int heightComparison = -(Integer.compare(height1, height2));
|
||||
//If height1==height2, compare by tx hash to make comparator consistent with equals
|
||||
return heightComparison != 0 ? heightComparison : tx1.getTxId().compareTo(tx2.getTxId());
|
||||
};
|
||||
private static final Logger log = LoggerFactory.getLogger(Transaction.class);
|
||||
|
||||
|
@ -165,12 +165,9 @@ public class TransactionBroadcast {
|
||||
if (dropPeersAfterBroadcast) {
|
||||
// We drop the peer shortly after the transaction has been sent, because this peer will not
|
||||
// send us back useful broadcast confirmations.
|
||||
future.addListener(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
|
||||
peer.close();
|
||||
}
|
||||
future.addListener(() -> {
|
||||
Uninterruptibles.sleepUninterruptibly(1, TimeUnit.SECONDS);
|
||||
peer.close();
|
||||
}, Threading.THREAD_POOL);
|
||||
}
|
||||
// We don't record the peer as having seen the tx in the memory pool because we want to track only
|
||||
@ -241,12 +238,7 @@ public class TransactionBroadcast {
|
||||
if (executor == null)
|
||||
callback.onBroadcastProgress(progress);
|
||||
else
|
||||
executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.onBroadcastProgress(progress);
|
||||
}
|
||||
});
|
||||
executor.execute(() -> callback.onBroadcastProgress(progress));
|
||||
} catch (Throwable e) {
|
||||
log.error("Exception during progress callback", e);
|
||||
}
|
||||
|
@ -460,12 +460,7 @@ public class TransactionConfidence {
|
||||
*/
|
||||
public void queueListeners(final Listener.ChangeReason reason) {
|
||||
for (final ListenerRegistration<Listener> registration : listeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onConfidenceChanged(TransactionConfidence.this, reason);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onConfidenceChanged(TransactionConfidence.this, reason));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -44,13 +44,10 @@ import static com.google.common.base.Preconditions.*;
|
||||
public class DeterministicKey extends ECKey {
|
||||
|
||||
/** Sorts deterministic keys in the order of their child number. That's <i>usually</i> the order used to derive them. */
|
||||
public static final Comparator<ECKey> CHILDNUM_ORDER = new Comparator<ECKey>() {
|
||||
@Override
|
||||
public int compare(ECKey k1, ECKey k2) {
|
||||
ChildNumber cn1 = ((DeterministicKey) k1).getChildNumber();
|
||||
ChildNumber cn2 = ((DeterministicKey) k2).getChildNumber();
|
||||
return cn1.compareTo(cn2);
|
||||
}
|
||||
public static final Comparator<ECKey> CHILDNUM_ORDER = (k1, k2) -> {
|
||||
ChildNumber cn1 = ((DeterministicKey) k1).getChildNumber();
|
||||
ChildNumber cn2 = ((DeterministicKey) k2).getChildNumber();
|
||||
return cn1.compareTo(cn2);
|
||||
};
|
||||
|
||||
private final DeterministicKey parent;
|
||||
|
@ -189,11 +189,6 @@ public class NioClientManager extends AbstractExecutionThreadService implements
|
||||
|
||||
@Override
|
||||
protected Executor executor() {
|
||||
return new Executor() {
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
new ContextPropagatingThreadFactory("NioClientManager").newThread(command).start();
|
||||
}
|
||||
};
|
||||
return command -> new ContextPropagatingThreadFactory("NioClientManager").newThread(command).start();
|
||||
}
|
||||
}
|
||||
|
@ -106,22 +106,14 @@ public class MultiplexingDiscovery implements PeerDiscovery {
|
||||
List<Callable<List<InetSocketAddress>>> tasks = new ArrayList<>();
|
||||
if (parallelQueries) {
|
||||
for (final PeerDiscovery seed : seeds) {
|
||||
tasks.add(new Callable<List<InetSocketAddress>>() {
|
||||
@Override
|
||||
public List<InetSocketAddress> call() throws Exception {
|
||||
return seed.getPeers(services, timeoutValue, timeoutUnit);
|
||||
}
|
||||
});
|
||||
tasks.add(() -> seed.getPeers(services, timeoutValue, timeoutUnit));
|
||||
}
|
||||
} else {
|
||||
tasks.add(new Callable<List<InetSocketAddress>>() {
|
||||
@Override
|
||||
public List<InetSocketAddress> call() throws Exception {
|
||||
List<InetSocketAddress> peers = new LinkedList<>();
|
||||
for (final PeerDiscovery seed : seeds)
|
||||
peers.addAll(seed.getPeers(services, timeoutValue, timeoutUnit));
|
||||
return peers;
|
||||
}
|
||||
tasks.add(() -> {
|
||||
List<InetSocketAddress> peers = new LinkedList<>();
|
||||
for (final PeerDiscovery seed : seeds)
|
||||
peers.addAll(seed.getPeers(services, timeoutValue, timeoutUnit));
|
||||
return peers;
|
||||
});
|
||||
}
|
||||
final List<Future<List<InetSocketAddress>>> futures = vThreadPool.invokeAll(tasks, timeoutValue, timeoutUnit);
|
||||
|
@ -171,15 +171,12 @@ public class PaymentSession {
|
||||
}
|
||||
|
||||
private static ListenableFuture<PaymentSession> fetchPaymentRequest(final URI uri, final boolean verifyPki, @Nullable final TrustStoreLoader trustStoreLoader) {
|
||||
return executor.submit(new Callable<PaymentSession>() {
|
||||
@Override
|
||||
public PaymentSession call() throws Exception {
|
||||
HttpURLConnection connection = (HttpURLConnection)uri.toURL().openConnection();
|
||||
connection.setRequestProperty("Accept", PaymentProtocol.MIMETYPE_PAYMENTREQUEST);
|
||||
connection.setUseCaches(false);
|
||||
Protos.PaymentRequest paymentRequest = Protos.PaymentRequest.parseFrom(connection.getInputStream());
|
||||
return new PaymentSession(paymentRequest, verifyPki, trustStoreLoader);
|
||||
}
|
||||
return executor.submit(() -> {
|
||||
HttpURLConnection connection = (HttpURLConnection)uri.toURL().openConnection();
|
||||
connection.setRequestProperty("Accept", PaymentProtocol.MIMETYPE_PAYMENTREQUEST);
|
||||
connection.setUseCaches(false);
|
||||
Protos.PaymentRequest paymentRequest = Protos.PaymentRequest.parseFrom(connection.getInputStream());
|
||||
return new PaymentSession(paymentRequest, verifyPki, trustStoreLoader);
|
||||
});
|
||||
}
|
||||
|
||||
@ -353,28 +350,25 @@ public class PaymentSession {
|
||||
|
||||
@VisibleForTesting
|
||||
protected ListenableFuture<PaymentProtocol.Ack> sendPayment(final URL url, final Protos.Payment payment) {
|
||||
return executor.submit(new Callable<PaymentProtocol.Ack>() {
|
||||
@Override
|
||||
public PaymentProtocol.Ack call() throws Exception {
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", PaymentProtocol.MIMETYPE_PAYMENT);
|
||||
connection.setRequestProperty("Accept", PaymentProtocol.MIMETYPE_PAYMENTACK);
|
||||
connection.setRequestProperty("Content-Length", Integer.toString(payment.getSerializedSize()));
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
return executor.submit(() -> {
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", PaymentProtocol.MIMETYPE_PAYMENT);
|
||||
connection.setRequestProperty("Accept", PaymentProtocol.MIMETYPE_PAYMENTACK);
|
||||
connection.setRequestProperty("Content-Length", Integer.toString(payment.getSerializedSize()));
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
|
||||
// Send request.
|
||||
DataOutputStream outStream = new DataOutputStream(connection.getOutputStream());
|
||||
payment.writeTo(outStream);
|
||||
outStream.flush();
|
||||
outStream.close();
|
||||
// Send request.
|
||||
DataOutputStream outStream = new DataOutputStream(connection.getOutputStream());
|
||||
payment.writeTo(outStream);
|
||||
outStream.flush();
|
||||
outStream.close();
|
||||
|
||||
// Get response.
|
||||
Protos.PaymentACK paymentAck = Protos.PaymentACK.parseFrom(connection.getInputStream());
|
||||
return PaymentProtocol.parsePaymentAck(paymentAck);
|
||||
}
|
||||
// Get response.
|
||||
Protos.PaymentACK paymentAck = Protos.PaymentACK.parseFrom(connection.getInputStream());
|
||||
return PaymentProtocol.parsePaymentAck(paymentAck);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -42,16 +42,13 @@ public class ContextPropagatingThreadFactory implements ThreadFactory {
|
||||
@Override
|
||||
public Thread newThread(final Runnable r) {
|
||||
final Context context = Context.get();
|
||||
Thread thread = new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Context.propagate(context);
|
||||
r.run();
|
||||
} catch (Exception e) {
|
||||
log.error("Exception in thread", e);
|
||||
throw e;
|
||||
}
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
Context.propagate(context);
|
||||
r.run();
|
||||
} catch (Exception e) {
|
||||
log.error("Exception in thread", e);
|
||||
throw e;
|
||||
}
|
||||
}, name);
|
||||
thread.setPriority(priority);
|
||||
|
@ -64,11 +64,7 @@ public class Threading {
|
||||
*/
|
||||
public static void waitForUserCode() {
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
USER_THREAD.execute(new Runnable() {
|
||||
@Override public void run() {
|
||||
latch.countDown();
|
||||
}
|
||||
});
|
||||
USER_THREAD.execute(() -> latch.countDown());
|
||||
Uninterruptibles.awaitUninterruptibly(latch);
|
||||
}
|
||||
|
||||
@ -133,12 +129,7 @@ public class Threading {
|
||||
throwOnLockCycles();
|
||||
|
||||
USER_THREAD = new UserThread();
|
||||
SAME_THREAD = new Executor() {
|
||||
@Override
|
||||
public void execute(@Nonnull Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
};
|
||||
SAME_THREAD = runnable -> runnable.run();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -190,14 +181,11 @@ public class Threading {
|
||||
|
||||
/** A caching thread pool that creates daemon threads, which won't keep the JVM alive waiting for more work. */
|
||||
public static ListeningExecutorService THREAD_POOL = MoreExecutors.listeningDecorator(
|
||||
Executors.newCachedThreadPool(new ThreadFactory() {
|
||||
@Override
|
||||
public Thread newThread(Runnable r) {
|
||||
Thread t = new Thread(r);
|
||||
t.setName("Threading.THREAD_POOL worker");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
}
|
||||
Executors.newCachedThreadPool(r -> {
|
||||
Thread t = new Thread(r);
|
||||
t.setName("Threading.THREAD_POOL worker");
|
||||
t.setDaemon(true);
|
||||
return t;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
@ -423,12 +423,7 @@ public class BasicKeyChain implements EncryptableKeyChain {
|
||||
private void queueOnKeysAdded(final List<ECKey> keys) {
|
||||
checkState(lock.isHeldByCurrentThread());
|
||||
for (final ListenerRegistration<KeyChainEventListener> registration : listeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onKeysAdded(keys);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onKeysAdded(keys));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,25 +63,22 @@ public class DefaultCoinSelector implements CoinSelector {
|
||||
}
|
||||
|
||||
@VisibleForTesting static void sortOutputs(ArrayList<TransactionOutput> outputs) {
|
||||
Collections.sort(outputs, new Comparator<TransactionOutput>() {
|
||||
@Override
|
||||
public int compare(TransactionOutput a, TransactionOutput b) {
|
||||
int depth1 = a.getParentTransactionDepthInBlocks();
|
||||
int depth2 = b.getParentTransactionDepthInBlocks();
|
||||
Coin aValue = a.getValue();
|
||||
Coin bValue = b.getValue();
|
||||
BigInteger aCoinDepth = BigInteger.valueOf(aValue.value).multiply(BigInteger.valueOf(depth1));
|
||||
BigInteger bCoinDepth = BigInteger.valueOf(bValue.value).multiply(BigInteger.valueOf(depth2));
|
||||
int c1 = bCoinDepth.compareTo(aCoinDepth);
|
||||
if (c1 != 0) return c1;
|
||||
// The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size.
|
||||
int c2 = bValue.compareTo(aValue);
|
||||
if (c2 != 0) return c2;
|
||||
// They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering.
|
||||
BigInteger aHash = a.getParentTransactionHash().toBigInteger();
|
||||
BigInteger bHash = b.getParentTransactionHash().toBigInteger();
|
||||
return aHash.compareTo(bHash);
|
||||
}
|
||||
Collections.sort(outputs, (a, b) -> {
|
||||
int depth1 = a.getParentTransactionDepthInBlocks();
|
||||
int depth2 = b.getParentTransactionDepthInBlocks();
|
||||
Coin aValue = a.getValue();
|
||||
Coin bValue = b.getValue();
|
||||
BigInteger aCoinDepth = BigInteger.valueOf(aValue.value).multiply(BigInteger.valueOf(depth1));
|
||||
BigInteger bCoinDepth = BigInteger.valueOf(bValue.value).multiply(BigInteger.valueOf(depth2));
|
||||
int c1 = bCoinDepth.compareTo(aCoinDepth);
|
||||
if (c1 != 0) return c1;
|
||||
// The "coin*days" destroyed are equal, sort by value alone to get the lowest transaction size.
|
||||
int c2 = bValue.compareTo(aValue);
|
||||
if (c2 != 0) return c2;
|
||||
// They are entirely equivalent (possibly pending) so sort by hash to ensure a total ordering.
|
||||
BigInteger aHash = a.getParentTransactionHash().toBigInteger();
|
||||
BigInteger bHash = b.getParentTransactionHash().toBigInteger();
|
||||
return aHash.compareTo(bHash);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -866,12 +866,7 @@ public class KeyChainGroup implements KeyBag {
|
||||
|
||||
private void queueOnCurrentKeyChanged() {
|
||||
for (final ListenerRegistration<CurrentKeyChangeEventListener> registration : currentKeyChangeListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onCurrentKeyChanged();
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onCurrentKeyChanged());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,15 +25,12 @@ public interface KeyChainGroupStructure {
|
||||
HDPath accountPathFor(Script.ScriptType outputScriptType);
|
||||
|
||||
/** Default {@link KeyChainGroupStructure} implementation. Based on BIP32 "Wallet structure". */
|
||||
public static final KeyChainGroupStructure DEFAULT = new KeyChainGroupStructure() {
|
||||
@Override
|
||||
public HDPath accountPathFor(Script.ScriptType outputScriptType) {
|
||||
if (outputScriptType == null || outputScriptType == Script.ScriptType.P2PKH)
|
||||
return DeterministicKeyChain.ACCOUNT_ZERO_PATH;
|
||||
else if (outputScriptType == Script.ScriptType.P2WPKH)
|
||||
return DeterministicKeyChain.ACCOUNT_ONE_PATH;
|
||||
else
|
||||
throw new IllegalArgumentException(outputScriptType.toString());
|
||||
}
|
||||
public static final KeyChainGroupStructure DEFAULT = outputScriptType -> {
|
||||
if (outputScriptType == null || outputScriptType == Script.ScriptType.P2PKH)
|
||||
return DeterministicKeyChain.ACCOUNT_ZERO_PATH;
|
||||
else if (outputScriptType == Script.ScriptType.P2WPKH)
|
||||
return DeterministicKeyChain.ACCOUNT_ONE_PATH;
|
||||
else
|
||||
throw new IllegalArgumentException(outputScriptType.toString());
|
||||
};
|
||||
}
|
||||
|
@ -482,25 +482,22 @@ public class Wallet extends BaseTaggableObject
|
||||
|
||||
private void createTransientState() {
|
||||
ignoreNextNewBlock = new HashSet<>();
|
||||
txConfidenceListener = new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) {
|
||||
// This will run on the user code thread so we shouldn't do anything too complicated here.
|
||||
// We only want to queue a wallet changed event and auto-save if the number of peers announcing
|
||||
// the transaction has changed, as that confidence change is made by the networking code which
|
||||
// doesn't necessarily know at that point which wallets contain which transactions, so it's up
|
||||
// to us to listen for that. Other types of confidence changes (type, etc) are triggered by us,
|
||||
// so we'll queue up a wallet change event in other parts of the code.
|
||||
if (reason == ChangeReason.SEEN_PEERS) {
|
||||
lock.lock();
|
||||
try {
|
||||
checkBalanceFuturesLocked(null);
|
||||
Transaction tx = getTransaction(confidence.getTransactionHash());
|
||||
queueOnTransactionConfidenceChanged(tx);
|
||||
maybeQueueOnWalletChanged();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
txConfidenceListener = (confidence, reason) -> {
|
||||
// This will run on the user code thread so we shouldn't do anything too complicated here.
|
||||
// We only want to queue a wallet changed event and auto-save if the number of peers announcing
|
||||
// the transaction has changed, as that confidence change is made by the networking code which
|
||||
// doesn't necessarily know at that point which wallets contain which transactions, so it's up
|
||||
// to us to listen for that. Other types of confidence changes (type, etc) are triggered by us,
|
||||
// so we'll queue up a wallet change event in other parts of the code.
|
||||
if (reason == Listener.ChangeReason.SEEN_PEERS) {
|
||||
lock.lock();
|
||||
try {
|
||||
checkBalanceFuturesLocked(null);
|
||||
Transaction tx = getTransaction(confidence.getTransactionHash());
|
||||
queueOnTransactionConfidenceChanged(tx);
|
||||
maybeQueueOnWalletChanged();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -2954,12 +2951,7 @@ public class Wallet extends BaseTaggableObject
|
||||
if (registration.executor == Threading.SAME_THREAD) {
|
||||
registration.listener.onTransactionConfidenceChanged(this, tx);
|
||||
} else {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onTransactionConfidenceChanged(Wallet.this, tx);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onTransactionConfidenceChanged(Wallet.this, tx));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2971,36 +2963,21 @@ public class Wallet extends BaseTaggableObject
|
||||
checkState(onWalletChangedSuppressions >= 0);
|
||||
if (onWalletChangedSuppressions > 0) return;
|
||||
for (final ListenerRegistration<WalletChangeEventListener> registration : changeListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onWalletChanged(Wallet.this);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onWalletChanged(Wallet.this));
|
||||
}
|
||||
}
|
||||
|
||||
protected void queueOnCoinsReceived(final Transaction tx, final Coin balance, final Coin newBalance) {
|
||||
checkState(lock.isHeldByCurrentThread());
|
||||
for (final ListenerRegistration<WalletCoinsReceivedEventListener> registration : coinsReceivedListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onCoinsReceived(Wallet.this, tx, balance, newBalance);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onCoinsReceived(Wallet.this, tx, balance, newBalance));
|
||||
}
|
||||
}
|
||||
|
||||
protected void queueOnCoinsSent(final Transaction tx, final Coin prevBalance, final Coin newBalance) {
|
||||
checkState(lock.isHeldByCurrentThread());
|
||||
for (final ListenerRegistration<WalletCoinsSentEventListener> registration : coinsSentListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onCoinsSent(Wallet.this, tx, prevBalance, newBalance);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onCoinsSent(Wallet.this, tx, prevBalance, newBalance));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3008,23 +2985,13 @@ public class Wallet extends BaseTaggableObject
|
||||
checkState(lock.isHeldByCurrentThread());
|
||||
checkState(insideReorg);
|
||||
for (final ListenerRegistration<WalletReorganizeEventListener> registration : reorganizeListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onReorganize(Wallet.this);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onReorganize(Wallet.this));
|
||||
}
|
||||
}
|
||||
|
||||
protected void queueOnScriptsChanged(final List<Script> scripts, final boolean isAddingScripts) {
|
||||
for (final ListenerRegistration<ScriptsChangeEventListener> registration : scriptsChangeListeners) {
|
||||
registration.executor.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
registration.listener.onScriptsChanged(Wallet.this, scripts, isAddingScripts);
|
||||
}
|
||||
});
|
||||
registration.executor.execute(() -> registration.listener.onScriptsChanged(Wallet.this, scripts, isAddingScripts));
|
||||
}
|
||||
}
|
||||
|
||||
@ -3827,11 +3794,7 @@ public class Wallet extends BaseTaggableObject
|
||||
it.remove();
|
||||
final Coin v = val;
|
||||
// Don't run any user-provided future listeners with our lock held.
|
||||
Threading.USER_THREAD.execute(new Runnable() {
|
||||
@Override public void run() {
|
||||
req.future.set(v);
|
||||
}
|
||||
});
|
||||
Threading.USER_THREAD.execute(() -> req.future.set(v));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,21 +84,19 @@ public class WalletFiles {
|
||||
this.delay = delay;
|
||||
this.delayTimeUnit = checkNotNull(delayTimeUnit);
|
||||
|
||||
this.saver = new Callable<Void>() {
|
||||
@Override public Void call() throws Exception {
|
||||
// Runs in an auto save thread.
|
||||
if (!savePending.getAndSet(false)) {
|
||||
// Some other scheduled request already beat us to it.
|
||||
return null;
|
||||
}
|
||||
Date lastBlockSeenTime = wallet.getLastBlockSeenTime();
|
||||
log.info("Background saving wallet; last seen block is height {}, date {}, hash {}",
|
||||
wallet.getLastBlockSeenHeight(),
|
||||
lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown",
|
||||
wallet.getLastBlockSeenHash());
|
||||
saveNowInternal();
|
||||
this.saver = () -> {
|
||||
// Runs in an auto save thread.
|
||||
if (!savePending.getAndSet(false)) {
|
||||
// Some other scheduled request already beat us to it.
|
||||
return null;
|
||||
}
|
||||
Date lastBlockSeenTime = wallet.getLastBlockSeenTime();
|
||||
log.info("Background saving wallet; last seen block is height {}, date {}, hash {}",
|
||||
wallet.getLastBlockSeenHeight(),
|
||||
lastBlockSeenTime != null ? Utils.dateTimeFormat(lastBlockSeenTime) : "unknown",
|
||||
wallet.getLastBlockSeenHash());
|
||||
saveNowInternal();
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -99,12 +99,7 @@ public class WalletProtobufSerializer {
|
||||
private KeyChainFactory keyChainFactory;
|
||||
|
||||
public WalletProtobufSerializer() {
|
||||
this(new WalletFactory() {
|
||||
@Override
|
||||
public Wallet create(NetworkParameters params, KeyChainGroup keyChainGroup) {
|
||||
return new Wallet(params, keyChainGroup);
|
||||
}
|
||||
});
|
||||
this((params, keyChainGroup) -> new Wallet(params, keyChainGroup));
|
||||
}
|
||||
|
||||
public WalletProtobufSerializer(WalletFactory factory) {
|
||||
|
@ -87,117 +87,108 @@ 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.addConnectedEventListener(Threading.SAME_THREAD, new PeerConnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
if (!peer.getPeerVersionMessage().subVer.contains("Satoshi")) {
|
||||
System.out.println();
|
||||
System.out.println("************************************************************************************************************************\n" +
|
||||
"WARNING: You appear to be using this to test an alternative implementation with full validation rules. You should go\n" +
|
||||
"think hard about what you're doing. Seriously, no one has gotten even close to correctly reimplementing Bitcoin\n" +
|
||||
"consensus rules, despite serious investment in trying. It is a huge task and the slightest difference is a huge bug.\n" +
|
||||
"Instead, go work on making Bitcoin Core consensus rules a shared library and use that. Seriously, you wont get it right,\n" +
|
||||
"and starting with this tester as a way to try to do so will simply end in pain and lost coins.\n" +
|
||||
"************************************************************************************************************************");
|
||||
System.out.println();
|
||||
}
|
||||
log.info("bitcoind connected");
|
||||
// Make sure bitcoind has no blocks
|
||||
bitcoind.setDownloadParameters(0, false);
|
||||
bitcoind.startBlockChainDownload();
|
||||
connectedFuture.set(null);
|
||||
bitcoind.addConnectedEventListener(Threading.SAME_THREAD, (peer, peerCount) -> {
|
||||
if (!peer.getPeerVersionMessage().subVer.contains("Satoshi")) {
|
||||
System.out.println();
|
||||
System.out.println("************************************************************************************************************************\n" +
|
||||
"WARNING: You appear to be using this to test an alternative implementation with full validation rules. You should go\n" +
|
||||
"think hard about what you're doing. Seriously, no one has gotten even close to correctly reimplementing Bitcoin\n" +
|
||||
"consensus rules, despite serious investment in trying. It is a huge task and the slightest difference is a huge bug.\n" +
|
||||
"Instead, go work on making Bitcoin Core consensus rules a shared library and use that. Seriously, you wont get it right,\n" +
|
||||
"and starting with this tester as a way to try to do so will simply end in pain and lost coins.\n" +
|
||||
"************************************************************************************************************************");
|
||||
System.out.println();
|
||||
}
|
||||
log.info("bitcoind connected");
|
||||
// Make sure bitcoind has no blocks
|
||||
bitcoind.setDownloadParameters(0, false);
|
||||
bitcoind.startBlockChainDownload();
|
||||
connectedFuture.set(null);
|
||||
});
|
||||
|
||||
bitcoind.addDisconnectedEventListener(Threading.SAME_THREAD, new PeerDisconnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
log.error("bitcoind node disconnected!");
|
||||
bitcoind.addDisconnectedEventListener(Threading.SAME_THREAD, (peer, peerCount) -> {
|
||||
log.error("bitcoind node disconnected!");
|
||||
System.exit(1);
|
||||
});
|
||||
|
||||
bitcoind.addPreMessageReceivedEventListener(Threading.SAME_THREAD, (peer, m) -> {
|
||||
if (m instanceof HeadersMessage) {
|
||||
if (!((HeadersMessage) m).getBlockHeaders().isEmpty()) {
|
||||
Block b = Iterables.getLast(((HeadersMessage) m).getBlockHeaders());
|
||||
log.info("Got header from bitcoind " + b.getHashAsString());
|
||||
bitcoindChainHead = b.getHash();
|
||||
} else
|
||||
log.info("Got empty header message from bitcoind");
|
||||
return null;
|
||||
} else if (m instanceof Block) {
|
||||
log.error("bitcoind sent us a block it already had, make sure bitcoind has no blocks!");
|
||||
System.exit(1);
|
||||
}
|
||||
});
|
||||
|
||||
bitcoind.addPreMessageReceivedEventListener(Threading.SAME_THREAD, new PreMessageReceivedEventListener() {
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
||||
if (m instanceof HeadersMessage) {
|
||||
if (!((HeadersMessage) m).getBlockHeaders().isEmpty()) {
|
||||
Block b = Iterables.getLast(((HeadersMessage) m).getBlockHeaders());
|
||||
log.info("Got header from bitcoind " + b.getHashAsString());
|
||||
bitcoindChainHead = b.getHash();
|
||||
} else
|
||||
log.info("Got empty header message from bitcoind");
|
||||
return null;
|
||||
} else if (m instanceof Block) {
|
||||
log.error("bitcoind sent us a block it already had, make sure bitcoind has no blocks!");
|
||||
System.exit(1);
|
||||
} else if (m instanceof GetDataMessage) {
|
||||
for (InventoryItem item : ((GetDataMessage) m).items)
|
||||
if (item.type == InventoryItem.Type.BLOCK) {
|
||||
log.info("Requested " + item.hash);
|
||||
if (currentBlock.block.getHash().equals(item.hash))
|
||||
bitcoind.sendMessage(currentBlock.block);
|
||||
} else if (m instanceof GetDataMessage) {
|
||||
for (InventoryItem item : ((GetDataMessage) m).items)
|
||||
if (item.type == InventoryItem.Type.BLOCK) {
|
||||
log.info("Requested " + item.hash);
|
||||
if (currentBlock.block.getHash().equals(item.hash))
|
||||
bitcoind.sendMessage(currentBlock.block);
|
||||
else {
|
||||
Block nextBlock = preloadedBlocks.get(item.hash);
|
||||
if (nextBlock != null)
|
||||
bitcoind.sendMessage(nextBlock);
|
||||
else {
|
||||
Block nextBlock = preloadedBlocks.get(item.hash);
|
||||
if (nextBlock != null)
|
||||
bitcoind.sendMessage(nextBlock);
|
||||
else {
|
||||
blocksPendingSend.add(item.hash);
|
||||
log.info("...which we will not provide yet");
|
||||
}
|
||||
blocksPendingSend.add(item.hash);
|
||||
log.info("...which we will not provide yet");
|
||||
}
|
||||
blocksRequested.add(item.hash);
|
||||
}
|
||||
return null;
|
||||
} else if (m instanceof GetHeadersMessage) {
|
||||
try {
|
||||
if (currentBlock.block == null) {
|
||||
log.info("Got a request for a header before we had even begun processing blocks!");
|
||||
return null;
|
||||
}
|
||||
LinkedList<Block> headers = new LinkedList<>();
|
||||
Block it = blockList.hashHeaderMap.get(currentBlock.block.getHash());
|
||||
while (it != null) {
|
||||
headers.addFirst(it);
|
||||
it = blockList.hashHeaderMap.get(it.getPrevBlockHash());
|
||||
}
|
||||
LinkedList<Block> sendHeaders = new LinkedList<>();
|
||||
boolean found = false;
|
||||
for (Sha256Hash hash : ((GetHeadersMessage) m).getLocator().getHashes()) {
|
||||
for (Block b : headers) {
|
||||
if (found) {
|
||||
sendHeaders.addLast(b);
|
||||
log.info("Sending header (" + b.getPrevBlockHash() + ") -> " + b.getHash());
|
||||
if (b.getHash().equals(((GetHeadersMessage) m).getStopHash()))
|
||||
break;
|
||||
} else if (b.getHash().equals(hash)) {
|
||||
log.info("Found header " + b.getHashAsString());
|
||||
found = true;
|
||||
}
|
||||
blocksRequested.add(item.hash);
|
||||
}
|
||||
return null;
|
||||
} else if (m instanceof GetHeadersMessage) {
|
||||
try {
|
||||
if (currentBlock.block == null) {
|
||||
log.info("Got a request for a header before we had even begun processing blocks!");
|
||||
return null;
|
||||
}
|
||||
LinkedList<Block> headers = new LinkedList<>();
|
||||
Block it = blockList.hashHeaderMap.get(currentBlock.block.getHash());
|
||||
while (it != null) {
|
||||
headers.addFirst(it);
|
||||
it = blockList.hashHeaderMap.get(it.getPrevBlockHash());
|
||||
}
|
||||
LinkedList<Block> sendHeaders = new LinkedList<>();
|
||||
boolean found = false;
|
||||
for (Sha256Hash hash : ((GetHeadersMessage) m).getLocator().getHashes()) {
|
||||
for (Block b : headers) {
|
||||
if (found) {
|
||||
sendHeaders.addLast(b);
|
||||
log.info("Sending header (" + b.getPrevBlockHash() + ") -> " + b.getHash());
|
||||
if (b.getHash().equals(((GetHeadersMessage) m).getStopHash()))
|
||||
break;
|
||||
} else if (b.getHash().equals(hash)) {
|
||||
log.info("Found header " + b.getHashAsString());
|
||||
found = true;
|
||||
}
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
sendHeaders = headers;
|
||||
bitcoind.sendMessage(new HeadersMessage(PARAMS, sendHeaders));
|
||||
InventoryMessage i = new InventoryMessage(PARAMS);
|
||||
for (Block b : sendHeaders)
|
||||
i.addBlock(b);
|
||||
bitcoind.sendMessage(i);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
} else if (m instanceof InventoryMessage) {
|
||||
if (mostRecentInv != null) {
|
||||
log.error("Got an inv when we weren't expecting one");
|
||||
unexpectedInvs.incrementAndGet();
|
||||
}
|
||||
mostRecentInv = (InventoryMessage) m;
|
||||
if (!found)
|
||||
sendHeaders = headers;
|
||||
bitcoind.sendMessage(new HeadersMessage(PARAMS, sendHeaders));
|
||||
InventoryMessage i = new InventoryMessage(PARAMS);
|
||||
for (Block b : sendHeaders)
|
||||
i.addBlock(b);
|
||||
bitcoind.sendMessage(i);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return m;
|
||||
return null;
|
||||
} else if (m instanceof InventoryMessage) {
|
||||
if (mostRecentInv != null) {
|
||||
log.error("Got an inv when we weren't expecting one");
|
||||
unexpectedInvs.incrementAndGet();
|
||||
}
|
||||
mostRecentInv = (InventoryMessage) m;
|
||||
}
|
||||
return m;
|
||||
});
|
||||
|
||||
bitcoindChainHead = PARAMS.getGenesisBlock().getHash();
|
||||
|
@ -77,19 +77,8 @@ public class ChainSplitTest {
|
||||
// (receiving coins). Checking that we understand reversed spends is in testForking2.
|
||||
final AtomicBoolean reorgHappened = new AtomicBoolean();
|
||||
final AtomicInteger walletChanged = new AtomicInteger();
|
||||
wallet.addReorganizeEventListener(new WalletReorganizeEventListener() {
|
||||
@Override
|
||||
public void onReorganize(Wallet wallet) {
|
||||
reorgHappened.set(true);
|
||||
}
|
||||
});
|
||||
wallet.addChangeEventListener(new WalletChangeEventListener() {
|
||||
|
||||
@Override
|
||||
public void onWalletChanged(Wallet wallet) {
|
||||
walletChanged.incrementAndGet();
|
||||
}
|
||||
});
|
||||
wallet.addReorganizeEventListener(wallet -> reorgHappened.set(true));
|
||||
wallet.addChangeEventListener(wallet -> walletChanged.incrementAndGet());
|
||||
|
||||
// Start by building a couple of blocks on top of the genesis block.
|
||||
Block b1 = UNITTEST.getGenesisBlock().createNextBlock(coinsTo);
|
||||
@ -300,12 +289,9 @@ public class ChainSplitTest {
|
||||
// double spend on the new best chain.
|
||||
|
||||
final boolean[] eventCalled = new boolean[1];
|
||||
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
|
||||
if (tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.DEAD)
|
||||
eventCalled[0] = true;
|
||||
}
|
||||
wallet.addTransactionConfidenceEventListener((wallet, tx) -> {
|
||||
if (tx.getConfidence().getConfidenceType() == ConfidenceType.DEAD)
|
||||
eventCalled[0] = true;
|
||||
});
|
||||
|
||||
Block b1 = UNITTEST.getGenesisBlock().createNextBlock(coinsTo);
|
||||
@ -340,13 +326,10 @@ public class ChainSplitTest {
|
||||
// double spend on the new best chain.
|
||||
final Transaction[] eventDead = new Transaction[1];
|
||||
final Transaction[] eventReplacement = new Transaction[1];
|
||||
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
|
||||
if (tx.getConfidence().getConfidenceType() == TransactionConfidence.ConfidenceType.DEAD) {
|
||||
eventDead[0] = tx;
|
||||
eventReplacement[0] = tx.getConfidence().getOverridingTransaction();
|
||||
}
|
||||
wallet.addTransactionConfidenceEventListener((wallet, tx) -> {
|
||||
if (tx.getConfidence().getConfidenceType() == ConfidenceType.DEAD) {
|
||||
eventDead[0] = tx;
|
||||
eventReplacement[0] = tx.getConfidence().getOverridingTransaction();
|
||||
}
|
||||
});
|
||||
|
||||
@ -402,12 +385,7 @@ public class ChainSplitTest {
|
||||
// Check that as the chain forks and re-orgs, the confidence data associated with each transaction is
|
||||
// maintained correctly.
|
||||
final ArrayList<Transaction> txns = new ArrayList<>(3);
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
txns.add(tx);
|
||||
}
|
||||
});
|
||||
wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> txns.add(tx));
|
||||
|
||||
// Start by building three blocks on top of the genesis block. All send to us.
|
||||
Block b1 = UNITTEST.getGenesisBlock().createNextBlock(coinsTo);
|
||||
@ -559,12 +537,7 @@ 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<>(3);
|
||||
wallet.addCoinsReceivedEventListener(Threading.SAME_THREAD, new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
txns.add(tx);
|
||||
}
|
||||
});
|
||||
wallet.addCoinsReceivedEventListener(Threading.SAME_THREAD, (wallet, tx, prevBalance, newBalance) -> txns.add(tx));
|
||||
|
||||
Block b1 = UNITTEST.getGenesisBlock().createNextBlock(someOtherGuy);
|
||||
final ECKey coinsTo2 = wallet.freshReceiveKey();
|
||||
@ -603,12 +576,7 @@ public class ChainSplitTest {
|
||||
Transaction fodder = wallet.createSend(LegacyAddress.fromKey(UNITTEST, new ECKey()), FIFTY_COINS);
|
||||
wallet.commitTx(fodder);
|
||||
final AtomicBoolean fodderIsDead = new AtomicBoolean(false);
|
||||
fodder.getConfidence().addEventListener(Threading.SAME_THREAD, new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
fodderIsDead.set(confidence.getConfidenceType() == ConfidenceType.DEAD);
|
||||
}
|
||||
});
|
||||
fodder.getConfidence().addEventListener(Threading.SAME_THREAD, (confidence, reason) -> fodderIsDead.set(confidence.getConfidenceType() == ConfidenceType.DEAD));
|
||||
|
||||
// Fork like this:
|
||||
//
|
||||
|
@ -78,12 +78,7 @@ public class ECKeyTest {
|
||||
final ECKey key = new ECKey();
|
||||
for (byte i = 0; i < ITERATIONS; i++) {
|
||||
final Sha256Hash hash = Sha256Hash.of(new byte[]{i});
|
||||
sigFutures.add(executor.submit(new Callable<ECKey.ECDSASignature>() {
|
||||
@Override
|
||||
public ECKey.ECDSASignature call() throws Exception {
|
||||
return key.sign(hash);
|
||||
}
|
||||
}));
|
||||
sigFutures.add(executor.submit(() -> key.sign(hash)));
|
||||
}
|
||||
List<ECKey.ECDSASignature> sigs = Futures.allAsList(sigFutures).get();
|
||||
for (ECKey.ECDSASignature signature : sigs) {
|
||||
|
@ -81,18 +81,15 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
peerToMessageCount = new HashMap<>();
|
||||
connectedPeers = new LinkedBlockingQueue<>();
|
||||
disconnectedPeers = new LinkedBlockingQueue<>();
|
||||
preMessageReceivedListener = new PreMessageReceivedEventListener() {
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer peer, Message m) {
|
||||
AtomicInteger messageCount = peerToMessageCount.get(peer);
|
||||
if (messageCount == null) {
|
||||
messageCount = new AtomicInteger(0);
|
||||
peerToMessageCount.put(peer, messageCount);
|
||||
}
|
||||
messageCount.incrementAndGet();
|
||||
// Just pass the message right through for further processing.
|
||||
return m;
|
||||
preMessageReceivedListener = (peer, m) -> {
|
||||
AtomicInteger messageCount = peerToMessageCount.get(peer);
|
||||
if (messageCount == null) {
|
||||
messageCount = new AtomicInteger(0);
|
||||
peerToMessageCount.put(peer, messageCount);
|
||||
}
|
||||
messageCount.incrementAndGet();
|
||||
// Just pass the message right through for further processing.
|
||||
return m;
|
||||
};
|
||||
}
|
||||
|
||||
@ -188,12 +185,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(96, 200));
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(3, 300));
|
||||
peerGroup.addPeerDiscovery(createPeerDiscovery(1, 400));
|
||||
peerGroup.addDiscoveredEventListener(new PeerDiscoveredEventListener() {
|
||||
@Override
|
||||
public void onPeersDiscovered(Set<PeerAddress> peerAddresses) {
|
||||
assertEquals(99, peerAddresses.size());
|
||||
}
|
||||
});
|
||||
peerGroup.addDiscoveredEventListener(peerAddresses -> assertEquals(99, peerAddresses.size()));
|
||||
peerGroup.start();
|
||||
}
|
||||
|
||||
@ -298,12 +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).addDisconnectedEventListener(new PeerDisconnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
p1CloseFuture.set(null);
|
||||
}
|
||||
});
|
||||
peerOf(p1).addDisconnectedEventListener((peer, peerCount) -> p1CloseFuture.set(null));
|
||||
closePeer(peerOf(p1));
|
||||
p1CloseFuture.get();
|
||||
// Peer 2 fetches it next time it hears an inv (should it fetch immediately?).
|
||||
@ -355,12 +342,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
|
||||
final Transaction[] event = new Transaction[1];
|
||||
final TransactionConfidence[] confEvent = new TransactionConfidence[1];
|
||||
peerGroup.addOnTransactionBroadcastListener(Threading.SAME_THREAD, new OnTransactionBroadcastListener() {
|
||||
@Override
|
||||
public void onTransaction(Peer peer, Transaction t) {
|
||||
event[0] = t;
|
||||
}
|
||||
});
|
||||
peerGroup.addOnTransactionBroadcastListener(Threading.SAME_THREAD, (peer, t) -> event[0] = t);
|
||||
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
InboundMessageQueuer p2 = connectPeer(2);
|
||||
@ -397,12 +379,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
assertTrue(tx.getConfidence().wasBroadcastBy(peerOf(p2).getAddress()));
|
||||
assertNotNull(tx.getConfidence().getLastBroadcastedAt());
|
||||
|
||||
tx.getConfidence().addEventListener(new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) {
|
||||
confEvent[0] = confidence;
|
||||
}
|
||||
});
|
||||
tx.getConfidence().addEventListener((confidence, reason) -> confEvent[0] = confidence);
|
||||
// A straggler reports in.
|
||||
inbound(p3, inv);
|
||||
pingAndWait(p3);
|
||||
@ -517,18 +494,8 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
|
||||
final SettableFuture<Void> peerConnectedFuture = SettableFuture.create();
|
||||
final SettableFuture<Void> peerDisconnectedFuture = SettableFuture.create();
|
||||
peerGroup.addConnectedEventListener(Threading.SAME_THREAD, new PeerConnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
peerConnectedFuture.set(null);
|
||||
}
|
||||
});
|
||||
peerGroup.addDisconnectedEventListener(Threading.SAME_THREAD, new PeerDisconnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
peerDisconnectedFuture.set(null);
|
||||
}
|
||||
});
|
||||
peerGroup.addConnectedEventListener(Threading.SAME_THREAD, (peer, peerCount) -> peerConnectedFuture.set(null));
|
||||
peerGroup.addDisconnectedEventListener(Threading.SAME_THREAD, (peer, peerCount) -> peerDisconnectedFuture.set(null));
|
||||
// connect to peer but don't do handshake
|
||||
final Stopwatch watch = Stopwatch.createStarted(); // before connection so we don't get elapsed < timeout
|
||||
connectPeerWithoutVersionExchange(0);
|
||||
|
@ -365,12 +365,9 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
|
||||
connect();
|
||||
fail.set(true);
|
||||
peer.addChainDownloadStartedEventListener(Threading.SAME_THREAD, new ChainDownloadStartedEventListener() {
|
||||
@Override
|
||||
public void onChainDownloadStarted(Peer p, int blocksLeft) {
|
||||
if (p == peer && blocksLeft == 108)
|
||||
fail.set(false);
|
||||
}
|
||||
peer.addChainDownloadStartedEventListener(Threading.SAME_THREAD, (p, blocksLeft) -> {
|
||||
if (p == peer && blocksLeft == 108)
|
||||
fail.set(false);
|
||||
});
|
||||
peer.startBlockChainDownload();
|
||||
|
||||
@ -523,12 +520,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
// Check that if we request dependency download to be disabled and receive a relevant tx, things work correctly.
|
||||
Transaction tx = FakeTxBuilder.createFakeTx(UNITTEST, COIN, address);
|
||||
final Transaction[] result = new Transaction[1];
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
result[0] = tx;
|
||||
}
|
||||
});
|
||||
wallet.addCoinsReceivedEventListener((wallet, tx1, prevBalance, newBalance) -> result[0] = tx1);
|
||||
inbound(writeTarget, tx);
|
||||
pingAndWait(writeTarget);
|
||||
assertEquals(tx, result[0]);
|
||||
@ -541,12 +533,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
ECKey to = new ECKey();
|
||||
|
||||
final Transaction[] onTx = new Transaction[1];
|
||||
peer.addOnTransactionBroadcastListener(Threading.SAME_THREAD, new OnTransactionBroadcastListener() {
|
||||
@Override
|
||||
public void onTransaction(Peer peer1, Transaction t) {
|
||||
onTx[0] = t;
|
||||
}
|
||||
});
|
||||
peer.addOnTransactionBroadcastListener(Threading.SAME_THREAD, (peer1, t) -> onTx[0] = t);
|
||||
|
||||
// Make some fake transactions in the following graph:
|
||||
// t1 -> t2 -> [t5]
|
||||
@ -691,12 +678,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
ECKey key = wallet.freshReceiveKey();
|
||||
peer.addWallet(wallet);
|
||||
final Transaction[] vtx = new Transaction[1];
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
vtx[0] = tx;
|
||||
}
|
||||
});
|
||||
wallet.addCoinsReceivedEventListener((wallet1, tx, prevBalance, newBalance) -> vtx[0] = tx);
|
||||
// Send a normal relevant transaction, it's received correctly.
|
||||
Transaction t1 = FakeTxBuilder.createFakeTx(UNITTEST, COIN, key);
|
||||
inbound(writeTarget, t1);
|
||||
@ -743,12 +725,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
wallet.setAcceptRiskyTransactions(shouldAccept);
|
||||
peer.addWallet(wallet);
|
||||
final Transaction[] vtx = new Transaction[1];
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
vtx[0] = tx;
|
||||
}
|
||||
});
|
||||
wallet.addCoinsReceivedEventListener((wallet1, tx, prevBalance, newBalance) -> vtx[0] = tx);
|
||||
// t1 -> t2 [locked] -> t3 (not available)
|
||||
Transaction t2 = new Transaction(UNITTEST);
|
||||
t2.setLockTime(999999);
|
||||
@ -795,19 +772,9 @@ 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.addConnectedEventListener(new PeerConnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerConnected(Peer peer, int peerCount) {
|
||||
connectedFuture.set(null);
|
||||
}
|
||||
});
|
||||
peer.addConnectedEventListener((peer, peerCount) -> connectedFuture.set(null));
|
||||
|
||||
peer.addDisconnectedEventListener(new PeerDisconnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer peer, int peerCount) {
|
||||
disconnectedFuture.set(null);
|
||||
}
|
||||
});
|
||||
peer.addDisconnectedEventListener((peer, peerCount) -> disconnectedFuture.set(null));
|
||||
connectWithVersion(500, VersionMessage.NODE_NETWORK);
|
||||
// We must wait uninterruptibly here because connect[WithVersion] generates a peer that interrupts the current
|
||||
// thread when it disconnects.
|
||||
@ -824,27 +791,16 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
|
||||
@Test
|
||||
public void exceptionListener() throws Exception {
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
throw new NullPointerException("boo!");
|
||||
}
|
||||
wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> {
|
||||
throw new NullPointerException("boo!");
|
||||
});
|
||||
final Throwable[] throwables = new Throwable[1];
|
||||
Threading.uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable throwable) {
|
||||
throwables[0] = throwable;
|
||||
}
|
||||
};
|
||||
Threading.uncaughtExceptionHandler = (thread, throwable) -> throwables[0] = throwable;
|
||||
// In real usage we're not really meant to adjust the uncaught exception handler after stuff started happening
|
||||
// but in the unit test environment other tests have just run so the thread is probably still kicking around.
|
||||
// Force it to crash so it'll be recreated with our new handler.
|
||||
Threading.USER_THREAD.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
Threading.USER_THREAD.execute(() -> {
|
||||
throw new RuntimeException();
|
||||
});
|
||||
connect();
|
||||
Transaction t1 = new Transaction(UNITTEST);
|
||||
@ -899,20 +855,10 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
public void badMessage() throws Exception {
|
||||
// Bring up an actual network connection and feed it bogus data.
|
||||
final SettableFuture<Void> result = SettableFuture.create();
|
||||
Threading.uncaughtExceptionHandler = new Thread.UncaughtExceptionHandler() {
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable throwable) {
|
||||
result.setException(throwable);
|
||||
}
|
||||
};
|
||||
Threading.uncaughtExceptionHandler = (thread, throwable) -> result.setException(throwable);
|
||||
connect(); // Writes out a verack+version.
|
||||
final SettableFuture<Void> peerDisconnected = SettableFuture.create();
|
||||
writeTarget.peer.addDisconnectedEventListener(new PeerDisconnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer p, int peerCount) {
|
||||
peerDisconnected.set(null);
|
||||
}
|
||||
});
|
||||
writeTarget.peer.addDisconnectedEventListener((p, peerCount) -> peerDisconnected.set(null));
|
||||
MessageSerializer serializer = TESTNET.getDefaultSerializer();
|
||||
// Now write some bogus truncated message.
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
@ -71,12 +71,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
|
||||
tx.getConfidence().setSource(TransactionConfidence.Source.SELF);
|
||||
TransactionBroadcast broadcast = new TransactionBroadcast(peerGroup, tx);
|
||||
final AtomicDouble lastProgress = new AtomicDouble();
|
||||
broadcast.setProgressCallback(new TransactionBroadcast.ProgressCallback() {
|
||||
@Override
|
||||
public void onBroadcastProgress(double progress) {
|
||||
lastProgress.set(progress);
|
||||
}
|
||||
});
|
||||
broadcast.setProgressCallback(progress -> lastProgress.set(progress));
|
||||
ListenableFuture<Transaction> future = broadcast.broadcast();
|
||||
assertFalse(future.isDone());
|
||||
assertEquals(0.0, lastProgress.get(), 0.0);
|
||||
@ -116,12 +111,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
|
||||
inbound(channels[1], InventoryMessage.with(tx));
|
||||
pingAndWait(channels[1]);
|
||||
final AtomicDouble p = new AtomicDouble();
|
||||
broadcast.setProgressCallback(new TransactionBroadcast.ProgressCallback() {
|
||||
@Override
|
||||
public void onBroadcastProgress(double progress) {
|
||||
p.set(progress);
|
||||
}
|
||||
}, Threading.SAME_THREAD);
|
||||
broadcast.setProgressCallback(progress -> p.set(progress), Threading.SAME_THREAD);
|
||||
assertEquals(1.0, p.get(), 0.01);
|
||||
}
|
||||
|
||||
@ -201,12 +191,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
|
||||
|
||||
// Check that the wallet informs us of changes in confidence as the transaction ripples across the network.
|
||||
final Transaction[] transactions = new Transaction[1];
|
||||
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
|
||||
transactions[0] = tx;
|
||||
}
|
||||
});
|
||||
wallet.addTransactionConfidenceEventListener((wallet, tx) -> transactions[0] = tx);
|
||||
|
||||
// Now create a spend, and expect the announcement on p1.
|
||||
Address dest = LegacyAddress.fromKey(UNITTEST, new ECKey());
|
||||
|
@ -64,12 +64,7 @@ public class TxConfidenceTableTest {
|
||||
table.seen(hash, address1);
|
||||
assertEquals(1, tx.getConfidence().numBroadcastPeers());
|
||||
final int[] seen = new int[1];
|
||||
tx.getConfidence().addEventListener(Threading.SAME_THREAD, new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
seen[0] = confidence.numBroadcastPeers();
|
||||
}
|
||||
});
|
||||
tx.getConfidence().addEventListener(Threading.SAME_THREAD, (confidence, reason) -> seen[0] = confidence.numBroadcastPeers());
|
||||
tx = null;
|
||||
System.gc();
|
||||
table.seen(hash, address2);
|
||||
@ -79,12 +74,7 @@ public class TxConfidenceTableTest {
|
||||
@Test
|
||||
public void events() throws Exception {
|
||||
final TransactionConfidence.Listener.ChangeReason[] run = new TransactionConfidence.Listener.ChangeReason[1];
|
||||
tx1.getConfidence().addEventListener(Threading.SAME_THREAD, new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
run[0] = reason;
|
||||
}
|
||||
});
|
||||
tx1.getConfidence().addEventListener(Threading.SAME_THREAD, (confidence, reason) -> run[0] = reason);
|
||||
table.seen(tx1.getTxId(), address1);
|
||||
assertEquals(TransactionConfidence.Listener.ChangeReason.SEEN_PEERS, run[0]);
|
||||
run[0] = null;
|
||||
|
@ -261,12 +261,7 @@ public class WalletProtobufSerializerTest {
|
||||
BlockChain chain = new BlockChain(UNITTEST, myWallet, new MemoryBlockStore(UNITTEST));
|
||||
|
||||
final ArrayList<Transaction> txns = new ArrayList<>(2);
|
||||
myWallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
txns.add(tx);
|
||||
}
|
||||
});
|
||||
myWallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> txns.add(tx));
|
||||
|
||||
// Start by building two blocks on top of the genesis block.
|
||||
Block b1 = UNITTEST.getGenesisBlock().createNextBlock(myAddress);
|
||||
|
@ -153,13 +153,10 @@ public class TestWithNetworkConnections {
|
||||
checkArgument(versionMessage.hasBlockChain());
|
||||
final AtomicBoolean doneConnecting = new AtomicBoolean(false);
|
||||
final Thread thisThread = Thread.currentThread();
|
||||
peer.addDisconnectedEventListener(new PeerDisconnectedEventListener() {
|
||||
@Override
|
||||
public void onPeerDisconnected(Peer p, int peerCount) {
|
||||
synchronized (doneConnecting) {
|
||||
if (!doneConnecting.get())
|
||||
thisThread.interrupt();
|
||||
}
|
||||
peer.addDisconnectedEventListener((p, peerCount) -> {
|
||||
synchronized (doneConnecting) {
|
||||
if (!doneConnecting.get())
|
||||
thisThread.interrupt();
|
||||
}
|
||||
});
|
||||
if (clientType == ClientType.NIO_CLIENT_MANAGER || clientType == ClientType.BLOCKING_CLIENT_MANAGER)
|
||||
@ -211,15 +208,12 @@ 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();
|
||||
PreMessageReceivedEventListener listener = new PreMessageReceivedEventListener() {
|
||||
@Override
|
||||
public Message onPreMessageReceived(Peer p, Message m) {
|
||||
if (m instanceof Pong && ((Pong) m).getNonce() == nonce) {
|
||||
pongReceivedFuture.set(null);
|
||||
return null;
|
||||
}
|
||||
return m;
|
||||
PreMessageReceivedEventListener listener = (p1, m) -> {
|
||||
if (m instanceof Pong && ((Pong) m).getNonce() == nonce) {
|
||||
pongReceivedFuture.set(null);
|
||||
return null;
|
||||
}
|
||||
return m;
|
||||
};
|
||||
p.peer.addPreMessageReceivedEventListener(Threading.SAME_THREAD, listener);
|
||||
inbound(p, new Pong(nonce));
|
||||
|
@ -104,13 +104,10 @@ public class TestWithPeerGroup extends TestWithNetworkConnections {
|
||||
public ScheduledFuture<?> schedule(final Runnable command, final long delay, final TimeUnit unit) {
|
||||
if (!blockJobs)
|
||||
return super.schedule(command, delay, unit);
|
||||
return super.schedule(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Utils.rollMockClockMillis(unit.toMillis(delay));
|
||||
command.run();
|
||||
jobBlocks.acquireUninterruptibly();
|
||||
}
|
||||
return super.schedule(() -> {
|
||||
Utils.rollMockClockMillis(unit.toMillis(delay));
|
||||
command.run();
|
||||
jobBlocks.acquireUninterruptibly();
|
||||
}, 0 /* immediate */, unit);
|
||||
}
|
||||
});
|
||||
|
@ -414,12 +414,7 @@ public class KeyChainGroupTest {
|
||||
// Check that events are registered with the right chains and that if a chain is added, it gets the event
|
||||
// listeners attached properly even post-hoc.
|
||||
final AtomicReference<ECKey> ran = new AtomicReference<>(null);
|
||||
final KeyChainEventListener listener = new KeyChainEventListener() {
|
||||
@Override
|
||||
public void onKeysAdded(List<ECKey> keys) {
|
||||
ran.set(keys.get(0));
|
||||
}
|
||||
};
|
||||
final KeyChainEventListener listener = keys -> ran.set(keys.get(0));
|
||||
group.addEventListener(listener, Threading.SAME_THREAD);
|
||||
ECKey key = group.freshKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
|
||||
assertEquals(key, ran.getAndSet(null));
|
||||
|
@ -456,12 +456,7 @@ public class WalletTest extends TestWithWallet {
|
||||
|
||||
private static void broadcastAndCommit(Wallet wallet, Transaction t) throws Exception {
|
||||
final LinkedList<Transaction> txns = new LinkedList<>();
|
||||
wallet.addCoinsSentEventListener(new WalletCoinsSentEventListener() {
|
||||
@Override
|
||||
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
txns.add(tx);
|
||||
}
|
||||
});
|
||||
wallet.addCoinsSentEventListener((wallet1, tx, prevBalance, newBalance) -> txns.add(tx));
|
||||
|
||||
t.getConfidence().markBroadcastBy(new PeerAddress(UNITTEST, InetAddress.getByAddress(new byte[]{1,2,3,4})));
|
||||
t.getConfidence().markBroadcastBy(new PeerAddress(UNITTEST, InetAddress.getByAddress(new byte[]{10,2,3,4})));
|
||||
@ -601,30 +596,19 @@ public class WalletTest extends TestWithWallet {
|
||||
final Coin[] bigints = new Coin[4];
|
||||
final Transaction[] txn = new Transaction[2];
|
||||
final LinkedList<Transaction> confTxns = new LinkedList<>();
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
bigints[0] = prevBalance;
|
||||
bigints[1] = newBalance;
|
||||
txn[0] = tx;
|
||||
}
|
||||
wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> {
|
||||
bigints[0] = prevBalance;
|
||||
bigints[1] = newBalance;
|
||||
txn[0] = tx;
|
||||
});
|
||||
|
||||
wallet.addCoinsSentEventListener(new WalletCoinsSentEventListener() {
|
||||
@Override
|
||||
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
bigints[2] = prevBalance;
|
||||
bigints[3] = newBalance;
|
||||
txn[1] = tx;
|
||||
}
|
||||
wallet.addCoinsSentEventListener((wallet, tx, prevBalance, newBalance) -> {
|
||||
bigints[2] = prevBalance;
|
||||
bigints[3] = newBalance;
|
||||
txn[1] = tx;
|
||||
});
|
||||
|
||||
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
|
||||
confTxns.add(tx);
|
||||
}
|
||||
});
|
||||
wallet.addTransactionConfidenceEventListener((wallet, tx) -> confTxns.add(tx));
|
||||
|
||||
// Receive some money.
|
||||
Coin oneCoin = COIN;
|
||||
@ -850,13 +834,10 @@ public class WalletTest extends TestWithWallet {
|
||||
wallet.commitTx(send3);
|
||||
assertEquals(ZERO, wallet.getBalance(BalanceType.AVAILABLE));
|
||||
final LinkedList<TransactionConfidence> dead = new LinkedList<>();
|
||||
final TransactionConfidence.Listener listener = new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) {
|
||||
final TransactionConfidence.ConfidenceType type = confidence.getConfidenceType();
|
||||
if (reason == ChangeReason.TYPE && type == TransactionConfidence.ConfidenceType.DEAD)
|
||||
dead.add(confidence);
|
||||
}
|
||||
final TransactionConfidence.Listener listener = (confidence, reason) -> {
|
||||
final ConfidenceType type = confidence.getConfidenceType();
|
||||
if (reason == TransactionConfidence.Listener.ChangeReason.TYPE && type == ConfidenceType.DEAD)
|
||||
dead.add(confidence);
|
||||
};
|
||||
send2.getConfidence().addEventListener(Threading.SAME_THREAD, listener);
|
||||
send3.getConfidence().addEventListener(Threading.SAME_THREAD, listener);
|
||||
@ -881,23 +862,15 @@ public class WalletTest extends TestWithWallet {
|
||||
final Transaction[] eventDead = new Transaction[1];
|
||||
final Transaction[] eventReplacement = new Transaction[1];
|
||||
final int[] eventWalletChanged = new int[1];
|
||||
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
|
||||
if (tx.getConfidence().getConfidenceType() ==
|
||||
TransactionConfidence.ConfidenceType.DEAD) {
|
||||
eventDead[0] = tx;
|
||||
eventReplacement[0] = tx.getConfidence().getOverridingTransaction();
|
||||
}
|
||||
wallet.addTransactionConfidenceEventListener((wallet, tx) -> {
|
||||
if (tx.getConfidence().getConfidenceType() ==
|
||||
ConfidenceType.DEAD) {
|
||||
eventDead[0] = tx;
|
||||
eventReplacement[0] = tx.getConfidence().getOverridingTransaction();
|
||||
}
|
||||
});
|
||||
|
||||
wallet.addChangeEventListener(new WalletChangeEventListener() {
|
||||
@Override
|
||||
public void onWalletChanged(Wallet wallet) {
|
||||
eventWalletChanged[0]++;
|
||||
}
|
||||
});
|
||||
wallet.addChangeEventListener(wallet -> eventWalletChanged[0]++);
|
||||
|
||||
// Receive 1 BTC.
|
||||
Coin nanos = COIN;
|
||||
@ -1299,26 +1272,18 @@ public class WalletTest extends TestWithWallet {
|
||||
final boolean[] flags = new boolean[2];
|
||||
final Transaction[] notifiedTx = new Transaction[1];
|
||||
final int[] walletChanged = new int[1];
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
// Check we got the expected transaction.
|
||||
assertEquals(tx, t1);
|
||||
// Check that it's considered to be pending inclusion in the block chain.
|
||||
assertEquals(prevBalance, ZERO);
|
||||
assertEquals(newBalance, nanos);
|
||||
flags[0] = true;
|
||||
flags[1] = tx.isPending();
|
||||
notifiedTx[0] = tx;
|
||||
}
|
||||
wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> {
|
||||
// Check we got the expected transaction.
|
||||
assertEquals(tx, t1);
|
||||
// Check that it's considered to be pending inclusion in the block chain.
|
||||
assertEquals(prevBalance, ZERO);
|
||||
assertEquals(newBalance, nanos);
|
||||
flags[0] = true;
|
||||
flags[1] = tx.isPending();
|
||||
notifiedTx[0] = tx;
|
||||
});
|
||||
|
||||
wallet.addChangeEventListener(new WalletChangeEventListener() {
|
||||
@Override
|
||||
public void onWalletChanged(Wallet wallet) {
|
||||
walletChanged[0]++;
|
||||
}
|
||||
});
|
||||
wallet.addChangeEventListener(wallet -> walletChanged[0]++);
|
||||
|
||||
if (wallet.isPendingTransactionRelevant(t1))
|
||||
wallet.receivePending(t1, null);
|
||||
@ -1334,12 +1299,9 @@ public class WalletTest extends TestWithWallet {
|
||||
// Make a fresh copy of the tx to ensure we're testing realistically.
|
||||
flags[0] = flags[1] = false;
|
||||
final TransactionConfidence.Listener.ChangeReason[] reasons = new TransactionConfidence.Listener.ChangeReason[1];
|
||||
notifiedTx[0].getConfidence().addEventListener(new TransactionConfidence.Listener() {
|
||||
@Override
|
||||
public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) {
|
||||
flags[1] = true;
|
||||
reasons[0] = reason;
|
||||
}
|
||||
notifiedTx[0].getConfidence().addEventListener((confidence, reason) -> {
|
||||
flags[1] = true;
|
||||
reasons[0] = reason;
|
||||
});
|
||||
assertEquals(TransactionConfidence.ConfidenceType.PENDING,
|
||||
notifiedTx[0].getConfidence().getConfidenceType());
|
||||
@ -1369,13 +1331,10 @@ 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.addCoinsSentEventListener(new WalletCoinsSentEventListener() {
|
||||
@Override
|
||||
public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
txn[0] = tx;
|
||||
bigints[0] = prevBalance;
|
||||
bigints[1] = newBalance;
|
||||
}
|
||||
wallet.addCoinsSentEventListener((wallet, tx, prevBalance, newBalance) -> {
|
||||
txn[0] = tx;
|
||||
bigints[0] = prevBalance;
|
||||
bigints[1] = newBalance;
|
||||
});
|
||||
// Receive some coins.
|
||||
Coin nanos = COIN;
|
||||
@ -1418,21 +1377,13 @@ public class WalletTest extends TestWithWallet {
|
||||
t2.addInput(doubleSpentOut);
|
||||
|
||||
final Transaction[] called = new Transaction[2];
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
called[0] = tx;
|
||||
}
|
||||
});
|
||||
wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> called[0] = tx);
|
||||
|
||||
wallet.addTransactionConfidenceEventListener(new TransactionConfidenceEventListener() {
|
||||
@Override
|
||||
public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) {
|
||||
if (tx.getConfidence().getConfidenceType() ==
|
||||
TransactionConfidence.ConfidenceType.DEAD) {
|
||||
called[0] = tx;
|
||||
called[1] = tx.getConfidence().getOverridingTransaction();
|
||||
}
|
||||
wallet.addTransactionConfidenceEventListener((wallet, tx) -> {
|
||||
if (tx.getConfidence().getConfidenceType() ==
|
||||
ConfidenceType.DEAD) {
|
||||
called[0] = tx;
|
||||
called[1] = tx.getConfidence().getOverridingTransaction();
|
||||
}
|
||||
});
|
||||
|
||||
@ -2812,20 +2763,14 @@ 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.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
log.info("onCoinsReceived 1");
|
||||
throw new RuntimeException("barf");
|
||||
}
|
||||
wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> {
|
||||
log.info("onCoinsReceived 1");
|
||||
throw new RuntimeException("barf");
|
||||
});
|
||||
final AtomicInteger flag = new AtomicInteger();
|
||||
wallet.addCoinsReceivedEventListener(new WalletCoinsReceivedEventListener() {
|
||||
@Override
|
||||
public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
|
||||
log.info("onCoinsReceived 2");
|
||||
flag.incrementAndGet();
|
||||
}
|
||||
wallet.addCoinsReceivedEventListener((wallet, tx, prevBalance, newBalance) -> {
|
||||
log.info("onCoinsReceived 2");
|
||||
flag.incrementAndGet();
|
||||
});
|
||||
|
||||
sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, COIN);
|
||||
@ -3234,21 +3179,15 @@ public class WalletTest extends TestWithWallet {
|
||||
// Send a tx that is considered risky to the wallet, verify it doesn't show up in the balances.
|
||||
final Transaction tx = createFakeTx(UNITTEST, COIN, myAddress);
|
||||
final AtomicBoolean bool = new AtomicBoolean();
|
||||
wallet.setRiskAnalyzer(new RiskAnalysis.Analyzer() {
|
||||
@Override
|
||||
public RiskAnalysis create(Wallet wallet, Transaction wtx, List<Transaction> dependencies) {
|
||||
RiskAnalysis.Result result = RiskAnalysis.Result.OK;
|
||||
if (wtx.getTxId().equals(tx.getTxId()))
|
||||
result = RiskAnalysis.Result.NON_STANDARD;
|
||||
final RiskAnalysis.Result finalResult = result;
|
||||
return new RiskAnalysis() {
|
||||
@Override
|
||||
public Result analyze() {
|
||||
bool.set(true);
|
||||
return finalResult;
|
||||
}
|
||||
};
|
||||
}
|
||||
wallet.setRiskAnalyzer((wallet, wtx, dependencies) -> {
|
||||
RiskAnalysis.Result result = RiskAnalysis.Result.OK;
|
||||
if (wtx.getTxId().equals(tx.getTxId()))
|
||||
result = RiskAnalysis.Result.NON_STANDARD;
|
||||
final RiskAnalysis.Result finalResult = result;
|
||||
return () -> {
|
||||
bool.set(true);
|
||||
return finalResult;
|
||||
};
|
||||
});
|
||||
assertTrue(wallet.isPendingTransactionRelevant(tx));
|
||||
assertEquals(Coin.ZERO, wallet.getBalance());
|
||||
@ -3290,12 +3229,7 @@ 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(UNITTEST, KeyChainGroup.builder(UNITTEST).fromRandom(Script.ScriptType.P2PKH).build());
|
||||
final List<ECKey> keys = new LinkedList<>();
|
||||
wallet.addKeyChainEventListener(Threading.SAME_THREAD, new KeyChainEventListener() {
|
||||
@Override
|
||||
public void onKeysAdded(List<ECKey> k) {
|
||||
keys.addAll(k);
|
||||
}
|
||||
});
|
||||
wallet.addKeyChainEventListener(Threading.SAME_THREAD, k -> keys.addAll(k));
|
||||
wallet.freshReceiveKey();
|
||||
assertEquals(1, keys.size());
|
||||
}
|
||||
|
@ -473,45 +473,39 @@ public class WalletTool implements Callable<Integer> {
|
||||
return 1;
|
||||
}
|
||||
final Address validSelectAddr = selectAddr;
|
||||
coinSelector = new CoinSelector() {
|
||||
@Override
|
||||
public CoinSelection select(Coin target, List<TransactionOutput> candidates) {
|
||||
Coin valueGathered = Coin.ZERO;
|
||||
List<TransactionOutput> gathered = new LinkedList<TransactionOutput>();
|
||||
for (TransactionOutput candidate : candidates) {
|
||||
try {
|
||||
Address candidateAddr = candidate.getScriptPubKey().getToAddress(params);
|
||||
if (validSelectAddr.equals(candidateAddr)) {
|
||||
gathered.add(candidate);
|
||||
valueGathered = valueGathered.add(candidate.getValue());
|
||||
}
|
||||
} catch (ScriptException x) {
|
||||
// swallow
|
||||
coinSelector = (target, candidates) -> {
|
||||
Coin valueGathered = Coin.ZERO;
|
||||
List<TransactionOutput> gathered = new LinkedList<TransactionOutput>();
|
||||
for (TransactionOutput candidate : candidates) {
|
||||
try {
|
||||
Address candidateAddr = candidate.getScriptPubKey().getToAddress(params);
|
||||
if (validSelectAddr.equals(candidateAddr)) {
|
||||
gathered.add(candidate);
|
||||
valueGathered = valueGathered.add(candidate.getValue());
|
||||
}
|
||||
} catch (ScriptException x) {
|
||||
// swallow
|
||||
}
|
||||
return new CoinSelection(valueGathered, gathered);
|
||||
}
|
||||
return new CoinSelection(valueGathered, gathered);
|
||||
};
|
||||
}
|
||||
if (selectOutputStr != null) {
|
||||
String[] parts = selectOutputStr.split(":", 2);
|
||||
Sha256Hash selectTransactionHash = Sha256Hash.wrap(parts[0]);
|
||||
int selectIndex = Integer.parseInt(parts[1]);
|
||||
coinSelector = new CoinSelector() {
|
||||
@Override
|
||||
public CoinSelection select(Coin target, List<TransactionOutput> candidates) {
|
||||
Coin valueGathered = Coin.ZERO;
|
||||
List<TransactionOutput> gathered = new LinkedList<TransactionOutput>();
|
||||
for (TransactionOutput candidate : candidates) {
|
||||
int candicateIndex = candidate.getIndex();
|
||||
final Sha256Hash candidateTransactionHash = candidate.getParentTransactionHash();
|
||||
if (selectIndex == candicateIndex && selectTransactionHash.equals(candidateTransactionHash)) {
|
||||
gathered.add(candidate);
|
||||
valueGathered = valueGathered.add(candidate.getValue());
|
||||
}
|
||||
coinSelector = (target, candidates) -> {
|
||||
Coin valueGathered = Coin.ZERO;
|
||||
List<TransactionOutput> gathered = new LinkedList<TransactionOutput>();
|
||||
for (TransactionOutput candidate : candidates) {
|
||||
int candicateIndex = candidate.getIndex();
|
||||
final Sha256Hash candidateTransactionHash = candidate.getParentTransactionHash();
|
||||
if (selectIndex == candicateIndex && selectTransactionHash.equals(candidateTransactionHash)) {
|
||||
gathered.add(candidate);
|
||||
valueGathered = valueGathered.add(candidate.getValue());
|
||||
}
|
||||
return new CoinSelection(valueGathered, gathered);
|
||||
}
|
||||
return new CoinSelection(valueGathered, gathered);
|
||||
};
|
||||
}
|
||||
send(coinSelector, outputsStr, feePerVkb, lockTimeStr, allowUnconfirmed);
|
||||
|
Loading…
Reference in New Issue
Block a user