diff --git a/core/src/main/java/org/bitcoinj/core/GetDataMessage.java b/core/src/main/java/org/bitcoinj/core/GetDataMessage.java
index fa6c765b6..7a2400da4 100644
--- a/core/src/main/java/org/bitcoinj/core/GetDataMessage.java
+++ b/core/src/main/java/org/bitcoinj/core/GetDataMessage.java
@@ -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;
/**
*
Represents the "getdata" P2P network message, which requests the contents of blocks or transactions given their
* hashes.
- *
- * Instances of this class are not safe for use by multiple threads.
+ *
+ * Instances of this class -- that use deprecated methods -- are not safe for use by multiple threads.
*/
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 items) {
+ GetDataMessage(List 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));
}
diff --git a/core/src/main/java/org/bitcoinj/core/InventoryItem.java b/core/src/main/java/org/bitcoinj/core/InventoryItem.java
index df7f99b84..96fba29f5 100644
--- a/core/src/main/java/org/bitcoinj/core/InventoryItem.java
+++ b/core/src/main/java/org/bitcoinj/core/InventoryItem.java
@@ -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;
diff --git a/core/src/main/java/org/bitcoinj/core/InventoryMessage.java b/core/src/main/java/org/bitcoinj/core/InventoryMessage.java
index c48e96cee..c3caf0931 100644
--- a/core/src/main/java/org/bitcoinj/core/InventoryMessage.java
+++ b/core/src/main/java/org/bitcoinj/core/InventoryMessage.java
@@ -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}.
- *
- * Instances of this class are not safe for use by multiple threads.
+ *
+ * Instances of this class -- that use deprecated methods -- are not safe for use by multiple threads.
*/
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 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 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);
}
}
diff --git a/core/src/main/java/org/bitcoinj/core/ListMessage.java b/core/src/main/java/org/bitcoinj/core/ListMessage.java
index 3fb2c5c8c..d0233dc68 100644
--- a/core/src/main/java/org/bitcoinj/core/ListMessage.java
+++ b/core/src/main/java/org/bitcoinj/core/ListMessage.java
@@ -35,12 +35,12 @@ import static org.bitcoinj.base.internal.Preconditions.check;
/**
* Abstract superclass of classes with list based payload, ie InventoryMessage and GetDataMessage.
*
- * Instances of this class are not safe for use by multiple threads.
+ * Instances of this class -- that use deprecated methods -- are not safe for use by multiple threads.
*/
public abstract class ListMessage extends BaseMessage {
// For some reason the compiler complains if this is inside InventoryItem
- protected List items;
+ protected final List 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 items) {
- this.items = items;
+ this.items = items; // TODO: unmodifiable defensive copy
}
public List getItems() {
return Collections.unmodifiableList(items);
}
+ @Deprecated
public void addItem(InventoryItem item) {
items.add(item);
}
+ @Deprecated
public void removeItem(int index) {
items.remove(index);
}
diff --git a/core/src/main/java/org/bitcoinj/core/NotFoundMessage.java b/core/src/main/java/org/bitcoinj/core/NotFoundMessage.java
index 90e1e7b7c..fdbfa2d82 100644
--- a/core/src/main/java/org/bitcoinj/core/NotFoundMessage.java
+++ b/core/src/main/java/org/bitcoinj/core/NotFoundMessage.java
@@ -24,8 +24,8 @@ import java.util.List;
/**
* 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.
- *
- * Instances of this class are not safe for use by multiple threads.
+ *
+ * Instances of this class -- that use deprecated methods -- are not safe for use by multiple threads.
*/
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();
}
diff --git a/core/src/main/java/org/bitcoinj/core/Peer.java b/core/src/main/java/org/bitcoinj/core/Peer.java
index 4122c424c..29214a140 100644
--- a/core/src/main/java/org/bitcoinj/core/Peer.java
+++ b/core/src/main/java/org/bitcoinj/core/Peer.java
@@ -910,10 +910,13 @@ public class Peer extends PeerSocketHandler {
* @return A GetDataMessage that will query those IDs
*/
private GetDataMessage buildMultiTransactionDataMessage(Set 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 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 items = inv.getItems();
// Separate out the blocks and transactions, we'll handle them differently
- List transactions = new LinkedList<>();
- List blocks = new LinkedList<>();
+ List transactions = new LinkedList<>();
+ List 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 getDataItems = new ArrayList<>();
- Iterator it = transactions.iterator();
+ Iterator 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 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 items = awaitingFreshFilter.stream()
+ .map(hash -> new InventoryItem(InventoryItem.Type.FILTERED_BLOCK, hash))
+ .collect(Collectors.toList());
+ GetDataMessage getdata = new GetDataMessage(items);
awaitingFreshFilter = null;
lock.unlock();
diff --git a/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java b/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java
index a34b33173..7387b8866 100644
--- a/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java
+++ b/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java
@@ -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())) {
diff --git a/integration-test/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTest.java b/integration-test/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTest.java
index 0e1539ced..32b9cfdfd 100644
--- a/integration-test/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTest.java
+++ b/integration-test/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTest.java
@@ -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
diff --git a/integration-test/src/test/java/org/bitcoinj/core/PeerGroupTest.java b/integration-test/src/test/java/org/bitcoinj/core/PeerGroupTest.java
index 3d1dde93e..73955606b 100644
--- a/integration-test/src/test/java/org/bitcoinj/core/PeerGroupTest.java
+++ b/integration-test/src/test/java/org/bitcoinj/core/PeerGroupTest.java
@@ -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());
diff --git a/integration-test/src/test/java/org/bitcoinj/core/PeerTest.java b/integration-test/src/test/java/org/bitcoinj/core/PeerTest.java
index dff03946b..bdb5bccb1 100644
--- a/integration-test/src/test/java/org/bitcoinj/core/PeerTest.java
+++ b/integration-test/src/test/java/org/bitcoinj/core/PeerTest.java
@@ -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 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 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();
diff --git a/integration-test/src/test/java/org/bitcoinj/core/TransactionBroadcastTest.java b/integration-test/src/test/java/org/bitcoinj/core/TransactionBroadcastTest.java
index 0ab93eaba..157bfaec8 100644
--- a/integration-test/src/test/java/org/bitcoinj/core/TransactionBroadcastTest.java
+++ b/integration-test/src/test/java/org/bitcoinj/core/TransactionBroadcastTest.java
@@ -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();