Enforce v4 block switchover

This enforces the switch over to block v4 once a supermajority is met, as
per BIP65.
This commit is contained in:
Ross Nicoll 2015-10-27 21:26:48 +00:00 committed by Andreas Schildbach
parent 1c8a60d2ef
commit 344c4c3baa
3 changed files with 25 additions and 7 deletions

View file

@ -544,12 +544,13 @@ public abstract class AbstractBlockChain {
if (expensiveChecks && block.getTimeSeconds() <= getMedianTimestampOfRecentBlocks(head, blockStore)) if (expensiveChecks && block.getTimeSeconds() <= getMedianTimestampOfRecentBlocks(head, blockStore))
throw new VerificationException("Block's timestamp is too early"); throw new VerificationException("Block's timestamp is too early");
// BIP 66: Enforce block version 3 once it's a supermajority of blocks // BIP 66 & 65: Enforce block version 3/4 once they are a supermajority of blocks
// NOTE: This requires 1,000 blocks since the last checkpoint (on main // NOTE: This requires 1,000 blocks since the last checkpoint (on main
// net, less on test) in order to be applied. It is also limited to // net, less on test) in order to be applied. It is also limited to
// stopping addition of new v2 blocks to the tip of the chain. // stopping addition of new v2/3 blocks to the tip of the chain.
if (block.getVersion() == Block.BLOCK_VERSION_BIP34) { if (block.getVersion() == Block.BLOCK_VERSION_BIP34
final Integer count = versionTally.getCountAtOrAbove(Block.BLOCK_VERSION_BIP66); || block.getVersion() == Block.BLOCK_VERSION_BIP66) {
final Integer count = versionTally.getCountAtOrAbove(block.getVersion() + 1);
if (count != null if (count != null
&& count >= params.getMajorityRejectBlockOutdated()) { && count >= params.getMajorityRejectBlockOutdated()) {
throw new VerificationException.BlockVersionOutOfDate(block.getVersion()); throw new VerificationException.BlockVersionOutOfDate(block.getVersion());

View file

@ -84,6 +84,8 @@ public class Block extends Message {
public static final long BLOCK_VERSION_BIP34 = 2; public static final long BLOCK_VERSION_BIP34 = 2;
/** Block version introduced in BIP 66: Strict DER signatures */ /** Block version introduced in BIP 66: Strict DER signatures */
public static final long BLOCK_VERSION_BIP66 = 3; public static final long BLOCK_VERSION_BIP66 = 3;
/** Block version introduced in BIP 65: OP_CHECKLOCKTIMEVERIFY */
public static final long BLOCK_VERSION_BIP65 = 4;
// Fields defined as part of the protocol format. // Fields defined as part of the protocol format.
private long version; private long version;

View file

@ -38,6 +38,7 @@ import java.util.Date;
import java.util.Locale; import java.util.Locale;
import static org.bitcoinj.core.Coin.*; import static org.bitcoinj.core.Coin.*;
import org.bitcoinj.store.BlockStoreException;
import static org.bitcoinj.testing.FakeTxBuilder.createFakeBlock; import static org.bitcoinj.testing.FakeTxBuilder.createFakeBlock;
import static org.bitcoinj.testing.FakeTxBuilder.createFakeTx; import static org.bitcoinj.testing.FakeTxBuilder.createFakeTx;
import static org.junit.Assert.*; import static org.junit.Assert.*;
@ -230,6 +231,20 @@ public class BlockChainTest {
*/ */
@Test @Test
public void badBip66Version() throws Exception { public void badBip66Version() throws Exception {
testDeprecatedBlockVersion(Block.BLOCK_VERSION_BIP34, Block.BLOCK_VERSION_BIP66);
}
/**
* Test that version 3 blocks are rejected once version 4 blocks are a super
* majority.
*/
@Test
public void badBip65Version() throws Exception {
testDeprecatedBlockVersion(Block.BLOCK_VERSION_BIP66, Block.BLOCK_VERSION_BIP65);
}
private void testDeprecatedBlockVersion(final long deprecatedVersion, final long newVersion)
throws Exception {
final BlockStore versionBlockStore = new MemoryBlockStore(unitTestParams); final BlockStore versionBlockStore = new MemoryBlockStore(unitTestParams);
final BlockChain versionChain = new BlockChain(unitTestParams, versionBlockStore); final BlockChain versionChain = new BlockChain(unitTestParams, versionBlockStore);
@ -240,18 +255,18 @@ public class BlockChainTest {
// Put in just enough v2 blocks to be a minority // Put in just enough v2 blocks to be a minority
for (height = 0; height < (unitTestParams.getMajorityWindow() - unitTestParams.getMajorityRejectBlockOutdated()); height++) { for (height = 0; height < (unitTestParams.getMajorityWindow() - unitTestParams.getMajorityRejectBlockOutdated()); height++) {
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP34, timeSeconds, height); chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, deprecatedVersion, timeSeconds, height);
versionChain.add(chainHead.block); versionChain.add(chainHead.block);
timeSeconds += 60; timeSeconds += 60;
} }
// Fill the rest of the window with v3 blocks // Fill the rest of the window with v3 blocks
for (; height < unitTestParams.getMajorityWindow(); height++) { for (; height < unitTestParams.getMajorityWindow(); height++) {
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP66, timeSeconds, height); chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, newVersion, timeSeconds, height);
versionChain.add(chainHead.block); versionChain.add(chainHead.block);
timeSeconds += 60; timeSeconds += 60;
} }
chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, Block.BLOCK_VERSION_BIP34, timeSeconds, height); chainHead = FakeTxBuilder.createFakeBlock(versionBlockStore, deprecatedVersion, timeSeconds, height);
// Trying to add a new v2 block should result in rejection // Trying to add a new v2 block should result in rejection
thrown.expect(VerificationException.BlockVersionOutOfDate.class); thrown.expect(VerificationException.BlockVersionOutOfDate.class);
try { try {