3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-07 06:44:16 +00:00

Some fixes for crashes that could occur with a chain-less PeerGroup post-TxConfidenceTable changes.

This commit is contained in:
Mike Hearn 2014-12-07 13:17:35 +02:00
parent 478fb5dac9
commit 40c4338aaa
4 changed files with 27 additions and 22 deletions

View File

@ -1,9 +1,10 @@
package org.bitcoinj.core;
/**
* The Context object holds various objects that are relevant to the global state of our
* view of the Bitcoin network. You can get an instance of this class
* through {@link AbstractBlockChain#getContext()}.
* The Context object holds various objects that are scoped to a specific instantiation of bitcoinj for a specific
* network. You can get an instance of this class through {@link AbstractBlockChain#getContext()}. At the momemnt it
* only contains a {@link org.bitcoinj.core.TxConfidenceTable} but in future it will likely contain file paths and
* other global configuration of use.
*/
public class Context {
protected TxConfidenceTable confidenceTable;

View File

@ -119,9 +119,6 @@ public class PeerGroup implements TransactionBroadcaster {
@GuardedBy("lock") private VersionMessage versionMessage;
// Switch for enabling download of pending transaction dependencies.
@GuardedBy("lock") private boolean downloadTxDependencies;
// A class that tracks recent transactions that have been broadcast across the network, counts how many
// peers announced them and updates the transaction confidence data. It is passed to each Peer.
private final TxConfidenceTable confidenceTable;
// How many connections we want to have open at the current time. If we lose connections, we'll try opening more
// until we reach this count.
@GuardedBy("lock") private int maxConnections;
@ -139,7 +136,7 @@ public class PeerGroup implements TransactionBroadcaster {
@GuardedBy("lock") private boolean ipv6Unreachable = false;
private final NetworkParameters params;
private final AbstractBlockChain chain;
@Nullable private final AbstractBlockChain chain;
@GuardedBy("lock") private long fastCatchupTimeSecs;
private final CopyOnWriteArrayList<Wallet> wallets;
private final CopyOnWriteArrayList<PeerFilterProvider> peerFilterProviders;
@ -154,7 +151,8 @@ public class PeerGroup implements TransactionBroadcaster {
@Override
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
final double rate = checkNotNull(chain).getFalsePositiveRate();
if (chain == null) return;
final double rate = chain.getFalsePositiveRate();
final double target = bloomFilterMerger.getBloomFilterFPRate() * MAX_FP_RATE_INCREASE;
if (rate > target) {
// TODO: Avoid hitting this path if the remote peer didn't acknowledge applying a new filter yet.
@ -335,8 +333,6 @@ public class PeerGroup implements TransactionBroadcaster {
downloadTxDependencies = true;
confidenceTable = chain.getContext().getConfidenceTable();
inactives = new PriorityQueue<PeerAddress>(1, new Comparator<PeerAddress>() {
@SuppressWarnings("FieldAccessNotGuarded") // only called when inactives is accessed, and lock is held then.
@Override
@ -450,8 +446,8 @@ public class PeerGroup implements TransactionBroadcaster {
}
}
long retryTime = 0;
PeerAddress addrToTry = null;
long retryTime;
PeerAddress addrToTry;
lock.lock();
try {
if (doDiscovery) {
@ -521,7 +517,7 @@ public class PeerGroup implements TransactionBroadcaster {
while (it.hasNext()) {
InventoryItem item = it.next();
// Check the confidence pool first.
Transaction tx = confidenceTable.get(item.hash);
Transaction tx = chain != null ? chain.getContext().getConfidenceTable().get(item.hash) : null;
if (tx != null) {
transactions.add(tx);
it.remove();
@ -1326,11 +1322,13 @@ public class PeerGroup implements TransactionBroadcaster {
}
/**
* Use {@link org.bitcoinj.core.Context#getConfidenceTable()} instead.
* Use {@link org.bitcoinj.core.Context#getConfidenceTable()} instead, which can be retrieved via
* {@link org.bitcoinj.core.AbstractBlockChain#getContext()}. Can return null if this peer group was
* configured without a block chain object.
*/
@Deprecated
public TxConfidenceTable getConfidenceTable() {
return confidenceTable;
@Deprecated @Nullable
public TxConfidenceTable getMemoryPool() {
return chain == null ? null : chain.getContext().getConfidenceTable();
}
/**
@ -1341,7 +1339,7 @@ public class PeerGroup implements TransactionBroadcaster {
public void setFastCatchupTimeSecs(long secondsSinceEpoch) {
lock.lock();
try {
Preconditions.checkState(chain == null || !chain.shouldVerifyTransactions(), "Fast catchup is incompatible with fully verifying");
checkState(chain == null || !chain.shouldVerifyTransactions(), "Fast catchup is incompatible with fully verifying");
fastCatchupTimeSecs = secondsSinceEpoch;
if (downloadPeer != null) {
downloadPeer.setDownloadParameters(secondsSinceEpoch, bloomFilterMerger.getLastFilter() != null);
@ -1563,7 +1561,8 @@ public class PeerGroup implements TransactionBroadcaster {
* bringup of the peer group you can lower it.</p>
*/
public ListenableFuture<Transaction> broadcastTransaction(final Transaction tx, final int minConnections) {
final TransactionBroadcast broadcast = new TransactionBroadcast(this, tx);
// TODO: Context being owned by BlockChain isn't right w.r.t future intentions so it shouldn't really be optional here.
final TransactionBroadcast broadcast = new TransactionBroadcast(this, chain != null ? chain.getContext() : null, tx);
broadcast.setMinConnections(minConnections);
// Send the TX to the wallet once we have a successful broadcast.
Futures.addCallback(broadcast.future(), new FutureCallback<Transaction>() {

View File

@ -24,6 +24,7 @@ import com.google.common.util.concurrent.SettableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Random;
@ -41,6 +42,7 @@ public class TransactionBroadcast {
private final SettableFuture<Transaction> future = SettableFuture.create();
private final PeerGroup peerGroup;
private final Transaction tx;
@Nullable private final Context context;
private int minConnections;
private int numWaitingFor, numToBroadcastTo;
@ -49,8 +51,10 @@ public class TransactionBroadcast {
public static Random random = new Random();
private Transaction pinnedTx;
public TransactionBroadcast(PeerGroup peerGroup, Transaction tx) {
// TODO: Context being owned by BlockChain isn't right w.r.t future intentions so it shouldn't really be optional here.
TransactionBroadcast(PeerGroup peerGroup, @Nullable Context context, Transaction tx) {
this.peerGroup = peerGroup;
this.context = context;
this.tx = tx;
this.minConnections = Math.max(1, peerGroup.getMinBroadcastConnections());
}
@ -98,7 +102,8 @@ public class TransactionBroadcast {
// a big effect.
List<Peer> peers = peerGroup.getConnectedPeers(); // snapshots
// We intern the tx here so we are using a canonical version of the object (as it's unfortunately mutable).
pinnedTx = peerGroup.getConfidenceTable().intern(tx);
// TODO: Once confidence state is moved out of Transaction we can kill off this step.
pinnedTx = context != null ? context.getConfidenceTable().intern(tx) : pinnedTx;
// Prepare to send the transaction by adding a listener that'll be called when confidence changes.
// Only bother with this if we might actually hear back:
if (minConnections > 1)

View File

@ -376,7 +376,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
inbound(p2, inv);
assertTrue(outbound(p2) instanceof GetDataMessage);
assertEquals(0, tx.getConfidence().numBroadcastPeers());
assertTrue(peerGroup.getConfidenceTable().maybeWasSeen(tx.getHash()));
assertTrue(blockChain.getContext().getConfidenceTable().maybeWasSeen(tx.getHash()));
assertNull(event[0]);
// Peer 1 advertises the tx, we don't do anything as it's already been requested.
inbound(p1, inv);