mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-07-31 12:01:24 +00:00
Some changes to how block chain download is done:
- Progress is now made available - Fixes bug: can now wait for downloads of chains < 500 blocks - Flesh out VersionMessage parsing, send BitCoinJ name in subVer field
This commit is contained in:
@@ -24,7 +24,7 @@ public class AddressMessage extends Message {
|
|||||||
throw new ProtocolException("Address message too large.");
|
throw new ProtocolException("Address message too large.");
|
||||||
addresses = new ArrayList<PeerAddress>((int)numAddresses);
|
addresses = new ArrayList<PeerAddress>((int)numAddresses);
|
||||||
for (int i = 0; i < numAddresses; i++) {
|
for (int i = 0; i < numAddresses; i++) {
|
||||||
PeerAddress addr = new PeerAddress(params, bytes, cursor);
|
PeerAddress addr = new PeerAddress(params, bytes, cursor, protocolVersion);
|
||||||
addresses.add(addr);
|
addresses.add(addr);
|
||||||
cursor += addr.getMessageSize();
|
cursor += addr.getMessageSize();
|
||||||
}
|
}
|
||||||
|
@@ -48,7 +48,7 @@ public class GetBlocksMessage extends Message {
|
|||||||
try {
|
try {
|
||||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
||||||
// Version, for some reason.
|
// Version, for some reason.
|
||||||
Utils.uint32ToByteStreamLE(VersionMessage.PROTOCOL_VERSION, buf);
|
Utils.uint32ToByteStreamLE(NetworkParameters.PROTOCOL_VERSION, buf);
|
||||||
// Then a vector of block hashes. This is actually a "block locator", a set of block
|
// Then a vector of block hashes. This is actually a "block locator", a set of block
|
||||||
// identifiers that spans the entire chain with exponentially increasing gaps between
|
// identifiers that spans the entire chain with exponentially increasing gaps between
|
||||||
// them, until we end up at the genesis block. See CBlockLocator::Set()
|
// them, until we end up at the genesis block. See CBlockLocator::Set()
|
||||||
|
@@ -16,10 +16,7 @@
|
|||||||
|
|
||||||
package com.google.bitcoin.core;
|
package com.google.bitcoin.core;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -44,8 +41,11 @@ public abstract class Message implements Serializable {
|
|||||||
// Note that it's relative to the start of the array NOT the start of the message.
|
// Note that it's relative to the start of the array NOT the start of the message.
|
||||||
protected transient int cursor;
|
protected transient int cursor;
|
||||||
|
|
||||||
|
// The raw message bytes themselves.
|
||||||
protected transient byte[] bytes;
|
protected transient byte[] bytes;
|
||||||
|
|
||||||
|
protected transient int protocolVersion;
|
||||||
|
|
||||||
// This will be saved by subclasses that implement Serializable.
|
// This will be saved by subclasses that implement Serializable.
|
||||||
protected NetworkParameters params;
|
protected NetworkParameters params;
|
||||||
|
|
||||||
@@ -58,7 +58,8 @@ public abstract class Message implements Serializable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
Message(NetworkParameters params, byte[] msg, int offset) throws ProtocolException {
|
Message(NetworkParameters params, byte[] msg, int offset, int protocolVersion) throws ProtocolException {
|
||||||
|
this.protocolVersion = protocolVersion;
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.bytes = msg;
|
this.bytes = msg;
|
||||||
this.cursor = this.offset = offset;
|
this.cursor = this.offset = offset;
|
||||||
@@ -75,6 +76,10 @@ public abstract class Message implements Serializable {
|
|||||||
this.bytes = null;
|
this.bytes = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message(NetworkParameters params, byte[] msg, int offset) throws ProtocolException {
|
||||||
|
this(params, msg, offset, NetworkParameters.PROTOCOL_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
// These methods handle the serialization/deserialization using the custom BitCoin protocol.
|
// These methods handle the serialization/deserialization using the custom BitCoin protocol.
|
||||||
// It's somewhat painful to work with in Java, so some of these objects support a second
|
// It's somewhat painful to work with in Java, so some of these objects support a second
|
||||||
// serialization mechanism - the standard Java serialization system. This is used when things
|
// serialization mechanism - the standard Java serialization system. This is used when things
|
||||||
@@ -141,4 +146,20 @@ public abstract class Message implements Serializable {
|
|||||||
cursor += length;
|
cursor += length;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String readStr() {
|
||||||
|
VarInt varInt = new VarInt(bytes, cursor);
|
||||||
|
if (varInt.value == 0) {
|
||||||
|
cursor += 1;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
byte[] characters = new byte[(int)varInt.value];
|
||||||
|
System.arraycopy(bytes, cursor, characters, 0, characters.length);
|
||||||
|
cursor += varInt.getSizeInBytes();
|
||||||
|
try {
|
||||||
|
return new String(characters, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,8 @@ public class NetworkConnection {
|
|||||||
private final InetAddress remoteIp;
|
private final InetAddress remoteIp;
|
||||||
private boolean usesChecksumming;
|
private boolean usesChecksumming;
|
||||||
private final NetworkParameters params;
|
private final NetworkParameters params;
|
||||||
static final private boolean PROTOCOL_LOG = false;
|
private final VersionMessage versionMessage;
|
||||||
|
private static final boolean PROTOCOL_LOG = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to the given IP address using the port specified as part of the network parameters. Once construction
|
* Connect to the given IP address using the port specified as part of the network parameters. Once construction
|
||||||
@@ -74,7 +75,7 @@ public class NetworkConnection {
|
|||||||
|
|
||||||
// When connecting, the remote peer sends us a version message with various bits of
|
// When connecting, the remote peer sends us a version message with various bits of
|
||||||
// useful data in it. We need to know the peer protocol version before we can talk to it.
|
// useful data in it. We need to know the peer protocol version before we can talk to it.
|
||||||
VersionMessage ver = (VersionMessage) readMessage();
|
versionMessage = (VersionMessage) readMessage();
|
||||||
// Now it's our turn ...
|
// Now it's our turn ...
|
||||||
writeMessage(MSG_VERSION, new VersionMessage(params));
|
writeMessage(MSG_VERSION, new VersionMessage(params));
|
||||||
// Send an ACK message stating we accept the peers protocol version.
|
// Send an ACK message stating we accept the peers protocol version.
|
||||||
@@ -82,12 +83,13 @@ public class NetworkConnection {
|
|||||||
// And get one back ...
|
// And get one back ...
|
||||||
readMessage();
|
readMessage();
|
||||||
// Switch to the new protocol version.
|
// Switch to the new protocol version.
|
||||||
int peerVersion = ver.clientVersion;
|
int peerVersion = versionMessage.clientVersion;
|
||||||
LOG("Connected to peer, version is " + peerVersion + ", services=" + Long.toHexString(
|
LOG(String.format("Connected to peer: version=%d, subVer='%s', services=0x%x, time=%s, blocks=%d",
|
||||||
ver.localServices) + ", time=" + new Date(ver.time.longValue() * 1000).toString());
|
peerVersion, versionMessage.subVer,
|
||||||
|
versionMessage.localServices, new Date(versionMessage.time * 1000).toString(), versionMessage.bestHeight));
|
||||||
// BitCoinJ is a client mode implementation. That means there's not much point in us talking to other client
|
// BitCoinJ is a client mode implementation. That means there's not much point in us talking to other client
|
||||||
// mode nodes because we can't download the data from them we need to find/verify transactions.
|
// mode nodes because we can't download the data from them we need to find/verify transactions.
|
||||||
if (!ver.hasBlockChain())
|
if (!versionMessage.hasBlockChain())
|
||||||
throw new ProtocolException("Peer does not have a copy of the block chain.");
|
throw new ProtocolException("Peer does not have a copy of the block chain.");
|
||||||
usesChecksumming = peerVersion >= 209;
|
usesChecksumming = peerVersion >= 209;
|
||||||
// Handshake is done!
|
// Handshake is done!
|
||||||
@@ -198,9 +200,6 @@ public class NetworkConnection {
|
|||||||
if (size > Message.MAX_SIZE)
|
if (size > Message.MAX_SIZE)
|
||||||
throw new ProtocolException("Message size too large: " + size);
|
throw new ProtocolException("Message size too large: " + size);
|
||||||
|
|
||||||
if (PROTOCOL_LOG)
|
|
||||||
LOG("Received " + size + " byte '" + command + "' command");
|
|
||||||
|
|
||||||
// Old clients don't send the checksum.
|
// Old clients don't send the checksum.
|
||||||
byte[] checksum = new byte[4];
|
byte[] checksum = new byte[4];
|
||||||
if (usesChecksumming) {
|
if (usesChecksumming) {
|
||||||
@@ -231,6 +230,9 @@ public class NetworkConnection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PROTOCOL_LOG)
|
||||||
|
LOG("Received " + size + " byte '" + command + "' message: " + Utils.bytesToHexString(payloadBytes));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Message message;
|
Message message;
|
||||||
if (command.equals(MSG_VERSION))
|
if (command.equals(MSG_VERSION))
|
||||||
@@ -292,4 +294,9 @@ public class NetworkConnection {
|
|||||||
// TODO: Requiring "tag" here is redundant, the message object should know its own protocol tag.
|
// TODO: Requiring "tag" here is redundant, the message object should know its own protocol tag.
|
||||||
writeMessage(tag, message.bitcoinSerialize());
|
writeMessage(tag, message.bitcoinSerialize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the version message received from the other end of the connection during the handshake. */
|
||||||
|
public VersionMessage getVersionMessage() {
|
||||||
|
return versionMessage;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,6 +29,11 @@ import java.math.BigInteger;
|
|||||||
* evolves there may be more. You can create your own as long as they don't conflict.
|
* evolves there may be more. You can create your own as long as they don't conflict.
|
||||||
*/
|
*/
|
||||||
public class NetworkParameters implements Serializable {
|
public class NetworkParameters implements Serializable {
|
||||||
|
/**
|
||||||
|
* The protocol version this library implements. A value of 31800 means 0.3.18.00.
|
||||||
|
*/
|
||||||
|
public static final int PROTOCOL_VERSION = 31800;
|
||||||
|
|
||||||
private static final long serialVersionUID = 2579833727976661964L;
|
private static final long serialVersionUID = 2579833727976661964L;
|
||||||
|
|
||||||
// TODO: Seed nodes and checkpoint values should be here as well.
|
// TODO: Seed nodes and checkpoint values should be here as well.
|
||||||
|
@@ -106,9 +106,6 @@ public class Peer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This tracks whether we have received a block we could not connect to the chain in this session.
|
|
||||||
private boolean hasSeenUnconnectedBlock = false;
|
|
||||||
|
|
||||||
private void processBlock(Block m) throws IOException {
|
private void processBlock(Block m) throws IOException {
|
||||||
assert Thread.currentThread() == thread;
|
assert Thread.currentThread() == thread;
|
||||||
try {
|
try {
|
||||||
@@ -128,17 +125,13 @@ public class Peer {
|
|||||||
// Otherwise it's a block sent to us because the peer thought we needed it, so add it to the block chain.
|
// Otherwise it's a block sent to us because the peer thought we needed it, so add it to the block chain.
|
||||||
// This call will synchronize on blockChain.
|
// This call will synchronize on blockChain.
|
||||||
if (blockChain.add(m)) {
|
if (blockChain.add(m)) {
|
||||||
// The block was successfully linked into the chain.
|
// The block was successfully linked into the chain. Notify the user of our progress.
|
||||||
if (hasSeenUnconnectedBlock && blockChain.getUnconnectedBlock() == null) {
|
if (chainCompletionLatch != null) {
|
||||||
// We cleared out our unconnected blocks. This likely means block chain download is "done" in the
|
chainCompletionLatch.countDown();
|
||||||
// sense that we were downloading blocks as part of the chained download,
|
if (chainCompletionLatch.getCount() == 0) {
|
||||||
// and there's no more to come. To some extent of course the download is never done.
|
// All blocks fetched, so we don't need this anymore.
|
||||||
LOG("Block chain download done.");
|
|
||||||
if (chainCompletionLatch != null) {
|
|
||||||
chainCompletionLatch.countDown();
|
|
||||||
chainCompletionLatch = null;
|
chainCompletionLatch = null;
|
||||||
}
|
}
|
||||||
hasSeenUnconnectedBlock = false;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// This block is unconnected - we don't know how to get from it back to the genesis block yet. That
|
// This block is unconnected - we don't know how to get from it back to the genesis block yet. That
|
||||||
@@ -148,7 +141,6 @@ public class Peer {
|
|||||||
// the others.
|
// the others.
|
||||||
|
|
||||||
// TODO: Should actually request root of orphan chain here.
|
// TODO: Should actually request root of orphan chain here.
|
||||||
hasSeenUnconnectedBlock = true;
|
|
||||||
blockChainDownload(m.getHash());
|
blockChainDownload(m.getHash());
|
||||||
}
|
}
|
||||||
} catch (VerificationException e) {
|
} catch (VerificationException e) {
|
||||||
@@ -319,14 +311,20 @@ public class Peer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts an asynchronous download of the block chain. Completion of the download is a somewhat vague concept in
|
* Starts an asynchronous download of the block chain. The chain download is deemed to be complete once we've
|
||||||
* BitCoin as the chain is constantly growing, but essentially we deem the download complete once we have
|
* downloaded the same number of blocks that the peer advertised having in its version handshake message.
|
||||||
* received the block that the peer told us was the head when we first started the download.
|
|
||||||
*
|
*
|
||||||
* @return a {@link CountDownLatch} that can be used to wait until the chain download is "complete".
|
* @return a {@link CountDownLatch} that can be used to track progress and wait for completion.
|
||||||
*/
|
*/
|
||||||
public CountDownLatch startBlockChainDownload() throws IOException {
|
public CountDownLatch startBlockChainDownload() throws IOException {
|
||||||
chainCompletionLatch = new CountDownLatch(1);
|
// Chain will overflow signed int blocks in ~41,000 years.
|
||||||
|
int chainHeight = (int) conn.getVersionMessage().bestHeight;
|
||||||
|
if (chainHeight <= 0) {
|
||||||
|
// This should not happen because we shouldn't have given the user a Peer that is to another client-mode
|
||||||
|
// node. If that happens it means the user overrode us somewhere.
|
||||||
|
throw new RuntimeException("Peer does not have block chain");
|
||||||
|
}
|
||||||
|
chainCompletionLatch = new CountDownLatch(chainHeight);
|
||||||
blockChainDownload(params.genesisBlock.getHash());
|
blockChainDownload(params.genesisBlock.getHash());
|
||||||
return chainCompletionLatch;
|
return chainCompletionLatch;
|
||||||
}
|
}
|
||||||
|
@@ -36,9 +36,10 @@ public class PeerAddress extends Message {
|
|||||||
InetAddress addr;
|
InetAddress addr;
|
||||||
int port;
|
int port;
|
||||||
BigInteger services;
|
BigInteger services;
|
||||||
|
long time;
|
||||||
|
|
||||||
public PeerAddress(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
|
public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
|
||||||
super(params, payload, offset);
|
super(params, payload, offset, protocolVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PeerAddress(InetAddress addr, int port) {
|
public PeerAddress(InetAddress addr, int port) {
|
||||||
@@ -72,7 +73,10 @@ public class PeerAddress extends Message {
|
|||||||
// uint64 services (flags determining what the node can do)
|
// uint64 services (flags determining what the node can do)
|
||||||
// 16 bytes ip address
|
// 16 bytes ip address
|
||||||
// 2 bytes port num
|
// 2 bytes port num
|
||||||
long time = readUint32();
|
if (protocolVersion > 31402)
|
||||||
|
time = readUint32();
|
||||||
|
else
|
||||||
|
time = -1;
|
||||||
services = readUint64();
|
services = readUint64();
|
||||||
byte[] addrBytes = readBytes(16);
|
byte[] addrBytes = readBytes(16);
|
||||||
try {
|
try {
|
||||||
|
@@ -25,22 +25,28 @@ import java.net.UnknownHostException;
|
|||||||
public class VersionMessage extends Message {
|
public class VersionMessage extends Message {
|
||||||
private static final long serialVersionUID = 7313594258967483180L;
|
private static final long serialVersionUID = 7313594258967483180L;
|
||||||
|
|
||||||
/**
|
|
||||||
* The protocol version this library implements. A value of 31800 means 0.3.18.00.
|
|
||||||
*/
|
|
||||||
public static final int PROTOCOL_VERSION = 31800;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A services flag that denotes whether the peer has a copy of the block chain or not.
|
* A services flag that denotes whether the peer has a copy of the block chain or not.
|
||||||
*/
|
*/
|
||||||
public static final int NODE_NETWORK = 1;
|
public static final int NODE_NETWORK = 1;
|
||||||
|
|
||||||
|
/** The version number of the protocol spoken. */
|
||||||
public int clientVersion;
|
public int clientVersion;
|
||||||
// Flags defining what the other side supports. Right now there's only one flag and it's
|
/** Flags defining what is supported. Right now {@link #NODE_NETWORK} is the only flag defined. */
|
||||||
// always set 1 by the official client, but we have to set it to zero as we don't store
|
|
||||||
// the block chain. In future there may be more services bits.
|
|
||||||
public long localServices;
|
public long localServices;
|
||||||
public BigInteger time;
|
/** What the other side believes the current time to be, in seconds. */
|
||||||
|
public long time;
|
||||||
|
/** What the other side believes the address of this program is. Not used. */
|
||||||
|
public PeerAddress myAddr;
|
||||||
|
/** What the other side believes their own address is. Not used. */
|
||||||
|
public PeerAddress theirAddr;
|
||||||
|
/**
|
||||||
|
* An additional string that today the official client sets to the empty string. We treat it as something like an
|
||||||
|
* HTTP User-Agent header.
|
||||||
|
*/
|
||||||
|
public String subVer;
|
||||||
|
/** How many blocks are in the chain, according to the other side. */
|
||||||
|
public long bestHeight;
|
||||||
|
|
||||||
public VersionMessage(NetworkParameters params, byte[] msg) throws ProtocolException {
|
public VersionMessage(NetworkParameters params, byte[] msg) throws ProtocolException {
|
||||||
super(params, msg, 0);
|
super(params, msg, 0);
|
||||||
@@ -48,43 +54,51 @@ public class VersionMessage extends Message {
|
|||||||
|
|
||||||
public VersionMessage(NetworkParameters params) {
|
public VersionMessage(NetworkParameters params) {
|
||||||
super(params);
|
super(params);
|
||||||
clientVersion = PROTOCOL_VERSION;
|
clientVersion = NetworkParameters.PROTOCOL_VERSION;
|
||||||
localServices = 0;
|
localServices = 0;
|
||||||
time = BigInteger.valueOf(System.currentTimeMillis() / 1000);
|
time = System.currentTimeMillis() / 1000;
|
||||||
|
// Note that the official client doesn't do anything with these, and finding out your own external IP address
|
||||||
|
// is kind of tricky anyway, so we just put nonsense here for now.
|
||||||
|
try {
|
||||||
|
myAddr = new PeerAddress(InetAddress.getLocalHost(), params.port);
|
||||||
|
theirAddr = new PeerAddress(InetAddress.getLocalHost(), params.port);
|
||||||
|
} catch (UnknownHostException e) {
|
||||||
|
throw new RuntimeException(e); // Cannot happen.
|
||||||
|
}
|
||||||
|
subVer = "BitCoinJ 0.1.99";
|
||||||
|
bestHeight = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void parse() throws ProtocolException {
|
public void parse() throws ProtocolException {
|
||||||
// There is probably a more Java-ish way to do this.
|
|
||||||
clientVersion = (int) readUint32();
|
clientVersion = (int) readUint32();
|
||||||
localServices = readUint64().longValue();
|
localServices = readUint64().longValue();
|
||||||
time = readUint64();
|
time = readUint64().longValue();
|
||||||
// The next fields are:
|
myAddr = new PeerAddress(params, bytes, cursor, 0);
|
||||||
// CAddress my address
|
cursor += myAddr.getMessageSize();
|
||||||
// CAddress their address
|
theirAddr = new PeerAddress(params, bytes, cursor, 0);
|
||||||
// uint64 localHostNonce (random data)
|
cursor += theirAddr.getMessageSize();
|
||||||
|
// uint64 localHostNonce (random data)
|
||||||
|
// 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 "")
|
// string subVer (currently "")
|
||||||
|
subVer = readStr();
|
||||||
// int bestHeight (size of known block chain).
|
// int bestHeight (size of known block chain).
|
||||||
//
|
bestHeight = readUint32();
|
||||||
// However, we don't care about these fields right now.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void bitcoinSerializeToStream(OutputStream buf) throws IOException {
|
public void bitcoinSerializeToStream(OutputStream buf) throws IOException {
|
||||||
Utils.uint32ToByteStreamLE(clientVersion, buf);
|
Utils.uint32ToByteStreamLE(clientVersion, buf);
|
||||||
Utils.uint32ToByteStreamLE(localServices, buf);
|
Utils.uint32ToByteStreamLE(localServices, buf);
|
||||||
long ltime = time.longValue();
|
Utils.uint32ToByteStreamLE(time >> 32, buf);
|
||||||
Utils.uint32ToByteStreamLE(ltime >> 32, buf);
|
Utils.uint32ToByteStreamLE(time, buf);
|
||||||
Utils.uint32ToByteStreamLE(ltime, buf);
|
|
||||||
try {
|
try {
|
||||||
// Now there are two address structures. Note that the official client doesn't do anything with these, and
|
|
||||||
// finding out your own external IP address is kind of tricky anyway, so we just serialize nonsense here.
|
|
||||||
|
|
||||||
// My address.
|
// My address.
|
||||||
new PeerAddress(InetAddress.getLocalHost(), params.port).bitcoinSerializeToStream(buf);
|
myAddr.bitcoinSerializeToStream(buf);
|
||||||
// Their address.
|
// Their address.
|
||||||
new PeerAddress(InetAddress.getLocalHost(), params.port).bitcoinSerializeToStream(buf);
|
theirAddr.bitcoinSerializeToStream(buf);
|
||||||
} catch (UnknownHostException e) {
|
} catch (UnknownHostException e) {
|
||||||
throw new RuntimeException(e); // Can't happen.
|
throw new RuntimeException(e); // Can't happen.
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -95,10 +109,12 @@ public class VersionMessage extends Message {
|
|||||||
// connections.
|
// connections.
|
||||||
Utils.uint32ToByteStreamLE(0, buf);
|
Utils.uint32ToByteStreamLE(0, buf);
|
||||||
Utils.uint32ToByteStreamLE(0, buf);
|
Utils.uint32ToByteStreamLE(0, buf);
|
||||||
// Now comes an empty string.
|
// Now comes subVer.
|
||||||
buf.write(0);
|
byte[] subVerBytes = subVer.getBytes("UTF-8");
|
||||||
// Size of known block chain. Claim we never saw any blocks.
|
buf.write(new VarInt(subVerBytes.length).encode());
|
||||||
Utils.uint32ToByteStreamLE(0, buf);
|
buf.write(subVerBytes);
|
||||||
|
// Size of known block chain.
|
||||||
|
Utils.uint32ToByteStreamLE(bestHeight, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -22,6 +22,8 @@ import java.io.File;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PingService demonstrates basic usage of the library. It sits on the network and when it receives coins, simply
|
* PingService demonstrates basic usage of the library. It sits on the network and when it receives coins, simply
|
||||||
@@ -29,7 +31,7 @@ import java.net.InetAddress;
|
|||||||
*/
|
*/
|
||||||
public class PingService {
|
public class PingService {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
final NetworkParameters params = NetworkParameters.prodNet();
|
final NetworkParameters params = NetworkParameters.testNet();
|
||||||
|
|
||||||
// Try to read the wallet from storage, create a new one if not possible.
|
// Try to read the wallet from storage, create a new one if not possible.
|
||||||
Wallet wallet;
|
Wallet wallet;
|
||||||
@@ -51,7 +53,6 @@ public class PingService {
|
|||||||
BlockChain chain = new BlockChain(params, wallet);
|
BlockChain chain = new BlockChain(params, wallet);
|
||||||
final Peer peer = new Peer(params, conn, chain);
|
final Peer peer = new Peer(params, conn, chain);
|
||||||
peer.start();
|
peer.start();
|
||||||
peer.startBlockChainDownload().await();
|
|
||||||
|
|
||||||
// We want to know when the balance changes.
|
// We want to know when the balance changes.
|
||||||
wallet.addEventListener(new WalletEventListener() {
|
wallet.addEventListener(new WalletEventListener() {
|
||||||
@@ -82,6 +83,15 @@ public class PingService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
CountDownLatch progress = peer.startBlockChainDownload();
|
||||||
|
long max = progress.getCount(); // Racy but no big deal.
|
||||||
|
long current = max;
|
||||||
|
while (current > 0) {
|
||||||
|
double pct = 100.0 - (100.0 * (current / (double)max));
|
||||||
|
System.out.println(String.format("Chain download %d%% done", (int)pct));
|
||||||
|
progress.await(1, TimeUnit.SECONDS);
|
||||||
|
current = progress.getCount();
|
||||||
|
}
|
||||||
System.out.println("Send coins to: " + key.toAddress(params).toString());
|
System.out.println("Send coins to: " + key.toAddress(params).toString());
|
||||||
System.out.println("Waiting for coins to arrive. Press Ctrl-C to quit.");
|
System.out.println("Waiting for coins to arrive. Press Ctrl-C to quit.");
|
||||||
// The peer thread keeps us alive until something kills the process.
|
// The peer thread keeps us alive until something kills the process.
|
||||||
|
Reference in New Issue
Block a user