mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2024-11-19 01:40:26 +01:00
ListMessage, InventoryMessage, GetDataMessage: make immutable (after deprecations removed)
Make `ListMessage` and its subclasses "almost" immutable. When the deprecated `addItem()`, `removeItem()`, etc. methods are removed and the constructors are changed to create an ummodifiable `List`, they will be immutable.
This commit is contained in:
parent
9d78d2bd9e
commit
111a8b8a37
@ -21,13 +21,14 @@ import org.bitcoinj.base.Sha256Hash;
|
||||
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <p>Represents the "getdata" P2P network message, which requests the contents of blocks or transactions given their
|
||||
* hashes.</p>
|
||||
*
|
||||
* <p>Instances of this class are not safe for use by multiple threads.</p>
|
||||
*
|
||||
* <p>Instances of this class -- that use deprecated methods -- are not safe for use by multiple threads.</p>
|
||||
*/
|
||||
public class GetDataMessage extends ListMessage {
|
||||
/**
|
||||
@ -41,23 +42,43 @@ public class GetDataMessage extends ListMessage {
|
||||
return new GetDataMessage(readItems(payload));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public GetDataMessage() {
|
||||
super();
|
||||
}
|
||||
|
||||
private GetDataMessage(List<InventoryItem> items) {
|
||||
GetDataMessage(List<InventoryItem> items) {
|
||||
super(items);
|
||||
}
|
||||
|
||||
public static GetDataMessage ofBlock(Sha256Hash blockHash, boolean includeWitness) {
|
||||
return new GetDataMessage(Collections.singletonList(
|
||||
new InventoryItem(includeWitness
|
||||
? InventoryItem.Type.WITNESS_BLOCK
|
||||
: InventoryItem.Type.BLOCK,
|
||||
blockHash)));
|
||||
}
|
||||
|
||||
public static GetDataMessage ofTransaction(Sha256Hash txId, boolean includeWitness) {
|
||||
return new GetDataMessage(Collections.singletonList(
|
||||
new InventoryItem(includeWitness
|
||||
? InventoryItem.Type.WITNESS_TRANSACTION
|
||||
: InventoryItem.Type.TRANSACTION,
|
||||
txId)));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addTransaction(Sha256Hash hash, boolean includeWitness) {
|
||||
addItem(new InventoryItem(
|
||||
includeWitness ? InventoryItem.Type.WITNESS_TRANSACTION : InventoryItem.Type.TRANSACTION, hash));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addBlock(Sha256Hash hash, boolean includeWitness) {
|
||||
addItem(new InventoryItem(includeWitness ? InventoryItem.Type.WITNESS_BLOCK : InventoryItem.Type.BLOCK, hash));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addFilteredBlock(Sha256Hash hash) {
|
||||
addItem(new InventoryItem(InventoryItem.Type.FILTERED_BLOCK, hash));
|
||||
}
|
||||
|
@ -57,6 +57,16 @@ public class InventoryItem {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public InventoryItem(Block block) {
|
||||
this.type = Type.BLOCK;
|
||||
this.hash = block.getHash();
|
||||
}
|
||||
|
||||
public InventoryItem(Transaction tx) {
|
||||
this.type = Type.TRANSACTION;
|
||||
this.hash = tx.getTxId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type + ": " + hash;
|
||||
|
@ -18,7 +18,10 @@ package org.bitcoinj.core;
|
||||
|
||||
import java.nio.BufferUnderflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.bitcoinj.base.internal.Preconditions.checkArgument;
|
||||
|
||||
@ -27,8 +30,8 @@ import static org.bitcoinj.base.internal.Preconditions.checkArgument;
|
||||
* a bandwidth optimization - on receiving some data, a (fully validating) peer sends every connected peer an inv
|
||||
* containing the hash of what it saw. It'll only transmit the full thing if a peer asks for it with a
|
||||
* {@link GetDataMessage}.</p>
|
||||
*
|
||||
* <p>Instances of this class are not safe for use by multiple threads.</p>
|
||||
*
|
||||
* <p>Instances of this class -- that use deprecated methods -- are not safe for use by multiple threads.</p>
|
||||
*/
|
||||
public class InventoryMessage extends ListMessage {
|
||||
|
||||
@ -46,7 +49,8 @@ public class InventoryMessage extends ListMessage {
|
||||
return new InventoryMessage(readItems(payload));
|
||||
}
|
||||
|
||||
public InventoryMessage() {
|
||||
@Deprecated
|
||||
protected InventoryMessage() {
|
||||
super();
|
||||
}
|
||||
|
||||
@ -54,20 +58,50 @@ public class InventoryMessage extends ListMessage {
|
||||
super(items);
|
||||
}
|
||||
|
||||
public static InventoryMessage ofBlocks(List<Block> blocks) {
|
||||
checkArgument(!blocks.isEmpty());
|
||||
return new InventoryMessage(blocks.stream()
|
||||
.map(InventoryItem::new)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static InventoryMessage ofBlocks(Block ...blocks) {
|
||||
return ofBlocks(Arrays.asList(blocks));
|
||||
}
|
||||
|
||||
public static InventoryMessage ofTransactions(List<Transaction> transactions) {
|
||||
checkArgument(!transactions.isEmpty());
|
||||
return new InventoryMessage(transactions.stream()
|
||||
.map(InventoryItem::new)
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public static InventoryMessage ofTransactions(Transaction ...transactions) {
|
||||
return ofTransactions(Arrays.asList(transactions));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use a constructor or factoring
|
||||
*/
|
||||
@Deprecated
|
||||
public void addBlock(Block block) {
|
||||
addItem(new InventoryItem(InventoryItem.Type.BLOCK, block.getHash()));
|
||||
addItem(new InventoryItem(block));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use a constructor or factoring
|
||||
*/
|
||||
@Deprecated
|
||||
public void addTransaction(Transaction tx) {
|
||||
addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, tx.getTxId()));
|
||||
addItem(new InventoryItem(tx));
|
||||
}
|
||||
|
||||
/** Creates a new inv message for the given transactions. */
|
||||
/**
|
||||
* Creates a new inv message for the given transactions.
|
||||
* @deprecated Use {@link #ofTransactions(Transaction...)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static InventoryMessage with(Transaction... txns) {
|
||||
checkArgument(txns.length > 0);
|
||||
InventoryMessage result = new InventoryMessage();
|
||||
for (Transaction tx : txns)
|
||||
result.addTransaction(tx);
|
||||
return result;
|
||||
return ofTransactions(txns);
|
||||
}
|
||||
}
|
||||
|
@ -35,12 +35,12 @@ import static org.bitcoinj.base.internal.Preconditions.check;
|
||||
/**
|
||||
* <p>Abstract superclass of classes with list based payload, ie InventoryMessage and GetDataMessage.</p>
|
||||
*
|
||||
* <p>Instances of this class are not safe for use by multiple threads.</p>
|
||||
* <p>Instances of this class -- that use deprecated methods -- are not safe for use by multiple threads.</p>
|
||||
*/
|
||||
public abstract class ListMessage extends BaseMessage {
|
||||
|
||||
// For some reason the compiler complains if this is inside InventoryItem
|
||||
protected List<InventoryItem> items;
|
||||
protected final List<InventoryItem> items;
|
||||
|
||||
public static final int MAX_INVENTORY_ITEMS = 50000;
|
||||
|
||||
@ -68,23 +68,26 @@ public abstract class ListMessage extends BaseMessage {
|
||||
return items;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ListMessage() {
|
||||
super();
|
||||
items = new ArrayList<>();
|
||||
items = new ArrayList<>(); // TODO: unmodifiable empty list
|
||||
}
|
||||
|
||||
protected ListMessage(List<InventoryItem> items) {
|
||||
this.items = items;
|
||||
this.items = items; // TODO: unmodifiable defensive copy
|
||||
}
|
||||
|
||||
public List<InventoryItem> getItems() {
|
||||
return Collections.unmodifiableList(items);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void addItem(InventoryItem item) {
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void removeItem(int index) {
|
||||
items.remove(index);
|
||||
}
|
||||
|
@ -24,8 +24,8 @@ import java.util.List;
|
||||
/**
|
||||
* <p>Sent by a peer when a getdata request doesn't find the requested data in the mempool. It has the same format
|
||||
* as an inventory message and lists the hashes of the missing items.</p>
|
||||
*
|
||||
* <p>Instances of this class are not safe for use by multiple threads.</p>
|
||||
*
|
||||
* <p>Instances of this class -- that use deprecated methods -- are not safe for use by multiple threads.</p>
|
||||
*/
|
||||
public class NotFoundMessage extends InventoryMessage {
|
||||
public static int MIN_PROTOCOL_VERSION = 70001;
|
||||
@ -41,6 +41,7 @@ public class NotFoundMessage extends InventoryMessage {
|
||||
return new NotFoundMessage(readItems(payload));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public NotFoundMessage() {
|
||||
super();
|
||||
}
|
||||
|
@ -910,10 +910,13 @@ public class Peer extends PeerSocketHandler {
|
||||
* @return A GetDataMessage that will query those IDs
|
||||
*/
|
||||
private GetDataMessage buildMultiTransactionDataMessage(Set<Sha256Hash> txIds) {
|
||||
GetDataMessage getdata = new GetDataMessage();
|
||||
txIds.forEach(txId ->
|
||||
getdata.addTransaction(txId, vPeerVersionMessage.services().has(Services.NODE_WITNESS)));
|
||||
return getdata;
|
||||
InventoryItem.Type itemType = vPeerVersionMessage.services().has(Services.NODE_WITNESS)
|
||||
? InventoryItem.Type.WITNESS_TRANSACTION
|
||||
: InventoryItem.Type.TRANSACTION;
|
||||
List<InventoryItem> items = txIds.stream()
|
||||
.map(hash -> new InventoryItem(itemType, hash))
|
||||
.collect(Collectors.toList());
|
||||
return new GetDataMessage(items);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1129,34 +1132,35 @@ public class Peer extends PeerSocketHandler {
|
||||
List<InventoryItem> items = inv.getItems();
|
||||
|
||||
// Separate out the blocks and transactions, we'll handle them differently
|
||||
List<InventoryItem> transactions = new LinkedList<>();
|
||||
List<InventoryItem> blocks = new LinkedList<>();
|
||||
List<Sha256Hash> transactions = new LinkedList<>();
|
||||
List<Sha256Hash> blocks = new LinkedList<>();
|
||||
|
||||
for (InventoryItem item : items) {
|
||||
switch (item.type) {
|
||||
case TRANSACTION:
|
||||
transactions.add(item);
|
||||
transactions.add(item.hash);
|
||||
break;
|
||||
case BLOCK:
|
||||
blocks.add(item);
|
||||
blocks.add(item.hash);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Not implemented: " + item.type);
|
||||
}
|
||||
}
|
||||
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("{}: processing 'inv' with {} items: {} blocks, {} txns", this, items.size(), blocks.size(),
|
||||
transactions.size());
|
||||
|
||||
final boolean downloadData = this.vDownloadData;
|
||||
|
||||
if (transactions.size() == 0 && blocks.size() == 1) {
|
||||
if (transactions.isEmpty() && blocks.size() == 1) {
|
||||
// Single block announcement. If we're downloading the chain this is just a tickle to make us continue
|
||||
// (the block chain download protocol is very implicit and not well thought out). If we're not downloading
|
||||
// the chain then this probably means a new block was solved and the peer believes it connects to the best
|
||||
// chain, so count it. This way getBestChainHeight() can be accurate.
|
||||
if (downloadData && blockChain != null) {
|
||||
if (!blockChain.isOrphan(blocks.get(0).hash)) {
|
||||
if (!blockChain.isOrphan(blocks.get(0))) {
|
||||
blocksAnnounced.incrementAndGet();
|
||||
}
|
||||
} else {
|
||||
@ -1164,11 +1168,14 @@ public class Peer extends PeerSocketHandler {
|
||||
}
|
||||
}
|
||||
|
||||
GetDataMessage getdata = new GetDataMessage();
|
||||
InventoryItem.Type txItemType = vPeerVersionMessage.services().has(Services.NODE_WITNESS)
|
||||
? InventoryItem.Type.WITNESS_TRANSACTION
|
||||
: InventoryItem.Type.TRANSACTION;
|
||||
List<InventoryItem> getDataItems = new ArrayList<>();
|
||||
|
||||
Iterator<InventoryItem> it = transactions.iterator();
|
||||
Iterator<Sha256Hash> it = transactions.iterator();
|
||||
while (it.hasNext()) {
|
||||
InventoryItem item = it.next();
|
||||
Sha256Hash item = it.next();
|
||||
// Only download the transaction if we are the first peer that saw it be advertised. Other peers will also
|
||||
// see it be advertised in inv packets asynchronously, they co-ordinate via the memory pool. We could
|
||||
// potentially download transactions faster by always asking every peer for a tx when advertised, as remote
|
||||
@ -1177,7 +1184,7 @@ public class Peer extends PeerSocketHandler {
|
||||
// sending us the transaction: currently we'll never try to re-fetch after a timeout.
|
||||
//
|
||||
// The line below can trigger confidence listeners.
|
||||
TransactionConfidence conf = context.getConfidenceTable().seen(item.hash, this.getAddress());
|
||||
TransactionConfidence conf = context.getConfidenceTable().seen(item, this.getAddress());
|
||||
if (conf.numBroadcastPeers() > 1) {
|
||||
// Some other peer already announced this so don't download.
|
||||
it.remove();
|
||||
@ -1186,8 +1193,8 @@ public class Peer extends PeerSocketHandler {
|
||||
it.remove();
|
||||
} else {
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("{}: getdata on tx {}", getAddress(), item.hash);
|
||||
getdata.addTransaction(item.hash, vPeerVersionMessage.services().has(Services.NODE_WITNESS));
|
||||
log.debug("{}: getdata on tx {}", getAddress(), item);
|
||||
getDataItems.add(new InventoryItem(txItemType, item));
|
||||
if (pendingTxDownloads.size() > PENDING_TX_DOWNLOADS_LIMIT) {
|
||||
log.info("{}: Too many pending transactions, disconnecting", this);
|
||||
close();
|
||||
@ -1208,11 +1215,11 @@ public class Peer extends PeerSocketHandler {
|
||||
// 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
|
||||
// so we just re-request it here, and if we get duplicates the block chain / wallet will filter them out.
|
||||
for (InventoryItem item : blocks) {
|
||||
if (blockChain.isOrphan(item.hash) && downloadBlockBodies) {
|
||||
for (Sha256Hash item : blocks) {
|
||||
if (blockChain.isOrphan(item) && downloadBlockBodies) {
|
||||
// If an orphan was re-advertised, ask for more blocks unless we are not currently downloading
|
||||
// full block data because we have a getheaders outstanding.
|
||||
final Block orphanRoot = Objects.requireNonNull(blockChain.getOrphanRoot(item.hash));
|
||||
final Block orphanRoot = Objects.requireNonNull(blockChain.getOrphanRoot(item));
|
||||
blockChainDownloadLocked(orphanRoot.getHash());
|
||||
} else {
|
||||
// Don't re-request blocks we already requested. Normally this should not happen. However there is
|
||||
@ -1227,14 +1234,14 @@ public class Peer extends PeerSocketHandler {
|
||||
// part of chain download with newly announced blocks, so it should always be taken care of by
|
||||
// the duplicate check in blockChainDownloadLocked(). But Bitcoin Core may change in future so
|
||||
// it's better to be safe here.
|
||||
if (!pendingBlockDownloads.contains(item.hash)) {
|
||||
if (!pendingBlockDownloads.contains(item)) {
|
||||
if (isBloomFilteringSupported(vPeerVersionMessage) && useFilteredBlocks) {
|
||||
getdata.addFilteredBlock(item.hash);
|
||||
getDataItems.add(new InventoryItem(InventoryItem.Type.FILTERED_BLOCK, item));
|
||||
pingAfterGetData = true;
|
||||
} else {
|
||||
getdata.addBlock(item.hash, vPeerVersionMessage.services().has(Services.NODE_WITNESS));
|
||||
getDataItems.add(new InventoryItem(InventoryItem.Type.BLOCK, item));
|
||||
}
|
||||
pendingBlockDownloads.add(item.hash);
|
||||
pendingBlockDownloads.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1248,8 +1255,9 @@ public class Peer extends PeerSocketHandler {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
if (!getdata.getItems().isEmpty()) {
|
||||
if (!getDataItems.isEmpty()) {
|
||||
// This will cause us to receive a bunch of block or tx messages.
|
||||
GetDataMessage getdata = new GetDataMessage(getDataItems);
|
||||
sendMessage(getdata);
|
||||
}
|
||||
|
||||
@ -1269,8 +1277,7 @@ public class Peer extends PeerSocketHandler {
|
||||
public ListenableCompletableFuture<Block> getBlock(Sha256Hash blockHash) {
|
||||
// This does not need to be locked.
|
||||
log.info("Request to fetch block {}", blockHash);
|
||||
GetDataMessage getdata = new GetDataMessage();
|
||||
getdata.addBlock(blockHash, true);
|
||||
GetDataMessage getdata = GetDataMessage.ofBlock(blockHash, true);
|
||||
return ListenableCompletableFuture.of(sendSingleGetData(getdata));
|
||||
}
|
||||
|
||||
@ -1287,8 +1294,7 @@ public class Peer extends PeerSocketHandler {
|
||||
// This does not need to be locked.
|
||||
// TODO: Unit test this method.
|
||||
log.info("Request to fetch peer mempool tx {}", hash);
|
||||
GetDataMessage getdata = new GetDataMessage();
|
||||
getdata.addTransaction(hash, vPeerVersionMessage.services().has(Services.NODE_WITNESS));
|
||||
GetDataMessage getdata = GetDataMessage.ofTransaction(hash, vPeerVersionMessage.services().has(Services.NODE_WITNESS));
|
||||
return ListenableCompletableFuture.of(sendSingleGetData(getdata));
|
||||
}
|
||||
|
||||
@ -1760,9 +1766,10 @@ public class Peer extends PeerSocketHandler {
|
||||
sendPing().thenRunAsync(() -> {
|
||||
lock.lock();
|
||||
Objects.requireNonNull(awaitingFreshFilter);
|
||||
GetDataMessage getdata = new GetDataMessage();
|
||||
for (Sha256Hash hash : awaitingFreshFilter)
|
||||
getdata.addFilteredBlock(hash);
|
||||
List<InventoryItem> items = awaitingFreshFilter.stream()
|
||||
.map(hash -> new InventoryItem(InventoryItem.Type.FILTERED_BLOCK, hash))
|
||||
.collect(Collectors.toList());
|
||||
GetDataMessage getdata = new GetDataMessage(items);
|
||||
awaitingFreshFilter = null;
|
||||
lock.unlock();
|
||||
|
||||
|
@ -188,9 +188,7 @@ public class BitcoindComparisonTool {
|
||||
if (!found)
|
||||
sendHeaders = headers;
|
||||
bitcoind.sendMessage(new HeadersMessage(sendHeaders));
|
||||
InventoryMessage i = new InventoryMessage();
|
||||
for (Block b : sendHeaders)
|
||||
i.addBlock(b);
|
||||
InventoryMessage i = InventoryMessage.ofBlocks(sendHeaders);
|
||||
bitcoind.sendMessage(i);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
@ -271,8 +269,7 @@ public class BitcoindComparisonTool {
|
||||
boolean shouldntRequest = blocksRequested.contains(nextBlock.getHash());
|
||||
if (shouldntRequest)
|
||||
blocksRequested.remove(nextBlock.getHash());
|
||||
InventoryMessage message = new InventoryMessage();
|
||||
message.addBlock(nextBlock);
|
||||
InventoryMessage message = InventoryMessage.ofBlocks(nextBlock);
|
||||
bitcoind.sendMessage(message);
|
||||
log.info("Sent inv with block " + nextBlock.getHashAsString());
|
||||
if (blocksPendingSend.contains(nextBlock.getHash())) {
|
||||
|
@ -188,8 +188,7 @@ public class FilteredBlockAndPartialMerkleTreeTest extends TestWithPeerGroup {
|
||||
InboundMessageQueuer p1 = connectPeer(1);
|
||||
assertEquals(1, peerGroup.numConnectedPeers());
|
||||
// Send an inv for block 100001
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addBlock(block);
|
||||
InventoryMessage inv = InventoryMessage.ofBlocks(block);
|
||||
inbound(p1, inv);
|
||||
|
||||
// Check that we properly requested the correct FilteredBlock
|
||||
|
@ -247,8 +247,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
|
||||
Coin value = COIN;
|
||||
Transaction t1 = FakeTxBuilder.createFakeTx(UNITTEST.network(), value, address);
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addTransaction(t1);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(t1);
|
||||
|
||||
// Note: we start with p2 here to verify that transactions are downloaded from whichever peer announces first
|
||||
// which does not have to be the same as the download peer (which is really the "block download peer").
|
||||
@ -287,8 +286,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
|
||||
Coin value = COIN;
|
||||
Transaction t1 = FakeTxBuilder.createFakeTx(UNITTEST.network(), value, address2);
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addTransaction(t1);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(t1);
|
||||
|
||||
inbound(p1, inv);
|
||||
assertTrue(outbound(p1) instanceof GetDataMessage);
|
||||
@ -319,8 +317,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
Block b3 = FakeTxBuilder.makeSolvedTestBlock(b2);
|
||||
|
||||
// Peer 1 and 2 receives an inv advertising a newly solved block.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addBlock(b3);
|
||||
InventoryMessage inv = InventoryMessage.ofBlocks(b3);
|
||||
// Only peer 1 tries to download it.
|
||||
inbound(p1, inv);
|
||||
pingAndWait(p1);
|
||||
@ -358,11 +355,8 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
GetBlocksMessage getblocks = (GetBlocksMessage) outbound(p1);
|
||||
assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash());
|
||||
// We give back an inv with some blocks in it.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addBlock(b1);
|
||||
inv.addBlock(b2);
|
||||
inv.addBlock(b3);
|
||||
|
||||
InventoryMessage inv = InventoryMessage.ofBlocks(b1, b2, b3);
|
||||
|
||||
inbound(p1, inv);
|
||||
assertTrue(outbound(p1) instanceof GetDataMessage);
|
||||
// We hand back the first block.
|
||||
@ -388,8 +382,7 @@ public class PeerGroupTest extends TestWithPeerGroup {
|
||||
InboundMessageQueuer p3 = connectPeer(3);
|
||||
|
||||
Transaction tx = FakeTxBuilder.createFakeTx(UNITTEST.network(), valueOf(20, 0), address);
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addTransaction(tx);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(tx);
|
||||
|
||||
assertEquals(0, tx.getConfidence().numBroadcastPeers());
|
||||
assertFalse(tx.getConfidence().lastBroadcastTime().isPresent());
|
||||
|
@ -30,6 +30,7 @@ import org.bitcoinj.testing.InboundMessageQueuer;
|
||||
import org.bitcoinj.testing.TestWithNetworkConnections;
|
||||
import org.bitcoinj.utils.Threading;
|
||||
import org.bitcoinj.wallet.Wallet;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -46,8 +47,10 @@ import java.net.SocketException;
|
||||
import java.nio.channels.CancelledKeyException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@ -140,9 +143,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
assertEquals(blockStore.getChainHead().getHeader().getHash(), getblocks.getLocator().get(0));
|
||||
assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash());
|
||||
// Remote peer sends us an inv with some blocks.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addBlock(b2);
|
||||
inv.addBlock(b3);
|
||||
InventoryMessage inv = InventoryMessage.ofBlocks(b2, b3);
|
||||
// We do a getdata on them.
|
||||
inbound(writeTarget, inv);
|
||||
GetDataMessage getdata = (GetDataMessage)outbound(writeTarget);
|
||||
@ -154,8 +155,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
inbound(writeTarget, b2);
|
||||
inbound(writeTarget, b3);
|
||||
|
||||
inv = new InventoryMessage();
|
||||
inv.addBlock(b5);
|
||||
inv = InventoryMessage.ofBlocks(b5);
|
||||
// We request the head block.
|
||||
inbound(writeTarget, inv);
|
||||
getdata = (GetDataMessage)outbound(writeTarget);
|
||||
@ -173,8 +173,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
// because we walk backwards down the orphan chain and then discover we already asked for those blocks, so
|
||||
// nothing is done.
|
||||
Block b6 = makeSolvedTestBlock(b5);
|
||||
inv = new InventoryMessage();
|
||||
inv.addBlock(b6);
|
||||
inv = InventoryMessage.ofBlocks(b6);
|
||||
inbound(writeTarget, inv);
|
||||
getdata = (GetDataMessage)outbound(writeTarget);
|
||||
assertEquals(1, getdata.getItems().size());
|
||||
@ -182,9 +181,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
inbound(writeTarget, b6);
|
||||
assertNull(outbound(writeTarget)); // Nothing is sent at this point.
|
||||
// We're still waiting for the response to the getblocks (b3,b5) sent above.
|
||||
inv = new InventoryMessage();
|
||||
inv.addBlock(b4);
|
||||
inv.addBlock(b5);
|
||||
inv = InventoryMessage.ofBlocks(b4, b5);
|
||||
inbound(writeTarget, inv);
|
||||
getdata = (GetDataMessage)outbound(writeTarget);
|
||||
assertEquals(1, getdata.getItems().size());
|
||||
@ -208,9 +205,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
Block b3 = makeSolvedTestBlock(b2);
|
||||
inbound(writeTarget, b3);
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
InventoryItem item = new InventoryItem(InventoryItem.Type.BLOCK, b3.getHash());
|
||||
inv.addItem(item);
|
||||
InventoryMessage inv = InventoryMessage.ofBlocks(b3);
|
||||
inbound(writeTarget, inv);
|
||||
|
||||
GetBlocksMessage getblocks = (GetBlocksMessage)outbound(writeTarget);
|
||||
@ -237,9 +232,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
Block b2 = makeSolvedTestBlock(b1);
|
||||
|
||||
// Receive an inv.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
InventoryItem item = new InventoryItem(InventoryItem.Type.BLOCK, b2.getHash());
|
||||
inv.addItem(item);
|
||||
InventoryMessage inv = InventoryMessage.ofBlocks(b2);
|
||||
inbound(writeTarget, inv);
|
||||
|
||||
// Peer does nothing with it.
|
||||
@ -254,9 +247,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
// Make a transaction and tell the peer we have it.
|
||||
Coin value = COIN;
|
||||
Transaction tx = createFakeTx(TESTNET.network(), value, address);
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
InventoryItem item = new InventoryItem(InventoryItem.Type.TRANSACTION, tx.getTxId());
|
||||
inv.addItem(item);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(tx);
|
||||
inbound(writeTarget, inv);
|
||||
// Peer hasn't seen it before, so will ask for it.
|
||||
GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
|
||||
@ -287,9 +278,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
// Make a tx and advertise it to one of the peers.
|
||||
Coin value = COIN;
|
||||
Transaction tx = createFakeTx(TESTNET.network(), value, this.address);
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
InventoryItem item = new InventoryItem(InventoryItem.Type.TRANSACTION, tx.getTxId());
|
||||
inv.addItem(item);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(tx);
|
||||
|
||||
inbound(writeTarget, inv);
|
||||
|
||||
@ -313,9 +302,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
blockChain.add(b1);
|
||||
final Block b2 = makeSolvedTestBlock(b1);
|
||||
// Receive notification of a new block.
|
||||
final InventoryMessage inv = new InventoryMessage();
|
||||
InventoryItem item = new InventoryItem(InventoryItem.Type.BLOCK, b2.getHash());
|
||||
inv.addItem(item);
|
||||
final InventoryMessage inv = InventoryMessage.ofBlocks(b2);
|
||||
|
||||
final AtomicInteger newBlockMessagesReceived = new AtomicInteger(0);
|
||||
|
||||
@ -489,8 +476,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
assertEquals(expectedLocator, getblocks.getLocator());
|
||||
assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash());
|
||||
// We're supposed to get an inv here.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addItem(new InventoryItem(InventoryItem.Type.BLOCK, b3.getHash()));
|
||||
InventoryMessage inv = InventoryMessage.ofBlocks(b3);
|
||||
inbound(writeTarget, inv);
|
||||
GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
|
||||
assertEquals(b3.getHash(), getdata.getItems().get(0).hash);
|
||||
@ -583,8 +569,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
t4 = roundTripTransaction(t4);
|
||||
|
||||
// Announce the first one. Wait for it to be downloaded.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addTransaction(t1);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(t1);
|
||||
inbound(writeTarget, inv);
|
||||
GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
|
||||
Threading.waitForUserCode();
|
||||
@ -605,17 +590,17 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
// Deliver the requested transactions.
|
||||
inbound(writeTarget, t2);
|
||||
inbound(writeTarget, t3);
|
||||
NotFoundMessage notFound = new NotFoundMessage();
|
||||
notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t7hash));
|
||||
notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t8hash));
|
||||
List<InventoryItem> notFoundList = new ArrayList<>();
|
||||
notFoundList.add(new InventoryItem(InventoryItem.Type.TRANSACTION, t7hash));
|
||||
notFoundList.add(new InventoryItem(InventoryItem.Type.TRANSACTION, t8hash));
|
||||
NotFoundMessage notFound = new NotFoundMessage(notFoundList);
|
||||
inbound(writeTarget, notFound);
|
||||
assertFalse(futures.isDone());
|
||||
// It will recursively ask for the dependencies of t2: t5 and t4, but not t3 because it already found t4.
|
||||
getdata = (GetDataMessage) outbound(writeTarget);
|
||||
assertEquals(getdata.getItems().get(0).hash, t2.getInput(0).getOutpoint().hash());
|
||||
// t5 isn't found and t4 is.
|
||||
notFound = new NotFoundMessage();
|
||||
notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t5hash));
|
||||
notFound = new NotFoundMessage(Collections.singletonList(new InventoryItem(InventoryItem.Type.TRANSACTION, t5hash)));
|
||||
inbound(writeTarget, notFound);
|
||||
assertFalse(futures.isDone());
|
||||
// Request t4 ...
|
||||
@ -625,8 +610,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
// Continue to explore the t4 branch and ask for t6, which is in the chain.
|
||||
getdata = (GetDataMessage) outbound(writeTarget);
|
||||
assertEquals(t6hash, getdata.getItems().get(0).hash);
|
||||
notFound = new NotFoundMessage();
|
||||
notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t6hash));
|
||||
notFound = new NotFoundMessage(Collections.singletonList(new InventoryItem(InventoryItem.Type.TRANSACTION, t6hash)));
|
||||
inbound(writeTarget, notFound);
|
||||
pingAndWait(writeTarget);
|
||||
// That's it, we explored the entire tree.
|
||||
@ -661,8 +645,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
t1 = roundTripTransaction(t1);
|
||||
|
||||
// Announce the first one. Wait for it to be downloaded.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addTransaction(t1);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(t1);
|
||||
inbound(writeTarget, inv);
|
||||
GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
|
||||
Threading.waitForUserCode();
|
||||
@ -758,8 +741,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
t1.addInput(t2.getOutput(0));
|
||||
t1.addOutput(COIN, key); // Make it relevant.
|
||||
// Announce t1.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addTransaction(t1);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(t1);
|
||||
inbound(writeTarget, inv);
|
||||
// Send it.
|
||||
GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
|
||||
@ -775,8 +757,7 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
getdata = (GetDataMessage) outbound(writeTarget);
|
||||
assertEquals(t3, getdata.getItems().get(0).hash);
|
||||
// Can't find it: bottom of tree.
|
||||
NotFoundMessage notFound = new NotFoundMessage();
|
||||
notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t3));
|
||||
NotFoundMessage notFound = new NotFoundMessage(Collections.singletonList(new InventoryItem(InventoryItem.Type.TRANSACTION, t3)));
|
||||
inbound(writeTarget, notFound);
|
||||
pingAndWait(writeTarget);
|
||||
Threading.waitForUserCode();
|
||||
@ -850,13 +831,14 @@ public class PeerTest extends TestWithNetworkConnections {
|
||||
MessageSerializer serializer = TESTNET.getDefaultSerializer();
|
||||
// Now write some bogus truncated message.
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
serializer.serialize("inv", new InventoryMessage() {
|
||||
List<InventoryItem> items = new ArrayList<>();
|
||||
items.add(new InventoryItem(InventoryItem.Type.TRANSACTION, Sha256Hash.of(new byte[] { 1 })));
|
||||
items.add(new InventoryItem(InventoryItem.Type.TRANSACTION, Sha256Hash.of(new byte[] { 2 })));
|
||||
items.add(new InventoryItem(InventoryItem.Type.TRANSACTION, Sha256Hash.of(new byte[] { 3 })));
|
||||
serializer.serialize("inv", new InventoryMessage(items) {
|
||||
@Override
|
||||
public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
|
||||
// Add some hashes.
|
||||
addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, Sha256Hash.of(new byte[] { 1 })));
|
||||
addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, Sha256Hash.of(new byte[] { 2 })));
|
||||
addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, Sha256Hash.of(new byte[] { 3 })));
|
||||
|
||||
// Write out a copy that's truncated in the middle.
|
||||
ByteArrayOutputStream bos = new ByteArrayOutputStream();
|
||||
|
@ -110,7 +110,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
|
||||
Threading.waitForUserCode();
|
||||
assertFalse(future.isDone());
|
||||
assertEquals(0.0, lastProgress.get(), 0.0);
|
||||
inbound(channels[1], InventoryMessage.with(tx));
|
||||
inbound(channels[1], InventoryMessage.ofTransactions(tx));
|
||||
future.get();
|
||||
Threading.waitForUserCode();
|
||||
assertEquals(1.0, lastProgress.get(), 0.0);
|
||||
@ -127,7 +127,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
|
||||
Transaction tx = FakeTxBuilder.createFakeTx(TESTNET.network(), CENT, address);
|
||||
tx.getConfidence().setSource(TransactionConfidence.Source.SELF);
|
||||
TransactionBroadcast broadcast = peerGroup.broadcastTransaction(tx);
|
||||
inbound(channels[1], InventoryMessage.with(tx));
|
||||
inbound(channels[1], InventoryMessage.ofTransactions(tx));
|
||||
pingAndWait(channels[1]);
|
||||
final AtomicDouble p = new AtomicDouble();
|
||||
broadcast.setProgressCallback(p::set, Threading.SAME_THREAD);
|
||||
@ -234,8 +234,7 @@ public class TransactionBroadcastTest extends TestWithPeerGroup {
|
||||
// 49 BTC in change.
|
||||
assertEquals(valueOf(49, 0), t1.getValueSentToMe(wallet));
|
||||
// The future won't complete until it's heard back from the network on p2.
|
||||
InventoryMessage inv = new InventoryMessage();
|
||||
inv.addTransaction(t1);
|
||||
InventoryMessage inv = InventoryMessage.ofTransactions(t1);
|
||||
inbound(p2, inv);
|
||||
pingAndWait(p2);
|
||||
Threading.waitForUserCode();
|
||||
|
Loading…
Reference in New Issue
Block a user