mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-02-22 14:22:45 +01:00
Block: add new constructors to reduce mutability
* New constructors and static factory methods * Update code to use the new constructors * Remove `public` from `@VisibleForTesting` setters where possible
This commit is contained in:
parent
734993db68
commit
16ac8751bb
8 changed files with 61 additions and 54 deletions
|
@ -51,6 +51,7 @@ import java.util.Date;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import static org.bitcoinj.base.Coin.FIFTY_COINS;
|
import static org.bitcoinj.base.Coin.FIFTY_COINS;
|
||||||
import static org.bitcoinj.base.Sha256Hash.hashTwice;
|
import static org.bitcoinj.base.Sha256Hash.hashTwice;
|
||||||
|
@ -178,13 +179,32 @@ public class Block extends BaseMessage {
|
||||||
return transactions;
|
return transactions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Special case constructor, used for the genesis node, cloneAsHeader and unit tests. */
|
/** Special case constructor, used for unit tests. */
|
||||||
|
@VisibleForTesting
|
||||||
Block(long setVersion) {
|
Block(long setVersion) {
|
||||||
// Set up a few basic things. We are not complete after this though.
|
// Set up a few basic things. We are not complete after this though.
|
||||||
version = setVersion;
|
this(setVersion,
|
||||||
difficultyTarget = 0x1d07fff8L;
|
TimeUtils.currentTime().truncatedTo(ChronoUnit.SECONDS), // convert to Bitcoin time)
|
||||||
time = TimeUtils.currentTime().truncatedTo(ChronoUnit.SECONDS); // convert to Bitcoin time
|
0x1d07fff8L,
|
||||||
prevBlockHash = Sha256Hash.ZERO_HASH;
|
0,
|
||||||
|
Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
// For unit-test genesis blocks
|
||||||
|
@VisibleForTesting
|
||||||
|
Block(long setVersion, Instant time, long difficultyTarget, List<Transaction> transactions) {
|
||||||
|
this(setVersion, time, difficultyTarget, 0, transactions);
|
||||||
|
// Solve for nonce?
|
||||||
|
}
|
||||||
|
|
||||||
|
// For genesis blocks (and also unit tests)
|
||||||
|
Block(long setVersion, Instant time, long difficultyTarget, long nonce, List<Transaction> transactions) {
|
||||||
|
this.version = setVersion;
|
||||||
|
this.time = time;
|
||||||
|
this.difficultyTarget = difficultyTarget;
|
||||||
|
this.nonce = nonce;
|
||||||
|
this.prevBlockHash = Sha256Hash.ZERO_HASH;
|
||||||
|
this.transactions = new ArrayList<>(Objects.requireNonNull(transactions));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -229,12 +249,18 @@ public class Block extends BaseMessage {
|
||||||
transactions);
|
transactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Block createGenesis() {
|
public static Block createGenesis(Instant time, long difficultyTarget) {
|
||||||
Block genesisBlock = new Block(BLOCK_VERSION_GENESIS);
|
return new Block(BLOCK_VERSION_GENESIS, time, difficultyTarget, genesisTransactions());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Block createGenesis(Instant time, long difficultyTarget, long nonce) {
|
||||||
|
return new Block(BLOCK_VERSION_GENESIS, time, difficultyTarget, nonce, genesisTransactions());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Transaction> genesisTransactions() {
|
||||||
Transaction tx = Transaction.coinbase(genesisTxInputScriptBytes);
|
Transaction tx = Transaction.coinbase(genesisTxInputScriptBytes);
|
||||||
tx.addOutput(new TransactionOutput(tx, FIFTY_COINS, genesisTxScriptPubKeyBytes));
|
tx.addOutput(new TransactionOutput(tx, FIFTY_COINS, genesisTxScriptPubKeyBytes));
|
||||||
genesisBlock.addTransaction(tx);
|
return Collections.singletonList(tx);
|
||||||
return genesisBlock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A script containing the difficulty bits and the following message:
|
// A script containing the difficulty bits and the following message:
|
||||||
|
@ -367,14 +393,8 @@ public class Block extends BaseMessage {
|
||||||
* @return new, header-only {@code Block}
|
* @return new, header-only {@code Block}
|
||||||
*/
|
*/
|
||||||
public Block cloneAsHeader() {
|
public Block cloneAsHeader() {
|
||||||
Block block = new Block(version);
|
Block block = new Block(version, prevBlockHash, getMerkleRoot(), time, difficultyTarget, nonce, null);
|
||||||
block.difficultyTarget = difficultyTarget;
|
|
||||||
block.time = time;
|
|
||||||
block.nonce = nonce;
|
|
||||||
block.prevBlockHash = prevBlockHash;
|
|
||||||
block.merkleRoot = getMerkleRoot();
|
|
||||||
block.hash = getHash();
|
block.hash = getHash();
|
||||||
block.transactions = null;
|
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,7 +749,7 @@ public class Block extends BaseMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setTime(Instant time) {
|
void setTime(Instant time) {
|
||||||
unCacheHeader();
|
unCacheHeader();
|
||||||
this.time = time.truncatedTo(ChronoUnit.SECONDS); // convert to Bitcoin time
|
this.time = time.truncatedTo(ChronoUnit.SECONDS); // convert to Bitcoin time
|
||||||
this.hash = null;
|
this.hash = null;
|
||||||
|
@ -750,7 +770,7 @@ public class Block extends BaseMessage {
|
||||||
|
|
||||||
/** Sets the difficulty target in compact form. */
|
/** Sets the difficulty target in compact form. */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setDifficultyTarget(long compactForm) {
|
void setDifficultyTarget(long compactForm) {
|
||||||
unCacheHeader();
|
unCacheHeader();
|
||||||
this.difficultyTarget = compactForm;
|
this.difficultyTarget = compactForm;
|
||||||
this.hash = null;
|
this.hash = null;
|
||||||
|
@ -766,7 +786,7 @@ public class Block extends BaseMessage {
|
||||||
|
|
||||||
/** Sets the nonce and clears any cached data. */
|
/** Sets the nonce and clears any cached data. */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setNonce(long nonce) {
|
void setNonce(long nonce) {
|
||||||
unCacheHeader();
|
unCacheHeader();
|
||||||
this.nonce = nonce;
|
this.nonce = nonce;
|
||||||
this.hash = null;
|
this.hash = null;
|
||||||
|
|
|
@ -134,10 +134,7 @@ public class MainNetParams extends BitcoinNetworkParams {
|
||||||
public Block getGenesisBlock() {
|
public Block getGenesisBlock() {
|
||||||
synchronized (GENESIS_HASH) {
|
synchronized (GENESIS_HASH) {
|
||||||
if (genesisBlock == null) {
|
if (genesisBlock == null) {
|
||||||
genesisBlock = Block.createGenesis();
|
genesisBlock = Block.createGenesis(GENESIS_TIME, Block.STANDARD_MAX_DIFFICULTY_TARGET, GENESIS_NONCE);
|
||||||
genesisBlock.setDifficultyTarget(Block.STANDARD_MAX_DIFFICULTY_TARGET);
|
|
||||||
genesisBlock.setTime(GENESIS_TIME);
|
|
||||||
genesisBlock.setNonce(GENESIS_NONCE);
|
|
||||||
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () -> "invalid genesis hash");
|
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () -> "invalid genesis hash");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,10 +82,7 @@ public class RegTestParams extends BitcoinNetworkParams {
|
||||||
public Block getGenesisBlock() {
|
public Block getGenesisBlock() {
|
||||||
synchronized (GENESIS_HASH) {
|
synchronized (GENESIS_HASH) {
|
||||||
if (genesisBlock == null) {
|
if (genesisBlock == null) {
|
||||||
genesisBlock = Block.createGenesis();
|
genesisBlock = Block.createGenesis(GENESIS_TIME, Block.EASIEST_DIFFICULTY_TARGET, GENESIS_NONCE);
|
||||||
genesisBlock.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
|
|
||||||
genesisBlock.setTime(GENESIS_TIME);
|
|
||||||
genesisBlock.setNonce(GENESIS_NONCE);
|
|
||||||
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () ->
|
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () ->
|
||||||
"invalid genesis hash");
|
"invalid genesis hash");
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,10 +79,7 @@ public class SigNetParams extends BitcoinNetworkParams {
|
||||||
public Block getGenesisBlock() {
|
public Block getGenesisBlock() {
|
||||||
synchronized (GENESIS_HASH) {
|
synchronized (GENESIS_HASH) {
|
||||||
if (genesisBlock == null) {
|
if (genesisBlock == null) {
|
||||||
genesisBlock = Block.createGenesis();
|
genesisBlock = Block.createGenesis(GENESIS_TIME, GENESIS_DIFFICULTY, GENESIS_NONCE);
|
||||||
genesisBlock.setDifficultyTarget(GENESIS_DIFFICULTY);
|
|
||||||
genesisBlock.setTime(GENESIS_TIME);
|
|
||||||
genesisBlock.setNonce(GENESIS_NONCE);
|
|
||||||
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () ->
|
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () ->
|
||||||
"invalid genesis hash");
|
"invalid genesis hash");
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,10 +88,7 @@ public class TestNet3Params extends BitcoinNetworkParams {
|
||||||
public Block getGenesisBlock() {
|
public Block getGenesisBlock() {
|
||||||
synchronized (GENESIS_HASH) {
|
synchronized (GENESIS_HASH) {
|
||||||
if (genesisBlock == null) {
|
if (genesisBlock == null) {
|
||||||
genesisBlock = Block.createGenesis();
|
genesisBlock = Block.createGenesis(GENESIS_TIME, Block.STANDARD_MAX_DIFFICULTY_TARGET, GENESIS_NONCE);
|
||||||
genesisBlock.setDifficultyTarget(Block.STANDARD_MAX_DIFFICULTY_TARGET);
|
|
||||||
genesisBlock.setTime(GENESIS_TIME);
|
|
||||||
genesisBlock.setNonce(GENESIS_NONCE);
|
|
||||||
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () ->
|
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () ->
|
||||||
"invalid genesis hash");
|
"invalid genesis hash");
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,9 +73,7 @@ public class UnitTestParams extends BitcoinNetworkParams {
|
||||||
public Block getGenesisBlock() {
|
public Block getGenesisBlock() {
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (genesisBlock == null) {
|
if (genesisBlock == null) {
|
||||||
genesisBlock = Block.createGenesis();
|
genesisBlock = Block.createGenesis(TimeUtils.currentTime(), Block.EASIEST_DIFFICULTY_TARGET);
|
||||||
genesisBlock.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
|
|
||||||
genesisBlock.setTime(TimeUtils.currentTime());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return genesisBlock;
|
return genesisBlock;
|
||||||
|
|
|
@ -414,24 +414,26 @@ public class BlockChainTest {
|
||||||
|
|
||||||
// Some blocks from the test net.
|
// Some blocks from the test net.
|
||||||
private static Block getBlock2() throws Exception {
|
private static Block getBlock2() throws Exception {
|
||||||
Block b2 = new Block(Block.BLOCK_VERSION_GENESIS);
|
Block b2 = new Block(Block.BLOCK_VERSION_GENESIS,
|
||||||
b2.setMerkleRoot(Sha256Hash.wrap("20222eb90f5895556926c112bb5aa0df4ab5abc3107e21a6950aec3b2e3541e2"));
|
Sha256Hash.wrap("00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206"), // prev
|
||||||
b2.setNonce(875942400L);
|
Sha256Hash.wrap("20222eb90f5895556926c112bb5aa0df4ab5abc3107e21a6950aec3b2e3541e2"), // merkle
|
||||||
b2.setTime(Instant.ofEpochSecond(1296688946L));
|
Instant.ofEpochSecond(1296688946L),
|
||||||
b2.setDifficultyTarget(0x1d00ffff);
|
0x1d00ffff,
|
||||||
b2.setPrevBlockHash(Sha256Hash.wrap("00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206"));
|
875942400L,
|
||||||
|
null);
|
||||||
assertEquals("000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820", b2.getHashAsString());
|
assertEquals("000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820", b2.getHashAsString());
|
||||||
Block.verifyHeader(b2);
|
Block.verifyHeader(b2);
|
||||||
return b2;
|
return b2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Block getBlock1() throws Exception {
|
private static Block getBlock1() throws Exception {
|
||||||
Block b1 = new Block(Block.BLOCK_VERSION_GENESIS);
|
Block b1 = new Block(Block.BLOCK_VERSION_GENESIS,
|
||||||
b1.setMerkleRoot(Sha256Hash.wrap("f0315ffc38709d70ad5647e22048358dd3745f3ce3874223c80a7c92fab0c8ba"));
|
Sha256Hash.wrap("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"), // prev
|
||||||
b1.setNonce(1924588547);
|
Sha256Hash.wrap("f0315ffc38709d70ad5647e22048358dd3745f3ce3874223c80a7c92fab0c8ba"), // merkle
|
||||||
b1.setTime(Instant.ofEpochSecond(1296688928));
|
Instant.ofEpochSecond(1296688928),
|
||||||
b1.setDifficultyTarget(0x1d00ffff);
|
0x1d00ffff,
|
||||||
b1.setPrevBlockHash(Sha256Hash.wrap("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
|
1924588547,
|
||||||
|
null);
|
||||||
assertEquals("00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206", b1.getHashAsString());
|
assertEquals("00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206", b1.getHashAsString());
|
||||||
Block.verifyHeader(b1);
|
Block.verifyHeader(b1);
|
||||||
return b1;
|
return b1;
|
||||||
|
|
|
@ -336,10 +336,9 @@ public class BlockTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenesisBlock() {
|
public void testGenesisBlock() {
|
||||||
Block genesisBlock = Block.createGenesis();
|
Block genesisBlock = Block.createGenesis(Instant.ofEpochSecond(1231006505L),
|
||||||
genesisBlock.setDifficultyTarget(0x1d00ffffL);
|
0x1d00ffffL,
|
||||||
genesisBlock.setTime(Instant.ofEpochSecond(1231006505L));
|
2083236893);
|
||||||
genesisBlock.setNonce(2083236893);
|
|
||||||
assertEquals(Sha256Hash.wrap("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"), genesisBlock.getHash());
|
assertEquals(Sha256Hash.wrap("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"), genesisBlock.getHash());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue