diff --git a/docs/com/google/bitcoin/core/Block.html b/docs/com/google/bitcoin/core/Block.html
index cc4922d9..b33355dd 100644
--- a/docs/com/google/bitcoin/core/Block.html
+++ b/docs/com/google/bitcoin/core/Block.html
@@ -73,9 +73,9 @@ function windowTitle()
- SUMMARY: NESTED | FIELD | CONSTR | METHOD |
+ SUMMARY: NESTED | FIELD | CONSTR | METHOD
-DETAIL: FIELD | CONSTR | METHOD |
+DETAIL: FIELD | CONSTR | METHOD
@@ -124,14 +124,6 @@ A block is the foundation of the BitCoin system. It records a set of
Field Summary
-
-
-static long |
-ALLOWED_TIME_DRIFT
-
-
- |
-
@@ -186,6 +178,22 @@ A block is the foundation of the BitCoin system. It records a set of
+ long |
+getDifficultyTarget()
+
+
+ Returns the difficulty of the proof of work that this block should meet encoded in compact form. |
+
+
+
+ java.math.BigInteger |
+getDifficultyTargetBI()
+
+
+ Returns the difficulty target as a 256 bit value that can be compared to a SHA-256 hash. |
+
+
+
byte[] |
getHash()
@@ -211,9 +219,90 @@ A block is the foundation of the BitCoin system. It records a set of
|
+ long |
+getNonce()
+
+
+ Returns the nonce, an arbitrary value that exists only to make the hash of the block header fall below the
+ difficulty target. |
+
+
+
+ byte[] |
+getPrevBlockHash()
+
+
+ Returns the hash of the previous block in the chain, as defined by the block header. |
+
+
+
+ long |
+getTime()
+
+
+ Returns the time at which the block was solved and broadcast, according to the clock of the solving node. |
+
+
+
+ long |
+getVersion()
+
+
+ Returns the version of the block data structure as defined by the BitCoin protocol. |
+
+
+
int |
hashCode()
+
+ |
+
+
+
+ void |
+setDifficultyTarget(long compactForm)
+
+
+ |
+
+
+
+ void |
+setMerkleRoot(byte[] value)
+
+
+ |
+
+
+
+ void |
+setNonce(long nonce)
+
+
+ |
+
+
+
+ void |
+setPrevBlockHash(byte[] prevBlockHash)
+
+
+ |
+
+
+
+ void |
+setTime(long time)
+
+
+ |
+
+
+
+ void |
+setVersion(long version)
+
|
@@ -255,25 +344,6 @@ A block is the foundation of the BitCoin system. It records a set of
-
-
-
-ALLOWED_TIME_DRIFT
-
-public static final long ALLOWED_TIME_DRIFT
-
-
-- See Also:
- Constant Field Values
-
-
@@ -414,6 +484,17 @@ public byte[] getMerkleRoot()
+
+setMerkleRoot
+
+public void setMerkleRoot(byte[] value)
+
+
+
+
+
+
+
addTransaction
@@ -425,6 +506,142 @@ public void addTransaction(
+getVersion
+
+public long getVersion()
+
+- Returns the version of the block data structure as defined by the BitCoin protocol.
+
+
+
+
+
+
+
+
+setVersion
+
+public void setVersion(long version)
+
+
+
+
+
+
+
+
+getPrevBlockHash
+
+public byte[] getPrevBlockHash()
+
+- Returns the hash of the previous block in the chain, as defined by the block header.
+
+
+
+
+
+
+
+
+setPrevBlockHash
+
+public void setPrevBlockHash(byte[] prevBlockHash)
+
+
+
+
+
+
+
+
+getTime
+
+public long getTime()
+
+- Returns the time at which the block was solved and broadcast, according to the clock of the solving node.
+
+
+
+
+
+
+
+
+setTime
+
+public void setTime(long time)
+
+
+
+
+
+
+
+
+getDifficultyTarget
+
+public long getDifficultyTarget()
+
+- Returns the difficulty of the proof of work that this block should meet encoded in compact form. The
+
BlockChain
verifies that this is not too easy by looking at the length of the chain when the block is
+ added. To find the actual value the hash should be compared against, use getDifficultyTargetBI.
+
+
+
+
+
+
+
+
+getDifficultyTargetBI
+
+public java.math.BigInteger getDifficultyTargetBI()
+
+- Returns the difficulty target as a 256 bit value that can be compared to a SHA-256 hash.
+
+
+
+
+
+
+
+
+setDifficultyTarget
+
+public void setDifficultyTarget(long compactForm)
+
+
+
+
+
+
+
+
+getNonce
+
+public long getNonce()
+
+- Returns the nonce, an arbitrary value that exists only to make the hash of the block header fall below the
+ difficulty target.
+
+
+
+
+
+
+
+
+setNonce
+
+public void setNonce(long nonce)
+
+
+
+
+
@@ -476,9 +693,9 @@ public void addTransaction(
- SUMMARY: NESTED | FIELD | CONSTR | METHOD
+ SUMMARY: NESTED | FIELD | CONSTR | METHOD
-DETAIL: FIELD | CONSTR | METHOD |
+DETAIL: FIELD | CONSTR | METHOD
diff --git a/docs/com/google/bitcoin/core/NetworkConnection.html b/docs/com/google/bitcoin/core/NetworkConnection.html
index f5622071..d5792e03 100644
--- a/docs/com/google/bitcoin/core/NetworkConnection.html
+++ b/docs/com/google/bitcoin/core/NetworkConnection.html
@@ -162,6 +162,14 @@ A NetworkConnection handles talking to a remote BitCoin peer at a low level. It
+ java.lang.String |
+toString()
+
+
+ |
+
+
+
void |
writeMessage(java.lang.String tag,
Message message)
@@ -176,7 +184,7 @@ A NetworkConnection handles talking to a remote BitCoin peer at a low level. It
| Methods inherited from class java.lang.Object |
-clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
+clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait |
@@ -253,19 +261,35 @@ public void shutdown()
+
+toString
+
+public java.lang.String toString()
+
+
+- Overrides:
toString
in class java.lang.Object
+
+
+
+
+
+
+
readMessage
public Message readMessage()
- throws ProtocolException
+ throws java.io.IOException,
+ ProtocolException
- Reads a network message from the wire, blocking until the message is fully received.
-- Returns:
- An instance of a Message subclass.
+
- Returns:
- An instance of a Message subclass
- Throws:
-
ProtocolException
- if the message is badly formatted, failed checksum or there was a protocol failure.
+ProtocolException
- if the message is badly formatted, failed checksum or there was a TCP failure.
+java.io.IOException
diff --git a/docs/constant-values.html b/docs/constant-values.html
index f6bd916b..cef3b8e4 100644
--- a/docs/constant-values.html
+++ b/docs/constant-values.html
@@ -95,24 +95,6 @@ com.google.*
-
-
-
-
-
-
com.google.bitcoin.core.Message |
diff --git a/docs/index-all.html b/docs/index-all.html
index 6f98fc12..99b512f7 100644
--- a/docs/index-all.html
+++ b/docs/index-all.html
@@ -112,9 +112,6 @@ Variable in class com.google.bitcoin.core.AddressMessage - Class in com.google.bitcoin.core addTransaction(Transaction) -
Method in class com.google.bitcoin.core.Block
Adds a transaction to this block.
-ALLOWED_TIME_DRIFT -
-Static variable in class com.google.bitcoin.core.Block
-
@@ -272,6 +269,12 @@ Constructor for class com.google.bitcoin.core.GetDataMessage - Class in com.google.bitcoin.core GetDataMessage(NetworkParameters, byte[]) -
Constructor for class com.google.bitcoin.core.GetDataMessage
+getDifficultyTarget() -
+Method in class com.google.bitcoin.core.Block
+Returns the difficulty of the proof of work that this block should meet encoded in compact form.
+getDifficultyTargetBI() -
+Method in class com.google.bitcoin.core.Block
+Returns the difficulty target as a 256 bit value that can be compared to a SHA-256 hash.
getFromAddress() -
Method in class com.google.bitcoin.core.Script
Convenience wrapper around getPubKey.
@@ -300,6 +303,13 @@ Method in class com.google.bitcoin.core.getMerkleRoot() -
Method in class com.google.bitcoin.core.Block
Returns the merkle root in big endian form, calculating it from transactions if necessary.
+getNonce() -
+Method in class com.google.bitcoin.core.Block
+Returns the nonce, an arbitrary value that exists only to make the hash of the block header fall below the
+ difficulty target.
+getPrevBlockHash() -
+Method in class com.google.bitcoin.core.Block
+Returns the hash of the previous block in the chain, as defined by the block header.
getPubKey() -
Method in class com.google.bitcoin.core.ECKey
Gets the raw public key value.
@@ -325,6 +335,9 @@ Method in class com.google.bitcoin.core.getSizeInBytes() -
Method in class com.google.bitcoin.core.VarInt
+getTime() -
+Method in class com.google.bitcoin.core.Block
+Returns the time at which the block was solved and broadcast, according to the clock of the solving node.
getToAddress() -
Method in class com.google.bitcoin.core.Script
Gets the destination address from this script, if it's in the required form (see getPubKey).
@@ -340,6 +353,9 @@ Method in class com.google.bitcoin.core.getValueSentToMe(Wallet) -
Method in class com.google.bitcoin.core.Transaction
Returns the sum of the outputs that are sending coins to a key in our wallet.
+getVersion() -
+Method in class com.google.bitcoin.core.Block
+Returns the version of the block data structure as defined by the BitCoin protocol.
@@ -594,9 +610,27 @@ Constructor for exception com.google.bitcoin.core.sendCoins(Peer, Address, BigInteger) -
Method in class com.google.bitcoin.core.Wallet
Sends coins to the given address, via the given Peer
.
+setDifficultyTarget(long) -
+Method in class com.google.bitcoin.core.Block
+
+setMerkleRoot(byte[]) -
+Method in class com.google.bitcoin.core.Block
+
+setNonce(long) -
+Method in class com.google.bitcoin.core.Block
+
+setPrevBlockHash(byte[]) -
+Method in class com.google.bitcoin.core.Block
+
+setTime(long) -
+Method in class com.google.bitcoin.core.Block
+
setTracing(boolean) -
Method in class com.google.bitcoin.core.Script
If true, running a program will log its instructions.
+setVersion(long) -
+Method in class com.google.bitcoin.core.Block
+
sha256hash160(byte[]) -
Static method in class com.google.bitcoin.core.Utils
Calculates RIPEMD160(SHA256(input)).
@@ -650,6 +684,9 @@ Method in class com.google.bitcoin.core.toString() -
Method in class com.google.bitcoin.core.InventoryItem
+toString() -
+Method in class com.google.bitcoin.core.NetworkConnection
+
toString() -
Method in class com.google.bitcoin.core.PeerAddress
diff --git a/docs/serialized-form.html b/docs/serialized-form.html
index 3d3e48b0..7fa49946 100644
--- a/docs/serialized-form.html
+++ b/docs/serialized-form.html
@@ -204,6 +204,8 @@ transactions
java.util.List<E> transactions
+- If null, it means this object holds only the headers.
+
@@ -213,6 +215,8 @@ hash
byte[] hash
+- Stores the hash of the block. If null, getHash() will recalculate it.
+
diff --git a/src/com/google/bitcoin/core/Block.java b/src/com/google/bitcoin/core/Block.java
index e4af58cd..a244486a 100644
--- a/src/com/google/bitcoin/core/Block.java
+++ b/src/com/google/bitcoin/core/Block.java
@@ -33,18 +33,22 @@ import static com.google.bitcoin.core.Utils.*;
* you grab it from a downloaded {@link BlockChain}.
*/
public class Block extends Message {
- public static final long ALLOWED_TIME_DRIFT = 2 * 60 * 60; // Same value as official client.
+ static final long ALLOWED_TIME_DRIFT = 2 * 60 * 60; // Same value as official client.
- long version;
- byte[] prevBlockHash;
- byte[] merkleRoot;
- long time;
- long difficultyTarget; // "nBits"
- long nonce;
+ /** A value for difficultyTarget (nBits) that allows half of all possible hash solutions. Used in unit testing. */
+ static final long EASIEST_DIFFICULTY_TARGET = 0x207fFFFFL;
- // If null, it means this object holds only the headers.
+ private long version;
+ private byte[] prevBlockHash;
+ private byte[] merkleRoot;
+ private long time;
+ private long difficultyTarget; // "nBits"
+ private long nonce;
+
+ /** If null, it means this object holds only the headers. */
List transactions;
- byte[] hash;
+ /** Stores the hash of the block. If null, getHash() will recalculate it. */
+ private byte[] hash;
// If set, points towards the previous block in the chain. Note that a block may have multiple other blocks
// pointing back to it because despite being called a "chain", the block chain is in fact a tree. There can be
@@ -106,7 +110,9 @@ public class Block extends Message {
}
}
- /** Returns hash in little endian form */
+ /**
+ * Calculates the block hash by serializing the block and hashing the resulting bytes.
+ */
private byte[] calculateHash() {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
@@ -155,8 +161,29 @@ public class Block extends Message {
}
return s.toString();
}
-
- private void checkProofOfWork() throws VerificationException {
+
+ /**
+ * Finds a value of nonce that makes the blocks hash lower than the difficulty target. This is called mining,
+ * but solve() is far too slow to do real mining with. It exists only for unit testing purposes and is not a part
+ * of the public API.
+ *
+ * This can loop forever if a solution cannot be found solely by incrementing nonce. It doesn't change extraNonce.
+ */
+ void solve() {
+ while (true) {
+ try {
+ // Is our proof of work valid yet?
+ if (checkProofOfWork(false)) return;
+ // No, so increment the nonce and try again.
+ setNonce(getNonce() + 1);
+ } catch (VerificationException e) {
+ throw new RuntimeException(e); // Cannot happen.
+ }
+ }
+ }
+
+ /** Returns true if the hash of the block is OK (lower than difficulty target). */
+ private boolean checkProofOfWork(boolean throwException) throws VerificationException {
// This part is key - it is what proves the block was as difficult to make as it claims
// to be. Note however that in the context of this function, the block can claim to be
// as difficult as it wants to be .... if somebody was able to take control of our network
@@ -170,11 +197,16 @@ public class Block extends Message {
if (target.compareTo(BigInteger.valueOf(0)) <= 0 || target.compareTo(params.proofOfWorkLimit) > 0)
throw new VerificationException("Difficulty target is bad");
- byte[] hashBytes = (hash == null ? calculateHash() : hash);
- BigInteger h = new BigInteger(1, hashBytes);
- if (h.compareTo(target) > 0)
- throw new VerificationException("Hash is higher than target: " + bytesToHexString(hashBytes) + " vs " +
- target.toString(16));
+ BigInteger h = new BigInteger(1, getHash());
+ if (h.compareTo(target) > 0) {
+ // Proof of work check failed!
+ if (throwException)
+ throw new VerificationException("Hash is higher than target: " + getHashAsString() + " vs " +
+ target.toString(16));
+ else
+ return false;
+ }
+ return true;
}
private void checkTimestamp() throws VerificationException {
@@ -260,7 +292,7 @@ public class Block extends Message {
//
// Firstly we need to ensure this block does in fact represent real work done. If the
// difficulty is high enough, it's probably been done by the network.
- checkProofOfWork();
+ checkProofOfWork(true);
checkTimestamp();
// Now we need to check that the body of the block actually matches the headers. The
// network won't generate an invalid block, but if we didn't validate this then an
@@ -281,14 +313,12 @@ public class Block extends Message {
if (hash != null && other.hash != null)
return Arrays.equals(hash, other.hash);
// Otherwise we have to do it the slow way.
- byte[] me = bitcoinSerialize();
- byte[] them = other.bitcoinSerialize();
- return Arrays.equals(me, them);
+ return Arrays.equals(getHash(), other.getHash());
}
@Override
public int hashCode() {
- return Arrays.hashCode(hash);
+ return Arrays.hashCode(getHash());
}
/** Returns the merkle root in big endian form, calculating it from transactions if necessary. */
@@ -298,6 +328,11 @@ public class Block extends Message {
return merkleRoot;
}
+ public void setMerkleRoot(byte[] value) {
+ merkleRoot = value;
+ hash = null;
+ }
+
/**
* Adds a transaction to this block.
*/
@@ -310,4 +345,82 @@ public class Block extends Message {
merkleRoot = null;
hash = null;
}
+
+ /**
+ * Returns the version of the block data structure as defined by the BitCoin protocol.
+ */
+ public long getVersion() {
+ return version;
+ }
+
+ public void setVersion(long version) {
+ this.version = version;
+ this.hash = null;
+ }
+
+ /**
+ * Returns the hash of the previous block in the chain, as defined by the block header.
+ */
+ public byte[] getPrevBlockHash() {
+ return prevBlockHash;
+ }
+
+ public void setPrevBlockHash(byte[] prevBlockHash) {
+ this.prevBlockHash = prevBlockHash;
+ this.hash = null;
+ }
+
+ /**
+ * Returns the time at which the block was solved and broadcast, according to the clock of the solving node.
+ */
+ public long getTime() {
+ return time;
+ }
+
+ public void setTime(long time) {
+ this.time = time;
+ this.hash = null;
+ }
+
+ /**
+ * Returns the difficulty of the proof of work that this block should meet encoded in compact form. The
+ * {@link BlockChain} verifies that this is not too easy by looking at the length of the chain when the block is
+ * added. To find the actual value the hash should be compared against, use getDifficultyTargetBI.
+ */
+ public long getDifficultyTarget() {
+ return difficultyTarget;
+ }
+
+ /**
+ * Returns the difficulty target as a 256 bit value that can be compared to a SHA-256 hash.
+ */
+ public BigInteger getDifficultyTargetBI() {
+ return Utils.decodeCompactBits(getDifficultyTarget());
+ }
+
+ public void setDifficultyTarget(long compactForm) {
+ this.difficultyTarget = compactForm;
+ this.hash = null;
+ }
+
+ /**
+ * Returns the nonce, an arbitrary value that exists only to make the hash of the block header fall below the
+ * difficulty target.
+ */
+ public long getNonce() {
+ return nonce;
+ }
+
+ public void setNonce(long nonce) {
+ this.nonce = nonce;
+ this.hash = null;
+ }
+
+ /** Adds a fake coinbase transaction for unit tests. */
+ void addFakeTransaction() {
+ transactions = new ArrayList();
+ Transaction coinbase = new Transaction(params);
+ coinbase.setFakeHashForTesting(Utils.doubleDigest("test tx".getBytes()));
+ transactions.add(coinbase);
+ }
}
diff --git a/src/com/google/bitcoin/core/BlockChain.java b/src/com/google/bitcoin/core/BlockChain.java
index 889fefab..d7d3255c 100644
--- a/src/com/google/bitcoin/core/BlockChain.java
+++ b/src/com/google/bitcoin/core/BlockChain.java
@@ -107,7 +107,7 @@ public class BlockChain {
LOG("Re-received block that is currently on top of the chain.");
return true;
}
- if (!Arrays.equals(block.prevBlockHash, prev.getHash())) {
+ if (!Arrays.equals(block.getPrevBlockHash(), prev.getHash())) {
// The block does not fit onto the top of the chain. It can either be:
// - Entirely unconnected. This can happen when a new block is solved and broadcast whilst we are in
// the process of downloading the block chain.
@@ -140,7 +140,7 @@ public class BlockChain {
blocksConnectedThisRound = 0;
for (int i = 0; i < unconnectedBlocks.size(); i++) {
Block block = unconnectedBlocks.get(i);
- if (Arrays.equals(block.prevBlockHash, blockChain.getLast().getHash())) {
+ if (Arrays.equals(block.getPrevBlockHash(), blockChain.getLast().getHash())) {
// False here ensures we don't recurse infinitely downwards when connecting huge chains.
add(block, false);
unconnectedBlocks.remove(i);
@@ -163,21 +163,22 @@ public class BlockChain {
// Is this supposed to be a difficulty transition point?
if (blockChain.size() % INTERVAL != 0) {
// No ... so check the difficulty didn't actually change.
- if (top.difficultyTarget != prev.difficultyTarget)
+ if (top.getDifficultyTarget() != prev.getDifficultyTarget())
throw new VerificationException("Unexpected change in difficulty at height " + blockChain.size() +
- ": " + Long.toHexString(top.difficultyTarget) + " vs " + Long.toHexString(prev.difficultyTarget));
+ ": " + Long.toHexString(top.getDifficultyTarget()) + " vs " +
+ Long.toHexString(prev.getDifficultyTarget()));
return;
}
Block blockIntervalAgo = blockChain.get(blockChain.size() - INTERVAL);
- int timespan = (int) (prev.time - blockIntervalAgo.time);
+ int timespan = (int) (prev.getTime() - blockIntervalAgo.getTime());
// Limit the adjustment step.
if (timespan < TARGET_TIMESPAN / 4)
timespan = TARGET_TIMESPAN / 4;
if (timespan > TARGET_TIMESPAN * 4)
timespan = TARGET_TIMESPAN * 4;
- BigInteger newDifficulty = Utils.decodeCompactBits(blockIntervalAgo.difficultyTarget);
+ BigInteger newDifficulty = Utils.decodeCompactBits(blockIntervalAgo.getDifficultyTarget());
newDifficulty = newDifficulty.multiply(BigInteger.valueOf(timespan));
newDifficulty = newDifficulty.divide(BigInteger.valueOf(TARGET_TIMESPAN));
@@ -185,8 +186,8 @@ public class BlockChain {
newDifficulty = params.proofOfWorkLimit;
}
- int accuracyBytes = (int) (top.difficultyTarget >>> 24) - 3;
- BigInteger receivedDifficulty = Utils.decodeCompactBits(top.difficultyTarget);
+ int accuracyBytes = (int) (top.getDifficultyTarget() >>> 24) - 3;
+ BigInteger receivedDifficulty = top.getDifficultyTargetBI();
// The calculated difficulty is to a higher precision than received, so reduce here.
BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8);
diff --git a/src/com/google/bitcoin/core/NetworkParameters.java b/src/com/google/bitcoin/core/NetworkParameters.java
index cd752628..88d20f40 100644
--- a/src/com/google/bitcoin/core/NetworkParameters.java
+++ b/src/com/google/bitcoin/core/NetworkParameters.java
@@ -78,9 +78,9 @@ public class NetworkParameters implements Serializable {
n.port = 18333;
n.addressHeader = 111;
n.genesisBlock = createGenesis(n);
- n.genesisBlock.time = 1296688602L;
- n.genesisBlock.difficultyTarget = 0x1d07fff8L;
- n.genesisBlock.nonce = 384568319;
+ n.genesisBlock.setTime(1296688602L);
+ n.genesisBlock.setDifficultyTarget(0x1d07fff8L);
+ n.genesisBlock.setNonce(384568319);
String genesisHash = n.genesisBlock.getHashAsString();
assert genesisHash.equals("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
return n;
@@ -94,11 +94,19 @@ public class NetworkParameters implements Serializable {
n.packetMagic = 0xf9beb4d9L;
n.addressHeader = 0;
n.genesisBlock = createGenesis(n);
- n.genesisBlock.difficultyTarget = 0x1d00ffffL;
- n.genesisBlock.time = 1231006505;
- n.genesisBlock.nonce = 2083236893;
+ n.genesisBlock.setDifficultyTarget(0x1d00ffffL);
+ n.genesisBlock.setTime(1231006505L);
+ n.genesisBlock.setNonce(2083236893);
String genesisHash = n.genesisBlock.getHashAsString();
- assert genesisHash.equals("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
+ assert genesisHash.equals("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f") : genesisHash;
+ return n;
+ }
+
+ /** Returns a testnet params modified to allow any difficulty target. */
+ static NetworkParameters unitTests() {
+ NetworkParameters n = NetworkParameters.testNet();
+ n.proofOfWorkLimit = new BigInteger("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
+ n.genesisBlock.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
return n;
}
}
diff --git a/src/com/google/bitcoin/core/Peer.java b/src/com/google/bitcoin/core/Peer.java
index 546de5c3..bade7e2e 100644
--- a/src/com/google/bitcoin/core/Peer.java
+++ b/src/com/google/bitcoin/core/Peer.java
@@ -98,7 +98,6 @@ public class Peer {
LOG("Shutting down peer thread");
} else {
// We caught an unexpected exception.
- System.err.println(e.toString());
e.printStackTrace();
}
}
diff --git a/tests/com/google/bitcoin/core/BlockChainTest.java b/tests/com/google/bitcoin/core/BlockChainTest.java
index e68f55de..cbe3607f 100644
--- a/tests/com/google/bitcoin/core/BlockChainTest.java
+++ b/tests/com/google/bitcoin/core/BlockChainTest.java
@@ -24,6 +24,7 @@ import java.math.BigInteger;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
// Tests still to write:
// - Rest of checkDifficultyTransitions: verify we don't accept invalid transitions.
@@ -50,18 +51,13 @@ public class BlockChainTest {
Block b2 = getBlock2();
// Let's try adding an invalid block.
- long n = b2.nonce;
+ long n = b2.getNonce();
try {
- // TODO: Encapsulate these fields behind setters that recalc the hash automatically.
- b2.nonce = 12345;
- b2.hash = null;
+ b2.setNonce(12345);
chain.add(b2);
- // We should not get here.
- assertTrue(false);
+ fail();
} catch (VerificationException e) {
- // Pass.
- b2.nonce = n;
- b2.hash = null;
+ b2.setNonce(n);
}
assertTrue(chain.add(b2));
}
@@ -74,20 +70,20 @@ public class BlockChainTest {
NetworkParameters params2 = NetworkParameters.testNet();
Block bad = new Block(params2);
// Merkle root can be anything here, doesn't matter.
- bad.merkleRoot = Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+ bad.setMerkleRoot(Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
// Nonce was just some number that made the hash < difficulty limit set below, it can be anything.
- bad.nonce = 140548933;
- bad.time = 1279242649;
- bad.prevBlockHash = b2.getHash();
+ bad.setNonce(140548933);
+ bad.setTime(1279242649);
+ bad.setPrevBlockHash(b2.getHash());
// We're going to make this block so easy 50% of solutions will pass, and check it gets rejected for having a
// bad difficulty target. Unfortunately the encoding mechanism means we cannot make one that accepts all
// solutions.
- bad.difficultyTarget = 0x207fFFFFL;
+ bad.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
try {
chain.add(bad);
// The difficulty target above should be rejected on the grounds of being easier than the networks
// allowable difficulty.
- assertTrue(false);
+ fail();
} catch (VerificationException e) {
assertTrue(e.getMessage(), e.getMessage().indexOf("Difficulty target is bad") >= 0);
}
@@ -98,7 +94,7 @@ public class BlockChainTest {
try {
chain.add(bad);
// We should not get here as the difficulty target should not be changing at this point.
- assertTrue(false);
+ fail();
} catch (VerificationException e) {
assertTrue(e.getMessage(), e.getMessage().indexOf("Unexpected change in difficulty") >= 0);
}
@@ -108,11 +104,10 @@ public class BlockChainTest {
private Block getBlock2() throws Exception {
Block b2 = new Block(params);
- b2.merkleRoot = Hex.decode("addc858a17e21e68350f968ccd384d6439b64aafa6c193c8b9dd66320470838b");
- b2.nonce = 2642058077L;
- b2.time = 1296734343;
- b2.prevBlockHash =
- Hex.decode("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604");
+ b2.setMerkleRoot(Hex.decode("addc858a17e21e68350f968ccd384d6439b64aafa6c193c8b9dd66320470838b"));
+ b2.setNonce(2642058077L);
+ b2.setTime(1296734343L);
+ b2.setPrevBlockHash(Hex.decode("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604"));
assertEquals("000000037b21cac5d30fc6fda2581cf7b2612908aed2abbcc429c45b0557a15f", b2.getHashAsString());
b2.verify();
return b2;
@@ -120,10 +115,10 @@ public class BlockChainTest {
private Block getBlock1() throws Exception {
Block b1 = new Block(params);
- b1.merkleRoot = Hex.decode("0e8e58ecdacaa7b3c6304a35ae4ffff964816d2b80b62b58558866ce4e648c10");
- b1.nonce = 236038445;
- b1.time = 1296734340;
- b1.prevBlockHash = Hex.decode("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008");
+ b1.setMerkleRoot(Hex.decode("0e8e58ecdacaa7b3c6304a35ae4ffff964816d2b80b62b58558866ce4e648c10"));
+ b1.setNonce(236038445);
+ b1.setTime(1296734340);
+ b1.setPrevBlockHash(Hex.decode("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"));
assertEquals("000000033cc282bc1fa9dcae7a533263fd7fe66490f550d80076433340831604", b1.getHashAsString());
b1.verify();
return b1;
diff --git a/tests/com/google/bitcoin/core/BlockTest.java b/tests/com/google/bitcoin/core/BlockTest.java
index 1c62b296..cea00544 100644
--- a/tests/com/google/bitcoin/core/BlockTest.java
+++ b/tests/com/google/bitcoin/core/BlockTest.java
@@ -25,13 +25,10 @@ import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
public class BlockTest {
static final NetworkParameters params = NetworkParameters.testNet();
-
static final byte[] blockBytes;
static {
@@ -44,6 +41,38 @@ public class BlockTest {
public void testBlockVerification() throws Exception {
Block block = new Block(params, blockBytes);
block.verify();
+ assertEquals("00000000a6e5eb79dcec11897af55e90cd571a4335383a3ccfbc12ec81085935", block.getHashAsString());
+ }
+
+ @Test
+ public void testProofOfWork() throws Exception {
+ // This params accepts any difficulty target.
+ NetworkParameters params = NetworkParameters.unitTests();
+ Block block = new Block(params, blockBytes);
+ block.setNonce(12346);
+ try {
+ block.verify();
+ fail();
+ } catch (VerificationException e) {
+ // Expected.
+ }
+ // Blocks contain their own difficulty target. The BlockChain verification mechanism is what stops real blocks
+ // from containing artificially weak difficulties.
+ block.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
+ // Now it should pass.
+ block.verify();
+ // Break the nonce again at the lower difficulty level so we can try solving for it.
+ block.setNonce(1);
+ try {
+ block.verify();
+ fail();
+ } catch (VerificationException e) {
+ // Expected to fail as the nonce is no longer correct.
+ }
+ // Should find an acceptable nonce.
+ block.solve();
+ block.verify();
+ assertEquals(block.getNonce(), 2);
}
@Test
@@ -56,7 +85,7 @@ public class BlockTest {
block.transactions.set(1, tx1);
try {
block.verify();
- assertTrue("Verified when should not.", false);
+ fail();
} catch (VerificationException e) {
// We should get here.
}