mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-13 10:45:51 +00:00
Moved block difficulty checks into NetworkParameters.
This commit is contained in:
parent
7a3aa74c6e
commit
e030f1a1f4
@ -409,8 +409,9 @@ public abstract class AbstractBlockChain {
|
|||||||
orphanBlocks.put(block.getHash(), new OrphanBlock(block, filteredTxHashList, filteredTxn));
|
orphanBlocks.put(block.getHash(), new OrphanBlock(block, filteredTxHashList, filteredTxn));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
checkState(lock.isHeldByCurrentThread());
|
||||||
// It connects to somewhere on the chain. Not necessarily the top of the best known chain.
|
// It connects to somewhere on the chain. Not necessarily the top of the best known chain.
|
||||||
checkDifficultyTransitions(storedPrev, block);
|
params.checkDifficultyTransitions(storedPrev, block, blockStore);
|
||||||
connectBlock(block, storedPrev, shouldVerifyTransactions(), filteredTxHashList, filteredTxn);
|
connectBlock(block, storedPrev, shouldVerifyTransactions(), filteredTxHashList, filteredTxn);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,109 +826,6 @@ public abstract class AbstractBlockChain {
|
|||||||
} while (blocksConnectedThisRound > 0);
|
} while (blocksConnectedThisRound > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// February 16th 2012
|
|
||||||
private static final Date testnetDiffDate = new Date(1329264000000L);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Throws an exception if the block's difficulty is not correct.
|
|
||||||
*
|
|
||||||
* @throws VerificationException if the block's difficulty is not correct.
|
|
||||||
*/
|
|
||||||
protected void checkDifficultyTransitions(StoredBlock storedPrev, Block nextBlock) throws BlockStoreException, VerificationException {
|
|
||||||
checkState(lock.isHeldByCurrentThread());
|
|
||||||
Block prev = storedPrev.getHeader();
|
|
||||||
|
|
||||||
// Is this supposed to be a difficulty transition point?
|
|
||||||
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
|
|
||||||
// for each network type. Then each network can define its own difficulty transition rules.
|
|
||||||
if (params.getId().equals(NetworkParameters.ID_TESTNET) && nextBlock.getTime().after(testnetDiffDate)) {
|
|
||||||
checkTestnetDifficulty(storedPrev, prev, nextBlock);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No ... so check the difficulty didn't actually change.
|
|
||||||
if (nextBlock.getDifficultyTarget() != prev.getDifficultyTarget())
|
|
||||||
throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.getHeight() +
|
|
||||||
": " + Long.toHexString(nextBlock.getDifficultyTarget()) + " vs " +
|
|
||||||
Long.toHexString(prev.getDifficultyTarget()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We need to find a block far back in the chain. It's OK that this is expensive because it only occurs every
|
|
||||||
// two weeks after the initial block chain download.
|
|
||||||
long now = System.currentTimeMillis();
|
|
||||||
StoredBlock cursor = blockStore.get(prev.getHash());
|
|
||||||
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(
|
|
||||||
"Difficulty transition point but we did not find a way back to the genesis block.");
|
|
||||||
}
|
|
||||||
cursor = blockStore.get(cursor.getHeader().getPrevBlockHash());
|
|
||||||
}
|
|
||||||
long elapsed = System.currentTimeMillis() - now;
|
|
||||||
if (elapsed > 50)
|
|
||||||
log.info("Difficulty transition traversal took {}msec", elapsed);
|
|
||||||
|
|
||||||
Block blockIntervalAgo = cursor.getHeader();
|
|
||||||
int timespan = (int) (prev.getTimeSeconds() - blockIntervalAgo.getTimeSeconds());
|
|
||||||
// Limit the adjustment step.
|
|
||||||
final int targetTimespan = params.getTargetTimespan();
|
|
||||||
if (timespan < targetTimespan / 4)
|
|
||||||
timespan = targetTimespan / 4;
|
|
||||||
if (timespan > targetTimespan * 4)
|
|
||||||
timespan = targetTimespan * 4;
|
|
||||||
|
|
||||||
BigInteger newTarget = Utils.decodeCompactBits(prev.getDifficultyTarget());
|
|
||||||
newTarget = newTarget.multiply(BigInteger.valueOf(timespan));
|
|
||||||
newTarget = newTarget.divide(BigInteger.valueOf(targetTimespan));
|
|
||||||
|
|
||||||
if (newTarget.compareTo(params.getMaxTarget()) > 0) {
|
|
||||||
log.info("Difficulty hit proof of work limit: {}", newTarget.toString(16));
|
|
||||||
newTarget = params.getMaxTarget();
|
|
||||||
}
|
|
||||||
|
|
||||||
int accuracyBytes = (int) (nextBlock.getDifficultyTarget() >>> 24) - 3;
|
|
||||||
long receivedTargetCompact = nextBlock.getDifficultyTarget();
|
|
||||||
|
|
||||||
// The calculated difficulty is to a higher precision than received, so reduce here.
|
|
||||||
BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8);
|
|
||||||
newTarget = newTarget.and(mask);
|
|
||||||
long newTargetCompact = Utils.encodeCompactBits(newTarget);
|
|
||||||
|
|
||||||
if (newTargetCompact != receivedTargetCompact)
|
|
||||||
throw new VerificationException("Network provided difficulty bits do not match what was calculated: " +
|
|
||||||
newTargetCompact + " vs " + receivedTargetCompact);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkTestnetDifficulty(StoredBlock storedPrev, Block prev, Block next) throws VerificationException, BlockStoreException {
|
|
||||||
checkState(lock.isHeldByCurrentThread());
|
|
||||||
// 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.getGenesisBlock()) &&
|
|
||||||
cursor.getHeight() % params.getInterval() != 0 &&
|
|
||||||
cursor.getHeader().getDifficultyTargetAsInteger().equals(params.getMaxTarget()))
|
|
||||||
cursor = cursor.getPrev(blockStore);
|
|
||||||
BigInteger cursorTarget = cursor.getHeader().getDifficultyTargetAsInteger();
|
|
||||||
BigInteger newTarget = next.getDifficultyTargetAsInteger();
|
|
||||||
if (!cursorTarget.equals(newTarget))
|
|
||||||
throw new VerificationException("Testnet block transition that is not allowed: " +
|
|
||||||
Long.toHexString(cursor.getHeader().getDifficultyTarget()) + " vs " +
|
|
||||||
Long.toHexString(next.getDifficultyTarget()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if any connected wallet considers any transaction in the block to be relevant.
|
* Returns true if any connected wallet considers any transaction in the block to be relevant.
|
||||||
*/
|
*/
|
||||||
|
@ -297,12 +297,12 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
|||||||
}
|
}
|
||||||
// All values were already checked for being non-negative (as it is verified in Transaction.verify())
|
// All values were already checked for being non-negative (as it is verified in Transaction.verify())
|
||||||
// but we check again here just for defence in depth. Transactions with zero output value are OK.
|
// but we check again here just for defence in depth. Transactions with zero output value are OK.
|
||||||
if (valueOut.signum() < 0 || valueOut.compareTo(this.params.getMaxMoney()) > 0)
|
if (valueOut.signum() < 0 || valueOut.compareTo(params.getMaxMoney()) > 0)
|
||||||
throw new VerificationException("Transaction output value out of range");
|
throw new VerificationException("Transaction output value out of range");
|
||||||
if (isCoinBase) {
|
if (isCoinBase) {
|
||||||
coinbaseValue = valueOut;
|
coinbaseValue = valueOut;
|
||||||
} else {
|
} else {
|
||||||
if (valueIn.compareTo(valueOut) < 0 || valueIn.compareTo(this.params.getMaxMoney()) > 0)
|
if (valueIn.compareTo(valueOut) < 0 || valueIn.compareTo(params.getMaxMoney()) > 0)
|
||||||
throw new VerificationException("Transaction input value out of range");
|
throw new VerificationException("Transaction input value out of range");
|
||||||
totalFees = totalFees.add(valueIn.subtract(valueOut));
|
totalFees = totalFees.add(valueIn.subtract(valueOut));
|
||||||
}
|
}
|
||||||
@ -314,7 +314,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
|||||||
listScriptVerificationResults.add(future);
|
listScriptVerificationResults.add(future);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (totalFees.compareTo(this.params.getMaxMoney()) > 0 || block.getBlockInflation(height).add(totalFees).compareTo(coinbaseValue) < 0)
|
if (totalFees.compareTo(params.getMaxMoney()) > 0 || block.getBlockInflation(height).add(totalFees).compareTo(coinbaseValue) < 0)
|
||||||
throw new VerificationException("Transaction fees out of range");
|
throw new VerificationException("Transaction fees out of range");
|
||||||
for (Future<VerificationException> future : listScriptVerificationResults) {
|
for (Future<VerificationException> future : listScriptVerificationResults) {
|
||||||
VerificationException e;
|
VerificationException e;
|
||||||
@ -427,12 +427,12 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
|||||||
}
|
}
|
||||||
// All values were already checked for being non-negative (as it is verified in Transaction.verify())
|
// All values were already checked for being non-negative (as it is verified in Transaction.verify())
|
||||||
// but we check again here just for defence in depth. Transactions with zero output value are OK.
|
// but we check again here just for defence in depth. Transactions with zero output value are OK.
|
||||||
if (valueOut.signum() < 0 || valueOut.compareTo(this.params.getMaxMoney()) > 0)
|
if (valueOut.signum() < 0 || valueOut.compareTo(params.getMaxMoney()) > 0)
|
||||||
throw new VerificationException("Transaction output value out of range");
|
throw new VerificationException("Transaction output value out of range");
|
||||||
if (isCoinBase) {
|
if (isCoinBase) {
|
||||||
coinbaseValue = valueOut;
|
coinbaseValue = valueOut;
|
||||||
} else {
|
} else {
|
||||||
if (valueIn.compareTo(valueOut) < 0 || valueIn.compareTo(this.params.getMaxMoney()) > 0)
|
if (valueIn.compareTo(valueOut) < 0 || valueIn.compareTo(params.getMaxMoney()) > 0)
|
||||||
throw new VerificationException("Transaction input value out of range");
|
throw new VerificationException("Transaction input value out of range");
|
||||||
totalFees = totalFees.add(valueIn.subtract(valueOut));
|
totalFees = totalFees.add(valueIn.subtract(valueOut));
|
||||||
}
|
}
|
||||||
@ -444,7 +444,7 @@ public class FullPrunedBlockChain extends AbstractBlockChain {
|
|||||||
listScriptVerificationResults.add(future);
|
listScriptVerificationResults.add(future);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (totalFees.compareTo(this.params.getMaxMoney()) > 0 ||
|
if (totalFees.compareTo(params.getMaxMoney()) > 0 ||
|
||||||
newBlock.getHeader().getBlockInflation(newBlock.getHeight()).add(totalFees).compareTo(coinbaseValue) < 0)
|
newBlock.getHeader().getBlockInflation(newBlock.getHeight()).add(totalFees).compareTo(coinbaseValue) < 0)
|
||||||
throw new VerificationException("Transaction fees out of range");
|
throw new VerificationException("Transaction fees out of range");
|
||||||
txOutChanges = new TransactionOutputChanges(txOutsCreated, txOutsSpent);
|
txOutChanges = new TransactionOutputChanges(txOutsCreated, txOutsSpent);
|
||||||
|
@ -18,9 +18,14 @@
|
|||||||
package org.bitcoinj.core;
|
package org.bitcoinj.core;
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
|
import org.bitcoinj.core.Block;
|
||||||
|
import org.bitcoinj.core.StoredBlock;
|
||||||
|
import org.bitcoinj.core.VerificationException;
|
||||||
import org.bitcoinj.net.discovery.*;
|
import org.bitcoinj.net.discovery.*;
|
||||||
import org.bitcoinj.params.*;
|
import org.bitcoinj.params.*;
|
||||||
import org.bitcoinj.script.*;
|
import org.bitcoinj.script.*;
|
||||||
|
import org.bitcoinj.store.BlockStore;
|
||||||
|
import org.bitcoinj.store.BlockStoreException;
|
||||||
|
|
||||||
import org.bitcoinj.store.BlockStore;
|
import org.bitcoinj.store.BlockStore;
|
||||||
import org.bitcoinj.store.BlockStoreException;
|
import org.bitcoinj.store.BlockStoreException;
|
||||||
@ -245,6 +250,13 @@ public abstract class NetworkParameters implements Serializable {
|
|||||||
return spendableCoinbaseDepth;
|
return spendableCoinbaseDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throws an exception if the block's difficulty is not correct.
|
||||||
|
*
|
||||||
|
* @throws VerificationException if the block's difficulty is not correct.
|
||||||
|
*/
|
||||||
|
public abstract void checkDifficultyTransitions(StoredBlock storedPrev, Block next, final BlockStore blockStore) throws VerificationException, BlockStoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the block height is either not a checkpoint, or is a checkpoint and the hash matches.
|
* Returns true if the block height is either not a checkpoint, or is a checkpoint and the hash matches.
|
||||||
*/
|
*/
|
||||||
|
@ -16,12 +16,19 @@
|
|||||||
|
|
||||||
package org.bitcoinj.params;
|
package org.bitcoinj.params;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Block;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.bitcoinj.core.NetworkParameters;
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
import org.bitcoinj.core.Sha256Hash;
|
import org.bitcoinj.core.Sha256Hash;
|
||||||
|
import org.bitcoinj.core.StoredBlock;
|
||||||
import org.bitcoinj.core.Transaction;
|
import org.bitcoinj.core.Transaction;
|
||||||
import org.bitcoinj.core.Utils;
|
import org.bitcoinj.core.Utils;
|
||||||
import org.bitcoinj.utils.MonetaryFormat;
|
import org.bitcoinj.utils.MonetaryFormat;
|
||||||
|
import org.bitcoinj.core.VerificationException;
|
||||||
|
import org.bitcoinj.store.BlockStore;
|
||||||
|
import org.bitcoinj.store.BlockStoreException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@ -42,6 +49,69 @@ public abstract class AbstractBitcoinNetParams extends NetworkParameters {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkDifficultyTransitions(final StoredBlock storedPrev, final Block nextBlock,
|
||||||
|
final BlockStore blockStore) throws VerificationException, BlockStoreException {
|
||||||
|
Block prev = storedPrev.getHeader();
|
||||||
|
|
||||||
|
// Is this supposed to be a difficulty transition point?
|
||||||
|
if ((storedPrev.getHeight() + 1) % this.getInterval() != 0) {
|
||||||
|
|
||||||
|
// No ... so check the difficulty didn't actually change.
|
||||||
|
if (nextBlock.getDifficultyTarget() != prev.getDifficultyTarget())
|
||||||
|
throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.getHeight() +
|
||||||
|
": " + Long.toHexString(nextBlock.getDifficultyTarget()) + " vs " +
|
||||||
|
Long.toHexString(prev.getDifficultyTarget()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to find a block far back in the chain. It's OK that this is expensive because it only occurs every
|
||||||
|
// two weeks after the initial block chain download.
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
StoredBlock cursor = blockStore.get(prev.getHash());
|
||||||
|
for (int i = 0; i < this.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(
|
||||||
|
"Difficulty transition point but we did not find a way back to the genesis block.");
|
||||||
|
}
|
||||||
|
cursor = blockStore.get(cursor.getHeader().getPrevBlockHash());
|
||||||
|
}
|
||||||
|
long elapsed = System.currentTimeMillis() - now;
|
||||||
|
if (elapsed > 50)
|
||||||
|
log.info("Difficulty transition traversal took {}msec", elapsed);
|
||||||
|
|
||||||
|
Block blockIntervalAgo = cursor.getHeader();
|
||||||
|
int timespan = (int) (prev.getTimeSeconds() - blockIntervalAgo.getTimeSeconds());
|
||||||
|
// Limit the adjustment step.
|
||||||
|
final int targetTimespan = this.getTargetTimespan();
|
||||||
|
if (timespan < targetTimespan / 4)
|
||||||
|
timespan = targetTimespan / 4;
|
||||||
|
if (timespan > targetTimespan * 4)
|
||||||
|
timespan = targetTimespan * 4;
|
||||||
|
|
||||||
|
BigInteger newTarget = Utils.decodeCompactBits(prev.getDifficultyTarget());
|
||||||
|
newTarget = newTarget.multiply(BigInteger.valueOf(timespan));
|
||||||
|
newTarget = newTarget.divide(BigInteger.valueOf(targetTimespan));
|
||||||
|
|
||||||
|
if (newTarget.compareTo(this.getMaxTarget()) > 0) {
|
||||||
|
log.info("Difficulty hit proof of work limit: {}", newTarget.toString(16));
|
||||||
|
newTarget = this.getMaxTarget();
|
||||||
|
}
|
||||||
|
|
||||||
|
int accuracyBytes = (int) (nextBlock.getDifficultyTarget() >>> 24) - 3;
|
||||||
|
long receivedTargetCompact = nextBlock.getDifficultyTarget();
|
||||||
|
|
||||||
|
// The calculated difficulty is to a higher precision than received, so reduce here.
|
||||||
|
BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8);
|
||||||
|
newTarget = newTarget.and(mask);
|
||||||
|
long newTargetCompact = Utils.encodeCompactBits(newTarget);
|
||||||
|
|
||||||
|
if (newTargetCompact != receivedTargetCompact)
|
||||||
|
throw new VerificationException("Network provided difficulty bits do not match what was calculated: " +
|
||||||
|
newTargetCompact + " vs " + receivedTargetCompact);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Coin getMaxMoney() {
|
public Coin getMaxMoney() {
|
||||||
return MAX_MONEY;
|
return MAX_MONEY;
|
||||||
|
@ -17,7 +17,16 @@
|
|||||||
|
|
||||||
package org.bitcoinj.params;
|
package org.bitcoinj.params;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.bitcoinj.core.Block;
|
||||||
|
import org.bitcoinj.core.NetworkParameters;
|
||||||
|
import org.bitcoinj.core.StoredBlock;
|
||||||
import org.bitcoinj.core.Utils;
|
import org.bitcoinj.core.Utils;
|
||||||
|
import org.bitcoinj.core.VerificationException;
|
||||||
|
import org.bitcoinj.store.BlockStore;
|
||||||
|
import org.bitcoinj.store.BlockStoreException;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
@ -69,4 +78,39 @@ public class TestNet3Params extends AbstractBitcoinNetParams {
|
|||||||
public String getPaymentProtocolId() {
|
public String getPaymentProtocolId() {
|
||||||
return PAYMENT_PROTOCOL_ID_TESTNET;
|
return PAYMENT_PROTOCOL_ID_TESTNET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// February 16th 2012
|
||||||
|
private static final Date testnetDiffDate = new Date(1329264000000L);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void checkDifficultyTransitions(final StoredBlock storedPrev, final Block nextBlock,
|
||||||
|
final BlockStore blockStore) throws VerificationException, BlockStoreException {
|
||||||
|
if (nextBlock.getTime().after(testnetDiffDate)) {
|
||||||
|
Block prev = storedPrev.getHeader();
|
||||||
|
|
||||||
|
// 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 = nextBlock.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(getGenesisBlock()) &&
|
||||||
|
cursor.getHeight() % getInterval() != 0 &&
|
||||||
|
cursor.getHeader().getDifficultyTargetAsInteger().equals(getMaxTarget()))
|
||||||
|
cursor = cursor.getPrev(blockStore);
|
||||||
|
BigInteger cursorTarget = cursor.getHeader().getDifficultyTargetAsInteger();
|
||||||
|
BigInteger newTarget = nextBlock.getDifficultyTargetAsInteger();
|
||||||
|
if (!cursorTarget.equals(newTarget))
|
||||||
|
throw new VerificationException("Testnet block transition that is not allowed: " +
|
||||||
|
Long.toHexString(cursor.getHeader().getDifficultyTarget()) + " vs " +
|
||||||
|
Long.toHexString(nextBlock.getDifficultyTarget()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.checkDifficultyTransitions(storedPrev, nextBlock, blockStore);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user