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.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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}.
*/
public class Block extends Message {
private static final Logger log = LoggerFactory.getLogger(Block.class);
private static final long serialVersionUID = 2738848929966035281L;
/** How many bytes are required to represent a block header. */
@ -263,8 +267,8 @@ public class Block extends Message {
List<byte[]> tree = buildMerkleTree();
byte[] calculatedRoot = tree.get(tree.size() - 1);
if (!Arrays.equals(calculatedRoot, merkleRoot)) {
LOG("Merkle tree did not verify: ");
for (byte[] b : tree) LOG(Utils.bytesToHexString(b));
log.error("Merkle tree did not verify: ");
for (byte[] b : tree) log.error(Utils.bytesToHexString(b));
throw new VerificationException("Merkle hashes do not match: " +
bytesToHexString(calculatedRoot) + " vs " + bytesToHexString(merkleRoot));

View File

@ -19,7 +19,8 @@ package com.google.bitcoin.core;
import java.math.BigInteger;
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
@ -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.
*/
public class BlockChain {
private static final Logger log = LoggerFactory.getLogger(BlockChain.class);
/** Keeps a map of block hashes to StoredBlocks. */
protected BlockStore blockStore;
@ -78,7 +81,7 @@ public class BlockChain {
try {
this.blockStore = blockStore;
chainHead = blockStore.getChainHead();
LOG("chain head is: " + chainHead.getHeader().toString());
log.info("chain head is:\n{}", chainHead.getHeader());
} catch (BlockStoreException e) {
throw new RuntimeException(e);
}
@ -103,9 +106,9 @@ public class BlockChain {
private synchronized boolean add(Block block, boolean tryConnecting)
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) {
LOG("Already have block");
log.info("Already have block");
return true;
}
@ -113,8 +116,8 @@ public class BlockChain {
try {
block.verify();
} catch (VerificationException e) {
LOG("Failed to verify block: " + e.toString());
LOG(block.toString());
log.error("Failed to verify block:", e);
log.error(block.toString());
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
// 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.
LOG("Block does not connect: " + block.getHashAsString());
log.warn("Block does not connect: {}", block.getHashAsString());
unconnectedBlocks.add(block);
return false;
} else {
@ -152,7 +155,7 @@ public class BlockChain {
if (storedPrev.equals(chainHead)) {
// This block connects to the best known block, it is a normal continuation of the system.
setChainHead(newStoredBlock);
LOG("Chain is now " + chainHead.getHeight() + " blocks high");
log.info("Chain is now {} blocks high", chainHead.getHeight());
if (newTransactions != null)
sendTransactionsToWallet(newStoredBlock, NewBlockType.BEST_CHAIN, newTransactions);
} 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.
boolean causedSplit = newStoredBlock.moreWorkThan(chainHead);
if (causedSplit) {
LOG("Block is causing a re-organize");
log.info("Block is causing a re-organize");
} 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
@ -187,10 +190,10 @@ public class BlockChain {
// Firstly, calculate the block at which the chain diverged. We only need to examine the
// chain from beyond this block to find differences.
StoredBlock splitPoint = findSplit(newChainHead, chainHead);
LOG("Re-organize after split at height " + splitPoint.getHeight());
LOG("Old chain head: " + chainHead.getHeader().getHashAsString());
LOG("New chain head: " + newChainHead.getHeader().getHashAsString());
LOG("Split at block: " + splitPoint.getHeader().getHashAsString());
log.info("Re-organize after split at height {}", splitPoint.getHeight());
log.info("Old chain head: {}", chainHead.getHeader().getHashAsString());
log.info("New chain head: {}", newChainHead.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.
Set<StoredBlock> oldBlocks = getPartialChain(chainHead, splitPoint);
Set<StoredBlock> newBlocks = getPartialChain(newChainHead, splitPoint);
@ -267,7 +270,7 @@ public class BlockChain {
} catch (ScriptException e) {
// 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.
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++;
}
if (blocksConnectedThisRound > 0) {
LOG("Connected " + blocksConnectedThisRound + " floating blocks.");
log.info("Connected {} floating blocks.", blocksConnectedThisRound);
}
} while (blocksConnectedThisRound > 0);
}
@ -353,7 +356,7 @@ public class BlockChain {
newDifficulty = newDifficulty.divide(BigInteger.valueOf(params.targetTimespan));
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;
}

View File

@ -21,13 +21,16 @@ import java.nio.ByteBuffer;
import java.util.HashMap;
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.
* 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 {
private static final Logger log = LoggerFactory.getLogger(DiskBlockStore.class);
private FileOutputStream stream;
private Map<Sha256Hash, StoredBlock> blockMap;
private Sha256Hash chainHead;
@ -40,7 +43,7 @@ public class DiskBlockStore implements BlockStore {
load(file);
stream = new FileOutputStream(file, true); // Do append.
} catch (IOException e) {
LOG(e.toString());
log.error("failed to load block store from file", e);
createNewStore(params, file);
}
}
@ -70,7 +73,7 @@ public class DiskBlockStore implements BlockStore {
}
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));
// Read a version byte.
int version = input.read();
@ -85,7 +88,7 @@ public class DiskBlockStore implements BlockStore {
byte[] chainHeadHash = new byte[32];
input.read(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();
// Rest of file is raw block headers.
byte[] headerBytes = new byte[Block.HEADER_SIZE];
@ -126,7 +129,7 @@ public class DiskBlockStore implements BlockStore {
throw new BlockStoreException(e);
}
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 {

View File

@ -16,6 +16,9 @@
package com.google.bitcoin.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.*;
import java.util.HashSet;
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().
*/
public class DnsDiscovery implements PeerDiscovery {
private static final Logger log = LoggerFactory.getLogger(DnsDiscovery.class);
private String[] hostNames;
private NetworkParameters netParams;
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) {
failedLookups++;
Utils.LOG("DNS lookup for " + hostName + " failed.");
log.info("DNS lookup for " + hostName + " failed.");
if (failedLookups == hostNames.length) {
// All the lookups failed.

View File

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

View File

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

View File

@ -23,7 +23,8 @@ import java.util.LinkedList;
import java.util.List;
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
@ -31,6 +32,8 @@ import static com.google.bitcoin.core.Utils.LOG;
* with the network. All these threads synchronize on the block chain.
*/
public class Peer {
private static final Logger log = LoggerFactory.getLogger(Peer.class);
private final NetworkConnection conn;
private final NetworkParameters params;
private Thread thread;
@ -88,13 +91,13 @@ public class Peer {
// properly explore the network.
} else {
// TODO: Handle the other messages we can receive.
LOG("Received unhandled message: " + m.toString());
log.warn("Received unhandled message: {}", m);
}
}
} catch (Exception e) {
if (e instanceof IOException && !running) {
// 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 {
// We caught an unexpected exception.
e.printStackTrace();
@ -144,12 +147,10 @@ public class Peer {
}
} catch (VerificationException e) {
// We don't want verification failures to kill the thread.
LOG(e.toString());
e.printStackTrace();
log.warn("block verification failed", e);
} catch (ScriptException e) {
// We don't want script failures to kill the thread.
LOG(e.toString());
e.printStackTrace();
log.warn("script exception", e);
}
}
@ -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
// 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.
List<byte[]> blockLocator = new LinkedList<byte[]>();

View File

@ -26,7 +26,9 @@ import java.util.ArrayList;
import java.util.List;
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;
/**
@ -38,6 +40,8 @@ import static com.google.bitcoin.core.Utils.bytesToHexString;
* transactions generated by the official client, but non-standard transactions will fail.
*/
public class Script {
private static Logger log = LoggerFactory.getLogger(Script.class);
// Some constants used for decoding the scripts.
public static final int OP_PUSHDATA1 = 76;
public static final int OP_PUSHDATA2 = 77;
@ -171,7 +175,7 @@ public class Script {
chunks.add(getData(len));
} else if (opcode == OP_PUSHDATA4) {
// Read a uint32, then read that many bytes of data.
LOG("PUSHDATA4: Unimplemented");
log.error("PUSHDATA4: Unimplemented");
} else {
chunks.add(new byte[] { (byte) opcode });
}
@ -260,11 +264,11 @@ public class Script {
case OP_EQUALVERIFY: opEqualVerify(); break;
case OP_CHECKSIG: opCheckSig(context); break;
default:
if (tracing) LOG("Unknown/unimplemented opcode: " + opcode);
log.debug("Unknown/unimplemented opcode: {}", opcode);
}
} else {
// Data block, push it onto the stack.
if (tracing) LOG("Push " + Utils.bytesToHexString(chunk));
log.debug("Push {}", Utils.bytesToHexString(chunk));
stack.add(chunk);
}
}
@ -276,7 +280,7 @@ public class Script {
void logStack() {
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];
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) {
// TODO: Fix the unit tests to run scripts in transaction context then remove this.
pushBool(true);
@ -327,7 +331,7 @@ public class Script {
}
private void opEqualVerify() throws ScriptException {
if (tracing) LOG("EQUALVERIFY");
log.debug("EQUALVERIFY");
byte[] a = stack.pop();
byte[] b = stack.pop();
if (!Arrays.areEqual(a, b))
@ -340,12 +344,12 @@ public class Script {
byte[] buf = stack.pop();
byte[] hash = Utils.sha256hash160(buf);
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 */
private void opDup() {
if (tracing) LOG("DUP");
log.debug("DUP");
stack.add(Arrays.clone(stack.lastElement()));
}

View File

@ -23,6 +23,9 @@ import java.io.Serializable;
import java.math.BigInteger;
import java.util.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.bitcoin.core.Utils.*;
/**
@ -35,6 +38,7 @@ import static com.google.bitcoin.core.Utils.*;
* or UI purposes.
*/
public class Transaction extends Message implements Serializable {
private static final Logger log = LoggerFactory.getLogger(Transaction.class);
private static final long serialVersionUID = -8567546957352643140L;
// 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.
boolean anyoneCanPay = false;
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.
input.scriptBytes = TransactionInput.EMPTY_ARRAY;

View File

@ -51,12 +51,6 @@ public class Utils {
*/
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. */
public static BigInteger toNanoCoins(int coins, int cents) {
assert cents < 100;
@ -195,16 +189,6 @@ public class Utils {
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.
*/

View File

@ -16,11 +16,13 @@
package com.google.bitcoin.core;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.math.BigInteger;
import java.util.*;
import static com.google.bitcoin.core.Utils.LOG;
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>
*/
public class Wallet implements Serializable {
private static final Logger log = LoggerFactory.getLogger(Wallet.class);
private static final long serialVersionUID = 2L;
// 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 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");
// 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.
Transaction wtx = 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
// accepted by the network.
//
@ -219,19 +222,19 @@ public class Wallet implements Serializable {
if (bestChain) {
if (valueSentToMe.equals(BigInteger.ZERO)) {
// There were no change transactions so this tx is fully spent.
LOG(" ->spent");
log.info(" ->spent");
boolean alreadyPresent = spent.put(wtx.getHash(), wtx) != null;
assert !alreadyPresent : "TX in both pending and spent pools";
} else {
// There was change back to us, or this tx was purely a spend back to ourselves (perhaps for
// anonymization purposes).
LOG(" ->unspent");
log.info(" ->unspent");
boolean alreadyPresent = unspent.put(wtx.getHash(), wtx) != null;
assert !alreadyPresent : "TX in both pending and unspent pools";
}
} else if (sideChain) {
// 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
// chains in which it appears:
//
@ -240,7 +243,7 @@ public class Wallet implements Serializable {
// \-> b4 (at this point it's already present in 'inactive'
boolean alreadyPresent = inactive.put(wtx.getHash(), wtx) != null;
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'.
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
// are being shared between different wallets.
if (sideChain) {
LOG(" ->inactive");
log.info(" ->inactive");
inactive.put(tx.getHash(), tx);
} else if (bestChain) {
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,
// 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);
if (!tx.getValueSentToMe(this).equals(BigInteger.ZERO)) {
// It's sending us coins.
LOG(" ->unspent");
log.info(" ->unspent");
boolean alreadyPresent = unspent.put(tx.getHash(), tx) != null;
assert !alreadyPresent : "TX was received twice";
} else {
// 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;
assert !alreadyPresent : "TX was received twice";
}
@ -302,16 +305,16 @@ public class Wallet implements Serializable {
if (input.outpoint.connect(unspent.values())) {
TransactionOutput output = input.outpoint.getConnectedOutput();
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(" Total spent value is " + bitcoinValueToFriendlyString(output.getValue()));
log.info(" Saw some of my unspent outputs be spent by someone else who has my keys.");
log.info(" Total spent value is " + bitcoinValueToFriendlyString(output.getValue()));
output.isSpent = true;
Transaction connectedTx = input.outpoint.fromTx;
if (connectedTx.getValueSentToMe(this, false).equals(BigInteger.ZERO)) {
// There's nothing left I can spend in this transaction.
if (unspent.remove(connectedTx.getHash()) != null);
LOG(" prevtx <-unspent");
log.info(" prevtx <-unspent");
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.
*/
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));
// 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.
@ -418,7 +421,7 @@ public class Wallet implements Serializable {
}
// Can we afford this?
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)));
// TODO: Should throw an exception here.
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,
// we need to take back some coins ... this is called "change". Add another output that sends the change
// back to us.
LOG(" with " + bitcoinValueToFriendlyString(change) + " coins change");
log.info(" with " + bitcoinValueToFriendlyString(change) + " coins change");
sendTx.addOutput(new TransactionOutput(params, change, changeAddress, sendTx));
}
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
// update the transaction block pointers for next time.
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;
// 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";
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());
spent.remove(tx.getHash());
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 org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -29,7 +31,9 @@ import java.util.Arrays;
import static org.junit.Assert.*;
public class BlockTest {
private static Logger log = LoggerFactory.getLogger(BlockTest.class);
static final NetworkParameters params = NetworkParameters.testNet();
static final byte[] blockBytes;
static {
@ -139,8 +143,6 @@ public class BlockTest {
// 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
// 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);
}
}