mirror of
https://github.com/bitcoinj/bitcoinj.git
synced 2025-03-13 11:36:15 +01:00
Merge c4318a3cbb
into 40b1ac351f
This commit is contained in:
commit
c5396ec5d1
17 changed files with 423 additions and 111 deletions
169
base/src/main/java/org/bitcoinj/base/Difficulty.java
Normal file
169
base/src/main/java/org/bitcoinj/base/Difficulty.java
Normal file
|
@ -0,0 +1,169 @@
|
|||
/*
|
||||
* Copyright by the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoinj.base;
|
||||
|
||||
import org.bitcoinj.base.internal.ByteUtils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.Duration;
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.bitcoinj.base.internal.Preconditions.checkArgument;
|
||||
|
||||
/**
|
||||
* The target difficulty is a value which a header hash must be equal to or below in order for that header to be a
|
||||
* valid part of the block chain.
|
||||
* <p>
|
||||
* Difficulty values cannot be negative. A high value means low difficulty, and a low value means high difficulty.
|
||||
* <p>
|
||||
* The value is stored in only 32 bits of space, so it uses a less precise “compact form”, or "nBits". Think of it as a
|
||||
* base-256 version of the scientific notation, consisting of a 1 byte exponent and 3 bytes of mantissa. That form is
|
||||
* used for storing the value in this class as well, so when constructing from an integer value, be prepared to lose
|
||||
* precision.
|
||||
*/
|
||||
public class Difficulty implements Comparable<Difficulty> {
|
||||
|
||||
/**
|
||||
* Standard maximum value for difficulty target. For most chains this is declared to be "difficulty 1", because
|
||||
* it is fairly easy.
|
||||
*/
|
||||
public static final Difficulty STANDARD_MAX_DIFFICULTY_TARGET = Difficulty.ofCompact(0x1d00ffff);
|
||||
/**
|
||||
* The easiest difficulty target possible, allowing (slightly less than) half of all possible hash solutions.
|
||||
* This is the highest value this class can represent. Used for testing.
|
||||
*/
|
||||
public static final Difficulty EASIEST_DIFFICULTY_TARGET = Difficulty.ofCompact(0x207fffff);
|
||||
|
||||
// for bounds checking
|
||||
private static final BigInteger MAX_INTEGER_VALUE = Difficulty.EASIEST_DIFFICULTY_TARGET.asInteger();
|
||||
|
||||
private final long compact;
|
||||
|
||||
private Difficulty(long compact) {
|
||||
this.compact = compact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a difficulty from a compact form, sometimes called "nBits".
|
||||
*
|
||||
* @param compact compact form
|
||||
* @return constructed difficulty
|
||||
*/
|
||||
public static Difficulty ofCompact(long compact) {
|
||||
long exponent = (compact >> 24) & 0xff;
|
||||
checkArgument(exponent <= 32, () ->
|
||||
"exponent cannot exceed 32: " + Long.toHexString(compact));
|
||||
long mantissa = compact & 0xffffff;
|
||||
checkArgument(mantissa <= 0x7fffff, () ->
|
||||
"sign bit 24 cannot be set: " + Long.toHexString(compact));
|
||||
checkArgument(mantissa >= 0x008000, () ->
|
||||
"not optimally encoded, can shift to left: " + Long.toHexString(compact));
|
||||
return new Difficulty(compact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a difficulty from an 256-bit integer value. Because the value is stored in compact form, it will
|
||||
* likely lose precision.
|
||||
*
|
||||
* @param value 256-bit integer value
|
||||
* @return constructed difficulty
|
||||
*/
|
||||
public static Difficulty ofInteger(BigInteger value) {
|
||||
checkArgument(value.signum() >= 0, () ->
|
||||
"cannot be negative: " + value.toString(16));
|
||||
checkArgument(value.compareTo(MAX_INTEGER_VALUE) <= 0, () ->
|
||||
"too high: " + value.toString(16));
|
||||
return new Difficulty(ByteUtils.encodeCompactBits(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Inside a block the difficulty target is represented using a compact form, sometimes called "nBits".
|
||||
*
|
||||
* @return difficulty target as a long in compact form
|
||||
*/
|
||||
public long compact() {
|
||||
return compact;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the difficulty target as a 256 bit value that can be compared to a SHA-256 hash.
|
||||
*
|
||||
* @return difficulty target as 256-bit integer value
|
||||
*/
|
||||
public BigInteger asInteger() {
|
||||
return ByteUtils.decodeCompactBits(compact);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust this difficulty so that actual time between blocks closely matches our target. This method doesn't take
|
||||
* hash rate changes between intervals into account.
|
||||
*
|
||||
* @param actualTimespan the actual duration of the last block interval, according to the headers
|
||||
* @param targetTimespan the duration of block intervals we're targetting at
|
||||
* @param maxTarget make sure adjusted difficulty doesn't get any easier than this value
|
||||
* @return adjusted difficulty to be used for the next interval
|
||||
*/
|
||||
public Difficulty adjust(Duration actualTimespan, Duration targetTimespan, Difficulty maxTarget) {
|
||||
checkArgument(!actualTimespan.isNegative(), () -> "cannot be negative: " + actualTimespan);
|
||||
checkArgument(!actualTimespan.isZero(), () -> "cannot be zero: " + actualTimespan);
|
||||
checkArgument(!targetTimespan.isNegative(), () -> "cannot be negative: " + targetTimespan);
|
||||
checkArgument(!targetTimespan.isZero(), () -> "cannot be zero: " + targetTimespan);
|
||||
BigInteger adjusted = asInteger()
|
||||
.multiply(BigInteger.valueOf(actualTimespan.getSeconds()))
|
||||
.divide(BigInteger.valueOf(targetTimespan.getSeconds()));
|
||||
if (adjusted.compareTo(maxTarget.asInteger()) > 0)
|
||||
return maxTarget;
|
||||
else
|
||||
return Difficulty.ofInteger(adjusted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the work represented by a given block hash meets or exceeds this difficulty target. The more
|
||||
* leading zero bits the hash has, the more work has been put into creating it.
|
||||
*
|
||||
* @param blockHash block hash that represents work
|
||||
* @return true if this target is met or exceeded by given work
|
||||
*/
|
||||
public boolean isMetByWork(Sha256Hash blockHash) {
|
||||
BigInteger work = blockHash.toBigInteger();
|
||||
return work.compareTo(this.asInteger()) <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Long.toHexString(compact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
return this.compact == ((Difficulty) o).compact;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(compact);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Difficulty other) {
|
||||
// This yields the same order as if we were comparing the integer
|
||||
// forms, due to the optimal encoding rule of the compact format.
|
||||
return Long.compare(this.compact, other.compact);
|
||||
}
|
||||
}
|
126
base/src/test/java/org/bitcoinj/base/DifficultyTest.java
Normal file
126
base/src/test/java/org/bitcoinj/base/DifficultyTest.java
Normal file
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright by the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.bitcoinj.base;
|
||||
|
||||
import junitparams.JUnitParamsRunner;
|
||||
import junitparams.Parameters;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.Duration;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
@RunWith(JUnitParamsRunner.class)
|
||||
public class DifficultyTest {
|
||||
|
||||
@Test
|
||||
@Parameters(method = "testVectors")
|
||||
public void compactToInteger(long compact, String expectedInteger) {
|
||||
Difficulty difficulty = Difficulty.ofCompact(compact);
|
||||
BigInteger integer = difficulty.asInteger();
|
||||
assertEquals(expectedInteger, integer.toString(16));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Parameters(method = "testVectors")
|
||||
public void integerToCompact(long expectedCompact, String integerHex) {
|
||||
Difficulty difficulty = Difficulty.ofInteger(new BigInteger(integerHex, 16));
|
||||
long compact = difficulty.compact();
|
||||
assertEquals(expectedCompact, compact);
|
||||
}
|
||||
|
||||
private Object[] testVectors() {
|
||||
return new Object[] {
|
||||
// from https://en.bitcoin.it/wiki/Difficulty
|
||||
new Object[] { 0x1d00ffff, "ffff0000000000000000000000000000000000000000000000000000" }, // difficulty 1
|
||||
new Object[] { 0x1b0404cb, "404cb000000000000000000000000000000000000000000000000" },
|
||||
// from https://developer.bitcoin.org/reference/block_chain.html#target-nbits
|
||||
new Object[] { 0x02008000, "80" },
|
||||
new Object[] { 0x05009234, "92340000" },
|
||||
new Object[] { 0x04123456, "12345600" },
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exponentZero_mantissaIsShiftedOutOfExistance() {
|
||||
assertEquals("0", Difficulty.ofCompact(0x00778899).asInteger().toString(16));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exponentOne_mantissaIsLoosingTwoBytes() {
|
||||
assertEquals("77", Difficulty.ofCompact(0x01778899).asInteger().toString(16));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exponentTwo_mantissaIsLoosingOneByte() {
|
||||
assertEquals("7788", Difficulty.ofCompact(0x02778899).asInteger().toString(16));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void exponent_tooHigh() {
|
||||
Difficulty.ofCompact(0x217fffff);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mantissa_highestPossible() {
|
||||
Difficulty.ofCompact(0x007fffff);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void mantissa_tooHigh() {
|
||||
// the 24th bit is sign, so the value would be negative
|
||||
Difficulty.ofCompact(0x00800000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mantissa_lowestPossible() {
|
||||
Difficulty.ofCompact(0x00008000);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void mantissa_tooLow() {
|
||||
// these bits can be encoded more optimally by shifting to the left by one
|
||||
Difficulty.ofCompact(0x00007fff);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void ofInteger_negativeValueNotAllowed() {
|
||||
Difficulty.ofInteger(BigInteger.ONE.negate());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void ofInteger_valueTooHigh() {
|
||||
BigInteger easierThanEasiest = Difficulty.EASIEST_DIFFICULTY_TARGET.asInteger().add(BigInteger.ONE);
|
||||
Difficulty.ofInteger(easierThanEasiest);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void adjust_easiestEvenEasier_shouldNotAdjust() {
|
||||
Difficulty easier = Difficulty.EASIEST_DIFFICULTY_TARGET.adjust(
|
||||
Duration.ofDays(15), Duration.ofDays(10), Difficulty.EASIEST_DIFFICULTY_TARGET);
|
||||
assertEquals(Difficulty.EASIEST_DIFFICULTY_TARGET, easier);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compareTo() {
|
||||
Difficulty d1 = Difficulty.ofCompact(0x10771111);
|
||||
Difficulty d2 = Difficulty.ofCompact(0x11111177);
|
||||
assertEquals(1, d2.compareTo(d1));
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
package org.bitcoinj.core;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.Network;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
import org.bitcoinj.core.listeners.NewBestBlockListener;
|
||||
|
@ -493,9 +494,9 @@ public abstract class AbstractBlockChain {
|
|||
return false;
|
||||
}
|
||||
|
||||
BigInteger target = block.getDifficultyTargetAsInteger();
|
||||
if (target.signum() <= 0 || target.compareTo(params.maxTarget) > 0)
|
||||
throw new VerificationException("Difficulty target is out of range: " + target.toString());
|
||||
Difficulty target = block.difficultyTarget();
|
||||
if (target.compareTo(params.maxTarget) > 0)
|
||||
throw new VerificationException("Difficulty target is out of range: " + target);
|
||||
|
||||
// If we want to verify transactions (ie we are running with full blocks), verify that block has transactions
|
||||
if (shouldVerifyTransactions() && block.getTransactions() == null)
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.bitcoinj.core;
|
|||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.bitcoinj.base.Address;
|
||||
import org.bitcoinj.base.Coin;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
import org.bitcoinj.base.VarInt;
|
||||
import org.bitcoinj.base.internal.Buffers;
|
||||
|
@ -29,7 +30,6 @@ import org.bitcoinj.base.internal.TimeUtils;
|
|||
import org.bitcoinj.base.internal.ByteUtils;
|
||||
import org.bitcoinj.base.internal.InternalUtils;
|
||||
import org.bitcoinj.crypto.ECKey;
|
||||
import org.bitcoinj.params.BitcoinNetworkParams;
|
||||
import org.bitcoinj.script.Script;
|
||||
import org.bitcoinj.script.ScriptBuilder;
|
||||
import org.bitcoinj.script.ScriptOpCodes;
|
||||
|
@ -101,11 +101,12 @@ public class Block extends BaseMessage {
|
|||
*/
|
||||
public static final int MAX_BLOCK_SIGOPS = MAX_BLOCK_SIZE / 50;
|
||||
|
||||
/** Standard maximum value for difficultyTarget (nBits) (Bitcoin MainNet and TestNet) */
|
||||
public static final long STANDARD_MAX_DIFFICULTY_TARGET = 0x1d00ffffL;
|
||||
|
||||
/** A value for difficultyTarget (nBits) that allows (slightly less than) half of all possible hash solutions. Used in unit testing. */
|
||||
public static final long EASIEST_DIFFICULTY_TARGET = 0x207fFFFFL;
|
||||
/** @deprecated use {@link Difficulty#STANDARD_MAX_DIFFICULTY_TARGET} */
|
||||
@Deprecated
|
||||
public static final long STANDARD_MAX_DIFFICULTY_TARGET = Difficulty.STANDARD_MAX_DIFFICULTY_TARGET.compact();
|
||||
/** @deprecated use {@link Difficulty#EASIEST_DIFFICULTY_TARGET} */
|
||||
@Deprecated
|
||||
public static final long EASIEST_DIFFICULTY_TARGET = Difficulty.EASIEST_DIFFICULTY_TARGET.compact();
|
||||
|
||||
/** Value to use if the block height is unknown */
|
||||
public static final int BLOCK_HEIGHT_UNKNOWN = -1;
|
||||
|
@ -125,7 +126,7 @@ public class Block extends BaseMessage {
|
|||
private Sha256Hash prevBlockHash;
|
||||
private Sha256Hash merkleRoot, witnessRoot;
|
||||
private Instant time;
|
||||
private long difficultyTarget; // "nBits"
|
||||
private Difficulty difficultyTarget; // "nBits"
|
||||
private long nonce;
|
||||
|
||||
// If null, it means this object holds only the headers.
|
||||
|
@ -149,7 +150,7 @@ public class Block extends BaseMessage {
|
|||
Sha256Hash prevBlockHash = Sha256Hash.read(payload);
|
||||
Sha256Hash merkleRoot = Sha256Hash.read(payload);
|
||||
Instant time = Instant.ofEpochSecond(ByteUtils.readUint32(payload));
|
||||
long difficultyTarget = ByteUtils.readUint32(payload);
|
||||
Difficulty difficultyTarget = Difficulty.ofCompact(ByteUtils.readUint32(payload));
|
||||
long nonce = ByteUtils.readUint32(payload);
|
||||
payload.reset(); // read again from the mark for the hash
|
||||
Sha256Hash hash = Sha256Hash.wrapReversed(Sha256Hash.hashTwice(Buffers.readBytes(payload, HEADER_SIZE)));
|
||||
|
@ -184,20 +185,20 @@ public class Block extends BaseMessage {
|
|||
// Set up a few basic things. We are not complete after this though.
|
||||
this(setVersion,
|
||||
TimeUtils.currentTime().truncatedTo(ChronoUnit.SECONDS), // convert to Bitcoin time)
|
||||
0x1d07fff8L,
|
||||
Difficulty.ofCompact(0x1d07fff8L),
|
||||
0,
|
||||
Collections.emptyList());
|
||||
}
|
||||
|
||||
// For unit-test genesis blocks
|
||||
// For testing only
|
||||
Block(long setVersion, Instant time, long difficultyTarget, List<Transaction> transactions) {
|
||||
Block(long setVersion, Instant time, Difficulty 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) {
|
||||
Block(long setVersion, Instant time, Difficulty difficultyTarget, long nonce, List<Transaction> transactions) {
|
||||
this.version = setVersion;
|
||||
this.time = time;
|
||||
this.difficultyTarget = difficultyTarget;
|
||||
|
@ -217,7 +218,7 @@ public class Block extends BaseMessage {
|
|||
* @param transactions List of transactions including the coinbase, or {@code null} for header-only blocks
|
||||
*/
|
||||
public Block(long version, Sha256Hash prevBlockHash, Sha256Hash merkleRoot, Instant time,
|
||||
long difficultyTarget, long nonce, @Nullable List<Transaction> transactions) {
|
||||
Difficulty difficultyTarget, long nonce, @Nullable List<Transaction> transactions) {
|
||||
super();
|
||||
this.version = version;
|
||||
this.prevBlockHash = prevBlockHash;
|
||||
|
@ -230,14 +231,33 @@ public class Block extends BaseMessage {
|
|||
null;
|
||||
}
|
||||
|
||||
public static Block createGenesis(Instant time, long difficultyTarget) {
|
||||
/** @deprecated use {@link #Block(long, Sha256Hash, Sha256Hash, Instant, Difficulty, long, List)} */
|
||||
@Deprecated
|
||||
public Block(long version, Sha256Hash prevBlockHash, Sha256Hash merkleRoot, Instant time,
|
||||
long difficultyTarget, long nonce, @Nullable List<Transaction> transactions) {
|
||||
this(version, prevBlockHash, merkleRoot, time, Difficulty.ofCompact(difficultyTarget), nonce, transactions);
|
||||
}
|
||||
|
||||
public static Block createGenesis(Instant time, Difficulty difficultyTarget) {
|
||||
return new Block(BLOCK_VERSION_GENESIS, time, difficultyTarget, genesisTransactions());
|
||||
}
|
||||
|
||||
public static Block createGenesis(Instant time, long difficultyTarget, long nonce) {
|
||||
/** @deprecated use {@link #createGenesis(Instant, Difficulty)} */
|
||||
@Deprecated
|
||||
public static Block createGenesis(Instant time, long difficultyTarget) {
|
||||
return createGenesis(time, Difficulty.ofCompact(difficultyTarget));
|
||||
}
|
||||
|
||||
public static Block createGenesis(Instant time, Difficulty difficultyTarget, long nonce) {
|
||||
return new Block(BLOCK_VERSION_GENESIS, time, difficultyTarget, nonce, genesisTransactions());
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #createGenesis(Instant, Difficulty, long)} */
|
||||
@Deprecated
|
||||
public static Block createGenesis(Instant time, long difficultyTarget, long nonce) {
|
||||
return createGenesis(time, Difficulty.ofCompact(difficultyTarget), nonce);
|
||||
}
|
||||
|
||||
private static List<Transaction> genesisTransactions() {
|
||||
Transaction tx = Transaction.coinbase(genesisTxInputScriptBytes);
|
||||
tx.addOutput(new TransactionOutput(tx, FIFTY_COINS, genesisTxScriptPubKeyBytes));
|
||||
|
@ -275,7 +295,7 @@ public class Block extends BaseMessage {
|
|||
stream.write(prevBlockHash.serialize());
|
||||
stream.write(getMerkleRoot().serialize());
|
||||
ByteUtils.writeInt32LE(time.getEpochSecond(), stream);
|
||||
ByteUtils.writeInt32LE(difficultyTarget, stream);
|
||||
ByteUtils.writeInt32LE(difficultyTarget.compact(), stream);
|
||||
ByteUtils.writeInt32LE(nonce, stream);
|
||||
}
|
||||
|
||||
|
@ -365,7 +385,7 @@ public class Block extends BaseMessage {
|
|||
* lower, the amount of work goes up.
|
||||
*/
|
||||
public BigInteger getWork() throws VerificationException {
|
||||
BigInteger target = getDifficultyTargetAsInteger();
|
||||
BigInteger target = difficultyTarget.asInteger();
|
||||
return LARGEST_HASH.divide(target.add(BigInteger.ONE));
|
||||
}
|
||||
|
||||
|
@ -437,14 +457,10 @@ public class Block extends BaseMessage {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @return difficulty target as 256-bit value
|
||||
*/
|
||||
/** @deprecated use {@link #difficultyTarget()} then {@link Difficulty#asInteger()} */
|
||||
@Deprecated
|
||||
public BigInteger getDifficultyTargetAsInteger() {
|
||||
return ByteUtils.decodeCompactBits(difficultyTarget);
|
||||
return difficultyTarget.asInteger();
|
||||
}
|
||||
|
||||
/** Returns true if the hash of the block is OK (lower than difficulty target). */
|
||||
|
@ -461,14 +477,11 @@ public class Block extends BaseMessage {
|
|||
//
|
||||
// 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 preceding blocks.
|
||||
BigInteger target = getDifficultyTargetAsInteger();
|
||||
|
||||
BigInteger h = getHash().toBigInteger();
|
||||
if (h.compareTo(target) > 0) {
|
||||
if (!difficultyTarget.isMetByWork(getHash())) {
|
||||
// Proof of work check failed!
|
||||
if (throwException)
|
||||
throw new VerificationException("Hash is higher than target: " + getHashAsString() + " vs "
|
||||
+ target.toString(16));
|
||||
+ difficultyTarget.asInteger().toString(16));
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
@ -728,23 +741,29 @@ public class Block extends BaseMessage {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the difficulty of the proof of work that this block should meet encoded <b>in compact form</b>. The {@link
|
||||
* Returns the difficulty of the proof of work that this block should meet. The {@link
|
||||
* BlockChain} verifies that this is not too easy by looking at the length of the chain when the block is added.
|
||||
* To find the actual value the hash should be compared against, use
|
||||
* {@link Block#getDifficultyTargetAsInteger()}. Note that this is <b>not</b> the same as
|
||||
* {@link Difficulty#asInteger()}. Note that this is <b>not</b> the same as
|
||||
* the difficulty value reported by the Bitcoin "getdifficulty" RPC that you may see on various block explorers.
|
||||
* That number is the result of applying a formula to the underlying difficulty to normalize the minimum to 1.
|
||||
* Calculating the difficulty that way is currently unsupported.
|
||||
*/
|
||||
public long getDifficultyTarget() {
|
||||
public Difficulty difficultyTarget() {
|
||||
return difficultyTarget;
|
||||
}
|
||||
|
||||
/** Sets the difficulty target in compact form. */
|
||||
/** @deprecated use {@link #difficultyTarget()} then {@link Difficulty#compact()} */
|
||||
@Deprecated
|
||||
public long getDifficultyTarget() {
|
||||
return difficultyTarget.compact();
|
||||
}
|
||||
|
||||
/** Sets the difficulty target. */
|
||||
// For testing only
|
||||
void setDifficultyTarget(long compactForm) {
|
||||
void setDifficultyTarget(Difficulty difficultyTarget) {
|
||||
unCacheHeader();
|
||||
this.difficultyTarget = compactForm;
|
||||
this.difficultyTarget = difficultyTarget;
|
||||
this.hash = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.bitcoinj.core;
|
|||
import org.bitcoinj.base.Address;
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.Coin;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.LegacyAddress;
|
||||
import org.bitcoinj.base.Network;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
|
@ -51,7 +52,7 @@ import java.util.Objects;
|
|||
public abstract class NetworkParameters {
|
||||
// TODO: Seed nodes should be here as well.
|
||||
|
||||
protected BigInteger maxTarget;
|
||||
protected Difficulty maxTarget;
|
||||
protected int port;
|
||||
protected int packetMagic; // Indicates message origin network and is used to seek to the next message when stream state is unknown.
|
||||
protected int addressHeader;
|
||||
|
@ -322,10 +323,16 @@ public abstract class NetworkParameters {
|
|||
* Maximum target represents the easiest allowable proof of work.
|
||||
* @return maximum target integer
|
||||
*/
|
||||
public BigInteger getMaxTarget() {
|
||||
public Difficulty maxTarget() {
|
||||
return maxTarget;
|
||||
}
|
||||
|
||||
/** @deprecated use {@link #maxTarget()} then {@link Difficulty#asInteger()} */
|
||||
@Deprecated
|
||||
public BigInteger getMaxTarget() {
|
||||
return maxTarget.asInteger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4 byte header for BIP32 wallet P2PKH - public key part.
|
||||
* @return the header value
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.bitcoinj.params;
|
||||
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.internal.Stopwatch;
|
||||
import org.bitcoinj.base.internal.TimeUtils;
|
||||
import org.bitcoinj.base.internal.ByteUtils;
|
||||
|
@ -158,10 +159,10 @@ public abstract class BitcoinNetworkParams extends NetworkParameters {
|
|||
if (!isDifficultyTransitionPoint(storedPrev.getHeight())) {
|
||||
|
||||
// No ... so check the difficulty didn't actually change.
|
||||
if (nextBlock.getDifficultyTarget() != prev.getDifficultyTarget())
|
||||
if (!nextBlock.difficultyTarget().equals(prev.difficultyTarget()))
|
||||
throw new VerificationException("Unexpected change in difficulty at height " + storedPrev.getHeight() +
|
||||
": " + Long.toHexString(nextBlock.getDifficultyTarget()) + " vs " +
|
||||
Long.toHexString(prev.getDifficultyTarget()));
|
||||
": " + nextBlock.difficultyTarget() + " vs " +
|
||||
prev.difficultyTarget());
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -187,37 +188,21 @@ public abstract class BitcoinNetworkParams extends NetworkParameters {
|
|||
log.info("Difficulty transition traversal took {}", watch);
|
||||
|
||||
Block blockIntervalAgo = cursor.getHeader();
|
||||
int timespan = (int) (prev.time().getEpochSecond() - blockIntervalAgo.time().getEpochSecond());
|
||||
long timespan = prev.time().getEpochSecond() - blockIntervalAgo.time().getEpochSecond();
|
||||
// Limit the adjustment step.
|
||||
final int targetTimespan = this.getTargetTimespan();
|
||||
final long targetTimespan = this.getTargetTimespan();
|
||||
if (timespan < targetTimespan / 4)
|
||||
timespan = targetTimespan / 4;
|
||||
if (timespan > targetTimespan * 4)
|
||||
timespan = targetTimespan * 4;
|
||||
|
||||
BigInteger newTarget = ByteUtils.decodeCompactBits(prev.getDifficultyTarget());
|
||||
newTarget = newTarget.multiply(BigInteger.valueOf(timespan));
|
||||
newTarget = newTarget.divide(BigInteger.valueOf(targetTimespan));
|
||||
Difficulty newTarget = prev.difficultyTarget().adjust(
|
||||
Duration.ofSeconds(timespan), Duration.ofSeconds(targetTimespan), this.maxTarget);
|
||||
|
||||
BigInteger maxTarget = this.getMaxTarget();
|
||||
if (newTarget.compareTo(maxTarget) > 0) {
|
||||
log.info("Difficulty hit proof of work limit: {} vs {}",
|
||||
Long.toHexString(ByteUtils.encodeCompactBits(newTarget)),
|
||||
Long.toHexString(ByteUtils.encodeCompactBits(maxTarget)));
|
||||
newTarget = maxTarget;
|
||||
}
|
||||
|
||||
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 = ByteUtils.encodeCompactBits(newTarget);
|
||||
|
||||
if (newTargetCompact != receivedTargetCompact)
|
||||
Difficulty receivedTarget = nextBlock.difficultyTarget();
|
||||
if (!newTarget.equals(receivedTarget))
|
||||
throw new VerificationException("Network provided difficulty bits do not match what was calculated: " +
|
||||
Long.toHexString(newTargetCompact) + " vs " + Long.toHexString(receivedTargetCompact));
|
||||
newTarget + " vs " + receivedTarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package org.bitcoinj.params;
|
||||
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.internal.ByteUtils;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
|
||||
|
@ -41,7 +41,7 @@ public class MainNetParams extends BitcoinNetworkParams {
|
|||
super(BitcoinNetwork.MAINNET);
|
||||
|
||||
targetTimespan = TARGET_TIMESPAN;
|
||||
maxTarget = ByteUtils.decodeCompactBits(Block.STANDARD_MAX_DIFFICULTY_TARGET);
|
||||
maxTarget = Difficulty.STANDARD_MAX_DIFFICULTY_TARGET;
|
||||
|
||||
port = 8333;
|
||||
packetMagic = 0xf9beb4d9;
|
||||
|
@ -134,7 +134,8 @@ public class MainNetParams extends BitcoinNetworkParams {
|
|||
public Block getGenesisBlock() {
|
||||
synchronized (GENESIS_HASH) {
|
||||
if (genesisBlock == null) {
|
||||
genesisBlock = Block.createGenesis(GENESIS_TIME, Block.STANDARD_MAX_DIFFICULTY_TARGET, GENESIS_NONCE);
|
||||
genesisBlock = Block.createGenesis(GENESIS_TIME, Difficulty.STANDARD_MAX_DIFFICULTY_TARGET,
|
||||
GENESIS_NONCE);
|
||||
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () -> "invalid genesis hash");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package org.bitcoinj.params;
|
||||
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.internal.ByteUtils;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
|
||||
|
@ -38,7 +38,7 @@ public class RegTestParams extends BitcoinNetworkParams {
|
|||
super(BitcoinNetwork.REGTEST);
|
||||
|
||||
targetTimespan = TARGET_TIMESPAN;
|
||||
maxTarget = ByteUtils.decodeCompactBits(Block.EASIEST_DIFFICULTY_TARGET);
|
||||
maxTarget = Difficulty.EASIEST_DIFFICULTY_TARGET;
|
||||
// Difficulty adjustments are disabled for regtest.
|
||||
// By setting the block interval for difficulty adjustments to Integer.MAX_VALUE we make sure difficulty never
|
||||
// changes.
|
||||
|
@ -82,7 +82,7 @@ public class RegTestParams extends BitcoinNetworkParams {
|
|||
public Block getGenesisBlock() {
|
||||
synchronized (GENESIS_HASH) {
|
||||
if (genesisBlock == null) {
|
||||
genesisBlock = Block.createGenesis(GENESIS_TIME, Block.EASIEST_DIFFICULTY_TARGET, GENESIS_NONCE);
|
||||
genesisBlock = Block.createGenesis(GENESIS_TIME, Difficulty.EASIEST_DIFFICULTY_TARGET, GENESIS_NONCE);
|
||||
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () ->
|
||||
"invalid genesis hash");
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
package org.bitcoinj.params;
|
||||
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.internal.ByteUtils;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class SigNetParams extends BitcoinNetworkParams {
|
|||
public static final int TESTNET_MAJORITY_WINDOW = 100;
|
||||
public static final int TESTNET_MAJORITY_REJECT_BLOCK_OUTDATED = 75;
|
||||
public static final int TESTNET_MAJORITY_ENFORCE_BLOCK_UPGRADE = 51;
|
||||
private static final long GENESIS_DIFFICULTY = 0x1e0377ae;
|
||||
private static final Difficulty GENESIS_DIFFICULTY = Difficulty.ofCompact(0x1e0377ae);
|
||||
private static final Instant GENESIS_TIME = Instant.ofEpochSecond(1598918400);
|
||||
private static final long GENESIS_NONCE = 52613770;
|
||||
private static final Sha256Hash GENESIS_HASH = Sha256Hash.wrap("00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6");
|
||||
|
@ -43,7 +43,7 @@ public class SigNetParams extends BitcoinNetworkParams {
|
|||
super(BitcoinNetwork.SIGNET);
|
||||
|
||||
targetTimespan = TARGET_TIMESPAN;
|
||||
maxTarget = ByteUtils.decodeCompactBits(Block.EASIEST_DIFFICULTY_TARGET);
|
||||
maxTarget = Difficulty.EASIEST_DIFFICULTY_TARGET;
|
||||
|
||||
port = 38333;
|
||||
packetMagic = 0x0a03cf40;
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
package org.bitcoinj.params;
|
||||
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.internal.ByteUtils;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.core.Block;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
|
@ -27,7 +27,6 @@ import org.bitcoinj.core.VerificationException;
|
|||
import org.bitcoinj.store.BlockStore;
|
||||
import org.bitcoinj.store.BlockStoreException;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.time.Instant;
|
||||
|
||||
import static org.bitcoinj.base.internal.Preconditions.checkState;
|
||||
|
@ -48,7 +47,7 @@ public class TestNet3Params extends BitcoinNetworkParams {
|
|||
super(BitcoinNetwork.TESTNET);
|
||||
|
||||
targetTimespan = TARGET_TIMESPAN;
|
||||
maxTarget = ByteUtils.decodeCompactBits(Block.STANDARD_MAX_DIFFICULTY_TARGET);
|
||||
maxTarget = Difficulty.STANDARD_MAX_DIFFICULTY_TARGET;
|
||||
|
||||
port = 18333;
|
||||
packetMagic = 0x0b110907;
|
||||
|
@ -89,7 +88,8 @@ public class TestNet3Params extends BitcoinNetworkParams {
|
|||
public Block getGenesisBlock() {
|
||||
synchronized (GENESIS_HASH) {
|
||||
if (genesisBlock == null) {
|
||||
genesisBlock = Block.createGenesis(GENESIS_TIME, Block.STANDARD_MAX_DIFFICULTY_TARGET, GENESIS_NONCE);
|
||||
genesisBlock = Block.createGenesis(GENESIS_TIME, Difficulty.STANDARD_MAX_DIFFICULTY_TARGET,
|
||||
GENESIS_NONCE);
|
||||
checkState(genesisBlock.getHash().equals(GENESIS_HASH), () ->
|
||||
"invalid genesis hash");
|
||||
}
|
||||
|
@ -118,14 +118,14 @@ public class TestNet3Params extends BitcoinNetworkParams {
|
|||
StoredBlock cursor = storedPrev;
|
||||
while (!cursor.getHeader().equals(getGenesisBlock()) &&
|
||||
cursor.getHeight() % getInterval() != 0 &&
|
||||
cursor.getHeader().getDifficultyTargetAsInteger().equals(getMaxTarget()))
|
||||
cursor.getHeader().difficultyTarget().equals(maxTarget()))
|
||||
cursor = cursor.getPrev(blockStore);
|
||||
BigInteger cursorTarget = cursor.getHeader().getDifficultyTargetAsInteger();
|
||||
BigInteger newTarget = nextBlock.getDifficultyTargetAsInteger();
|
||||
Difficulty cursorTarget = cursor.getHeader().difficultyTarget();
|
||||
Difficulty newTarget = nextBlock.difficultyTarget();
|
||||
if (!cursorTarget.equals(newTarget))
|
||||
throw new VerificationException("Testnet block transition that is not allowed: " +
|
||||
Long.toHexString(cursor.getHeader().getDifficultyTarget()) + " vs " +
|
||||
Long.toHexString(nextBlock.getDifficultyTarget()));
|
||||
cursorTarget + " vs " +
|
||||
newTarget);
|
||||
}
|
||||
} else {
|
||||
super.checkDifficultyTransitions(storedPrev, nextBlock, blockStore);
|
||||
|
|
|
@ -18,8 +18,8 @@
|
|||
package org.bitcoinj.params;
|
||||
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.internal.TimeUtils;
|
||||
import org.bitcoinj.base.internal.ByteUtils;
|
||||
import org.bitcoinj.core.Block;
|
||||
|
||||
/**
|
||||
|
@ -37,7 +37,7 @@ public class UnitTestParams extends BitcoinNetworkParams {
|
|||
super(BitcoinNetwork.TESTNET);
|
||||
|
||||
targetTimespan = 200000000; // 6 years. Just a very big number.
|
||||
maxTarget = ByteUtils.decodeCompactBits(Block.EASIEST_DIFFICULTY_TARGET);
|
||||
maxTarget = Difficulty.EASIEST_DIFFICULTY_TARGET;
|
||||
interval = 10;
|
||||
subsidyDecreaseBlockCount = 100;
|
||||
|
||||
|
@ -73,7 +73,7 @@ public class UnitTestParams extends BitcoinNetworkParams {
|
|||
public Block getGenesisBlock() {
|
||||
synchronized (this) {
|
||||
if (genesisBlock == null) {
|
||||
genesisBlock = Block.createGenesis(TimeUtils.currentTime(), Block.EASIEST_DIFFICULTY_TARGET);
|
||||
genesisBlock = Block.createGenesis(TimeUtils.currentTime(), Difficulty.EASIEST_DIFFICULTY_TARGET);
|
||||
}
|
||||
}
|
||||
return genesisBlock;
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.bitcoinj.core;
|
|||
import org.bitcoinj.base.Address;
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.Coin;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.ScriptType;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
import org.bitcoinj.base.internal.TimeUtils;
|
||||
|
@ -208,7 +209,7 @@ public class BlockChainTest {
|
|||
Block prev = chain.getChainHead().getHeader();
|
||||
Instant newTime = prev.time().plus(Duration.ofMinutes(10));
|
||||
Block newBlock = prev.createNextBlock(null, 1, newTime, 1);
|
||||
newBlock.setDifficultyTarget(newBlock.getDifficultyTarget() + 10);
|
||||
newBlock.setDifficultyTarget(Difficulty.ofCompact(newBlock.difficultyTarget().compact() + 10));
|
||||
assertTrue(chain.add(newBlock));
|
||||
}
|
||||
|
||||
|
@ -227,7 +228,7 @@ public class BlockChainTest {
|
|||
// We're going to make this block so easy 50% of solutions will pass, and check it gets rejected for having a
|
||||
// bad difficulty target. Unfortunately the encoding mechanism means we cannot make one that accepts all
|
||||
// solutions.
|
||||
bad.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
|
||||
bad.setDifficultyTarget(Difficulty.EASIEST_DIFFICULTY_TARGET);
|
||||
try {
|
||||
testNetChain.add(bad);
|
||||
// The difficulty target above should be rejected on the grounds of being easier than the networks
|
||||
|
@ -418,7 +419,7 @@ public class BlockChainTest {
|
|||
Sha256Hash.wrap("00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206"), // prev
|
||||
Sha256Hash.wrap("20222eb90f5895556926c112bb5aa0df4ab5abc3107e21a6950aec3b2e3541e2"), // merkle
|
||||
Instant.ofEpochSecond(1296688946L),
|
||||
0x1d00ffff,
|
||||
Difficulty.STANDARD_MAX_DIFFICULTY_TARGET,
|
||||
875942400L,
|
||||
null);
|
||||
assertEquals("000000006c02c8ea6e4ff69651f7fcde348fb9d557a06e6957b65552002a7820", b2.getHashAsString());
|
||||
|
@ -431,7 +432,7 @@ public class BlockChainTest {
|
|||
Sha256Hash.wrap("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"), // prev
|
||||
Sha256Hash.wrap("f0315ffc38709d70ad5647e22048358dd3745f3ce3874223c80a7c92fab0c8ba"), // merkle
|
||||
Instant.ofEpochSecond(1296688928),
|
||||
0x1d00ffff,
|
||||
Difficulty.STANDARD_MAX_DIFFICULTY_TARGET,
|
||||
1924588547,
|
||||
null);
|
||||
assertEquals("00000000b873e79784647a6c82962c70d228557d24a747ea4d1b8bbe878e1206", b1.getHashAsString());
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.bitcoinj.core;
|
|||
import com.google.common.io.ByteStreams;
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.Coin;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.ScriptType;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
import org.bitcoinj.base.VarInt;
|
||||
|
@ -91,7 +92,7 @@ public class BlockTest {
|
|||
}
|
||||
|
||||
private static class TweakableTestNet3Params extends TestNet3Params {
|
||||
public void setMaxTarget(BigInteger limit) {
|
||||
public void setMaxTarget(Difficulty limit) {
|
||||
maxTarget = limit;
|
||||
}
|
||||
}
|
||||
|
@ -100,7 +101,7 @@ public class BlockTest {
|
|||
public void testProofOfWork() {
|
||||
// This params accepts any difficulty target.
|
||||
final TweakableTestNet3Params TWEAK_TESTNET = new TweakableTestNet3Params();
|
||||
TWEAK_TESTNET.setMaxTarget(ByteUtils.decodeCompactBits(Block.EASIEST_DIFFICULTY_TARGET));
|
||||
TWEAK_TESTNET.setMaxTarget(Difficulty.EASIEST_DIFFICULTY_TARGET);
|
||||
Block block = TWEAK_TESTNET.getDefaultSerializer().makeBlock(ByteBuffer.wrap(block700000Bytes));
|
||||
block.setNonce(12346);
|
||||
try {
|
||||
|
@ -111,7 +112,7 @@ public class BlockTest {
|
|||
}
|
||||
// Blocks contain their own difficulty target. The BlockChain verification mechanism is what stops real blocks
|
||||
// from containing artificially weak difficulties.
|
||||
block.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET);
|
||||
block.setDifficultyTarget(Difficulty.EASIEST_DIFFICULTY_TARGET);
|
||||
// Now it should pass.
|
||||
Block.verify(TWEAK_TESTNET, block, Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(Block.VerifyFlag.class));
|
||||
// Break the nonce again at the lower difficulty level so we can try solving for it.
|
||||
|
@ -312,15 +313,15 @@ public class BlockTest {
|
|||
@Test
|
||||
public void parseBlockWithHugeDeclaredTransactionsSize() {
|
||||
Context.propagate(new Context(100, Transaction.DEFAULT_TX_FEE, false, true));
|
||||
Block block = new Block(1, Sha256Hash.ZERO_HASH, Sha256Hash.ZERO_HASH, Instant.ofEpochSecond(1), 1, 1,
|
||||
new ArrayList<Transaction>()) {
|
||||
Block block = new Block(1, Sha256Hash.ZERO_HASH, Sha256Hash.ZERO_HASH, Instant.ofEpochSecond(1),
|
||||
Difficulty.EASIEST_DIFFICULTY_TARGET, 1, new ArrayList<Transaction>()) {
|
||||
@Override
|
||||
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException {
|
||||
ByteUtils.writeInt32LE(getVersion(), stream);
|
||||
stream.write(getPrevBlockHash().serialize());
|
||||
stream.write(getMerkleRoot().serialize());
|
||||
ByteUtils.writeInt32LE(time().getEpochSecond(), stream);
|
||||
ByteUtils.writeInt32LE(getDifficultyTarget(), stream);
|
||||
ByteUtils.writeInt32LE(difficultyTarget().compact(), stream);
|
||||
ByteUtils.writeInt32LE(getNonce(), stream);
|
||||
|
||||
stream.write(VarInt.of(Integer.MAX_VALUE).serialize());
|
||||
|
@ -338,7 +339,7 @@ public class BlockTest {
|
|||
@Test
|
||||
public void testGenesisBlock() {
|
||||
Block genesisBlock = Block.createGenesis(Instant.ofEpochSecond(1231006505L),
|
||||
0x1d00ffffL,
|
||||
Difficulty.ofCompact(0x1d00ffff),
|
||||
2083236893);
|
||||
assertEquals(Sha256Hash.wrap("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"), genesisBlock.getHash());
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.bitcoinj.core;
|
||||
|
||||
import org.bitcoinj.base.Coin;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.Sha256Hash;
|
||||
import org.bitcoinj.base.VarInt;
|
||||
import org.bitcoinj.base.internal.TimeUtils;
|
||||
|
@ -903,7 +904,7 @@ public class FullBlockTestGenerator {
|
|||
Block b44 = new Block(Block.BLOCK_VERSION_GENESIS);
|
||||
byte[] outScriptBytes = ScriptBuilder.createP2PKOutputScript(ECKey.fromPublicOnly(coinbaseOutKeyPubKey)).program();
|
||||
{
|
||||
b44.setDifficultyTarget(b43.block.getDifficultyTarget());
|
||||
b44.setDifficultyTarget(b43.block.difficultyTarget());
|
||||
b44.addCoinbaseTransaction(coinbaseOutKeyPubKey, ZERO, chainHeadHeight + 15);
|
||||
|
||||
Transaction t = new Transaction();
|
||||
|
@ -926,7 +927,7 @@ public class FullBlockTestGenerator {
|
|||
// A block with a non-coinbase as the first tx
|
||||
Block b45 = new Block(Block.BLOCK_VERSION_GENESIS);
|
||||
{
|
||||
b45.setDifficultyTarget(b44.getDifficultyTarget());
|
||||
b45.setDifficultyTarget(b44.difficultyTarget());
|
||||
//b45.addCoinbaseTransaction(pubKey, coinbaseValue);
|
||||
|
||||
Transaction t = new Transaction();
|
||||
|
@ -953,7 +954,7 @@ public class FullBlockTestGenerator {
|
|||
Block b46 = new Block(Block.BLOCK_VERSION_GENESIS);
|
||||
{
|
||||
b46.transactions = new ArrayList<>();
|
||||
b46.setDifficultyTarget(b44.getDifficultyTarget());
|
||||
b46.setDifficultyTarget(b44.difficultyTarget());
|
||||
b46.setMerkleRoot(Sha256Hash.ZERO_HASH);
|
||||
|
||||
b46.setPrevBlockHash(b44.getHash());
|
||||
|
@ -967,10 +968,9 @@ public class FullBlockTestGenerator {
|
|||
{
|
||||
try {
|
||||
// Inverse solve
|
||||
BigInteger target = b47.block.getDifficultyTargetAsInteger();
|
||||
Difficulty target = b47.block.difficultyTarget();
|
||||
while (true) {
|
||||
BigInteger h = b47.getHash().toBigInteger();
|
||||
if (h.compareTo(target) > 0) // if invalid
|
||||
if (!target.isMetByWork(b47.getHash()))
|
||||
break;
|
||||
// increment the nonce and try again.
|
||||
b47.block.setNonce(b47.block.getNonce() + 1);
|
||||
|
@ -998,9 +998,9 @@ public class FullBlockTestGenerator {
|
|||
// Block with incorrect POW limit
|
||||
NewBlock b50 = createNextBlock(b44, chainHeadHeight + 16, out15, null);
|
||||
{
|
||||
long diffTarget = b44.getDifficultyTarget();
|
||||
diffTarget &= 0xFFBFFFFF; // Make difficulty one bit harder
|
||||
b50.block.setDifficultyTarget(diffTarget);
|
||||
Difficulty target = b44.difficultyTarget();
|
||||
target = Difficulty.ofCompact(target.compact() & 0xFFBFFFFF); // Make difficulty one bit harder
|
||||
b50.block.setDifficultyTarget(target);
|
||||
}
|
||||
b50.solve();
|
||||
blocks.add(new BlockAndValidity(b50, false, true, b44.getHash(), chainHeadHeight + 15, "b50"));
|
||||
|
|
|
@ -177,7 +177,7 @@ public class ParseByteCacheTest {
|
|||
bRef = (Block) serializerRef.deserialize(ByteBuffer.wrap(blockBytes));
|
||||
|
||||
// retrieve a value from header
|
||||
b1.getDifficultyTarget();
|
||||
b1.difficultyTarget();
|
||||
|
||||
// does it still match ref block?
|
||||
serDeser(serializer, b1, bos.toByteArray(), null, null);
|
||||
|
@ -187,7 +187,7 @@ public class ParseByteCacheTest {
|
|||
bRef = (Block) serializerRef.deserialize(ByteBuffer.wrap(blockBytes));
|
||||
|
||||
// retrieve a value from a child and header
|
||||
b1.getDifficultyTarget();
|
||||
b1.difficultyTarget();
|
||||
|
||||
b1.getTransactions();
|
||||
if (b1.getTransactions().size() > 0) {
|
||||
|
|
|
@ -18,6 +18,7 @@ package org.bitcoinj.core;
|
|||
|
||||
import junitparams.JUnitParamsRunner;
|
||||
import junitparams.Parameters;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
@ -43,7 +44,7 @@ public class StoredBlockTest {
|
|||
private static final BigInteger TOO_LARGE_WORK_V2 = new BigInteger(/* 33 bytes */
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 16);
|
||||
// Just an arbitrary block
|
||||
private static final Block BLOCK = Block.createGenesis(Instant.now(), Block.EASIEST_DIFFICULTY_TARGET);
|
||||
private static final Block BLOCK = Block.createGenesis(Instant.now(), Difficulty.EASIEST_DIFFICULTY_TARGET);
|
||||
|
||||
private Object[] vectors_serializeCompact_pass() {
|
||||
return new Object[] {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.bitcoinj.store;
|
||||
|
||||
import org.bitcoinj.base.BitcoinNetwork;
|
||||
import org.bitcoinj.base.Difficulty;
|
||||
import org.bitcoinj.base.ScriptType;
|
||||
import org.bitcoinj.base.Address;
|
||||
import org.bitcoinj.base.internal.PlatformUtils;
|
||||
|
@ -162,8 +163,8 @@ public class SPVBlockStoreTest {
|
|||
Stopwatch watch = Stopwatch.start();
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
// Using i as the nonce so that the block hashes are different.
|
||||
Block block = new Block(0, Sha256Hash.ZERO_HASH, Sha256Hash.ZERO_HASH, Instant.EPOCH, 0, i,
|
||||
Collections.emptyList());
|
||||
Block block = new Block(0, Sha256Hash.ZERO_HASH, Sha256Hash.ZERO_HASH, Instant.EPOCH,
|
||||
Difficulty.EASIEST_DIFFICULTY_TARGET, i, Collections.emptyList());
|
||||
StoredBlock b = new StoredBlock(block, BigInteger.ZERO, i);
|
||||
store.put(b);
|
||||
store.setChainHead(b);
|
||||
|
|
Loading…
Add table
Reference in a new issue