mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-07 06:44:16 +00:00
Add checkpoint support and use it in AbstractBlockChain.
This greatly simplifies block connection logic as it does not need to consider reorgs through non-BIP30-compliant blocks.
This commit is contained in:
parent
8edd6c5399
commit
c3ff3d112e
@ -283,7 +283,11 @@ public abstract class AbstractBlockChain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void connectBlock(Block block, StoredBlock storedPrev)
|
private void connectBlock(Block block, StoredBlock storedPrev)
|
||||||
throws BlockStoreException, VerificationException, PrunedException {
|
throws BlockStoreException, VerificationException, PrunedException {
|
||||||
|
// Check that we aren't connecting a block that fails a checkpoint check
|
||||||
|
if (!params.passesCheckpoint(storedPrev.getHeight() + 1, block.getHash()))
|
||||||
|
throw new VerificationException("Block failed checkpoint lockin at " + (storedPrev.getHeight() + 1));
|
||||||
|
|
||||||
StoredBlock head = getChainHead();
|
StoredBlock head = getChainHead();
|
||||||
if (storedPrev.equals(head)) {
|
if (storedPrev.equals(head)) {
|
||||||
// This block connects to the best known block, it is a normal continuation of the system.
|
// This block connects to the best known block, it is a normal continuation of the system.
|
||||||
|
@ -21,6 +21,8 @@ import org.spongycastle.util.encoders.Hex;
|
|||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkState;
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
|
|
||||||
@ -54,7 +56,7 @@ public class NetworkParameters implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public static final String ID_TESTNET = "org.bitcoin.test";
|
public static final String ID_TESTNET = "org.bitcoin.test";
|
||||||
|
|
||||||
// TODO: Seed nodes and checkpoint values should be here as well.
|
// TODO: Seed nodes should be here as well.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Genesis block for this chain.<p>
|
* Genesis block for this chain.<p>
|
||||||
@ -114,6 +116,15 @@ public class NetworkParameters implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public int[] acceptableAddressCodes;
|
public int[] acceptableAddressCodes;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block checkpoints are a safety mechanism that hard-codes the hashes of blocks at particular heights. Re-orgs
|
||||||
|
* beyond this point will never be accepted. This field should be accessed using
|
||||||
|
* {@link NetworkParameters#passesCheckpoint(int, Sha256Hash)} and {@link NetworkParameters#isCheckpoint(int)}.
|
||||||
|
*/
|
||||||
|
public Map<Integer, Sha256Hash> checkpoints = new HashMap<Integer, Sha256Hash>();
|
||||||
|
|
||||||
|
|
||||||
private static Block createGenesis(NetworkParameters n) {
|
private static Block createGenesis(NetworkParameters n) {
|
||||||
Block genesisBlock = new Block(n);
|
Block genesisBlock = new Block(n);
|
||||||
Transaction t = new Transaction(n);
|
Transaction t = new Transaction(n);
|
||||||
@ -222,6 +233,16 @@ public class NetworkParameters implements Serializable {
|
|||||||
String genesisHash = n.genesisBlock.getHashAsString();
|
String genesisHash = n.genesisBlock.getHashAsString();
|
||||||
checkState(genesisHash.equals("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"),
|
checkState(genesisHash.equals("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"),
|
||||||
genesisHash);
|
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.
|
||||||
|
n.checkpoints.put(new Integer(91722), new Sha256Hash("00000000000271a2dc26e7667f8419f2e15416dc6955e5a6c6cdf3f2574dd08e"));
|
||||||
|
n.checkpoints.put(new Integer(91812), new Sha256Hash("00000000000af0aed4792b1acee3d966af36cf5def14935db8de83d6f9306f2f"));
|
||||||
|
n.checkpoints.put(new Integer(91842), new Sha256Hash("00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec"));
|
||||||
|
n.checkpoints.put(new Integer(91880), new Sha256Hash("00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721"));
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,4 +300,26 @@ public class NetworkParameters implements Serializable {
|
|||||||
public void setSpendableCoinbaseDepth(int coinbaseDepth) {
|
public void setSpendableCoinbaseDepth(int coinbaseDepth) {
|
||||||
this.spendableCoinbaseDepth = coinbaseDepth;
|
this.spendableCoinbaseDepth = coinbaseDepth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the block height is either not a checkpoint, or is a checkpoint and the hash matches.
|
||||||
|
*/
|
||||||
|
public boolean passesCheckpoint(int height, Sha256Hash hash) {
|
||||||
|
Sha256Hash checkpointHash = checkpoints.get(new Integer(height));
|
||||||
|
if (checkpointHash != null)
|
||||||
|
return checkpointHash.equals(hash);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given height has a recorded checkpoint.
|
||||||
|
* @param height
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isCheckpoint(int height) {
|
||||||
|
Sha256Hash checkpointHash = checkpoints.get(new Integer(height));
|
||||||
|
if (checkpointHash != null)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user