BlockChainTest: replace difficultyTransitions() by five individual tests

These tests use `MainNetParams` and `SigNetParams`, but not `UnitTestParams`.
This commit is contained in:
Andreas Schildbach 2023-04-02 13:14:17 +02:00
parent c1e83e53c4
commit ce10061510

View File

@ -25,8 +25,8 @@ import org.bitcoinj.base.Sha256Hash;
import org.bitcoinj.base.internal.TimeUtils; import org.bitcoinj.base.internal.TimeUtils;
import org.bitcoinj.crypto.ECKey; import org.bitcoinj.crypto.ECKey;
import org.bitcoinj.params.MainNetParams; import org.bitcoinj.params.MainNetParams;
import org.bitcoinj.params.SigNetParams;
import org.bitcoinj.params.TestNet3Params; import org.bitcoinj.params.TestNet3Params;
import org.bitcoinj.params.UnitTestParams;
import org.bitcoinj.store.BlockStore; import org.bitcoinj.store.BlockStore;
import org.bitcoinj.store.MemoryBlockStore; import org.bitcoinj.store.MemoryBlockStore;
import org.bitcoinj.testing.FakeTxBuilder; import org.bitcoinj.testing.FakeTxBuilder;
@ -69,7 +69,9 @@ public class BlockChainTest {
private BlockChain testNetChain; private BlockChain testNetChain;
private Address coinbaseTo; private Address coinbaseTo;
private static final TestNet3Params TESTNET = TestNet3Params.get(); private static final NetworkParameters TESTNET = TestNet3Params.get();
private static final NetworkParameters SIGNET = SigNetParams.get();
private static final NetworkParameters MAINNET = MainNetParams.get();
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
@ -138,37 +140,77 @@ public class BlockChainTest {
assertEquals(testNetChain.getChainHead().getHeader(), b3.cloneAsHeader()); assertEquals(testNetChain.getChainHead().getHeader(), b3.cloneAsHeader());
} }
@Test // adds 2015 (interval-1) intermediate blocks between the transition points
public void difficultyTransitions() throws Exception { private static void addIntermediteBlocks(BlockChain chain, int epoch, Duration spacing) throws PrunedException {
NetworkParameters UNITTEST = UnitTestParams.get(); int interval = chain.params.interval;
BlockChain unitTestChain = new BlockChain(UNITTEST, Block prev = chain.getChainHead().getHeader();
Wallet.createDeterministic(UNITTEST, ScriptType.P2PKH), // there is an additional spacing here, to account for the fact that for the difficulty adjustment only
new MemoryBlockStore(UNITTEST.getGenesisBlock())); // interval minus 1 blocks are taken into account
Instant newTime = prev.time().plus(spacing);
// Add a bunch of blocks in a loop until we reach a difficulty transition point. The unit test params have an for (int i = 1; i < interval; i++) {
// artificially shortened period. newTime = newTime.plus(spacing);
Block prev = UNITTEST.getGenesisBlock(); Block newBlock = prev.createNextBlock(null, 1, newTime, epoch * interval + i);
TimeUtils.setMockClock(); assertTrue(chain.add(newBlock));
for (int height = 0; height < UNITTEST.getInterval() - 1; height++) {
Block newBlock = prev.createNextBlock(coinbaseTo, 1, TimeUtils.currentTime(), height);
assertTrue(unitTestChain.add(newBlock));
prev = newBlock; prev = newBlock;
// The fake chain should seem to be "fast" for the purposes of difficulty calculations.
TimeUtils.rollMockClock(Duration.ofSeconds(2));
} }
// Now add another block that has no difficulty adjustment, it should be rejected. }
try {
unitTestChain.add(prev.createNextBlock(coinbaseTo, 1, TimeUtils.currentTime(), UNITTEST.getInterval())); private static void addTransitionBlock(BlockChain chain, int epoch, Duration spacing) throws PrunedException {
fail(); int interval = chain.params.interval;
} catch (VerificationException e) { Block prev = chain.getChainHead().getHeader();
} Instant newTime = prev.time().plus(spacing);
// Create a new block with the right difficulty target given our blistering speed relative to the huge amount Block newBlock = prev.createNextBlock(null, 1, newTime, epoch * interval);
// of time it's supposed to take (set in the unit test network parameters). assertTrue(chain.add(newBlock));
Block b = prev.createNextBlock(coinbaseTo, 1, TimeUtils.currentTime(), UNITTEST.getInterval() + 1); }
b.setDifficultyTarget(0x201fFFFFL);
b.solve(); @Test
assertTrue(unitTestChain.add(b)); public void difficultyTransitions_perfectSpacing() throws Exception {
// Successfully traversed a difficulty transition period. Context.propagate(new Context(100, Coin.ZERO, false, true));
BlockChain chain = new BlockChain(MAINNET, new MemoryBlockStore(MAINNET.getGenesisBlock()));
// genesis block is already there
addIntermediteBlocks(chain, 0, Duration.ofMinutes(10));
addTransitionBlock(chain, 1, Duration.ofMinutes(10));
}
@Test(expected = VerificationException.class)
public void difficultyTransitions_tooQuick() throws Exception {
Context.propagate(new Context(100, Coin.ZERO, false, true));
BlockChain chain = new BlockChain(MAINNET, new MemoryBlockStore(MAINNET.getGenesisBlock()));
// genesis block is already there
addIntermediteBlocks(chain, 0, Duration.ofMinutes(10).minusSeconds(1));
addTransitionBlock(chain, 1, Duration.ofMinutes(10).minusSeconds(1));
}
@Test(expected = VerificationException.class)
public void difficultyTransitions_tooSlow() throws Exception {
// we're using signet because it's not at max target from the start
Context.propagate(new Context(100, Coin.ZERO, false, true));
BlockChain chain = new BlockChain(SIGNET, new MemoryBlockStore(SIGNET.getGenesisBlock()));
// genesis block is already there
addIntermediteBlocks(chain, 0, Duration.ofMinutes(10).plusSeconds(1));
addTransitionBlock(chain, 1, Duration.ofMinutes(10).plusSeconds(1));
}
@Test
public void difficultyTransitions_tooSlow_butIsAtMax() throws Exception {
Context.propagate(new Context(100, Coin.ZERO, false, true));
BlockChain chain = new BlockChain(MAINNET, new MemoryBlockStore(MAINNET.getGenesisBlock()));
// genesis block is already there
addIntermediteBlocks(chain, 0, Duration.ofMinutes(20));
// we can add the transition block with the old target, becuase it is already at the maximum (genesis block)
addTransitionBlock(chain, 1, Duration.ofMinutes(20));
}
@Test(expected = VerificationException.class)
public void difficultyTransitions_unexpectedChange() throws Exception {
Context.propagate(new Context(100, Coin.ZERO, false, true));
BlockChain chain = new BlockChain(MAINNET, new MemoryBlockStore(MAINNET.getGenesisBlock()));
// genesis block is already there
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);
assertTrue(chain.add(newBlock));
} }
private static class TweakableTestNet3Params extends TestNet3Params { private static class TweakableTestNet3Params extends TestNet3Params {
@ -420,7 +462,6 @@ public class BlockChainTest {
@Test @Test
public void estimatedBlockTime() throws Exception { public void estimatedBlockTime() throws Exception {
NetworkParameters MAINNET = MainNetParams.get();
BlockChain prod = new BlockChain(MAINNET, new MemoryBlockStore(MAINNET.getGenesisBlock())); BlockChain prod = new BlockChain(MAINNET, new MemoryBlockStore(MAINNET.getGenesisBlock()));
Instant t = prod.estimateBlockTimeInstant(200000); Instant t = prod.estimateBlockTimeInstant(200000);
// The actual date of block 200,000 was 2012-09-22 10:47:00 // The actual date of block 200,000 was 2012-09-22 10:47:00