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

Move MockTransactionBroadcaster into utils so third party code can use it in its own tests.

This commit is contained in:
Mike Hearn 2013-09-17 12:37:58 +02:00
parent 8d839ae5ad
commit d4786acb14
2 changed files with 47 additions and 16 deletions

View File

@ -14,18 +14,35 @@
* limitations under the License.
*/
package com.google.bitcoin.core;
package com.google.bitcoin.utils;
import com.google.bitcoin.utils.Threading;
import com.google.bitcoin.core.Transaction;
import com.google.bitcoin.core.TransactionBroadcaster;
import com.google.bitcoin.core.Wallet;
import com.google.common.util.concurrent.SettableFuture;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.ReentrantLock;
/**
* A mock transaction broadcaster can be used in unit tests as a stand-in for a PeerGroup. It catches any transactions
* broadcast through it and makes them available via the {@link #broadcasts} member. Reading from that
* {@link LinkedBlockingQueue} will block the thread until a transaction is available.
*/
public class MockTransactionBroadcaster implements TransactionBroadcaster {
private ReentrantLock lock = Threading.lock("mock tx broadcaster");
private final ReentrantLock lock = Threading.lock("mock tx broadcaster");
public LinkedBlockingQueue<Transaction> broadcasts = new LinkedBlockingQueue<Transaction>();
public static class TxFuturePair {
public Transaction tx;
public SettableFuture<Transaction> future;
public TxFuturePair(Transaction tx, SettableFuture<Transaction> future) {
this.tx = tx;
this.future = future;
}
}
private final LinkedBlockingQueue<TxFuturePair> broadcasts = new LinkedBlockingQueue<TxFuturePair>();
public MockTransactionBroadcaster(Wallet wallet) {
// This code achieves nothing directly, but it sets up the broadcaster/peergroup > wallet lock ordering
@ -40,11 +57,11 @@ public class MockTransactionBroadcaster implements TransactionBroadcaster {
@Override
public SettableFuture<Transaction> broadcastTransaction(Transaction tx) {
// Use a lock just to catch lock ordering inversions.
// Use a lock just to catch lock ordering inversions e.g. wallet->broadcaster.
lock.lock();
try {
SettableFuture<Transaction> result = SettableFuture.create();
broadcasts.put(tx);
broadcasts.put(new TxFuturePair(tx, result));
return result;
} catch (InterruptedException e) {
throw new RuntimeException(e);
@ -52,4 +69,20 @@ public class MockTransactionBroadcaster implements TransactionBroadcaster {
lock.unlock();
}
}
public Transaction waitForTransaction() {
return waitForTxFuture().tx;
}
public TxFuturePair waitForTxFuture() {
try {
return broadcasts.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
public int size() {
return broadcasts.size();
}
}

View File

@ -24,6 +24,7 @@ import com.google.bitcoin.crypto.KeyCrypterException;
import com.google.bitcoin.crypto.KeyCrypterScrypt;
import com.google.bitcoin.crypto.TransactionSignature;
import com.google.bitcoin.store.WalletProtobufSerializer;
import com.google.bitcoin.utils.MockTransactionBroadcaster;
import com.google.bitcoin.utils.Threading;
import com.google.bitcoin.wallet.KeyTimeCoinSelector;
import com.google.bitcoin.wallet.WalletFiles;
@ -1910,7 +1911,7 @@ public class WalletTest extends TestWithWallet {
sendMoneyToWallet(wallet, CENT, key2.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN);
Utils.rollMockClock(86400);
Date compromiseTime = Utils.now();
assertEquals(0, broadcaster.broadcasts.size());
assertEquals(0, broadcaster.size());
assertFalse(wallet.isKeyRotating(key1));
// Rotate the wallet.
@ -1919,7 +1920,7 @@ public class WalletTest extends TestWithWallet {
// We see a broadcast triggered by setting the rotation time.
wallet.setKeyRotationTime(compromiseTime);
assertTrue(wallet.isKeyRotating(key1));
Transaction tx = broadcaster.broadcasts.take();
Transaction tx = broadcaster.waitForTransaction();
final BigInteger THREE_CENTS = CENT.add(CENT).add(CENT);
assertEquals(THREE_CENTS, tx.getValueSentFromMe(wallet));
assertEquals(THREE_CENTS.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), tx.getValueSentToMe(wallet));
@ -1931,11 +1932,11 @@ public class WalletTest extends TestWithWallet {
// Now receive some more money to key3 (secure) via a new block and check that nothing happens.
sendMoneyToWallet(wallet, CENT, key3.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN);
assertTrue(broadcaster.broadcasts.isEmpty());
assertEquals(0, broadcaster.size());
// Receive money via a new block on key1 and ensure it's immediately moved.
sendMoneyToWallet(wallet, CENT, key1.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN);
tx = broadcaster.broadcasts.take();
tx = broadcaster.waitForTransaction();
assertArrayEquals(key3.getPubKey(), tx.getOutput(0).getScriptPubKey().getPubKey());
assertEquals(1, tx.getInputs().size());
assertEquals(1, tx.getOutputs().size());
@ -1958,11 +1959,8 @@ public class WalletTest extends TestWithWallet {
// Make a normal spend and check it's all ok.
final Address address = new ECKey().toAddress(params);
wallet.sendCoins(broadcaster, address, wallet.getBalance());
tx = broadcaster.broadcasts.take();
tx = broadcaster.waitForTransaction();
assertArrayEquals(address.getHash160(), tx.getOutput(0).getScriptPubKey().getPubKeyHash());
// We have to race here because we're checking for the ABSENCE of a broadcast, and if there were to be one,
// it'd be happening in parallel.
assertEquals(null, broadcaster.broadcasts.poll(1, TimeUnit.SECONDS));
}
@Test
@ -1985,14 +1983,14 @@ public class WalletTest extends TestWithWallet {
wallet.addKey(new ECKey());
wallet.setKeyRotationTime(compromise);
Transaction tx = broadcaster.broadcasts.take();
Transaction tx = broadcaster.waitForTransaction();
final BigInteger valueSentToMe = tx.getValueSentToMe(wallet);
BigInteger fee = tx.getValueSentFromMe(wallet).subtract(valueSentToMe);
assertEquals(BigInteger.valueOf(900000), fee);
assertEquals(KeyTimeCoinSelector.MAX_SIMULTANEOUS_INPUTS, tx.getInputs().size());
assertEquals(BigInteger.valueOf(599100000), valueSentToMe);
tx = broadcaster.broadcasts.take();
tx = broadcaster.waitForTransaction();
assertNotNull(tx);
assertEquals(200, tx.getInputs().size());
}