mirror of
https://github.com/Qortal/altcoinj.git
synced 2025-02-11 17:55:53 +00:00
Implement block work calculations, add a test. Small internal refactoring of BlockChain in preparation for bigger changes.
This commit is contained in:
parent
57caa5503d
commit
30327cd888
@ -27,10 +27,10 @@ import static com.google.bitcoin.core.Utils.*;
|
|||||||
/**
|
/**
|
||||||
* A block is the foundation of the BitCoin system. It records a set of {@link Transaction}s together with
|
* A block is the foundation of the BitCoin system. It records a set of {@link Transaction}s together with
|
||||||
* some data that links it into a place in the global block chain, and proves that a difficult calculation was done
|
* some data that links it into a place in the global block chain, and proves that a difficult calculation was done
|
||||||
* over its contents. See the BitCoin technical paper for more detail on blocks.
|
* over its contents. See the BitCoin technical paper for more detail on blocks.<p>
|
||||||
*
|
*
|
||||||
* To get a block, you can either build one from the raw bytes you can get from another implementation, or more likely
|
* To get a block, you can either build one from the raw bytes you can get from another implementation,
|
||||||
* you grab it from a downloaded {@link BlockChain}.
|
* or request one specifically using {@link Peer#getBlock(byte[])}, or grab one from a downloaded {@link BlockChain}.
|
||||||
*/
|
*/
|
||||||
public class Block extends Message {
|
public class Block extends Message {
|
||||||
private static final long serialVersionUID = 2738848929966035281L;
|
private static final long serialVersionUID = 2738848929966035281L;
|
||||||
@ -142,6 +142,21 @@ public class Block extends Message {
|
|||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The number that is one greater than the largest representable SHA-256 hash. */
|
||||||
|
static private BigInteger LARGEST_HASH = BigInteger.ONE.shiftLeft(256);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the work represented by this block.<p>
|
||||||
|
*
|
||||||
|
* Work is defined as the number of tries needed to solve a block in the average case. Consider a difficulty
|
||||||
|
* target that covers 5% of all possible hash values. Then the work of the block will be 20. As the target gets
|
||||||
|
* lower, the amount of work goes up.
|
||||||
|
*/
|
||||||
|
public BigInteger getWork() throws VerificationException {
|
||||||
|
BigInteger target = getDifficultyTargetAsInteger();
|
||||||
|
return LARGEST_HASH.divide(target.add(BigInteger.ONE));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a multi-line string containing a description of the contents of the block. Use for debugging purposes
|
* Returns a multi-line string containing a description of the contents of the block. Use for debugging purposes
|
||||||
* only.
|
* only.
|
||||||
@ -183,6 +198,18 @@ public class Block extends Message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the difficulty target as a 256 bit value that can be compared to a SHA-256 hash. Inside a block the
|
||||||
|
* target is represented using a compact form. If this form decodes to a value that is out of bounds,
|
||||||
|
* an exception is thrown.
|
||||||
|
*/
|
||||||
|
public BigInteger getDifficultyTargetAsInteger() throws VerificationException {
|
||||||
|
BigInteger target = Utils.decodeCompactBits(difficultyTarget);
|
||||||
|
if (target.compareTo(BigInteger.valueOf(0)) <= 0 || target.compareTo(params.proofOfWorkLimit) > 0)
|
||||||
|
throw new VerificationException("Difficulty target is bad");
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns true if the hash of the block is OK (lower than difficulty target). */
|
/** Returns true if the hash of the block is OK (lower than difficulty target). */
|
||||||
private boolean checkProofOfWork(boolean throwException) throws VerificationException {
|
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
|
// This part is key - it is what proves the block was as difficult to make as it claims
|
||||||
@ -193,10 +220,7 @@ public class Block extends Message {
|
|||||||
//
|
//
|
||||||
// To prevent this attack from being possible, elsewhere we check that the difficultyTarget
|
// To prevent this attack from being possible, elsewhere we check that the difficultyTarget
|
||||||
// field is of the right value. This requires us to have the preceeding blocks.
|
// field is of the right value. This requires us to have the preceeding blocks.
|
||||||
BigInteger target = Utils.decodeCompactBits(difficultyTarget);
|
BigInteger target = getDifficultyTargetAsInteger();
|
||||||
|
|
||||||
if (target.compareTo(BigInteger.valueOf(0)) <= 0 || target.compareTo(params.proofOfWorkLimit) > 0)
|
|
||||||
throw new VerificationException("Difficulty target is bad");
|
|
||||||
|
|
||||||
BigInteger h = new BigInteger(1, getHash());
|
BigInteger h = new BigInteger(1, getHash());
|
||||||
if (h.compareTo(target) > 0) {
|
if (h.compareTo(target) > 0) {
|
||||||
@ -392,13 +416,6 @@ public class Block extends Message {
|
|||||||
return difficultyTarget;
|
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) {
|
public void setDifficultyTarget(long compactForm) {
|
||||||
this.difficultyTarget = compactForm;
|
this.difficultyTarget = compactForm;
|
||||||
this.hash = null;
|
this.hash = null;
|
||||||
|
@ -22,7 +22,6 @@ import java.util.Arrays;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
|
||||||
import static com.google.bitcoin.core.Utils.LOG;
|
import static com.google.bitcoin.core.Utils.LOG;
|
||||||
import static com.google.bitcoin.core.Utils.bytesToHexString;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A BlockChain holds a series of {@link Block} objects, links them together, and knows how to verify that the
|
* A BlockChain holds a series of {@link Block} objects, links them together, and knows how to verify that the
|
||||||
@ -50,10 +49,7 @@ import static com.google.bitcoin.core.Utils.bytesToHexString;
|
|||||||
*/
|
*/
|
||||||
public class BlockChain {
|
public class BlockChain {
|
||||||
// This is going away.
|
// This is going away.
|
||||||
private final LinkedList<Block> blockChain = new LinkedList<Block>();
|
private final LinkedList<Block> blockChain;
|
||||||
|
|
||||||
/** Each chain head that we saw so far. */
|
|
||||||
private final ArrayList<Block> chainHeads = new ArrayList<Block>();
|
|
||||||
|
|
||||||
private final NetworkParameters params;
|
private final NetworkParameters params;
|
||||||
private final Wallet wallet;
|
private final Wallet wallet;
|
||||||
@ -63,6 +59,7 @@ public class BlockChain {
|
|||||||
private final ArrayList<Block> unconnectedBlocks = new ArrayList<Block>();
|
private final ArrayList<Block> unconnectedBlocks = new ArrayList<Block>();
|
||||||
|
|
||||||
public BlockChain(NetworkParameters params, Wallet wallet) {
|
public BlockChain(NetworkParameters params, Wallet wallet) {
|
||||||
|
blockChain = new LinkedList<Block>();
|
||||||
blockChain.add(params.genesisBlock);
|
blockChain.add(params.genesisBlock);
|
||||||
this.params = params;
|
this.params = params;
|
||||||
this.wallet = wallet;
|
this.wallet = wallet;
|
||||||
@ -119,7 +116,7 @@ public class BlockChain {
|
|||||||
unconnectedBlocks.add(block);
|
unconnectedBlocks.add(block);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
checkDifficultyTransitions(block);
|
checkDifficultyTransitions(prev, block);
|
||||||
// The block is OK so let's build the rest of the chain on it.
|
// The block is OK so let's build the rest of the chain on it.
|
||||||
block.prevBlock = prev;
|
block.prevBlock = prev;
|
||||||
blockChain.add(block);
|
blockChain.add(block);
|
||||||
@ -158,14 +155,13 @@ public class BlockChain {
|
|||||||
static private final int TARGET_SPACING = 10 * 60;
|
static private final int TARGET_SPACING = 10 * 60;
|
||||||
static private final int INTERVAL = TARGET_TIMESPAN / TARGET_SPACING;
|
static private final int INTERVAL = TARGET_TIMESPAN / TARGET_SPACING;
|
||||||
|
|
||||||
private void checkDifficultyTransitions(Block top) throws VerificationException {
|
private void checkDifficultyTransitions(Block prev, Block next) throws VerificationException {
|
||||||
Block prev = blockChain.getLast();
|
|
||||||
// Is this supposed to be a difficulty transition point?
|
// Is this supposed to be a difficulty transition point?
|
||||||
if (blockChain.size() % INTERVAL != 0) {
|
if (blockChain.size() % INTERVAL != 0) {
|
||||||
// No ... so check the difficulty didn't actually change.
|
// No ... so check the difficulty didn't actually change.
|
||||||
if (top.getDifficultyTarget() != prev.getDifficultyTarget())
|
if (next.getDifficultyTarget() != prev.getDifficultyTarget())
|
||||||
throw new VerificationException("Unexpected change in difficulty at height " + blockChain.size() +
|
throw new VerificationException("Unexpected change in difficulty at height " + blockChain.size() +
|
||||||
": " + Long.toHexString(top.getDifficultyTarget()) + " vs " +
|
": " + Long.toHexString(next.getDifficultyTarget()) + " vs " +
|
||||||
Long.toHexString(prev.getDifficultyTarget()));
|
Long.toHexString(prev.getDifficultyTarget()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -186,8 +182,8 @@ public class BlockChain {
|
|||||||
newDifficulty = params.proofOfWorkLimit;
|
newDifficulty = params.proofOfWorkLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
int accuracyBytes = (int) (top.getDifficultyTarget() >>> 24) - 3;
|
int accuracyBytes = (int) (next.getDifficultyTarget() >>> 24) - 3;
|
||||||
BigInteger receivedDifficulty = top.getDifficultyTargetBI();
|
BigInteger receivedDifficulty = next.getDifficultyTargetAsInteger();
|
||||||
|
|
||||||
// The calculated difficulty is to a higher precision than received, so reduce here.
|
// The calculated difficulty is to a higher precision than received, so reduce here.
|
||||||
BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8);
|
BigInteger mask = BigInteger.valueOf(0xFFFFFFL).shiftLeft(accuracyBytes * 8);
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user