mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-02-26 07:23:53 +01:00
Move MockTransactionBroadcaster into utils so third party code can use it in its own tests.
This commit is contained in:
parent
8d839ae5ad
commit
d4786acb14
2 changed files with 47 additions and 16 deletions
|
@ -14,18 +14,35 @@
|
||||||
* limitations under the License.
|
* 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 com.google.common.util.concurrent.SettableFuture;
|
||||||
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
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 {
|
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) {
|
public MockTransactionBroadcaster(Wallet wallet) {
|
||||||
// This code achieves nothing directly, but it sets up the broadcaster/peergroup > wallet lock ordering
|
// 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
|
@Override
|
||||||
public SettableFuture<Transaction> broadcastTransaction(Transaction tx) {
|
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();
|
lock.lock();
|
||||||
try {
|
try {
|
||||||
SettableFuture<Transaction> result = SettableFuture.create();
|
SettableFuture<Transaction> result = SettableFuture.create();
|
||||||
broadcasts.put(tx);
|
broadcasts.put(new TxFuturePair(tx, result));
|
||||||
return result;
|
return result;
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
@ -52,4 +69,20 @@ public class MockTransactionBroadcaster implements TransactionBroadcaster {
|
||||||
lock.unlock();
|
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();
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -24,6 +24,7 @@ import com.google.bitcoin.crypto.KeyCrypterException;
|
||||||
import com.google.bitcoin.crypto.KeyCrypterScrypt;
|
import com.google.bitcoin.crypto.KeyCrypterScrypt;
|
||||||
import com.google.bitcoin.crypto.TransactionSignature;
|
import com.google.bitcoin.crypto.TransactionSignature;
|
||||||
import com.google.bitcoin.store.WalletProtobufSerializer;
|
import com.google.bitcoin.store.WalletProtobufSerializer;
|
||||||
|
import com.google.bitcoin.utils.MockTransactionBroadcaster;
|
||||||
import com.google.bitcoin.utils.Threading;
|
import com.google.bitcoin.utils.Threading;
|
||||||
import com.google.bitcoin.wallet.KeyTimeCoinSelector;
|
import com.google.bitcoin.wallet.KeyTimeCoinSelector;
|
||||||
import com.google.bitcoin.wallet.WalletFiles;
|
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);
|
sendMoneyToWallet(wallet, CENT, key2.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN);
|
||||||
Utils.rollMockClock(86400);
|
Utils.rollMockClock(86400);
|
||||||
Date compromiseTime = Utils.now();
|
Date compromiseTime = Utils.now();
|
||||||
assertEquals(0, broadcaster.broadcasts.size());
|
assertEquals(0, broadcaster.size());
|
||||||
assertFalse(wallet.isKeyRotating(key1));
|
assertFalse(wallet.isKeyRotating(key1));
|
||||||
|
|
||||||
// Rotate the wallet.
|
// Rotate the wallet.
|
||||||
|
@ -1919,7 +1920,7 @@ public class WalletTest extends TestWithWallet {
|
||||||
// We see a broadcast triggered by setting the rotation time.
|
// We see a broadcast triggered by setting the rotation time.
|
||||||
wallet.setKeyRotationTime(compromiseTime);
|
wallet.setKeyRotationTime(compromiseTime);
|
||||||
assertTrue(wallet.isKeyRotating(key1));
|
assertTrue(wallet.isKeyRotating(key1));
|
||||||
Transaction tx = broadcaster.broadcasts.take();
|
Transaction tx = broadcaster.waitForTransaction();
|
||||||
final BigInteger THREE_CENTS = CENT.add(CENT).add(CENT);
|
final BigInteger THREE_CENTS = CENT.add(CENT).add(CENT);
|
||||||
assertEquals(THREE_CENTS, tx.getValueSentFromMe(wallet));
|
assertEquals(THREE_CENTS, tx.getValueSentFromMe(wallet));
|
||||||
assertEquals(THREE_CENTS.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), tx.getValueSentToMe(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.
|
// 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);
|
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.
|
// Receive money via a new block on key1 and ensure it's immediately moved.
|
||||||
sendMoneyToWallet(wallet, CENT, key1.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN);
|
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());
|
assertArrayEquals(key3.getPubKey(), tx.getOutput(0).getScriptPubKey().getPubKey());
|
||||||
assertEquals(1, tx.getInputs().size());
|
assertEquals(1, tx.getInputs().size());
|
||||||
assertEquals(1, tx.getOutputs().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.
|
// Make a normal spend and check it's all ok.
|
||||||
final Address address = new ECKey().toAddress(params);
|
final Address address = new ECKey().toAddress(params);
|
||||||
wallet.sendCoins(broadcaster, address, wallet.getBalance());
|
wallet.sendCoins(broadcaster, address, wallet.getBalance());
|
||||||
tx = broadcaster.broadcasts.take();
|
tx = broadcaster.waitForTransaction();
|
||||||
assertArrayEquals(address.getHash160(), tx.getOutput(0).getScriptPubKey().getPubKeyHash());
|
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
|
@Test
|
||||||
|
@ -1985,14 +1983,14 @@ public class WalletTest extends TestWithWallet {
|
||||||
wallet.addKey(new ECKey());
|
wallet.addKey(new ECKey());
|
||||||
wallet.setKeyRotationTime(compromise);
|
wallet.setKeyRotationTime(compromise);
|
||||||
|
|
||||||
Transaction tx = broadcaster.broadcasts.take();
|
Transaction tx = broadcaster.waitForTransaction();
|
||||||
final BigInteger valueSentToMe = tx.getValueSentToMe(wallet);
|
final BigInteger valueSentToMe = tx.getValueSentToMe(wallet);
|
||||||
BigInteger fee = tx.getValueSentFromMe(wallet).subtract(valueSentToMe);
|
BigInteger fee = tx.getValueSentFromMe(wallet).subtract(valueSentToMe);
|
||||||
assertEquals(BigInteger.valueOf(900000), fee);
|
assertEquals(BigInteger.valueOf(900000), fee);
|
||||||
assertEquals(KeyTimeCoinSelector.MAX_SIMULTANEOUS_INPUTS, tx.getInputs().size());
|
assertEquals(KeyTimeCoinSelector.MAX_SIMULTANEOUS_INPUTS, tx.getInputs().size());
|
||||||
assertEquals(BigInteger.valueOf(599100000), valueSentToMe);
|
assertEquals(BigInteger.valueOf(599100000), valueSentToMe);
|
||||||
|
|
||||||
tx = broadcaster.broadcasts.take();
|
tx = broadcaster.waitForTransaction();
|
||||||
assertNotNull(tx);
|
assertNotNull(tx);
|
||||||
assertEquals(200, tx.getInputs().size());
|
assertEquals(200, tx.getInputs().size());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue