diff --git a/core/src/main/java/com/google/bitcoin/core/AbstractBlockChain.java b/core/src/main/java/com/google/bitcoin/core/AbstractBlockChain.java
index 02ff3761..4dfd1077 100644
--- a/core/src/main/java/com/google/bitcoin/core/AbstractBlockChain.java
+++ b/core/src/main/java/com/google/bitcoin/core/AbstractBlockChain.java
@@ -716,7 +716,7 @@ public abstract class AbstractBlockChain {
Block prev = storedPrev.getHeader();
// Is this supposed to be a difficulty transition point?
- if ((storedPrev.getHeight() + 1) % params.interval != 0) {
+ if ((storedPrev.getHeight() + 1) % params.getInterval() != 0) {
// TODO: Refactor this hack after 0.5 is released and we stop supporting deserialization compatibility.
// This should be a method of the NetworkParameters, which should in turn be using singletons and a subclass
@@ -738,7 +738,7 @@ public abstract class AbstractBlockChain {
// two weeks after the initial block chain download.
long now = System.currentTimeMillis();
StoredBlock cursor = blockStore.get(prev.getHash());
- for (int i = 0; i < params.interval - 1; i++) {
+ for (int i = 0; i < params.getInterval() - 1; i++) {
if (cursor == null) {
// This should never happen. If it does, it means we are following an incorrect or busted chain.
throw new VerificationException(
@@ -763,9 +763,9 @@ public abstract class AbstractBlockChain {
newDifficulty = newDifficulty.multiply(BigInteger.valueOf(timespan));
newDifficulty = newDifficulty.divide(BigInteger.valueOf(targetTimespan));
- if (newDifficulty.compareTo(params.proofOfWorkLimit) > 0) {
+ if (newDifficulty.compareTo(params.getProofOfWorkLimit()) > 0) {
log.info("Difficulty hit proof of work limit: {}", newDifficulty.toString(16));
- newDifficulty = params.proofOfWorkLimit;
+ newDifficulty = params.getProofOfWorkLimit();
}
int accuracyBytes = (int) (nextBlock.getDifficultyTarget() >>> 24) - 3;
@@ -793,8 +793,8 @@ public abstract class AbstractBlockChain {
// that difficulty is equal to that one.
StoredBlock cursor = storedPrev;
while (!cursor.getHeader().equals(params.getGenesisBlock()) &&
- cursor.getHeight() % params.interval != 0 &&
- cursor.getHeader().getDifficultyTargetAsInteger().equals(params.proofOfWorkLimit))
+ cursor.getHeight() % params.getInterval() != 0 &&
+ cursor.getHeader().getDifficultyTargetAsInteger().equals(params.getProofOfWorkLimit()))
cursor = cursor.getPrev(blockStore);
BigInteger cursorDifficulty = cursor.getHeader().getDifficultyTargetAsInteger();
BigInteger newDifficulty = next.getDifficultyTargetAsInteger();
diff --git a/core/src/main/java/com/google/bitcoin/core/AlertMessage.java b/core/src/main/java/com/google/bitcoin/core/AlertMessage.java
index bfeb190e..13261ef1 100644
--- a/core/src/main/java/com/google/bitcoin/core/AlertMessage.java
+++ b/core/src/main/java/com/google/bitcoin/core/AlertMessage.java
@@ -114,7 +114,7 @@ public class AlertMessage extends Message {
* doesn't verify, because that would allow arbitrary attackers to spam your users.
*/
public boolean isSignatureValid() {
- return ECKey.verify(Utils.doubleDigest(content), signature, params.alertSigningKey);
+ return ECKey.verify(Utils.doubleDigest(content), signature, params.getAlertSigningKey());
}
@Override
diff --git a/core/src/main/java/com/google/bitcoin/core/Block.java b/core/src/main/java/com/google/bitcoin/core/Block.java
index 4aab9ea7..e2dd91a5 100644
--- a/core/src/main/java/com/google/bitcoin/core/Block.java
+++ b/core/src/main/java/com/google/bitcoin/core/Block.java
@@ -865,7 +865,7 @@ public class Block extends Message {
return new Date(getTimeSeconds()*1000);
}
- void setTime(long time) {
+ public void setTime(long time) {
unCacheHeader();
this.time = time;
this.hash = null;
diff --git a/core/src/main/java/com/google/bitcoin/core/NetworkParameters.java b/core/src/main/java/com/google/bitcoin/core/NetworkParameters.java
index 456f02e3..c3a89d9f 100644
--- a/core/src/main/java/com/google/bitcoin/core/NetworkParameters.java
+++ b/core/src/main/java/com/google/bitcoin/core/NetworkParameters.java
@@ -16,6 +16,10 @@
package com.google.bitcoin.core;
+import com.google.bitcoin.params.MainNetParams;
+import com.google.bitcoin.params.TestNet2Params;
+import com.google.bitcoin.params.TestNet3Params;
+import com.google.bitcoin.params.UnitTestParams;
import com.google.bitcoin.script.Script;
import com.google.bitcoin.script.ScriptOpCodes;
import com.google.common.base.Objects;
@@ -28,15 +32,14 @@ import java.util.HashMap;
import java.util.Map;
import static com.google.bitcoin.core.Utils.COIN;
-import static com.google.common.base.Preconditions.checkState;
/**
*
NetworkParameters contains the data needed for working with an instantiation of a Bitcoin chain.
*
- * Currently there are only two, the production chain and the test chain. There is also a "unit test chain" which
+ * Currently there are only two, the production chain and the test chain. There is also a "unit test chain" which
* is internal to bitcoinj and can't be used on a real network. In future there may be others.
*/
-public class NetworkParameters implements Serializable {
+public abstract class NetworkParameters implements Serializable {
/**
* The protocol version this library implements.
*/
@@ -58,148 +61,35 @@ public class NetworkParameters implements Serializable {
// TODO: Replace with getters and then finish making all these fields final.
- private final Block genesisBlock;
- /** What the easiest allowable proof of work should be. */
- public /*final*/ BigInteger proofOfWorkLimit;
- private final int port;
- private final long packetMagic;
- private final int addressHeader;
- private final int dumpedPrivateKeyHeader;
- /** How many blocks pass between difficulty adjustment periods. Bitcoin standardises this to be 2015. */
- public /*final*/ int interval;
- private final int targetTimespan;
- /**
- * The key used to sign {@link AlertMessage}s. You can use {@link ECKey#verify(byte[], byte[], byte[])} to verify
- * signatures using it.
- */
- public /*final*/ byte[] alertSigningKey;
+ protected Block genesisBlock;
+ protected BigInteger proofOfWorkLimit;
+ protected int port;
+ protected long packetMagic;
+ protected int addressHeader;
+ protected int dumpedPrivateKeyHeader;
+ protected int interval;
+ protected int targetTimespan;
+ protected byte[] alertSigningKey;
/**
* See getId(). This may be null for old deserialized wallets. In that case we derive it heuristically
* by looking at the port number.
*/
- private final String id;
+ protected String id;
/**
* The depth of blocks required for a coinbase transaction to be spendable.
*/
- private final int spendableCoinbaseDepth;
- private /*final*/ int subsidyDecreaseBlockCount;
+ protected int spendableCoinbaseDepth;
+ protected int subsidyDecreaseBlockCount;
- /**
- * If we are running in testnet-in-a-box mode, we allow connections to nodes with 0 non-genesis blocks
- */
- boolean allowEmptyPeerChains;
- private final int[] acceptableAddressCodes;
- private final String[] dnsSeeds;
- private Map checkpoints = new HashMap();
+ protected int[] acceptableAddressCodes;
+ protected String[] dnsSeeds;
+ protected Map checkpoints = new HashMap();
- private NetworkParameters(int type) {
+ protected NetworkParameters() {
alertSigningKey = SATOSHI_KEY;
genesisBlock = createGenesis(this);
- if (type == 0) {
- // Production.
- interval = INTERVAL;
- targetTimespan = TARGET_TIMESPAN;
- proofOfWorkLimit = Utils.decodeCompactBits(0x1d00ffffL);
- acceptableAddressCodes = new int[] { 0 };
- dumpedPrivateKeyHeader = 128;
- addressHeader = 0;
- port = 8333;
- packetMagic = 0xf9beb4d9L;
- genesisBlock.setDifficultyTarget(0x1d00ffffL);
- genesisBlock.setTime(1231006505L);
- genesisBlock.setNonce(2083236893);
- id = ID_PRODNET;
- subsidyDecreaseBlockCount = 210000;
- allowEmptyPeerChains = false;
- spendableCoinbaseDepth = 100;
- String genesisHash = genesisBlock.getHashAsString();
- checkState(genesisHash.equals("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"),
- genesisHash);
-
- // This contains (at a minimum) the blocks which are not BIP30 compliant. BIP30 changed how duplicate
- // transactions are handled. Duplicated transactions could occur in the case where a coinbase had the same
- // extraNonce and the same outputs but appeared at different heights, and greatly complicated re-org handling.
- // Having these here simplifies block connection logic considerably.
- checkpoints.put(91722, new Sha256Hash("00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e"));
- checkpoints.put(91812, new Sha256Hash("00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"));
- checkpoints.put(91842, new Sha256Hash("00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec"));
- checkpoints.put(91880, new Sha256Hash("00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"));
- checkpoints.put(200000, new Sha256Hash("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"));
-
- dnsSeeds = new String[] {
- "seed.bitcoin.sipa.be", // Pieter Wuille
- "dnsseed.bluematt.me", // Matt Corallo
- "dnsseed.bitcoin.dashjr.org", // Luke Dashjr
- "dnsseed.plan99.net", // Mike Hearn
- };
- } else if (type == 3) {
- // Testnet3
- id = ID_TESTNET;
- // Genesis hash is 000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943
- packetMagic = 0x0b110907;
- interval = INTERVAL;
- targetTimespan = TARGET_TIMESPAN;
- proofOfWorkLimit = Utils.decodeCompactBits(0x1d00ffffL);
- port = 18333;
- addressHeader = 111;
- acceptableAddressCodes = new int[] { 111 };
- dumpedPrivateKeyHeader = 239;
- genesisBlock.setTime(1296688602L);
- genesisBlock.setDifficultyTarget(0x1d00ffffL);
- genesisBlock.setNonce(414098458);
- allowEmptyPeerChains = true;
- spendableCoinbaseDepth = 100;
- subsidyDecreaseBlockCount = 210000;
- String genesisHash = genesisBlock.getHashAsString();
- checkState(genesisHash.equals("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"),
- genesisHash);
-
- dnsSeeds = new String[] {
- "testnet-seed.bitcoin.petertodd.org",
- "testnet-seed.bluematt.me"
- };
- } else if (type == 2) {
- id = ID_TESTNET;
- packetMagic = 0xfabfb5daL;
- port = 18333;
- addressHeader = 111;
- interval = INTERVAL;
- targetTimespan = TARGET_TIMESPAN;
- proofOfWorkLimit = Utils.decodeCompactBits(0x1d0fffffL);
- acceptableAddressCodes = new int[] { 111 };
- dumpedPrivateKeyHeader = 239;
- genesisBlock.setTime(1296688602L);
- genesisBlock.setDifficultyTarget(0x1d07fff8L);
- genesisBlock.setNonce(384568319);
- allowEmptyPeerChains = false;
- spendableCoinbaseDepth = 100;
- subsidyDecreaseBlockCount = 210000;
- String genesisHash = genesisBlock.getHashAsString();
- checkState(genesisHash.equals("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"),
- genesisHash);
- dnsSeeds = null;
- } else if (type == -1) {
- id = ID_UNITTESTNET;
- packetMagic = 0x0b110907;
- addressHeader = 111;
- proofOfWorkLimit = new BigInteger("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
- genesisBlock.setTime(System.currentTimeMillis() / 1000);
- genesisBlock.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
- genesisBlock.solve();
- port = 18333;
- interval = 10;
- dumpedPrivateKeyHeader = 239;
- allowEmptyPeerChains = false;
- targetTimespan = 200000000; // 6 years. Just a very big number.
- spendableCoinbaseDepth = 5;
- acceptableAddressCodes = new int[] { 111 };
- subsidyDecreaseBlockCount = 100;
- dnsSeeds = null;
- } else {
- throw new RuntimeException();
- }
}
private static Block createGenesis(NetworkParameters n) {
@@ -241,43 +131,29 @@ public class NetworkParameters implements Serializable {
*/
public static final BigInteger MAX_MONEY = new BigInteger("21000000", 10).multiply(COIN);
- /** Returns whatever the latest testNet parameters are. Use this rather than the versioned equivalents. */
+ /** Alias for TestNet3Params.get(), use that instead. */
public static NetworkParameters testNet() {
- return testNet3();
+ return TestNet3Params.get();
}
- private static NetworkParameters tn2;
- public synchronized static NetworkParameters testNet2() {
- if (tn2 == null) {
- tn2 = new NetworkParameters(2);
- }
- return tn2;
+ /** Alias for TestNet2Params.get(), use that instead. */
+ public static NetworkParameters testNet2() {
+ return TestNet2Params.get();
}
- private static NetworkParameters tn3;
- public synchronized static NetworkParameters testNet3() {
- if (tn3 == null) {
- tn3 = new NetworkParameters(3);
- }
- return tn3;
+ /** Alias for TestNet3Params.get(), use that instead. */
+ public static NetworkParameters testNet3() {
+ return TestNet3Params.get();
}
- private static NetworkParameters pn;
- /** The primary Bitcoin chain created by Satoshi. */
- public synchronized static NetworkParameters prodNet() {
- if (pn == null) {
- pn = new NetworkParameters(0);
- }
- return pn;
+ /** Alias for MainNetParams.get(), use that instead */
+ public static NetworkParameters prodNet() {
+ return MainNetParams.get();
}
- private static NetworkParameters ut;
/** Returns a testnet params modified to allow any difficulty target. */
- public synchronized static NetworkParameters unitTests() {
- if (ut == null) {
- ut = new NetworkParameters(-1);
- }
- return ut;
+ public static NetworkParameters unitTests() {
+ return UnitTestParams.get();
}
/**
@@ -336,10 +212,6 @@ public class NetworkParameters implements Serializable {
return subsidyDecreaseBlockCount;
}
- public void setSubsidyDecreaseBlockCount(int value) {
- subsidyDecreaseBlockCount = value;
- }
-
/** Returns DNS names that when resolved, give IP addresses of active peers. */
public String[] getDnsSeeds() {
return dnsSeeds;
@@ -401,4 +273,29 @@ public class NetworkParameters implements Serializable {
public int[] getAcceptableAddressCodes() {
return acceptableAddressCodes;
}
+
+ /**
+ * If we are running in testnet-in-a-box mode, we allow connections to nodes with 0 non-genesis blocks.
+ */
+ public boolean allowEmptyPeerChain() {
+ return true;
+ }
+
+ /** How many blocks pass between difficulty adjustment periods. Bitcoin standardises this to be 2015. */
+ public int getInterval() {
+ return interval;
+ }
+
+ /** What the easiest allowable proof of work should be. */
+ public BigInteger getProofOfWorkLimit() {
+ return proofOfWorkLimit;
+ }
+
+ /**
+ * The key used to sign {@link com.google.bitcoin.core.AlertMessage}s. You can use {@link com.google.bitcoin.core.ECKey#verify(byte[], byte[], byte[])} to verify
+ * signatures using it.
+ */
+ public byte[] getAlertSigningKey() {
+ return alertSigningKey;
+ }
}
diff --git a/core/src/main/java/com/google/bitcoin/core/Peer.java b/core/src/main/java/com/google/bitcoin/core/Peer.java
index 6a5b8362..a3eea59f 100644
--- a/core/src/main/java/com/google/bitcoin/core/Peer.java
+++ b/core/src/main/java/com/google/bitcoin/core/Peer.java
@@ -1253,7 +1253,7 @@ public class Peer {
// chainHeight should not be zero/negative because we shouldn't have given the user a Peer that is to another
// client-mode node, nor should it be unconnected. If that happens it means the user overrode us somewhere or
// there is a bug in the peer management code.
- checkState(params.allowEmptyPeerChains || chainHeight > 0, "Connected to peer with zero/negative chain height", chainHeight);
+ checkState(params.allowEmptyPeerChain() || chainHeight > 0, "Connected to peer with zero/negative chain height", chainHeight);
return chainHeight - blockChain.getBestChainHeight();
}
diff --git a/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java b/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java
index 812d720b..d86e75d7 100644
--- a/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java
+++ b/core/src/main/java/com/google/bitcoin/core/TCPNetworkConnection.java
@@ -158,7 +158,7 @@ public class TCPNetworkConnection implements NetworkConnection {
// implementations claim to have a block chain in their services field but then report a height of zero, filter
// them out here.
if (!versionMessage.hasBlockChain() ||
- (!params.allowEmptyPeerChains && versionMessage.bestHeight <= 0)) {
+ (!params.allowEmptyPeerChain() && versionMessage.bestHeight <= 0)) {
// Shut down the channel
throw new ProtocolException("Peer does not have a copy of the block chain.");
}
diff --git a/core/src/main/java/com/google/bitcoin/params/MainNetParams.java b/core/src/main/java/com/google/bitcoin/params/MainNetParams.java
new file mode 100644
index 00000000..96acad7b
--- /dev/null
+++ b/core/src/main/java/com/google/bitcoin/params/MainNetParams.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.bitcoin.params;
+
+import com.google.bitcoin.core.NetworkParameters;
+import com.google.bitcoin.core.Sha256Hash;
+import com.google.bitcoin.core.Utils;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Parameters for the main production network on which people trade goods and services.
+ */
+public class MainNetParams extends NetworkParameters {
+ public MainNetParams() {
+ super();
+ interval = INTERVAL;
+ targetTimespan = TARGET_TIMESPAN;
+ proofOfWorkLimit = Utils.decodeCompactBits(0x1d00ffffL);
+ acceptableAddressCodes = new int[] { 0 };
+ dumpedPrivateKeyHeader = 128;
+ addressHeader = 0;
+ port = 8333;
+ packetMagic = 0xf9beb4d9L;
+ genesisBlock.setDifficultyTarget(0x1d00ffffL);
+ genesisBlock.setTime(1231006505L);
+ genesisBlock.setNonce(2083236893);
+ id = ID_PRODNET;
+ subsidyDecreaseBlockCount = 210000;
+ spendableCoinbaseDepth = 100;
+ String genesisHash = genesisBlock.getHashAsString();
+ checkState(genesisHash.equals("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"),
+ genesisHash);
+
+ // This contains (at a minimum) the blocks which are not BIP30 compliant. BIP30 changed how duplicate
+ // transactions are handled. Duplicated transactions could occur in the case where a coinbase had the same
+ // extraNonce and the same outputs but appeared at different heights, and greatly complicated re-org handling.
+ // Having these here simplifies block connection logic considerably.
+ checkpoints.put(91722, new Sha256Hash("00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e"));
+ checkpoints.put(91812, new Sha256Hash("00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"));
+ checkpoints.put(91842, new Sha256Hash("00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec"));
+ checkpoints.put(91880, new Sha256Hash("00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"));
+ checkpoints.put(200000, new Sha256Hash("000000000000034a7dedef4a161fa058a2d67a173a90155f3a2fe6fc132e0ebf"));
+
+ dnsSeeds = new String[] {
+ "seed.bitcoin.sipa.be", // Pieter Wuille
+ "dnsseed.bluematt.me", // Matt Corallo
+ "dnsseed.bitcoin.dashjr.org", // Luke Dashjr
+ "dnsseed.plan99.net", // Mike Hearn
+ };
+ }
+
+ private static MainNetParams instance;
+ public static synchronized MainNetParams get() {
+ if (instance == null) {
+ instance = new MainNetParams();
+ }
+ return instance;
+ }
+}
diff --git a/core/src/main/java/com/google/bitcoin/params/RegTestParams.java b/core/src/main/java/com/google/bitcoin/params/RegTestParams.java
new file mode 100644
index 00000000..ffc2e233
--- /dev/null
+++ b/core/src/main/java/com/google/bitcoin/params/RegTestParams.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.bitcoin.params;
+
+import com.google.bitcoin.core.Block;
+
+import java.math.BigInteger;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Network parameters for the regression test mode of bitcoind in which all blocks are trivially solvable.
+ */
+public class RegTestParams extends TestNet2Params {
+ private static final BigInteger PROOF_OF_WORK_LIMIT = new BigInteger("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
+
+ public RegTestParams() {
+ interval = 10000;
+ proofOfWorkLimit = PROOF_OF_WORK_LIMIT;
+ subsidyDecreaseBlockCount = 10000;
+ port = 18444;
+ }
+
+ @Override
+ public boolean allowEmptyPeerChain() {
+ return true;
+ }
+
+ private static Block genesis;
+
+ @Override
+ public Block getGenesisBlock() {
+ synchronized (RegTestParams.class) {
+ if (genesis == null) {
+ genesis = super.getGenesisBlock();
+ genesis.setNonce(2);
+ genesis.setDifficultyTarget(0x207fFFFFL);
+ genesis.setTime(1296688602L);
+ checkState(genesis.getHashAsString().toLowerCase().equals("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
+ }
+ return genesis;
+ }
+ }
+}
diff --git a/core/src/main/java/com/google/bitcoin/params/TestNet2Params.java b/core/src/main/java/com/google/bitcoin/params/TestNet2Params.java
new file mode 100644
index 00000000..6b3b2a3c
--- /dev/null
+++ b/core/src/main/java/com/google/bitcoin/params/TestNet2Params.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.bitcoin.params;
+
+import com.google.bitcoin.core.NetworkParameters;
+import com.google.bitcoin.core.Utils;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Parameters for the old version 2 testnet. This is not useful to you - it exists only because some unit tests are
+ * based on it.
+ */
+public class TestNet2Params extends NetworkParameters {
+ public TestNet2Params() {
+ super();
+ id = ID_TESTNET;
+ packetMagic = 0xfabfb5daL;
+ port = 18333;
+ addressHeader = 111;
+ interval = INTERVAL;
+ targetTimespan = TARGET_TIMESPAN;
+ proofOfWorkLimit = Utils.decodeCompactBits(0x1d0fffffL);
+ acceptableAddressCodes = new int[] { 111 };
+ dumpedPrivateKeyHeader = 239;
+ genesisBlock.setTime(1296688602L);
+ genesisBlock.setDifficultyTarget(0x1d07fff8L);
+ genesisBlock.setNonce(384568319);
+ spendableCoinbaseDepth = 100;
+ subsidyDecreaseBlockCount = 210000;
+ String genesisHash = genesisBlock.getHashAsString();
+ checkState(genesisHash.equals("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"));
+ dnsSeeds = null;
+ }
+
+ private static TestNet2Params instance;
+ public static synchronized TestNet2Params get() {
+ if (instance == null) {
+ instance = new TestNet2Params();
+ }
+ return instance;
+ }
+}
diff --git a/core/src/main/java/com/google/bitcoin/params/TestNet3Params.java b/core/src/main/java/com/google/bitcoin/params/TestNet3Params.java
new file mode 100644
index 00000000..0b1bdf10
--- /dev/null
+++ b/core/src/main/java/com/google/bitcoin/params/TestNet3Params.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.bitcoin.params;
+
+import com.google.bitcoin.core.NetworkParameters;
+import com.google.bitcoin.core.Utils;
+
+import static com.google.common.base.Preconditions.checkState;
+
+/**
+ * Parameters for the testnet, a separate public instance of Bitcoin that has relaxed rules suitable for development
+ * and testing of applications and new Bitcoin versions.
+ */
+public class TestNet3Params extends NetworkParameters {
+ public TestNet3Params() {
+ super();
+ id = ID_TESTNET;
+ // Genesis hash is 000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943
+ packetMagic = 0x0b110907;
+ interval = INTERVAL;
+ targetTimespan = TARGET_TIMESPAN;
+ proofOfWorkLimit = Utils.decodeCompactBits(0x1d00ffffL);
+ port = 18333;
+ addressHeader = 111;
+ acceptableAddressCodes = new int[] { 111 };
+ dumpedPrivateKeyHeader = 239;
+ genesisBlock.setTime(1296688602L);
+ genesisBlock.setDifficultyTarget(0x1d00ffffL);
+ genesisBlock.setNonce(414098458);
+ spendableCoinbaseDepth = 100;
+ subsidyDecreaseBlockCount = 210000;
+ String genesisHash = genesisBlock.getHashAsString();
+ checkState(genesisHash.equals("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
+
+ dnsSeeds = new String[] {
+ "testnet-seed.bitcoin.petertodd.org",
+ "testnet-seed.bluematt.me"
+ };
+ }
+
+ private static TestNet3Params instance;
+ public static synchronized TestNet3Params get() {
+ if (instance == null) {
+ instance = new TestNet3Params();
+ }
+ return instance;
+ }
+}
diff --git a/core/src/main/java/com/google/bitcoin/params/UnitTestParams.java b/core/src/main/java/com/google/bitcoin/params/UnitTestParams.java
new file mode 100644
index 00000000..e9b68d91
--- /dev/null
+++ b/core/src/main/java/com/google/bitcoin/params/UnitTestParams.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.bitcoin.params;
+
+import com.google.bitcoin.core.Block;
+import com.google.bitcoin.core.NetworkParameters;
+
+import java.math.BigInteger;
+
+/**
+ * Network parameters used by the bitcoinj unit tests (and potentially your own). This lets you solve a block using
+ * {@link com.google.bitcoin.core.Block#solve()} by setting difficulty to the easiest possible.
+ */
+public class UnitTestParams extends NetworkParameters {
+ public UnitTestParams() {
+ super();
+ id = ID_UNITTESTNET;
+ packetMagic = 0x0b110907;
+ addressHeader = 111;
+ proofOfWorkLimit = new BigInteger("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
+ genesisBlock.setTime(System.currentTimeMillis() / 1000);
+ genesisBlock.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
+ genesisBlock.solve();
+ port = 18333;
+ interval = 10;
+ dumpedPrivateKeyHeader = 239;
+ targetTimespan = 200000000; // 6 years. Just a very big number.
+ spendableCoinbaseDepth = 5;
+ acceptableAddressCodes = new int[] { 111 };
+ subsidyDecreaseBlockCount = 100;
+ dnsSeeds = null;
+ }
+
+ private static UnitTestParams instance;
+ public static synchronized UnitTestParams get() {
+ if (instance == null) {
+ instance = new UnitTestParams();
+ }
+ return instance;
+ }
+}
diff --git a/core/src/test/java/com/google/bitcoin/core/AlertMessageTest.java b/core/src/test/java/com/google/bitcoin/core/AlertMessageTest.java
index 9a6ab352..2985dd71 100644
--- a/core/src/test/java/com/google/bitcoin/core/AlertMessageTest.java
+++ b/core/src/test/java/com/google/bitcoin/core/AlertMessageTest.java
@@ -16,6 +16,7 @@
package com.google.bitcoin.core;
+import com.google.bitcoin.params.UnitTestParams;
import org.junit.Before;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
@@ -29,9 +30,13 @@ public class AlertMessageTest {
@Before
public void setUp() throws Exception {
- ECKey key = new ECKey(TEST_KEY_PRIV, null);
- params = NetworkParameters.unitTests();
- params.alertSigningKey = key.getPubKey();
+ final ECKey key = new ECKey(TEST_KEY_PRIV, null);
+ params = new UnitTestParams() {
+ @Override
+ public byte[] getAlertSigningKey() {
+ return key.getPubKey();
+ }
+ };
}
@Test
diff --git a/core/src/test/java/com/google/bitcoin/core/BitcoindComparisonTool.java b/core/src/test/java/com/google/bitcoin/core/BitcoindComparisonTool.java
index 52c46773..8ff1d11d 100644
--- a/core/src/test/java/com/google/bitcoin/core/BitcoindComparisonTool.java
+++ b/core/src/test/java/com/google/bitcoin/core/BitcoindComparisonTool.java
@@ -16,6 +16,7 @@
package com.google.bitcoin.core;
+import com.google.bitcoin.params.RegTestParams;
import com.google.bitcoin.store.BlockStoreException;
import com.google.bitcoin.store.FullPrunedBlockStore;
import com.google.bitcoin.store.H2FullPrunedBlockStore;
@@ -58,38 +59,15 @@ public class BitcoindComparisonTool {
System.out.println("USAGE: bitcoinjBlockStoreLocation runLargeReorgs(1/0) [port=18444]");
boolean runLargeReorgs = Integer.parseInt(args[1]) == 1;
- params = NetworkParameters.testNet2();
- /**
- * The following have been changed from the default and do not match bitcoind's default.
- * In order for this test to work, bitcoind should be recompiled with the same values you see here.
- * You can also opt to comment out these lines to use the default, however that will cause this tool to be
- * very significantly less efficient and useful (it will likely run forever trying to mine new blocks).
- *
- * You could also simply use git apply to apply the test-patches included with bitcoind
- */
-
- // bnProofOfWorkLimit set in main.cpp
- params.proofOfWorkLimit = new BigInteger("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
- // Also set hashGenesisBlock to 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206 one line up
-
- // constant (210000) in GetBlockValue (main.cpp)
- params.setSubsidyDecreaseBlockCount(150);
-
- // block.nNonce/block.nBits in LoadBlockIndex not the ones under "if (fTestNet)"
- params.getGenesisBlock().setNonce(2);
- params.getGenesisBlock().setDifficultyTarget(0x207fFFFFL);
- // Also set block.nTime = 1296688602; in the same block
-
+ params = new RegTestParams();
+
File blockFile = File.createTempFile("testBlocks", ".dat");
blockFile.deleteOnExit();
-
+
FullBlockTestGenerator generator = new FullBlockTestGenerator(params);
BlockAndValidityList blockList = generator.getBlocksToTest(true, runLargeReorgs, blockFile);
Iterator blocks = new BlockFileLoader(params, Arrays.asList(blockFile));
-
- // Only needs to be set in bitcoinj
- params.allowEmptyPeerChains = true;
-
+
try {
store = new H2FullPrunedBlockStore(params, args[0], blockList.maximumReorgBlockCount);
((H2FullPrunedBlockStore)store).resetStore();
@@ -104,7 +82,7 @@ public class BitcoindComparisonTool {
peers.setUserAgent("BlockAcceptanceComparisonTool", "1.0");
// bitcoind MUST be on localhost or we will get banned as a DoSer
- peers.addAddress(new PeerAddress(InetAddress.getByName("localhost"), args.length > 2 ? Integer.parseInt(args[2]) : 18444));
+ peers.addAddress(new PeerAddress(InetAddress.getByName("localhost"), args.length > 2 ? Integer.parseInt(args[2]) : params.getPort()));
final Set blocksRequested = Collections.synchronizedSet(new HashSet());
peers.addEventListener(new AbstractPeerEventListener() {
diff --git a/core/src/test/java/com/google/bitcoin/core/BlockChainTest.java b/core/src/test/java/com/google/bitcoin/core/BlockChainTest.java
index 73c48bcb..a6a18d92 100644
--- a/core/src/test/java/com/google/bitcoin/core/BlockChainTest.java
+++ b/core/src/test/java/com/google/bitcoin/core/BlockChainTest.java
@@ -17,6 +17,7 @@
package com.google.bitcoin.core;
import com.google.bitcoin.core.Wallet.BalanceType;
+import com.google.bitcoin.params.TestNet2Params;
import com.google.bitcoin.store.BlockStore;
import com.google.bitcoin.store.MemoryBlockStore;
import com.google.bitcoin.utils.BriefLogFormatter;
@@ -35,7 +36,6 @@ import static org.junit.Assert.*;
// Handling of chain splits/reorgs are in ChainSplitTests.
public class BlockChainTest {
- private static final NetworkParameters testNet = NetworkParameters.testNet2();
private BlockChain testNetChain;
private Wallet wallet;
@@ -46,6 +46,13 @@ public class BlockChainTest {
private final StoredBlock[] block = new StoredBlock[1];
private Transaction coinbaseTransaction;
+ private static class TweakableTestNet2Params extends TestNet2Params {
+ public void setProofOfWorkLimit(BigInteger limit) {
+ proofOfWorkLimit = limit;
+ }
+ }
+ private static final TweakableTestNet2Params testNet = new TweakableTestNet2Params();
+
private void resetBlockStore() {
blockStore = new MemoryBlockStore(unitTestParams);
}
@@ -54,6 +61,7 @@ public class BlockChainTest {
public void setUp() throws Exception {
BriefLogFormatter.initVerbose();
testNetChain = new BlockChain(testNet, new Wallet(testNet), new MemoryBlockStore(testNet));
+
unitTestParams = NetworkParameters.unitTests();
wallet = new Wallet(unitTestParams) {
@Override
@@ -161,7 +169,7 @@ public class BlockChainTest {
// artificially shortened period.
Block prev = unitTestParams.getGenesisBlock();
Block.fakeClock = System.currentTimeMillis() / 1000;
- for (int i = 0; i < unitTestParams.interval - 1; i++) {
+ for (int i = 0; i < unitTestParams.getInterval() - 1; i++) {
Block newBlock = prev.createNextBlock(coinbaseTo, Block.fakeClock);
assertTrue(chain.add(newBlock));
prev = newBlock;
@@ -209,9 +217,9 @@ public class BlockChainTest {
}
// Accept any level of difficulty now.
- BigInteger oldVal = testNet.proofOfWorkLimit;
- testNet.proofOfWorkLimit = new BigInteger
- ("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
+ BigInteger oldVal = testNet.getProofOfWorkLimit();
+ testNet.setProofOfWorkLimit(new BigInteger
+ ("00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16));
try {
testNetChain.add(bad);
// We should not get here as the difficulty target should not be changing at this point.
@@ -219,7 +227,7 @@ public class BlockChainTest {
} catch (VerificationException e) {
assertTrue(e.getMessage(), e.getCause().getMessage().contains("Unexpected change in difficulty"));
}
- testNet.proofOfWorkLimit = oldVal;
+ testNet.setProofOfWorkLimit(oldVal);
// TODO: Test difficulty change is not out of range when a transition period becomes valid.
}
diff --git a/core/src/test/java/com/google/bitcoin/core/FullPrunedBlockChainTest.java b/core/src/test/java/com/google/bitcoin/core/FullPrunedBlockChainTest.java
index eb440082..d32c23ff 100644
--- a/core/src/test/java/com/google/bitcoin/core/FullPrunedBlockChainTest.java
+++ b/core/src/test/java/com/google/bitcoin/core/FullPrunedBlockChainTest.java
@@ -18,13 +18,13 @@
package com.google.bitcoin.core;
import com.google.bitcoin.core.Transaction.SigHash;
+import com.google.bitcoin.params.UnitTestParams;
import com.google.bitcoin.script.Script;
import com.google.bitcoin.store.BlockStoreException;
import com.google.bitcoin.store.FullPrunedBlockStore;
import com.google.bitcoin.store.MemoryFullPrunedBlockStore;
import com.google.bitcoin.utils.BlockFileLoader;
import com.google.bitcoin.utils.BriefLogFormatter;
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
@@ -45,33 +45,28 @@ import static org.junit.Assert.*;
public class FullPrunedBlockChainTest {
private static final Logger log = LoggerFactory.getLogger(FullPrunedBlockChainTest.class);
- private NetworkParameters unitTestParams;
+ private NetworkParameters params;
private FullPrunedBlockChain chain;
private FullPrunedBlockStore store;
- private int oldInterval;
-
@Before
public void setUp() throws Exception {
BriefLogFormatter.init();
- unitTestParams = NetworkParameters.unitTests();
- oldInterval = unitTestParams.interval;
- unitTestParams.interval = 10000;
+ params = new UnitTestParams() {
+ @Override public int getInterval() {
+ return 10000;
+ }
+ };
}
- @After
- public void tearDown() {
- unitTestParams.interval = oldInterval;
- }
-
@Test
public void testGeneratedChain() throws Exception {
- // Tests various test cases from FullBlockTestGenerator
- FullBlockTestGenerator generator = new FullBlockTestGenerator(unitTestParams);
+ // Tests various test cases from FullBlockTestGenerator
+ FullBlockTestGenerator generator = new FullBlockTestGenerator(params);
BlockAndValidityList blockList = generator.getBlocksToTest(false, false, null);
- store = new MemoryFullPrunedBlockStore(unitTestParams, blockList.maximumReorgBlockCount);
- chain = new FullPrunedBlockChain(unitTestParams, store);
+ store = new MemoryFullPrunedBlockStore(params, blockList.maximumReorgBlockCount);
+ chain = new FullPrunedBlockChain(params, store);
for (BlockAndValidity block : blockList.list) {
boolean threw = false;
@@ -109,8 +104,8 @@ public class FullPrunedBlockChainTest {
@Test
public void testFinalizedBlocks() throws Exception {
final int UNDOABLE_BLOCKS_STORED = 10;
- store = new MemoryFullPrunedBlockStore(unitTestParams, UNDOABLE_BLOCKS_STORED);
- chain = new FullPrunedBlockChain(unitTestParams, store);
+ store = new MemoryFullPrunedBlockStore(params, UNDOABLE_BLOCKS_STORED);
+ chain = new FullPrunedBlockChain(params, store);
// Check that we aren't accidentally leaving any references
// to the full StoredUndoableBlock's lying around (ie memory leaks)
@@ -118,11 +113,11 @@ public class FullPrunedBlockChainTest {
ECKey outKey = new ECKey();
// Build some blocks on genesis block to create a spendable output
- Block rollingBlock = unitTestParams.getGenesisBlock().createNextBlockWithCoinbase(outKey.getPubKey());
+ Block rollingBlock = params.getGenesisBlock().createNextBlockWithCoinbase(outKey.getPubKey());
chain.add(rollingBlock);
- TransactionOutPoint spendableOutput = new TransactionOutPoint(unitTestParams, 0, rollingBlock.getTransactions().get(0).getHash());
+ TransactionOutPoint spendableOutput = new TransactionOutPoint(params, 0, rollingBlock.getTransactions().get(0).getHash());
byte[] spendableOutputScriptPubKey = rollingBlock.getTransactions().get(0).getOutputs().get(0).getScriptBytes();
- for (int i = 1; i < unitTestParams.getSpendableCoinbaseDepth(); i++) {
+ for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) {
rollingBlock = rollingBlock.createNextBlockWithCoinbase(outKey.getPubKey());
chain.add(rollingBlock);
}
@@ -131,9 +126,9 @@ public class FullPrunedBlockChainTest {
(store.getTransactionOutput(spendableOutput.getHash(), spendableOutput.getIndex()));
rollingBlock = rollingBlock.createNextBlock(null);
- Transaction t = new Transaction(unitTestParams);
+ Transaction t = new Transaction(params);
// Entirely invalid scriptPubKey
- t.addOutput(new TransactionOutput(unitTestParams, t, Utils.toNanoCoins(50, 0), new byte[] {}));
+ t.addOutput(new TransactionOutput(params, t, Utils.toNanoCoins(50, 0), new byte[] {}));
addInputToTransaction(t, spendableOutput, spendableOutputScriptPubKey, outKey);
rollingBlock.addTransaction(t);
rollingBlock.solve();
@@ -161,7 +156,7 @@ public class FullPrunedBlockChainTest {
}
private void addInputToTransaction(Transaction t, TransactionOutPoint prevOut, byte[] prevOutScriptPubKey, ECKey sigKey) throws ScriptException {
- TransactionInput input = new TransactionInput(unitTestParams, t, new byte[]{}, prevOut);
+ TransactionInput input = new TransactionInput(params, t, new byte[]{}, prevOut);
t.addInput(input);
Sha256Hash hash = t.hashTransactionForSignature(0, prevOutScriptPubKey, SigHash.ALL, false);
diff --git a/tools/src/main/java/com/google/bitcoin/tools/BuildCheckpoints.java b/tools/src/main/java/com/google/bitcoin/tools/BuildCheckpoints.java
index 7524af68..1e65d52e 100644
--- a/tools/src/main/java/com/google/bitcoin/tools/BuildCheckpoints.java
+++ b/tools/src/main/java/com/google/bitcoin/tools/BuildCheckpoints.java
@@ -3,7 +3,6 @@ package com.google.bitcoin.tools;
import com.google.bitcoin.core.*;
import com.google.bitcoin.store.BlockStore;
import com.google.bitcoin.store.MemoryBlockStore;
-import com.google.bitcoin.store.SPVBlockStore;
import com.google.bitcoin.utils.BriefLogFormatter;
import java.io.*;
@@ -43,7 +42,7 @@ public class BuildCheckpoints {
@Override
public void notifyNewBestBlock(StoredBlock block) throws VerificationException {
int height = block.getHeight();
- if (height % params.interval == 0 && block.getHeader().getTimeSeconds() <= oneMonthAgo) {
+ if (height % params.getInterval() == 0 && block.getHeader().getTimeSeconds() <= oneMonthAgo) {
System.out.println(String.format("Checkpointing block %s at height %d",
block.getHeader().getHash(), block.getHeight()));
checkpoints.put(height, block);