3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-31 07:12:17 +00:00

Reformat the codebase, this is pretty much whatever IntelliJ thinks the code should look like.

This will unfortunately break all patches, but it has to be done at some point.
This commit is contained in:
Mike Hearn 2011-10-14 13:06:54 +00:00
parent 84f738763f
commit fb5915e4c4
51 changed files with 2399 additions and 2310 deletions

View File

@ -18,11 +18,10 @@ package com.google.bitcoin.core;
/** /**
* Convenience abstract class for implmenting a PeerEventListener. * Convenience abstract class for implmenting a PeerEventListener.
*
* <p>The default method implementations do nothing.
*
* @author miron@google.com (Miron Cuperman)
* *
* <p>The default method implementations do nothing.
*
* @author miron@google.com (Miron Cuperman)
*/ */
public class AbstractPeerEventListener extends Object implements PeerEventListener { public class AbstractPeerEventListener extends Object implements PeerEventListener {
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) { public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
@ -30,10 +29,10 @@ public class AbstractPeerEventListener extends Object implements PeerEventListen
public void onChainDownloadStarted(Peer peer, int blocksLeft) { public void onChainDownloadStarted(Peer peer, int blocksLeft) {
} }
public void onPeerConnected(Peer peer, int peerCount) { public void onPeerConnected(Peer peer, int peerCount) {
} }
public void onPeerDisconnected(Peer peer, int peerCount) { public void onPeerDisconnected(Peer peer, int peerCount) {
} }
} }

View File

@ -30,10 +30,10 @@ public abstract class AbstractWalletEventListener implements WalletEventListener
* register the event listener after the chain is downloaded. It's safe to use methods of wallet during the * register the event listener after the chain is downloaded. It's safe to use methods of wallet during the
* execution of this callback. * execution of this callback.
* *
* @param wallet The wallet object that received the coins/ * @param wallet The wallet object that received the coins/
* @param tx The transaction which sent us the coins. * @param tx The transaction which sent us the coins.
* @param prevBalance Balance before the coins were received. * @param prevBalance Balance before the coins were received.
* @param newBalance Current balance of the wallet. * @param newBalance Current balance of the wallet.
*/ */
public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) { public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) {
onChange(); onChange();
@ -65,7 +65,7 @@ public abstract class AbstractWalletEventListener implements WalletEventListener
* C++ client of the recipient as 0/unconfirmed forever, so if it was used to purchase something, * C++ client of the recipient as 0/unconfirmed forever, so if it was used to purchase something,
* the user needs to know their goods will never arrive. * the user needs to know their goods will never arrive.
* *
* @param deadTx The transaction that is newly dead. * @param deadTx The transaction that is newly dead.
* @param replacementTx The transaction that killed it. * @param replacementTx The transaction that killed it.
*/ */
public void onDeadTransaction(Wallet wallet, Transaction deadTx, Transaction replacementTx) { public void onDeadTransaction(Wallet wallet, Transaction deadTx, Transaction replacementTx) {

View File

@ -16,16 +16,14 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import java.util.Arrays;
/** /**
* A BitCoin address is fundamentally derived from an elliptic curve public key and a set of network parameters. * A BitCoin address is fundamentally derived from an elliptic curve public key and a set of network parameters.
* It has several possible representations:<p> * It has several possible representations:<p>
* *
* <ol> * <ol>
* <li>The raw public key bytes themselves. * <li>The raw public key bytes themselves.
* <li>RIPEMD160 hash of the public key bytes. * <li>RIPEMD160 hash of the public key bytes.
* <li>A base58 encoded "human form" that includes a version and check code, to guard against typos. * <li>A base58 encoded "human form" that includes a version and check code, to guard against typos.
* </ol><p> * </ol><p>
* *
* One may question whether the base58 form is really an improvement over the hash160 form, given * One may question whether the base58 form is really an improvement over the hash160 form, given
@ -40,7 +38,7 @@ public class Address extends VersionedChecksummedBytes {
* *
* <pre>new Address(NetworkParameters.prodNet(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre> * <pre>new Address(NetworkParameters.prodNet(), Hex.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a"));</pre>
*/ */
public Address(NetworkParameters params, byte[] hash160) { public Address(NetworkParameters params, byte[] hash160) {
super(params.addressHeader, hash160); super(params.addressHeader, hash160);
if (hash160.length != 20) // 160 = 8 * 20 if (hash160.length != 20) // 160 = 8 * 20
throw new RuntimeException("Addresses are 160-bit hashes, so you must provide 20 bytes"); throw new RuntimeException("Addresses are 160-bit hashes, so you must provide 20 bytes");

View File

@ -15,11 +15,11 @@ public class AddressMessage extends Message {
AddressMessage(NetworkParameters params, byte[] payload, int offset, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException { AddressMessage(NetworkParameters params, byte[] payload, int offset, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
super(params, payload, offset, parseLazy, parseRetain, length); super(params, payload, offset, parseLazy, parseRetain, length);
} }
AddressMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException { AddressMessage(NetworkParameters params, byte[] payload, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException {
super(params, payload, 0, parseLazy, parseRetain, length); super(params, payload, 0, parseLazy, parseRetain, length);
} }
AddressMessage(NetworkParameters params, byte[] payload, int offset) throws ProtocolException { AddressMessage(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset, false, false, UNKNOWN_LENGTH); super(params, payload, offset, false, false, UNKNOWN_LENGTH);
} }
@ -27,22 +27,22 @@ public class AddressMessage extends Message {
AddressMessage(NetworkParameters params, byte[] payload) throws ProtocolException { AddressMessage(NetworkParameters params, byte[] payload) throws ProtocolException {
super(params, payload, 0, false, false, UNKNOWN_LENGTH); super(params, payload, 0, false, false, UNKNOWN_LENGTH);
} }
/* (non-Javadoc)
* @see com.google.bitcoin.core.Message#parseLite()
*/
@Override
protected void parseLite() throws ProtocolException {
//nop this should never be taken off the wire without having a length provided.
}
@Override /* (non-Javadoc)
* @see com.google.bitcoin.core.Message#parseLite()
*/
@Override
protected void parseLite() throws ProtocolException {
//nop this should never be taken off the wire without having a length provided.
}
@Override
void parse() throws ProtocolException { void parse() throws ProtocolException {
numAddresses = readVarInt(); numAddresses = readVarInt();
// Guard against ultra large messages that will crash us. // Guard against ultra large messages that will crash us.
if (numAddresses > MAX_ADDRESSES) if (numAddresses > MAX_ADDRESSES)
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, protocolVersion, this, parseLazy, parseRetain); PeerAddress addr = new PeerAddress(params, bytes, cursor, protocolVersion, this, parseLazy, parseRetain);
addresses.add(addr); addresses.add(addr);
@ -50,72 +50,73 @@ public class AddressMessage extends Message {
} }
length = cursor - offset; length = cursor - offset;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see com.google.bitcoin.core.Message#bitcoinSerializeToStream(java.io.OutputStream) * @see com.google.bitcoin.core.Message#bitcoinSerializeToStream(java.io.OutputStream)
*/ */
@Override @Override
void bitcoinSerializeToStream(OutputStream stream) throws IOException { void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (addresses == null) if (addresses == null)
return; return;
stream.write(new VarInt(addresses.size()).encode()); stream.write(new VarInt(addresses.size()).encode());
for (PeerAddress addr: addresses) { for (PeerAddress addr : addresses) {
addr.bitcoinSerialize(stream); addr.bitcoinSerialize(stream);
} }
} }
int getMessageSize() { int getMessageSize() {
if (length != UNKNOWN_LENGTH) if (length != UNKNOWN_LENGTH)
return length; return length;
length = new VarInt(addresses.size()).getSizeInBytes(); length = new VarInt(addresses.size()).getSizeInBytes();
if (addresses != null) if (addresses != null)
length += addresses.size() * (protocolVersion > 31402 ? PeerAddress.MESSAGE_SIZE : PeerAddress.MESSAGE_SIZE - 4); length += addresses.size() * (protocolVersion > 31402 ? PeerAddress.MESSAGE_SIZE : PeerAddress.MESSAGE_SIZE - 4);
return length; return length;
} }
/**
* AddressMessage cannot cache checksum in non-retain mode due to dynamic time being used.
*/
@Override
void setChecksum(byte[] checksum) {
if (parseRetain)
super.setChecksum(checksum);
else
this.checksum = null;
}
/** /**
* @return An unmodifiableList view of the backing List of addresses. Addresses contained within the list may be safely modified. * AddressMessage cannot cache checksum in non-retain mode due to dynamic time being used.
*/ */
public List<PeerAddress> getAddresses() { @Override
checkParse(); void setChecksum(byte[] checksum) {
return Collections.unmodifiableList(addresses); if (parseRetain)
} super.setChecksum(checksum);
else
public void addAddress(PeerAddress address) { this.checksum = null;
unCache(); }
checkParse();
address.setParent(this);
addresses.add(address);
if (length == UNKNOWN_LENGTH)
getMessageSize();
else
length += address.getMessageSize();;
}
public void removeAddress(int index) {
unCache();
PeerAddress address = addresses.remove(index);
if (address != null)
address.setParent(null);
if (length == UNKNOWN_LENGTH)
getMessageSize();
else
length -= address.getMessageSize();
}
@Override /**
* @return An unmodifiableList view of the backing List of addresses. Addresses contained within the list may be safely modified.
*/
public List<PeerAddress> getAddresses() {
checkParse();
return Collections.unmodifiableList(addresses);
}
public void addAddress(PeerAddress address) {
unCache();
checkParse();
address.setParent(this);
addresses.add(address);
if (length == UNKNOWN_LENGTH)
getMessageSize();
else
length += address.getMessageSize();
;
}
public void removeAddress(int index) {
unCache();
PeerAddress address = addresses.remove(index);
if (address != null)
address.setParent(null);
if (length == UNKNOWN_LENGTH)
getMessageSize();
else
length -= address.getMessageSize();
}
@Override
public String toString() { public String toString() {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
builder.append("addr: "); builder.append("addr: ");

View File

@ -22,7 +22,7 @@ import java.util.Arrays;
/** /**
* A custom form of base58 is used to encode BitCoin addresses. Note that this is not the same base58 as used by * A custom form of base58 is used to encode BitCoin addresses. Note that this is not the same base58 as used by
* Flickr, which you may see reference to around the internet.<p> * Flickr, which you may see reference to around the internet.<p>
* *
* Satoshi says: why base-58 instead of standard base-64 encoding?<p> * Satoshi says: why base-58 instead of standard base-64 encoding?<p>
* *
* <ul> * <ul>

View File

@ -37,9 +37,9 @@ import static com.google.bitcoin.core.Utils.*;
* *
* To be able to serialize and deserialize new Message subclasses the following criteria needs to be met. * To be able to serialize and deserialize new Message subclasses the following criteria needs to be met.
* <ul> * <ul>
* <li>The proper Class instance needs to be mapped to it's message name in the names variable below</li> * <li>The proper Class instance needs to be mapped to it's message name in the names variable below</li>
* <li>There needs to be a constructor matching: NetworkParameters params, byte[] payload</li> * <li>There needs to be a constructor matching: NetworkParameters params, byte[] payload</li>
* <li>Message.bitcoinSerializeToStream() needs to be properly subclassed</li> * <li>Message.bitcoinSerializeToStream() needs to be properly subclassed</li>
* </ul><p> * </ul><p>
* *
* BitcoinSerializers can be given a map which will be locked during reading/deserialization. This is used to * BitcoinSerializers can be given a map which will be locked during reading/deserialization. This is used to
@ -55,7 +55,7 @@ public class BitcoinSerializer {
private boolean parseLazy = false; private boolean parseLazy = false;
private boolean parseRetain = false; private boolean parseRetain = false;
private static Map<Class<? extends Message>, String> names = new HashMap<Class<? extends Message>,String>(); private static Map<Class<? extends Message>, String> names = new HashMap<Class<? extends Message>, String>();
static { static {
names.put(VersionMessage.class, "version"); names.put(VersionMessage.class, "version");
@ -94,22 +94,22 @@ public class BitcoinSerializer {
/** /**
* Constructs a BitcoinSerializer with the given behavior. * Constructs a BitcoinSerializer with the given behavior.
* *
* @param params networkParams used to create Messages instances and termining packetMagic * @param params networkParams used to create Messages instances and termining packetMagic
* @param usesChecksumming set to true if checkums should be included and expected in headers * @param usesChecksumming set to true if checkums should be included and expected in headers
*/ */
public BitcoinSerializer(NetworkParameters params, boolean usesChecksumming, public BitcoinSerializer(NetworkParameters params, boolean usesChecksumming,
LinkedHashMap<Sha256Hash, Integer> dedupeList) { LinkedHashMap<Sha256Hash, Integer> dedupeList) {
this(params, usesChecksumming, false, false, dedupeList); this(params, usesChecksumming, false, false, dedupeList);
} }
/** /**
* Constructs a BitcoinSerializer with the given behavior. * Constructs a BitcoinSerializer with the given behavior.
* *
* @param params networkParams used to create Messages instances and termining packetMagic * @param params networkParams used to create Messages instances and termining packetMagic
* @param usesChecksumming set to true if checkums should be included and expected in headers * @param usesChecksumming set to true if checkums should be included and expected in headers
* @param parseLazy deserialize messages in lazy mode. * @param parseLazy deserialize messages in lazy mode.
* @param parseRetain retain the backing byte array of a message for fast reserialization. * @param parseRetain retain the backing byte array of a message for fast reserialization.
* @param dedupeList possibly shared list of previously received messages used to avoid parsing duplicates. * @param dedupeList possibly shared list of previously received messages used to avoid parsing duplicates.
*/ */
public BitcoinSerializer(NetworkParameters params, boolean usesChecksumming, boolean parseLazy, boolean parseRetain, public BitcoinSerializer(NetworkParameters params, boolean usesChecksumming, boolean parseLazy, boolean parseRetain,
LinkedHashMap<Sha256Hash, Integer> dedupeList) { LinkedHashMap<Sha256Hash, Integer> dedupeList) {
@ -142,7 +142,7 @@ public class BitcoinSerializer {
public void serialize(Message message, OutputStream out) throws IOException { public void serialize(Message message, OutputStream out) throws IOException {
String name = names.get(message.getClass()); String name = names.get(message.getClass());
if (name == null) { if (name == null) {
throw new Error("BitcoinSerializer doesn't currently know how to serialize "+ message.getClass()); throw new Error("BitcoinSerializer doesn't currently know how to serialize " + message.getClass());
} }
byte[] header = new byte[4 + COMMAND_LEN + 4 + (usesChecksumming ? 4 : 0)]; byte[] header = new byte[4 + COMMAND_LEN + 4 + (usesChecksumming ? 4 : 0)];
@ -161,29 +161,29 @@ public class BitcoinSerializer {
if (usesChecksumming) { if (usesChecksumming) {
byte[] checksum = message.getChecksum(); byte[] checksum = message.getChecksum();
if (checksum == null) { if (checksum == null) {
Sha256Hash msgHash = message.getHash(); Sha256Hash msgHash = message.getHash();
if (msgHash != null && message instanceof Transaction) { if (msgHash != null && message instanceof Transaction) {
// if the message happens to have a precalculated hash use // if the message happens to have a precalculated hash use
// it. // it.
// reverse copying 4 bytes is about 1600 times faster than // reverse copying 4 bytes is about 1600 times faster than
// calculating a new hash // calculating a new hash
// this is only possible for transactions as block hashes // this is only possible for transactions as block hashes
// are hashes of the header only // are hashes of the header only
byte[] hash = msgHash.getBytes(); byte[] hash = msgHash.getBytes();
int start = 4 + COMMAND_LEN + 4; int start = 4 + COMMAND_LEN + 4;
for (int i = start; i < start + 4; i++) for (int i = start; i < start + 4; i++)
header[i] = hash[31 - i + start]; header[i] = hash[31 - i + start];
} else { } else {
byte[] hash = doubleDigest(payload); byte[] hash = doubleDigest(payload);
System.arraycopy(hash, 0, header, 4 + COMMAND_LEN + 4, 4); System.arraycopy(hash, 0, header, 4 + COMMAND_LEN + 4, 4);
} }
} else { } else {
assert Arrays.equals(checksum, Arrays.copyOf(doubleDigest(payload), 4)) assert Arrays.equals(checksum, Arrays.copyOf(doubleDigest(payload), 4))
: "Checksum match failure on serialization. Cached: " + Arrays.toString(checksum) : "Checksum match failure on serialization. Cached: " + Arrays.toString(checksum)
+ " Calculated: " + Arrays.toString(Arrays.copyOf(doubleDigest(payload), 4)); + " Calculated: " + Arrays.toString(Arrays.copyOf(doubleDigest(payload), 4));
System.arraycopy(checksum, 0, header, 4 + COMMAND_LEN + 4, 4); System.arraycopy(checksum, 0, header, 4 + COMMAND_LEN + 4, 4);
} }
} }
@ -252,11 +252,11 @@ public class BitcoinSerializer {
// Check for duplicates. This is to avoid the cost (cpu and memory) of parsing the message twice, which can // Check for duplicates. This is to avoid the cost (cpu and memory) of parsing the message twice, which can
// be an issue on constrained devices. // be an issue on constrained devices.
//save this for reuse later. Hashing is expensive so checksumming starting with a single hash //save this for reuse later. Hashing is expensive so checksumming starting with a single hash
//is a significant saving. //is a significant saving.
Sha256Hash singleHash = null; Sha256Hash singleHash = null;
if (dedupeList != null && canDedupeMessageType(header.command)) { if (dedupeList != null && canDedupeMessageType(header.command)) {
// We use a secure hash here rather than the faster and simpler array hashes because otherwise a malicious // We use a secure hash here rather than the faster and simpler array hashes because otherwise a malicious
// node on the network could broadcast a message designed to mask a different message. They would not // node on the network could broadcast a message designed to mask a different message. They would not
@ -264,7 +264,7 @@ public class BitcoinSerializer {
synchronized (dedupeList) { synchronized (dedupeList) {
// Calculate hash inside the lock to avoid unnecessary battery power spent on hashing messages arriving // Calculate hash inside the lock to avoid unnecessary battery power spent on hashing messages arriving
// on different threads simultaneously. // on different threads simultaneously.
singleHash = Sha256Hash.create(payloadBytes); singleHash = Sha256Hash.create(payloadBytes);
Integer count = dedupeList.get(singleHash); Integer count = dedupeList.get(singleHash);
if (count != null) { if (count != null) {
int newCount = count + 1; int newCount = count + 1;
@ -280,11 +280,11 @@ public class BitcoinSerializer {
// Verify the checksum. // Verify the checksum.
byte[] hash = null; byte[] hash = null;
if (usesChecksumming) { if (usesChecksumming) {
if (singleHash != null) { if (singleHash != null) {
hash = singleDigest(singleHash.getBytes(), 0, 32); hash = singleDigest(singleHash.getBytes(), 0, 32);
} else { } else {
hash = doubleDigest(payloadBytes); hash = doubleDigest(payloadBytes);
} }
if (header.checksum[0] != hash[0] || header.checksum[1] != hash[1] || if (header.checksum[0] != hash[0] || header.checksum[1] != hash[1] ||
header.checksum[2] != hash[2] || header.checksum[3] != hash[3]) { header.checksum[2] != hash[2] || header.checksum[3] != hash[3]) {
throw new ProtocolException("Checksum failed to verify, actual " + throw new ProtocolException("Checksum failed to verify, actual " +
@ -311,21 +311,21 @@ public class BitcoinSerializer {
private Message makeMessage(String command, int length, byte[] payloadBytes, byte[] hash, byte[] checksum) throws ProtocolException { private Message makeMessage(String command, int length, byte[] payloadBytes, byte[] hash, byte[] checksum) throws ProtocolException {
// We use an if ladder rather than reflection because reflection is very slow on Android. // We use an if ladder rather than reflection because reflection is very slow on Android.
Message message; Message message;
if (command.equals("version")) { if (command.equals("version")) {
return new VersionMessage(params, payloadBytes); return new VersionMessage(params, payloadBytes);
} else if (command.equals("inv")) { } else if (command.equals("inv")) {
message = new InventoryMessage(params, payloadBytes, parseLazy, parseRetain, length); message = new InventoryMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("block")) { } else if (command.equals("block")) {
message = new Block(params, payloadBytes, parseLazy, parseRetain, length); message = new Block(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("getdata")) { } else if (command.equals("getdata")) {
message = new GetDataMessage(params, payloadBytes, parseLazy, parseRetain, length); message = new GetDataMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("tx")) { } else if (command.equals("tx")) {
Transaction tx = new Transaction(params, payloadBytes, null, parseLazy, parseRetain, length); Transaction tx = new Transaction(params, payloadBytes, null, parseLazy, parseRetain, length);
if (hash != null) if (hash != null)
tx.setHash(new Sha256Hash(Utils.reverseBytes(hash))); tx.setHash(new Sha256Hash(Utils.reverseBytes(hash)));
message = tx; message = tx;
} else if (command.equals("addr")) { } else if (command.equals("addr")) {
message = new AddressMessage(params, payloadBytes, parseLazy, parseRetain, length); message = new AddressMessage(params, payloadBytes, parseLazy, parseRetain, length);
} else if (command.equals("ping")) { } else if (command.equals("ping")) {
return new Ping(); return new Ping();
} else if (command.equals("verack")) { } else if (command.equals("verack")) {
@ -333,9 +333,9 @@ public class BitcoinSerializer {
} else { } else {
throw new ProtocolException("No support for deserializing message with name " + command); throw new ProtocolException("No support for deserializing message with name " + command);
} }
if (checksum != null) if (checksum != null)
message.setChecksum(checksum); message.setChecksum(checksum);
return message; return message;
} }
public void seekPastMagicBytes(InputStream in) throws IOException { public void seekPastMagicBytes(InputStream in) throws IOException {
@ -348,7 +348,7 @@ public class BitcoinSerializer {
} }
// We're looking for a run of bytes that is the same as the packet magic but we want to ignore partial // We're looking for a run of bytes that is the same as the packet magic but we want to ignore partial
// magics that aren't complete. So we keep track of where we're up to with magicCursor. // magics that aren't complete. So we keep track of where we're up to with magicCursor.
int expectedByte = 0xFF & (int)(params.packetMagic >>> (magicCursor * 8)); int expectedByte = 0xFF & (int) (params.packetMagic >>> (magicCursor * 8));
if (b == expectedByte) { if (b == expectedByte) {
magicCursor--; magicCursor--;
if (magicCursor < 0) { if (magicCursor < 0) {
@ -362,24 +362,23 @@ public class BitcoinSerializer {
} }
} }
} }
/** /**
* Whether the serializer will produce lazy parse mode Messages * Whether the serializer will produce lazy parse mode Messages
*/ */
public boolean isParseLazyMode() { public boolean isParseLazyMode() {
return parseLazy; return parseLazy;
} }
/** /**
* Whether the serializer will produce cached mode Messages * Whether the serializer will produce cached mode Messages
*/ */
public boolean isParseRetainMode() { public boolean isParseRetainMode() {
return parseRetain; return parseRetain;
} }
public class BitcoinPacketHeader {
public class BitcoinPacketHeader {
final byte[] header; final byte[] header;
final String command; final String command;
final int size; final int size;
@ -402,7 +401,7 @@ public class BitcoinSerializer {
// The command is a NULL terminated string, unless the command fills all twelve bytes // The command is a NULL terminated string, unless the command fills all twelve bytes
// in which case the termination is implicit. // in which case the termination is implicit.
int mark = cursor; int mark = cursor;
for (; header[cursor] != 0 && cursor - mark < COMMAND_LEN; cursor++); for (; header[cursor] != 0 && cursor - mark < COMMAND_LEN; cursor++) ;
byte[] commandBytes = new byte[cursor - mark]; byte[] commandBytes = new byte[cursor - mark];
System.arraycopy(header, mark, commandBytes, 0, cursor - mark); System.arraycopy(header, mark, commandBytes, 0, cursor - mark);
try { try {

File diff suppressed because it is too large Load Diff

View File

@ -16,14 +16,14 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import java.math.BigInteger;
import java.util.*;
import com.google.bitcoin.store.BlockStore; import com.google.bitcoin.store.BlockStore;
import com.google.bitcoin.store.BlockStoreException; import com.google.bitcoin.store.BlockStoreException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.util.*;
/** /**
* A BlockChain holds a series of {@link Block} objects, links them together, and knows how to verify that the * A BlockChain holds a series of {@link Block} objects, links them together, and knows how to verify that the
* chain follows the rules of the {@link NetworkParameters} for this chain.<p> * chain follows the rules of the {@link NetworkParameters} for this chain.<p>
@ -74,7 +74,7 @@ public class BlockChain {
/** /**
* Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you can construct * Constructs a BlockChain connected to the given wallet and store. To obtain a {@link Wallet} you can construct
* one from scratch, or you can deserialize a saved wallet from disk using {@link Wallet#loadFromFile(java.io.File)} * one from scratch, or you can deserialize a saved wallet from disk using {@link Wallet#loadFromFile(java.io.File)}
* <p> * <p/>
* *
* For the store you can use a {@link com.google.bitcoin.store.MemoryBlockStore} if you don't care about saving the downloaded data, or a * For the store you can use a {@link com.google.bitcoin.store.MemoryBlockStore} if you don't care about saving the downloaded data, or a
* {@link com.google.bitcoin.store.BoundedOverheadBlockStore} if you'd like to ensure fast startup the next time you run the program. * {@link com.google.bitcoin.store.BoundedOverheadBlockStore} if you'd like to ensure fast startup the next time you run the program.
@ -92,9 +92,9 @@ public class BlockChain {
public BlockChain(NetworkParameters params, BlockStore blockStore) throws BlockStoreException { public BlockChain(NetworkParameters params, BlockStore blockStore) throws BlockStoreException {
this(params, new ArrayList<Wallet>(), blockStore); this(params, new ArrayList<Wallet>(), blockStore);
} }
/** /**
* Constructs a BlockChain connected to the given list of wallets and a store. * Constructs a BlockChain connected to the given list of wallets and a store.
*/ */
public BlockChain(NetworkParameters params, List<Wallet> wallets, public BlockChain(NetworkParameters params, List<Wallet> wallets,
BlockStore blockStore) throws BlockStoreException { BlockStore blockStore) throws BlockStoreException {
@ -107,7 +107,7 @@ public class BlockChain {
/** /**
* Add a wallet to the BlockChain. Note that the wallet will be unaffected by any blocks received while it * Add a wallet to the BlockChain. Note that the wallet will be unaffected by any blocks received while it
* was not part of this BlockChain. This method is useful if the wallet has just been created, and its keys * was not part of this BlockChain. This method is useful if the wallet has just been created, and its keys
* have never been in use, or if the wallet has been loaded along with the BlockChain * have never been in use, or if the wallet has been loaded along with the BlockChain
*/ */
public synchronized void addWallet(Wallet wallet) { public synchronized void addWallet(Wallet wallet) {
@ -150,7 +150,7 @@ public class BlockChain {
// blocks validity so we can skip the merkle root verification if the contents aren't interesting. This saves // blocks validity so we can skip the merkle root verification if the contents aren't interesting. This saves
// a lot of time for big blocks. // a lot of time for big blocks.
boolean contentsImportant = false; boolean contentsImportant = false;
HashMap<Wallet, List<Transaction>> walletToTxMap = new HashMap<Wallet, List<Transaction>>();; HashMap<Wallet, List<Transaction>> walletToTxMap = new HashMap<Wallet, List<Transaction>>();
if (block.transactions != null) { if (block.transactions != null) {
scanTransactions(block, walletToTxMap); scanTransactions(block, walletToTxMap);
contentsImportant = walletToTxMap.size() > 0; contentsImportant = walletToTxMap.size() > 0;
@ -220,7 +220,7 @@ public class BlockChain {
String splitPointHash = String splitPointHash =
splitPoint != null ? splitPoint.getHeader().getHashAsString() : "?"; splitPoint != null ? splitPoint.getHeader().getHashAsString() : "?";
log.info("Block forks the chain at {}, but it did not cause a reorganize:\n{}", log.info("Block forks the chain at {}, but it did not cause a reorganize:\n{}",
splitPointHash, newStoredBlock); splitPointHash, newStoredBlock);
} }
// We may not have any transactions if we received only a header. That never happens today but will in // We may not have any transactions if we received only a header. That never happens today but will in

View File

@ -3,66 +3,65 @@ package com.google.bitcoin.core;
/** /**
* Represents a Message type that can be contained within another Message. ChildMessages that have a cached * Represents a Message type that can be contained within another Message. ChildMessages that have a cached
* backing byte array need to invalidate their parent's caches as well as their own if they are modified. * backing byte array need to invalidate their parent's caches as well as their own if they are modified.
*
* @author git
* *
* @author git
*/ */
public abstract class ChildMessage extends Message { public abstract class ChildMessage extends Message {
private Message parent; private Message parent;
protected ChildMessage() {
}
public ChildMessage(NetworkParameters params) { protected ChildMessage() {
super(params); }
}
public ChildMessage(NetworkParameters params, byte[] msg, int offset, int protocolVersion) throws ProtocolException { public ChildMessage(NetworkParameters params) {
super(params, msg, offset, protocolVersion); super(params);
} }
public ChildMessage(NetworkParameters params, byte[] msg, int offset, int protocolVersion, Message parent, boolean parseLazy, public ChildMessage(NetworkParameters params, byte[] msg, int offset, int protocolVersion) throws ProtocolException {
boolean parseRetain, int length) throws ProtocolException { super(params, msg, offset, protocolVersion);
super(params, msg, offset, protocolVersion, parseLazy, parseRetain, length); }
this.parent = parent;
}
public ChildMessage(NetworkParameters params, byte[] msg, int offset) throws ProtocolException { public ChildMessage(NetworkParameters params, byte[] msg, int offset, int protocolVersion, Message parent, boolean parseLazy,
super(params, msg, offset); boolean parseRetain, int length) throws ProtocolException {
} super(params, msg, offset, protocolVersion, parseLazy, parseRetain, length);
this.parent = parent;
}
public ChildMessage(NetworkParameters params, byte[] msg, int offset, Message parent, boolean parseLazy, boolean parseRetain, int length) public ChildMessage(NetworkParameters params, byte[] msg, int offset) throws ProtocolException {
throws ProtocolException { super(params, msg, offset);
super(params, msg, offset, parseLazy, parseRetain, length); }
this.parent = parent;
} public ChildMessage(NetworkParameters params, byte[] msg, int offset, Message parent, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, msg, offset, parseLazy, parseRetain, length);
this.parent = parent;
}
public void setParent(Message parent) {
if (this.parent != null && this.parent != parent && parent != null) {
//after old parent is unlinked it won't be able to receive notice if this ChildMessage
//changes internally. To be safe we invalidate the parent cache to ensure it rebuilds
//manually on serialization.
this.parent.unCache();
}
this.parent = parent;
}
/* (non-Javadoc)
* @see com.google.bitcoin.core.Message#unCache()
*/
@Override
protected void unCache() {
super.unCache();
if (parent != null)
parent.unCache();
}
public void setParent(Message parent) {
if (this.parent != null && this.parent != parent && parent !=null) {
//after old parent is unlinked it won't be able to receive notice if this ChildMessage
//changes internally. To be safe we invalidate the parent cache to ensure it rebuilds
//manually on serialization.
this.parent.unCache();
}
this.parent = parent;
}
/* (non-Javadoc)
* @see com.google.bitcoin.core.Message#unCache()
*/
@Override
protected void unCache() {
super.unCache();
if (parent != null)
parent.unCache();
}
protected void adjustLength(int adjustment) { protected void adjustLength(int adjustment) {
if (length != UNKNOWN_LENGTH) if (length != UNKNOWN_LENGTH)
length += adjustment; length += adjustment;
if (parent != null) if (parent != null)
parent.adjustLength(adjustment); parent.adjustLength(adjustment);
} }
} }

View File

@ -16,59 +16,54 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import com.google.bitcoin.core.AbstractPeerEventListener;
import com.google.bitcoin.core.Block;
import com.google.bitcoin.core.Peer;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.Date; import java.util.Date;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
/** /**
* Listen to chain download events and print useful informational messages. * Listen to chain download events and print useful informational messages.
*
* <p>progress, startDownload, doneDownload maybe be overridden to change the way the user
* is notified.
*
* <p>Methods are called with the event listener object locked so your
* implementation does not have to be thread safe.
*
* @author miron@google.com (Miron Cuperman a.k.a. devrandom)
* *
* <p>progress, startDownload, doneDownload maybe be overridden to change the way the user
* is notified.
*
* <p>Methods are called with the event listener object locked so your
* implementation does not have to be thread safe.
*
* @author miron@google.com (Miron Cuperman a.k.a. devrandom)
*/ */
public class DownloadListener extends AbstractPeerEventListener { public class DownloadListener extends AbstractPeerEventListener {
private int originalBlocksLeft = -1; private int originalBlocksLeft = -1;
private int lastPercent = 0; private int lastPercent = 0;
Semaphore done = new Semaphore(0); Semaphore done = new Semaphore(0);
@Override @Override
public void onChainDownloadStarted(Peer peer, int blocksLeft) { public void onChainDownloadStarted(Peer peer, int blocksLeft) {
startDownload(blocksLeft); startDownload(blocksLeft);
originalBlocksLeft = blocksLeft; originalBlocksLeft = blocksLeft;
} }
@Override @Override
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) { public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft) {
if (blocksLeft == 0) { if (blocksLeft == 0) {
doneDownload(); doneDownload();
done.release(); done.release();
} }
if (blocksLeft < 0 || originalBlocksLeft <= 0) if (blocksLeft < 0 || originalBlocksLeft <= 0)
return; return;
double pct = 100.0 - (100.0 * (blocksLeft / (double) originalBlocksLeft)); double pct = 100.0 - (100.0 * (blocksLeft / (double) originalBlocksLeft));
if ((int)pct != lastPercent) { if ((int) pct != lastPercent) {
progress(pct, new Date(block.getTimeSeconds() * 1000)); progress(pct, new Date(block.getTimeSeconds() * 1000));
lastPercent = (int)pct; lastPercent = (int) pct;
} }
} }
/** /**
* Called when download progress is made. * Called when download progress is made.
* *
* @param pct the percentage of chain downloaded, estimated * @param pct the percentage of chain downloaded, estimated
* @param date the date of the last block downloaded * @param date the date of the last block downloaded
*/ */
protected void progress(double pct, Date date) { protected void progress(double pct, Date date) {
System.out.println(String.format("Chain download %d%% done, block date %s", (int) pct, System.out.println(String.format("Chain download %d%% done, block date %s", (int) pct,
@ -77,7 +72,7 @@ public class DownloadListener extends AbstractPeerEventListener {
/** /**
* Called when download is initiated. * Called when download is initiated.
* *
* @param blocks the number of blocks to download, estimated * @param blocks the number of blocks to download, estimated
*/ */
protected void startDownload(int blocks) { protected void startDownload(int blocks) {
@ -93,7 +88,7 @@ public class DownloadListener extends AbstractPeerEventListener {
} }
/** /**
* Wait for the chain to be downloaded. * Wait for the chain to be downloaded.
*/ */
public void await() throws InterruptedException { public void await() throws InterruptedException {
done.acquire(); done.acquire();

View File

@ -34,7 +34,7 @@ public class DumpedPrivateKey extends VersionedChecksummedBytes {
/** /**
* Parses the given private key as created by the "dumpprivkey" Bitcoin C++ RPC. * Parses the given private key as created by the "dumpprivkey" Bitcoin C++ RPC.
* *
* @param params The expected network parameters of the key. If you don't care, provide null. * @param params The expected network parameters of the key. If you don't care, provide null.
* @param encoded The base58 encoded string. * @param encoded The base58 encoded string.
* @throws AddressFormatException If the string is invalid or the header byte doesn't match the network params. * @throws AddressFormatException If the string is invalid or the header byte doesn't match the network params.
*/ */
@ -42,7 +42,7 @@ public class DumpedPrivateKey extends VersionedChecksummedBytes {
super(encoded); super(encoded);
if (params != null && version != params.dumpedPrivateKeyHeader) if (params != null && version != params.dumpedPrivateKeyHeader)
throw new AddressFormatException("Mismatched version number, trying to cross networks? " + version + throw new AddressFormatException("Mismatched version number, trying to cross networks? " + version +
" vs " + params.dumpedPrivateKeyHeader); " vs " + params.dumpedPrivateKeyHeader);
} }
/** /**

View File

@ -16,20 +16,7 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import java.io.ByteArrayOutputStream; import org.bouncycastle.asn1.*;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OutputStream;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSequenceGenerator;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.sec.SECNamedCurves; import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
@ -40,6 +27,12 @@ import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters; import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.signers.ECDSASigner; import org.bouncycastle.crypto.signers.ECDSASigner;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.math.BigInteger;
import java.security.SecureRandom;
/** /**
* Represents an elliptic curve keypair that we own and can use for signing transactions. Currently, * Represents an elliptic curve keypair that we own and can use for signing transactions. Currently,
* Bouncy Castle is used. In future this may become an interface with multiple implementations using different crypto * Bouncy Castle is used. In future this may become an interface with multiple implementations using different crypto
@ -54,13 +47,13 @@ public class ECKey implements Serializable {
static { static {
// All clients must agree on the curve to use by agreement. BitCoin uses secp256k1. // All clients must agree on the curve to use by agreement. BitCoin uses secp256k1.
X9ECParameters params = SECNamedCurves.getByName("secp256k1"); X9ECParameters params = SECNamedCurves.getByName("secp256k1");
ecParams = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH()); ecParams = new ECDomainParameters(params.getCurve(), params.getG(), params.getN(), params.getH());
secureRandom = new SecureRandom(); secureRandom = new SecureRandom();
} }
private final BigInteger priv; private final BigInteger priv;
private final byte[] pub; private final byte[] pub;
transient private byte[] pubKeyHash; transient private byte[] pubKeyHash;
/** Generates an entirely new keypair. */ /** Generates an entirely new keypair. */
@ -88,28 +81,28 @@ public class ECKey implements Serializable {
* Output this ECKey as an ASN.1 encoded private key, as understood by OpenSSL or used by the BitCoin reference * Output this ECKey as an ASN.1 encoded private key, as understood by OpenSSL or used by the BitCoin reference
* implementation in its wallet storage format. * implementation in its wallet storage format.
*/ */
public byte[] toASN1(){ public byte[] toASN1() {
try { try {
ByteArrayOutputStream baos = new ByteArrayOutputStream(400); ByteArrayOutputStream baos = new ByteArrayOutputStream(400);
ASN1OutputStream encoder = new ASN1OutputStream(baos); ASN1OutputStream encoder = new ASN1OutputStream(baos);
// ASN1_SEQUENCE(EC_PRIVATEKEY) = { // ASN1_SEQUENCE(EC_PRIVATEKEY) = {
// ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG), // ASN1_SIMPLE(EC_PRIVATEKEY, version, LONG),
// ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING), // ASN1_SIMPLE(EC_PRIVATEKEY, privateKey, ASN1_OCTET_STRING),
// ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0), // ASN1_EXP_OPT(EC_PRIVATEKEY, parameters, ECPKPARAMETERS, 0),
// ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1) // ASN1_EXP_OPT(EC_PRIVATEKEY, publicKey, ASN1_BIT_STRING, 1)
// } ASN1_SEQUENCE_END(EC_PRIVATEKEY) // } ASN1_SEQUENCE_END(EC_PRIVATEKEY)
DERSequenceGenerator seq = new DERSequenceGenerator(encoder); DERSequenceGenerator seq = new DERSequenceGenerator(encoder);
seq.addObject(new DERInteger(1)); // version seq.addObject(new DERInteger(1)); // version
seq.addObject(new DEROctetString(priv.toByteArray())); seq.addObject(new DEROctetString(priv.toByteArray()));
seq.addObject(new DERTaggedObject(0, SECNamedCurves.getByName("secp256k1").getDERObject())); seq.addObject(new DERTaggedObject(0, SECNamedCurves.getByName("secp256k1").getDERObject()));
seq.addObject(new DERTaggedObject(1, new DERBitString(getPubKey()))); seq.addObject(new DERTaggedObject(1, new DERBitString(getPubKey())));
seq.close(); seq.close();
encoder.close(); encoder.close();
return baos.toByteArray(); return baos.toByteArray();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); // Cannot happen, writing to memory stream. throw new RuntimeException(e); // Cannot happen, writing to memory stream.
} }
} }
/** /**
@ -170,7 +163,7 @@ public class ECKey implements Serializable {
// of the type used by BitCoin we have to encode them using DER encoding, which is just a way to pack the two // of the type used by BitCoin we have to encode them using DER encoding, which is just a way to pack the two
// components into a structure. // components into a structure.
try { try {
//usually 70-72 bytes. //usually 70-72 bytes.
ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(72); ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(72);
DERSequenceGenerator seq = new DERSequenceGenerator(bos); DERSequenceGenerator seq = new DERSequenceGenerator(bos);
seq.addObject(new DERInteger(sigs[0])); seq.addObject(new DERInteger(sigs[0]));
@ -184,9 +177,10 @@ public class ECKey implements Serializable {
/** /**
* Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key. * Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key.
* @param data Hash of the data to verify. *
* @param data Hash of the data to verify.
* @param signature ASN.1 encoded signature. * @param signature ASN.1 encoded signature.
* @param pub The public key bytes to use. * @param pub The public key bytes to use.
*/ */
public static boolean verify(byte[] data, byte[] signature, byte[] pub) { public static boolean verify(byte[] data, byte[] signature, byte[] pub) {
ECDSASigner signer = new ECDSASigner(); ECDSASigner signer = new ECDSASigner();
@ -206,7 +200,8 @@ public class ECKey implements Serializable {
/** /**
* Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key. * Verifies the given ASN.1 encoded ECDSA signature against a hash using the public key.
* @param data Hash of the data to verify. *
* @param data Hash of the data to verify.
* @param signature ASN.1 encoded signature. * @param signature ASN.1 encoded signature.
*/ */
public boolean verify(byte[] data, byte[] signature) { public boolean verify(byte[] data, byte[] signature) {
@ -238,7 +233,9 @@ public class ECKey implements Serializable {
} }
} }
/** Returns a 32 byte array containing the private key. */ /**
* Returns a 32 byte array containing the private key.
*/
public byte[] getPrivKeyBytes() { public byte[] getPrivKeyBytes() {
// Getting the bytes out of a BigInteger gives us an extra zero byte on the end (for signedness) // Getting the bytes out of a BigInteger gives us an extra zero byte on the end (for signedness)
// or less than 32 bytes (leading zeros). Coerce to 32 bytes in all cases. // or less than 32 bytes (leading zeros). Coerce to 32 bytes in all cases.

View File

@ -6,65 +6,64 @@ import java.io.OutputStream;
/** /**
* Parent class for header only messages that don't have a payload. * Parent class for header only messages that don't have a payload.
* Currently this includes getaddr, ping, verack as well as the special bitcoinj class UnknownMessage * Currently this includes getaddr, ping, verack as well as the special bitcoinj class UnknownMessage
* @author git
* *
* @author git
*/ */
public abstract class EmptyMessage extends Message { public abstract class EmptyMessage extends Message {
public EmptyMessage() { public EmptyMessage() {
length = 0; length = 0;
} }
public EmptyMessage(NetworkParameters params) { public EmptyMessage(NetworkParameters params) {
super(params); super(params);
length = 0; length = 0;
} }
public EmptyMessage(NetworkParameters params, byte[] msg, int offset) throws ProtocolException { public EmptyMessage(NetworkParameters params, byte[] msg, int offset) throws ProtocolException {
super(params, msg, offset); super(params, msg, offset);
length = 0; length = 0;
} }
@Override @Override
final protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { final protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
} }
@Override @Override
int getMessageSize() { int getMessageSize() {
return 0; return 0;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see com.google.bitcoin.core.Message#parse() * @see com.google.bitcoin.core.Message#parse()
*/ */
@Override @Override
void parse() throws ProtocolException { void parse() throws ProtocolException {
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see com.google.bitcoin.core.Message#parseLite() * @see com.google.bitcoin.core.Message#parseLite()
*/ */
@Override @Override
protected void parseLite() throws ProtocolException { protected void parseLite() throws ProtocolException {
length = 0; length = 0;
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see com.google.bitcoin.core.Message#ensureParsed() * @see com.google.bitcoin.core.Message#ensureParsed()
*/ */
@Override @Override
public void ensureParsed() throws ProtocolException { public void ensureParsed() throws ProtocolException {
parsed = true; parsed = true;
} }
/* (non-Javadoc)
* @see com.google.bitcoin.core.Message#bitcoinSerialize()
*/
@Override
public byte[] bitcoinSerialize() {
return new byte[0];
}
/* (non-Javadoc)
* @see com.google.bitcoin.core.Message#bitcoinSerialize()
*/
@Override
public byte[] bitcoinSerialize() {
return new byte[0];
}
} }

View File

@ -17,14 +17,14 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
public class GetAddrMessage extends EmptyMessage { public class GetAddrMessage extends EmptyMessage {
public GetAddrMessage(NetworkParameters params) {
super(params);
}
@Override public GetAddrMessage(NetworkParameters params) {
void parse() throws ProtocolException { super(params);
// TODO: Implement this. }
}
@Override
void parse() throws ProtocolException {
// TODO: Implement this.
}
} }

View File

@ -33,27 +33,28 @@ public class GetBlocksMessage extends Message {
this.locator = locator; this.locator = locator;
this.stopHash = stopHash; this.stopHash = stopHash;
} }
protected void parseLite() throws ProtocolException { protected void parseLite() throws ProtocolException {
//NOP. This is a root level message and should always be provided with a length. //NOP. This is a root level message and should always be provided with a length.
} }
public void parse() throws ProtocolException { public void parse() throws ProtocolException {
cursor = offset; cursor = offset;
version = readUint32(); version = readUint32();
int startCount = (int) readVarInt(); int startCount = (int) readVarInt();
if (startCount > 500) if (startCount > 500)
throw new ProtocolException("Number of locators cannot be > 500, received: " + startCount);locator = new ArrayList(startCount); throw new ProtocolException("Number of locators cannot be > 500, received: " + startCount);
for (int i = 0; i < startCount; i++) { locator = new ArrayList(startCount);
locator.add(readHash()); for (int i = 0; i < startCount; i++) {
} locator.add(readHash());
stopHash = readHash(); }
stopHash = readHash();
} }
public List<Sha256Hash> getLocator() { public List<Sha256Hash> getLocator() {
return locator; return locator;
} }
public Sha256Hash getStopHash() { public Sha256Hash getStopHash() {
return stopHash; return stopHash;
} }
@ -69,18 +70,17 @@ public class GetBlocksMessage extends Message {
} }
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
// Version, for some reason. // Version, for some reason.
Utils.uint32ToByteStreamLE(NetworkParameters.PROTOCOL_VERSION, stream); Utils.uint32ToByteStreamLE(NetworkParameters.PROTOCOL_VERSION, stream);
// 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()
stream.write(new VarInt(locator.size()).encode()); stream.write(new VarInt(locator.size()).encode());
for (Sha256Hash hash : locator) { for (Sha256Hash hash : locator) {
// Have to reverse as wire format is little endian. // Have to reverse as wire format is little endian.
stream.write(Utils.reverseBytes(hash.getBytes())); stream.write(Utils.reverseBytes(hash.getBytes()));
} }
// Next, a block ID to stop at. // Next, a block ID to stop at.
stream.write(stopHash.getBytes()); stream.write(stopHash.getBytes());
} }
} }

View File

@ -22,13 +22,13 @@ public class GetDataMessage extends ListMessage {
public GetDataMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException { public GetDataMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes); super(params, payloadBytes);
} }
public GetDataMessage(NetworkParameters params, byte[] msg, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, msg, parseLazy, parseRetain, length);
}
public GetDataMessage(NetworkParameters params) { public GetDataMessage(NetworkParameters params, byte[] msg, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException {
super(params, msg, parseLazy, parseRetain, length);
}
public GetDataMessage(NetworkParameters params) {
super(params); super(params);
} }
} }

View File

@ -22,15 +22,15 @@ public class InventoryItem {
Transaction, Transaction,
Block Block
} }
public final Type type; public final Type type;
public final Sha256Hash hash; public final Sha256Hash hash;
public InventoryItem(Type type, Sha256Hash hash) { public InventoryItem(Type type, Sha256Hash hash) {
this.type = type; this.type = type;
this.hash = hash; this.hash = hash;
} }
public String toString() { public String toString() {
return type.toString() + ": " + hash; return type.toString() + ": " + hash;

View File

@ -24,11 +24,11 @@ public class InventoryMessage extends ListMessage {
} }
public InventoryMessage(NetworkParameters params, byte[] msg, boolean parseLazy, boolean parseRetain, int length) public InventoryMessage(NetworkParameters params, byte[] msg, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException { throws ProtocolException {
super(params, msg, parseLazy, parseRetain, length); super(params, msg, parseLazy, parseRetain, length);
} }
public InventoryMessage(NetworkParameters params) { public InventoryMessage(NetworkParameters params) {
super(params); super(params);
} }

View File

@ -25,10 +25,9 @@ import java.util.List;
/** /**
* Abstract superclass of classes with list based payload, i.e. InventoryMessage and GetDataMessage. * Abstract superclass of classes with list based payload, i.e. InventoryMessage and GetDataMessage.
*/ */
public abstract class ListMessage extends Message public abstract class ListMessage extends Message {
{
private long arrayLen; private long arrayLen;
// For some reason the compiler complains if this is inside InventoryItem // For some reason the compiler complains if this is inside InventoryItem
private List<InventoryItem> items; private List<InventoryItem> items;
private static final long MAX_INVENTORY_ITEMS = 50000; private static final long MAX_INVENTORY_ITEMS = 50000;
@ -38,55 +37,50 @@ public abstract class ListMessage extends Message
super(params, bytes, 0); super(params, bytes, 0);
} }
public ListMessage(NetworkParameters params, byte[] msg, boolean parseLazy, boolean parseRetain, int length) public ListMessage(NetworkParameters params, byte[] msg, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException { throws ProtocolException {
super(params, msg, 0, parseLazy, parseRetain, length); super(params, msg, 0, parseLazy, parseRetain, length);
} }
public ListMessage(NetworkParameters params) {
public ListMessage(NetworkParameters params) {
super(params); super(params);
items = new ArrayList<InventoryItem>(); items = new ArrayList<InventoryItem>();
length = 1; //length of 0 varint; length = 1; //length of 0 varint;
} }
public List<InventoryItem> getItems() public List<InventoryItem> getItems() {
{ checkParse();
checkParse(); return Collections.unmodifiableList(items);
return Collections.unmodifiableList(items);
} }
public void addItem(InventoryItem item) public void addItem(InventoryItem item) {
{
unCache(); unCache();
length -= VarInt.sizeOf(items.size()); length -= VarInt.sizeOf(items.size());
items.add(item); items.add(item);
length += VarInt.sizeOf(items.size()) + 36; length += VarInt.sizeOf(items.size()) + 36;
} }
public void removeItem(int index) public void removeItem(int index) {
{
unCache(); unCache();
length -= VarInt.sizeOf(items.size()); length -= VarInt.sizeOf(items.size());
items.remove(index); items.remove(index);
length += VarInt.sizeOf(items.size()) - 36; length += VarInt.sizeOf(items.size()) - 36;
} }
@Override @Override
protected void parseLite() throws ProtocolException { protected void parseLite() throws ProtocolException {
arrayLen = readVarInt(); arrayLen = readVarInt();
if (arrayLen > MAX_INVENTORY_ITEMS) if (arrayLen > MAX_INVENTORY_ITEMS)
throw new ProtocolException("Too many items in INV message: " + arrayLen); throw new ProtocolException("Too many items in INV message: " + arrayLen);
length = (int) (cursor - offset + (arrayLen * 36)); length = (int) (cursor - offset + (arrayLen * 36));
} }
@Override @Override
public void parse() throws ProtocolException { public void parse() throws ProtocolException {
// An inv is vector<CInv> where CInv is int+hash. The int is either 1 or 2 for tx or block. // An inv is vector<CInv> where CInv is int+hash. The int is either 1 or 2 for tx or block.
items = new ArrayList<InventoryItem>((int)arrayLen); items = new ArrayList<InventoryItem>((int) arrayLen);
for (int i = 0; i < arrayLen; i++) { for (int i = 0; i < arrayLen; i++) {
if (cursor + 4 + 32 > bytes.length) { if (cursor + 4 + 32 > bytes.length) {
throw new ProtocolException("Ran off the end of the INV"); throw new ProtocolException("Ran off the end of the INV");
@ -95,11 +89,17 @@ public abstract class ListMessage extends Message
InventoryItem.Type type; InventoryItem.Type type;
// See ppszTypeName in net.h // See ppszTypeName in net.h
switch (typeCode) { switch (typeCode) {
case 0: type = InventoryItem.Type.Error; break; case 0:
case 1: type = InventoryItem.Type.Transaction; break; type = InventoryItem.Type.Error;
case 2: type = InventoryItem.Type.Block; break; break;
default: case 1:
throw new ProtocolException("Unknown CInv type: " + typeCode); type = InventoryItem.Type.Transaction;
break;
case 2:
type = InventoryItem.Type.Block;
break;
default:
throw new ProtocolException("Unknown CInv type: " + typeCode);
} }
InventoryItem item = new InventoryItem(type, readHash()); InventoryItem item = new InventoryItem(type, readHash());
items.add(item); items.add(item);
@ -109,8 +109,7 @@ public abstract class ListMessage extends Message
@Override @Override
public void bitcoinSerializeToStream(OutputStream stream) throws IOException public void bitcoinSerializeToStream(OutputStream stream) throws IOException {
{
stream.write(new VarInt(items.size()).encode()); stream.write(new VarInt(items.size()).encode());
for (InventoryItem i : items) { for (InventoryItem i : items) {
// Write out the type code. // Write out the type code.

View File

@ -16,27 +16,27 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*; import java.io.*;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.Arrays; import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* A Message is a data structure that can be serialized/deserialized using both the BitCoin proprietary serialization * A Message is a data structure that can be serialized/deserialized using both the BitCoin proprietary serialization
* format and built-in Java object serialization. Specific types of messages that are used both in the block chain, * format and built-in Java object serialization. Specific types of messages that are used both in the block chain,
* and on the wire, are derived from this class. * and on the wire, are derived from this class.
* * <p/>
* This class is not useful for library users. If you want to talk to the network see the {@link Peer} class. * This class is not useful for library users. If you want to talk to the network see the {@link Peer} class.
*/ */
public abstract class Message implements Serializable { public abstract class Message implements Serializable {
private static final Logger log = LoggerFactory.getLogger(Message.class); private static final Logger log = LoggerFactory.getLogger(Message.class);
private static final long serialVersionUID = -3561053461717079135L; private static final long serialVersionUID = -3561053461717079135L;
public static final int MAX_SIZE = 0x02000000; public static final int MAX_SIZE = 0x02000000;
public static final int UNKNOWN_LENGTH = -1; public static final int UNKNOWN_LENGTH = -1;
// Useful to ensure serialize/deserialize are consistent with each other. // Useful to ensure serialize/deserialize are consistent with each other.
private static final boolean SELF_CHECK = false; private static final boolean SELF_CHECK = false;
@ -46,67 +46,69 @@ public abstract class Message implements Serializable {
// The cursor keeps track of where we are in the byte array as we parse it. // The cursor keeps track of where we are in the byte array as we parse it.
// 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;
protected transient int length = UNKNOWN_LENGTH; protected transient int length = UNKNOWN_LENGTH;
// The raw message bytes themselves. // The raw message bytes themselves.
protected transient byte[] bytes; protected transient byte[] bytes;
protected transient boolean parsed = false; protected transient boolean parsed = false;
protected transient boolean recached = false; protected transient boolean recached = false;
protected transient final boolean parseLazy; protected transient final boolean parseLazy;
protected transient final boolean parseRetain; protected transient final boolean parseRetain;
protected transient int protocolVersion; protected transient int protocolVersion;
protected transient byte[] checksum; protected transient byte[] checksum;
// This will be saved by subclasses that implement Serializable. // This will be saved by subclasses that implement Serializable.
protected NetworkParameters params; protected NetworkParameters params;
/** This exists for the Java serialization framework to use only. */ /**
* This exists for the Java serialization framework to use only.
*/
protected Message() { protected Message() {
parsed = true; parsed = true;
parseLazy = false; parseLazy = false;
parseRetain = false; parseRetain = false;
} }
Message(NetworkParameters params) { Message(NetworkParameters params) {
this.params = params; this.params = params;
parsed = true; parsed = true;
parseLazy = false; parseLazy = false;
parseRetain = false; parseRetain = false;
} }
Message(NetworkParameters params, byte[] msg, int offset, int protocolVersion) throws ProtocolException { Message(NetworkParameters params, byte[] msg, int offset, int protocolVersion) throws ProtocolException {
this(params, msg, offset, protocolVersion, false, false, UNKNOWN_LENGTH); this(params, msg, offset, protocolVersion, false, false, UNKNOWN_LENGTH);
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
Message(NetworkParameters params, byte[] msg, int offset, int protocolVersion, final boolean parseLazy, final boolean parseRetain, int length) throws ProtocolException { Message(NetworkParameters params, byte[] msg, int offset, int protocolVersion, final boolean parseLazy, final boolean parseRetain, int length) throws ProtocolException {
this.parseLazy = parseLazy; this.parseLazy = parseLazy;
this.parseRetain = parseRetain; this.parseRetain = parseRetain;
this.protocolVersion = protocolVersion; 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;
this.length = length; this.length = length;
if (parseLazy) { if (parseLazy) {
parseLite(); parseLite();
} else { } else {
parseLite(); parseLite();
parse(); parse();
parsed = true; parsed = true;
} }
assert (parseLazy ? !parsed : parsed && (parseRetain ? bytes != null : bytes == null)) assert (parseLazy ? !parsed : parsed && (parseRetain ? bytes != null : bytes == null))
: "parseLazy : " + parseLazy + " parsed: " + parsed : "parseLazy : " + parseLazy + " parsed: " + parsed
+ " parseRetain:" + parseRetain + " parseRetain:" + parseRetain
+ " bytes == null" + bytes == null; + " bytes == null" + bytes == null;
if (SELF_CHECK && !this.getClass().getSimpleName().equals("VersionMessage")) { if (SELF_CHECK && !this.getClass().getSimpleName().equals("VersionMessage")) {
checkParse(); checkParse();
byte[] msgbytes = new byte[cursor - offset]; byte[] msgbytes = new byte[cursor - offset];
System.arraycopy(msg, offset, msgbytes, 0, cursor - offset); System.arraycopy(msg, offset, msgbytes, 0, cursor - offset);
byte[] reserialized = bitcoinSerialize(); byte[] reserialized = bitcoinSerialize();
if (!Arrays.equals(reserialized, msgbytes)) if (!Arrays.equals(reserialized, msgbytes))
@ -115,204 +117,207 @@ public abstract class Message implements Serializable {
Utils.bytesToHexString(msgbytes)); Utils.bytesToHexString(msgbytes));
} }
if (parseRetain || !parsed) if (parseRetain || !parsed)
return; return;
this.bytes = null; this.bytes = null;
} }
Message(NetworkParameters params, byte[] msg, int offset) throws ProtocolException { Message(NetworkParameters params, byte[] msg, int offset) throws ProtocolException {
this(params, msg, offset, NetworkParameters.PROTOCOL_VERSION, false, false, UNKNOWN_LENGTH); this(params, msg, offset, NetworkParameters.PROTOCOL_VERSION, false, false, UNKNOWN_LENGTH);
} }
Message(NetworkParameters params, byte[] msg, int offset, final boolean parseLazy, final boolean parseRetain, int length) throws ProtocolException { Message(NetworkParameters params, byte[] msg, int offset, final boolean parseLazy, final boolean parseRetain, int length) throws ProtocolException {
this(params, msg, offset, NetworkParameters.PROTOCOL_VERSION, parseLazy, parseRetain, length); this(params, msg, offset, NetworkParameters.PROTOCOL_VERSION, parseLazy, parseRetain, length);
} }
// 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
// are serialized to the wallet. // are serialized to the wallet.
abstract void parse() throws ProtocolException; abstract void parse() throws ProtocolException;
/** /**
* Perform the most minimal parse possible to calculate the length of the message. * Perform the most minimal parse possible to calculate the length of the message.
* This is only required for subclasses of ChildClass as root level messages will have their length passed * This is only required for subclasses of ChildClass as root level messages will have their length passed
* into the constructor. * into the constructor.
* * <p/>
* It is expected that the length field will be set before this method returns. * It is expected that the length field will be set before this method returns.
* @return *
* @throws ProtocolException * @return
* @throws ProtocolException
*/ */
protected abstract void parseLite() throws ProtocolException; protected abstract void parseLite() throws ProtocolException;
// { // {
// length = getMessageSize(); // length = getMessageSize();
// } // }
/** /**
* Ensure the object is parsed if needed. This should be called in every getter before returning a value. * Ensure the object is parsed if needed. This should be called in every getter before returning a value.
* If the lazy parse flag is not set this is a method returns immediately. * If the lazy parse flag is not set this is a method returns immediately.
*/ */
protected synchronized void checkParse() { protected synchronized void checkParse() {
if (parsed || bytes == null) if (parsed || bytes == null)
return; return;
try { try {
parse(); parse();
parsed = true; parsed = true;
if (!parseRetain) if (!parseRetain)
bytes = null; bytes = null;
} catch (ProtocolException e) { } catch (ProtocolException e) {
throw new LazyParseException("ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access", e); throw new LazyParseException("ProtocolException caught during lazy parse. For safe access to fields call ensureParsed before attempting read or write access", e);
} }
} }
/** /**
* In lazy parsing mode access to getters and setters may throw an unchecked LazyParseException. If guaranteed safe access is required * In lazy parsing mode access to getters and setters may throw an unchecked LazyParseException. If guaranteed safe access is required
* this method will force parsing to occur immediately thus ensuring LazyParseExeption will never be thrown from this Message. * this method will force parsing to occur immediately thus ensuring LazyParseExeption will never be thrown from this Message.
* If the Message contains child messages (e.g. a Block containing Transaction messages) this will not force child messages to parse. * If the Message contains child messages (e.g. a Block containing Transaction messages) this will not force child messages to parse.
* * <p/>
* This could be overidden for Transaction and it's child classes to ensure the entire tree of Message objects is parsed. * This could be overidden for Transaction and it's child classes to ensure the entire tree of Message objects is parsed.
* *
* @throws ProtocolException * @throws ProtocolException
*/ */
public void ensureParsed() throws ProtocolException { public void ensureParsed() throws ProtocolException {
try { try {
checkParse(); checkParse();
} catch (LazyParseException e) { } catch (LazyParseException e) {
if (e.getCause() instanceof ProtocolException) if (e.getCause() instanceof ProtocolException)
throw (ProtocolException) e.getCause(); throw (ProtocolException) e.getCause();
throw new ProtocolException(e); throw new ProtocolException(e);
} }
} }
/** /**
* To be called before any change of internal values including any setters. This ensures any cached byte array is removed after performing * To be called before any change of internal values including any setters. This ensures any cached byte array is removed after performing
* a lazy parse if necessary to ensure the object is fully populated. * a lazy parse if necessary to ensure the object is fully populated.
* * <p/>
* Child messages of this object(e.g. Transactions belonging to a Block) will not have their internal byte caches invalidated unless * Child messages of this object(e.g. Transactions belonging to a Block) will not have their internal byte caches invalidated unless
* they are also modified internally. * they are also modified internally.
*/ */
protected void unCache() { protected void unCache() {
/*
* This is a NOP at the moment. Will complete lazy parsing as a separate patch first.
* safe retention of backing byte array is tricky in cases where a parent Message object
* may have child message objects (e.g. block - tx). There has to be a way to either
* mark the cursor at the end of the parent portion of the array or a way the child can
* invalidate the parent array. This might require a ByteArrayView class which implements List
* and retains a reference to it's parent ByteArrayView so it can invalidate it.
* Alternately the child message can hold a reference to
* it's parent and propagate a call to unCache up the chain to the parent. This way only those children on the
* invalidated branch lose their caching. On the other hand this might introduce more overhead than it's worth
* since this call has to made in every setter.
* Perhaps a simpler approach where in the special cases where a cached array is wanted it is the callers responsibility
* to keep track of whether the cache is valid or not.
*/
checkParse(); /*
checksum = null; * This is a NOP at the moment. Will complete lazy parsing as a separate patch first.
bytes = null; * safe retention of backing byte array is tricky in cases where a parent Message object
recached = false; * may have child message objects (e.g. block - tx). There has to be a way to either
* mark the cursor at the end of the parent portion of the array or a way the child can
* invalidate the parent array. This might require a ByteArrayView class which implements List
* and retains a reference to it's parent ByteArrayView so it can invalidate it.
* Alternately the child message can hold a reference to
* it's parent and propagate a call to unCache up the chain to the parent. This way only those children on the
* invalidated branch lose their caching. On the other hand this might introduce more overhead than it's worth
* since this call has to made in every setter.
* Perhaps a simpler approach where in the special cases where a cached array is wanted it is the callers responsibility
* to keep track of whether the cache is valid or not.
*/
checkParse();
checksum = null;
bytes = null;
recached = false;
} }
protected void adjustLength(int adjustment) { protected void adjustLength(int adjustment) {
if (length != UNKNOWN_LENGTH) if (length != UNKNOWN_LENGTH)
//our own length is now unknown if we have an unknown length adjustment. //our own length is now unknown if we have an unknown length adjustment.
length = adjustment == UNKNOWN_LENGTH ? UNKNOWN_LENGTH : length + adjustment; length = adjustment == UNKNOWN_LENGTH ? UNKNOWN_LENGTH : length + adjustment;
} }
/** /**
* used for unit testing * used for unit testing
*/ */
public boolean isParsed() { public boolean isParsed() {
return parsed; return parsed;
} }
/** /**
* used for unit testing * used for unit testing
*/ */
public boolean isCached() { public boolean isCached() {
//return parseLazy ? parsed && bytes != null : bytes != null; //return parseLazy ? parsed && bytes != null : bytes != null;
return bytes != null; return bytes != null;
} }
public boolean isRecached() { public boolean isRecached() {
return recached; return recached;
} }
/** /**
* Should only used by BitcoinSerializer for cached checksum * Should only used by BitcoinSerializer for cached checksum
* @return the checksum *
*/ * @return the checksum
byte[] getChecksum() { */
return checksum; byte[] getChecksum() {
} return checksum;
}
/** /**
* Should only used by BitcoinSerializer for caching checksum * Should only used by BitcoinSerializer for caching checksum
* @param checksum the checksum to set *
*/ * @param checksum the checksum to set
void setChecksum(byte[] checksum) { */
if (checksum.length != 4) void setChecksum(byte[] checksum) {
throw new IllegalArgumentException("Checksum length must be 4 bytes, actual length: " + checksum.length); if (checksum.length != 4)
this.checksum = checksum; throw new IllegalArgumentException("Checksum length must be 4 bytes, actual length: " + checksum.length);
} this.checksum = checksum;
}
/** /**
* Serialize this message to a byte array that conforms to the bitcoin wire protocol. * Serialize this message to a byte array that conforms to the bitcoin wire protocol.
* <br/> * <br/>
* This method may return the original byte array used to construct this message if the * This method may return the original byte array used to construct this message if the
* following conditions are met: * following conditions are met:
* <ol> * <ol>
* <li>1) The message was parsed from a byte array with parseRetain = true</li> * <li>1) The message was parsed from a byte array with parseRetain = true</li>
* <li>2) The message has not been modified</li> * <li>2) The message has not been modified</li>
* <li>3) The array had an offset of 0 and no surplus bytes</li> * <li>3) The array had an offset of 0 and no surplus bytes</li>
* </ol> * </ol>
* *
* If condition 3 is not met then an copy of the relevant portion of the array will be returned. * If condition 3 is not met then an copy of the relevant portion of the array will be returned.
* Otherwise a full serialize will occur. * Otherwise a full serialize will occur.
* *
* @return * @return
*/ */
public byte[] bitcoinSerialize() { public byte[] bitcoinSerialize() {
//1st attempt to use a cached array //1st attempt to use a cached array
if (bytes != null) { if (bytes != null) {
if (offset == 0 && length == bytes.length) { if (offset == 0 && length == bytes.length) {
//cached byte array is the entire message with no extras //cached byte array is the entire message with no extras
//so we can return as is and avoid an array copy. //so we can return as is and avoid an array copy.
return bytes; return bytes;
} }
//int len = cursor - offset; //int len = cursor - offset;
byte[] buf = new byte[length]; byte[] buf = new byte[length];
System.arraycopy(bytes, offset, buf, 0, length); System.arraycopy(bytes, offset, buf, 0, length);
return buf; return buf;
} }
assert bytes == null : "cached bytes present but failed to use them for serialization"; assert bytes == null : "cached bytes present but failed to use them for serialization";
//no cached array available so serialize parts by stream. //no cached array available so serialize parts by stream.
ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(length < 32 ? 32 : length + 32); ByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(length < 32 ? 32 : length + 32);
try { try {
bitcoinSerializeToStream(stream); bitcoinSerializeToStream(stream);
} catch (IOException e) { } catch (IOException e) {
// Cannot happen, we are serializing to a memory stream. // Cannot happen, we are serializing to a memory stream.
} }
if (parseRetain) { if (parseRetain) {
//a free set of steak knives! //a free set of steak knives!
//If there happens to be a call to this method we gain an opportunity to recache //If there happens to be a call to this method we gain an opportunity to recache
//the byte array and in this case it contains no bytes from parent messages. //the byte array and in this case it contains no bytes from parent messages.
//This give a dual benefit. Releasing references to the larger byte array so that it //This give a dual benefit. Releasing references to the larger byte array so that it
//it is more likely to be GC'd. A preventing double serializations. E.g. calculating //it is more likely to be GC'd. A preventing double serializations. E.g. calculating
//merkle root calls this method. It is will frequently happen prior to serializing the block //merkle root calls this method. It is will frequently happen prior to serializing the block
//which means another call to bitcoinSerialize is coming. If we didn't recache then internal //which means another call to bitcoinSerialize is coming. If we didn't recache then internal
//serialization would occur a 2nd time and every subsequent time the message is serialized. //serialization would occur a 2nd time and every subsequent time the message is serialized.
bytes = stream.toByteArray(); bytes = stream.toByteArray();
cursor = cursor - offset; cursor = cursor - offset;
offset = 0; offset = 0;
recached = true; recached = true;
length = bytes.length; length = bytes.length;
return bytes; return bytes;
} }
//record length. If this Message wasn't parsed from a but stream it won't have length field //record length. If this Message wasn't parsed from a but stream it won't have length field
//set (except for static length message types). Setting it makes future streaming more efficient //set (except for static length message types). Setting it makes future streaming more efficient
@ -321,66 +326,69 @@ public abstract class Message implements Serializable {
length = buf.length; length = buf.length;
return buf; return buf;
} }
/** /**
* Serialize this message to the provided OutputStream using the bitcoin wire format. * Serialize this message to the provided OutputStream using the bitcoin wire format.
*
* @param stream * @param stream
* @throws IOException * @throws IOException
*/ */
final public void bitcoinSerialize(OutputStream stream) throws IOException { final public void bitcoinSerialize(OutputStream stream) throws IOException {
//1st check for cached bytes //1st check for cached bytes
if (bytes != null && length != UNKNOWN_LENGTH) { if (bytes != null && length != UNKNOWN_LENGTH) {
stream.write(bytes, offset, length); stream.write(bytes, offset, length);
return; return;
} }
bitcoinSerializeToStream(stream); bitcoinSerializeToStream(stream);
} }
/** /**
* Serializes this message to the provided stream. If you just want the raw bytes use bitcoinSerialize(). * Serializes this message to the provided stream. If you just want the raw bytes use bitcoinSerialize().
*/ */
void bitcoinSerializeToStream(OutputStream stream) throws IOException { void bitcoinSerializeToStream(OutputStream stream) throws IOException {
log.debug("Warning: {} class has not implemented bitcoinSerializeToStream method. Generating message with no payload", getClass()); log.debug("Warning: {} class has not implemented bitcoinSerializeToStream method. Generating message with no payload", getClass());
} }
/** /**
* This method is a NOP for all classes except Block and Transaction. It is only declared in Message * This method is a NOP for all classes except Block and Transaction. It is only declared in Message
* so BitcoinSerializer can avoid 2 instanceof checks + a casting. * so BitcoinSerializer can avoid 2 instanceof checks + a casting.
*
* @return * @return
*/ */
public Sha256Hash getHash() { public Sha256Hash getHash() {
return null; return null;
} }
/** /**
* This should be overridden to extract correct message size in the case of lazy parsing. Until this method is * This should be overridden to extract correct message size in the case of lazy parsing. Until this method is
* implemented in a subclass of ChildMessage lazy parsing may have no effect. * implemented in a subclass of ChildMessage lazy parsing may have no effect.
* *
* This default implementation is a safe fall back that will ensure it returns a correct value by parsing the message. * This default implementation is a safe fall back that will ensure it returns a correct value by parsing the message.
*
* @return * @return
*/ */
int getMessageSize() { int getMessageSize() {
if (length != UNKNOWN_LENGTH) if (length != UNKNOWN_LENGTH)
return length; return length;
checkParse(); checkParse();
if (length != UNKNOWN_LENGTH) if (length != UNKNOWN_LENGTH)
length = cursor - offset; length = cursor - offset;
return length; return length;
} }
long readUint32() { long readUint32() {
long u = Utils.readUint32(bytes, cursor); long u = Utils.readUint32(bytes, cursor);
cursor += 4; cursor += 4;
return u; return u;
} }
Sha256Hash readHash() { Sha256Hash readHash() {
byte[] hash = new byte[32]; byte[] hash = new byte[32];
System.arraycopy(bytes, cursor, hash, 0, 32); System.arraycopy(bytes, cursor, hash, 0, 32);
// We have to flip it around, as it's been read off the wire in little endian. // We have to flip it around, as it's been read off the wire in little endian.
// Not the most efficient way to do this but the clearest. // Not the most efficient way to do this but the clearest.
hash = Utils.reverseBytes(hash); hash = Utils.reverseBytes(hash);
cursor += 32; cursor += 32;
return new Sha256Hash(hash); return new Sha256Hash(hash);
} }
@ -394,15 +402,15 @@ public abstract class Message implements Serializable {
cursor += valbytes.length; cursor += valbytes.length;
return new BigInteger(valbytes); return new BigInteger(valbytes);
} }
long readVarInt() { long readVarInt() {
VarInt varint = new VarInt(bytes, cursor); VarInt varint = new VarInt(bytes, cursor);
cursor += varint.getSizeInBytes(); cursor += varint.getSizeInBytes();
return varint.value; return varint.value;
} }
long readVarInt(int offset) { long readVarInt(int offset) {
VarInt varint = new VarInt(bytes, cursor + offset); VarInt varint = new VarInt(bytes, cursor + offset);
cursor += offset + varint.getSizeInBytes(); cursor += offset + varint.getSizeInBytes();
return varint.value; return varint.value;
} }
@ -422,7 +430,7 @@ public abstract class Message implements Serializable {
return ""; return "";
} }
cursor += varInt.getSizeInBytes(); cursor += varInt.getSizeInBytes();
byte[] characters = new byte[(int)varInt.value]; byte[] characters = new byte[(int) varInt.value];
System.arraycopy(bytes, cursor, characters, 0, characters.length); System.arraycopy(bytes, cursor, characters, 0, characters.length);
cursor += characters.length; cursor += characters.length;
try { try {
@ -431,16 +439,16 @@ public abstract class Message implements Serializable {
throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported. throw new RuntimeException(e); // Cannot happen, UTF-8 is always supported.
} }
} }
public class LazyParseException extends RuntimeException { public class LazyParseException extends RuntimeException {
public LazyParseException(String message, Throwable cause) { public LazyParseException(String message, Throwable cause) {
super(message, cause); super(message, cause);
} }
public LazyParseException(String message) {
super(message);
}
public LazyParseException(String message) {
super(message);
}
} }
} }

View File

@ -27,7 +27,6 @@ import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.LinkedList;
/** /**
* A NetworkConnection handles talking to a remote BitCoin peer at a low level. It understands how to read and write * A NetworkConnection handles talking to a remote BitCoin peer at a low level. It understands how to read and write
@ -43,8 +42,8 @@ import java.util.LinkedList;
* Construction is blocking whilst the protocol version is negotiated. * Construction is blocking whilst the protocol version is negotiated.
*/ */
public class NetworkConnection { public class NetworkConnection {
private static final Logger log = LoggerFactory.getLogger(NetworkConnection.class); private static final Logger log = LoggerFactory.getLogger(NetworkConnection.class);
private final Socket socket; private final Socket socket;
private final OutputStream out; private final OutputStream out;
private final InputStream in; private final InputStream in;
@ -61,13 +60,13 @@ public class NetworkConnection {
* 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
* is complete a functioning network channel is set up and running. * is complete a functioning network channel is set up and running.
* *
* @param peerAddress address to connect to. IPv6 is not currently supported by BitCoin. If * @param peerAddress address to connect to. IPv6 is not currently supported by BitCoin. If
* port is not positive the default port from params is used. * port is not positive the default port from params is used.
* @param params Defines which network to connect to and details of the protocol. * @param params Defines which network to connect to and details of the protocol.
* @param bestHeight How many blocks are in our best chain * @param bestHeight How many blocks are in our best chain
* @param connectTimeout Timeout in milliseconds when initially connecting to peer * @param connectTimeout Timeout in milliseconds when initially connecting to peer
* @param dedupe Whether to avoid parsing duplicate messages from the network (ie from other peers). * @param dedupe Whether to avoid parsing duplicate messages from the network (ie from other peers).
* @throws IOException if there is a network related failure. * @throws IOException if there is a network related failure.
* @throws ProtocolException if the version negotiation failed. * @throws ProtocolException if the version negotiation failed.
*/ */
public NetworkConnection(PeerAddress peerAddress, NetworkParameters params, public NetworkConnection(PeerAddress peerAddress, NetworkParameters params,
@ -81,7 +80,7 @@ public class NetworkConnection {
InetSocketAddress address = new InetSocketAddress(remoteIp, port); InetSocketAddress address = new InetSocketAddress(remoteIp, port);
socket = new Socket(); socket = new Socket();
socket.connect(address, connectTimeout); socket.connect(address, connectTimeout);
out = socket.getOutputStream(); out = socket.getOutputStream();
in = socket.getInputStream(); in = socket.getInputStream();
@ -106,10 +105,10 @@ public class NetworkConnection {
readMessage(); readMessage();
// Switch to the new protocol version. // Switch to the new protocol version.
int peerVersion = versionMessage.clientVersion; int peerVersion = versionMessage.clientVersion;
log.info("Connected to peer: version={}, subVer='{}', services=0x{}, time={}, blocks={}", new Object[] { log.info("Connected to peer: version={}, subVer='{}', services=0x{}, time={}, blocks={}", new Object[]{
peerVersion, peerVersion,
versionMessage.subVer, versionMessage.subVer,
versionMessage.localServices, versionMessage.localServices,
new Date(versionMessage.time * 1000), new Date(versionMessage.time * 1000),
versionMessage.bestHeight versionMessage.bestHeight
}); });
@ -136,6 +135,7 @@ public class NetworkConnection {
/** /**
* Sends a "ping" message to the remote node. The protocol doesn't presently use this feature much. * Sends a "ping" message to the remote node. The protocol doesn't presently use this feature much.
*
* @throws IOException * @throws IOException
*/ */
public void ping() throws IOException { public void ping() throws IOException {
@ -187,7 +187,9 @@ public class NetworkConnection {
} }
} }
/** Returns the version message received from the other end of the connection during the handshake. */ /**
* Returns the version message received from the other end of the connection during the handshake.
*/
public VersionMessage getVersionMessage() { public VersionMessage getVersionMessage() {
return versionMessage; return versionMessage;
} }

View File

@ -77,11 +77,11 @@ public class NetworkParameters implements Serializable {
// //
// "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks" // "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"
byte[] bytes = Hex.decode byte[] bytes = Hex.decode
("04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73"); ("04ffff001d0104455468652054696d65732030332f4a616e2f32303039204368616e63656c6c6f72206f6e206272696e6b206f66207365636f6e64206261696c6f757420666f722062616e6b73");
t.addInput(new TransactionInput(n, t, bytes)); t.addInput(new TransactionInput(n, t, bytes));
ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream(); ByteArrayOutputStream scriptPubKeyBytes = new ByteArrayOutputStream();
Script.writeBytes(scriptPubKeyBytes, Hex.decode Script.writeBytes(scriptPubKeyBytes, Hex.decode
("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f")); ("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"));
scriptPubKeyBytes.write(Script.OP_CHECKSIG); scriptPubKeyBytes.write(Script.OP_CHECKSIG);
t.addOutput(new TransactionOutput(n, t, scriptPubKeyBytes.toByteArray())); t.addOutput(new TransactionOutput(n, t, scriptPubKeyBytes.toByteArray()));
} catch (Exception e) { } catch (Exception e) {

View File

@ -23,20 +23,16 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/** /**
* A Peer handles the high level communication with a BitCoin node. * A Peer handles the high level communication with a BitCoin node.
* *
* <p>After making the connection with connect(), call run() to start the message handling loop. * <p>After making the connection with connect(), call run() to start the message handling loop.
*/ */
public class Peer { public class Peer {
private static final Logger log = LoggerFactory.getLogger(Peer.class); private static final Logger log = LoggerFactory.getLogger(Peer.class);
private NetworkConnection conn; private NetworkConnection conn;
private final NetworkParameters params; private final NetworkParameters params;
// Whether the peer loop is supposed to be running or not. Set to false during shutdown so the peer loop // Whether the peer loop is supposed to be running or not. Set to false during shutdown so the peer loop
@ -63,7 +59,7 @@ public class Peer {
/** /**
* Construct a peer that handles the given network connection and reads/writes from the given block chain. Note that * Construct a peer that handles the given network connection and reads/writes from the given block chain. Note that
* communication won't occur until you call connect(). * communication won't occur until you call connect().
* *
* @param bestHeight our current best chain height, to facilitate downloading * @param bestHeight our current best chain height, to facilitate downloading
*/ */
public Peer(NetworkParameters params, PeerAddress address, int bestHeight, BlockChain blockChain) { public Peer(NetworkParameters params, PeerAddress address, int bestHeight, BlockChain blockChain) {
@ -82,7 +78,7 @@ public class Peer {
public Peer(NetworkParameters params, PeerAddress address, BlockChain blockChain) { public Peer(NetworkParameters params, PeerAddress address, BlockChain blockChain) {
this(params, address, 0, blockChain); this(params, address, 0, blockChain);
} }
public synchronized void addEventListener(PeerEventListener listener) { public synchronized void addEventListener(PeerEventListener listener) {
eventListeners.add(listener); eventListeners.add(listener);
} }
@ -98,7 +94,7 @@ public class Peer {
/** /**
* Connects to the peer. * Connects to the peer.
* *
* @throws PeerException when there is a temporary problem with the peer and we should retry later * @throws PeerException when there is a temporary problem with the peer and we should retry later
*/ */
public synchronized void connect() throws PeerException { public synchronized void connect() throws PeerException {
@ -118,18 +114,18 @@ public class Peer {
/** /**
* Runs in the peers network loop and manages communication with the peer. * Runs in the peers network loop and manages communication with the peer.
* *
* <p>connect() must be called first * <p>connect() must be called first
* *
* @throws PeerException when there is a temporary problem with the peer and we should retry later * @throws PeerException when there is a temporary problem with the peer and we should retry later
*/ */
public void run() throws PeerException { public void run() throws PeerException {
// This should be called in the network loop thread for this peer // This should be called in the network loop thread for this peer
if (conn == null) if (conn == null)
throw new RuntimeException("please call connect() first"); throw new RuntimeException("please call connect() first");
running = true; running = true;
try { try {
while (true) { while (true) {
Message m = conn.readMessage(); Message m = conn.readMessage();
@ -137,7 +133,7 @@ public class Peer {
processInv((InventoryMessage) m); processInv((InventoryMessage) m);
} else if (m instanceof Block) { } else if (m instanceof Block) {
processBlock((Block) m); processBlock((Block) m);
} else if (m instanceof AddressMessage) { } else if (m instanceof AddressMessage) {
// We don't care about addresses of the network right now. But in future, // We don't care about addresses of the network right now. But in future,
// we should save them in the wallet so we don't put too much load on the seed nodes and can // we should save them in the wallet so we don't put too much load on the seed nodes and can
// properly explore the network. // properly explore the network.
@ -261,7 +257,7 @@ public class Peer {
// Add to the list of things we're waiting for. It's important this come before the network send to avoid // Add to the list of things we're waiting for. It's important this come before the network send to avoid
// race conditions. // race conditions.
synchronized (pendingGetBlockFutures) { synchronized (pendingGetBlockFutures) {
pendingGetBlockFutures.add(future); pendingGetBlockFutures.add(future);
} }
conn.writeMessage(getdata); conn.writeMessage(getdata);
return future; return future;

View File

@ -22,7 +22,6 @@ import java.math.BigInteger;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Date;
import static com.google.bitcoin.core.Utils.uint32ToByteStreamLE; import static com.google.bitcoin.core.Utils.uint32ToByteStreamLE;
import static com.google.bitcoin.core.Utils.uint64ToByteStreamLE; import static com.google.bitcoin.core.Utils.uint64ToByteStreamLE;
@ -46,21 +45,20 @@ public class PeerAddress extends ChildMessage {
public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException { public PeerAddress(NetworkParameters params, byte[] payload, int offset, int protocolVersion) throws ProtocolException {
super(params, payload, offset, protocolVersion); super(params, payload, offset, protocolVersion);
} }
/** /**
* Construct a peer address from a serialized payload. * Construct a peer address from a serialized payload.
*/ */
public PeerAddress(NetworkParameters params, byte[] msg, int offset, int protocolVersion, Message parent, boolean parseLazy, public PeerAddress(NetworkParameters params, byte[] msg, int offset, int protocolVersion, Message parent, boolean parseLazy,
boolean parseRetain) throws ProtocolException { boolean parseRetain) throws ProtocolException {
super(params, msg, offset, protocolVersion, parent, parseLazy, parseRetain, UNKNOWN_LENGTH); super(params, msg, offset, protocolVersion, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
//Message length is calculated in parseLite which is guaranteed to be called before it is ever read. //Message length is calculated in parseLite which is guaranteed to be called before it is ever read.
//Safer to leave it there as it will be set regardless of which constructor was used. //Safer to leave it there as it will be set regardless of which constructor was used.
} }
/**
/**
* Construct a peer address from a memorized or hardcoded address. * Construct a peer address from a memorized or hardcoded address.
*/ */
public PeerAddress(InetAddress addr, int port, int protocolVersion) { public PeerAddress(InetAddress addr, int port, int protocolVersion) {
@ -70,26 +68,26 @@ public class PeerAddress extends ChildMessage {
this.services = BigInteger.ZERO; this.services = BigInteger.ZERO;
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4; length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
} }
public PeerAddress(InetAddress addr, int port) { public PeerAddress(InetAddress addr, int port) {
this(addr, port, NetworkParameters.PROTOCOL_VERSION); this(addr, port, NetworkParameters.PROTOCOL_VERSION);
} }
public PeerAddress(InetAddress addr) { public PeerAddress(InetAddress addr) {
this(addr, 0); this(addr, 0);
} }
public PeerAddress(InetSocketAddress addr) { public PeerAddress(InetSocketAddress addr) {
this(addr.getAddress(), addr.getPort()); this(addr.getAddress(), addr.getPort());
} }
@Override @Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
if (protocolVersion >= 31402) { if (protocolVersion >= 31402) {
//TODO this appears to be dynamic because the client only ever sends out it's own address //TODO this appears to be dynamic because the client only ever sends out it's own address
//so assumes itself to be up. For a fuller implementation this needs to be dynamic only if //so assumes itself to be up. For a fuller implementation this needs to be dynamic only if
//the address refers to this clinet. //the address refers to this clinet.
int secs = (int)(Utils.now().getTime() / 1000); int secs = (int) (Utils.now().getTime() / 1000);
uint32ToByteStreamLE(secs, stream); uint32ToByteStreamLE(secs, stream);
} }
uint64ToByteStreamLE(services, stream); // nServices. uint64ToByteStreamLE(services, stream); // nServices.
@ -108,10 +106,10 @@ public class PeerAddress extends ChildMessage {
stream.write((byte) (0xFF & port)); stream.write((byte) (0xFF & port));
} }
protected void parseLite() { protected void parseLite() {
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4; length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
} }
@Override @Override
protected void parse() { protected void parse() {
// Format of a serialized address: // Format of a serialized address:
@ -132,89 +130,89 @@ public class PeerAddress extends ChildMessage {
} }
port = ((0xFF & bytes[cursor++]) << 8) | (0xFF & bytes[cursor++]); port = ((0xFF & bytes[cursor++]) << 8) | (0xFF & bytes[cursor++]);
} }
/* (non-Javadoc) /* (non-Javadoc)
* @see com.google.bitcoin.core.Message#getMessageSize() * @see com.google.bitcoin.core.Message#getMessageSize()
*/ */
@Override @Override
int getMessageSize() { int getMessageSize() {
length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4; length = protocolVersion > 31402 ? MESSAGE_SIZE : MESSAGE_SIZE - 4;
return length; return length;
} }
/** /**
* @return the addr * @return the addr
*/ */
public InetAddress getAddr() { public InetAddress getAddr() {
checkParse(); checkParse();
return addr; return addr;
} }
/** /**
* @param addr the addr to set * @param addr the addr to set
*/ */
public void setAddr(InetAddress addr) { public void setAddr(InetAddress addr) {
unCache(); unCache();
this.addr = addr; this.addr = addr;
} }
/** /**
* @return the port * @return the port
*/ */
public int getPort() { public int getPort() {
checkParse(); checkParse();
return port; return port;
} }
/** /**
* @param port the port to set * @param port the port to set
*/ */
public void setPort(int port) { public void setPort(int port) {
unCache(); unCache();
this.port = port; this.port = port;
} }
/** /**
* @return the services * @return the services
*/ */
public BigInteger getServices() { public BigInteger getServices() {
checkParse(); checkParse();
return services; return services;
} }
/** /**
* @param services the services to set * @param services the services to set
*/ */
public void setServices(BigInteger services) { public void setServices(BigInteger services) {
unCache(); unCache();
this.services = services; this.services = services;
} }
/** /**
* @return the time * @return the time
*/ */
public long getTime() { public long getTime() {
checkParse(); checkParse();
return time; return time;
} }
/** /**
* @param time the time to set * @param time the time to set
*/ */
public void setTime(long time) { public void setTime(long time) {
unCache(); unCache();
this.time = time; this.time = time;
} }
@Override @Override
public String toString() { public String toString() {
return "[" + addr.getHostAddress() + "]:" + port; return "[" + addr.getHostAddress() + "]:" + port;
} }
@ -224,13 +222,13 @@ public class PeerAddress extends ChildMessage {
if (!(o instanceof PeerAddress)) return false; if (!(o instanceof PeerAddress)) return false;
PeerAddress other = (PeerAddress) o; PeerAddress other = (PeerAddress) o;
return other.addr.equals(addr) && return other.addr.equals(addr) &&
other.port == port && other.port == port &&
other.services.equals(services) && other.services.equals(services) &&
other.time == time; other.time == time;
} }
@Override @Override
public int hashCode() { public int hashCode() {
return addr.hashCode() ^ port ^ (int)time ^ services.hashCode(); return addr.hashCode() ^ port ^ (int) time ^ services.hashCode();
} }
} }

View File

@ -19,45 +19,44 @@ package com.google.bitcoin.core;
/** /**
* Implementing a PeerEventListener allows you to learn when significant Peer communication * Implementing a PeerEventListener allows you to learn when significant Peer communication
* has occurred. * has occurred.
* *
* <p>Methods are called with the event listener object locked so your * <p>Methods are called with the event listener object locked so your
* implementation does not have to be thread safe. * implementation does not have to be thread safe.
* *
* @author miron@google.com (Miron Cuperman a.k.a devrandom) * @author miron@google.com (Miron Cuperman a.k.a devrandom)
*
*/ */
public interface PeerEventListener { public interface PeerEventListener {
/** /**
* Called on a Peer thread when a block is received. * Called on a Peer thread when a block is received.
* * <p/>
* <p>The block may have transactions or may be a header only once getheaders is implemented. * <p>The block may have transactions or may be a header only once getheaders is implemented.
* *
* @param peer the peer receiving the block * @param peer the peer receiving the block
* @param block the downloaded block * @param block the downloaded block
* @param blocksLeft the number of blocks left to download * @param blocksLeft the number of blocks left to download
*/ */
public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft); public void onBlocksDownloaded(Peer peer, Block block, int blocksLeft);
/** /**
* Called when a download is started with the initial number of blocks to be downloaded. * Called when a download is started with the initial number of blocks to be downloaded.
* *
* @param peer the peer receiving the block * @param peer the peer receiving the block
* @param blocksLeft the number of blocks left to download * @param blocksLeft the number of blocks left to download
*/ */
public void onChainDownloadStarted(Peer peer, int blocksLeft); public void onChainDownloadStarted(Peer peer, int blocksLeft);
/** /**
* Called when a peer is connected * Called when a peer is connected
* *
* @param peer * @param peer
* @param peerCount the total number of connected peers * @param peerCount the total number of connected peers
*/ */
public void onPeerConnected(Peer peer, int peerCount); public void onPeerConnected(Peer peer, int peerCount);
/** /**
* Called when a peer is disconnected * Called when a peer is disconnected
* *
* @param peer * @param peer
* @param peerCount the total number of connected peers * @param peerCount the total number of connected peers
*/ */
public void onPeerDisconnected(Peer peer, int peerCount); public void onPeerDisconnected(Peer peer, int peerCount);

View File

@ -18,7 +18,7 @@ package com.google.bitcoin.core;
/** /**
* Thrown when a problem occurs in communicating with a peer, and we should * Thrown when a problem occurs in communicating with a peer, and we should
* retry. * retry.
*/ */
public class PeerException extends Exception { public class PeerException extends Exception {
@SuppressWarnings("serial") @SuppressWarnings("serial")

View File

@ -26,7 +26,7 @@ public class ProtocolException extends Exception {
public ProtocolException(Exception e) { public ProtocolException(Exception e) {
super(e); super(e);
} }
public ProtocolException(String msg, Exception e) { public ProtocolException(String msg, Exception e) {
super(msg, e); super(msg, e);
} }

View File

@ -16,18 +16,14 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import com.google.bitcoin.core.Transaction.SigHash; import org.slf4j.Logger;
import org.bouncycastle.util.Arrays; import org.slf4j.LoggerFactory;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Stack;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.bitcoin.core.Utils.bytesToHexString; import static com.google.bitcoin.core.Utils.bytesToHexString;
@ -35,13 +31,13 @@ import static com.google.bitcoin.core.Utils.bytesToHexString;
* BitCoin transactions don't specify what they do directly. Instead <a href="https://en.bitcoin.it/wiki/Script">a * BitCoin transactions don't specify what they do directly. Instead <a href="https://en.bitcoin.it/wiki/Script">a
* small binary stack language</a> is used to define programs that when evaluated return whether the transaction * small binary stack language</a> is used to define programs that when evaluated return whether the transaction
* "accepts" or rejects the other transactions connected to it.<p> * "accepts" or rejects the other transactions connected to it.<p>
* *
* This implementation of the scripting language is incomplete. It contains enough support to run standard * This implementation of the scripting language is incomplete. It contains enough support to run standard
* transactions generated by the official client, but non-standard transactions will fail. * transactions generated by the official client, but non-standard transactions will fail.
*/ */
public class Script { public class Script {
private static Logger log = LoggerFactory.getLogger(Script.class); private static Logger log = LoggerFactory.getLogger(Script.class);
// Some constants used for decoding the scripts. // Some constants used for decoding the scripts.
public static final int OP_PUSHDATA1 = 76; public static final int OP_PUSHDATA1 = 76;
public static final int OP_PUSHDATA2 = 77; public static final int OP_PUSHDATA2 = 77;
@ -53,7 +49,7 @@ public class Script {
byte[] program; byte[] program;
private int cursor; private int cursor;
// The program is a set of byte[]s where each element is either [opcode] or [data, data, data ...] // The program is a set of byte[]s where each element is either [opcode] or [data, data, data ...]
private List<byte[]> chunks; private List<byte[]> chunks;
byte[] programCopy; // TODO: remove this byte[] programCopy; // TODO: remove this
@ -61,10 +57,11 @@ public class Script {
/** /**
* Construct a Script using the given network parameters and a range of the programBytes array. * Construct a Script using the given network parameters and a range of the programBytes array.
* @param params Network parameters. *
* @param params Network parameters.
* @param programBytes Array of program bytes from a transaction. * @param programBytes Array of program bytes from a transaction.
* @param offset How many bytes into programBytes to start reading from. * @param offset How many bytes into programBytes to start reading from.
* @param length How many bytes to read. * @param length How many bytes to read.
* @throws ScriptException * @throws ScriptException
*/ */
public Script(NetworkParameters params, byte[] programBytes, int offset, int length) throws ScriptException { public Script(NetworkParameters params, byte[] programBytes, int offset, int length) throws ScriptException {
@ -72,7 +69,9 @@ public class Script {
parse(programBytes, offset, length); parse(programBytes, offset, length);
} }
/** Returns the program opcodes as a string, for example "[1234] DUP HAHS160" */ /**
* Returns the program opcodes as a string, for example "[1234] DUP HAHS160"
*/
public String toString() { public String toString() {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
for (byte[] chunk : chunks) { for (byte[] chunk : chunks) {
@ -80,10 +79,18 @@ public class Script {
String opName; String opName;
int opcode = 0xFF & chunk[0]; int opcode = 0xFF & chunk[0];
switch (opcode) { switch (opcode) {
case OP_DUP: opName = "DUP"; break; case OP_DUP:
case OP_HASH160: opName = "HASH160"; break; opName = "DUP";
case OP_CHECKSIG: opName = "CHECKSIG"; break; break;
case OP_EQUALVERIFY: opName = "EQUALVERIFY"; break; case OP_HASH160:
opName = "HASH160";
break;
case OP_CHECKSIG:
opName = "CHECKSIG";
break;
case OP_EQUALVERIFY:
opName = "EQUALVERIFY";
break;
default: default:
opName = "?(" + opcode + ")"; opName = "?(" + opcode + ")";
break; break;
@ -115,15 +122,15 @@ public class Script {
throw new ScriptException("Failed read of " + len + " bytes", e); throw new ScriptException("Failed read of " + len + " bytes", e);
} }
} }
private int readByte() { private int readByte() {
return 0xFF & program[cursor++]; return 0xFF & program[cursor++];
} }
/** /**
* To run a script, first we parse it which breaks it up into chunks representing pushes of * To run a script, first we parse it which breaks it up into chunks representing pushes of
* data or logical opcodes. Then we can run the parsed chunks. * data or logical opcodes. Then we can run the parsed chunks.
* * <p/>
* The reason for this split, instead of just interpreting directly, is to make it easier * The reason for this split, instead of just interpreting directly, is to make it easier
* to reach into a programs structure and pull out bits of data without having to run it. * to reach into a programs structure and pull out bits of data without having to run it.
* This is necessary to render the to/from addresses of transactions in a user interface. * This is necessary to render the to/from addresses of transactions in a user interface.
@ -144,7 +151,7 @@ public class Script {
// Not a single byte opcode. // Not a single byte opcode.
opcode = (opcode << 8) | readByte(); opcode = (opcode << 8) | readByte();
} }
if (opcode > 0 && opcode < OP_PUSHDATA1) { if (opcode > 0 && opcode < OP_PUSHDATA1) {
// Read some bytes of data, where how many is the opcode value itself. // Read some bytes of data, where how many is the opcode value itself.
chunks.add(getData(opcode)); // opcode == len here. chunks.add(getData(opcode)); // opcode == len here.
@ -159,7 +166,7 @@ public class Script {
// Read a uint32, then read that many bytes of data. // Read a uint32, then read that many bytes of data.
log.error("PUSHDATA4: Unimplemented"); log.error("PUSHDATA4: Unimplemented");
} else { } else {
chunks.add(new byte[] { (byte) opcode }); chunks.add(new byte[]{(byte) opcode});
} }
} }
} }
@ -174,31 +181,31 @@ public class Script {
return false; return false;
return (0xFF & chunks.get(1)[0]) == OP_CHECKSIG && chunks.get(0).length > 1; return (0xFF & chunks.get(1)[0]) == OP_CHECKSIG && chunks.get(0).length > 1;
} }
/** /**
* If a program matches the standard template DUP HASH160 <pubkey hash> EQUALVERIFY CHECKSIG * If a program matches the standard template DUP HASH160 <pubkey hash> EQUALVERIFY CHECKSIG
* then this function retrieves the third element, otherwise it throws a ScriptException. * then this function retrieves the third element, otherwise it throws a ScriptException.
* * <p/>
* This is useful for fetching the destination address of a transaction. * This is useful for fetching the destination address of a transaction.
*/ */
public byte[] getPubKeyHash() throws ScriptException { public byte[] getPubKeyHash() throws ScriptException {
if (chunks.size() != 5) if (chunks.size() != 5)
throw new ScriptException("Script not of right size to be a scriptPubKey, " + throw new ScriptException("Script not of right size to be a scriptPubKey, " +
"expecting 5 but got " + chunks.size()); "expecting 5 but got " + chunks.size());
if ((0xFF & chunks.get(0)[0]) != OP_DUP || if ((0xFF & chunks.get(0)[0]) != OP_DUP ||
(0xFF & chunks.get(1)[0]) != OP_HASH160 || (0xFF & chunks.get(1)[0]) != OP_HASH160 ||
(0xFF & chunks.get(3)[0]) != OP_EQUALVERIFY || (0xFF & chunks.get(3)[0]) != OP_EQUALVERIFY ||
(0xFF & chunks.get(4)[0]) != OP_CHECKSIG) (0xFF & chunks.get(4)[0]) != OP_CHECKSIG)
throw new ScriptException("Script not in the standard scriptPubKey form"); throw new ScriptException("Script not in the standard scriptPubKey form");
// Otherwise, the third element is the hash of the public key, ie the bitcoin address. // Otherwise, the third element is the hash of the public key, ie the bitcoin address.
return chunks.get(2); return chunks.get(2);
} }
/** /**
* If a program has two data buffers (constants) and nothing else, the second one is returned. * If a program has two data buffers (constants) and nothing else, the second one is returned.
* For a scriptSig this should be the public key of the sender. * For a scriptSig this should be the public key of the sender.
* * <p/>
* This is useful for fetching the source address of a transaction. * This is useful for fetching the source address of a transaction.
*/ */
public byte[] getPubKey() throws ScriptException { public byte[] getPubKey() throws ScriptException {
@ -207,14 +214,14 @@ public class Script {
return chunks.get(0); return chunks.get(0);
} }
if (chunks.size() != 2) if (chunks.size() != 2)
throw new ScriptException("Script not of right size to be a scriptSig, expecting 2" + throw new ScriptException("Script not of right size to be a scriptSig, expecting 2" +
" but got " + chunks.size()); " but got " + chunks.size());
if (!(chunks.get(0).length > 1) && (chunks.get(1).length > 1)) if (!(chunks.get(0).length > 1) && (chunks.get(1).length > 1))
throw new ScriptException("Script not in the standard scriptSig form: " + throw new ScriptException("Script not in the standard scriptSig form: " +
chunks.size() + " chunks"); chunks.size() + " chunks");
return chunks.get(1); return chunks.get(1);
} }
/** /**
* Convenience wrapper around getPubKey. Only works for scriptSigs. * Convenience wrapper around getPubKey. Only works for scriptSigs.
*/ */
@ -224,6 +231,7 @@ public class Script {
/** /**
* Gets the destination address from this script, if it's in the required form (see getPubKey). * Gets the destination address from this script, if it's in the required form (see getPubKey).
*
* @throws ScriptException * @throws ScriptException
*/ */
public Address getToAddress() throws ScriptException { public Address getToAddress() throws ScriptException {
@ -232,8 +240,10 @@ public class Script {
////////////////////// Interface for writing scripts from scratch //////////////////////////////// ////////////////////// Interface for writing scripts from scratch ////////////////////////////////
/** Writes out the given byte buffer to the output stream with the correct opcode prefix */ /**
static void writeBytes(OutputStream os, byte[] buf) throws IOException { * Writes out the given byte buffer to the output stream with the correct opcode prefix
*/
static void writeBytes(OutputStream os, byte[] buf) throws IOException {
if (buf.length < OP_PUSHDATA1) { if (buf.length < OP_PUSHDATA1) {
os.write(buf.length); os.write(buf.length);
os.write(buf); os.write(buf);
@ -266,7 +276,9 @@ public class Script {
} }
} }
/** Create a script that sends coins directly to the given public key (eg in a coinbase transaction). */ /**
* Create a script that sends coins directly to the given public key (eg in a coinbase transaction).
*/
static byte[] createOutputScript(byte[] pubkey) { static byte[] createOutputScript(byte[] pubkey) {
try { try {
// TODO: Do this by creating a Script *first* then having the script reassemble itself into bytes. // TODO: Do this by creating a Script *first* then having the script reassemble itself into bytes.
@ -279,7 +291,7 @@ public class Script {
} }
} }
static byte[] createInputScript(byte[] signature, byte[] pubkey) { static byte[] createInputScript(byte[] signature, byte[] pubkey) {
try { try {
// TODO: Do this by creating a Script *first* then having the script reassemble itself into bytes. // TODO: Do this by creating a Script *first* then having the script reassemble itself into bytes.
ByteArrayOutputStream bits = new UnsafeByteArrayOutputStream(signature.length + pubkey.length); ByteArrayOutputStream bits = new UnsafeByteArrayOutputStream(signature.length + pubkey.length);

View File

@ -33,13 +33,13 @@ public class Sha256Hash implements Serializable {
private byte[] bytes; private byte[] bytes;
private int hash = -1; private int hash = -1;
/** /**
* @see setHashcodeByteLength(int hashcodeByteLength) * @see setHashcodeByteLength(int hashcodeByteLength)
*/ */
private static int HASHCODE_BYTES_TO_CHECK = 5; private static int HASHCODE_BYTES_TO_CHECK = 5;
private static boolean HASHCODE_BYTES_TO_CHECK_CHANGED = false; private static boolean HASHCODE_BYTES_TO_CHECK_CHANGED = false;
public static final Sha256Hash ZERO_HASH = new Sha256Hash(new byte[32]); public static final Sha256Hash ZERO_HASH = new Sha256Hash(new byte[32]);
@ -49,41 +49,48 @@ public class Sha256Hash implements Serializable {
* The default value of 5 gives approximately 1 trillion possible unique combinations. * The default value of 5 gives approximately 1 trillion possible unique combinations.
* Given that an int hashcode only has 4 billion possible values it should be more than enough. * Given that an int hashcode only has 4 billion possible values it should be more than enough.
* <br/><br/> * <br/><br/>
* Changing this value after Sha256Hashes have been stored in hashed collections breaks the * Changing this value after Sha256Hashes have been stored in hashed collections breaks the
* hashCode contract and will result in unpredictable behaviour. If this * hashCode contract and will result in unpredictable behaviour. If this
* needs to be set to a different value it should be done once and only once * needs to be set to a different value it should be done once and only once
* and before any calls to hashCode() are made on any instance of Sha256Hash instances. * and before any calls to hashCode() are made on any instance of Sha256Hash instances.
* <br/> * <br/>
*
* @param hashcodeByteLength the number of bytes in the hash to use for generating the hashcode. * @param hashcodeByteLength the number of bytes in the hash to use for generating the hashcode.
* @throws IllegalStateException if called more than once. * @throws IllegalStateException if called more than once.
*/ */
public static void setHashcodeByteLength(int hashcodeByteLength) { public static void setHashcodeByteLength(int hashcodeByteLength) {
if (HASHCODE_BYTES_TO_CHECK_CHANGED) if (HASHCODE_BYTES_TO_CHECK_CHANGED)
throw new IllegalStateException("setHashcodeByteLength can only be called once and should be called before any instances of Sha256Hash are constructed"); throw new IllegalStateException("setHashcodeByteLength can only be called once and should be called before any instances of Sha256Hash are constructed");
HASHCODE_BYTES_TO_CHECK = hashcodeByteLength; HASHCODE_BYTES_TO_CHECK = hashcodeByteLength;
HASHCODE_BYTES_TO_CHECK_CHANGED = true; HASHCODE_BYTES_TO_CHECK_CHANGED = true;
} }
/** Creates a Sha256Hash by wrapping the given byte array. It must be 32 bytes long. */ /**
* Creates a Sha256Hash by wrapping the given byte array. It must be 32 bytes long.
*/
public Sha256Hash(byte[] bytes) { public Sha256Hash(byte[] bytes) {
assert bytes.length == 32; assert bytes.length == 32;
this.bytes = bytes; this.bytes = bytes;
} }
private Sha256Hash(byte[] bytes, int hash) { private Sha256Hash(byte[] bytes, int hash) {
assert bytes.length == 32; assert bytes.length == 32;
this.bytes = bytes; this.bytes = bytes;
this.hash = hash; this.hash = hash;
} }
/** Creates a Sha256Hash by decoding the given hex string. It must be 64 characters long. */ /**
* Creates a Sha256Hash by decoding the given hex string. It must be 64 characters long.
*/
public Sha256Hash(String string) { public Sha256Hash(String string) {
assert string.length() == 64; assert string.length() == 64;
this.bytes = Hex.decode(string); this.bytes = Hex.decode(string);
} }
/** Calculates the (one-time) hash of contents and returns it as a new wrapped hash. */ /**
* Calculates the (one-time) hash of contents and returns it as a new wrapped hash.
*/
public static Sha256Hash create(byte[] contents) { public static Sha256Hash create(byte[] contents) {
try { try {
MessageDigest digest = MessageDigest.getInstance("SHA-256"); MessageDigest digest = MessageDigest.getInstance("SHA-256");
@ -93,11 +100,13 @@ public class Sha256Hash implements Serializable {
} }
} }
/** Returns true if the hashes are equal. */ /**
* Returns true if the hashes are equal.
*/
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (!(other instanceof Sha256Hash)) return false; if (!(other instanceof Sha256Hash)) return false;
return Arrays.equals(bytes, ((Sha256Hash)other).bytes); return Arrays.equals(bytes, ((Sha256Hash) other).bytes);
} }
/** /**
@ -110,7 +119,7 @@ public class Sha256Hash implements Serializable {
if (hash == -1) { if (hash == -1) {
hash = 1; hash = 1;
for (int i = 0; i < HASHCODE_BYTES_TO_CHECK; i++) for (int i = 0; i < HASHCODE_BYTES_TO_CHECK; i++)
hash = 31 * hash + bytes[i]; hash = 31 * hash + bytes[i];
} }
return hash; return hash;
} }
@ -120,7 +129,9 @@ public class Sha256Hash implements Serializable {
return Utils.bytesToHexString(bytes); return Utils.bytesToHexString(bytes);
} }
/** Returns the bytes interpreted as a positive integer. */ /**
* Returns the bytes interpreted as a positive integer.
*/
public BigInteger toBigInteger() { public BigInteger toBigInteger() {
return new BigInteger(1, bytes); return new BigInteger(1, bytes);
} }
@ -130,6 +141,6 @@ public class Sha256Hash implements Serializable {
} }
public Sha256Hash duplicate() { public Sha256Hash duplicate() {
return new Sha256Hash(bytes, hash); return new Sha256Hash(bytes, hash);
} }
} }

View File

@ -16,17 +16,13 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.math.BigInteger;
import java.util.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigInteger;
import java.util.*;
import static com.google.bitcoin.core.Utils.*; import static com.google.bitcoin.core.Utils.*;
/** /**
@ -47,11 +43,11 @@ public class Transaction extends ChildMessage implements Serializable {
private ArrayList<TransactionInput> inputs; private ArrayList<TransactionInput> inputs;
//a cached copy to prevent constantly rewrapping //a cached copy to prevent constantly rewrapping
private transient List<TransactionInput> immutableInputs; private transient List<TransactionInput> immutableInputs;
private ArrayList<TransactionOutput> outputs; private ArrayList<TransactionOutput> outputs;
//a cached copy to prevent constantly rewrapping //a cached copy to prevent constantly rewrapping
private transient List<TransactionOutput> immutableOutputs; private transient List<TransactionOutput> immutableOutputs;
private long lockTime; private long lockTime;
// This is only stored in Java serialization. It records which blocks (and their height + work) the transaction // This is only stored in Java serialization. It records which blocks (and their height + work) the transaction
@ -88,7 +84,7 @@ public class Transaction extends ChildMessage implements Serializable {
public Transaction(NetworkParameters params, byte[] payloadBytes) throws ProtocolException { public Transaction(NetworkParameters params, byte[] payloadBytes) throws ProtocolException {
super(params, payloadBytes, 0); super(params, payloadBytes, 0);
} }
/** /**
* Creates a transaction by reading payload starting from offset bytes in. Length of a transaction is fixed. * Creates a transaction by reading payload starting from offset bytes in. Length of a transaction is fixed.
*/ */
@ -96,22 +92,22 @@ public class Transaction extends ChildMessage implements Serializable {
super(params, payload, offset); super(params, payload, offset);
// inputs/outputs will be created in parse() // inputs/outputs will be created in parse()
} }
/** /**
* Creates a transaction by reading payload starting from offset bytes in. Length of a transaction is fixed. * Creates a transaction by reading payload starting from offset bytes in. Length of a transaction is fixed.
*/ */
public Transaction(NetworkParameters params, byte[] msg, int offset, Message parent, boolean parseLazy, boolean parseRetain, int length) public Transaction(NetworkParameters params, byte[] msg, int offset, Message parent, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException { throws ProtocolException {
super(params, msg, offset, parent, parseLazy, parseRetain, length); super(params, msg, offset, parent, parseLazy, parseRetain, length);
} }
/** /**
* Creates a transaction by reading payload starting from offset bytes in. Length of a transaction is fixed. * Creates a transaction by reading payload starting from offset bytes in. Length of a transaction is fixed.
*/ */
public Transaction(NetworkParameters params, byte[] msg, Message parent, boolean parseLazy, boolean parseRetain, int length) public Transaction(NetworkParameters params, byte[] msg, Message parent, boolean parseLazy, boolean parseRetain, int length)
throws ProtocolException { throws ProtocolException {
super(params, msg, 0, parent, parseLazy, parseRetain, length); super(params, msg, 0, parent, parseLazy, parseRetain, length);
} }
/** /**
* Returns the transaction hash as you see them in the block explorer. * Returns the transaction hash as you see them in the block explorer.
@ -123,16 +119,16 @@ public class Transaction extends ChildMessage implements Serializable {
} }
return hash; return hash;
} }
/** /**
* Used by BitcoinSerializer. The serializer has to calculate a hash for checksumming so to * Used by BitcoinSerializer. The serializer has to calculate a hash for checksumming so to
* avoid wasting the considerable effort a set method is provided so the serializer can set it. * avoid wasting the considerable effort a set method is provided so the serializer can set it.
* *
* No verification is performed on this hash. * No verification is performed on this hash.
*/ */
void setHash(Sha256Hash hash) { void setHash(Sha256Hash hash) {
this.hash = hash; this.hash = hash;
} }
public String getHashAsString() { public String getHashAsString() {
return getHash().toString(); return getHash().toString();
@ -144,7 +140,7 @@ public class Transaction extends ChildMessage implements Serializable {
*/ */
BigInteger getValueSentToMe(Wallet wallet, boolean includeSpent) { BigInteger getValueSentToMe(Wallet wallet, boolean includeSpent) {
checkParse(); checkParse();
// This is tested in WalletTest. // This is tested in WalletTest.
BigInteger v = BigInteger.ZERO; BigInteger v = BigInteger.ZERO;
for (TransactionOutput o : outputs) { for (TransactionOutput o : outputs) {
if (!o.isMine(wallet)) continue; if (!o.isMine(wallet)) continue;
@ -154,7 +150,9 @@ public class Transaction extends ChildMessage implements Serializable {
return v; return v;
} }
/** Calculates the sum of the outputs that are sending coins to a key in the wallet. */ /**
* Calculates the sum of the outputs that are sending coins to a key in the wallet.
*/
public BigInteger getValueSentToMe(Wallet wallet) { public BigInteger getValueSentToMe(Wallet wallet) {
return getValueSentToMe(wallet, true); return getValueSentToMe(wallet, true);
} }
@ -172,7 +170,7 @@ public class Transaction extends ChildMessage implements Serializable {
* used by the wallet to ensure transactions that appear on side chains are recorded properly even though the * used by the wallet to ensure transactions that appear on side chains are recorded properly even though the
* block stores do not save the transaction data at all. * block stores do not save the transaction data at all.
* *
* @param block The {@link StoredBlock} in which the transaction has appeared. * @param block The {@link StoredBlock} in which the transaction has appeared.
* @param bestChain whether to set the updatedAt timestamp from the block header (only if not already set) * @param bestChain whether to set the updatedAt timestamp from the block header (only if not already set)
*/ */
void addBlockAppearance(StoredBlock block, boolean bestChain) { void addBlockAppearance(StoredBlock block, boolean bestChain) {
@ -193,8 +191,8 @@ public class Transaction extends ChildMessage implements Serializable {
* @return sum in nanocoins. * @return sum in nanocoins.
*/ */
public BigInteger getValueSentFromMe(Wallet wallet) throws ScriptException { public BigInteger getValueSentFromMe(Wallet wallet) throws ScriptException {
checkParse(); checkParse();
// This is tested in WalletTest. // This is tested in WalletTest.
BigInteger v = BigInteger.ZERO; BigInteger v = BigInteger.ZERO;
for (TransactionInput input : inputs) { for (TransactionInput input : inputs) {
// This input is taking value from an transaction in our wallet. To discover the value, // This input is taking value from an transaction in our wallet. To discover the value,
@ -230,7 +228,7 @@ public class Transaction extends ChildMessage implements Serializable {
*/ */
TransactionInput connectForReorganize(Map<Sha256Hash, Transaction> transactions) { TransactionInput connectForReorganize(Map<Sha256Hash, Transaction> transactions) {
checkParse(); checkParse();
for (TransactionInput input : inputs) { for (TransactionInput input : inputs) {
// Coinbase transactions, by definition, do not have connectable inputs. // Coinbase transactions, by definition, do not have connectable inputs.
if (input.isCoinBase()) continue; if (input.isCoinBase()) continue;
TransactionInput.ConnectionResult result = input.connect(transactions, false); TransactionInput.ConnectionResult result = input.connect(transactions, false);
@ -251,7 +249,7 @@ public class Transaction extends ChildMessage implements Serializable {
*/ */
public boolean isEveryOutputSpent() { public boolean isEveryOutputSpent() {
checkParse(); checkParse();
for (TransactionOutput output : outputs) { for (TransactionOutput output : outputs) {
if (output.isAvailableForSpending()) if (output.isAvailableForSpending())
return false; return false;
} }
@ -287,7 +285,7 @@ public class Transaction extends ChildMessage implements Serializable {
/** /**
* These constants are a part of a scriptSig signature on the inputs. They define the details of how a * These constants are a part of a scriptSig signature on the inputs. They define the details of how a
* transaction can be redeemed, specifically, they control how the hash of the transaction is calculated. * transaction can be redeemed, specifically, they control how the hash of the transaction is calculated.
* * <p/>
* In the official client, this enum also has another flag, SIGHASH_ANYONECANPAY. In this implementation, * In the official client, this enum also has another flag, SIGHASH_ANYONECANPAY. In this implementation,
* that's kept separate. Only SIGHASH_ALL is actually used in the official client today. The other flags * that's kept separate. Only SIGHASH_ALL is actually used in the official client today. The other flags
* exist to allow for distributed contracts. * exist to allow for distributed contracts.
@ -297,78 +295,78 @@ public class Transaction extends ChildMessage implements Serializable {
NONE, // 2 NONE, // 2
SINGLE, // 3 SINGLE, // 3
} }
protected void unCache() { protected void unCache() {
super.unCache(); super.unCache();
hash = null; hash = null;
} }
protected void parseLite() throws ProtocolException { protected void parseLite() throws ProtocolException {
//skip this if the length has been provided i.e. the tx is not part of a block //skip this if the length has been provided i.e. the tx is not part of a block
if (parseLazy && length == UNKNOWN_LENGTH) { if (parseLazy && length == UNKNOWN_LENGTH) {
//If length hasn't been provided this tx is probably contained within a block. //If length hasn't been provided this tx is probably contained within a block.
//In parseRetain mode the block needs to know how long the transaction is //In parseRetain mode the block needs to know how long the transaction is
//unfortunately this requires a fairly deep (though not total) parse. //unfortunately this requires a fairly deep (though not total) parse.
//This is due to the fact that transactions in the block's list do not include a //This is due to the fact that transactions in the block's list do not include a
//size header and inputs/outputs are also variable length due the contained //size header and inputs/outputs are also variable length due the contained
//script so each must be instantiated so the scriptlength varint can be read //script so each must be instantiated so the scriptlength varint can be read
//to calculate total length of the transaction. //to calculate total length of the transaction.
//We will still persist will this semi-light parsing because getting the lengths //We will still persist will this semi-light parsing because getting the lengths
//of the various components gains us the ability to cache the backing bytearrays //of the various components gains us the ability to cache the backing bytearrays
//so that only those subcomponents that have changed will need to be reserialized. //so that only those subcomponents that have changed will need to be reserialized.
//parse(); //parse();
//parsed = true; //parsed = true;
length = calcLength(bytes, cursor, offset); length = calcLength(bytes, cursor, offset);
cursor = offset + length; cursor = offset + length;
} }
} }
protected static int calcLength(byte[] buf, int cursor, int offset) { protected static int calcLength(byte[] buf, int cursor, int offset) {
VarInt varint; VarInt varint;
cursor = offset + 4; cursor = offset + 4;
int i; int i;
long scriptLen; long scriptLen;
varint = new VarInt(buf, cursor); varint = new VarInt(buf, cursor);
long txInCount = varint.value; long txInCount = varint.value;
cursor += varint.getSizeInBytes(); cursor += varint.getSizeInBytes();
for (i = 0; i < txInCount; i++) { for (i = 0; i < txInCount; i++) {
cursor += 36; cursor += 36;
varint = new VarInt(buf, cursor); varint = new VarInt(buf, cursor);
scriptLen = varint.value; scriptLen = varint.value;
cursor += scriptLen + 4 + varint.getSizeInBytes(); cursor += scriptLen + 4 + varint.getSizeInBytes();
} }
varint = new VarInt(buf, cursor); varint = new VarInt(buf, cursor);
long txOutCount = varint.value; long txOutCount = varint.value;
cursor += varint.getSizeInBytes(); cursor += varint.getSizeInBytes();
for (i = 0; i < txOutCount; i++) { for (i = 0; i < txOutCount; i++) {
cursor += 8; cursor += 8;
varint = new VarInt(buf, cursor); varint = new VarInt(buf, cursor);
scriptLen = varint.value; scriptLen = varint.value;
cursor += scriptLen + varint.getSizeInBytes(); cursor += scriptLen + varint.getSizeInBytes();
} }
return cursor - offset + 4; return cursor - offset + 4;
} }
void parse() throws ProtocolException { void parse() throws ProtocolException {
if (parsed) if (parsed)
return; return;
cursor = offset; cursor = offset;
version = readUint32(); version = readUint32();
int marker = cursor; int marker = cursor;
// First come the inputs. // First come the inputs.
long numInputs = readVarInt(); long numInputs = readVarInt();
inputs = new ArrayList<TransactionInput>((int)numInputs); inputs = new ArrayList<TransactionInput>((int) numInputs);
for (long i = 0; i < numInputs; i++) { for (long i = 0; i < numInputs; i++) {
TransactionInput input = new TransactionInput(params, this, bytes, cursor, parseLazy, parseRetain); TransactionInput input = new TransactionInput(params, this, bytes, cursor, parseLazy, parseRetain);
inputs.add(input); inputs.add(input);
@ -376,7 +374,7 @@ public class Transaction extends ChildMessage implements Serializable {
} }
// Now the outputs // Now the outputs
long numOutputs = readVarInt(); long numOutputs = readVarInt();
outputs = new ArrayList<TransactionOutput>((int)numOutputs); outputs = new ArrayList<TransactionOutput>((int) numOutputs);
for (long i = 0; i < numOutputs; i++) { for (long i = 0; i < numOutputs; i++) {
TransactionOutput output = new TransactionOutput(params, this, bytes, cursor, parseLazy, parseRetain); TransactionOutput output = new TransactionOutput(params, this, bytes, cursor, parseLazy, parseRetain);
outputs.add(output); outputs.add(output);
@ -394,7 +392,7 @@ public class Transaction extends ChildMessage implements Serializable {
*/ */
public boolean isCoinBase() { public boolean isCoinBase() {
checkParse(); checkParse();
return inputs.get(0).isCoinBase(); return inputs.get(0).isCoinBase();
} }
/** /**
@ -420,7 +418,7 @@ public class Transaction extends ChildMessage implements Serializable {
for (TransactionInput in : inputs) { for (TransactionInput in : inputs) {
s.append(" "); s.append(" ");
s.append("from "); s.append("from ");
try { try {
s.append(in.getScriptSig().getFromAddress().toString()); s.append(in.getScriptSig().getFromAddress().toString());
} catch (Exception e) { } catch (Exception e) {
@ -456,7 +454,9 @@ public class Transaction extends ChildMessage implements Serializable {
addInput(new TransactionInput(params, this, from)); addInput(new TransactionInput(params, this, from));
} }
/** Adds an input directly, with no checking that it's valid. */ /**
* Adds an input directly, with no checking that it's valid.
*/
public void addInput(TransactionInput input) { public void addInput(TransactionInput input) {
unCache(); unCache();
input.setParent(this); input.setParent(this);
@ -470,11 +470,11 @@ public class Transaction extends ChildMessage implements Serializable {
*/ */
public void addOutput(TransactionOutput to) { public void addOutput(TransactionOutput to) {
unCache(); unCache();
//these could be merged into one but would need parentTransaction to be cast whenever it was accessed. //these could be merged into one but would need parentTransaction to be cast whenever it was accessed.
to.setParent(this); to.setParent(this);
to.parentTransaction = this; to.parentTransaction = this;
immutableOutputs = null; immutableOutputs = null;
outputs.add(to); outputs.add(to);
adjustLength(to.length); adjustLength(to.length);
@ -484,11 +484,11 @@ public class Transaction extends ChildMessage implements Serializable {
* Once a transaction has some inputs and outputs added, the signatures in the inputs can be calculated. The * Once a transaction has some inputs and outputs added, the signatures in the inputs can be calculated. The
* signature is over the transaction itself, to prove the redeemer actually created that transaction, * signature is over the transaction itself, to prove the redeemer actually created that transaction,
* so we have to do this step last.<p> * so we have to do this step last.<p>
* * <p/>
* This method is similar to SignatureHash in script.cpp * This method is similar to SignatureHash in script.cpp
* *
* @param hashType This should always be set to SigHash.ALL currently. Other types are unused. * @param hashType This should always be set to SigHash.ALL currently. Other types are unused.
* @param wallet A wallet is required to fetch the keys needed for signing. * @param wallet A wallet is required to fetch the keys needed for signing.
*/ */
@SuppressWarnings({"SameParameterValue"}) @SuppressWarnings({"SameParameterValue"})
public void signInputs(SigHash hashType, Wallet wallet) throws ScriptException { public void signInputs(SigHash hashType, Wallet wallet) throws ScriptException {
@ -528,10 +528,10 @@ public class Transaction extends ChildMessage implements Serializable {
// Now sign for the output so we can redeem it. We use the keypair to sign the hash, // Now sign for the output so we can redeem it. We use the keypair to sign the hash,
// and then put the resulting signature in the script along with the public key (below). // and then put the resulting signature in the script along with the public key (below).
try { try {
//usually 71-73 bytes //usually 71-73 bytes
ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(73); ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(73);
bos.write(key.sign(hash)); bos.write(key.sign(hash));
bos.write((hashType.ordinal() + 1) | (anyoneCanPay ? 0x80 : 0)) ; bos.write((hashType.ordinal() + 1) | (anyoneCanPay ? 0x80 : 0));
signatures[i] = bos.toByteArray(); signatures[i] = bos.toByteArray();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); // Cannot happen. throw new RuntimeException(e); // Cannot happen.
@ -567,7 +567,7 @@ public class Transaction extends ChildMessage implements Serializable {
throw new RuntimeException(e); // Cannot happen. throw new RuntimeException(e); // Cannot happen.
} }
} }
@Override @Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
uint32ToByteStreamLE(version, stream); uint32ToByteStreamLE(version, stream);
@ -579,56 +579,55 @@ public class Transaction extends ChildMessage implements Serializable {
out.bitcoinSerialize(stream); out.bitcoinSerialize(stream);
uint32ToByteStreamLE(lockTime, stream); uint32ToByteStreamLE(lockTime, stream);
} }
/** /**
* @return the lockTime * @return the lockTime
*/ */
public long getLockTime() { public long getLockTime() {
checkParse(); checkParse();
return lockTime; return lockTime;
} }
/** /**
* @param lockTime the lockTime to set * @param lockTime the lockTime to set
*/ */
public void setLockTime(long lockTime) { public void setLockTime(long lockTime) {
unCache(); unCache();
this.lockTime = lockTime; this.lockTime = lockTime;
} }
/** /**
* @return the version * @return the version
*/ */
public long getVersion() { public long getVersion() {
checkParse(); checkParse();
return version; return version;
} }
/** /**
* @return a read-only list of the inputs of this transaction. * @return a read-only list of the inputs of this transaction.
*/ */
public List<TransactionInput> getInputs() { public List<TransactionInput> getInputs() {
if (immutableInputs == null) { if (immutableInputs == null) {
checkParse(); checkParse();
immutableInputs = Collections.unmodifiableList(inputs); immutableInputs = Collections.unmodifiableList(inputs);
} }
return immutableInputs; return immutableInputs;
} }
/** /**
* @return a read-only list of the outputs of this transaction. * @return a read-only list of the outputs of this transaction.
*/ */
public List<TransactionOutput> getOutputs() { public List<TransactionOutput> getOutputs() {
if (immutableOutputs == null) { if (immutableOutputs == null) {
checkParse(); checkParse();
immutableOutputs = Collections.unmodifiableList(outputs); immutableOutputs = Collections.unmodifiableList(outputs);
} }
return immutableOutputs; return immutableOutputs;
} }
@Override @Override
public boolean equals(Object other) { public boolean equals(Object other) {
if (!(other instanceof Transaction)) return false; if (!(other instanceof Transaction)) return false;
Transaction t = (Transaction) other; Transaction t = (Transaction) other;
@ -640,15 +639,15 @@ public class Transaction extends ChildMessage implements Serializable {
public int hashCode() { public int hashCode() {
return getHash().hashCode(); return getHash().hashCode();
} }
/** /**
* Ensure object is fully parsed before invoking java serialization. The backing byte array * Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet * is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization. * then data will be lost during serialization.
*/ */
private void writeObject(ObjectOutputStream out) throws IOException { private void writeObject(ObjectOutputStream out) throws IOException {
checkParse(); checkParse();
out.defaultWriteObject(); out.defaultWriteObject();
} }
} }

View File

@ -48,18 +48,22 @@ public class TransactionInput extends ChildMessage implements Serializable {
// A pointer to the transaction that owns this input. // A pointer to the transaction that owns this input.
private Transaction parentTransaction; private Transaction parentTransaction;
/** Used only in creation of the genesis block. */ /**
* Used only in creation of the genesis block.
*/
TransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] scriptBytes) { TransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] scriptBytes) {
super(params); super(params);
this.scriptBytes = scriptBytes; this.scriptBytes = scriptBytes;
this.outpoint = new TransactionOutPoint(params, -1, null); this.outpoint = new TransactionOutPoint(params, -1, null);
this.sequence = 0xFFFFFFFFL; this.sequence = 0xFFFFFFFFL;
this.parentTransaction = parentTransaction; this.parentTransaction = parentTransaction;
length = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length); length = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
} }
/** Creates an UNSIGNED input that links to the given output */ /**
* Creates an UNSIGNED input that links to the given output
*/
TransactionInput(NetworkParameters params, Transaction parentTransaction, TransactionOutput output) { TransactionInput(NetworkParameters params, Transaction parentTransaction, TransactionOutput output) {
super(params); super(params);
long outputIndex = output.getIndex(); long outputIndex = output.getIndex();
@ -67,39 +71,43 @@ public class TransactionInput extends ChildMessage implements Serializable {
scriptBytes = EMPTY_ARRAY; scriptBytes = EMPTY_ARRAY;
sequence = 0xFFFFFFFFL; sequence = 0xFFFFFFFFL;
this.parentTransaction = parentTransaction; this.parentTransaction = parentTransaction;
length = 41; length = 41;
} }
/** Deserializes an input message. This is usually part of a transaction message. */ /**
* Deserializes an input message. This is usually part of a transaction message.
*/
public TransactionInput(NetworkParameters params, Transaction parentTransaction, public TransactionInput(NetworkParameters params, Transaction parentTransaction,
byte[] payload, int offset) throws ProtocolException { byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset); super(params, payload, offset);
this.parentTransaction = parentTransaction; this.parentTransaction = parentTransaction;
} }
/** Deserializes an input message. This is usually part of a transaction message. */ /**
* Deserializes an input message. This is usually part of a transaction message.
*/
public TransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] msg, int offset, boolean parseLazy, boolean parseRetain) public TransactionInput(NetworkParameters params, Transaction parentTransaction, byte[] msg, int offset, boolean parseLazy, boolean parseRetain)
throws ProtocolException { throws ProtocolException {
super(params, msg, offset, parentTransaction, parseLazy, parseRetain, UNKNOWN_LENGTH); super(params, msg, offset, parentTransaction, parseLazy, parseRetain, UNKNOWN_LENGTH);
this.parentTransaction = parentTransaction; this.parentTransaction = parentTransaction;
} }
protected void parseLite() { protected void parseLite() {
int curs = cursor; int curs = cursor;
int scriptLen = (int) readVarInt(36); int scriptLen = (int) readVarInt(36);
length = cursor - offset + scriptLen + 4; length = cursor - offset + scriptLen + 4;
cursor = curs; cursor = curs;
} }
void parse() throws ProtocolException { void parse() throws ProtocolException {
outpoint = new TransactionOutPoint(params, bytes, cursor, this, parseLazy, parseRetain); outpoint = new TransactionOutPoint(params, bytes, cursor, this, parseLazy, parseRetain);
cursor += outpoint.getMessageSize(); cursor += outpoint.getMessageSize();
int scriptLen = (int) readVarInt(); int scriptLen = (int) readVarInt();
scriptBytes = readBytes(scriptLen); scriptBytes = readBytes(scriptLen);
sequence = readUint32(); sequence = readUint32();
} }
@Override @Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
outpoint.bitcoinSerialize(stream); outpoint.bitcoinSerialize(stream);
@ -113,7 +121,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
*/ */
public boolean isCoinBase() { public boolean isCoinBase() {
checkParse(); checkParse();
return outpoint.getHash().equals(Sha256Hash.ZERO_HASH); return outpoint.getHash().equals(Sha256Hash.ZERO_HASH);
} }
/** /**
@ -124,7 +132,7 @@ public class TransactionInput extends ChildMessage implements Serializable {
// parameter is overloaded to be something totally different. // parameter is overloaded to be something totally different.
if (scriptSig == null) { if (scriptSig == null) {
checkParse(); checkParse();
assert scriptBytes != null; assert scriptBytes != null;
scriptSig = new Script(params, scriptBytes, 0, scriptBytes.length); scriptSig = new Script(params, scriptBytes, 0, scriptBytes.length);
} }
return scriptSig; return scriptSig;
@ -132,64 +140,67 @@ public class TransactionInput extends ChildMessage implements Serializable {
/** /**
* Convenience method that returns the from address of this input by parsing the scriptSig. * Convenience method that returns the from address of this input by parsing the scriptSig.
*
* @throws ScriptException if the scriptSig could not be understood (eg, if this is a coinbase transaction). * @throws ScriptException if the scriptSig could not be understood (eg, if this is a coinbase transaction).
*/ */
public Address getFromAddress() throws ScriptException { public Address getFromAddress() throws ScriptException {
assert !isCoinBase(); assert !isCoinBase();
return getScriptSig().getFromAddress(); return getScriptSig().getFromAddress();
} }
/** /**
* @return the sequence * @return the sequence
*/ */
public long getSequence() { public long getSequence() {
checkParse(); checkParse();
return sequence; return sequence;
} }
/** /**
* @param sequence the sequence to set * @param sequence the sequence to set
*/ */
public void setSequence(long sequence) { public void setSequence(long sequence) {
unCache(); unCache();
this.sequence = sequence; this.sequence = sequence;
} }
/** /**
* @return the outpoint * @return the outpoint
*/ */
public TransactionOutPoint getOutpoint() { public TransactionOutPoint getOutpoint() {
checkParse(); checkParse();
return outpoint; return outpoint;
} }
/** /**
* @return the scriptBytes * @return the scriptBytes
*/ */
public byte[] getScriptBytes() { public byte[] getScriptBytes() {
checkParse(); checkParse();
return scriptBytes; return scriptBytes;
} }
/**
* @param scriptBytes the scriptBytes to set
*/
void setScriptBytes(byte[] scriptBytes) {
unCache();
int oldLength = length;
this.scriptBytes = scriptBytes;
int newLength = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
adjustLength(newLength - oldLength);
}
/** /**
* @return the parentTransaction * @param scriptBytes the scriptBytes to set
*/ */
public Transaction getParentTransaction() { void setScriptBytes(byte[] scriptBytes) {
return parentTransaction; unCache();
} int oldLength = length;
this.scriptBytes = scriptBytes;
int newLength = 40 + (scriptBytes == null ? 1 : VarInt.sizeOf(scriptBytes.length) + scriptBytes.length);
adjustLength(newLength - oldLength);
}
/** Returns a human readable debug string. */ /**
* @return the parentTransaction
*/
public Transaction getParentTransaction() {
return parentTransaction;
}
/**
* Returns a human readable debug string.
*/
public String toString() { public String toString() {
if (isCoinBase()) if (isCoinBase())
return "TxIn: COINBASE"; return "TxIn: COINBASE";
@ -212,13 +223,14 @@ public class TransactionInput extends ChildMessage implements Serializable {
/** /**
* Locates the referenced output from the given pool of transactions. * Locates the referenced output from the given pool of transactions.
*
* @return The TransactionOutput or null if the transactions map doesn't contain the referenced tx. * @return The TransactionOutput or null if the transactions map doesn't contain the referenced tx.
*/ */
TransactionOutput getConnectedOutput(Map<Sha256Hash, Transaction> transactions) { TransactionOutput getConnectedOutput(Map<Sha256Hash, Transaction> transactions) {
Transaction tx = transactions.get(outpoint.getHash()); Transaction tx = transactions.get(outpoint.getHash());
if (tx == null) if (tx == null)
return null; return null;
TransactionOutput out = tx.getOutputs().get((int)outpoint.getIndex()); TransactionOutput out = tx.getOutputs().get((int) outpoint.getIndex());
return out; return out;
} }
@ -227,14 +239,14 @@ public class TransactionInput extends ChildMessage implements Serializable {
* Connecting means updating the internal pointers and spent flags. * Connecting means updating the internal pointers and spent flags.
* *
* @param transactions Map of txhash->transaction. * @param transactions Map of txhash->transaction.
* @param disconnect Whether to abort if there's a pre-existing connection or not. * @param disconnect Whether to abort if there's a pre-existing connection or not.
* @return true if connection took place, false if the referenced transaction was not in the list. * @return true if connection took place, false if the referenced transaction was not in the list.
*/ */
ConnectionResult connect(Map<Sha256Hash, Transaction> transactions, boolean disconnect) { ConnectionResult connect(Map<Sha256Hash, Transaction> transactions, boolean disconnect) {
Transaction tx = transactions.get(outpoint.getHash()); Transaction tx = transactions.get(outpoint.getHash());
if (tx == null) if (tx == null)
return TransactionInput.ConnectionResult.NO_SUCH_TX; return TransactionInput.ConnectionResult.NO_SUCH_TX;
TransactionOutput out = tx.getOutputs().get((int)outpoint.getIndex()); TransactionOutput out = tx.getOutputs().get((int) outpoint.getIndex());
if (!out.isAvailableForSpending()) { if (!out.isAvailableForSpending()) {
if (disconnect) if (disconnect)
out.markAsUnspent(); out.markAsUnspent();
@ -253,18 +265,18 @@ public class TransactionInput extends ChildMessage implements Serializable {
*/ */
boolean disconnect() { boolean disconnect() {
if (outpoint.fromTx == null) return false; if (outpoint.fromTx == null) return false;
outpoint.fromTx.getOutputs().get((int)outpoint.getIndex()).markAsUnspent(); outpoint.fromTx.getOutputs().get((int) outpoint.getIndex()).markAsUnspent();
outpoint.fromTx = null; outpoint.fromTx = null;
return true; return true;
} }
/** /**
* Ensure object is fully parsed before invoking java serialization. The backing byte array * Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet * is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization. * then data will be lost during serialization.
*/ */
private void writeObject(ObjectOutputStream out) throws IOException { private void writeObject(ObjectOutputStream out) throws IOException {
checkParse(); checkParse();
out.defaultWriteObject(); out.defaultWriteObject();
} }
} }

View File

@ -28,7 +28,7 @@ import java.io.Serializable;
*/ */
public class TransactionOutPoint extends ChildMessage implements Serializable { public class TransactionOutPoint extends ChildMessage implements Serializable {
private static final long serialVersionUID = -6320880638344662579L; private static final long serialVersionUID = -6320880638344662579L;
static final int MESSAGE_LENGTH = 36; static final int MESSAGE_LENGTH = 36;
/** Hash of the transaction to which we refer. */ /** Hash of the transaction to which we refer. */
@ -53,35 +53,39 @@ public class TransactionOutPoint extends ChildMessage implements Serializable {
length = MESSAGE_LENGTH; length = MESSAGE_LENGTH;
} }
/** Deserializes the message. This is usually part of a transaction message. */ /**
* Deserializes the message. This is usually part of a transaction message.
*/
public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset) throws ProtocolException { public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset) throws ProtocolException {
super(params, payload, offset); super(params, payload, offset);
} }
/** Deserializes the message. This is usually part of a transaction message. */ /**
* Deserializes the message. This is usually part of a transaction message.
*/
public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset, Message parent, boolean parseLazy, boolean parseRetain) throws ProtocolException { public TransactionOutPoint(NetworkParameters params, byte[] payload, int offset, Message parent, boolean parseLazy, boolean parseRetain) throws ProtocolException {
super(params, payload, offset, parent, parseLazy, parseRetain, MESSAGE_LENGTH); super(params, payload, offset, parent, parseLazy, parseRetain, MESSAGE_LENGTH);
} }
protected void parseLite() throws ProtocolException { protected void parseLite() throws ProtocolException {
length = MESSAGE_LENGTH; length = MESSAGE_LENGTH;
} }
@Override @Override
void parse() throws ProtocolException { void parse() throws ProtocolException {
hash = readHash(); hash = readHash();
index = readUint32(); index = readUint32();
} }
/* (non-Javadoc)
* @see com.google.bitcoin.core.Message#getMessageSize()
*/
@Override
int getMessageSize() {
return MESSAGE_LENGTH;
}
@Override /* (non-Javadoc)
* @see com.google.bitcoin.core.Message#getMessageSize()
*/
@Override
int getMessageSize() {
return MESSAGE_LENGTH;
}
@Override
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
stream.write(Utils.reverseBytes(hash.getBytes())); stream.write(Utils.reverseBytes(hash.getBytes()));
Utils.uint32ToByteStreamLE(index, stream); Utils.uint32ToByteStreamLE(index, stream);
@ -93,7 +97,7 @@ public class TransactionOutPoint extends ChildMessage implements Serializable {
*/ */
TransactionOutput getConnectedOutput() { TransactionOutput getConnectedOutput() {
if (fromTx == null) return null; if (fromTx == null) return null;
return fromTx.getOutputs().get((int)index); return fromTx.getOutputs().get((int) index);
} }
/** /**
@ -117,31 +121,30 @@ public class TransactionOutPoint extends ChildMessage implements Serializable {
public String toString() { public String toString() {
return "outpoint " + index + ":" + hash.toString(); return "outpoint " + index + ":" + hash.toString();
} }
/** /**
* @return the hash * @return the hash
*/ */
public Sha256Hash getHash() { public Sha256Hash getHash() {
checkParse(); checkParse();
return hash; return hash;
} }
/** /**
* @param hash the hash to set * @param hash the hash to set
*/ */
void setHash(Sha256Hash hash) { void setHash(Sha256Hash hash) {
this.hash = hash; this.hash = hash;
} }
/** /**
* @return the index * @return the index
*/ */
public long getIndex() { public long getIndex() {
checkParse(); checkParse();
return index; return index;
} }
// /** // /**
// * @param index the index to set // * @param index the index to set
@ -151,13 +154,13 @@ public class TransactionOutPoint extends ChildMessage implements Serializable {
// this.index = index; // this.index = index;
// } // }
/** /**
* Ensure object is fully parsed before invoking java serialization. The backing byte array * Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet * is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization. * then data will be lost during serialization.
*/ */
private void writeObject(ObjectOutputStream out) throws IOException { private void writeObject(ObjectOutputStream out) throws IOException {
checkParse(); checkParse();
out.defaultWriteObject(); out.defaultWriteObject();
} }
} }

View File

@ -50,25 +50,29 @@ public class TransactionOutput extends ChildMessage implements Serializable {
// A reference to the transaction which holds this output. // A reference to the transaction which holds this output.
Transaction parentTransaction; Transaction parentTransaction;
private transient int scriptLen; private transient int scriptLen;
/** Deserializes a transaction output message. This is usually part of a transaction message. */ /**
* Deserializes a transaction output message. This is usually part of a transaction message.
*/
public TransactionOutput(NetworkParameters params, Transaction parent, byte[] payload, public TransactionOutput(NetworkParameters params, Transaction parent, byte[] payload,
int offset) throws ProtocolException { int offset) throws ProtocolException {
super(params, payload, offset); super(params, payload, offset);
parentTransaction = parent; parentTransaction = parent;
availableForSpending = true; availableForSpending = true;
} }
/** Deserializes a transaction output message. This is usually part of a transaction message. */
public TransactionOutput(NetworkParameters params, Transaction parent, byte[] msg, int offset, boolean parseLazy, boolean parseRetain)
throws ProtocolException {
super(params, msg, offset, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
parentTransaction = parent;
availableForSpending = true;
}
TransactionOutput(NetworkParameters params, Transaction parent, BigInteger value, Address to) { /**
* Deserializes a transaction output message. This is usually part of a transaction message.
*/
public TransactionOutput(NetworkParameters params, Transaction parent, byte[] msg, int offset, boolean parseLazy, boolean parseRetain)
throws ProtocolException {
super(params, msg, offset, parent, parseLazy, parseRetain, UNKNOWN_LENGTH);
parentTransaction = parent;
availableForSpending = true;
}
TransactionOutput(NetworkParameters params, Transaction parent, BigInteger value, Address to) {
super(params); super(params);
this.value = value; this.value = value;
this.scriptBytes = Script.createOutputScript(to); this.scriptBytes = Script.createOutputScript(to);
@ -77,7 +81,9 @@ public class TransactionOutput extends ChildMessage implements Serializable {
length = 8 + VarInt.sizeOf(scriptBytes.length) + scriptBytes.length; length = 8 + VarInt.sizeOf(scriptBytes.length) + scriptBytes.length;
} }
/** Used only in creation of the genesis blocks and in unit tests. */ /**
* Used only in creation of the genesis blocks and in unit tests.
*/
TransactionOutput(NetworkParameters params, Transaction parent, byte[] scriptBytes) { TransactionOutput(NetworkParameters params, Transaction parent, byte[] scriptBytes) {
super(params); super(params);
this.scriptBytes = scriptBytes; this.scriptBytes = scriptBytes;
@ -86,26 +92,26 @@ public class TransactionOutput extends ChildMessage implements Serializable {
availableForSpending = true; availableForSpending = true;
} }
public Script getScriptPubKey() throws ScriptException { public Script getScriptPubKey() throws ScriptException {
if (scriptPubKey == null) { if (scriptPubKey == null) {
checkParse(); checkParse();
scriptPubKey = new Script(params, scriptBytes, 0, scriptBytes.length); scriptPubKey = new Script(params, scriptBytes, 0, scriptBytes.length);
} }
return scriptPubKey; return scriptPubKey;
} }
protected void parseLite() { protected void parseLite() {
value = readUint64(); value = readUint64();
scriptLen = (int) readVarInt(); scriptLen = (int) readVarInt();
length = cursor - offset + scriptLen; length = cursor - offset + scriptLen;
} }
void parse() throws ProtocolException { void parse() throws ProtocolException {
scriptBytes = readBytes(scriptLen); scriptBytes = readBytes(scriptLen);
} }
@Override @Override
protected void bitcoinSerializeToStream( OutputStream stream) throws IOException { protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
assert scriptBytes != null; assert scriptBytes != null;
Utils.uint64ToByteStreamLE(getValue(), stream); Utils.uint64ToByteStreamLE(getValue(), stream);
// TODO: Move script serialization into the Script class, where it belongs. // TODO: Move script serialization into the Script class, where it belongs.
@ -119,7 +125,7 @@ public class TransactionOutput extends ChildMessage implements Serializable {
*/ */
public BigInteger getValue() { public BigInteger getValue() {
checkParse(); checkParse();
return value; return value;
} }
int getIndex() { int getIndex() {
@ -153,10 +159,12 @@ public class TransactionOutput extends ChildMessage implements Serializable {
public byte[] getScriptBytes() { public byte[] getScriptBytes() {
checkParse(); checkParse();
return scriptBytes; return scriptBytes;
} }
/** Returns true if this output is to an address we have the keys for in the wallet. */ /**
* Returns true if this output is to an address we have the keys for in the wallet.
*/
public boolean isMine(Wallet wallet) { public boolean isMine(Wallet wallet) {
try { try {
byte[] pubkeyHash = getScriptPubKey().getPubKeyHash(); byte[] pubkeyHash = getScriptPubKey().getPubKeyHash();
@ -167,7 +175,9 @@ public class TransactionOutput extends ChildMessage implements Serializable {
} }
} }
/** Returns a human readable debug string. */ /**
* Returns a human readable debug string.
*/
public String toString() { public String toString() {
try { try {
return "TxOut of " + Utils.bitcoinValueToFriendlyString(value) + " to " + getScriptPubKey().getToAddress() return "TxOut of " + Utils.bitcoinValueToFriendlyString(value) + " to " + getScriptPubKey().getToAddress()
@ -177,18 +187,20 @@ public class TransactionOutput extends ChildMessage implements Serializable {
} }
} }
/** Returns the connected input. */ /**
* Returns the connected input.
*/
TransactionInput getSpentBy() { TransactionInput getSpentBy() {
return spentBy; return spentBy;
} }
/** /**
* Ensure object is fully parsed before invoking java serialization. The backing byte array * Ensure object is fully parsed before invoking java serialization. The backing byte array
* is transient so if the object has parseLazy = true and hasn't invoked checkParse yet * is transient so if the object has parseLazy = true and hasn't invoked checkParse yet
* then data will be lost during serialization. * then data will be lost during serialization.
*/ */
private void writeObject(ObjectOutputStream out) throws IOException { private void writeObject(ObjectOutputStream out) throws IOException {
checkParse(); checkParse();
out.defaultWriteObject(); out.defaultWriteObject();
} }
} }

View File

@ -24,7 +24,6 @@ public class UnknownMessage extends EmptyMessage {
super(params, payloadBytes, 0); super(params, payloadBytes, 0);
this.name = name; this.name = name;
} }
public String toString() { public String toString() {
return "Unknown message [" + name + "]: " + (bytes == null ? "" : Utils.bytesToHexString(bytes)); return "Unknown message [" + name + "]: " + (bytes == null ? "" : Utils.bytesToHexString(bytes));
@ -33,7 +32,4 @@ public class UnknownMessage extends EmptyMessage {
@Override @Override
public void parse() throws ProtocolException { public void parse() throws ProtocolException {
} }
} }

View File

@ -9,51 +9,51 @@ import java.util.Arrays;
* An unsynchronized implementation of ByteArrayOutputStream that will return the backing byte array if its length == size(). * An unsynchronized implementation of ByteArrayOutputStream that will return the backing byte array if its length == size().
* This avoids unneeded array copy where the BOS is simply being used to extract a byte array of known length from a * This avoids unneeded array copy where the BOS is simply being used to extract a byte array of known length from a
* 'serialized to stream' method. * 'serialized to stream' method.
* * <p/>
* Unless the final length can be accurately predicted the only performance this will yield is due to unsynchronized * Unless the final length can be accurately predicted the only performance this will yield is due to unsynchronized
* methods. * methods.
* @author git
* *
* @author git
*/ */
public class UnsafeByteArrayOutputStream extends ByteArrayOutputStream { public class UnsafeByteArrayOutputStream extends ByteArrayOutputStream {
public UnsafeByteArrayOutputStream() { public UnsafeByteArrayOutputStream() {
super(32); super(32);
} }
public UnsafeByteArrayOutputStream(int size) { public UnsafeByteArrayOutputStream(int size) {
super(size); super(size);
}
/**
* Writes the specified byte to this byte array output stream.
*
* @param b the byte to be written.
*/
public void write(int b) {
int newcount = count + 1;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
buf[count] = (byte)b;
count = newcount;
} }
/** /**
* Writes <code>len</code> bytes from the specified byte array * Writes the specified byte to this byte array output stream.
*
* @param b the byte to be written.
*/
public void write(int b) {
int newcount = count + 1;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
buf[count] = (byte) b;
count = newcount;
}
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to this byte array output stream. * starting at offset <code>off</code> to this byte array output stream.
* *
* @param b the data. * @param b the data.
* @param off the start offset in the data. * @param off the start offset in the data.
* @param len the number of bytes to write. * @param len the number of bytes to write.
*/ */
public void write(byte b[], int off, int len) { public void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) || if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) { ((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException(); throw new IndexOutOfBoundsException();
} else if (len == 0) { } else if (len == 0) {
return; return;
} }
int newcount = count + len; int newcount = count + len;
if (newcount > buf.length) { if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount)); buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
@ -61,52 +61,52 @@ public class UnsafeByteArrayOutputStream extends ByteArrayOutputStream {
System.arraycopy(b, off, buf, count, len); System.arraycopy(b, off, buf, count, len);
count = newcount; count = newcount;
} }
/** /**
* Writes the complete contents of this byte array output stream to * Writes the complete contents of this byte array output stream to
* the specified output stream argument, as if by calling the output * the specified output stream argument, as if by calling the output
* stream's write method using <code>out.write(buf, 0, count)</code>. * stream's write method using <code>out.write(buf, 0, count)</code>.
* *
* @param out the output stream to which to write the data. * @param out the output stream to which to write the data.
* @exception IOException if an I/O error occurs. * @throws IOException if an I/O error occurs.
*/ */
public void writeTo(OutputStream out) throws IOException { public void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count); out.write(buf, 0, count);
} }
/** /**
* Resets the <code>count</code> field of this byte array output * Resets the <code>count</code> field of this byte array output
* stream to zero, so that all currently accumulated output in the * stream to zero, so that all currently accumulated output in the
* output stream is discarded. The output stream can be used again, * output stream is discarded. The output stream can be used again,
* reusing the already allocated buffer space. * reusing the already allocated buffer space.
* *
* @see java.io.ByteArrayInputStream#count * @see java.io.ByteArrayInputStream#count
*/ */
public void reset() { public void reset() {
count = 0; count = 0;
} }
/** /**
* Creates a newly allocated byte array. Its size is the current * Creates a newly allocated byte array. Its size is the current
* size of this output stream and the valid contents of the buffer * size of this output stream and the valid contents of the buffer
* have been copied into it. * have been copied into it.
* *
* @return the current contents of this output stream, as a byte array. * @return the current contents of this output stream, as a byte array.
* @see java.io.ByteArrayOutputStream#size() * @see java.io.ByteArrayOutputStream#size()
*/ */
public byte toByteArray()[] { public byte toByteArray()[] {
return count == buf.length ? buf : Arrays.copyOf(buf, count); return count == buf.length ? buf : Arrays.copyOf(buf, count);
} }
/** /**
* Returns the current size of the buffer. * Returns the current size of the buffer.
* *
* @return the value of the <code>count</code> field, which is the number * @return the value of the <code>count</code> field, which is the number
* of valid bytes in this output stream. * of valid bytes in this output stream.
* @see java.io.ByteArrayOutputStream#count * @see java.io.ByteArrayOutputStream#count
*/ */
public int size() { public int size() {
return count; return count;
} }
} }

View File

@ -36,7 +36,7 @@ public class Utils {
/** /**
* How many "nanocoins" there are in a BitCoin. * How many "nanocoins" there are in a BitCoin.
* * <p/>
* A nanocoin is the smallest unit that can be transferred using BitCoin. * A nanocoin is the smallest unit that can be transferred using BitCoin.
* The term nanocoin is very misleading, though, because there are only 100 million * The term nanocoin is very misleading, though, because there are only 100 million
* of them in a coin (whereas one would expect 1 billion. * of them in a coin (whereas one would expect 1 billion.
@ -45,14 +45,16 @@ public class Utils {
/** /**
* How many "nanocoins" there are in 0.01 BitCoins. * How many "nanocoins" there are in 0.01 BitCoins.
* * <p/>
* A nanocoin is the smallest unit that can be transferred using BitCoin. * A nanocoin is the smallest unit that can be transferred using BitCoin.
* The term nanocoin is very misleading, though, because there are only 100 million * The term nanocoin is very misleading, though, because there are only 100 million
* of them in a coin (whereas one would expect 1 billion). * of them in a coin (whereas one would expect 1 billion).
*/ */
public static final BigInteger CENT = new BigInteger("1000000", 10); public static final BigInteger CENT = new BigInteger("1000000", 10);
/** Convert an amount expressed in the way humans are used to into nanocoins. */ /**
* Convert an amount expressed in the way humans are used to into nanocoins.
*/
public static BigInteger toNanoCoins(int coins, int cents) { public static BigInteger toNanoCoins(int coins, int cents) {
assert cents < 100; assert cents < 100;
BigInteger bi = BigInteger.valueOf(coins).multiply(COIN); BigInteger bi = BigInteger.valueOf(coins).multiply(COIN);
@ -62,40 +64,40 @@ public class Utils {
/** /**
* Convert an amount expressed in the way humans are used to into nanocoins.<p> * Convert an amount expressed in the way humans are used to into nanocoins.<p>
* * <p/>
* This takes string in a format understood by {@link BigDecimal#BigDecimal(String)}, * This takes string in a format understood by {@link BigDecimal#BigDecimal(String)},
* for example "0", "1", "0.10", "1.23E3", "1234.5E-5". * for example "0", "1", "0.10", "1.23E3", "1234.5E-5".
* *
* @throws ArithmeticException if you try to specify fractional nanocoins * @throws ArithmeticException if you try to specify fractional nanocoins
**/ */
public static BigInteger toNanoCoins(String coins){ public static BigInteger toNanoCoins(String coins) {
return new BigDecimal(coins).movePointRight(8).toBigIntegerExact(); return new BigDecimal(coins).movePointRight(8).toBigIntegerExact();
} }
public static void uint32ToByteArrayBE(long val, byte[] out, int offset) { public static void uint32ToByteArrayBE(long val, byte[] out, int offset) {
out[offset + 0] = (byte) (0xFF & (val >> 24)); out[offset + 0] = (byte) (0xFF & (val >> 24));
out[offset + 1] = (byte) (0xFF & (val >> 16)); out[offset + 1] = (byte) (0xFF & (val >> 16));
out[offset + 2] = (byte) (0xFF & (val >> 8)); out[offset + 2] = (byte) (0xFF & (val >> 8));
out[offset + 3] = (byte) (0xFF & (val >> 0)); out[offset + 3] = (byte) (0xFF & (val >> 0));
} }
public static void uint32ToByteArrayLE(long val, byte[] out, int offset) { public static void uint32ToByteArrayLE(long val, byte[] out, int offset) {
out[offset + 0] = (byte) (0xFF & (val >> 0)); out[offset + 0] = (byte) (0xFF & (val >> 0));
out[offset + 1] = (byte) (0xFF & (val >> 8)); out[offset + 1] = (byte) (0xFF & (val >> 8));
out[offset + 2] = (byte) (0xFF & (val >> 16)); out[offset + 2] = (byte) (0xFF & (val >> 16));
out[offset + 3] = (byte) (0xFF & (val >> 24)); out[offset + 3] = (byte) (0xFF & (val >> 24));
} }
public static void uint32ToByteStreamLE(long val, OutputStream stream) throws IOException { public static void uint32ToByteStreamLE(long val, OutputStream stream) throws IOException {
stream.write((int)(0xFF & (val >> 0))); stream.write((int) (0xFF & (val >> 0)));
stream.write((int)(0xFF & (val >> 8))); stream.write((int) (0xFF & (val >> 8)));
stream.write((int)(0xFF & (val >> 16))); stream.write((int) (0xFF & (val >> 16)));
stream.write((int)(0xFF & (val >> 24))); stream.write((int) (0xFF & (val >> 24)));
} }
public static void uint64ToByteStreamLE(BigInteger val, OutputStream stream) throws IOException { public static void uint64ToByteStreamLE(BigInteger val, OutputStream stream) throws IOException {
byte[] bytes = val.toByteArray(); byte[] bytes = val.toByteArray();
if (bytes.length > 8) { if (bytes.length > 8) {
throw new RuntimeException("Input too large to encode into a uint64"); throw new RuntimeException("Input too large to encode into a uint64");
} }
bytes = reverseBytes(bytes); bytes = reverseBytes(bytes);
@ -107,7 +109,7 @@ public class Utils {
} }
/** /**
* See {@link Utils#doubleDigest(byte[],int,int)}. * See {@link Utils#doubleDigest(byte[], int, int)}.
*/ */
public static byte[] doubleDigest(byte[] input) { public static byte[] doubleDigest(byte[] input) {
return doubleDigest(input, 0, input.length); return doubleDigest(input, 0, input.length);
@ -127,7 +129,7 @@ public class Utils {
throw new RuntimeException(e); // Cannot happen. throw new RuntimeException(e); // Cannot happen.
} }
} }
public static byte[] singleDigest(byte[] input, int offset, int length) { public static byte[] singleDigest(byte[] input, int offset, int length) {
try { try {
MessageDigest digest = MessageDigest.getInstance("SHA-256"); MessageDigest digest = MessageDigest.getInstance("SHA-256");
@ -154,12 +156,16 @@ public class Utils {
} }
} }
/** Work around lack of unsigned types in Java. */ /**
public static boolean isLessThanUnsigned(long n1, long n2) { * Work around lack of unsigned types in Java.
*/
public static boolean isLessThanUnsigned(long n1, long n2) {
return (n1 < n2) ^ ((n1 < 0) != (n2 < 0)); return (n1 < n2) ^ ((n1 < 0) != (n2 < 0));
} }
/** Returns the given byte array hex encoded. */ /**
* Returns the given byte array hex encoded.
*/
public static String bytesToHexString(byte[] bytes) { public static String bytesToHexString(byte[] bytes) {
StringBuffer buf = new StringBuffer(bytes.length * 2); StringBuffer buf = new StringBuffer(bytes.length * 2);
for (byte b : bytes) { for (byte b : bytes) {
@ -170,9 +176,11 @@ public class Utils {
} }
return buf.toString(); return buf.toString();
} }
/** Returns a copy of the given byte array in reverse order. */
/**
* Returns a copy of the given byte array in reverse order.
*/
public static byte[] reverseBytes(byte[] bytes) { public static byte[] reverseBytes(byte[] bytes) {
// We could use the XOR trick here but it's easier to understand if we don't. If we find this is really a // We could use the XOR trick here but it's easier to understand if we don't. If we find this is really a
// performance issue the matter can be revisited. // performance issue the matter can be revisited.
@ -183,21 +191,21 @@ public class Utils {
} }
public static long readUint32(byte[] bytes, int offset) { public static long readUint32(byte[] bytes, int offset) {
return ((bytes[offset++] & 0xFFL) << 0) | return ((bytes[offset++] & 0xFFL) << 0) |
((bytes[offset++] & 0xFFL) << 8) | ((bytes[offset++] & 0xFFL) << 8) |
((bytes[offset++] & 0xFFL) << 16) | ((bytes[offset++] & 0xFFL) << 16) |
((bytes[offset] & 0xFFL) << 24); ((bytes[offset] & 0xFFL) << 24);
} }
public static long readUint32BE(byte[] bytes, int offset) { public static long readUint32BE(byte[] bytes, int offset) {
return ((bytes[offset + 0] & 0xFFL) << 24) | return ((bytes[offset + 0] & 0xFFL) << 24) |
((bytes[offset + 1] & 0xFFL) << 16) | ((bytes[offset + 1] & 0xFFL) << 16) |
((bytes[offset + 2] & 0xFFL) << 8) | ((bytes[offset + 2] & 0xFFL) << 8) |
((bytes[offset + 3] & 0xFFL) << 0); ((bytes[offset + 3] & 0xFFL) << 0);
} }
public static int readUint16BE(byte[] bytes, int offset) { public static int readUint16BE(byte[] bytes, int offset) {
return ((bytes[offset] & 0xff) << 8) | bytes[offset + 1] & 0xff; return ((bytes[offset] & 0xff) << 8) | bytes[offset + 1] & 0xff;
} }
/** /**
@ -216,7 +224,9 @@ public class Utils {
} }
} }
/** Returns the given value in nanocoins as a 0.12 type string. */ /**
* Returns the given value in nanocoins as a 0.12 type string.
*/
public static String bitcoinValueToFriendlyString(BigInteger value) { public static String bitcoinValueToFriendlyString(BigInteger value) {
boolean negative = value.compareTo(BigInteger.ZERO) < 0; boolean negative = value.compareTo(BigInteger.ZERO) < 0;
if (negative) if (negative)
@ -225,7 +235,7 @@ public class Utils {
BigInteger cents = value.remainder(COIN); BigInteger cents = value.remainder(COIN);
return String.format("%s%d.%02d", negative ? "-" : "", coins.intValue(), cents.intValue() / 1000000); return String.format("%s%d.%02d", negative ? "-" : "", coins.intValue(), cents.intValue() / 1000000);
} }
/** /**
* MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of * MPI encoded numbers are produced by the OpenSSL BN_bn2mpi function. They consist of
* a 4 byte big endian length field, followed by the stated number of bytes representing * a 4 byte big endian length field, followed by the stated number of bytes representing
@ -241,19 +251,23 @@ public class Utils {
// The representation of nBits uses another home-brew encoding, as a way to represent a large // The representation of nBits uses another home-brew encoding, as a way to represent a large
// hash value in only 32 bits. // hash value in only 32 bits.
static BigInteger decodeCompactBits(long compact) { static BigInteger decodeCompactBits(long compact) {
int size = ((int)(compact >> 24)) & 0xFF; int size = ((int) (compact >> 24)) & 0xFF;
byte[] bytes = new byte[4 + size]; byte[] bytes = new byte[4 + size];
bytes[3] = (byte) size; bytes[3] = (byte) size;
if (size >= 1) bytes[4] = (byte) ((compact >> 16) & 0xFF); if (size >= 1) bytes[4] = (byte) ((compact >> 16) & 0xFF);
if (size >= 2) bytes[5] = (byte) ((compact >> 8) & 0xFF); if (size >= 2) bytes[5] = (byte) ((compact >> 8) & 0xFF);
if (size >= 3) bytes[6] = (byte) ((compact >> 0) & 0xFF); if (size >= 3) bytes[6] = (byte) ((compact >> 0) & 0xFF);
return decodeMPI(bytes); return decodeMPI(bytes);
} }
/** If non-null, overrides the return value of now(). */ /**
* If non-null, overrides the return value of now().
*/
public static Date mockTime; public static Date mockTime;
/** Advances (or rewinds) the mock clock by the given number of seconds. */ /**
* Advances (or rewinds) the mock clock by the given number of seconds.
*/
public static Date rollMockClock(int seconds) { public static Date rollMockClock(int seconds) {
if (mockTime == null) if (mockTime == null)
mockTime = new Date(); mockTime = new Date();
@ -261,7 +275,9 @@ public class Utils {
return mockTime; return mockTime;
} }
/** Returns the current time, or a mocked out equivalent. */ /**
* Returns the current time, or a mocked out equivalent.
*/
public static Date now() { public static Date now() {
if (mockTime != null) if (mockTime != null)
return mockTime; return mockTime;

View File

@ -20,7 +20,7 @@ import static com.google.bitcoin.core.Utils.isLessThanUnsigned;
public class VarInt { public class VarInt {
public final long value; public final long value;
public VarInt(long value) { public VarInt(long value) {
this.value = value; this.value = value;
} }
@ -44,11 +44,11 @@ public class VarInt {
} }
this.value = val; this.value = val;
} }
public int getSizeInBytes() { public int getSizeInBytes() {
return sizeOf(value); return sizeOf(value);
} }
public static int sizeOf(int value) { public static int sizeOf(int value) {
// Java doesn't have the actual value of MAX_INT, as all types in Java are signed. // Java doesn't have the actual value of MAX_INT, as all types in Java are signed.
if (value < 253) if (value < 253)
@ -57,7 +57,7 @@ public class VarInt {
return 3; // 1 marker + 2 data bytes return 3; // 1 marker + 2 data bytes
return 5; // 1 marker + 4 data bytes return 5; // 1 marker + 4 data bytes
} }
public static int sizeOf(long value) { public static int sizeOf(long value) {
// Java doesn't have the actual value of MAX_INT, as all types in Java are signed. // Java doesn't have the actual value of MAX_INT, as all types in Java are signed.
if (isLessThanUnsigned(value, 253)) if (isLessThanUnsigned(value, 253))
@ -73,13 +73,13 @@ public class VarInt {
public byte[] encode() { public byte[] encode() {
return encodeBE(); return encodeBE();
} }
public byte[] encodeBE() { public byte[] encodeBE() {
if (isLessThanUnsigned(value, 253)) { if (isLessThanUnsigned(value, 253)) {
return new byte[] { (byte)value }; return new byte[]{(byte) value};
} else if (isLessThanUnsigned(value, 65536)) { } else if (isLessThanUnsigned(value, 65536)) {
return new byte[] { (byte) 253, (byte) (value), (byte) (value >> 8) }; return new byte[]{(byte) 253, (byte) (value), (byte) (value >> 8)};
} else if (isLessThanUnsigned(value, 4294967295L)) { } else if (isLessThanUnsigned(value, 4294967295L)) {
byte[] bytes = new byte[5]; byte[] bytes = new byte[5];
bytes[0] = (byte) 254; bytes[0] = (byte) 254;

View File

@ -21,18 +21,18 @@ package com.google.bitcoin.core;
* received from their peer. * received from their peer.
*/ */
public class VersionAck extends EmptyMessage { public class VersionAck extends EmptyMessage {
public VersionAck() { public VersionAck() {
} }
// this is needed by the BitcoinSerializer // this is needed by the BitcoinSerializer
public VersionAck(NetworkParameters params, byte[] payload) { public VersionAck(NetworkParameters params, byte[] payload) {
} }
@Override @Override
void parse() throws ProtocolException { void parse() throws ProtocolException {
// nothing to parse for now // nothing to parse for now
} }
} }

View File

@ -29,28 +29,40 @@ public class VersionMessage extends Message {
*/ */
public static final int NODE_NETWORK = 1; public static final int NODE_NETWORK = 1;
/** The version number of the protocol spoken. */ /**
* The version number of the protocol spoken.
*/
public int clientVersion; public int clientVersion;
/** Flags defining what is supported. Right now {@link #NODE_NETWORK} is the only flag defined. */ /**
* Flags defining what is supported. Right now {@link #NODE_NETWORK} is the only flag defined.
*/
public long localServices; public long localServices;
/** What the other side believes the current time to be, in seconds. */ /**
* What the other side believes the current time to be, in seconds.
*/
public long time; public long time;
/** What the other side believes the address of this program is. Not used. */ /**
* What the other side believes the address of this program is. Not used.
*/
public PeerAddress myAddr; public PeerAddress myAddr;
/** What the other side believes their own address is. Not used. */ /**
* What the other side believes their own address is. Not used.
*/
public PeerAddress theirAddr; public PeerAddress theirAddr;
/** /**
* An additional string that today the official client sets to the empty string. We treat it as something like an * An additional string that today the official client sets to the empty string. We treat it as something like an
* HTTP User-Agent header. * HTTP User-Agent header.
*/ */
public String subVer; public String subVer;
/** How many blocks are in the chain, according to the other side. */ /**
* How many blocks are in the chain, according to the other side.
*/
public long bestHeight; 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);
} }
/** /**
* It doesn't really make sense to ever lazily parse a version message or to retain the backing bytes. * 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 * If you're receiving this on the wire you need to check the protocol version and it will never need to be sent
@ -59,7 +71,6 @@ public class VersionMessage extends Message {
// public VersionMessage(NetworkParameters params, byte[] msg, boolean parseLazy, boolean parseRetain) throws ProtocolException { // public VersionMessage(NetworkParameters params, byte[] msg, boolean parseLazy, boolean parseRetain) throws ProtocolException {
// super(params, msg, 0, parseLazy, parseRetain); // super(params, msg, 0, parseLazy, parseRetain);
// } // }
public VersionMessage(NetworkParameters params, int newBestHeight) { public VersionMessage(NetworkParameters params, int newBestHeight) {
super(params); super(params);
clientVersion = NetworkParameters.PROTOCOL_VERSION; clientVersion = NetworkParameters.PROTOCOL_VERSION;
@ -75,25 +86,25 @@ public class VersionMessage extends Message {
} }
subVer = "BitCoinJ 0.3-SNAPSHOT"; subVer = "BitCoinJ 0.3-SNAPSHOT";
bestHeight = newBestHeight; bestHeight = newBestHeight;
length = 84; length = 84;
if (protocolVersion > 31402) if (protocolVersion > 31402)
length += 8; length += 8;
length += subVer == null ? 1 : VarInt.sizeOf(subVer.length()) + subVer.length(); length += subVer == null ? 1 : VarInt.sizeOf(subVer.length()) + subVer.length();
} }
@Override @Override
protected void parseLite() throws ProtocolException { protected void parseLite() throws ProtocolException {
//NOP. VersionMessage is never lazy parsed. //NOP. VersionMessage is never lazy parsed.
} }
@Override @Override
public void parse() throws ProtocolException { public void parse() throws ProtocolException {
if (parsed) if (parsed)
return; return;
parsed = true; parsed = true;
clientVersion = (int) readUint32(); clientVersion = (int) readUint32();
localServices = readUint64().longValue(); localServices = readUint64().longValue();
time = readUint64().longValue(); time = readUint64().longValue();
myAddr = new PeerAddress(params, bytes, cursor, 0); myAddr = new PeerAddress(params, bytes, cursor, 0);
@ -110,7 +121,7 @@ public class VersionMessage extends Message {
bestHeight = readUint32(); bestHeight = readUint32();
length = cursor - offset; length = cursor - offset;
} }
@Override @Override
public void bitcoinSerializeToStream(OutputStream buf) throws IOException { public void bitcoinSerializeToStream(OutputStream buf) throws IOException {
Utils.uint32ToByteStreamLE(clientVersion, buf); Utils.uint32ToByteStreamLE(clientVersion, buf);
@ -154,47 +165,47 @@ public class VersionMessage extends Message {
if (!(o instanceof VersionMessage)) return false; if (!(o instanceof VersionMessage)) return false;
VersionMessage other = (VersionMessage) o; VersionMessage other = (VersionMessage) o;
return other.bestHeight == bestHeight && return other.bestHeight == bestHeight &&
other.clientVersion == clientVersion && other.clientVersion == clientVersion &&
other.localServices == localServices && other.localServices == localServices &&
other.time == time && other.time == time &&
other.subVer.equals(subVer) && other.subVer.equals(subVer) &&
other.myAddr.equals(myAddr) && other.myAddr.equals(myAddr) &&
other.theirAddr.equals(theirAddr); other.theirAddr.equals(theirAddr);
} }
/** /**
* VersionMessage does not handle cached byte array so should not have a cached checksum. * VersionMessage does not handle cached byte array so should not have a cached checksum.
*/ */
@Override @Override
byte[] getChecksum() { byte[] getChecksum() {
return null; return null;
} }
/** /**
* VersionMessage does not handle cached byte array so should not have a cached checksum. * VersionMessage does not handle cached byte array so should not have a cached checksum.
*/ */
@Override @Override
void setChecksum(byte[] checksum) { void setChecksum(byte[] checksum) {
}
@Override }
@Override
public int hashCode() { public int hashCode() {
return (int)bestHeight ^ clientVersion ^ (int)localServices ^ (int)time ^ subVer.hashCode() ^ myAddr.hashCode() return (int) bestHeight ^ clientVersion ^ (int) localServices ^ (int) time ^ subVer.hashCode() ^ myAddr.hashCode()
^ theirAddr.hashCode(); ^ theirAddr.hashCode();
} }
public String toString() { public String toString() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("\n"); sb.append("\n");
sb.append("client version: ").append(clientVersion).append("\n"); sb.append("client version: ").append(clientVersion).append("\n");
sb.append("local services: ").append(localServices).append("\n"); sb.append("local services: ").append(localServices).append("\n");
sb.append("time: ").append(time).append("\n"); sb.append("time: ").append(time).append("\n");
sb.append("my addr: ").append(myAddr).append("\n"); sb.append("my addr: ").append(myAddr).append("\n");
sb.append("their addr: ").append(theirAddr).append("\n"); sb.append("their addr: ").append(theirAddr).append("\n");
sb.append("sub version: ").append(subVer).append("\n"); sb.append("sub version: ").append(subVer).append("\n");
sb.append("best height: ").append(bestHeight).append("\n"); sb.append("best height: ").append(bestHeight).append("\n");
return sb.toString(); return sb.toString();
} }
} }

View File

@ -20,9 +20,9 @@ import java.util.Arrays;
/** /**
* <p>In Bitcoin the following format is often used to represent some type of key:</p> * <p>In Bitcoin the following format is often used to represent some type of key:</p>
* * <p/>
* <pre>[one version byte] [data bytes] [4 checksum bytes]</pre> * <pre>[one version byte] [data bytes] [4 checksum bytes]</pre>
* * <p/>
* <p>and the result is then Base58 encoded. This format is used for addresses, and private keys exported using the * <p>and the result is then Base58 encoded. This format is used for addresses, and private keys exported using the
* dumpprivkey command.</p> * dumpprivkey command.</p>
*/ */
@ -48,7 +48,7 @@ public class VersionedChecksummedBytes {
// A stringified buffer is: // A stringified buffer is:
// 1 byte version + data bytes + 4 bytes check code (a truncated hash) // 1 byte version + data bytes + 4 bytes check code (a truncated hash)
byte[] addressBytes = new byte[1 + bytes.length + 4]; byte[] addressBytes = new byte[1 + bytes.length + 4];
addressBytes[0] = (byte)version; addressBytes[0] = (byte) version;
System.arraycopy(bytes, 0, addressBytes, 1, bytes.length); System.arraycopy(bytes, 0, addressBytes, 1, bytes.length);
byte[] check = Utils.doubleDigest(addressBytes, 0, bytes.length + 1); byte[] check = Utils.doubleDigest(addressBytes, 0, bytes.length + 1);
System.arraycopy(check, 0, addressBytes, bytes.length + 1, 4); System.arraycopy(check, 0, addressBytes, bytes.length + 1, 4);
@ -70,6 +70,7 @@ public class VersionedChecksummedBytes {
/** /**
* Returns the "version" or "header" byte: the first byte of the data. This is used to disambiguate what the * Returns the "version" or "header" byte: the first byte of the data. This is used to disambiguate what the
* contents apply to, for example, which network the key or address is valid on. * contents apply to, for example, which network the key or address is valid on.
*
* @return A positive number between 0 and 255. * @return A positive number between 0 and 255.
*/ */
public int getVersion() { public int getVersion() {

View File

@ -28,7 +28,7 @@ import static com.google.bitcoin.core.Utils.bitcoinValueToFriendlyString;
/** /**
* A Wallet stores keys and a record of transactions that have not yet been spent. Thus, it is capable of * A Wallet stores keys and a record of transactions that have not yet been spent. Thus, it is capable of
* providing transactions on demand that meet a given combined value.<p> * providing transactions on demand that meet a given combined value.<p>
* * <p/>
* The Wallet is read and written from disk, so be sure to follow the Java serialization versioning rules here. We * The Wallet is read and written from disk, so be sure to follow the Java serialization versioning rules here. We
* use the built in Java serialization to avoid the need to pull in a potentially large (code-size) third party * use the built in Java serialization to avoid the need to pull in a potentially large (code-size) third party
* serialization library.<p> * serialization library.<p>
@ -86,7 +86,7 @@ public class Wallet implements Serializable {
* to pay other people and so count towards our balance. Transactions only appear in this map if they are part * to pay other people and so count towards our balance. Transactions only appear in this map if they are part
* of the best chain. Transactions we have broacast that are not confirmed yet appear in pending even though they * of the best chain. Transactions we have broacast that are not confirmed yet appear in pending even though they
* may have unspent "change" outputs.<p> * may have unspent "change" outputs.<p>
* * <p/>
* Note: for now we will not allow spends of transactions that did not make it into the block chain. The code * Note: for now we will not allow spends of transactions that did not make it into the block chain. The code
* that handles this in BitCoin C++ is complicated. Satoshis code will not allow you to spend unconfirmed coins, * that handles this in BitCoin C++ is complicated. Satoshis code will not allow you to spend unconfirmed coins,
* however, it does seem to support dependency resolution entirely within the context of the memory pool so * however, it does seem to support dependency resolution entirely within the context of the memory pool so
@ -100,7 +100,7 @@ public class Wallet implements Serializable {
* the time to create a spend does not grow infinitely as wallets become more used. Some of these transactions * the time to create a spend does not grow infinitely as wallets become more used. Some of these transactions
* may not have appeared in a block yet if they were created by us to spend coins and that spend is still being * may not have appeared in a block yet if they were created by us to spend coins and that spend is still being
* worked on by miners.<p> * worked on by miners.<p>
* * <p/>
* Transactions only appear in this map if they are part of the best chain. * Transactions only appear in this map if they are part of the best chain.
*/ */
final Map<Sha256Hash, Transaction> spent; final Map<Sha256Hash, Transaction> spent;
@ -109,7 +109,7 @@ public class Wallet implements Serializable {
* An inactive transaction is one that is seen only in a block that is not a part of the best chain. We keep it * An inactive transaction is one that is seen only in a block that is not a part of the best chain. We keep it
* around in case a re-org promotes a different chain to be the best. In this case some (not necessarily all) * around in case a re-org promotes a different chain to be the best. In this case some (not necessarily all)
* inactive transactions will be moved out to unspent and spent, and some might be moved in.<p> * inactive transactions will be moved out to unspent and spent, and some might be moved in.<p>
* * <p/>
* Note that in the case where a transaction appears in both the best chain and a side chain as well, it is not * Note that in the case where a transaction appears in both the best chain and a side chain as well, it is not
* placed in this map. It's an error for a transaction to be in both the inactive pool and unspent/spent. * placed in this map. It's an error for a transaction to be in both the inactive pool and unspent/spent.
*/ */
@ -123,7 +123,9 @@ public class Wallet implements Serializable {
*/ */
private Map<Sha256Hash, Transaction> dead; private Map<Sha256Hash, Transaction> dead;
/** A list of public/private EC keys owned by this user. */ /**
* A list of public/private EC keys owned by this user.
*/
public final ArrayList<ECKey> keychain; public final ArrayList<ECKey> keychain;
private final NetworkParameters params; private final NetworkParameters params;
@ -198,16 +200,16 @@ public class Wallet implements Serializable {
/** /**
* Called by the {@link BlockChain} when we receive a new block that sends coins to one of our addresses or * Called by the {@link BlockChain} when we receive a new block that sends coins to one of our addresses or
* spends coins from one of our addresses (note that a single transaction can do both).<p> * spends coins from one of our addresses (note that a single transaction can do both).<p>
* * <p/>
* This is necessary for the internal book-keeping Wallet does. When a transaction is received that sends us * This is necessary for the internal book-keeping Wallet does. When a transaction is received that sends us
* coins it is added to a pool so we can use it later to create spends. When a transaction is received that * coins it is added to a pool so we can use it later to create spends. When a transaction is received that
* consumes outputs they are marked as spent so they won't be used in future.<p> * consumes outputs they are marked as spent so they won't be used in future.<p>
* * <p/>
* A transaction that spends our own coins can be received either because a spend we created was accepted by the * A transaction that spends our own coins can be received either because a spend we created was accepted by the
* network and thus made it into a block, or because our keys are being shared between multiple instances and * network and thus made it into a block, or because our keys are being shared between multiple instances and
* some other node spent the coins instead. We still have to know about that to avoid accidentally trying to * some other node spent the coins instead. We still have to know about that to avoid accidentally trying to
* double spend.<p> * double spend.<p>
* * <p/>
* A transaction may be received multiple times if is included into blocks in parallel chains. The blockType * A transaction may be received multiple times if is included into blocks in parallel chains. The blockType
* parameter describes whether the containing block is on the main/best chain or whether it's on a presently * parameter describes whether the containing block is on the main/best chain or whether it's on a presently
* inactive side chain. We must still record these transactions and the blocks they appear in because a future * inactive side chain. We must still record these transactions and the blocks they appear in because a future
@ -232,7 +234,7 @@ public class Wallet implements Serializable {
BigInteger valueDifference = valueSentToMe.subtract(valueSentFromMe); BigInteger valueDifference = valueSentToMe.subtract(valueSentFromMe);
if (!reorg) { if (!reorg) {
log.info("Received tx{} for {} BTC: {}", new Object[] { sideChain ? " on a side chain" : "", log.info("Received tx{} for {} BTC: {}", new Object[]{sideChain ? " on a side chain" : "",
bitcoinValueToFriendlyString(valueDifference), tx.getHashAsString()}); bitcoinValueToFriendlyString(valueDifference), tx.getHashAsString()});
} }
@ -384,7 +386,9 @@ public class Wallet implements Serializable {
} }
} }
/** If the transactions outputs are all marked as spent, and it's in the unspent map, move it. */ /**
* If the transactions outputs are all marked as spent, and it's in the unspent map, move it.
*/
private void maybeMoveTxToSpent(Transaction tx, String context) { private void maybeMoveTxToSpent(Transaction tx, String context) {
if (tx.isEveryOutputSpent()) { if (tx.isEveryOutputSpent()) {
// There's nothing left I can spend in this transaction. // There's nothing left I can spend in this transaction.
@ -401,7 +405,7 @@ public class Wallet implements Serializable {
/** /**
* Adds an event listener object. Methods on this object are called when something interesting happens, * Adds an event listener object. Methods on this object are called when something interesting happens,
* like receiving money.<p> * like receiving money.<p>
* * <p/>
* Threading: Event listener methods are dispatched on library provided threads and the both the wallet and the * Threading: Event listener methods are dispatched on library provided threads and the both the wallet and the
* listener objects are locked during dispatch, so your listeners do not have to be thread safe. However they * listener objects are locked during dispatch, so your listeners do not have to be thread safe. However they
* should not block as the Peer will be unresponsive to network traffic whilst your listener is running. * should not block as the Peer will be unresponsive to network traffic whilst your listener is running.
@ -439,7 +443,7 @@ public class Wallet implements Serializable {
/** /**
* Returns a set of all transactions in the wallet. * Returns a set of all transactions in the wallet.
* *
* @param includeDead If true, transactions that were overridden by a double spend are included. * @param includeDead If true, transactions that were overridden by a double spend are included.
* @param includeInactive If true, transactions that are on side chains (are unspendable) are included. * @param includeInactive If true, transactions that are on side chains (are unspendable) are included.
*/ */
public Set<Transaction> getTransactions(boolean includeDead, boolean includeInactive) { public Set<Transaction> getTransactions(boolean includeDead, boolean includeInactive) {
@ -454,7 +458,9 @@ public class Wallet implements Serializable {
return all; return all;
} }
/** Returns all non-dead, active transactions ordered by recency. */ /**
* Returns all non-dead, active transactions ordered by recency.
*/
public List<Transaction> getTransactionsByTime() { public List<Transaction> getTransactionsByTime() {
return getRecentTransactions(0, false); return getRecentTransactions(0, false);
} }
@ -462,7 +468,7 @@ public class Wallet implements Serializable {
/** /**
* Returns an list of N transactions, ordered by increasing age. Transactions on side chains are not included. * Returns an list of N transactions, ordered by increasing age. Transactions on side chains are not included.
* Dead transactions (overridden by double spends) are optionally included. <p> * Dead transactions (overridden by double spends) are optionally included. <p>
* * <p/>
* Note: the current implementation is O(num transactions in wallet). Regardless of how many transactions are * Note: the current implementation is O(num transactions in wallet). Regardless of how many transactions are
* requested, the cost is always the same. In future, requesting smaller numbers of transactions may be faster * requested, the cost is always the same. In future, requesting smaller numbers of transactions may be faster
* depending on how the wallet is implemented (eg if backed by a database). * depending on how the wallet is implemented (eg if backed by a database).
@ -501,12 +507,18 @@ public class Wallet implements Serializable {
int getPoolSize(Pool pool) { int getPoolSize(Pool pool) {
switch (pool) { switch (pool) {
case UNSPENT: return unspent.size(); case UNSPENT:
case SPENT: return spent.size(); return unspent.size();
case PENDING: return pending.size(); case SPENT:
case INACTIVE: return inactive.size(); return spent.size();
case DEAD: return dead.size(); case PENDING:
case ALL: return unspent.size() + spent.size() + pending.size() + inactive.size() + dead.size(); return pending.size();
case INACTIVE:
return inactive.size();
case DEAD:
return dead.size();
case ALL:
return unspent.size() + spent.size() + pending.size() + inactive.size() + dead.size();
} }
throw new RuntimeException("Unreachable"); throw new RuntimeException("Unreachable");
} }
@ -514,12 +526,12 @@ public class Wallet implements Serializable {
/** /**
* Statelessly creates a transaction that sends the given number of nanocoins to address. The change is sent to * Statelessly creates a transaction that sends the given number of nanocoins to address. The change is sent to
* the first address in the wallet, so you must have added at least one key.<p> * the first address in the wallet, so you must have added at least one key.<p>
* * <p/>
* This method is stateless in the sense that calling it twice with the same inputs will result in two * This method is stateless in the sense that calling it twice with the same inputs will result in two
* Transaction objects which are equal. The wallet is not updated to track its pending status or to mark the * Transaction objects which are equal. The wallet is not updated to track its pending status or to mark the
* coins as spent until confirmSend is called on the result. * coins as spent until confirmSend is called on the result.
*/ */
synchronized Transaction createSend(Address address, BigInteger nanocoins) { synchronized Transaction createSend(Address address, BigInteger nanocoins) {
// For now let's just pick the first key in our keychain. In future we might want to do something else to // For now let's just pick the first key in our keychain. In future we might want to do something else to
// give the user better privacy here, eg in incognito mode. // give the user better privacy here, eg in incognito mode.
assert keychain.size() > 0 : "Can't send value without an address to use for receiving change"; assert keychain.size() > 0 : "Can't send value without an address to use for receiving change";
@ -530,8 +542,8 @@ public class Wallet implements Serializable {
/** /**
* Sends coins to the given address, via the given {@link PeerGroup}. * Sends coins to the given address, via the given {@link PeerGroup}.
* Change is returned to the first key in the wallet. * Change is returned to the first key in the wallet.
* *
* @param to Which address to send coins to. * @param to Which address to send coins to.
* @param nanocoins How many nanocoins to send. You can use Utils.toNanoCoins() to calculate this. * @param nanocoins How many nanocoins to send. You can use Utils.toNanoCoins() to calculate this.
* @return The {@link Transaction} that was created or null if there was insufficient balance to send the coins. * @return The {@link Transaction} that was created or null if there was insufficient balance to send the coins.
* @throws IOException if there was a problem broadcasting the transaction * @throws IOException if there was a problem broadcasting the transaction
@ -543,7 +555,7 @@ public class Wallet implements Serializable {
if (!peerGroup.broadcastTransaction(tx)) { if (!peerGroup.broadcastTransaction(tx)) {
throw new IOException("Failed to broadcast tx to all connected peers"); throw new IOException("Failed to broadcast tx to all connected peers");
} }
// TODO - retry logic // TODO - retry logic
confirmSend(tx); confirmSend(tx);
return tx; return tx;
@ -552,8 +564,8 @@ public class Wallet implements Serializable {
/** /**
* Sends coins to the given address, via the given {@link Peer}. * Sends coins to the given address, via the given {@link Peer}.
* Change is returned to the first key in the wallet. * Change is returned to the first key in the wallet.
* *
* @param to Which address to send coins to. * @param to Which address to send coins to.
* @param nanocoins How many nanocoins to send. You can use Utils.toNanoCoins() to calculate this. * @param nanocoins How many nanocoins to send. You can use Utils.toNanoCoins() to calculate this.
* @return The {@link Transaction} that was created or null if there was insufficient balance to send the coins. * @return The {@link Transaction} that was created or null if there was insufficient balance to send the coins.
* @throws IOException if there was a problem broadcasting the transaction * @throws IOException if there was a problem broadcasting the transaction
@ -569,16 +581,16 @@ public class Wallet implements Serializable {
/** /**
* Creates a transaction that sends $coins.$cents BTC to the given address.<p> * Creates a transaction that sends $coins.$cents BTC to the given address.<p>
* * <p/>
* IMPORTANT: This method does NOT update the wallet. If you call createSend again you may get two transactions * IMPORTANT: This method does NOT update the wallet. If you call createSend again you may get two transactions
* that spend the same coins. You have to call confirmSend on the created transaction to prevent this, * that spend the same coins. You have to call confirmSend on the created transaction to prevent this,
* but that should only occur once the transaction has been accepted by the network. This implies you cannot have * but that should only occur once the transaction has been accepted by the network. This implies you cannot have
* more than one outstanding sending tx at once. * more than one outstanding sending tx at once.
* *
* @param address The BitCoin address to send the money to. * @param address The BitCoin address to send the money to.
* @param nanocoins How much currency to send, in nanocoins. * @param nanocoins How much currency to send, in nanocoins.
* @param changeAddress Which address to send the change to, in case we can't make exactly the right value from * @param changeAddress Which address to send the change to, in case we can't make exactly the right value from
* our coins. This should be an address we own (is in the keychain). * our coins. This should be an address we own (is in the keychain).
* @return a new {@link Transaction} or null if we cannot afford this send. * @return a new {@link Transaction} or null if we cannot afford this send.
*/ */
synchronized Transaction createSend(Address address, BigInteger nanocoins, Address changeAddress) { synchronized Transaction createSend(Address address, BigInteger nanocoins, Address changeAddress) {
@ -643,6 +655,7 @@ public class Wallet implements Serializable {
/** /**
* Locates a keypair from the keychain given the hash of the public key. This is needed when finding out which * Locates a keypair from the keychain given the hash of the public key. This is needed when finding out which
* key we need to use to redeem a transaction output. * key we need to use to redeem a transaction output.
*
* @return ECKey object or null if no such key was found. * @return ECKey object or null if no such key was found.
*/ */
public synchronized ECKey findKeyFromPubHash(byte[] pubkeyHash) { public synchronized ECKey findKeyFromPubHash(byte[] pubkeyHash) {
@ -652,13 +665,16 @@ public class Wallet implements Serializable {
return null; return null;
} }
/** Returns true if this wallet contains a public key which hashes to the given hash. */ /**
* Returns true if this wallet contains a public key which hashes to the given hash.
*/
public synchronized boolean isPubKeyHashMine(byte[] pubkeyHash) { public synchronized boolean isPubKeyHashMine(byte[] pubkeyHash) {
return findKeyFromPubHash(pubkeyHash) != null; return findKeyFromPubHash(pubkeyHash) != null;
} }
/** /**
* Locates a keypair from the keychain given the raw public key bytes. * Locates a keypair from the keychain given the raw public key bytes.
*
* @return ECKey or null if no such key was found. * @return ECKey or null if no such key was found.
*/ */
public synchronized ECKey findKeyFromPubKey(byte[] pubkey) { public synchronized ECKey findKeyFromPubKey(byte[] pubkey) {
@ -668,7 +684,9 @@ public class Wallet implements Serializable {
return null; return null;
} }
/** Returns true if this wallet contains a keypair with the given public key. */ /**
* Returns true if this wallet contains a keypair with the given public key.
*/
public synchronized boolean isPubKeyMine(byte[] pubkey) { public synchronized boolean isPubKeyMine(byte[] pubkey) {
return findKeyFromPubKey(pubkey) != null; return findKeyFromPubKey(pubkey) != null;
} }
@ -676,7 +694,7 @@ public class Wallet implements Serializable {
/** /**
* It's possible to calculate a wallets balance from multiple points of view. This enum selects which * It's possible to calculate a wallets balance from multiple points of view. This enum selects which
* getBalance() should use.<p> * getBalance() should use.<p>
* * <p/>
* Consider a real-world example: you buy a snack costing $5 but you only have a $10 bill. At the start you have * Consider a real-world example: you buy a snack costing $5 but you only have a $10 bill. At the start you have
* $10 viewed from every possible angle. After you order the snack you hand over your $10 bill. From the * $10 viewed from every possible angle. After you order the snack you hand over your $10 bill. From the
* perspective of your wallet you have zero dollars (AVAILABLE). But you know in a few seconds the shopkeeper * perspective of your wallet you have zero dollars (AVAILABLE). But you know in a few seconds the shopkeeper
@ -694,12 +712,14 @@ public class Wallet implements Serializable {
* spent by pending transactions, but not including the outputs of those pending transactions. * spent by pending transactions, but not including the outputs of those pending transactions.
*/ */
AVAILABLE AVAILABLE
}; }
;
/** /**
* Returns the AVAILABLE balance of this wallet. See {@link BalanceType#AVAILABLE} for details on what this * Returns the AVAILABLE balance of this wallet. See {@link BalanceType#AVAILABLE} for details on what this
* means.<p> * means.<p>
* * <p/>
* Note: the estimated balance is usually the one you want to show to the end user - however attempting to * Note: the estimated balance is usually the one you want to show to the end user - however attempting to
* actually spend these coins may result in temporary failure. This method returns how much you can safely * actually spend these coins may result in temporary failure. This method returns how much you can safely
* provide to {@link Wallet#createSend(Address, java.math.BigInteger)}. * provide to {@link Wallet#createSend(Address, java.math.BigInteger)}.
@ -781,7 +801,7 @@ public class Wallet implements Serializable {
* we need to go through our transactions and find out if any have become invalid. It's possible for our balance * we need to go through our transactions and find out if any have become invalid. It's possible for our balance
* to go down in this case: money we thought we had can suddenly vanish if the rest of the network agrees it * to go down in this case: money we thought we had can suddenly vanish if the rest of the network agrees it
* should be so.<p> * should be so.<p>
* * <p/>
* The oldBlocks/newBlocks lists are ordered height-wise from top first to bottom last. * The oldBlocks/newBlocks lists are ordered height-wise from top first to bottom last.
*/ */
synchronized void reorganize(List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks) throws VerificationException { synchronized void reorganize(List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks) throws VerificationException {

View File

@ -31,23 +31,23 @@ public interface WalletEventListener {
* register the event listener after the chain is downloaded. It's safe to use methods of wallet during the * register the event listener after the chain is downloaded. It's safe to use methods of wallet during the
* execution of this callback. * execution of this callback.
* *
* @param wallet The wallet object that received the coins/ * @param wallet The wallet object that received the coins/
* @param tx The transaction which sent us the coins. * @param tx The transaction which sent us the coins.
* @param prevBalance Balance before the coins were received. * @param prevBalance Balance before the coins were received.
* @param newBalance Current balance of the wallet. * @param newBalance Current balance of the wallet.
*/ */
void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance); void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance);
/** /**
* This is called on a Peer thread when a block is received that triggers a block chain re-organization.<p> * This is called on a Peer thread when a block is received that triggers a block chain re-organization.<p>
* * <p/>
* A re-organize means that the consensus (chain) of the network has diverged and now changed from what we * A re-organize means that the consensus (chain) of the network has diverged and now changed from what we
* believed it was previously. Usually this won't matter because the new consensus will include all our old * believed it was previously. Usually this won't matter because the new consensus will include all our old
* transactions assuming we are playing by the rules. However it's theoretically possible for our balance to * transactions assuming we are playing by the rules. However it's theoretically possible for our balance to
* change in arbitrary ways, most likely, we could lose some money we thought we had.<p> * change in arbitrary ways, most likely, we could lose some money we thought we had.<p>
* * <p/>
* It is safe to use methods of wallet whilst inside this callback. * It is safe to use methods of wallet whilst inside this callback.
* * <p/>
* TODO: Finish this interface. * TODO: Finish this interface.
*/ */
void onReorganize(Wallet wallet); void onReorganize(Wallet wallet);
@ -55,13 +55,13 @@ public interface WalletEventListener {
/** /**
* This is called on a Peer thread when a transaction becomes <i>dead</i>. A dead transaction is one that has * This is called on a Peer thread when a transaction becomes <i>dead</i>. A dead transaction is one that has
* been overridden by a double spend from the network and so will never confirm no matter how long you wait.<p> * been overridden by a double spend from the network and so will never confirm no matter how long you wait.<p>
* * <p/>
* A dead transaction can occur if somebody is attacking the network, or by accident if keys are being shared. * A dead transaction can occur if somebody is attacking the network, or by accident if keys are being shared.
* You can use this event handler to inform the user of the situation. A dead spend will show up in the BitCoin * You can use this event handler to inform the user of the situation. A dead spend will show up in the BitCoin
* C++ client of the recipient as 0/unconfirmed forever, so if it was used to purchase something, * C++ client of the recipient as 0/unconfirmed forever, so if it was used to purchase something,
* the user needs to know their goods will never arrive. * the user needs to know their goods will never arrive.
* *
* @param deadTx The transaction that is newly dead. * @param deadTx The transaction that is newly dead.
* @param replacementTx The transaction that killed it. * @param replacementTx The transaction that killed it.
*/ */
void onDeadTransaction(Wallet wallet, Transaction deadTx, Transaction replacementTx); void onDeadTransaction(Wallet wallet, Transaction deadTx, Transaction replacementTx);

View File

@ -20,7 +20,8 @@ import com.google.bitcoin.core.NetworkParameters;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.net.*; import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -29,7 +30,7 @@ import java.util.Set;
* *
* This class does not support the testnet as currently there are no DNS servers providing testnet hosts. * This class does not support the testnet as currently there are no DNS servers providing testnet hosts.
* If this class is being used for testnet you must specify the hostnames to use.<p> * If this class is being used for testnet you must specify the hostnames to use.<p>
* *
* Failure to resolve individual host names will not cause an Exception to be thrown. * Failure to resolve individual host names will not cause an Exception to be thrown.
* However, if all hosts passed fail to resolve a PeerDiscoveryException will be thrown during getPeers(). * However, if all hosts passed fail to resolve a PeerDiscoveryException will be thrown during getPeers().
*/ */
@ -39,30 +40,28 @@ public class DnsDiscovery implements PeerDiscovery {
private String[] hostNames; private String[] hostNames;
private NetworkParameters netParams; private NetworkParameters netParams;
public static final String[] defaultHosts = new String[] { public static final String[] defaultHosts = new String[]{
"dnsseed.bluematt.me", // Auto generated "dnsseed.bluematt.me", // Auto generated
"bitseed.xf2.org", // Static "bitseed.xf2.org", // Static
"bitseed.bitcoin.org.uk" // Static "bitseed.bitcoin.org.uk" // Static
}; };
/** /**
* Supports finding peers through DNS A records. Community run DNS entry points will be used. * Supports finding peers through DNS A records. Community run DNS entry points will be used.
* *
* @param netParams Network parameters to be used for port information. * @param netParams Network parameters to be used for port information.
*/ */
public DnsDiscovery(NetworkParameters netParams) public DnsDiscovery(NetworkParameters netParams) {
{
this(getDefaultHostNames(), netParams); this(getDefaultHostNames(), netParams);
} }
/** /**
* Supports finding peers through DNS A records. * Supports finding peers through DNS A records.
* *
* @param hostNames Host names to be examined for seed addresses. * @param hostNames Host names to be examined for seed addresses.
* @param netParams Network parameters to be used for port information. * @param netParams Network parameters to be used for port information.
*/ */
public DnsDiscovery(String[] hostNames, NetworkParameters netParams) public DnsDiscovery(String[] hostNames, NetworkParameters netParams) {
{
this.hostNames = hostNames; this.hostNames = hostNames;
this.netParams = netParams; this.netParams = netParams;
} }
@ -76,16 +75,16 @@ public class DnsDiscovery implements PeerDiscovery {
* We don't want to throw an exception if only one of many lookups fails. * We don't want to throw an exception if only one of many lookups fails.
*/ */
int failedLookups = 0; int failedLookups = 0;
for (String hostName : hostNames) { for (String hostName : hostNames) {
try { try {
InetAddress[] hostAddresses = InetAddress.getAllByName(hostName); InetAddress[] hostAddresses = InetAddress.getAllByName(hostName);
for (InetAddress inetAddress : hostAddresses) { for (InetAddress inetAddress : hostAddresses) {
// DNS isn't going to provide us with the port. // DNS isn't going to provide us with the port.
// Grab the port from the specified NetworkParameters. // Grab the port from the specified NetworkParameters.
InetSocketAddress socketAddress = new InetSocketAddress(inetAddress, netParams.port); InetSocketAddress socketAddress = new InetSocketAddress(inetAddress, netParams.port);
// Only add the new address if it's not already in the combined list. // Only add the new address if it's not already in the combined list.
if (!addresses.contains(socketAddress)) { if (!addresses.contains(socketAddress)) {
addresses.add(socketAddress); addresses.add(socketAddress);
@ -94,7 +93,7 @@ public class DnsDiscovery implements PeerDiscovery {
} catch (Exception e) { } catch (Exception e) {
failedLookups++; failedLookups++;
log.info("DNS lookup for " + hostName + " failed."); log.info("DNS lookup for " + hostName + " failed.");
if (failedLookups == hostNames.length) { if (failedLookups == hostNames.length) {
// All the lookups failed. // All the lookups failed.
// Throw the discovery exception and include the last inner exception. // Throw the discovery exception and include the last inner exception.
@ -104,12 +103,11 @@ public class DnsDiscovery implements PeerDiscovery {
} }
return addresses.toArray(new InetSocketAddress[]{}); return addresses.toArray(new InetSocketAddress[]{});
} }
/** /**
* Returns the well known discovery host names on the production network. * Returns the well known discovery host names on the production network.
*/ */
public static String[] getDefaultHostNames() public static String[] getDefaultHostNames() {
{
return defaultHosts; return defaultHosts;
} }

View File

@ -22,9 +22,16 @@ import com.google.bitcoin.core.Utils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.*; import java.io.BufferedReader;
import java.net.*; import java.io.BufferedWriter;
import java.util.*; import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Random;
/** /**
* IrcDiscovery provides a way to find network peers by joining a pre-agreed rendevouz point on the LFnet IRC network. * IrcDiscovery provides a way to find network peers by joining a pre-agreed rendevouz point on the LFnet IRC network.
@ -42,8 +49,8 @@ public class IrcDiscovery implements PeerDiscovery {
* Finds a list of peers by connecting to an IRC network, joining a channel, decoding the nicks and then * Finds a list of peers by connecting to an IRC network, joining a channel, decoding the nicks and then
* disconnecting. * disconnecting.
* *
* @param channel The IRC channel to join, either "#bitcoin" or "#bitcoinTEST" for the production and test networks * @param channel The IRC channel to join, either "#bitcoin" or "#bitcoinTEST" for the production and test networks
* respectively. * respectively.
*/ */
public IrcDiscovery(String channel) { public IrcDiscovery(String channel) {
this(channel, "irc.lfnet.org", 6667); this(channel, "irc.lfnet.org", 6667);
@ -53,7 +60,7 @@ public class IrcDiscovery implements PeerDiscovery {
* Finds a list of peers by connecting to an IRC network, joining a channel, decoding the nicks and then * Finds a list of peers by connecting to an IRC network, joining a channel, decoding the nicks and then
* disconnecting. * disconnecting.
* *
* @param server Name or textual IP address of the IRC server to join. * @param server Name or textual IP address of the IRC server to join.
* @param channel The IRC channel to join, either "#bitcoin" or "#bitcoinTEST" for the production and test networks * @param channel The IRC channel to join, either "#bitcoin" or "#bitcoinTEST" for the production and test networks
*/ */
public IrcDiscovery(String channel, String server, int port) { public IrcDiscovery(String channel, String server, int port) {
@ -137,7 +144,8 @@ public class IrcDiscovery implements PeerDiscovery {
try { try {
// No matter what try to close the connection. // No matter what try to close the connection.
connection.close(); connection.close();
} catch (Exception e2) {} } catch (Exception e2) {
}
} }
return addresses.toArray(new InetSocketAddress[]{}); return addresses.toArray(new InetSocketAddress[]{});
} }

View File

@ -17,25 +17,21 @@
package com.google.bitcoin.discovery; package com.google.bitcoin.discovery;
public class PeerDiscoveryException extends Exception { public class PeerDiscoveryException extends Exception {
private static final long serialVersionUID = -2863411151549391392L; private static final long serialVersionUID = -2863411151549391392L;
public PeerDiscoveryException() { public PeerDiscoveryException() {
super(); super();
} }
public PeerDiscoveryException(String message) { public PeerDiscoveryException(String message) {
super(message); super(message);
} }
public PeerDiscoveryException(Throwable arg0) public PeerDiscoveryException(Throwable arg0) {
{ super(arg0);
super(arg0);
} }
public PeerDiscoveryException(String message, Throwable arg0) { public PeerDiscoveryException(String message, Throwable arg0) {
super(message, arg0); super(message, arg0);
} }
} }

View File

@ -16,8 +16,6 @@
package com.google.bitcoin.discovery; package com.google.bitcoin.discovery;
import com.google.bitcoin.core.NetworkParameters; import com.google.bitcoin.core.NetworkParameters;
import com.google.bitcoin.discovery.PeerDiscovery;
import com.google.bitcoin.discovery.PeerDiscoveryException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -29,101 +27,103 @@ import java.net.UnknownHostException;
* to the network, in case IRC and DNS fail. The list comes from the Bitcoin C++ source code. * to the network, in case IRC and DNS fail. The list comes from the Bitcoin C++ source code.
*/ */
public class SeedPeers implements PeerDiscovery { public class SeedPeers implements PeerDiscovery {
private NetworkParameters params; private NetworkParameters params;
private int pnseedIndex; private int pnseedIndex;
public SeedPeers(NetworkParameters params) { public SeedPeers(NetworkParameters params) {
this.params = params; this.params = params;
} }
/** /**
* Acts as an iterator, returning the address of each node in the list sequentially. * Acts as an iterator, returning the address of each node in the list sequentially.
* Once all the list has been iterated, null will be returned for each subsequent query. * Once all the list has been iterated, null will be returned for each subsequent query.
* *
* @return InetSocketAddress - The address/port of the next node. * @return InetSocketAddress - The address/port of the next node.
* @throws PeerDiscoveryException * @throws PeerDiscoveryException
*/ */
public InetSocketAddress getPeer() throws PeerDiscoveryException { public InetSocketAddress getPeer() throws PeerDiscoveryException {
try { try {
return nextPeer(); return nextPeer();
} catch (UnknownHostException e) { } catch (UnknownHostException e) {
throw new PeerDiscoveryException(e); throw new PeerDiscoveryException(e);
} }
} }
private InetSocketAddress nextPeer() throws UnknownHostException {
if(pnseedIndex >= seedAddrs.length)return null;
return new InetSocketAddress(convertAddress(seedAddrs[pnseedIndex++]),
params.port);
}
/** Returns an array containing all the Bitcoin nodes within the list. */ private InetSocketAddress nextPeer() throws UnknownHostException {
public InetSocketAddress[] getPeers() throws PeerDiscoveryException { if (pnseedIndex >= seedAddrs.length) return null;
try { return new InetSocketAddress(convertAddress(seedAddrs[pnseedIndex++]),
return allPeers(); params.port);
} catch (UnknownHostException e) { }
throw new PeerDiscoveryException(e);
}
}
private InetSocketAddress[] allPeers() throws UnknownHostException { /**
InetSocketAddress[] addresses = new InetSocketAddress[seedAddrs.length]; * Returns an array containing all the Bitcoin nodes within the list.
for(int i=0;i < seedAddrs.length; ++i) { */
addresses[i] = new InetSocketAddress(convertAddress(seedAddrs[i]), params.port); public InetSocketAddress[] getPeers() throws PeerDiscoveryException {
} try {
return addresses; return allPeers();
} } catch (UnknownHostException e) {
throw new PeerDiscoveryException(e);
private InetAddress convertAddress(int seed) throws UnknownHostException{ }
byte[] v4addr = new byte[4]; }
v4addr[0] = (byte) (0xFF & (seed));
v4addr[1] = (byte) (0xFF & (seed >> 8)); private InetSocketAddress[] allPeers() throws UnknownHostException {
v4addr[2] = (byte) (0xFF & (seed >> 16)); InetSocketAddress[] addresses = new InetSocketAddress[seedAddrs.length];
v4addr[3] = (byte) (0xFF & (seed >> 24)); for (int i = 0; i < seedAddrs.length; ++i) {
return InetAddress.getByAddress(v4addr); addresses[i] = new InetSocketAddress(convertAddress(seedAddrs[i]), params.port);
} }
return addresses;
public static int[] seedAddrs = }
{
0x1ddb1032, 0x6242ce40, 0x52d6a445, 0x2dd7a445, 0x8a53cd47, 0x73263750, 0xda23c257, 0xecd4ed57, private InetAddress convertAddress(int seed) throws UnknownHostException {
0x0a40ec59, 0x75dce160, 0x7df76791, 0x89370bad, 0xa4f214ad, 0x767700ae, 0x638b0418, 0x868a1018, byte[] v4addr = new byte[4];
0xcd9f332e, 0x0129653e, 0xcc92dc3e, 0x96671640, 0x56487e40, 0x5b66f440, 0xb1d01f41, 0xf1dc6041, v4addr[0] = (byte) (0xFF & (seed));
0xc1d12b42, 0x86ba1243, 0x6be4df43, 0x6d4cef43, 0xd18e0644, 0x1ab0b344, 0x6584a345, 0xe7c1a445, v4addr[1] = (byte) (0xFF & (seed >> 8));
0x58cea445, 0xc5daa445, 0x21dda445, 0x3d3b5346, 0x13e55347, 0x1080d24a, 0x8e611e4b, 0x81518e4b, v4addr[2] = (byte) (0xFF & (seed >> 16));
0x6c839e4b, 0xe2ad0a4c, 0xfbbc0a4c, 0x7f5b6e4c, 0x7244224e, 0x1300554e, 0x20690652, 0x5a48b652, v4addr[3] = (byte) (0xFF & (seed >> 24));
0x75c5c752, 0x4335cc54, 0x340fd154, 0x87c07455, 0x087b2b56, 0x8a133a57, 0xac23c257, 0x70374959, return InetAddress.getByAddress(v4addr);
0xfb63d45b, 0xb9a1685c, 0x180d765c, 0x674f645d, 0x04d3495e, 0x1de44b5e, 0x4ee8a362, 0x0ded1b63, }
0xc1b04b6d, 0x8d921581, 0x97b7ea82, 0x1cf83a8e, 0x91490bad, 0x09dc75ae, 0x9a6d79ae, 0xa26d79ae,
0x0fd08fae, 0x0f3e3fb2, 0x4f944fb2, 0xcca448b8, 0x3ecd6ab8, 0xa9d5a5bc, 0x8d0119c1, 0x045997d5, public static int[] seedAddrs =
0xca019dd9, 0x0d526c4d, 0xabf1ba44, 0x66b1ab55, 0x1165f462, 0x3ed7cbad, 0xa38fae6e, 0x3bd2cbad, {
0xd36f0547, 0x20df7840, 0x7a337742, 0x549f8e4b, 0x9062365c, 0xd399f562, 0x2b5274a1, 0x8edfa153, 0x1ddb1032, 0x6242ce40, 0x52d6a445, 0x2dd7a445, 0x8a53cd47, 0x73263750, 0xda23c257, 0xecd4ed57,
0x3bffb347, 0x7074bf58, 0xb74fcbad, 0x5b5a795b, 0x02fa29ce, 0x5a6738d4, 0xe8a1d23e, 0xef98c445, 0x0a40ec59, 0x75dce160, 0x7df76791, 0x89370bad, 0xa4f214ad, 0x767700ae, 0x638b0418, 0x868a1018,
0x4b0f494c, 0xa2bc1e56, 0x7694ad63, 0xa4a800c3, 0x05fda6cd, 0x9f22175e, 0x364a795b, 0x536285d5, 0xcd9f332e, 0x0129653e, 0xcc92dc3e, 0x96671640, 0x56487e40, 0x5b66f440, 0xb1d01f41, 0xf1dc6041,
0xac44c9d4, 0x0b06254d, 0x150c2fd4, 0x32a50dcc, 0xfd79ce48, 0xf15cfa53, 0x66c01e60, 0x6bc26661, 0xc1d12b42, 0x86ba1243, 0x6be4df43, 0x6d4cef43, 0xd18e0644, 0x1ab0b344, 0x6584a345, 0xe7c1a445,
0xc03b47ae, 0x4dda1b81, 0x3285a4c1, 0x883ca96d, 0x35d60a4c, 0xdae09744, 0x2e314d61, 0x84e247cf, 0x58cea445, 0xc5daa445, 0x21dda445, 0x3d3b5346, 0x13e55347, 0x1080d24a, 0x8e611e4b, 0x81518e4b,
0x6c814552, 0x3a1cc658, 0x98d8f382, 0xe584cb5b, 0x15e86057, 0x7b01504e, 0xd852dd48, 0x56382f56, 0x6c839e4b, 0xe2ad0a4c, 0xfbbc0a4c, 0x7f5b6e4c, 0x7244224e, 0x1300554e, 0x20690652, 0x5a48b652,
0x0a5df454, 0xa0d18d18, 0x2e89b148, 0xa79c114c, 0xcbdcd054, 0x5523bc43, 0xa9832640, 0x8a066144, 0x75c5c752, 0x4335cc54, 0x340fd154, 0x87c07455, 0x087b2b56, 0x8a133a57, 0xac23c257, 0x70374959,
0x3894c3bc, 0xab76bf58, 0x6a018ac1, 0xfebf4f43, 0x2f26c658, 0x31102f4e, 0x85e929d5, 0x2a1c175e, 0xfb63d45b, 0xb9a1685c, 0x180d765c, 0x674f645d, 0x04d3495e, 0x1de44b5e, 0x4ee8a362, 0x0ded1b63,
0xfc6c2cd1, 0x27b04b6d, 0xdf024650, 0x161748b8, 0x28be6580, 0x57be6580, 0x1cee677a, 0xaa6bb742, 0xc1b04b6d, 0x8d921581, 0x97b7ea82, 0x1cf83a8e, 0x91490bad, 0x09dc75ae, 0x9a6d79ae, 0xa26d79ae,
0x9a53964b, 0x0a5a2d4d, 0x2434c658, 0x9a494f57, 0x1ebb0e48, 0xf610b85d, 0x077ecf44, 0x085128bc, 0x0fd08fae, 0x0f3e3fb2, 0x4f944fb2, 0xcca448b8, 0x3ecd6ab8, 0xa9d5a5bc, 0x8d0119c1, 0x045997d5,
0x5ba17a18, 0x27ca1b42, 0xf8a00b56, 0xfcd4c257, 0xcf2fc15e, 0xd897e052, 0x4cada04f, 0x2f35f6d5, 0xca019dd9, 0x0d526c4d, 0xabf1ba44, 0x66b1ab55, 0x1165f462, 0x3ed7cbad, 0xa38fae6e, 0x3bd2cbad,
0x382ce8c9, 0xe523984b, 0x3f946846, 0x60c8be43, 0x41da6257, 0xde0be142, 0xae8a544b, 0xeff0c254, 0xd36f0547, 0x20df7840, 0x7a337742, 0x549f8e4b, 0x9062365c, 0xd399f562, 0x2b5274a1, 0x8edfa153,
0x1e0f795b, 0xaeb28890, 0xca16acd9, 0x1e47ddd8, 0x8c8c4829, 0xd27dc747, 0xd53b1663, 0x4096b163, 0x3bffb347, 0x7074bf58, 0xb74fcbad, 0x5b5a795b, 0x02fa29ce, 0x5a6738d4, 0xe8a1d23e, 0xef98c445,
0x9c8dd958, 0xcb12f860, 0x9e79305c, 0x40c1a445, 0x4a90c2bc, 0x2c3a464d, 0x2727f23c, 0x30b04b6d, 0x4b0f494c, 0xa2bc1e56, 0x7694ad63, 0xa4a800c3, 0x05fda6cd, 0x9f22175e, 0x364a795b, 0x536285d5,
0x59024cb8, 0xa091e6ad, 0x31b04b6d, 0xc29d46a6, 0x63934fb2, 0xd9224dbe, 0x9f5910d8, 0x7f530a6b, 0xac44c9d4, 0x0b06254d, 0x150c2fd4, 0x32a50dcc, 0xfd79ce48, 0xf15cfa53, 0x66c01e60, 0x6bc26661,
0x752e9c95, 0x65453548, 0xa484be46, 0xce5a1b59, 0x710e0718, 0x46a13d18, 0xdaaf5318, 0xc4a8ff53, 0xc03b47ae, 0x4dda1b81, 0x3285a4c1, 0x883ca96d, 0x35d60a4c, 0xdae09744, 0x2e314d61, 0x84e247cf,
0x87abaa52, 0xb764cf51, 0xb2025d4a, 0x6d351e41, 0xc035c33e, 0xa432c162, 0x61ef34ae, 0xd16fddbc, 0x6c814552, 0x3a1cc658, 0x98d8f382, 0xe584cb5b, 0x15e86057, 0x7b01504e, 0xd852dd48, 0x56382f56,
0x0870e8c1, 0x3070e8c1, 0x9c71e8c1, 0xa4992363, 0x85a1f663, 0x4184e559, 0x18d96ed8, 0x17b8dbd5, 0x0a5df454, 0xa0d18d18, 0x2e89b148, 0xa79c114c, 0xcbdcd054, 0x5523bc43, 0xa9832640, 0x8a066144,
0x60e7cd18, 0xe5ee104c, 0xab17ac62, 0x1e786e1b, 0x5d23b762, 0xf2388fae, 0x88270360, 0x9e5b3d80, 0x3894c3bc, 0xab76bf58, 0x6a018ac1, 0xfebf4f43, 0x2f26c658, 0x31102f4e, 0x85e929d5, 0x2a1c175e,
0x7da518b2, 0xb5613b45, 0x1ad41f3e, 0xd550854a, 0x8617e9a9, 0x925b229c, 0xf2e92542, 0x47af0544, 0xfc6c2cd1, 0x27b04b6d, 0xdf024650, 0x161748b8, 0x28be6580, 0x57be6580, 0x1cee677a, 0xaa6bb742,
0x73b5a843, 0xb9b7a0ad, 0x03a748d0, 0x0a6ff862, 0x6694df62, 0x3bfac948, 0x8e098f4f, 0x746916c3, 0x9a53964b, 0x0a5a2d4d, 0x2434c658, 0x9a494f57, 0x1ebb0e48, 0xf610b85d, 0x077ecf44, 0x085128bc,
0x02f38e4f, 0x40bb1243, 0x6a54d162, 0x6008414b, 0xa513794c, 0x514aa343, 0x63781747, 0xdbb6795b, 0x5ba17a18, 0x27ca1b42, 0xf8a00b56, 0xfcd4c257, 0xcf2fc15e, 0xd897e052, 0x4cada04f, 0x2f35f6d5,
0xed065058, 0x42d24b46, 0x1518794c, 0x9b271681, 0x73e4ffad, 0x0654784f, 0x438dc945, 0x641846a6, 0x382ce8c9, 0xe523984b, 0x3f946846, 0x60c8be43, 0x41da6257, 0xde0be142, 0xae8a544b, 0xeff0c254,
0x2d1b0944, 0x94b59148, 0x8d369558, 0xa5a97662, 0x8b705b42, 0xce9204ae, 0x8d584450, 0x2df61555, 0x1e0f795b, 0xaeb28890, 0xca16acd9, 0x1e47ddd8, 0x8c8c4829, 0xd27dc747, 0xd53b1663, 0x4096b163,
0xeebff943, 0x2e75fb4d, 0x3ef8fc57, 0x9921135e, 0x8e31042e, 0xb5afad43, 0x89ecedd1, 0x9cfcc047, 0x9c8dd958, 0xcb12f860, 0x9e79305c, 0x40c1a445, 0x4a90c2bc, 0x2c3a464d, 0x2727f23c, 0x30b04b6d,
0x8fcd0f4c, 0xbe49f5ad, 0x146a8d45, 0x98669ab8, 0x98d9175e, 0xd1a8e46d, 0x839a3ab8, 0x40a0016c, 0x59024cb8, 0xa091e6ad, 0x31b04b6d, 0xc29d46a6, 0x63934fb2, 0xd9224dbe, 0x9f5910d8, 0x7f530a6b,
0x6d27c257, 0x977fffad, 0x7baa5d5d, 0x1213be43, 0xb167e5a9, 0x640fe8ca, 0xbc9ea655, 0x0f820a4c, 0x752e9c95, 0x65453548, 0xa484be46, 0xce5a1b59, 0x710e0718, 0x46a13d18, 0xdaaf5318, 0xc4a8ff53,
0x0f097059, 0x69ac957c, 0x366d8453, 0xb1ba2844, 0x8857f081, 0x70b5be63, 0xc545454b, 0xaf36ded1, 0x87abaa52, 0xb764cf51, 0xb2025d4a, 0x6d351e41, 0xc035c33e, 0xa432c162, 0x61ef34ae, 0xd16fddbc,
0xb5a4b052, 0x21f062d1, 0x72ab89b2, 0x74a45318, 0x8312e6bc, 0xb916965f, 0x8aa7c858, 0xfe7effad, 0x0870e8c1, 0x3070e8c1, 0x9c71e8c1, 0xa4992363, 0x85a1f663, 0x4184e559, 0x18d96ed8, 0x17b8dbd5,
}; 0x60e7cd18, 0xe5ee104c, 0xab17ac62, 0x1e786e1b, 0x5d23b762, 0xf2388fae, 0x88270360, 0x9e5b3d80,
0x7da518b2, 0xb5613b45, 0x1ad41f3e, 0xd550854a, 0x8617e9a9, 0x925b229c, 0xf2e92542, 0x47af0544,
0x73b5a843, 0xb9b7a0ad, 0x03a748d0, 0x0a6ff862, 0x6694df62, 0x3bfac948, 0x8e098f4f, 0x746916c3,
0x02f38e4f, 0x40bb1243, 0x6a54d162, 0x6008414b, 0xa513794c, 0x514aa343, 0x63781747, 0xdbb6795b,
0xed065058, 0x42d24b46, 0x1518794c, 0x9b271681, 0x73e4ffad, 0x0654784f, 0x438dc945, 0x641846a6,
0x2d1b0944, 0x94b59148, 0x8d369558, 0xa5a97662, 0x8b705b42, 0xce9204ae, 0x8d584450, 0x2df61555,
0xeebff943, 0x2e75fb4d, 0x3ef8fc57, 0x9921135e, 0x8e31042e, 0xb5afad43, 0x89ecedd1, 0x9cfcc047,
0x8fcd0f4c, 0xbe49f5ad, 0x146a8d45, 0x98669ab8, 0x98d9175e, 0xd1a8e46d, 0x839a3ab8, 0x40a0016c,
0x6d27c257, 0x977fffad, 0x7baa5d5d, 0x1213be43, 0xb167e5a9, 0x640fe8ca, 0xbc9ea655, 0x0f820a4c,
0x0f097059, 0x69ac957c, 0x366d8453, 0xb1ba2844, 0x8857f081, 0x70b5be63, 0xc545454b, 0xaf36ded1,
0xb5a4b052, 0x21f062d1, 0x72ab89b2, 0x74a45318, 0x8312e6bc, 0xb916965f, 0x8aa7c858, 0xfe7effad,
};
} }

View File

@ -16,13 +16,13 @@
package com.google.bitcoin.examples; package com.google.bitcoin.examples;
import java.net.InetSocketAddress; import com.google.bitcoin.core.NetworkParameters;
import com.google.bitcoin.core.*;
import com.google.bitcoin.discovery.DnsDiscovery; import com.google.bitcoin.discovery.DnsDiscovery;
import com.google.bitcoin.discovery.IrcDiscovery; import com.google.bitcoin.discovery.IrcDiscovery;
import com.google.bitcoin.discovery.PeerDiscoveryException; import com.google.bitcoin.discovery.PeerDiscoveryException;
import java.net.InetSocketAddress;
/** /**
* Prints a list of IP addresses connected to the rendezvous point on the LFnet IRC channel. * Prints a list of IP addresses connected to the rendezvous point on the LFnet IRC channel.
*/ */

View File

@ -25,8 +25,8 @@ import java.net.InetAddress;
/** /**
* This example shows how to solve the challenge Hal posted here:<p> * This example shows how to solve the challenge Hal posted here:<p>
* *
* <a href="http://www.bitcoin.org/smf/index.php?topic=3638.0">http://www.bitcoin.org/smf/index.php?topic=3638 * <a href="http://www.bitcoin.org/smf/index.php?topic=3638.0">http://www.bitcoin.org/smf/index.php?topic=3638
* .0</a><p> * .0</a><p>
* *
* in which a private key with some coins associated with it is published. The goal is to import the private key, * in which a private key with some coins associated with it is published. The goal is to import the private key,
* claim the coins and then send them to a different address. * claim the coins and then send them to a different address.
@ -57,7 +57,7 @@ public class PrivateKeys {
// Find the transactions that involve those coins. // Find the transactions that involve those coins.
final MemoryBlockStore blockStore = new MemoryBlockStore(params); final MemoryBlockStore blockStore = new MemoryBlockStore(params);
BlockChain chain = new BlockChain(params, wallet, blockStore); BlockChain chain = new BlockChain(params, wallet, blockStore);
final PeerGroup peerGroup = new PeerGroup(blockStore, params, chain); final PeerGroup peerGroup = new PeerGroup(blockStore, params, chain);
peerGroup.addAddress(new PeerAddress(InetAddress.getLocalHost())); peerGroup.addAddress(new PeerAddress(InetAddress.getLocalHost()));
peerGroup.start(); peerGroup.start();

View File

@ -16,16 +16,20 @@
package com.google.bitcoin.store; package com.google.bitcoin.store;
import java.io.*;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.*;
import com.google.bitcoin.core.*; import com.google.bitcoin.core.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.LinkedHashMap;
import java.util.Map;
/** /**
* Stores the block chain to disk.<p> * Stores the block chain to disk.<p>
* *
@ -43,7 +47,7 @@ import org.slf4j.LoggerFactory;
* expensive on Android. * expensive on Android.
*/ */
public class BoundedOverheadBlockStore implements BlockStore { public class BoundedOverheadBlockStore implements BlockStore {
private static final Logger log = LoggerFactory.getLogger(BoundedOverheadBlockStore.class); private static final Logger log = LoggerFactory.getLogger(BoundedOverheadBlockStore.class);
private static final byte FILE_FORMAT_VERSION = 1; private static final byte FILE_FORMAT_VERSION = 1;
private RandomAccessFile file; private RandomAccessFile file;
@ -248,6 +252,7 @@ public class BoundedOverheadBlockStore implements BlockStore {
} }
private ByteBuffer buf = ByteBuffer.allocateDirect(Record.SIZE); private ByteBuffer buf = ByteBuffer.allocateDirect(Record.SIZE);
private Record getRecord(Sha256Hash hash) throws BlockStoreException, IOException, ProtocolException { private Record getRecord(Sha256Hash hash) throws BlockStoreException, IOException, ProtocolException {
long startPos = channel.position(); long startPos = channel.position();
// Use our own file pointer within the tight loop as updating channel positions is really expensive. // Use our own file pointer within the tight loop as updating channel positions is really expensive.

View File

@ -16,22 +16,25 @@
package com.google.bitcoin.store; package com.google.bitcoin.store;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import com.google.bitcoin.core.*; import com.google.bitcoin.core.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
/** /**
* Stores the block chain to disk but still holds it in memory. This is intended for desktop apps and tests. * Stores the block chain to disk but still holds it in memory. This is intended for desktop apps and tests.
* Constrained environments like mobile phones probably won't want to or be able to store all the block headers in RAM. * Constrained environments like mobile phones probably won't want to or be able to store all the block headers in RAM.
*/ */
public class DiskBlockStore implements BlockStore { public class DiskBlockStore implements BlockStore {
private static final Logger log = LoggerFactory.getLogger(DiskBlockStore.class); private static final Logger log = LoggerFactory.getLogger(DiskBlockStore.class);
private RandomAccessFile file; private RandomAccessFile file;
private Map<Sha256Hash, StoredBlock> blockMap; private Map<Sha256Hash, StoredBlock> blockMap;
private Sha256Hash chainHead; private Sha256Hash chainHead;
@ -99,7 +102,7 @@ public class DiskBlockStore implements BlockStore {
try { try {
while (true) { while (true) {
// Read a block from disk. // Read a block from disk.
int read = file.read(headerBytes); int read = file.read(headerBytes);
if (read == -1) { if (read == -1) {
// End of file. // End of file.
break; break;
@ -118,7 +121,7 @@ public class DiskBlockStore implements BlockStore {
s = new StoredBlock(params.genesisBlock.cloneAsHeader(), params.genesisBlock.getWork(), 0); s = new StoredBlock(params.genesisBlock.cloneAsHeader(), params.genesisBlock.getWork(), 0);
} else { } else {
throw new BlockStoreException("Could not connect " + b.getHash().toString() + " to " throw new BlockStoreException("Could not connect " + b.getHash().toString() + " to "
+ b.getPrevBlockHash().toString()); + b.getPrevBlockHash().toString());
} }
} else { } else {
// Don't try to verify the genesis block to avoid upsetting the unit tests. // Don't try to verify the genesis block to avoid upsetting the unit tests.

View File

@ -18,8 +18,6 @@ package com.google.bitcoin.store;
import com.google.bitcoin.core.*; import com.google.bitcoin.core.*;
import java.io.*;
import java.nio.ByteBuffer;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;