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

Switch to using SLF4J + the simple logger, allowing people to integrate BitCoinJ with whatever logging system they

are already using.

Resolves issue 16.
This commit is contained in:
Mike Hearn 2011-05-02 12:35:10 +00:00
parent a32a612630
commit 068dcba122
14 changed files with 118 additions and 89 deletions

BIN
lib/slf4j-api-1.6.1.jar Normal file

Binary file not shown.

BIN
lib/slf4j-simple-1.6.1.jar Normal file

Binary file not shown.

View File

@ -22,6 +22,9 @@ import java.io.OutputStream;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.*; import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.bitcoin.core.Utils.*; import static com.google.bitcoin.core.Utils.*;
/** /**
@ -33,6 +36,7 @@ import static com.google.bitcoin.core.Utils.*;
* or request one specifically using {@link Peer#getBlock(byte[])}, or grab one from a downloaded {@link BlockChain}. * or request one specifically using {@link Peer#getBlock(byte[])}, or grab one from a downloaded {@link BlockChain}.
*/ */
public class Block extends Message { public class Block extends Message {
private static final Logger log = LoggerFactory.getLogger(Block.class);
private static final long serialVersionUID = 2738848929966035281L; private static final long serialVersionUID = 2738848929966035281L;
/** How many bytes are required to represent a block header. */ /** How many bytes are required to represent a block header. */
@ -263,8 +267,8 @@ public class Block extends Message {
List<byte[]> tree = buildMerkleTree(); List<byte[]> tree = buildMerkleTree();
byte[] calculatedRoot = tree.get(tree.size() - 1); byte[] calculatedRoot = tree.get(tree.size() - 1);
if (!Arrays.equals(calculatedRoot, merkleRoot)) { if (!Arrays.equals(calculatedRoot, merkleRoot)) {
LOG("Merkle tree did not verify: "); log.error("Merkle tree did not verify: ");
for (byte[] b : tree) LOG(Utils.bytesToHexString(b)); for (byte[] b : tree) log.error(Utils.bytesToHexString(b));
throw new VerificationException("Merkle hashes do not match: " + throw new VerificationException("Merkle hashes do not match: " +
bytesToHexString(calculatedRoot) + " vs " + bytesToHexString(merkleRoot)); bytesToHexString(calculatedRoot) + " vs " + bytesToHexString(merkleRoot));

View File

@ -19,7 +19,8 @@ package com.google.bitcoin.core;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.*; import java.util.*;
import static com.google.bitcoin.core.Utils.LOG; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* 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
@ -46,6 +47,8 @@ import static com.google.bitcoin.core.Utils.LOG;
* or if we connect to a peer that doesn't send us blocks in order. * or if we connect to a peer that doesn't send us blocks in order.
*/ */
public class BlockChain { public class BlockChain {
private static final Logger log = LoggerFactory.getLogger(BlockChain.class);
/** Keeps a map of block hashes to StoredBlocks. */ /** Keeps a map of block hashes to StoredBlocks. */
protected BlockStore blockStore; protected BlockStore blockStore;
@ -78,7 +81,7 @@ public class BlockChain {
try { try {
this.blockStore = blockStore; this.blockStore = blockStore;
chainHead = blockStore.getChainHead(); chainHead = blockStore.getChainHead();
LOG("chain head is: " + chainHead.getHeader().toString()); log.info("chain head is:\n{}", chainHead.getHeader());
} catch (BlockStoreException e) { } catch (BlockStoreException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -103,9 +106,9 @@ public class BlockChain {
private synchronized boolean add(Block block, boolean tryConnecting) private synchronized boolean add(Block block, boolean tryConnecting)
throws BlockStoreException, VerificationException, ScriptException { throws BlockStoreException, VerificationException, ScriptException {
LOG("Adding block " + block.getHashAsString() + " to the chain"); log.info("Adding block " + block.getHashAsString() + " to the chain");
if (blockStore.get(block.getHash()) != null) { if (blockStore.get(block.getHash()) != null) {
LOG("Already have block"); log.info("Already have block");
return true; return true;
} }
@ -113,8 +116,8 @@ public class BlockChain {
try { try {
block.verify(); block.verify();
} catch (VerificationException e) { } catch (VerificationException e) {
LOG("Failed to verify block: " + e.toString()); log.error("Failed to verify block:", e);
LOG(block.toString()); log.error(block.toString());
throw e; throw e;
} }
@ -125,7 +128,7 @@ public class BlockChain {
// We can't find the previous block. Probably we are still in the process of downloading the chain and a // We can't find the previous block. Probably we are still in the process of downloading the chain and a
// block was solved whilst we were doing it. We put it to one side and try to connect it later when we // block was solved whilst we were doing it. We put it to one side and try to connect it later when we
// have more blocks. // have more blocks.
LOG("Block does not connect: " + block.getHashAsString()); log.warn("Block does not connect: {}", block.getHashAsString());
unconnectedBlocks.add(block); unconnectedBlocks.add(block);
return false; return false;
} else { } else {
@ -152,7 +155,7 @@ public class BlockChain {
if (storedPrev.equals(chainHead)) { if (storedPrev.equals(chainHead)) {
// This block connects to the best known block, it is a normal continuation of the system. // This block connects to the best known block, it is a normal continuation of the system.
setChainHead(newStoredBlock); setChainHead(newStoredBlock);
LOG("Chain is now " + chainHead.getHeight() + " blocks high"); log.info("Chain is now {} blocks high", chainHead.getHeight());
if (newTransactions != null) if (newTransactions != null)
sendTransactionsToWallet(newStoredBlock, NewBlockType.BEST_CHAIN, newTransactions); sendTransactionsToWallet(newStoredBlock, NewBlockType.BEST_CHAIN, newTransactions);
} else { } else {
@ -162,9 +165,9 @@ public class BlockChain {
// to become the new best chain head. This simplifies handling of the re-org in the Wallet class. // to become the new best chain head. This simplifies handling of the re-org in the Wallet class.
boolean causedSplit = newStoredBlock.moreWorkThan(chainHead); boolean causedSplit = newStoredBlock.moreWorkThan(chainHead);
if (causedSplit) { if (causedSplit) {
LOG("Block is causing a re-organize"); log.info("Block is causing a re-organize");
} else { } else {
LOG("Block forks the chain, but it did not cause a reorganize."); log.info("Block forks the chain, but it did not cause a reorganize.");
} }
// 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
@ -187,10 +190,10 @@ public class BlockChain {
// Firstly, calculate the block at which the chain diverged. We only need to examine the // Firstly, calculate the block at which the chain diverged. We only need to examine the
// chain from beyond this block to find differences. // chain from beyond this block to find differences.
StoredBlock splitPoint = findSplit(newChainHead, chainHead); StoredBlock splitPoint = findSplit(newChainHead, chainHead);
LOG("Re-organize after split at height " + splitPoint.getHeight()); log.info("Re-organize after split at height {}", splitPoint.getHeight());
LOG("Old chain head: " + chainHead.getHeader().getHashAsString()); log.info("Old chain head: {}", chainHead.getHeader().getHashAsString());
LOG("New chain head: " + newChainHead.getHeader().getHashAsString()); log.info("New chain head: {}", newChainHead.getHeader().getHashAsString());
LOG("Split at block: " + splitPoint.getHeader().getHashAsString()); log.info("Split at block: {}", splitPoint.getHeader().getHashAsString());
// Then build a list of all blocks in the old part of the chain and the new part. // Then build a list of all blocks in the old part of the chain and the new part.
Set<StoredBlock> oldBlocks = getPartialChain(chainHead, splitPoint); Set<StoredBlock> oldBlocks = getPartialChain(chainHead, splitPoint);
Set<StoredBlock> newBlocks = getPartialChain(newChainHead, splitPoint); Set<StoredBlock> newBlocks = getPartialChain(newChainHead, splitPoint);
@ -267,7 +270,7 @@ public class BlockChain {
} catch (ScriptException e) { } catch (ScriptException e) {
// We don't want scripts we don't understand to break the block chain, // We don't want scripts we don't understand to break the block chain,
// so just note that this tx was not scanned here and continue. // so just note that this tx was not scanned here and continue.
LOG("Failed to parse a script: " + e.toString()); log.warn("Failed to parse a script: " + e.toString());
} }
} }
} }
@ -307,7 +310,7 @@ public class BlockChain {
blocksConnectedThisRound++; blocksConnectedThisRound++;
} }
if (blocksConnectedThisRound > 0) { if (blocksConnectedThisRound > 0) {
LOG("Connected " + blocksConnectedThisRound + " floating blocks."); log.info("Connected {} floating blocks.", blocksConnectedThisRound);
} }
} while (blocksConnectedThisRound > 0); } while (blocksConnectedThisRound > 0);
} }
@ -353,7 +356,7 @@ public class BlockChain {
newDifficulty = newDifficulty.divide(BigInteger.valueOf(params.targetTimespan)); newDifficulty = newDifficulty.divide(BigInteger.valueOf(params.targetTimespan));
if (newDifficulty.compareTo(params.proofOfWorkLimit) > 0) { if (newDifficulty.compareTo(params.proofOfWorkLimit) > 0) {
LOG("Difficulty hit proof of work limit: " + newDifficulty.toString(16)); log.warn("Difficulty hit proof of work limit: {}", newDifficulty.toString(16));
newDifficulty = params.proofOfWorkLimit; newDifficulty = params.proofOfWorkLimit;
} }

View File

@ -21,13 +21,16 @@ import java.nio.ByteBuffer;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static com.google.bitcoin.core.Utils.LOG; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* 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 FileOutputStream stream; private FileOutputStream stream;
private Map<Sha256Hash, StoredBlock> blockMap; private Map<Sha256Hash, StoredBlock> blockMap;
private Sha256Hash chainHead; private Sha256Hash chainHead;
@ -40,7 +43,7 @@ public class DiskBlockStore implements BlockStore {
load(file); load(file);
stream = new FileOutputStream(file, true); // Do append. stream = new FileOutputStream(file, true); // Do append.
} catch (IOException e) { } catch (IOException e) {
LOG(e.toString()); log.error("failed to load block store from file", e);
createNewStore(params, file); createNewStore(params, file);
} }
} }
@ -70,7 +73,7 @@ public class DiskBlockStore implements BlockStore {
} }
private void load(File file) throws IOException, BlockStoreException { private void load(File file) throws IOException, BlockStoreException {
LOG("Reading block store from " + file.getAbsolutePath()); log.info("Reading block store from {}", file);
InputStream input = new BufferedInputStream(new FileInputStream(file)); InputStream input = new BufferedInputStream(new FileInputStream(file));
// Read a version byte. // Read a version byte.
int version = input.read(); int version = input.read();
@ -85,7 +88,7 @@ public class DiskBlockStore implements BlockStore {
byte[] chainHeadHash = new byte[32]; byte[] chainHeadHash = new byte[32];
input.read(chainHeadHash); input.read(chainHeadHash);
this.chainHead = new Sha256Hash(chainHeadHash); this.chainHead = new Sha256Hash(chainHeadHash);
LOG("Read chain head from disk: " + this.chainHead); log.info("Read chain head from disk: {}", this.chainHead);
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
// Rest of file is raw block headers. // Rest of file is raw block headers.
byte[] headerBytes = new byte[Block.HEADER_SIZE]; byte[] headerBytes = new byte[Block.HEADER_SIZE];
@ -126,7 +129,7 @@ public class DiskBlockStore implements BlockStore {
throw new BlockStoreException(e); throw new BlockStoreException(e);
} }
long elapsed = System.currentTimeMillis() - now; long elapsed = System.currentTimeMillis() - now;
LOG("Block chain read complete in " + elapsed + "ms"); log.info("Block chain read complete in {}ms", elapsed);
} }
public synchronized void put(StoredBlock block) throws BlockStoreException { public synchronized void put(StoredBlock block) throws BlockStoreException {

View File

@ -16,6 +16,9 @@
package com.google.bitcoin.core; package com.google.bitcoin.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.*; import java.net.*;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -31,6 +34,8 @@ import java.util.Vector;
* 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().
*/ */
public class DnsDiscovery implements PeerDiscovery { public class DnsDiscovery implements PeerDiscovery {
private static final Logger log = LoggerFactory.getLogger(DnsDiscovery.class);
private String[] hostNames; private String[] hostNames;
private NetworkParameters netParams; private NetworkParameters netParams;
private static final String[] defaultHosts = new String[] {"bitseed.xf2.org","bitseed.bitcoin.org.uk"}; private static final String[] defaultHosts = new String[] {"bitseed.xf2.org","bitseed.bitcoin.org.uk"};
@ -83,7 +88,7 @@ public class DnsDiscovery implements PeerDiscovery {
} }
} catch (Exception e) { } catch (Exception e) {
failedLookups++; failedLookups++;
Utils.LOG("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.

View File

@ -16,6 +16,9 @@
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.net.*; import java.net.*;
import java.util.*; import java.util.*;
@ -24,6 +27,8 @@ import java.util.*;
* 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.
*/ */
public class IrcDiscovery implements PeerDiscovery { public class IrcDiscovery implements PeerDiscovery {
private static final Logger log = LoggerFactory.getLogger(IrcDiscovery.class);
private String channel; private String channel;
private int port = 6667; private int port = 6667;
private String server; private String server;
@ -157,7 +162,7 @@ public class IrcDiscovery implements PeerDiscovery {
// decodeChecked removes the checksum from the returned bytes. // decodeChecked removes the checksum from the returned bytes.
addressBytes = Base58.decodeChecked(user.substring(1)); addressBytes = Base58.decodeChecked(user.substring(1));
} catch (AddressFormatException e) { } catch (AddressFormatException e) {
Utils.LOG("IRC nick does not parse as base58: " + user); log.warn("IRC nick does not parse as base58: " + user);
continue; continue;
} }

View File

@ -25,6 +25,9 @@ import java.net.InetSocketAddress;
import java.net.Socket; import java.net.Socket;
import java.util.Date; import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.bitcoin.core.Utils.*; import static com.google.bitcoin.core.Utils.*;
/** /**
@ -36,6 +39,8 @@ import static com.google.bitcoin.core.Utils.*;
* 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);
static final int COMMAND_LEN = 12; static final int COMMAND_LEN = 12;
// Message strings. // Message strings.
@ -94,9 +99,13 @@ 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(String.format("Connected to peer: version=%d, subVer='%s', services=0x%x, time=%s, blocks=%d", log.info("Connected to peer: version={}, subVer='{}', services=0x{}, time={}, blocks={}", new Object[] {
peerVersion, versionMessage.subVer, peerVersion,
versionMessage.localServices, new Date(versionMessage.time * 1000).toString(), versionMessage.bestHeight)); versionMessage.subVer,
versionMessage.localServices,
new Date(versionMessage.time * 1000),
versionMessage.bestHeight
});
// BitCoinJ is a client mode implementation. That means there's not much point in us talking to other client // BitCoinJ is a client mode implementation. That means there's not much point in us talking to other client
// mode nodes because we can't download the data from them we need to find/verify transactions. // mode nodes because we can't download the data from them we need to find/verify transactions.
if (!versionMessage.hasBlockChain()) if (!versionMessage.hasBlockChain())
@ -240,8 +249,11 @@ public class NetworkConnection {
} }
} }
if (PROTOCOL_LOG) log.debug("Received {} byte '{}' message: {}", new Object[]{
LOG("Received " + size + " byte '" + command + "' message: " + Utils.bytesToHexString(payloadBytes)); size,
command,
Utils.bytesToHexString(payloadBytes)
});
try { try {
Message message; Message message;
@ -283,8 +295,7 @@ public class NetworkConnection {
System.arraycopy(hash, 0, header, 4 + COMMAND_LEN + 4, 4); System.arraycopy(hash, 0, header, 4 + COMMAND_LEN + 4, 4);
} }
if (PROTOCOL_LOG) log.debug("Sending {} message: {}", name, bytesToHexString(payload));
LOG("Sending " + name + " message: " + bytesToHexString(payload));
// Another writeMessage call may be running concurrently. // Another writeMessage call may be running concurrently.
synchronized (out) { synchronized (out) {

View File

@ -23,7 +23,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.*; import java.util.concurrent.*;
import static com.google.bitcoin.core.Utils.LOG; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* A Peer handles the high level communication with a BitCoin node. It requires a NetworkConnection to be set up for * A Peer handles the high level communication with a BitCoin node. It requires a NetworkConnection to be set up for
@ -31,6 +32,8 @@ import static com.google.bitcoin.core.Utils.LOG;
* with the network. All these threads synchronize on the block chain. * with the network. All these threads synchronize on the block chain.
*/ */
public class Peer { public class Peer {
private static final Logger log = LoggerFactory.getLogger(Peer.class);
private final NetworkConnection conn; private final NetworkConnection conn;
private final NetworkParameters params; private final NetworkParameters params;
private Thread thread; private Thread thread;
@ -88,13 +91,13 @@ public class Peer {
// properly explore the network. // properly explore the network.
} else { } else {
// TODO: Handle the other messages we can receive. // TODO: Handle the other messages we can receive.
LOG("Received unhandled message: " + m.toString()); log.warn("Received unhandled message: {}", m);
} }
} }
} catch (Exception e) { } catch (Exception e) {
if (e instanceof IOException && !running) { if (e instanceof IOException && !running) {
// This exception was expected because we are tearing down the socket as part of quitting. // This exception was expected because we are tearing down the socket as part of quitting.
LOG("Shutting down peer thread"); log.info("Shutting down peer thread");
} else { } else {
// We caught an unexpected exception. // We caught an unexpected exception.
e.printStackTrace(); e.printStackTrace();
@ -144,12 +147,10 @@ public class Peer {
} }
} catch (VerificationException e) { } catch (VerificationException e) {
// We don't want verification failures to kill the thread. // We don't want verification failures to kill the thread.
LOG(e.toString()); log.warn("block verification failed", e);
e.printStackTrace();
} catch (ScriptException e) { } catch (ScriptException e) {
// We don't want script failures to kill the thread. // We don't want script failures to kill the thread.
LOG(e.toString()); log.warn("script exception", e);
e.printStackTrace();
} }
} }
@ -297,7 +298,7 @@ public class Peer {
// //
// So this is a complicated process but it has the advantage that we can download a chain of enormous length // So this is a complicated process but it has the advantage that we can download a chain of enormous length
// in a relatively stateless manner and with constant/bounded memory usage. // in a relatively stateless manner and with constant/bounded memory usage.
LOG("Peer.blockChainDownload: " + Utils.bytesToHexString(toHash)); log.info("blockChainDownload({})", Utils.bytesToHexString(toHash));
// TODO: Block locators should be abstracted out rather than special cased here. // TODO: Block locators should be abstracted out rather than special cased here.
List<byte[]> blockLocator = new LinkedList<byte[]>(); List<byte[]> blockLocator = new LinkedList<byte[]>();

View File

@ -26,7 +26,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Stack; import java.util.Stack;
import static com.google.bitcoin.core.Utils.LOG; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.bitcoin.core.Utils.bytesToHexString; import static com.google.bitcoin.core.Utils.bytesToHexString;
/** /**
@ -38,6 +40,8 @@ import static com.google.bitcoin.core.Utils.bytesToHexString;
* 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);
// 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;
@ -171,7 +175,7 @@ public class Script {
chunks.add(getData(len)); chunks.add(getData(len));
} else if (opcode == OP_PUSHDATA4) { } else if (opcode == OP_PUSHDATA4) {
// Read a uint32, then read that many bytes of data. // Read a uint32, then read that many bytes of data.
LOG("PUSHDATA4: Unimplemented"); log.error("PUSHDATA4: Unimplemented");
} else { } else {
chunks.add(new byte[] { (byte) opcode }); chunks.add(new byte[] { (byte) opcode });
} }
@ -260,11 +264,11 @@ public class Script {
case OP_EQUALVERIFY: opEqualVerify(); break; case OP_EQUALVERIFY: opEqualVerify(); break;
case OP_CHECKSIG: opCheckSig(context); break; case OP_CHECKSIG: opCheckSig(context); break;
default: default:
if (tracing) LOG("Unknown/unimplemented opcode: " + opcode); log.debug("Unknown/unimplemented opcode: {}", opcode);
} }
} else { } else {
// Data block, push it onto the stack. // Data block, push it onto the stack.
if (tracing) LOG("Push " + Utils.bytesToHexString(chunk)); log.debug("Push {}", Utils.bytesToHexString(chunk));
stack.add(chunk); stack.add(chunk);
} }
} }
@ -276,7 +280,7 @@ public class Script {
void logStack() { void logStack() {
for (int i = 0; i < stack.size(); i++) { for (int i = 0; i < stack.size(); i++) {
LOG("Stack[" + i + "]: " + Utils.bytesToHexString(stack.get(i))); log.debug("Stack[{}]: {}",i , Utils.bytesToHexString(stack.get(i)));
} }
} }
@ -305,7 +309,7 @@ public class Script {
byte[] sig = new byte[sigAndHashType.length - 1]; byte[] sig = new byte[sigAndHashType.length - 1];
System.arraycopy(sigAndHashType, 0, sig, 0, sig.length); System.arraycopy(sigAndHashType, 0, sig, 0, sig.length);
if (tracing) LOG("CHECKSIG: hashtype=" + sigHash.toString() + " anyoneCanPay=" + anyoneCanPay); log.debug("CHECKSIG: hashtype={} anyoneCanPay={}", sigHash, anyoneCanPay);
if (context == null) { if (context == null) {
// TODO: Fix the unit tests to run scripts in transaction context then remove this. // TODO: Fix the unit tests to run scripts in transaction context then remove this.
pushBool(true); pushBool(true);
@ -327,7 +331,7 @@ public class Script {
} }
private void opEqualVerify() throws ScriptException { private void opEqualVerify() throws ScriptException {
if (tracing) LOG("EQUALVERIFY"); log.debug("EQUALVERIFY");
byte[] a = stack.pop(); byte[] a = stack.pop();
byte[] b = stack.pop(); byte[] b = stack.pop();
if (!Arrays.areEqual(a, b)) if (!Arrays.areEqual(a, b))
@ -340,12 +344,12 @@ public class Script {
byte[] buf = stack.pop(); byte[] buf = stack.pop();
byte[] hash = Utils.sha256hash160(buf); byte[] hash = Utils.sha256hash160(buf);
stack.add(hash); stack.add(hash);
if (tracing) LOG("HASH160: output is " + Utils.bytesToHexString(hash)); log.debug("HASH160: output is {}", Utils.bytesToHexString(hash));
} }
/** Duplicates the top item on the stack */ /** Duplicates the top item on the stack */
private void opDup() { private void opDup() {
if (tracing) LOG("DUP"); log.debug("DUP");
stack.add(Arrays.clone(stack.lastElement())); stack.add(Arrays.clone(stack.lastElement()));
} }

View File

@ -23,6 +23,9 @@ import java.io.Serializable;
import java.math.BigInteger; import java.math.BigInteger;
import java.util.*; import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.bitcoin.core.Utils.*; import static com.google.bitcoin.core.Utils.*;
/** /**
@ -35,6 +38,7 @@ import static com.google.bitcoin.core.Utils.*;
* or UI purposes. * or UI purposes.
*/ */
public class Transaction extends Message implements Serializable { public class Transaction extends Message implements Serializable {
private static final Logger log = LoggerFactory.getLogger(Transaction.class);
private static final long serialVersionUID = -8567546957352643140L; private static final long serialVersionUID = -8567546957352643140L;
// These are serialized in both bitcoin and java serialization. // These are serialized in both bitcoin and java serialization.
@ -319,7 +323,7 @@ public class Transaction extends Message implements Serializable {
// The anyoneCanPay feature isn't used at the moment. // The anyoneCanPay feature isn't used at the moment.
boolean anyoneCanPay = false; boolean anyoneCanPay = false;
byte[] hash = hashTransactionForSignature(hashType, anyoneCanPay); byte[] hash = hashTransactionForSignature(hashType, anyoneCanPay);
Utils.LOG(" signInputs hash=" + Utils.bytesToHexString(hash)); log.info(" signInputs hash={}", Utils.bytesToHexString(hash));
// Set the script to empty again for the next input. // Set the script to empty again for the next input.
input.scriptBytes = TransactionInput.EMPTY_ARRAY; input.scriptBytes = TransactionInput.EMPTY_ARRAY;

View File

@ -51,12 +51,6 @@ public class Utils {
*/ */
public static final BigInteger CENT = new BigInteger("1000000", 10); public static final BigInteger CENT = new BigInteger("1000000", 10);
private static final boolean logging;
static {
logging = Boolean.parseBoolean(System.getProperty("bitcoinj.logging", "false"));
}
/** 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;
@ -195,16 +189,6 @@ public class Utils {
return ((bytes[offset] & 0xff) << 8) | bytes[offset + 1] & 0xff; return ((bytes[offset] & 0xff) << 8) | bytes[offset + 1] & 0xff;
} }
static void LOG(String msg) {
// Set this to true to see debug prints from the library.
if (logging) {
System.err.print("BitCoin: ");
System.err.println(msg);
System.err.flush();
System.out.flush();
}
}
/** /**
* Calculates RIPEMD160(SHA256(input)). This is used in Address calculations. * Calculates RIPEMD160(SHA256(input)). This is used in Address calculations.
*/ */

View File

@ -16,11 +16,13 @@
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.*; import java.util.*;
import static com.google.bitcoin.core.Utils.LOG;
import static com.google.bitcoin.core.Utils.bitcoinValueToFriendlyString; import static com.google.bitcoin.core.Utils.bitcoinValueToFriendlyString;
/** /**
@ -33,6 +35,7 @@ import static com.google.bitcoin.core.Utils.bitcoinValueToFriendlyString;
* pull in a potentially large (code-size) third party serialization library.<p> * pull in a potentially large (code-size) third party serialization library.<p>
*/ */
public class Wallet implements Serializable { public class Wallet implements Serializable {
private static final Logger log = LoggerFactory.getLogger(Wallet.class);
private static final long serialVersionUID = 2L; private static final long serialVersionUID = 2L;
// Algorithm for movement of transactions between pools. Outbound tx = us spending coins. Inbound tx = us // Algorithm for movement of transactions between pools. Outbound tx = us spending coins. Inbound tx = us
@ -203,14 +206,14 @@ public class Wallet implements Serializable {
BigInteger valueSentToMe = tx.getValueSentToMe(this); BigInteger valueSentToMe = tx.getValueSentToMe(this);
BigInteger valueDifference = valueSentToMe.subtract(valueSentFromMe); BigInteger valueDifference = valueSentToMe.subtract(valueSentFromMe);
LOG("Wallet: Received tx" + (sideChain ? " on a side chain" :"") + " for " + log.info("Wallet: Received tx" + (sideChain ? " on a side chain" :"") + " for " +
bitcoinValueToFriendlyString(valueDifference) + " BTC"); bitcoinValueToFriendlyString(valueDifference) + " BTC");
// If this transaction is already in the wallet we may need to move it into a different pool. At the very // If this transaction is already in the wallet we may need to move it into a different pool. At the very
// least we need to ensure we're manipulating the canonical object rather than a duplicate. // least we need to ensure we're manipulating the canonical object rather than a duplicate.
Transaction wtx = null; Transaction wtx = null;
if ((wtx = pending.remove(txHash)) != null) { if ((wtx = pending.remove(txHash)) != null) {
LOG(" <-pending"); log.info(" <-pending");
// A transaction we created appeared in a block. Probably this is a spend we broadcast that has been // A transaction we created appeared in a block. Probably this is a spend we broadcast that has been
// accepted by the network. // accepted by the network.
// //
@ -219,19 +222,19 @@ public class Wallet implements Serializable {
if (bestChain) { if (bestChain) {
if (valueSentToMe.equals(BigInteger.ZERO)) { if (valueSentToMe.equals(BigInteger.ZERO)) {
// There were no change transactions so this tx is fully spent. // There were no change transactions so this tx is fully spent.
LOG(" ->spent"); log.info(" ->spent");
boolean alreadyPresent = spent.put(wtx.getHash(), wtx) != null; boolean alreadyPresent = spent.put(wtx.getHash(), wtx) != null;
assert !alreadyPresent : "TX in both pending and spent pools"; assert !alreadyPresent : "TX in both pending and spent pools";
} else { } else {
// There was change back to us, or this tx was purely a spend back to ourselves (perhaps for // There was change back to us, or this tx was purely a spend back to ourselves (perhaps for
// anonymization purposes). // anonymization purposes).
LOG(" ->unspent"); log.info(" ->unspent");
boolean alreadyPresent = unspent.put(wtx.getHash(), wtx) != null; boolean alreadyPresent = unspent.put(wtx.getHash(), wtx) != null;
assert !alreadyPresent : "TX in both pending and unspent pools"; assert !alreadyPresent : "TX in both pending and unspent pools";
} }
} else if (sideChain) { } else if (sideChain) {
// The transaction was accepted on an inactive side chain, but not yet by the best chain. // The transaction was accepted on an inactive side chain, but not yet by the best chain.
LOG(" ->inactive"); log.info(" ->inactive");
// It's OK for this to already be in the inactive pool because there can be multiple independent side // It's OK for this to already be in the inactive pool because there can be multiple independent side
// chains in which it appears: // chains in which it appears:
// //
@ -240,7 +243,7 @@ public class Wallet implements Serializable {
// \-> b4 (at this point it's already present in 'inactive' // \-> b4 (at this point it's already present in 'inactive'
boolean alreadyPresent = inactive.put(wtx.getHash(), wtx) != null; boolean alreadyPresent = inactive.put(wtx.getHash(), wtx) != null;
if (alreadyPresent) if (alreadyPresent)
LOG("Saw a transaction be incorporated into multiple independent side chains"); log.info("Saw a transaction be incorporated into multiple independent side chains");
// Put it back into the pending pool, because 'pending' means 'waiting to be included in best chain'. // Put it back into the pending pool, because 'pending' means 'waiting to be included in best chain'.
pending.put(wtx.getHash(), wtx); pending.put(wtx.getHash(), wtx);
} }
@ -250,14 +253,14 @@ public class Wallet implements Serializable {
// This TX didn't originate with us. It could be sending us coins and also spending our own coins if keys // This TX didn't originate with us. It could be sending us coins and also spending our own coins if keys
// are being shared between different wallets. // are being shared between different wallets.
if (sideChain) { if (sideChain) {
LOG(" ->inactive"); log.info(" ->inactive");
inactive.put(tx.getHash(), tx); inactive.put(tx.getHash(), tx);
} else if (bestChain) { } else if (bestChain) {
processTxFromBestChain(tx); processTxFromBestChain(tx);
} }
} }
LOG("Balance is now: " + bitcoinValueToFriendlyString(getBalance())); log.info("Balance is now: " + bitcoinValueToFriendlyString(getBalance()));
// Inform anyone interested that we have new coins. Note: we may be re-entered by the event listener, // Inform anyone interested that we have new coins. Note: we may be re-entered by the event listener,
// so we must not make assumptions about our state after this loop returns! For example, // so we must not make assumptions about our state after this loop returns! For example,
@ -281,12 +284,12 @@ public class Wallet implements Serializable {
updateForSpends(tx); updateForSpends(tx);
if (!tx.getValueSentToMe(this).equals(BigInteger.ZERO)) { if (!tx.getValueSentToMe(this).equals(BigInteger.ZERO)) {
// It's sending us coins. // It's sending us coins.
LOG(" ->unspent"); log.info(" ->unspent");
boolean alreadyPresent = unspent.put(tx.getHash(), tx) != null; boolean alreadyPresent = unspent.put(tx.getHash(), tx) != null;
assert !alreadyPresent : "TX was received twice"; assert !alreadyPresent : "TX was received twice";
} else { } else {
// It spent some of our coins and did not send us any. // It spent some of our coins and did not send us any.
LOG(" ->spent"); log.info(" ->spent");
boolean alreadyPresent = spent.put(tx.getHash(), tx) != null; boolean alreadyPresent = spent.put(tx.getHash(), tx) != null;
assert !alreadyPresent : "TX was received twice"; assert !alreadyPresent : "TX was received twice";
} }
@ -302,16 +305,16 @@ public class Wallet implements Serializable {
if (input.outpoint.connect(unspent.values())) { if (input.outpoint.connect(unspent.values())) {
TransactionOutput output = input.outpoint.getConnectedOutput(); TransactionOutput output = input.outpoint.getConnectedOutput();
assert !output.isSpent : "Double spend accepted by the network?"; assert !output.isSpent : "Double spend accepted by the network?";
LOG(" Saw some of my unspent outputs be spent by someone else who has my keys."); log.info(" Saw some of my unspent outputs be spent by someone else who has my keys.");
LOG(" Total spent value is " + bitcoinValueToFriendlyString(output.getValue())); log.info(" Total spent value is " + bitcoinValueToFriendlyString(output.getValue()));
output.isSpent = true; output.isSpent = true;
Transaction connectedTx = input.outpoint.fromTx; Transaction connectedTx = input.outpoint.fromTx;
if (connectedTx.getValueSentToMe(this, false).equals(BigInteger.ZERO)) { if (connectedTx.getValueSentToMe(this, false).equals(BigInteger.ZERO)) {
// There's nothing left I can spend in this transaction. // There's nothing left I can spend in this transaction.
if (unspent.remove(connectedTx.getHash()) != null); if (unspent.remove(connectedTx.getHash()) != null);
LOG(" prevtx <-unspent"); log.info(" prevtx <-unspent");
spent.put(connectedTx.getHash(), connectedTx); spent.put(connectedTx.getHash(), connectedTx);
LOG(" prevtx ->spent"); log.info(" prevtx ->spent");
} }
} }
} }
@ -400,7 +403,7 @@ public class Wallet implements Serializable {
* @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) {
LOG("Creating send tx to " + address.toString() + " for " + log.info("Creating send tx to " + address.toString() + " for " +
bitcoinValueToFriendlyString(nanocoins)); bitcoinValueToFriendlyString(nanocoins));
// To send money to somebody else, we need to do gather up transactions with unspent outputs until we have // To send money to somebody else, we need to do gather up transactions with unspent outputs until we have
// sufficient value. Many coin selection algorithms are possible, we use a simple but suboptimal one. // sufficient value. Many coin selection algorithms are possible, we use a simple but suboptimal one.
@ -418,7 +421,7 @@ public class Wallet implements Serializable {
} }
// Can we afford this? // Can we afford this?
if (valueGathered.compareTo(nanocoins) < 0) { if (valueGathered.compareTo(nanocoins) < 0) {
LOG("Insufficient value in wallet for send, missing " + log.info("Insufficient value in wallet for send, missing " +
bitcoinValueToFriendlyString(nanocoins.subtract(valueGathered))); bitcoinValueToFriendlyString(nanocoins.subtract(valueGathered)));
// TODO: Should throw an exception here. // TODO: Should throw an exception here.
return null; return null;
@ -431,7 +434,7 @@ public class Wallet implements Serializable {
// The value of the inputs is greater than what we want to send. Just like in real life then, // The value of the inputs is greater than what we want to send. Just like in real life then,
// we need to take back some coins ... this is called "change". Add another output that sends the change // we need to take back some coins ... this is called "change". Add another output that sends the change
// back to us. // back to us.
LOG(" with " + bitcoinValueToFriendlyString(change) + " coins change"); log.info(" with " + bitcoinValueToFriendlyString(change) + " coins change");
sendTx.addOutput(new TransactionOutput(params, change, changeAddress, sendTx)); sendTx.addOutput(new TransactionOutput(params, change, changeAddress, sendTx));
} }
for (TransactionOutput output : gathered) { for (TransactionOutput output : gathered) {
@ -567,7 +570,7 @@ public class Wallet implements Serializable {
// If there is no difference it means we the user doesn't really care about this re-org but we still need to // If there is no difference it means we the user doesn't really care about this re-org but we still need to
// update the transaction block pointers for next time. // update the transaction block pointers for next time.
boolean affectedUs = !oldChainTransactions.equals(newChainTransactions); boolean affectedUs = !oldChainTransactions.equals(newChainTransactions);
LOG(affectedUs ? "Re-org affected our transactions" : "Re-org had no effect on our transactions"); log.info(affectedUs ? "Re-org affected our transactions" : "Re-org had no effect on our transactions");
if (!affectedUs) return; if (!affectedUs) return;
// Transactions that were in the old chain but aren't in the new chain. These will become inactive. // Transactions that were in the old chain but aren't in the new chain. These will become inactive.
@ -579,7 +582,7 @@ public class Wallet implements Serializable {
assert !(gone.isEmpty() && fresh.isEmpty()) : "There must have been some changes to get here"; assert !(gone.isEmpty() && fresh.isEmpty()) : "There must have been some changes to get here";
for (Transaction tx : gone) { for (Transaction tx : gone) {
LOG("tx not in new chain: <-unspent/spent ->inactive\n" + tx.toString()); log.info("tx not in new chain: <-unspent/spent ->inactive\n" + tx.toString());
unspent.remove(tx.getHash()); unspent.remove(tx.getHash());
spent.remove(tx.getHash()); spent.remove(tx.getHash());
inactive.put(tx.getHash(), tx); inactive.put(tx.getHash(), tx);

View File

@ -18,6 +18,8 @@ package com.google.bitcoin.core;
import com.google.bitcoin.bouncycastle.util.encoders.Hex; import com.google.bitcoin.bouncycastle.util.encoders.Hex;
import org.junit.Test; import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
@ -29,7 +31,9 @@ import java.util.Arrays;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class BlockTest { public class BlockTest {
private static Logger log = LoggerFactory.getLogger(BlockTest.class);
static final NetworkParameters params = NetworkParameters.testNet(); static final NetworkParameters params = NetworkParameters.testNet();
static final byte[] blockBytes; static final byte[] blockBytes;
static { static {
@ -139,8 +143,6 @@ public class BlockTest {
// Note that this will actually check the transactions are equal by doing bitcoin serialization and checking // Note that this will actually check the transactions are equal by doing bitcoin serialization and checking
// the bytestreams are the same! A true "deep equals" is not implemented for Transaction. The primary purpose // the bytestreams are the same! A true "deep equals" is not implemented for Transaction. The primary purpose
// of this test is to ensure no errors occur during the Java serialization/deserialization process. // of this test is to ensure no errors occur during the Java serialization/deserialization process.
Utils.LOG(Utils.bytesToHexString(tx.bitcoinSerialize()));
Utils.LOG(Utils.bytesToHexString(tx2.bitcoinSerialize()));
assertEquals(tx, tx2); assertEquals(tx, tx2);
} }
} }