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

Add relayTxesBeforeFilter flag to VersionMessage, PROTOCOL_VERSION

This adds a relayTxesBeforeFilter flag to VersionMessage, bringing
it in line with PROTOCOL_VERSION 70001, and bumps the
PROTOCOL_VERSION accordingly.
This commit is contained in:
Matt Corallo 2012-12-20 18:21:57 -05:00
parent a0c25aed28
commit a5f9c3381b
8 changed files with 96 additions and 21 deletions

View File

@ -472,6 +472,10 @@ public abstract class Message implements Serializable {
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported.
}
}
boolean hasMoreBytes() {
return cursor < bytes.length;
}
public static class LazyParseException extends RuntimeException {
private static final long serialVersionUID = 6971943053112975594L;

View File

@ -41,7 +41,7 @@ public class NetworkParameters implements Serializable {
/**
* The protocol version this library implements.
*/
public static final int PROTOCOL_VERSION = 60001;
public static final int PROTOCOL_VERSION = 70001;
/**
* The alert signing key originally owned by Satoshi, and now passed on to Gavin along with a few others.

View File

@ -119,10 +119,11 @@ public class Peer {
/**
* Construct a peer that reads/writes from the given chain. Automatically creates a VersionMessage for you from the
* given software name/version strings, which should be something like "MySimpleTool", "1.0"
* given software name/version strings, which should be something like "MySimpleTool", "1.0" and which will tell the
* remote node to relay transaction inv messages before it has received a filter.
*/
public Peer(NetworkParameters params, AbstractBlockChain blockChain, String thisSoftwareName, String thisSoftwareVersion) {
this(params, blockChain, new VersionMessage(params, blockChain.getBestChainHeight()));
this(params, blockChain, new VersionMessage(params, blockChain.getBestChainHeight(), true));
this.versionMessage.appendToSubVer(thisSoftwareName, thisSoftwareVersion, null);
}

View File

@ -187,7 +187,8 @@ public class PeerGroup extends AbstractIdleService {
this.maxConnections = 0;
int height = chain == null ? 0 : chain.getBestChainHeight();
this.versionMessage = new VersionMessage(params, height);
// We never request that the remote node wait for a bloom filter yet, as we have no wallets
this.versionMessage = new VersionMessage(params, height, true);
memoryPool = new MemoryPool();
@ -346,10 +347,21 @@ public class PeerGroup extends AbstractIdleService {
* @param version
*/
public void setUserAgent(String name, String version, String comments) {
VersionMessage ver = new VersionMessage(params, 0);
//TODO Check that height is needed here (it wasnt, but it should be, no?)
int height = chain == null ? 0 : chain.getBestChainHeight();
VersionMessage ver = new VersionMessage(params, height, false);
updateVersionMessageRelayTxesBeforeFilter(ver);
ver.appendToSubVer(name, version, comments);
setVersionMessage(ver);
}
// Updates the relayTxesBeforeFilter flag of ver
private synchronized void updateVersionMessageRelayTxesBeforeFilter(VersionMessage ver) {
// We will provide the remote node with a bloom filter (ie they shouldn't relay yet)
// iff chain == null || !chain.shouldVerifyTransactions() and a wallet is added
// Note that the default here means that no tx invs will be received if no wallet is ever added
ver.relayTxesBeforeFilter = chain != null && chain.shouldVerifyTransactions() && wallets.size() > 0;
}
/**
* Sets information that identifies this software to remote nodes. This is a convenience wrapper for creating
@ -535,6 +547,7 @@ public class PeerGroup extends AbstractIdleService {
}
});
recalculateFastCatchupAndFilter();
updateVersionMessageRelayTxesBeforeFilter(getVersionMessage());
}
private synchronized void recalculateFastCatchupAndFilter() {

View File

@ -67,6 +67,10 @@ public class VersionMessage extends Message {
* How many blocks are in the chain, according to the other side.
*/
public long bestHeight;
/**
* Whether or not to relay tx invs before a filter is received
*/
public boolean relayTxesBeforeFilter;
public VersionMessage(NetworkParameters params, byte[] msg) throws ProtocolException {
super(params, msg, 0);
@ -75,8 +79,13 @@ public class VersionMessage extends Message {
// It doesn't really make sense to ever lazily parse a version message or to retain the backing bytes.
// If you're receiving this on the wire you need to check the protocol version and it will never need to be sent
// back down the wire.
/** Equivalent to VersionMessage(params, newBestHeight, true) */
public VersionMessage(NetworkParameters params, int newBestHeight) {
this(params, newBestHeight, true);
}
public VersionMessage(NetworkParameters params, int newBestHeight, boolean relayTxesBeforeFilter) {
super(params);
clientVersion = NetworkParameters.PROTOCOL_VERSION;
localServices = 0;
@ -94,8 +103,9 @@ public class VersionMessage extends Message {
}
subVer = "/BitCoinJ:0.7-SNAPSHOT/";
bestHeight = newBestHeight;
this.relayTxesBeforeFilter = relayTxesBeforeFilter;
length = 84;
length = 85;
if (protocolVersion > 31402)
length += 8;
length += subVer == null ? 1 : VarInt.sizeOf(subVer.length()) + subVer.length();
@ -123,11 +133,25 @@ public class VersionMessage extends Message {
// We don't care about the localhost nonce. It's used to detect connecting back to yourself in cases where
// there are NATs and proxies in the way. However we don't listen for inbound connections so it's irrelevant.
readUint64();
// string subVer (currently "")
subVer = readStr();
// int bestHeight (size of known block chain).
bestHeight = readUint32();
length = cursor - offset;
try {
// Initialize default values for flags which may not be sent by old nodes
subVer = "";
bestHeight = 0;
relayTxesBeforeFilter = true;
if (!hasMoreBytes())
return;
// string subVer (currently "")
subVer = readStr();
if (!hasMoreBytes())
return;
// int bestHeight (size of known block chain).
bestHeight = readUint32();
if (!hasMoreBytes())
return;
relayTxesBeforeFilter = readBytes(1)[0] != 0;
} finally {
length = cursor - offset;
}
}
@Override
@ -158,6 +182,7 @@ public class VersionMessage extends Message {
buf.write(subVerBytes);
// Size of known block chain.
Utils.uint32ToByteStreamLE(bestHeight, buf);
buf.write(relayTxesBeforeFilter ? 1 : 0);
}
/**
@ -178,7 +203,8 @@ public class VersionMessage extends Message {
other.time == time &&
other.subVer.equals(subVer) &&
other.myAddr.equals(myAddr) &&
other.theirAddr.equals(theirAddr);
other.theirAddr.equals(theirAddr) &&
other.relayTxesBeforeFilter == relayTxesBeforeFilter;
}
/**
@ -199,7 +225,7 @@ public class VersionMessage extends Message {
@Override
public int hashCode() {
return (int) bestHeight ^ clientVersion ^ (int) localServices ^ (int) time ^ subVer.hashCode() ^ myAddr.hashCode()
^ theirAddr.hashCode();
^ theirAddr.hashCode() * (relayTxesBeforeFilter ? 1 : 2);
}
public String toString() {
@ -212,11 +238,12 @@ public class VersionMessage extends Message {
sb.append("their addr: ").append(theirAddr).append("\n");
sb.append("sub version: ").append(subVer).append("\n");
sb.append("best height: ").append(bestHeight).append("\n");
sb.append("delay tx relay: ").append(relayTxesBeforeFilter).append("\n");
return sb.toString();
}
public VersionMessage duplicate() {
VersionMessage v = new VersionMessage(params, (int) bestHeight);
VersionMessage v = new VersionMessage(params, (int) bestHeight, relayTxesBeforeFilter);
v.clientVersion = clientVersion;
v.localServices = localServices;
v.time = time;

View File

@ -55,9 +55,9 @@ public class BitcoinSerializerTest {
public void testVersion() throws Exception {
BitcoinSerializer bs = new BitcoinSerializer(NetworkParameters.prodNet(), false);
// the actual data from https://en.bitcoin.it/wiki/Protocol_specification#version
ByteArrayInputStream bais = new ByteArrayInputStream(Hex.decode("f9beb4d976657273696f6e0000000000550000009" +
ByteArrayInputStream bais = new ByteArrayInputStream(Hex.decode("f9beb4d976657273696f6e0000000000560000009" +
"c7c00000100000000000000e615104d00000000010000000000000000000000000000000000ffff0a000001daf6010000" +
"000000000000000000000000000000ffff0a000002208ddd9d202c3ab457130055810100"));
"000000000000000000000000000000ffff0a000002208ddd9d202c3ab45713005581010000"));
VersionMessage vm = (VersionMessage)bs.deserialize(bais);
assertEquals(31900, vm.clientVersion);
assertEquals(1292899814L, vm.time);

View File

@ -102,10 +102,6 @@ public class MockNetworkConnection implements NetworkConnection {
this.versionMessage = msg;
}
public void setVersionMessageForHeight(NetworkParameters params, int chainHeight) {
versionMessage = new VersionMessage(params, chainHeight);
}
public VersionMessage getVersionMessage() {
if (versionMessage == null) throw new RuntimeException("Need to call setVersionMessage first");
return versionMessage;

View File

@ -0,0 +1,34 @@
package com.google.bitcoin.core;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
public class VersionMessageTest {
@Test
// Test that we can decode version messages which miss data which some old nodes may not include
public void testDecode() throws Exception {
NetworkParameters params = NetworkParameters.unitTests();
VersionMessage ver = new VersionMessage(params, Hex.decode("71110100000000000000000048e5e95000000000000000000000000000000000000000000000ffff7f000001479d000000000000000000000000000000000000ffff7f000001479d0000000000000000172f426974436f696e4a3a302e372d534e415053484f542f0004000000"));
assertTrue(!ver.relayTxesBeforeFilter);
assertTrue(ver.bestHeight == 1024);
assertTrue(ver.subVer.equals("/BitCoinJ:0.7-SNAPSHOT/"));
ver = new VersionMessage(params, Hex.decode("71110100000000000000000048e5e95000000000000000000000000000000000000000000000ffff7f000001479d000000000000000000000000000000000000ffff7f000001479d0000000000000000172f426974436f696e4a3a302e372d534e415053484f542f00040000"));
assertTrue(ver.relayTxesBeforeFilter);
assertTrue(ver.bestHeight == 1024);
assertTrue(ver.subVer.equals("/BitCoinJ:0.7-SNAPSHOT/"));
ver = new VersionMessage(params, Hex.decode("71110100000000000000000048e5e95000000000000000000000000000000000000000000000ffff7f000001479d000000000000000000000000000000000000ffff7f000001479d0000000000000000172f426974436f696e4a3a302e372d534e415053484f542f"));
assertTrue(ver.relayTxesBeforeFilter);
assertTrue(ver.bestHeight == 0);
assertTrue(ver.subVer.equals("/BitCoinJ:0.7-SNAPSHOT/"));
ver = new VersionMessage(params, Hex.decode("71110100000000000000000048e5e95000000000000000000000000000000000000000000000ffff7f000001479d000000000000000000000000000000000000ffff7f000001479d0000000000000000"));
assertTrue(ver.relayTxesBeforeFilter);
assertTrue(ver.bestHeight == 0);
assertTrue(ver.subVer.equals(""));
}
}