diff --git a/core/src/main/java/org/bitcoinj/core/GetDataMessage.java b/core/src/main/java/org/bitcoinj/core/GetDataMessage.java index 09442b1e..1cdba992 100644 --- a/core/src/main/java/org/bitcoinj/core/GetDataMessage.java +++ b/core/src/main/java/org/bitcoinj/core/GetDataMessage.java @@ -46,16 +46,17 @@ public class GetDataMessage extends ListMessage { super(params); } - public void addTransaction(Sha256Hash hash) { - addItem(new InventoryItem(InventoryItem.Type.Transaction, hash)); + public void addTransaction(Sha256Hash hash, boolean includeWitness) { + addItem(new InventoryItem( + includeWitness ? InventoryItem.Type.WITNESS_TRANSACTION : InventoryItem.Type.TRANSACTION, hash)); } public void addBlock(Sha256Hash hash) { - addItem(new InventoryItem(InventoryItem.Type.Block, hash)); + addItem(new InventoryItem(InventoryItem.Type.BLOCK, hash)); } public void addFilteredBlock(Sha256Hash hash) { - addItem(new InventoryItem(InventoryItem.Type.FilteredBlock, hash)); + addItem(new InventoryItem(InventoryItem.Type.FILTERED_BLOCK, hash)); } public Sha256Hash getHashOf(int i) { diff --git a/core/src/main/java/org/bitcoinj/core/InventoryItem.java b/core/src/main/java/org/bitcoinj/core/InventoryItem.java index a505bc5c..ea01df40 100644 --- a/core/src/main/java/org/bitcoinj/core/InventoryItem.java +++ b/core/src/main/java/org/bitcoinj/core/InventoryItem.java @@ -1,5 +1,6 @@ /* * Copyright 2011 Google Inc. + * Copyright 2019 Andreas Schildbach * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,10 +27,24 @@ public class InventoryItem { static final int MESSAGE_LENGTH = 36; public enum Type { - Error, - Transaction, - Block, - FilteredBlock + ERROR(0x0), TRANSACTION(0x1), BLOCK(0x2), + // BIP37 extension: + FILTERED_BLOCK(0x3), + // BIP44 extensions: + WITNESS_TRANSACTION(0x40000001), WITNESS_BLOCK(0x40000002), WITNESS_FILTERED_BLOCK(0x40000003); + + public final int code; + + private Type(int code) { + this.code = code; + } + + public static Type ofCode(int code) { + for (Type type : values()) + if (type.code == code) + return type; + return null; + } } public final Type type; diff --git a/core/src/main/java/org/bitcoinj/core/InventoryMessage.java b/core/src/main/java/org/bitcoinj/core/InventoryMessage.java index 1660dd7c..0a16f040 100644 --- a/core/src/main/java/org/bitcoinj/core/InventoryMessage.java +++ b/core/src/main/java/org/bitcoinj/core/InventoryMessage.java @@ -54,11 +54,11 @@ public class InventoryMessage extends ListMessage { } public void addBlock(Block block) { - addItem(new InventoryItem(InventoryItem.Type.Block, block.getHash())); + addItem(new InventoryItem(InventoryItem.Type.BLOCK, block.getHash())); } public void addTransaction(Transaction tx) { - addItem(new InventoryItem(InventoryItem.Type.Transaction, tx.getHash())); + addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, tx.getHash())); } /** Creates a new inv message for the given transactions. */ diff --git a/core/src/main/java/org/bitcoinj/core/ListMessage.java b/core/src/main/java/org/bitcoinj/core/ListMessage.java index d4258938..1a65c477 100644 --- a/core/src/main/java/org/bitcoinj/core/ListMessage.java +++ b/core/src/main/java/org/bitcoinj/core/ListMessage.java @@ -85,24 +85,9 @@ public abstract class ListMessage extends Message { throw new ProtocolException("Ran off the end of the INV"); } int typeCode = (int) readUint32(); - InventoryItem.Type type; - // See ppszTypeName in net.h - switch (typeCode) { - case 0: - type = InventoryItem.Type.Error; - break; - case 1: - type = InventoryItem.Type.Transaction; - break; - case 2: - type = InventoryItem.Type.Block; - break; - case 3: - type = InventoryItem.Type.FilteredBlock; - break; - default: - throw new ProtocolException("Unknown CInv type: " + typeCode); - } + InventoryItem.Type type = InventoryItem.Type.ofCode(typeCode); + if (type == null) + throw new ProtocolException("Unknown CInv type: " + typeCode); InventoryItem item = new InventoryItem(type, readHash()); items.add(item); } @@ -114,7 +99,7 @@ public abstract class ListMessage extends Message { stream.write(new VarInt(items.size()).encode()); for (InventoryItem i : items) { // Write out the type code. - Utils.uint32ToByteStreamLE(i.type.ordinal(), stream); + Utils.uint32ToByteStreamLE(i.type.code, stream); // And now the hash. stream.write(i.hash.getReversedBytes()); } diff --git a/core/src/main/java/org/bitcoinj/core/Peer.java b/core/src/main/java/org/bitcoinj/core/Peer.java index d9c02bfc..162281b7 100644 --- a/core/src/main/java/org/bitcoinj/core/Peer.java +++ b/core/src/main/java/org/bitcoinj/core/Peer.java @@ -931,7 +931,7 @@ public class Peer extends PeerSocketHandler { if (needToRequest.size() > 1) log.info("{}: Requesting {} transactions for depth {} dep resolution", getAddress(), needToRequest.size(), depth + 1); for (Sha256Hash hash : needToRequest) { - getdata.addTransaction(hash); + getdata.addTransaction(hash, vPeerVersionMessage.isWitnessSupported()); GetDataRequest req = new GetDataRequest(hash, SettableFuture.create()); futures.add(req.future); getDataFutures.add(req); @@ -1194,10 +1194,10 @@ public class Peer extends PeerSocketHandler { for (InventoryItem item : items) { switch (item.type) { - case Transaction: + case TRANSACTION: transactions.add(item); break; - case Block: + case BLOCK: blocks.add(item); break; default: @@ -1243,7 +1243,7 @@ public class Peer extends PeerSocketHandler { it.remove(); } else { log.debug("{}: getdata on tx {}", getAddress(), item.hash); - getdata.addItem(item); + getdata.addTransaction(item.hash, vPeerVersionMessage.isWitnessSupported()); // Register with the garbage collector that we care about the confidence data for a while. pendingTxDownloads.add(conf); } @@ -1283,7 +1283,7 @@ public class Peer extends PeerSocketHandler { getdata.addFilteredBlock(item.hash); pingAfterGetData = true; } else { - getdata.addItem(item); + getdata.addBlock(item.hash); } pendingBlockDownloads.add(item.hash); } @@ -1339,7 +1339,7 @@ public class Peer extends PeerSocketHandler { // TODO: Unit test this method. log.info("Request to fetch peer mempool tx {}", hash); GetDataMessage getdata = new GetDataMessage(params); - getdata.addTransaction(hash); + getdata.addTransaction(hash, vPeerVersionMessage.isWitnessSupported()); return sendSingleGetData(getdata); } diff --git a/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java b/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java index 8decd80f..ca48409d 100644 --- a/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java +++ b/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java @@ -132,7 +132,7 @@ public class BitcoindComparisonTool { System.exit(1); } else if (m instanceof GetDataMessage) { for (InventoryItem item : ((GetDataMessage) m).items) - if (item.type == InventoryItem.Type.Block) { + if (item.type == InventoryItem.Type.BLOCK) { log.info("Requested " + item.hash); if (currentBlock.block.getHash().equals(item.hash)) bitcoind.sendMessage(currentBlock.block); diff --git a/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java b/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java index 9578b089..78637202 100644 --- a/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java +++ b/core/src/test/java/org/bitcoinj/core/FilteredBlockAndPartialMerkleTreeTests.java @@ -176,7 +176,7 @@ public class FilteredBlockAndPartialMerkleTreeTests extends TestWithPeerGroup { assertTrue(getData instanceof GetDataMessage); assertTrue(((GetDataMessage)getData).getItems().size() == 1); assertTrue(((GetDataMessage)getData).getItems().get(0).hash.equals(block.getHash())); - assertTrue(((GetDataMessage)getData).getItems().get(0).type == InventoryItem.Type.FilteredBlock); + assertTrue(((GetDataMessage)getData).getItems().get(0).type == InventoryItem.Type.FILTERED_BLOCK); // Check that we then immediately pinged. Object ping = outbound(p1); diff --git a/core/src/test/java/org/bitcoinj/core/FullBlockTestGenerator.java b/core/src/test/java/org/bitcoinj/core/FullBlockTestGenerator.java index 774a32c9..fc4646b6 100644 --- a/core/src/test/java/org/bitcoinj/core/FullBlockTestGenerator.java +++ b/core/src/test/java/org/bitcoinj/core/FullBlockTestGenerator.java @@ -1511,8 +1511,8 @@ public class FullBlockTestGenerator { spendableOutputs.offer(b82.getCoinbaseOutput()); HashSet post82Mempool = new HashSet<>(); - post82Mempool.add(new InventoryItem(InventoryItem.Type.Transaction, b78tx.getHash())); - post82Mempool.add(new InventoryItem(InventoryItem.Type.Transaction, b79tx.getHash())); + post82Mempool.add(new InventoryItem(InventoryItem.Type.TRANSACTION, b78tx.getHash())); + post82Mempool.add(new InventoryItem(InventoryItem.Type.TRANSACTION, b79tx.getHash())); blocks.add(new MemoryPoolState(post82Mempool, "post-b82 tx resurrection")); // Check the UTXO query takes mempool into account. diff --git a/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java b/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java index 11b749cb..cfb62264 100644 --- a/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java +++ b/core/src/test/java/org/bitcoinj/core/PeerGroupTest.java @@ -626,7 +626,7 @@ public class PeerGroupTest extends TestWithPeerGroup { // p1 requests dep resolution, p2 is quiet. assertTrue(outbound(p1) instanceof GetDataMessage); final Sha256Hash dephash = tx.getInput(0).getOutpoint().getHash(); - final InventoryItem inv = new InventoryItem(InventoryItem.Type.Transaction, dephash); + final InventoryItem inv = new InventoryItem(InventoryItem.Type.TRANSACTION, dephash); inbound(p1, new NotFoundMessage(UNITTEST, ImmutableList.of(inv))); assertNull(outbound(p1)); assertNull(outbound(p2)); @@ -834,7 +834,7 @@ public class PeerGroupTest extends TestWithPeerGroup { // Await restart of the chain download. GetDataMessage getdata = assertNextMessageIs(p1, GetDataMessage.class); assertEquals(exhaustionPoint.getHash(), getdata.getHashOf(0)); - assertEquals(InventoryItem.Type.FilteredBlock, getdata.getItems().get(0).type); + assertEquals(InventoryItem.Type.FILTERED_BLOCK, getdata.getItems().get(0).type); List newBlocks = blocks.subList(3, blocks.size()); filterAndSend(p1, newBlocks, newFilter); assertNextMessageIs(p1, Ping.class); diff --git a/core/src/test/java/org/bitcoinj/core/PeerTest.java b/core/src/test/java/org/bitcoinj/core/PeerTest.java index b94f5b07..41f600bd 100644 --- a/core/src/test/java/org/bitcoinj/core/PeerTest.java +++ b/core/src/test/java/org/bitcoinj/core/PeerTest.java @@ -220,7 +220,7 @@ public class PeerTest extends TestWithNetworkConnections { Block b3 = makeSolvedTestBlock(b2); inbound(writeTarget, b3); InventoryMessage inv = new InventoryMessage(UNITTEST); - InventoryItem item = new InventoryItem(InventoryItem.Type.Block, b3.getHash()); + InventoryItem item = new InventoryItem(InventoryItem.Type.BLOCK, b3.getHash()); inv.addItem(item); inbound(writeTarget, inv); @@ -249,7 +249,7 @@ public class PeerTest extends TestWithNetworkConnections { // Receive an inv. InventoryMessage inv = new InventoryMessage(UNITTEST); - InventoryItem item = new InventoryItem(InventoryItem.Type.Block, b2.getHash()); + InventoryItem item = new InventoryItem(InventoryItem.Type.BLOCK, b2.getHash()); inv.addItem(item); inbound(writeTarget, inv); @@ -266,7 +266,7 @@ public class PeerTest extends TestWithNetworkConnections { Coin value = COIN; Transaction tx = createFakeTx(UNITTEST, value, address); InventoryMessage inv = new InventoryMessage(UNITTEST); - InventoryItem item = new InventoryItem(InventoryItem.Type.Transaction, tx.getHash()); + InventoryItem item = new InventoryItem(InventoryItem.Type.TRANSACTION, tx.getHash()); inv.addItem(item); inbound(writeTarget, inv); // Peer hasn't seen it before, so will ask for it. @@ -299,7 +299,7 @@ public class PeerTest extends TestWithNetworkConnections { Coin value = COIN; Transaction tx = createFakeTx(UNITTEST, value, this.address); InventoryMessage inv = new InventoryMessage(UNITTEST); - InventoryItem item = new InventoryItem(InventoryItem.Type.Transaction, tx.getHash()); + InventoryItem item = new InventoryItem(InventoryItem.Type.TRANSACTION, tx.getHash()); inv.addItem(item); inbound(writeTarget, inv); @@ -324,7 +324,7 @@ public class PeerTest extends TestWithNetworkConnections { final Block b2 = makeSolvedTestBlock(b1); // Receive notification of a new block. final InventoryMessage inv = new InventoryMessage(UNITTEST); - InventoryItem item = new InventoryItem(InventoryItem.Type.Block, b2.getHash()); + InventoryItem item = new InventoryItem(InventoryItem.Type.BLOCK, b2.getHash()); inv.addItem(item); final AtomicInteger newBlockMessagesReceived = new AtomicInteger(0); @@ -374,7 +374,7 @@ public class PeerTest extends TestWithNetworkConnections { List items = getdata.getItems(); assertEquals(1, items.size()); assertEquals(b2.getHash(), items.get(0).hash); - assertEquals(InventoryItem.Type.Block, items.get(0).type); + assertEquals(InventoryItem.Type.BLOCK, items.get(0).type); } // Check that it starts downloading the block chain correctly on request. @@ -497,7 +497,7 @@ public class PeerTest extends TestWithNetworkConnections { assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash()); // We're supposed to get an inv here. InventoryMessage inv = new InventoryMessage(UNITTEST); - inv.addItem(new InventoryItem(InventoryItem.Type.Block, b3.getHash())); + inv.addItem(new InventoryItem(InventoryItem.Type.BLOCK, b3.getHash())); inbound(writeTarget, inv); GetDataMessage getdata = (GetDataMessage) outbound(writeTarget); assertEquals(b3.getHash(), getdata.getItems().get(0).hash); @@ -621,8 +621,8 @@ public class PeerTest extends TestWithNetworkConnections { inbound(writeTarget, t2); inbound(writeTarget, t3); NotFoundMessage notFound = new NotFoundMessage(UNITTEST); - notFound.addItem(new InventoryItem(InventoryItem.Type.Transaction, t7hash)); - notFound.addItem(new InventoryItem(InventoryItem.Type.Transaction, t8hash)); + notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t7hash)); + notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t8hash)); 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. @@ -630,7 +630,7 @@ public class PeerTest extends TestWithNetworkConnections { assertEquals(getdata.getItems().get(0).hash, t2.getInput(0).getOutpoint().getHash()); // t5 isn't found and t4 is. notFound = new NotFoundMessage(UNITTEST); - notFound.addItem(new InventoryItem(InventoryItem.Type.Transaction, t5hash)); + notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t5hash)); inbound(writeTarget, notFound); assertFalse(futures.isDone()); // Request t4 ... @@ -641,7 +641,7 @@ public class PeerTest extends TestWithNetworkConnections { getdata = (GetDataMessage) outbound(writeTarget); assertEquals(t6hash, getdata.getItems().get(0).hash); notFound = new NotFoundMessage(UNITTEST); - notFound.addItem(new InventoryItem(InventoryItem.Type.Transaction, t6hash)); + notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t6hash)); inbound(writeTarget, notFound); pingAndWait(writeTarget); // That's it, we explored the entire tree. @@ -801,7 +801,7 @@ public class PeerTest extends TestWithNetworkConnections { assertEquals(t3, getdata.getItems().get(0).hash); // Can't find it: bottom of tree. NotFoundMessage notFound = new NotFoundMessage(UNITTEST); - notFound.addItem(new InventoryItem(InventoryItem.Type.Transaction, t3)); + notFound.addItem(new InventoryItem(InventoryItem.Type.TRANSACTION, t3)); inbound(writeTarget, notFound); pingAndWait(writeTarget); Threading.waitForUserCode(); @@ -876,7 +876,7 @@ public class PeerTest extends TestWithNetworkConnections { t2.addInput(t1.getOutput(0)); t2.addOutput(COIN, wallet.currentChangeAddress()); inbound(writeTarget, t2); - final InventoryItem inventoryItem = new InventoryItem(InventoryItem.Type.Transaction, t2.getInput(0).getOutpoint().getHash()); + final InventoryItem inventoryItem = new InventoryItem(InventoryItem.Type.TRANSACTION, t2.getInput(0).getOutpoint().getHash()); final NotFoundMessage nfm = new NotFoundMessage(UNITTEST, Lists.newArrayList(inventoryItem)); inbound(writeTarget, nfm); pingAndWait(writeTarget); @@ -942,9 +942,9 @@ public class PeerTest extends TestWithNetworkConnections { @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}))); + 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();