mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-01-30 23:02:15 +00:00
Catch up with new testnet rules. Resolves issue 164.
This commit is contained in:
parent
2f904e7a37
commit
cf30280767
@ -198,7 +198,7 @@ public class BlockChain {
|
||||
// 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.
|
||||
checkState(tryConnecting, "bug in tryConnectingUnconnected");
|
||||
log.warn("Block does not connect: {}", block.getHashAsString());
|
||||
log.warn("Block does not connect: {} prev {}", block.getHashAsString(), block.getPrevBlockHash());
|
||||
unconnectedBlocks.add(block);
|
||||
return false;
|
||||
} else {
|
||||
@ -207,8 +207,7 @@ public class BlockChain {
|
||||
// Create a new StoredBlock from this block. It will throw away the transaction data so when block goes
|
||||
// out of scope we will reclaim the used memory.
|
||||
StoredBlock newStoredBlock = storedPrev.build(block);
|
||||
if (params.checkBlockDifficulty)
|
||||
checkDifficultyTransitions(storedPrev, newStoredBlock);
|
||||
checkDifficultyTransitions(storedPrev, newStoredBlock);
|
||||
blockStore.put(newStoredBlock);
|
||||
connectBlock(newStoredBlock, storedPrev, block.transactions);
|
||||
}
|
||||
@ -406,6 +405,9 @@ public class BlockChain {
|
||||
} while (blocksConnectedThisRound > 0);
|
||||
}
|
||||
|
||||
// February 16th 2012
|
||||
private static Date testnetDiffDate = new Date(1329264000000L);
|
||||
|
||||
/**
|
||||
* Throws an exception if the blocks difficulty is not correct.
|
||||
*/
|
||||
@ -413,8 +415,18 @@ public class BlockChain {
|
||||
throws BlockStoreException, VerificationException {
|
||||
Block prev = storedPrev.getHeader();
|
||||
Block next = storedNext.getHeader();
|
||||
|
||||
// Is this supposed to be a difficulty transition point?
|
||||
if ((storedPrev.getHeight() + 1) % params.interval != 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
|
||||
// for each network type. Then each network can define its own difficulty transition rules.
|
||||
if (params.getId().equals(NetworkParameters.ID_TESTNET) && next.getTime().after(testnetDiffDate)) {
|
||||
checkTestnetDifficulty(storedPrev, prev, next);
|
||||
return;
|
||||
}
|
||||
|
||||
// No ... so check the difficulty didn't actually change.
|
||||
if (next.getDifficultyTarget() != prev.getDifficultyTarget())
|
||||
throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.getHeight() +
|
||||
@ -435,7 +447,7 @@ public class BlockChain {
|
||||
}
|
||||
cursor = blockStore.get(cursor.getHeader().getPrevBlockHash());
|
||||
}
|
||||
log.debug("Difficulty transition traversal took {}msec", System.currentTimeMillis() - now);
|
||||
log.info("Difficulty transition traversal took {}msec", System.currentTimeMillis() - now);
|
||||
|
||||
Block blockIntervalAgo = cursor.getHeader();
|
||||
int timespan = (int) (prev.getTimeSeconds() - blockIntervalAgo.getTimeSeconds());
|
||||
@ -450,7 +462,7 @@ public class BlockChain {
|
||||
newDifficulty = newDifficulty.divide(BigInteger.valueOf(params.targetTimespan));
|
||||
|
||||
if (newDifficulty.compareTo(params.proofOfWorkLimit) > 0) {
|
||||
log.debug("Difficulty hit proof of work limit: {}", newDifficulty.toString(16));
|
||||
log.info("Difficulty hit proof of work limit: {}", newDifficulty.toString(16));
|
||||
newDifficulty = params.proofOfWorkLimit;
|
||||
}
|
||||
|
||||
@ -466,6 +478,30 @@ public class BlockChain {
|
||||
receivedDifficulty.toString(16) + " vs " + newDifficulty.toString(16));
|
||||
}
|
||||
|
||||
private void checkTestnetDifficulty(StoredBlock storedPrev, Block prev, Block next) throws VerificationException, BlockStoreException {
|
||||
// After 15th February 2012 the rules on the testnet change to avoid people running up the difficulty
|
||||
// and then leaving, making it too hard to mine a block. On non-difficulty transition points, easy
|
||||
// blocks are allowed if there has been a span of 20 minutes without one.
|
||||
final long timeDelta = next.getTimeSeconds() - prev.getTimeSeconds();
|
||||
// There is an integer underflow bug in bitcoin-qt that means mindiff blocks are accepted when time
|
||||
// goes backwards.
|
||||
if (timeDelta >= 0 && timeDelta <= NetworkParameters.TARGET_SPACING * 2) {
|
||||
// Walk backwards until we find a block that doesn't have the easiest proof of work, then check
|
||||
// that difficulty is equal to that one.
|
||||
StoredBlock cursor = storedPrev;
|
||||
while (!cursor.getHeader().equals(params.genesisBlock) &&
|
||||
cursor.getHeight() % params.interval != 0 &&
|
||||
cursor.getHeader().getDifficultyTargetAsInteger().equals(params.proofOfWorkLimit))
|
||||
cursor = cursor.getPrev(blockStore);
|
||||
BigInteger cursorDifficulty = cursor.getHeader().getDifficultyTargetAsInteger();
|
||||
BigInteger newDifficulty = next.getDifficultyTargetAsInteger();
|
||||
if (!cursorDifficulty.equals(newDifficulty))
|
||||
throw new VerificationException("Testnet block transition that is not allowed: " +
|
||||
Long.toHexString(cursor.getHeader().getDifficultyTarget()) + " vs " +
|
||||
Long.toHexString(next.getDifficultyTarget()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For the transactions in the given block, update the txToWalletMap such that each wallet maps to a list of
|
||||
* transactions for which it is relevant.
|
||||
|
@ -24,10 +24,12 @@ import java.math.BigInteger;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
// TODO: Refactor this after we stop supporting serialization compatibility to use subclasses and singletons.
|
||||
|
||||
/**
|
||||
* NetworkParameters contains the data needed for working with an instantiation of a BitCoin chain.
|
||||
* NetworkParameters contains the data needed for working with an instantiation of a Bitcoin chain.<p>
|
||||
*
|
||||
* Currently there are only two, the production chain and the test chain. But in future as BitCoin
|
||||
* Currently there are only two, the production chain and the test chain. But in future as Bitcoin
|
||||
* evolves there may be more. You can create your own as long as they don't conflict.
|
||||
*/
|
||||
public class NetworkParameters implements Serializable {
|
||||
@ -86,7 +88,7 @@ public class NetworkParameters implements Serializable {
|
||||
/**
|
||||
* How much time in seconds is supposed to pass between "interval" blocks. If the actual elapsed time is
|
||||
* significantly different from this value, the network difficulty formula will produce a different value. Both
|
||||
* test and production BitCoin networks use 2 weeks (1209600 seconds).
|
||||
* test and production Bitcoin networks use 2 weeks (1209600 seconds).
|
||||
*/
|
||||
public int targetTimespan;
|
||||
/**
|
||||
@ -94,11 +96,6 @@ public class NetworkParameters implements Serializable {
|
||||
* signatures using it.
|
||||
*/
|
||||
public byte[] alertSigningKey;
|
||||
/**
|
||||
* Whether to check block difficulty on this network. The rules for testnet have changed and become
|
||||
* quite complicated, so don't bother verifying them. It's only a useful security check on the main network.
|
||||
*/
|
||||
public boolean checkBlockDifficulty;
|
||||
|
||||
/**
|
||||
* See getId(). This may be null for old deserialized wallets. In that case we derive it heuristically
|
||||
@ -136,15 +133,14 @@ public class NetworkParameters implements Serializable {
|
||||
return genesisBlock;
|
||||
}
|
||||
|
||||
static private final int TARGET_TIMESPAN = 14 * 24 * 60 * 60; // 2 weeks per difficulty cycle, on average.
|
||||
static private final int TARGET_SPACING = 10 * 60; // 10 minutes per block.
|
||||
static private final int INTERVAL = TARGET_TIMESPAN / TARGET_SPACING;
|
||||
public static final int TARGET_TIMESPAN = 14 * 24 * 60 * 60; // 2 weeks per difficulty cycle, on average.
|
||||
public static final int TARGET_SPACING = 10 * 60; // 10 minutes per block.
|
||||
public static final int INTERVAL = TARGET_TIMESPAN / TARGET_SPACING;
|
||||
|
||||
/** Sets up the given NetworkParameters with testnet values. */
|
||||
private static NetworkParameters createTestNet(NetworkParameters n) {
|
||||
// Genesis hash is 0000000224b1593e3ff16a0e3b61285bbc393a39f78c8aa48c456142671f7110
|
||||
// The proof of work limit has to start with 00, as otherwise the value will be interpreted as negative.
|
||||
n.proofOfWorkLimit = new BigInteger("0000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
|
||||
n.proofOfWorkLimit = Utils.decodeCompactBits(0x1d0fffffL);
|
||||
n.packetMagic = 0xfabfb5daL;
|
||||
n.port = 18333;
|
||||
n.addressHeader = 111;
|
||||
@ -158,7 +154,6 @@ public class NetworkParameters implements Serializable {
|
||||
n.genesisBlock.setDifficultyTarget(0x1d07fff8L);
|
||||
n.genesisBlock.setNonce(384568319);
|
||||
n.id = ID_TESTNET;
|
||||
n.checkBlockDifficulty = false;
|
||||
String genesisHash = n.genesisBlock.getHashAsString();
|
||||
checkState(genesisHash.equals("00000007199508e34a9ff81e6ec0c477a4cccff2a4767a8eee39c11db367b008"),
|
||||
genesisHash);
|
||||
@ -174,7 +169,7 @@ public class NetworkParameters implements Serializable {
|
||||
/** The primary BitCoin chain created by Satoshi. */
|
||||
public static NetworkParameters prodNet() {
|
||||
NetworkParameters n = new NetworkParameters();
|
||||
n.proofOfWorkLimit = new BigInteger("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
|
||||
n.proofOfWorkLimit = Utils.decodeCompactBits(0x1d00ffffL);
|
||||
n.port = 8333;
|
||||
n.packetMagic = 0xf9beb4d9L;
|
||||
n.addressHeader = 0;
|
||||
@ -188,7 +183,6 @@ public class NetworkParameters implements Serializable {
|
||||
n.genesisBlock.setTime(1231006505L);
|
||||
n.genesisBlock.setNonce(2083236893);
|
||||
n.id = ID_PRODNET;
|
||||
n.checkBlockDifficulty = true;
|
||||
String genesisHash = n.genesisBlock.getHashAsString();
|
||||
checkState(genesisHash.equals("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"),
|
||||
genesisHash);
|
||||
@ -204,7 +198,6 @@ public class NetworkParameters implements Serializable {
|
||||
n.genesisBlock.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
|
||||
n.interval = 10;
|
||||
n.targetTimespan = 200000000; // 6 years. Just a very big number.
|
||||
n.checkBlockDifficulty = true;
|
||||
n.id = "com.google.bitcoin.unittest";
|
||||
return n;
|
||||
}
|
||||
|
@ -315,7 +315,7 @@ public class Peer {
|
||||
}
|
||||
|
||||
private void processBlock(Block m) throws IOException {
|
||||
log.info("Received broadcast block {}", m.getHashAsString());
|
||||
log.debug("Received broadcast block {}", m.getHashAsString());
|
||||
try {
|
||||
// Was this block requested by getBlock()?
|
||||
synchronized (pendingGetBlockFutures) {
|
||||
|
@ -64,7 +64,6 @@ public class BlockChainTest {
|
||||
|
||||
coinbaseTo = wallet.keychain.get(0).toAddress(unitTestParams);
|
||||
|
||||
testNet.checkBlockDifficulty = true;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
Loading…
Reference in New Issue
Block a user