diff --git a/core/src/main/java/com/google/bitcoin/core/BitcoinSerializer.java b/core/src/main/java/com/google/bitcoin/core/BitcoinSerializer.java index 1cc6e23e..9035443a 100644 --- a/core/src/main/java/com/google/bitcoin/core/BitcoinSerializer.java +++ b/core/src/main/java/com/google/bitcoin/core/BitcoinSerializer.java @@ -64,6 +64,7 @@ public class BitcoinSerializer { names.put(Transaction.class, "tx"); names.put(AddressMessage.class, "addr"); names.put(Ping.class, "ping"); + names.put(Pong.class, "pong"); names.put(VersionAck.class, "verack"); names.put(GetBlocksMessage.class, "getblocks"); names.put(GetHeadersMessage.class, "getheaders"); @@ -264,7 +265,9 @@ public class BitcoinSerializer { } else if (command.equals("addr")) { message = new AddressMessage(params, payloadBytes, parseLazy, parseRetain, length); } else if (command.equals("ping")) { - return new Ping(); + message = new Ping(params, payloadBytes); + } else if (command.equals("pong")) { + message = new Pong(params, payloadBytes); } else if (command.equals("verack")) { return new VersionAck(params, payloadBytes); } else if (command.equals("headers")) { diff --git a/core/src/main/java/com/google/bitcoin/core/NetworkParameters.java b/core/src/main/java/com/google/bitcoin/core/NetworkParameters.java index e7917a35..db28496b 100644 --- a/core/src/main/java/com/google/bitcoin/core/NetworkParameters.java +++ b/core/src/main/java/com/google/bitcoin/core/NetworkParameters.java @@ -36,9 +36,9 @@ public class NetworkParameters implements Serializable { private static final long serialVersionUID = 3L; /** - * The protocol version this library implements. A value of 31800 means 0.3.18.00. + * The protocol version this library implements. */ - public static final int PROTOCOL_VERSION = 31800; + public static final int PROTOCOL_VERSION = 60001; /** * The alert signing key originally owned by Satoshi, and now passed on to Gavin along with a few others. diff --git a/core/src/main/java/com/google/bitcoin/core/Peer.java b/core/src/main/java/com/google/bitcoin/core/Peer.java index 3550ac87..712ea863 100644 --- a/core/src/main/java/com/google/bitcoin/core/Peer.java +++ b/core/src/main/java/com/google/bitcoin/core/Peer.java @@ -237,6 +237,11 @@ public class Peer { throw new ProtocolException("got more than one version ack"); } isAcked = true; + } else if (m instanceof Ping) { + if (((Ping) m).hasNonce()) + sendMessage(new Pong(((Ping) m).getNonce())); + } else if (m instanceof Pong) { + // We don't do anything with pongs right now, leave that to eventListeners } else { // TODO: Handle the other messages we can receive. log.warn("Received unhandled message: {}", m); diff --git a/core/src/main/java/com/google/bitcoin/core/Ping.java b/core/src/main/java/com/google/bitcoin/core/Ping.java index 5984ea43..87d3b24e 100644 --- a/core/src/main/java/com/google/bitcoin/core/Ping.java +++ b/core/src/main/java/com/google/bitcoin/core/Ping.java @@ -16,6 +16,60 @@ package com.google.bitcoin.core; -public class Ping extends EmptyMessage { +import java.io.IOException; +import java.io.OutputStream; +public class Ping extends Message { + private long nonce; + private boolean hasNonce; + + public Ping(NetworkParameters params, byte[] payloadBytes) throws ProtocolException { + super(params, payloadBytes, 0); + } + + /** + * Create a Ping with a nonce value. + * Only use this if the remote node has a protocol version > 60000 + */ + public Ping(long nonce) { + this.nonce = nonce; + this.hasNonce = true; + } + + /** + * Create a Ping without a nonce value. + * Only use this if the remote node has a protocol version <= 60000 + */ + public Ping() { + this.hasNonce = false; + } + + public void bitcoinSerializeToStream(OutputStream stream) throws IOException { + if (hasNonce) + Utils.int64ToByteStreamLE(nonce, stream); + } + + @Override + void parse() throws ProtocolException { + try { + nonce = readInt64(); + hasNonce = true; + } catch(ArrayIndexOutOfBoundsException e) { + hasNonce = false; + } + length = hasNonce ? 8 : 0; + } + + @Override + protected void parseLite() { + + } + + boolean hasNonce() { + return hasNonce; + } + + long getNonce() { + return nonce; + } } diff --git a/core/src/main/java/com/google/bitcoin/core/Pong.java b/core/src/main/java/com/google/bitcoin/core/Pong.java new file mode 100644 index 00000000..012b5ded --- /dev/null +++ b/core/src/main/java/com/google/bitcoin/core/Pong.java @@ -0,0 +1,55 @@ +/** + * Copyright 2012 Matt Corallo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.bitcoin.core; + +import java.io.IOException; +import java.io.OutputStream; + +public class Pong extends Message { + private long nonce; + + public Pong(NetworkParameters params, byte[] payloadBytes) throws ProtocolException { + super(params, payloadBytes, 0); + } + + /** + * Create a Pong with a nonce value. + * Only use this if the remote node has a protocol version > 60000 + */ + public Pong(long nonce) { + this.nonce = nonce; + } + + @Override + void parse() throws ProtocolException { + nonce = readInt64(); + length = 8; + } + + public void bitcoinSerializeToStream(OutputStream stream) throws IOException { + Utils.int64ToByteStreamLE(nonce, stream); + } + + @Override + protected void parseLite() { + + } + + long getNonce() { + return nonce; + } +} diff --git a/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java b/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java index 095d0760..b817db62 100644 --- a/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java +++ b/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java @@ -31,6 +31,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Date; +import java.util.Random; import static org.jboss.netty.channel.Channels.write; @@ -114,7 +115,11 @@ public class TCPNetworkConnection { } public void ping() throws IOException { - write(channel, new Ping()); + // pong/nonce messages were added to any protocol version greater than 60000 + if (versionMessage.clientVersion > 60000) + write(channel, new Ping(new Random().nextLong())); + else + write(channel, new Ping()); } @Override diff --git a/core/src/main/java/com/google/bitcoin/core/Utils.java b/core/src/main/java/com/google/bitcoin/core/Utils.java index e14555c5..30213818 100644 --- a/core/src/main/java/com/google/bitcoin/core/Utils.java +++ b/core/src/main/java/com/google/bitcoin/core/Utils.java @@ -115,6 +115,17 @@ public class Utils { stream.write((int) (0xFF & (val >> 16))); stream.write((int) (0xFF & (val >> 24))); } + + public static void int64ToByteStreamLE(long val, OutputStream stream) throws IOException { + stream.write((int) (0xFF & (val >> 0))); + stream.write((int) (0xFF & (val >> 8))); + stream.write((int) (0xFF & (val >> 16))); + stream.write((int) (0xFF & (val >> 24))); + stream.write((int) (0xFF & (val >> 32))); + stream.write((int) (0xFF & (val >> 40))); + stream.write((int) (0xFF & (val >> 48))); + stream.write((int) (0xFF & (val >> 56))); + } public static void uint64ToByteStreamLE(BigInteger val, OutputStream stream) throws IOException { byte[] bytes = val.toByteArray();