3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-15 03:35:52 +00:00

Narrow the locking in Peer.processInv() to avoid invoking memoryPool.seen() with the Peer lock held.

This resolves an inversion that can occur if a transaction confidence listener is run due to being marked as broadcast.
Update issue 233.
This commit is contained in:
Mike Hearn 2013-03-07 16:20:06 +01:00
parent 2fb3667c42
commit f0aff6484e

View File

@ -39,6 +39,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock; import java.util.concurrent.locks.ReentrantLock;
import static com.google.bitcoin.utils.Locks.checkNotLocked;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
/** /**
@ -795,9 +796,7 @@ public class Peer {
} }
private void processInv(InventoryMessage inv) throws IOException { private void processInv(InventoryMessage inv) throws IOException {
lock.lock(); checkNotLocked(lock);
try {
// This should be called in the network loop thread for this peer.
List<InventoryItem> items = inv.getItems(); List<InventoryItem> items = inv.getItems();
// Separate out the blocks and transactions, we'll handle them differently // Separate out the blocks and transactions, we'll handle them differently
@ -857,6 +856,8 @@ public class Peer {
log.debug("{}: getdata on tx {}", address.get(), item.hash); log.debug("{}: getdata on tx {}", address.get(), item.hash);
getdata.addItem(item); getdata.addItem(item);
} }
// This can trigger transaction confidence listeners.
checkNotLocked(lock);
memoryPool.seen(item.hash, this.getAddress()); memoryPool.seen(item.hash, this.getAddress());
} }
} }
@ -865,6 +866,8 @@ public class Peer {
// end to the final FilteredBlock's transactions (in the form of a pong) sent to us // end to the final FilteredBlock's transactions (in the form of a pong) sent to us
boolean pingAfterGetData = false; boolean pingAfterGetData = false;
lock.lock();
try {
if (blocks.size() > 0 && downloadData && blockChain != null) { if (blocks.size() > 0 && downloadData && blockChain != null) {
// Ideally, we'd only ask for the data here if we actually needed it. However that can imply a lot of // Ideally, we'd only ask for the data here if we actually needed it. However that can imply a lot of
// disk IO to figure out what we've got. Normally peers will not send us inv for things we already have // disk IO to figure out what we've got. Normally peers will not send us inv for things we already have
@ -904,6 +907,9 @@ public class Peer {
// current best block we have and the orphan block. If more blocks arrive in the meantime they'll also // current best block we have and the orphan block. If more blocks arrive in the meantime they'll also
// become orphan. // become orphan.
} }
} finally {
lock.unlock();
}
if (!getdata.getItems().isEmpty()) { if (!getdata.getItems().isEmpty()) {
// This will cause us to receive a bunch of block or tx messages. // This will cause us to receive a bunch of block or tx messages.
@ -912,9 +918,6 @@ public class Peer {
if (pingAfterGetData) if (pingAfterGetData)
sendMessage(new Ping((long) Math.random() * Long.MAX_VALUE)); sendMessage(new Ping((long) Math.random() * Long.MAX_VALUE));
} finally {
lock.unlock();
}
} }
/** /**