diff --git a/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java b/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java index 0ddbe8596..f77d83442 100644 --- a/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java +++ b/core/src/main/java/org/bitcoinj/core/AbstractBlockChain.java @@ -544,12 +544,13 @@ public abstract class AbstractBlockChain { if (expensiveChecks && block.getTimeSeconds() <= getMedianTimestampOfRecentBlocks(head, blockStore)) 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 // 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. - if (block.getVersion() == Block.BLOCK_VERSION_BIP34) { - final Integer count = versionTally.getCountAtOrAbove(Block.BLOCK_VERSION_BIP66); + // stopping addition of new v2/3 blocks to the tip of the chain. + if (block.getVersion() == Block.BLOCK_VERSION_BIP34 + || block.getVersion() == Block.BLOCK_VERSION_BIP66) { + final Integer count = versionTally.getCountAtOrAbove(block.getVersion() + 1); if (count != null && count >= params.getMajorityRejectBlockOutdated()) { throw new VerificationException.BlockVersionOutOfDate(block.getVersion()); diff --git a/core/src/main/java/org/bitcoinj/core/Block.java b/core/src/main/java/org/bitcoinj/core/Block.java index 8a4b7c265..49c57c97e 100644 --- a/core/src/main/java/org/bitcoinj/core/Block.java +++ b/core/src/main/java/org/bitcoinj/core/Block.java @@ -84,6 +84,8 @@ public class Block extends Message { public static final long BLOCK_VERSION_BIP34 = 2; /** Block version introduced in BIP 66: Strict DER signatures */ 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. private long version; diff --git a/core/src/test/java/org/bitcoinj/core/BlockChainTest.java b/core/src/test/java/org/bitcoinj/core/BlockChainTest.java index 6d08aaa48..93322a02c 100644 --- a/core/src/test/java/org/bitcoinj/core/BlockChainTest.java +++ b/core/src/test/java/org/bitcoinj/core/BlockChainTest.java @@ -38,6 +38,7 @@ import java.util.Date; import java.util.Locale; import static org.bitcoinj.core.Coin.*; +import org.bitcoinj.store.BlockStoreException; import static org.bitcoinj.testing.FakeTxBuilder.createFakeBlock; import static org.bitcoinj.testing.FakeTxBuilder.createFakeTx; import static org.junit.Assert.*; @@ -230,6 +231,20 @@ public class BlockChainTest { */ @Test 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 BlockChain versionChain = new BlockChain(unitTestParams, versionBlockStore); @@ -240,18 +255,18 @@ public class BlockChainTest { // Put in just enough v2 blocks to be a minority 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); timeSeconds += 60; } // Fill the rest of the window with v3 blocks 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); 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 thrown.expect(VerificationException.BlockVersionOutOfDate.class); try {