3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-02-12 18:25:51 +00:00

TxConfidenceTable: Fix a lock in seen() and add a test.

This commit is contained in:
tau3 2018-09-04 15:29:59 +02:00 committed by Andreas Schildbach
parent 5df91ca886
commit 0c96402fc0
3 changed files with 59 additions and 6 deletions

View File

@ -62,6 +62,11 @@ import static com.google.common.base.Preconditions.*;
* To make a copy that won't be changed, use {@link TransactionConfidence#duplicate()}. * To make a copy that won't be changed, use {@link TransactionConfidence#duplicate()}.
*/ */
public class TransactionConfidence { public class TransactionConfidence {
public static class Factory {
public TransactionConfidence createConfidence(Sha256Hash hash) {
return new TransactionConfidence(hash);
}
}
/** /**
* The peers that have announced the transaction to us. Network nodes don't have stable identities, so we use * The peers that have announced the transaction to us. Network nodes don't have stable identities, so we use

View File

@ -46,7 +46,8 @@ public class TxConfidenceTable {
hash = confidence.getTransactionHash(); hash = confidence.getTransactionHash();
} }
} }
private LinkedHashMap<Sha256Hash, WeakConfidenceReference> table; private final Map<Sha256Hash, WeakConfidenceReference> table;
private final TransactionConfidence.Factory confidenceFactory;
// This ReferenceQueue gets entries added to it when they are only weakly reachable, ie, the TxConfidenceTable is the // This ReferenceQueue gets entries added to it when they are only weakly reachable, ie, the TxConfidenceTable is the
// only thing that is tracking the confidence data anymore. We check it from time to time and delete table entries // only thing that is tracking the confidence data anymore. We check it from time to time and delete table entries
@ -64,6 +65,10 @@ public class TxConfidenceTable {
* @param size Max number of transactions to track. The table will fill up to this size then stop growing. * @param size Max number of transactions to track. The table will fill up to this size then stop growing.
*/ */
public TxConfidenceTable(final int size) { public TxConfidenceTable(final int size) {
this(size, new TransactionConfidence.Factory());
}
TxConfidenceTable(final int size, TransactionConfidence.Factory confidenceFactory){
table = new LinkedHashMap<Sha256Hash, WeakConfidenceReference>() { table = new LinkedHashMap<Sha256Hash, WeakConfidenceReference>() {
@Override @Override
protected boolean removeEldestEntry(Map.Entry<Sha256Hash, WeakConfidenceReference> entry) { protected boolean removeEldestEntry(Map.Entry<Sha256Hash, WeakConfidenceReference> entry) {
@ -73,6 +78,7 @@ public class TxConfidenceTable {
} }
}; };
referenceQueue = new ReferenceQueue<>(); referenceQueue = new ReferenceQueue<>();
this.confidenceFactory = confidenceFactory;
} }
/** /**
@ -139,12 +145,13 @@ public class TxConfidenceTable {
TransactionConfidence confidence; TransactionConfidence confidence;
boolean fresh = false; boolean fresh = false;
lock.lock(); lock.lock();
{ try {
cleanTable(); cleanTable();
confidence = getOrCreate(hash); confidence = getOrCreate(hash);
fresh = confidence.markBroadcastBy(byPeer); fresh = confidence.markBroadcastBy(byPeer);
} finally {
lock.unlock();
} }
lock.unlock();
if (fresh) if (fresh)
confidence.queueListeners(TransactionConfidence.Listener.ChangeReason.SEEN_PEERS); confidence.queueListeners(TransactionConfidence.Listener.ChangeReason.SEEN_PEERS);
return confidence; return confidence;
@ -164,7 +171,7 @@ public class TxConfidenceTable {
if (confidence != null) if (confidence != null)
return confidence; return confidence;
} }
TransactionConfidence newConfidence = new TransactionConfidence(hash); TransactionConfidence newConfidence = confidenceFactory.createConfidence(hash);
table.put(hash, new WeakConfidenceReference(newConfidence, referenceQueue)); table.put(hash, new WeakConfidenceReference(newConfidence, referenceQueue));
return newConfidence; return newConfidence;
} finally { } finally {

View File

@ -23,8 +23,15 @@ import org.junit.*;
import java.net.*; import java.net.*;
import static org.bitcoinj.core.Coin.*; import static org.bitcoinj.core.Coin.COIN;
import static org.junit.Assert.*; import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.expectLastCall;
import static org.easymock.EasyMock.replay;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
public class TxConfidenceTableTest { public class TxConfidenceTableTest {
private static final NetworkParameters UNITTEST = UnitTestParams.get(); private static final NetworkParameters UNITTEST = UnitTestParams.get();
@ -85,6 +92,40 @@ public class TxConfidenceTableTest {
assertNull(run[0]); assertNull(run[0]);
} }
@Test
public void testSeen() {
PeerAddress peer = createMock(PeerAddress.class);
Sha256Hash brokenHash = createMock(Sha256Hash.class);
Sha256Hash correctHash = createMock(Sha256Hash.class);
TransactionConfidence brokenConfidence = createMock(TransactionConfidence.class);
expect(brokenConfidence.getTransactionHash()).andReturn(brokenHash);
expect(brokenConfidence.markBroadcastBy(peer)).andThrow(new ArithmeticException("some error"));
TransactionConfidence correctConfidence = createMock(TransactionConfidence.class);
expect(correctConfidence.getTransactionHash()).andReturn(correctHash);
expect(correctConfidence.markBroadcastBy(peer)).andReturn(true);
correctConfidence.queueListeners(anyObject(TransactionConfidence.Listener.ChangeReason.class));
expectLastCall();
TransactionConfidence.Factory factory = createMock(TransactionConfidence.Factory.class);
expect(factory.createConfidence(brokenHash)).andReturn(brokenConfidence);
expect(factory.createConfidence(correctHash)).andReturn(correctConfidence);
replay(factory, brokenConfidence, correctConfidence);
TxConfidenceTable table = new TxConfidenceTable(1, factory);
try {
table.seen(brokenHash, peer);
} catch (ArithmeticException expected) {
// do nothing
}
assertNotNull(table.seen(correctHash, peer));
}
@Test @Test
public void invAndDownload() throws Exception { public void invAndDownload() throws Exception {
// Base case: we see a transaction announced twice and then download it. The count is in the confidence object. // Base case: we see a transaction announced twice and then download it. The count is in the confidence object.