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:
parent
a32a612630
commit
068dcba122
BIN
lib/slf4j-api-1.6.1.jar
Normal file
BIN
lib/slf4j-api-1.6.1.jar
Normal file
Binary file not shown.
BIN
lib/slf4j-simple-1.6.1.jar
Normal file
BIN
lib/slf4j-simple-1.6.1.jar
Normal file
Binary file not shown.
@ -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));
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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.
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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[]>();
|
||||||
|
@ -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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user