├── FullBlockTestGenerator.java ├── README.txt └── pull-tests-f56eec3.jar /FullBlockTestGenerator.java: -------------------------------------------------------------------------------- 1 | package org.bitcoinj.core; 2 | 3 | import org.bitcoinj.core.Transaction.SigHash; 4 | import org.bitcoinj.crypto.TransactionSignature; 5 | import org.bitcoinj.script.Script; 6 | import org.bitcoinj.script.ScriptBuilder; 7 | import com.google.common.base.Preconditions; 8 | 9 | import javax.annotation.Nullable; 10 | import java.io.ByteArrayOutputStream; 11 | import java.io.File; 12 | import java.io.FileOutputStream; 13 | import java.io.IOException; 14 | import java.math.BigInteger; 15 | import java.util.*; 16 | 17 | import static org.bitcoinj.core.Coin.*; 18 | import static org.bitcoinj.script.ScriptOpCodes.*; 19 | import static com.google.common.base.Preconditions.checkNotNull; 20 | import static com.google.common.base.Preconditions.checkState; 21 | 22 | /** 23 | * YOU ARE READING THIS CODE BECAUSE EITHER... 24 | * 25 | * a) You are testing an alternative implementation with full validation rules. If you are doing this, you should go 26 | * rethink your life. Seriously, why are you reimplementing Bitcoin consensus rules? Instead, go work on making 27 | * Bitcoin Core consensus rules a shared library and use that. Seriously, you wont get it right, and starting with 28 | * this tester as a way to try to do so will simply end in pain and lost coins. SERIOUSLY, JUST STOP! 29 | * 30 | * b) Bitcoin Core is failing some test in here and you're wondering what test is causing failure. Just stop. There is no 31 | * hope trying to read this file and decipher it. Give up and ping BlueMatt. Seriously, this stuff is a huge mess. 32 | * 33 | * c) You are trying to add a new test. STOP! WHY THE HELL WOULD YOU EVEN DO THAT? GO REWRITE THIS TESTER! 34 | * 35 | * d) You are BlueMatt and you're trying to hack more crap onto this multi-headed lopsided Proof Of Stake. Why are you 36 | * doing this? Seriously, why have you not rewritten this thing yet? WTF man... 37 | * 38 | * IN ANY CASE, STOP READING NOW. IT WILL SAVE YOU MUCH PAIN AND MISERY LATER 39 | */ 40 | 41 | class NewBlock { 42 | public Block block; 43 | private TransactionOutPointWithValue spendableOutput; 44 | public NewBlock(Block block, TransactionOutPointWithValue spendableOutput) { 45 | this.block = block; this.spendableOutput = spendableOutput; 46 | } 47 | // Wrappers to make it more block-like 48 | public Sha256Hash getHash() { return block.getHash(); } 49 | public void solve() { block.solve(); } 50 | public void addTransaction(Transaction tx) { block.addTransaction(tx); } 51 | 52 | public TransactionOutPointWithValue getCoinbaseOutput() { 53 | return new TransactionOutPointWithValue(block.getTransactions().get(0), 0); 54 | } 55 | 56 | public TransactionOutPointWithValue getSpendableOutput() { 57 | return spendableOutput; 58 | } 59 | } 60 | 61 | class TransactionOutPointWithValue { 62 | public TransactionOutPoint outpoint; 63 | public Coin value; 64 | public Script scriptPubKey; 65 | 66 | public TransactionOutPointWithValue(TransactionOutPoint outpoint, Coin value, Script scriptPubKey) { 67 | this.outpoint = outpoint; 68 | this.value = value; 69 | this.scriptPubKey = scriptPubKey; 70 | } 71 | 72 | public TransactionOutPointWithValue(Transaction tx, int output) { 73 | this(new TransactionOutPoint(tx.getParams(), output, tx.getHash()), 74 | tx.getOutput(output).getValue(), tx.getOutput(output).getScriptPubKey()); 75 | } 76 | } 77 | 78 | /** An arbitrary rule which the testing client must match */ 79 | class Rule { 80 | String ruleName; 81 | Rule(String ruleName) { 82 | this.ruleName = ruleName; 83 | } 84 | } 85 | 86 | /** 87 | * A test which checks the mempool state (ie defined which transactions should be in memory pool 88 | */ 89 | class MemoryPoolState extends Rule { 90 | Set mempool; 91 | public MemoryPoolState(Set mempool, String ruleName) { 92 | super(ruleName); 93 | this.mempool = mempool; 94 | } 95 | } 96 | 97 | class RuleList { 98 | public List list; 99 | public int maximumReorgBlockCount; 100 | Map hashHeaderMap; 101 | public RuleList(List list, Map hashHeaderMap, int maximumReorgBlockCount) { 102 | this.list = list; 103 | this.hashHeaderMap = hashHeaderMap; 104 | this.maximumReorgBlockCount = maximumReorgBlockCount; 105 | } 106 | } 107 | 108 | public class FullBlockTestGenerator { 109 | // Used by BitcoindComparisonTool and AbstractFullPrunedBlockChainTest to create test cases 110 | private NetworkParameters params; 111 | private ECKey coinbaseOutKey; 112 | private byte[] coinbaseOutKeyPubKey; 113 | 114 | // Used to double-check that we are always using the right next-height 115 | private Map blockToHeightMap = new HashMap(); 116 | 117 | private Map hashHeaderMap = new HashMap(); 118 | private Map coinbaseBlockMap = new HashMap(); 119 | 120 | public FullBlockTestGenerator(NetworkParameters params) { 121 | this.params = params; 122 | coinbaseOutKey = new ECKey(); 123 | coinbaseOutKeyPubKey = coinbaseOutKey.getPubKey(); 124 | Utils.setMockClock(); 125 | } 126 | 127 | public RuleList getBlocksToTest(boolean runBarelyExpensiveTests, boolean runExpensiveTests, File blockStorageFile) throws ScriptException, ProtocolException, IOException { 128 | final FileOutputStream outStream = blockStorageFile != null ? new FileOutputStream(blockStorageFile) : null; 129 | 130 | final Script OP_TRUE_SCRIPT = new ScriptBuilder().op(OP_TRUE).build(); 131 | final Script OP_NOP_SCRIPT = new ScriptBuilder().op(OP_NOP).build(); 132 | 133 | // TODO: Rename this variable. 134 | List blocks = new LinkedList() { 135 | @Override 136 | public boolean add(Rule element) { 137 | if (outStream != null && element instanceof BlockAndValidity) { 138 | try { 139 | outStream.write((int) (params.getPacketMagic() >>> 24)); 140 | outStream.write((int) (params.getPacketMagic() >>> 16)); 141 | outStream.write((int) (params.getPacketMagic() >>> 8)); 142 | outStream.write((int) (params.getPacketMagic() >>> 0)); 143 | byte[] block = ((BlockAndValidity)element).block.bitcoinSerialize(); 144 | byte[] length = new byte[4]; 145 | Utils.uint32ToByteArrayBE(block.length, length, 0); 146 | outStream.write(Utils.reverseBytes(length)); 147 | outStream.write(block); 148 | ((BlockAndValidity)element).block = null; 149 | } catch (IOException e) { 150 | throw new RuntimeException(e); 151 | } 152 | } 153 | return super.add(element); 154 | } 155 | }; 156 | RuleList ret = new RuleList(blocks, hashHeaderMap, 10); 157 | 158 | Queue spendableOutputs = new LinkedList(); 159 | 160 | int chainHeadHeight = 1; 161 | Block chainHead = params.getGenesisBlock().createNextBlockWithCoinbase(coinbaseOutKeyPubKey); 162 | blocks.add(new BlockAndValidity(chainHead, true, false, chainHead.getHash(), 1, "Initial Block")); 163 | spendableOutputs.offer(new TransactionOutPointWithValue( 164 | new TransactionOutPoint(params, 0, chainHead.getTransactions().get(0).getHash()), 165 | FIFTY_COINS, chainHead.getTransactions().get(0).getOutputs().get(0).getScriptPubKey())); 166 | for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) { 167 | chainHead = chainHead.createNextBlockWithCoinbase(coinbaseOutKeyPubKey); 168 | chainHeadHeight++; 169 | blocks.add(new BlockAndValidity(chainHead, true, false, chainHead.getHash(), i+1, "Initial Block chain output generation")); 170 | spendableOutputs.offer(new TransactionOutPointWithValue( 171 | new TransactionOutPoint(params, 0, chainHead.getTransactions().get(0).getHash()), 172 | FIFTY_COINS, chainHead.getTransactions().get(0).getOutputs().get(0).getScriptPubKey())); 173 | } 174 | 175 | // Start by building a couple of blocks on top of the genesis block. 176 | NewBlock b1 = createNextBlock(chainHead, chainHeadHeight + 1, spendableOutputs.poll(), null); 177 | blocks.add(new BlockAndValidity(b1, true, false, b1.getHash(), chainHeadHeight + 1, "b1")); 178 | spendableOutputs.offer(b1.getCoinbaseOutput()); 179 | 180 | TransactionOutPointWithValue out1 = spendableOutputs.poll(); checkState(out1 != null); 181 | NewBlock b2 = createNextBlock(b1, chainHeadHeight + 2, out1, null); 182 | blocks.add(new BlockAndValidity(b2, true, false, b2.getHash(), chainHeadHeight + 2, "b2")); 183 | // Make sure nothing funky happens if we try to re-add b2 184 | blocks.add(new BlockAndValidity(b2, true, false, b2.getHash(), chainHeadHeight + 2, "b2")); 185 | spendableOutputs.offer(b2.getCoinbaseOutput()); 186 | // We now have the following chain (which output is spent is in parentheses): 187 | // genesis -> b1 (0) -> b2 (1) 188 | // 189 | // so fork like this: 190 | // 191 | // genesis -> b1 (0) -> b2 (1) 192 | // \-> b3 (1) 193 | // 194 | // Nothing should happen at this point. We saw b2 first so it takes priority. 195 | NewBlock b3 = createNextBlock(b1, chainHeadHeight + 2, out1, null); 196 | blocks.add(new BlockAndValidity(b3, true, false, b2.getHash(), chainHeadHeight + 2, "b3")); 197 | // Make sure nothing breaks if we add b3 twice 198 | blocks.add(new BlockAndValidity(b3, true, false, b2.getHash(), chainHeadHeight + 2, "b3")); 199 | 200 | // Now we add another block to make the alternative chain longer. 201 | // 202 | // genesis -> b1 (0) -> b2 (1) 203 | // \-> b3 (1) -> b4 (2) 204 | // 205 | TransactionOutPointWithValue out2 = checkNotNull(spendableOutputs.poll()); 206 | NewBlock b4 = createNextBlock(b3, chainHeadHeight + 3, out2, null); 207 | blocks.add(new BlockAndValidity(b4, true, false, b4.getHash(), chainHeadHeight + 3, "b4")); 208 | 209 | // ... and back to the first chain. 210 | NewBlock b5 = createNextBlock(b2, chainHeadHeight + 3, out2, null); 211 | blocks.add(new BlockAndValidity(b5, true, false, b4.getHash(), chainHeadHeight + 3, "b5")); 212 | spendableOutputs.offer(b5.getCoinbaseOutput()); 213 | 214 | TransactionOutPointWithValue out3 = spendableOutputs.poll(); 215 | 216 | NewBlock b6 = createNextBlock(b5, chainHeadHeight + 4, out3, null); 217 | blocks.add(new BlockAndValidity(b6, true, false, b6.getHash(), chainHeadHeight + 4, "b6")); 218 | // 219 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 220 | // \-> b3 (1) -> b4 (2) 221 | // 222 | 223 | // Try to create a fork that double-spends 224 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 225 | // \-> b7 (2) -> b8 (4) 226 | // \-> b3 (1) -> b4 (2) 227 | // 228 | NewBlock b7 = createNextBlock(b5, chainHeadHeight + 5, out2, null); 229 | blocks.add(new BlockAndValidity(b7, true, false, b6.getHash(), chainHeadHeight + 4, "b7")); 230 | 231 | TransactionOutPointWithValue out4 = spendableOutputs.poll(); 232 | 233 | NewBlock b8 = createNextBlock(b7, chainHeadHeight + 6, out4, null); 234 | blocks.add(new BlockAndValidity(b8, false, true, b6.getHash(), chainHeadHeight + 4, "b8")); 235 | 236 | // Try to create a block that has too much fee 237 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 238 | // \-> b9 (4) 239 | // \-> b3 (1) -> b4 (2) 240 | // 241 | NewBlock b9 = createNextBlock(b6, chainHeadHeight + 5, out4, SATOSHI); 242 | blocks.add(new BlockAndValidity(b9, false, true, b6.getHash(), chainHeadHeight + 4, "b9")); 243 | 244 | // Create a fork that ends in a block with too much fee (the one that causes the reorg) 245 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 246 | // \-> b10 (3) -> b11 (4) 247 | // \-> b3 (1) -> b4 (2) 248 | // 249 | NewBlock b10 = createNextBlock(b5, chainHeadHeight + 4, out3, null); 250 | blocks.add(new BlockAndValidity(b10, true, false, b6.getHash(), chainHeadHeight + 4, "b10")); 251 | 252 | NewBlock b11 = createNextBlock(b10, chainHeadHeight + 5, out4, SATOSHI); 253 | blocks.add(new BlockAndValidity(b11, false, true, b6.getHash(), chainHeadHeight + 4, "b11")); 254 | 255 | // Try again, but with a valid fork first 256 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 257 | // \-> b12 (3) -> b13 (4) -> b14 (5) 258 | // (b12 added last) 259 | // \-> b3 (1) -> b4 (2) 260 | // 261 | NewBlock b12 = createNextBlock(b5, chainHeadHeight + 4, out3, null); 262 | spendableOutputs.offer(b12.getCoinbaseOutput()); 263 | 264 | NewBlock b13 = createNextBlock(b12, chainHeadHeight + 5, out4, null); 265 | blocks.add(new BlockAndValidity(b13, false, false, b6.getHash(), chainHeadHeight + 4, "b13")); 266 | // Make sure we dont die if an orphan gets added twice 267 | blocks.add(new BlockAndValidity(b13, false, false, b6.getHash(), chainHeadHeight + 4, "b13")); 268 | spendableOutputs.offer(b13.getCoinbaseOutput()); 269 | 270 | TransactionOutPointWithValue out5 = spendableOutputs.poll(); 271 | 272 | NewBlock b14 = createNextBlock(b13, chainHeadHeight + 6, out5, SATOSHI); 273 | // This will be "validly" added, though its actually invalid, it will just be marked orphan 274 | // and will be discarded when an attempt is made to reorg to it. 275 | // TODO: Use a WeakReference to check that it is freed properly after the reorg 276 | blocks.add(new BlockAndValidity(b14, false, false, b6.getHash(), chainHeadHeight + 4, "b14")); 277 | // Make sure we dont die if an orphan gets added twice 278 | blocks.add(new BlockAndValidity(b14, false, false, b6.getHash(), chainHeadHeight + 4, "b14")); 279 | 280 | blocks.add(new BlockAndValidity(b12, false, true, b13.getHash(), chainHeadHeight + 5, "b12")); 281 | 282 | // Add a block with MAX_BLOCK_SIGOPS and one with one more sigop 283 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 284 | // \-> b12 (3) -> b13 (4) -> b15 (5) -> b16 (6) 285 | // \-> b3 (1) -> b4 (2) 286 | // 287 | NewBlock b15 = createNextBlock(b13, chainHeadHeight + 6, out5, null); 288 | { 289 | int sigOps = 0; 290 | for (Transaction tx : b15.block.getTransactions()) 291 | sigOps += tx.getSigOpCount(); 292 | Transaction tx = new Transaction(params); 293 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIGOPS - sigOps]; 294 | Arrays.fill(outputScript, (byte) OP_CHECKSIG); 295 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 296 | addOnlyInputToTransaction(tx, b15); 297 | b15.addTransaction(tx); 298 | 299 | sigOps = 0; 300 | for (Transaction tx2 : b15.block.getTransactions()) 301 | sigOps += tx2.getSigOpCount(); 302 | checkState(sigOps == Block.MAX_BLOCK_SIGOPS); 303 | } 304 | b15.solve(); 305 | 306 | blocks.add(new BlockAndValidity(b15, true, false, b15.getHash(), chainHeadHeight + 6, "b15")); 307 | spendableOutputs.offer(b15.getCoinbaseOutput()); 308 | 309 | TransactionOutPointWithValue out6 = spendableOutputs.poll(); 310 | 311 | NewBlock b16 = createNextBlock(b15, chainHeadHeight + 7, out6, null); 312 | { 313 | int sigOps = 0; 314 | for (Transaction tx : b16.block.getTransactions()) { 315 | sigOps += tx.getSigOpCount(); 316 | } 317 | Transaction tx = new Transaction(params); 318 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIGOPS - sigOps + 1]; 319 | Arrays.fill(outputScript, (byte) OP_CHECKSIG); 320 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 321 | addOnlyInputToTransaction(tx, b16); 322 | b16.addTransaction(tx); 323 | 324 | sigOps = 0; 325 | for (Transaction tx2 : b16.block.getTransactions()) 326 | sigOps += tx2.getSigOpCount(); 327 | checkState(sigOps == Block.MAX_BLOCK_SIGOPS + 1); 328 | } 329 | b16.solve(); 330 | 331 | blocks.add(new BlockAndValidity(b16, false, true, b15.getHash(), chainHeadHeight + 6, "b16")); 332 | 333 | // Attempt to spend a transaction created on a different fork 334 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 335 | // \-> b12 (3) -> b13 (4) -> b15 (5) -> b17 (6) 336 | // \-> b3 (1) -> b4 (2) 337 | // 338 | NewBlock b17 = createNextBlock(b15, chainHeadHeight + 7, out6, null); 339 | { 340 | Transaction tx = new Transaction(params); 341 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, new byte[] {})); 342 | addOnlyInputToTransaction(tx, b3); 343 | b17.addTransaction(tx); 344 | } 345 | b17.solve(); 346 | blocks.add(new BlockAndValidity(b17, false, true, b15.getHash(), chainHeadHeight + 6, "b17")); 347 | 348 | // Attempt to spend a transaction created on a different fork (on a fork this time) 349 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 350 | // \-> b12 (3) -> b13 (4) -> b15 (5) 351 | // \-> b18 (5) -> b19 (6) 352 | // \-> b3 (1) -> b4 (2) 353 | // 354 | NewBlock b18 = createNextBlock(b13, chainHeadHeight + 6, out5, null); 355 | { 356 | Transaction tx = new Transaction(params); 357 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, new byte[] {})); 358 | addOnlyInputToTransaction(tx, b3); 359 | b18.addTransaction(tx); 360 | } 361 | b18.solve(); 362 | blocks.add(new BlockAndValidity(b18, true, false, b15.getHash(), chainHeadHeight + 6, "b17")); 363 | 364 | NewBlock b19 = createNextBlock(b18, chainHeadHeight + 7, out6, null); 365 | blocks.add(new BlockAndValidity(b19, false, true, b15.getHash(), chainHeadHeight + 6, "b19")); 366 | 367 | // Attempt to spend a coinbase at depth too low 368 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 369 | // \-> b12 (3) -> b13 (4) -> b15 (5) -> b20 (7) 370 | // \-> b3 (1) -> b4 (2) 371 | // 372 | TransactionOutPointWithValue out7 = spendableOutputs.poll(); 373 | 374 | NewBlock b20 = createNextBlock(b15.block, chainHeadHeight + 7, out7, null); 375 | blocks.add(new BlockAndValidity(b20, false, true, b15.getHash(), chainHeadHeight + 6, "b20")); 376 | 377 | // Attempt to spend a coinbase at depth too low (on a fork this time) 378 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 379 | // \-> b12 (3) -> b13 (4) -> b15 (5) 380 | // \-> b21 (6) -> b22 (5) 381 | // \-> b3 (1) -> b4 (2) 382 | // 383 | NewBlock b21 = createNextBlock(b13, chainHeadHeight + 6, out6, null); 384 | blocks.add(new BlockAndValidity(b21.block, true, false, b15.getHash(), chainHeadHeight + 6, "b21")); 385 | NewBlock b22 = createNextBlock(b21, chainHeadHeight + 7, out5, null); 386 | blocks.add(new BlockAndValidity(b22.block, false, true, b15.getHash(), chainHeadHeight + 6, "b22")); 387 | 388 | // Create a block on either side of MAX_BLOCK_SIZE and make sure its accepted/rejected 389 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 390 | // \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) 391 | // \-> b24 (6) -> b25 (7) 392 | // \-> b3 (1) -> b4 (2) 393 | // 394 | NewBlock b23 = createNextBlock(b15, chainHeadHeight + 7, out6, null); 395 | { 396 | Transaction tx = new Transaction(params); 397 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIZE - b23.block.getMessageSize() - 65]; 398 | Arrays.fill(outputScript, (byte) OP_FALSE); 399 | tx.addOutput(new TransactionOutput(params, tx, ZERO, outputScript)); 400 | addOnlyInputToTransaction(tx, b23); 401 | b23.addTransaction(tx); 402 | } 403 | b23.solve(); 404 | checkState(b23.block.getMessageSize() == Block.MAX_BLOCK_SIZE); 405 | blocks.add(new BlockAndValidity(b23, true, false, b23.getHash(), chainHeadHeight + 7, "b23")); 406 | spendableOutputs.offer(b23.getCoinbaseOutput()); 407 | 408 | NewBlock b24 = createNextBlock(b15, chainHeadHeight + 7, out6, null); 409 | { 410 | Transaction tx = new Transaction(params); 411 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIZE - b24.block.getMessageSize() - 64]; 412 | Arrays.fill(outputScript, (byte) OP_FALSE); 413 | tx.addOutput(new TransactionOutput(params, tx, ZERO, outputScript)); 414 | addOnlyInputToTransaction(tx, b24); 415 | b24.addTransaction(tx); 416 | } 417 | b24.solve(); 418 | checkState(b24.block.getMessageSize() == Block.MAX_BLOCK_SIZE + 1); 419 | blocks.add(new BlockAndValidity(b24, false, true, b23.getHash(), chainHeadHeight + 7, "b24")); 420 | 421 | // Extend the b24 chain to make sure bitcoind isn't accepting b24 422 | NewBlock b25 = createNextBlock(b24, chainHeadHeight + 8, out7, null); 423 | blocks.add(new BlockAndValidity(b25, false, false, b23.getHash(), chainHeadHeight + 7, "b25")); 424 | 425 | // Create blocks with a coinbase input script size out of range 426 | // genesis -> b1 (0) -> b2 (1) -> b5 (2) -> b6 (3) 427 | // \-> b12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) 428 | // \-> ... (6) -> ... (7) 429 | // \-> b3 (1) -> b4 (2) 430 | // 431 | NewBlock b26 = createNextBlock(b15, chainHeadHeight + 7, out6, null); 432 | // 1 is too small, but we already generate every other block with 2, so that is tested 433 | b26.block.getTransactions().get(0).getInputs().get(0).setScriptBytes(new byte[] {0}); 434 | b26.block.setMerkleRoot(null); 435 | b26.solve(); 436 | blocks.add(new BlockAndValidity(b26, false, true, b23.getHash(), chainHeadHeight + 7, "b26")); 437 | 438 | // Extend the b26 chain to make sure bitcoind isn't accepting b26 439 | NewBlock b27 = createNextBlock(b26, chainHeadHeight + 8, out7, null); 440 | blocks.add(new BlockAndValidity(b27, false, false, b23.getHash(), chainHeadHeight + 7, "b27")); 441 | 442 | NewBlock b28 = createNextBlock(b15, chainHeadHeight + 7, out6, null); 443 | { 444 | byte[] coinbase = new byte[101]; 445 | Arrays.fill(coinbase, (byte)0); 446 | b28.block.getTransactions().get(0).getInputs().get(0).setScriptBytes(coinbase); 447 | } 448 | b28.block.setMerkleRoot(null); 449 | b28.solve(); 450 | blocks.add(new BlockAndValidity(b28, false, true, b23.getHash(), chainHeadHeight + 7, "b28")); 451 | 452 | // Extend the b28 chain to make sure bitcoind isn't accepting b28 453 | NewBlock b29 = createNextBlock(b28, chainHeadHeight + 8, out7, null); 454 | blocks.add(new BlockAndValidity(b29, false, false, b23.getHash(), chainHeadHeight + 7, "b29")); 455 | 456 | NewBlock b30 = createNextBlock(b23, chainHeadHeight + 8, out7, null); 457 | { 458 | byte[] coinbase = new byte[100]; 459 | Arrays.fill(coinbase, (byte)0); 460 | b30.block.getTransactions().get(0).getInputs().get(0).setScriptBytes(coinbase); 461 | } 462 | b30.block.setMerkleRoot(null); 463 | b30.solve(); 464 | blocks.add(new BlockAndValidity(b30, true, false, b30.getHash(), chainHeadHeight + 8, "b30")); 465 | spendableOutputs.offer(b30.getCoinbaseOutput()); 466 | 467 | // Check sigops of OP_CHECKMULTISIG/OP_CHECKMULTISIGVERIFY/OP_CHECKSIGVERIFY 468 | // 6 (3) 469 | // 12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) 470 | // \-> b36 (11) 471 | // \-> b34 (10) 472 | // \-> b32 (9) 473 | // 474 | TransactionOutPointWithValue out8 = spendableOutputs.poll(); 475 | 476 | NewBlock b31 = createNextBlock(b30, chainHeadHeight + 9, out8, null); 477 | { 478 | int sigOps = 0; 479 | for (Transaction tx : b31.block.transactions) { 480 | sigOps += tx.getSigOpCount(); 481 | } 482 | Transaction tx = new Transaction(params); 483 | byte[] outputScript = new byte[(Block.MAX_BLOCK_SIGOPS - sigOps)/20]; 484 | Arrays.fill(outputScript, (byte) OP_CHECKMULTISIG); 485 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 486 | addOnlyInputToTransaction(tx, b31); 487 | b31.addTransaction(tx); 488 | } 489 | b31.solve(); 490 | 491 | blocks.add(new BlockAndValidity(b31, true, false, b31.getHash(), chainHeadHeight + 9, "b31")); 492 | spendableOutputs.offer(b31.getCoinbaseOutput()); 493 | 494 | TransactionOutPointWithValue out9 = spendableOutputs.poll(); 495 | 496 | NewBlock b32 = createNextBlock(b31, chainHeadHeight + 10, out9, null); 497 | { 498 | int sigOps = 0; 499 | for (Transaction tx : b32.block.transactions) { 500 | sigOps += tx.getSigOpCount(); 501 | } 502 | Transaction tx = new Transaction(params); 503 | byte[] outputScript = new byte[(Block.MAX_BLOCK_SIGOPS - sigOps)/20 + (Block.MAX_BLOCK_SIGOPS - sigOps)%20 + 1]; 504 | Arrays.fill(outputScript, (byte) OP_CHECKMULTISIG); 505 | for (int i = 0; i < (Block.MAX_BLOCK_SIGOPS - sigOps)%20; i++) 506 | outputScript[i] = (byte) OP_CHECKSIG; 507 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 508 | addOnlyInputToTransaction(tx, b32); 509 | b32.addTransaction(tx); 510 | } 511 | b32.solve(); 512 | blocks.add(new BlockAndValidity(b32, false, true, b31.getHash(), chainHeadHeight + 9, "b32")); 513 | 514 | NewBlock b33 = createNextBlock(b31, chainHeadHeight + 10, out9, null); 515 | { 516 | int sigOps = 0; 517 | for (Transaction tx : b33.block.transactions) { 518 | sigOps += tx.getSigOpCount(); 519 | } 520 | Transaction tx = new Transaction(params); 521 | byte[] outputScript = new byte[(Block.MAX_BLOCK_SIGOPS - sigOps)/20]; 522 | Arrays.fill(outputScript, (byte) OP_CHECKMULTISIGVERIFY); 523 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 524 | addOnlyInputToTransaction(tx, b33); 525 | b33.addTransaction(tx); 526 | } 527 | b33.solve(); 528 | 529 | blocks.add(new BlockAndValidity(b33, true, false, b33.getHash(), chainHeadHeight + 10, "b33")); 530 | spendableOutputs.offer(b33.getCoinbaseOutput()); 531 | 532 | TransactionOutPointWithValue out10 = spendableOutputs.poll(); 533 | 534 | NewBlock b34 = createNextBlock(b33, chainHeadHeight + 11, out10, null); 535 | { 536 | int sigOps = 0; 537 | for (Transaction tx : b34.block.getTransactions()) { 538 | sigOps += tx.getSigOpCount(); 539 | } 540 | Transaction tx = new Transaction(params); 541 | byte[] outputScript = new byte[(Block.MAX_BLOCK_SIGOPS - sigOps)/20 + (Block.MAX_BLOCK_SIGOPS - sigOps)%20 + 1]; 542 | Arrays.fill(outputScript, (byte) OP_CHECKMULTISIGVERIFY); 543 | for (int i = 0; i < (Block.MAX_BLOCK_SIGOPS - sigOps)%20; i++) 544 | outputScript[i] = (byte) OP_CHECKSIG; 545 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 546 | addOnlyInputToTransaction(tx, b34); 547 | b34.addTransaction(tx); 548 | } 549 | b34.solve(); 550 | blocks.add(new BlockAndValidity(b34, false, true, b33.getHash(), chainHeadHeight + 10, "b34")); 551 | 552 | NewBlock b35 = createNextBlock(b33, chainHeadHeight + 11, out10, null); 553 | { 554 | int sigOps = 0; 555 | for (Transaction tx : b35.block.getTransactions()) { 556 | sigOps += tx.getSigOpCount(); 557 | } 558 | Transaction tx = new Transaction(params); 559 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIGOPS - sigOps]; 560 | Arrays.fill(outputScript, (byte) OP_CHECKSIGVERIFY); 561 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 562 | addOnlyInputToTransaction(tx, b35); 563 | b35.addTransaction(tx); 564 | } 565 | b35.solve(); 566 | 567 | blocks.add(new BlockAndValidity(b35, true, false, b35.getHash(), chainHeadHeight + 11, "b35")); 568 | spendableOutputs.offer(b35.getCoinbaseOutput()); 569 | 570 | TransactionOutPointWithValue out11 = spendableOutputs.poll(); 571 | 572 | NewBlock b36 = createNextBlock(b35, chainHeadHeight + 12, out11, null); 573 | { 574 | int sigOps = 0; 575 | for (Transaction tx : b36.block.getTransactions()) { 576 | sigOps += tx.getSigOpCount(); 577 | } 578 | Transaction tx = new Transaction(params); 579 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIGOPS - sigOps + 1]; 580 | Arrays.fill(outputScript, (byte) OP_CHECKSIGVERIFY); 581 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 582 | addOnlyInputToTransaction(tx, b36); 583 | b36.addTransaction(tx); 584 | } 585 | b36.solve(); 586 | 587 | blocks.add(new BlockAndValidity(b36, false, true, b35.getHash(), chainHeadHeight + 11, "b36")); 588 | 589 | // Check spending of a transaction in a block which failed to connect 590 | // (test block store transaction abort handling, not that it should get this far if that's broken...) 591 | // 6 (3) 592 | // 12 (3) -> b13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) 593 | // \-> b37 (11) 594 | // \-> b38 (11) 595 | // 596 | NewBlock b37 = createNextBlock(b35, chainHeadHeight + 12, out11, null); 597 | { 598 | Transaction tx = new Transaction(params); 599 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, new byte[] {})); 600 | addOnlyInputToTransaction(tx, out11); // double spend out11 601 | b37.addTransaction(tx); 602 | } 603 | b37.solve(); 604 | blocks.add(new BlockAndValidity(b37, false, true, b35.getHash(), chainHeadHeight + 11, "b37")); 605 | 606 | NewBlock b38 = createNextBlock(b35, chainHeadHeight + 12, out11, null); 607 | { 608 | Transaction tx = new Transaction(params); 609 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, new byte[] {})); 610 | // Attempt to spend b37's first non-coinbase tx, at which point b37 was still considered valid 611 | addOnlyInputToTransaction(tx, b37); 612 | b38.addTransaction(tx); 613 | } 614 | b38.solve(); 615 | blocks.add(new BlockAndValidity(b38, false, true, b35.getHash(), chainHeadHeight + 11, "b38")); 616 | 617 | // Check P2SH SigOp counting 618 | // 13 (4) -> b15 (5) -> b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b41 (12) 619 | // \-> b40 (12) 620 | // 621 | // Create some P2SH outputs that will require 6 sigops to spend 622 | byte[] b39p2shScriptPubKey; 623 | int b39numP2SHOutputs = 0, b39sigOpsPerOutput = 6; 624 | NewBlock b39 = createNextBlock(b35, chainHeadHeight + 12, null, null); 625 | { 626 | ByteArrayOutputStream p2shScriptPubKey = new UnsafeByteArrayOutputStream(); 627 | try { 628 | Script.writeBytes(p2shScriptPubKey, coinbaseOutKeyPubKey); 629 | p2shScriptPubKey.write(OP_2DUP); 630 | p2shScriptPubKey.write(OP_CHECKSIGVERIFY); 631 | p2shScriptPubKey.write(OP_2DUP); 632 | p2shScriptPubKey.write(OP_CHECKSIGVERIFY); 633 | p2shScriptPubKey.write(OP_2DUP); 634 | p2shScriptPubKey.write(OP_CHECKSIGVERIFY); 635 | p2shScriptPubKey.write(OP_2DUP); 636 | p2shScriptPubKey.write(OP_CHECKSIGVERIFY); 637 | p2shScriptPubKey.write(OP_2DUP); 638 | p2shScriptPubKey.write(OP_CHECKSIGVERIFY); 639 | p2shScriptPubKey.write(OP_CHECKSIG); 640 | } catch (IOException e) { 641 | throw new RuntimeException(e); // Cannot happen. 642 | } 643 | b39p2shScriptPubKey = p2shScriptPubKey.toByteArray(); 644 | 645 | byte[] scriptHash = Utils.sha256hash160(b39p2shScriptPubKey); 646 | UnsafeByteArrayOutputStream scriptPubKey = new UnsafeByteArrayOutputStream(scriptHash.length + 3); 647 | scriptPubKey.write(OP_HASH160); 648 | try { 649 | Script.writeBytes(scriptPubKey, scriptHash); 650 | } catch (IOException e) { 651 | throw new RuntimeException(e); // Cannot happen. 652 | } 653 | scriptPubKey.write(OP_EQUAL); 654 | 655 | Coin lastOutputValue = out11.value.subtract(SATOSHI); 656 | TransactionOutPoint lastOutPoint; 657 | { 658 | Transaction tx = new Transaction(params); 659 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, scriptPubKey.toByteArray())); 660 | tx.addOutput(new TransactionOutput(params, tx, lastOutputValue, new byte[]{OP_1})); 661 | addOnlyInputToTransaction(tx, out11); 662 | lastOutPoint = new TransactionOutPoint(params, 1, tx.getHash()); 663 | b39.addTransaction(tx); 664 | } 665 | b39numP2SHOutputs++; 666 | 667 | while (b39.block.getMessageSize() < Block.MAX_BLOCK_SIZE) 668 | { 669 | Transaction tx = new Transaction(params); 670 | 671 | lastOutputValue = lastOutputValue.subtract(SATOSHI); 672 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, scriptPubKey.toByteArray())); 673 | tx.addOutput(new TransactionOutput(params, tx, lastOutputValue, new byte[]{OP_1})); 674 | tx.addInput(new TransactionInput(params, tx, new byte[]{OP_1}, lastOutPoint)); 675 | lastOutPoint = new TransactionOutPoint(params, 1, tx.getHash()); 676 | 677 | if (b39.block.getMessageSize() + tx.getMessageSize() < Block.MAX_BLOCK_SIZE) { 678 | b39.addTransaction(tx); 679 | b39numP2SHOutputs++; 680 | } else 681 | break; 682 | } 683 | } 684 | b39.solve(); 685 | blocks.add(new BlockAndValidity(b39, true, false, b39.getHash(), chainHeadHeight + 12, "b39")); 686 | spendableOutputs.offer(b39.getCoinbaseOutput()); 687 | 688 | TransactionOutPointWithValue out12 = spendableOutputs.poll(); 689 | 690 | NewBlock b40 = createNextBlock(b39, chainHeadHeight + 13, out12, null); 691 | { 692 | int sigOps = 0; 693 | for (Transaction tx : b40.block.getTransactions()) { 694 | sigOps += tx.getSigOpCount(); 695 | } 696 | 697 | int numTxes = (Block.MAX_BLOCK_SIGOPS - sigOps) / b39sigOpsPerOutput; 698 | checkState(numTxes <= b39numP2SHOutputs); 699 | 700 | TransactionOutPoint lastOutPoint = new TransactionOutPoint(params, 1, b40.block.getTransactions().get(1).getHash()); 701 | 702 | byte[] scriptSig = null; 703 | for (int i = 1; i <= numTxes; i++) { 704 | Transaction tx = new Transaction(params); 705 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, new byte[] {OP_1})); 706 | tx.addInput(new TransactionInput(params, tx, new byte[]{OP_1}, lastOutPoint)); 707 | 708 | TransactionInput input = new TransactionInput(params, tx, new byte[]{}, 709 | new TransactionOutPoint(params, 0, b39.block.getTransactions().get(i).getHash())); 710 | tx.addInput(input); 711 | 712 | if (scriptSig == null) { 713 | // Exploit the SigHash.SINGLE bug to avoid having to make more than one signature 714 | Sha256Hash hash = tx.hashForSignature(1, b39p2shScriptPubKey, SigHash.SINGLE, false); 715 | 716 | // Sign input 717 | try { 718 | ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(73); 719 | bos.write(coinbaseOutKey.sign(hash).encodeToDER()); 720 | bos.write(SigHash.SINGLE.ordinal() + 1); 721 | byte[] signature = bos.toByteArray(); 722 | 723 | ByteArrayOutputStream scriptSigBos = new UnsafeByteArrayOutputStream(signature.length + b39p2shScriptPubKey.length + 3); 724 | Script.writeBytes(scriptSigBos, new byte[] {(byte) OP_CHECKSIG}); 725 | scriptSigBos.write(Script.createInputScript(signature)); 726 | Script.writeBytes(scriptSigBos, b39p2shScriptPubKey); 727 | 728 | scriptSig = scriptSigBos.toByteArray(); 729 | } catch (IOException e) { 730 | throw new RuntimeException(e); // Cannot happen. 731 | } 732 | } 733 | 734 | input.setScriptBytes(scriptSig); 735 | 736 | lastOutPoint = new TransactionOutPoint(params, 0, tx.getHash()); 737 | 738 | b40.addTransaction(tx); 739 | } 740 | 741 | sigOps += numTxes * b39sigOpsPerOutput; 742 | Transaction tx = new Transaction(params); 743 | tx.addInput(new TransactionInput(params, tx, new byte[]{OP_1}, lastOutPoint)); 744 | byte[] scriptPubKey = new byte[Block.MAX_BLOCK_SIGOPS - sigOps + 1]; 745 | Arrays.fill(scriptPubKey, (byte) OP_CHECKSIG); 746 | tx.addOutput(new TransactionOutput(params, tx, ZERO, scriptPubKey)); 747 | b40.addTransaction(tx); 748 | } 749 | b40.solve(); 750 | blocks.add(new BlockAndValidity(b40, false, true, b39.getHash(), chainHeadHeight + 12, "b40")); 751 | 752 | NewBlock b41 = null; 753 | if (runBarelyExpensiveTests) { 754 | b41 = createNextBlock(b39, chainHeadHeight + 13, out12, null); 755 | { 756 | int sigOps = 0; 757 | for (Transaction tx : b41.block.getTransactions()) { 758 | sigOps += tx.getSigOpCount(); 759 | } 760 | 761 | int numTxes = (Block.MAX_BLOCK_SIGOPS - sigOps) 762 | / b39sigOpsPerOutput; 763 | checkState(numTxes <= b39numP2SHOutputs); 764 | 765 | TransactionOutPoint lastOutPoint = new TransactionOutPoint( 766 | params, 1, b41.block.getTransactions().get(1).getHash()); 767 | 768 | byte[] scriptSig = null; 769 | for (int i = 1; i <= numTxes; i++) { 770 | Transaction tx = new Transaction(params); 771 | tx.addOutput(new TransactionOutput(params, tx, Coin 772 | .SATOSHI, new byte[] {OP_1})); 773 | tx.addInput(new TransactionInput(params, tx, 774 | new byte[] {OP_1}, lastOutPoint)); 775 | 776 | TransactionInput input = new TransactionInput(params, tx, 777 | new byte[] {}, new TransactionOutPoint(params, 0, 778 | b39.block.getTransactions().get(i).getHash())); 779 | tx.addInput(input); 780 | 781 | if (scriptSig == null) { 782 | // Exploit the SigHash.SINGLE bug to avoid having to make more than one signature 783 | Sha256Hash hash = tx.hashForSignature(1, 784 | b39p2shScriptPubKey, SigHash.SINGLE, false); 785 | 786 | // Sign input 787 | try { 788 | ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream( 789 | 73); 790 | bos.write(coinbaseOutKey.sign(hash).encodeToDER()); 791 | bos.write(SigHash.SINGLE.ordinal() + 1); 792 | byte[] signature = bos.toByteArray(); 793 | 794 | ByteArrayOutputStream scriptSigBos = new UnsafeByteArrayOutputStream( 795 | signature.length 796 | + b39p2shScriptPubKey.length + 3); 797 | Script.writeBytes(scriptSigBos, 798 | new byte[] { (byte) OP_CHECKSIG}); 799 | scriptSigBos.write(Script 800 | .createInputScript(signature)); 801 | Script.writeBytes(scriptSigBos, b39p2shScriptPubKey); 802 | 803 | scriptSig = scriptSigBos.toByteArray(); 804 | } catch (IOException e) { 805 | throw new RuntimeException(e); // Cannot happen. 806 | } 807 | } 808 | 809 | input.setScriptBytes(scriptSig); 810 | 811 | lastOutPoint = new TransactionOutPoint(params, 0, 812 | tx.getHash()); 813 | 814 | b41.addTransaction(tx); 815 | } 816 | 817 | sigOps += numTxes * b39sigOpsPerOutput; 818 | Transaction tx = new Transaction(params); 819 | tx.addInput(new TransactionInput(params, tx, 820 | new byte[] {OP_1}, lastOutPoint)); 821 | byte[] scriptPubKey = new byte[Block.MAX_BLOCK_SIGOPS - sigOps]; 822 | Arrays.fill(scriptPubKey, (byte) OP_CHECKSIG); 823 | tx.addOutput(new TransactionOutput(params, tx, ZERO, scriptPubKey)); 824 | b41.addTransaction(tx); 825 | } 826 | b41.solve(); 827 | blocks.add(new BlockAndValidity(b41, true, false, b41.getHash(), chainHeadHeight + 13, "b41")); 828 | } 829 | 830 | // Fork off of b39 to create a constant base again 831 | // b23 (6) -> b30 (7) -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) 832 | // \-> b41 (12) 833 | // 834 | NewBlock b42 = createNextBlock(b39, chainHeadHeight + 13, out12, null); 835 | blocks.add(new BlockAndValidity(b42, true, false, b41 == null ? b42.getHash() : b41.getHash(), chainHeadHeight + 13, "b42")); 836 | spendableOutputs.offer(b42.getCoinbaseOutput()); 837 | 838 | TransactionOutPointWithValue out13 = spendableOutputs.poll(); 839 | 840 | NewBlock b43 = createNextBlock(b42, chainHeadHeight + 14, out13, null); 841 | blocks.add(new BlockAndValidity(b43, true, false, b43.getHash(), chainHeadHeight + 14, "b43")); 842 | spendableOutputs.offer(b43.getCoinbaseOutput()); 843 | 844 | // Test a number of really invalid scenarios 845 | // -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b44 (14) 846 | // \-> ??? (15) 847 | // 848 | TransactionOutPointWithValue out14 = spendableOutputs.poll(); 849 | 850 | // A valid block created exactly like b44 to make sure the creation itself works 851 | Block b44 = new Block(params); 852 | byte[] outScriptBytes = ScriptBuilder.createOutputScript(ECKey.fromPublicOnly(coinbaseOutKeyPubKey)).getProgram(); 853 | { 854 | b44.setDifficultyTarget(b43.block.getDifficultyTarget()); 855 | b44.addCoinbaseTransaction(coinbaseOutKeyPubKey, ZERO); 856 | 857 | Transaction t = new Transaction(params); 858 | // Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much 859 | t.addOutput(new TransactionOutput(params, t, ZERO, new byte[] {OP_PUSHDATA1 - 1 })); 860 | t.addOutput(new TransactionOutput(params, t, SATOSHI, outScriptBytes)); 861 | // Spendable output 862 | t.addOutput(new TransactionOutput(params, t, ZERO, new byte[] {OP_1})); 863 | addOnlyInputToTransaction(t, out14); 864 | b44.addTransaction(t); 865 | 866 | b44.setPrevBlockHash(b43.getHash()); 867 | b44.setTime(b43.block.getTimeSeconds() + 1); 868 | } 869 | b44.solve(); 870 | blocks.add(new BlockAndValidity(b44, true, false, b44.getHash(), chainHeadHeight + 15, "b44")); 871 | 872 | TransactionOutPointWithValue out15 = spendableOutputs.poll(); 873 | 874 | // A block with a non-coinbase as the first tx 875 | Block b45 = new Block(params); 876 | { 877 | b45.setDifficultyTarget(b44.getDifficultyTarget()); 878 | //b45.addCoinbaseTransaction(pubKey, coinbaseValue); 879 | 880 | Transaction t = new Transaction(params); 881 | // Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much 882 | t.addOutput(new TransactionOutput(params, t, ZERO, new byte[] {OP_PUSHDATA1 - 1 })); 883 | t.addOutput(new TransactionOutput(params, t, SATOSHI, outScriptBytes)); 884 | // Spendable output 885 | t.addOutput(new TransactionOutput(params, t, ZERO, new byte[] {OP_1})); 886 | addOnlyInputToTransaction(t, out15); 887 | try { 888 | b45.addTransaction(t); 889 | } catch (RuntimeException e) { } // Should happen 890 | if (b45.getTransactions().size() > 0) 891 | throw new RuntimeException("addTransaction doesn't properly check for adding a non-coinbase as first tx"); 892 | b45.addTransaction(t, false); 893 | 894 | b45.setPrevBlockHash(b44.getHash()); 895 | b45.setTime(b44.getTimeSeconds() + 1); 896 | } 897 | b45.solve(); 898 | blocks.add(new BlockAndValidity(b45, false, true, b44.getHash(), chainHeadHeight + 15, "b45")); 899 | 900 | // A block with no txn 901 | Block b46 = new Block(params); 902 | { 903 | b46.transactions = new ArrayList(); 904 | b46.setDifficultyTarget(b44.getDifficultyTarget()); 905 | b46.setMerkleRoot(Sha256Hash.ZERO_HASH); 906 | 907 | b46.setPrevBlockHash(b44.getHash()); 908 | b46.setTime(b44.getTimeSeconds() + 1); 909 | } 910 | b46.solve(); 911 | blocks.add(new BlockAndValidity(b46, false, true, b44.getHash(), chainHeadHeight + 15, "b46")); 912 | 913 | // A block with invalid work 914 | NewBlock b47 = createNextBlock(b44, chainHeadHeight + 16, out15, null); 915 | { 916 | try { 917 | // Inverse solve 918 | BigInteger target = b47.block.getDifficultyTargetAsInteger(); 919 | while (true) { 920 | BigInteger h = b47.getHash().toBigInteger(); 921 | if (h.compareTo(target) > 0) // if invalid 922 | break; 923 | // increment the nonce and try again. 924 | b47.block.setNonce(b47.block.getNonce() + 1); 925 | } 926 | } catch (VerificationException e) { 927 | throw new RuntimeException(e); // Cannot happen. 928 | } 929 | } 930 | blocks.add(new BlockAndValidity(b47, false, true, b44.getHash(), chainHeadHeight + 15, "b47")); 931 | 932 | // Block with timestamp > 2h in the future 933 | NewBlock b48 = createNextBlock(b44, chainHeadHeight + 16, out15, null); 934 | b48.block.setTime(Utils.currentTimeSeconds() + 60 * 60 * 3); 935 | b48.solve(); 936 | blocks.add(new BlockAndValidity(b48, false, true, b44.getHash(), chainHeadHeight + 15, "b48")); 937 | 938 | // Block with invalid merkle hash 939 | NewBlock b49 = createNextBlock(b44, chainHeadHeight + 16, out15, null); 940 | byte[] b49MerkleHash = Sha256Hash.ZERO_HASH.getBytes().clone(); 941 | b49MerkleHash[1] = (byte) 0xDE; 942 | b49.block.setMerkleRoot(Sha256Hash.create(b49MerkleHash)); 943 | b49.solve(); 944 | blocks.add(new BlockAndValidity(b49, false, true, b44.getHash(), chainHeadHeight + 15, "b49")); 945 | 946 | // Block with incorrect POW limit 947 | NewBlock b50 = createNextBlock(b44, chainHeadHeight + 16, out15, null); 948 | { 949 | long diffTarget = b44.getDifficultyTarget(); 950 | diffTarget &= 0xFFBFFFFF; // Make difficulty one bit harder 951 | b50.block.setDifficultyTarget(diffTarget); 952 | } 953 | b50.solve(); 954 | blocks.add(new BlockAndValidity(b50, false, true, b44.getHash(), chainHeadHeight + 15, "b50")); 955 | 956 | // A block with two coinbase txn 957 | NewBlock b51 = createNextBlock(b44, chainHeadHeight + 16, out15, null); 958 | { 959 | Transaction coinbase = new Transaction(params); 960 | coinbase.addInput(new TransactionInput(params, coinbase, new byte[]{(byte) 0xff, 110, 1})); 961 | coinbase.addOutput(new TransactionOutput(params, coinbase, SATOSHI, outScriptBytes)); 962 | b51.block.addTransaction(coinbase, false); 963 | } 964 | b51.solve(); 965 | blocks.add(new BlockAndValidity(b51, false, true, b44.getHash(), chainHeadHeight + 15, "b51")); 966 | 967 | // A block with duplicate txn 968 | NewBlock b52 = createNextBlock(b44, chainHeadHeight + 16, out15, null); 969 | { 970 | Transaction tx = new Transaction(params); 971 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, new byte[] {})); 972 | addOnlyInputToTransaction(tx, b52); 973 | b52.addTransaction(tx); 974 | b52.addTransaction(tx); 975 | } 976 | b52.solve(); 977 | blocks.add(new BlockAndValidity(b52, false, true, b44.getHash(), chainHeadHeight + 15, "b52")); 978 | 979 | // Test block timestamp 980 | // -> b31 (8) -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) 981 | // \-> b54 (15) 982 | // \-> b44 (14) 983 | // 984 | NewBlock b53 = createNextBlock(b43, chainHeadHeight + 15, out14, null); 985 | blocks.add(new BlockAndValidity(b53, true, false, b44.getHash(), chainHeadHeight + 15, "b53")); 986 | spendableOutputs.offer(b53.getCoinbaseOutput()); 987 | 988 | // Block with invalid timestamp 989 | NewBlock b54 = createNextBlock(b53, chainHeadHeight + 16, out15, null); 990 | b54.block.setTime(b35.block.getTimeSeconds() - 1); 991 | b54.solve(); 992 | blocks.add(new BlockAndValidity(b54, false, true, b44.getHash(), chainHeadHeight + 15, "b54")); 993 | 994 | // Block with valid timestamp 995 | NewBlock b55 = createNextBlock(b53, chainHeadHeight + 16, out15, null); 996 | b55.block.setTime(b35.block.getTimeSeconds()); 997 | b55.solve(); 998 | blocks.add(new BlockAndValidity(b55, true, false, b55.getHash(), chainHeadHeight + 16, "b55")); 999 | spendableOutputs.offer(b55.getCoinbaseOutput()); 1000 | 1001 | // Test CVE-2012-2459 1002 | // -> b33 (9) -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) 1003 | // \-> b56 (16) 1004 | // 1005 | TransactionOutPointWithValue out16 = spendableOutputs.poll(); 1006 | 1007 | NewBlock b57 = createNextBlock(b55, chainHeadHeight + 17, out16, null); 1008 | Transaction b56txToDuplicate; 1009 | { 1010 | b56txToDuplicate = new Transaction(params); 1011 | b56txToDuplicate.addOutput(new TransactionOutput(params, b56txToDuplicate, SATOSHI, new byte[] {})); 1012 | addOnlyInputToTransaction(b56txToDuplicate, b57); 1013 | b57.addTransaction(b56txToDuplicate); 1014 | } 1015 | b57.solve(); 1016 | 1017 | Block b56; 1018 | try { 1019 | b56 = new Block(params, b57.block.bitcoinSerialize()); 1020 | } catch (ProtocolException e) { 1021 | throw new RuntimeException(e); // Cannot happen. 1022 | } 1023 | b56.addTransaction(b56txToDuplicate); 1024 | checkState(b56.getHash().equals(b57.getHash())); 1025 | blocks.add(new BlockAndValidity(b56, false, true, b55.getHash(), chainHeadHeight + 16, "b56")); 1026 | 1027 | NewBlock b57p2 = createNextBlock(b55, chainHeadHeight + 17, out16, null); 1028 | Transaction b56p2txToDuplicate1, b56p2txToDuplicate2; 1029 | { 1030 | Transaction tx1 = new Transaction(params); 1031 | tx1.addOutput(new TransactionOutput(params, tx1, SATOSHI, new byte[] {OP_TRUE})); 1032 | addOnlyInputToTransaction(tx1, b57p2); 1033 | b57p2.addTransaction(tx1); 1034 | 1035 | Transaction tx2 = new Transaction(params); 1036 | tx2.addOutput(new TransactionOutput(params, tx2, SATOSHI, new byte[] {OP_TRUE})); 1037 | addOnlyInputToTransaction(tx2, new TransactionOutPointWithValue( 1038 | new TransactionOutPoint(params, 0, tx1.getHash()), 1039 | SATOSHI, tx1.getOutputs().get(0).getScriptPubKey())); 1040 | b57p2.addTransaction(tx2); 1041 | 1042 | b56p2txToDuplicate1 = new Transaction(params); 1043 | b56p2txToDuplicate1.addOutput(new TransactionOutput(params, b56p2txToDuplicate1, SATOSHI, new byte[]{OP_TRUE})); 1044 | addOnlyInputToTransaction(b56p2txToDuplicate1, new TransactionOutPointWithValue( 1045 | new TransactionOutPoint(params, 0, tx2.getHash()), 1046 | SATOSHI, tx2.getOutputs().get(0).getScriptPubKey())); 1047 | b57p2.addTransaction(b56p2txToDuplicate1); 1048 | 1049 | b56p2txToDuplicate2 = new Transaction(params); 1050 | b56p2txToDuplicate2.addOutput(new TransactionOutput(params, b56p2txToDuplicate2, SATOSHI, new byte[]{})); 1051 | addOnlyInputToTransaction(b56p2txToDuplicate2, new TransactionOutPointWithValue( 1052 | new TransactionOutPoint(params, 0, b56p2txToDuplicate1.getHash()), 1053 | SATOSHI, b56p2txToDuplicate1.getOutputs().get(0).getScriptPubKey())); 1054 | b57p2.addTransaction(b56p2txToDuplicate2); 1055 | } 1056 | b57p2.solve(); 1057 | 1058 | Block b56p2; 1059 | try { 1060 | b56p2 = new Block(params, b57p2.block.bitcoinSerialize()); 1061 | } catch (ProtocolException e) { 1062 | throw new RuntimeException(e); // Cannot happen. 1063 | } 1064 | b56p2.addTransaction(b56p2txToDuplicate1); 1065 | b56p2.addTransaction(b56p2txToDuplicate2); 1066 | checkState(b56p2.getHash().equals(b57p2.getHash())); 1067 | blocks.add(new BlockAndValidity(b56p2, false, true, b55.getHash(), chainHeadHeight + 16, "b56p2")); 1068 | blocks.add(new BlockAndValidity(b57p2, true, false, b57p2.getHash(), chainHeadHeight + 17, "b57p2")); 1069 | 1070 | blocks.add(new BlockAndValidity(b57, true, false, b57p2.getHash(), chainHeadHeight + 17, "b57")); 1071 | spendableOutputs.offer(b57.getCoinbaseOutput()); 1072 | 1073 | // Test a few invalid tx types 1074 | // -> b35 (10) -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) 1075 | // \-> ??? (17) 1076 | // 1077 | TransactionOutPointWithValue out17 = spendableOutputs.poll(); 1078 | 1079 | // tx with prevout.n out of range 1080 | NewBlock b58 = createNextBlock(b57, chainHeadHeight + 18, out17, null); 1081 | { 1082 | Transaction tx = new Transaction(params); 1083 | tx.addOutput(new TransactionOutput(params, tx, ZERO, new byte[] {})); 1084 | b58.getSpendableOutput().outpoint.setIndex(42); 1085 | addOnlyInputToTransaction(tx, b58); 1086 | b58.addTransaction(tx); 1087 | } 1088 | b58.solve(); 1089 | blocks.add(new BlockAndValidity(b58, false, true, b57p2.getHash(), chainHeadHeight + 17, "b58")); 1090 | 1091 | // tx with output value > input value out of range 1092 | NewBlock b59 = createNextBlock(b57, chainHeadHeight + 18, out17, null); 1093 | { 1094 | Transaction tx = new Transaction(params); 1095 | tx.addOutput(new TransactionOutput(params, tx, 1096 | b59.getSpendableOutput().value.add(SATOSHI), new byte[]{})); 1097 | addOnlyInputToTransaction(tx, b59); 1098 | b59.addTransaction(tx); 1099 | } 1100 | b59.solve(); 1101 | blocks.add(new BlockAndValidity(b59, false, true, b57p2.getHash(), chainHeadHeight + 17, "b59")); 1102 | 1103 | NewBlock b60 = createNextBlock(b57, chainHeadHeight + 18, out17, null); 1104 | blocks.add(new BlockAndValidity(b60, true, false, b60.getHash(), chainHeadHeight + 18, "b60")); 1105 | spendableOutputs.offer(b60.getCoinbaseOutput()); 1106 | 1107 | // Test BIP30 1108 | // -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) 1109 | // \-> b61 (18) 1110 | // 1111 | TransactionOutPointWithValue out18 = spendableOutputs.poll(); 1112 | 1113 | NewBlock b61 = createNextBlock(b60, chainHeadHeight + 19, out18, null); 1114 | { 1115 | b61.block.getTransactions().get(0).getInput(0).setScriptBytes(b60.block.getTransactions().get(0).getInput(0).getScriptBytes()); 1116 | b61.block.unCache(); 1117 | checkState(b61.block.getTransactions().get(0).equals(b60.block.getTransactions().get(0))); 1118 | } 1119 | b61.solve(); 1120 | blocks.add(new BlockAndValidity(b61, false, true, b60.getHash(), chainHeadHeight + 18, "b61")); 1121 | 1122 | // Test tx.isFinal is properly rejected (not an exhaustive tx.isFinal test, that should be in data-driven transaction tests) 1123 | // -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) 1124 | // \-> b62 (18) 1125 | // 1126 | NewBlock b62 = createNextBlock(b60, chainHeadHeight + 19, null, null); 1127 | { 1128 | Transaction tx = new Transaction(params); 1129 | tx.setLockTime(0xffffffffL); 1130 | tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1131 | addOnlyInputToTransaction(tx, out18, 0); 1132 | b62.addTransaction(tx); 1133 | checkState(!tx.isFinal(chainHeadHeight + 17, b62.block.getTimeSeconds())); 1134 | } 1135 | b62.solve(); 1136 | blocks.add(new BlockAndValidity(b62, false, true, b60.getHash(), chainHeadHeight + 18, "b62")); 1137 | 1138 | // Test a non-final coinbase is also rejected 1139 | // -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) 1140 | // \-> b63 (-) 1141 | // 1142 | NewBlock b63 = createNextBlock(b60, chainHeadHeight + 19, null, null); 1143 | { 1144 | b63.block.getTransactions().get(0).setLockTime(0xffffffffL); 1145 | b63.block.getTransactions().get(0).getInputs().get(0).setSequenceNumber(0xDEADBEEF); 1146 | checkState(!b63.block.getTransactions().get(0).isFinal(chainHeadHeight + 17, b63.block.getTimeSeconds())); 1147 | } 1148 | b63.solve(); 1149 | blocks.add(new BlockAndValidity(b63, false, true, b60.getHash(), chainHeadHeight + 18, "b63")); 1150 | 1151 | // Check that a block which is (when properly encoded) <= MAX_BLOCK_SIZE is accepted 1152 | // Even when it is encoded with varints that make its encoded size actually > MAX_BLOCK_SIZE 1153 | // -> b39 (11) -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) 1154 | // 1155 | Block b64; NewBlock b64Original; 1156 | { 1157 | b64Original = createNextBlock(b60, chainHeadHeight + 19, out18, null); 1158 | Transaction tx = new Transaction(params); 1159 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIZE - b64Original.block.getMessageSize() - 65]; 1160 | Arrays.fill(outputScript, (byte) OP_FALSE); 1161 | tx.addOutput(new TransactionOutput(params, tx, ZERO, outputScript)); 1162 | addOnlyInputToTransaction(tx, b64Original); 1163 | b64Original.addTransaction(tx); 1164 | b64Original.solve(); 1165 | checkState(b64Original.block.getMessageSize() == Block.MAX_BLOCK_SIZE); 1166 | 1167 | UnsafeByteArrayOutputStream stream = new UnsafeByteArrayOutputStream(b64Original.block.getMessageSize() + 8); 1168 | b64Original.block.writeHeader(stream); 1169 | 1170 | byte[] varIntBytes = new byte[9]; 1171 | varIntBytes[0] = (byte) 255; 1172 | Utils.uint32ToByteArrayLE((long)b64Original.block.getTransactions().size(), varIntBytes, 1); 1173 | Utils.uint32ToByteArrayLE(((long)b64Original.block.getTransactions().size()) >>> 32, varIntBytes, 5); 1174 | stream.write(varIntBytes); 1175 | checkState(new VarInt(varIntBytes, 0).value == b64Original.block.getTransactions().size()); 1176 | 1177 | for (Transaction transaction : b64Original.block.getTransactions()) 1178 | transaction.bitcoinSerialize(stream); 1179 | b64 = new Block(params, stream.toByteArray(), false, true, stream.size()); 1180 | 1181 | // The following checks are checking to ensure block serialization functions in the way needed for this test 1182 | // If they fail, it is likely not an indication of error, but an indication that this test needs rewritten 1183 | checkState(stream.size() == b64Original.block.getMessageSize() + 8); 1184 | checkState(stream.size() == b64.getMessageSize()); 1185 | checkState(Arrays.equals(stream.toByteArray(), b64.bitcoinSerialize())); 1186 | checkState(b64.getOptimalEncodingMessageSize() == b64Original.block.getMessageSize()); 1187 | } 1188 | blocks.add(new BlockAndValidity(b64, true, false, b64.getHash(), chainHeadHeight + 19, "b64")); 1189 | spendableOutputs.offer(b64Original.getCoinbaseOutput()); 1190 | 1191 | // Spend an output created in the block itself 1192 | // -> b42 (12) -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) 1193 | // 1194 | TransactionOutPointWithValue out19 = spendableOutputs.poll(); checkState(out19 != null);//TODO preconditions all the way up 1195 | 1196 | NewBlock b65 = createNextBlock(b64, chainHeadHeight + 20, null, null); 1197 | { 1198 | Transaction tx1 = new Transaction(params); 1199 | tx1.addOutput(out19.value, OP_TRUE_SCRIPT); 1200 | addOnlyInputToTransaction(tx1, out19, 0); 1201 | b65.addTransaction(tx1); 1202 | Transaction tx2 = new Transaction(params); 1203 | tx2.addOutput(ZERO, OP_TRUE_SCRIPT); 1204 | tx2.addInput(tx1.getHash(), 0, OP_TRUE_SCRIPT); 1205 | b65.addTransaction(tx2); 1206 | } 1207 | b65.solve(); 1208 | blocks.add(new BlockAndValidity(b65, true, false, b65.getHash(), chainHeadHeight + 20, "b65")); 1209 | spendableOutputs.offer(b65.getCoinbaseOutput()); 1210 | 1211 | // Attempt to spend an output created later in the same block 1212 | // -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) 1213 | // \-> b66 (20) 1214 | // 1215 | TransactionOutPointWithValue out20 = spendableOutputs.poll(); checkState(out20 != null); 1216 | 1217 | NewBlock b66 = createNextBlock(b65, chainHeadHeight + 21, null, null); 1218 | { 1219 | Transaction tx1 = new Transaction(params); 1220 | tx1.addOutput(out20.value, OP_TRUE_SCRIPT); 1221 | addOnlyInputToTransaction(tx1, out20, 0); 1222 | Transaction tx2 = new Transaction(params); 1223 | tx2.addOutput(ZERO, OP_TRUE_SCRIPT); 1224 | tx2.addInput(tx1.getHash(), 0, OP_NOP_SCRIPT); 1225 | b66.addTransaction(tx2); 1226 | b66.addTransaction(tx1); 1227 | } 1228 | b66.solve(); 1229 | blocks.add(new BlockAndValidity(b66, false, true, b65.getHash(), chainHeadHeight + 20, "b66")); 1230 | 1231 | // Attempt to double-spend a transaction created in a block 1232 | // -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) 1233 | // \-> b67 (20) 1234 | // 1235 | NewBlock b67 = createNextBlock(b65, chainHeadHeight + 21, null, null); 1236 | { 1237 | Transaction tx1 = new Transaction(params); 1238 | tx1.addOutput(out20.value, OP_TRUE_SCRIPT); 1239 | addOnlyInputToTransaction(tx1, out20, 0); 1240 | b67.addTransaction(tx1); 1241 | Transaction tx2 = new Transaction(params); 1242 | tx2.addOutput(ZERO, OP_TRUE_SCRIPT); 1243 | tx2.addInput(tx1.getHash(), 0, OP_NOP_SCRIPT); 1244 | b67.addTransaction(tx2); 1245 | Transaction tx3 = new Transaction(params); 1246 | tx3.addOutput(out20.value, OP_TRUE_SCRIPT); 1247 | tx3.addInput(tx1.getHash(), 0, OP_NOP_SCRIPT); 1248 | b67.addTransaction(tx3); 1249 | } 1250 | b67.solve(); 1251 | blocks.add(new BlockAndValidity(b67, false, true, b65.getHash(), chainHeadHeight + 20, "b67")); 1252 | 1253 | // A few more tests of block subsidy 1254 | // -> b43 (13) -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) 1255 | // \-> b68 (20) 1256 | // 1257 | NewBlock b68 = createNextBlock(b65, chainHeadHeight + 21, null, SATOSHI.multiply(10)); 1258 | { 1259 | Transaction tx = new Transaction(params); 1260 | tx.addOutput(out20.value.subtract(Coin.valueOf(9)), OP_TRUE_SCRIPT); 1261 | addOnlyInputToTransaction(tx, out20, 0); 1262 | b68.addTransaction(tx); 1263 | } 1264 | b68.solve(); 1265 | blocks.add(new BlockAndValidity(b68, false, true, b65.getHash(), chainHeadHeight + 20, "b68")); 1266 | 1267 | NewBlock b69 = createNextBlock(b65, chainHeadHeight + 21, null, SATOSHI.multiply(10)); 1268 | { 1269 | Transaction tx = new Transaction(params); 1270 | tx.addOutput(out20.value.subtract(Coin.valueOf(10)), OP_TRUE_SCRIPT); 1271 | addOnlyInputToTransaction(tx, out20, 0); 1272 | b69.addTransaction(tx); 1273 | } 1274 | b69.solve(); 1275 | blocks.add(new BlockAndValidity(b69, true, false, b69.getHash(), chainHeadHeight + 21, "b69")); 1276 | spendableOutputs.offer(b69.getCoinbaseOutput()); 1277 | 1278 | // Test spending the outpoint of a non-existent transaction 1279 | // -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) 1280 | // \-> b70 (21) 1281 | // 1282 | TransactionOutPointWithValue out21 = spendableOutputs.poll(); checkState(out21 != null); 1283 | NewBlock b70 = createNextBlock(b69, chainHeadHeight + 22, out21, null); 1284 | { 1285 | Transaction tx = new Transaction(params); 1286 | tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1287 | tx.addInput(new Sha256Hash("23c70ed7c0506e9178fc1a987f40a33946d4ad4c962b5ae3a52546da53af0c5c"), 0, 1288 | OP_NOP_SCRIPT); 1289 | b70.addTransaction(tx); 1290 | } 1291 | b70.solve(); 1292 | blocks.add(new BlockAndValidity(b70, false, true, b69.getHash(), chainHeadHeight + 21, "b70")); 1293 | 1294 | // Test accepting an invalid block which has the same hash as a valid one (via merkle tree tricks) 1295 | // -> b53 (14) -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b71 (21) 1296 | // \-> b72 (21) 1297 | // 1298 | NewBlock b72 = createNextBlock(b69, chainHeadHeight + 22, out21, null); 1299 | { 1300 | Transaction tx = new Transaction(params); 1301 | tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1302 | addOnlyInputToTransaction(tx, b72); 1303 | b72.addTransaction(tx); 1304 | } 1305 | b72.solve(); 1306 | 1307 | Block b71 = new Block(params, b72.block.bitcoinSerialize()); 1308 | b71.addTransaction(b72.block.getTransactions().get(2)); 1309 | checkState(b71.getHash().equals(b72.getHash())); 1310 | blocks.add(new BlockAndValidity(b71, false, true, b69.getHash(), chainHeadHeight + 21, "b71")); 1311 | blocks.add(new BlockAndValidity(b72, true, false, b72.getHash(), chainHeadHeight + 22, "b72")); 1312 | spendableOutputs.offer(b72.getCoinbaseOutput()); 1313 | 1314 | // Have some fun with invalid scripts and MAX_BLOCK_SIGOPS 1315 | // -> b55 (15) -> b57 (16) -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21) 1316 | // \-> b** (22) 1317 | // 1318 | TransactionOutPointWithValue out22 = spendableOutputs.poll(); checkState(out22 != null); 1319 | 1320 | NewBlock b73 = createNextBlock(b72, chainHeadHeight + 23, out22, null); 1321 | { 1322 | int sigOps = 0; 1323 | for (Transaction tx : b73.block.getTransactions()) { 1324 | sigOps += tx.getSigOpCount(); 1325 | } 1326 | Transaction tx = new Transaction(params); 1327 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIGOPS - sigOps + (int)Script.MAX_SCRIPT_ELEMENT_SIZE + 1 + 5 + 1]; 1328 | Arrays.fill(outputScript, (byte) OP_CHECKSIG); 1329 | // If we push an element that is too large, the CHECKSIGs after that push are still counted 1330 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps] = OP_PUSHDATA4; 1331 | Utils.uint32ToByteArrayLE(Script.MAX_SCRIPT_ELEMENT_SIZE + 1, outputScript, Block.MAX_BLOCK_SIGOPS - sigOps + 1); 1332 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 1333 | addOnlyInputToTransaction(tx, b73); 1334 | b73.addTransaction(tx); 1335 | } 1336 | b73.solve(); 1337 | blocks.add(new BlockAndValidity(b73, false, true, b72.getHash(), chainHeadHeight + 22, "b73")); 1338 | 1339 | NewBlock b74 = createNextBlock(b72, chainHeadHeight + 23, out22, null); 1340 | { 1341 | int sigOps = 0; 1342 | for (Transaction tx : b74.block.getTransactions()) { 1343 | sigOps += tx.getSigOpCount(); 1344 | } 1345 | Transaction tx = new Transaction(params); 1346 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIGOPS - sigOps + (int)Script.MAX_SCRIPT_ELEMENT_SIZE + 42]; 1347 | Arrays.fill(outputScript, (byte) OP_CHECKSIG); 1348 | // If we push an invalid element, all previous CHECKSIGs are counted 1349 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 1] = OP_PUSHDATA4; 1350 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 2] = (byte)0xfe; 1351 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 3] = (byte)0xff; 1352 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 4] = (byte)0xff; 1353 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 5] = (byte)0xff; 1354 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 1355 | addOnlyInputToTransaction(tx, b74); 1356 | b74.addTransaction(tx); 1357 | } 1358 | b74.solve(); 1359 | blocks.add(new BlockAndValidity(b74, false, true, b72.getHash(), chainHeadHeight + 22, "b74")); 1360 | 1361 | NewBlock b75 = createNextBlock(b72, chainHeadHeight + 23, out22, null); 1362 | { 1363 | int sigOps = 0; 1364 | for (Transaction tx : b75.block.getTransactions()) { 1365 | sigOps += tx.getSigOpCount(); 1366 | } 1367 | Transaction tx = new Transaction(params); 1368 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIGOPS - sigOps + (int)Script.MAX_SCRIPT_ELEMENT_SIZE + 42]; 1369 | Arrays.fill(outputScript, (byte) OP_CHECKSIG); 1370 | // If we push an invalid element, all subsequent CHECKSIGs are not counted 1371 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps] = OP_PUSHDATA4; 1372 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 1] = (byte)0xff; 1373 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 2] = (byte)0xff; 1374 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 3] = (byte)0xff; 1375 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps + 4] = (byte)0xff; 1376 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 1377 | addOnlyInputToTransaction(tx, b75); 1378 | b75.addTransaction(tx); 1379 | } 1380 | b75.solve(); 1381 | blocks.add(new BlockAndValidity(b75, true, false, b75.getHash(), chainHeadHeight + 23, "b75")); 1382 | spendableOutputs.offer(b75.getCoinbaseOutput()); 1383 | 1384 | TransactionOutPointWithValue out23 = spendableOutputs.poll(); checkState(out23 != null); 1385 | 1386 | NewBlock b76 = createNextBlock(b75, chainHeadHeight + 24, out23, null); 1387 | { 1388 | int sigOps = 0; 1389 | for (Transaction tx : b76.block.getTransactions()) { 1390 | sigOps += tx.getSigOpCount(); 1391 | } 1392 | Transaction tx = new Transaction(params); 1393 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIGOPS - sigOps + (int)Script.MAX_SCRIPT_ELEMENT_SIZE + 1 + 5]; 1394 | Arrays.fill(outputScript, (byte) OP_CHECKSIG); 1395 | // If we push an element that is filled with CHECKSIGs, they (obviously) arent counted 1396 | outputScript[Block.MAX_BLOCK_SIGOPS - sigOps] = OP_PUSHDATA4; 1397 | Utils.uint32ToByteArrayLE(Block.MAX_BLOCK_SIGOPS, outputScript, Block.MAX_BLOCK_SIGOPS - sigOps + 1); 1398 | tx.addOutput(new TransactionOutput(params, tx, SATOSHI, outputScript)); 1399 | addOnlyInputToTransaction(tx, b76); 1400 | b76.addTransaction(tx); 1401 | } 1402 | b76.solve(); 1403 | blocks.add(new BlockAndValidity(b76, true, false, b76.getHash(), chainHeadHeight + 24, "b76")); 1404 | spendableOutputs.offer(b76.getCoinbaseOutput()); 1405 | 1406 | // Test transaction resurrection 1407 | // -> b77 (24) -> b78 (25) -> b79 (26) 1408 | // \-> b80 (25) -> b81 (26) -> b82 (27) 1409 | // b78 creates a tx, which is spent in b79. after b82, both should be in mempool 1410 | // 1411 | TransactionOutPointWithValue out24 = checkNotNull(spendableOutputs.poll()); 1412 | TransactionOutPointWithValue out25 = checkNotNull(spendableOutputs.poll()); 1413 | TransactionOutPointWithValue out26 = checkNotNull(spendableOutputs.poll()); 1414 | TransactionOutPointWithValue out27 = checkNotNull(spendableOutputs.poll()); 1415 | 1416 | NewBlock b77 = createNextBlock(b76, chainHeadHeight + 25, out24, null); 1417 | blocks.add(new BlockAndValidity(b77, true, false, b77.getHash(), chainHeadHeight + 25, "b77")); 1418 | spendableOutputs.offer(b77.getCoinbaseOutput()); 1419 | 1420 | NewBlock b78 = createNextBlock(b77, chainHeadHeight + 26, out25, null); 1421 | Transaction b78tx = new Transaction(params); 1422 | { 1423 | b78tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1424 | addOnlyInputToTransaction(b78tx, b77); 1425 | b78.addTransaction(b78tx); 1426 | } 1427 | b78.solve(); 1428 | blocks.add(new BlockAndValidity(b78, true, false, b78.getHash(), chainHeadHeight + 26, "b78")); 1429 | 1430 | NewBlock b79 = createNextBlock(b78, chainHeadHeight + 27, out26, null); 1431 | Transaction b79tx = new Transaction(params); 1432 | 1433 | { 1434 | b79tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1435 | b79tx.addInput(b78tx.getHash(), 0, OP_NOP_SCRIPT); 1436 | b79.addTransaction(b79tx); 1437 | } 1438 | b79.solve(); 1439 | blocks.add(new BlockAndValidity(b79, true, false, b79.getHash(), chainHeadHeight + 27, "b79")); 1440 | 1441 | blocks.add(new MemoryPoolState(new HashSet(), "post-b79 empty mempool")); 1442 | 1443 | NewBlock b80 = createNextBlock(b77, chainHeadHeight + 26, out25, null); 1444 | blocks.add(new BlockAndValidity(b80, true, false, b79.getHash(), chainHeadHeight + 27, "b80")); 1445 | spendableOutputs.offer(b80.getCoinbaseOutput()); 1446 | 1447 | NewBlock b81 = createNextBlock(b80, chainHeadHeight + 27, out26, null); 1448 | blocks.add(new BlockAndValidity(b81, true, false, b79.getHash(), chainHeadHeight + 27, "b81")); 1449 | spendableOutputs.offer(b81.getCoinbaseOutput()); 1450 | 1451 | NewBlock b82 = createNextBlock(b81, chainHeadHeight + 28, out27, null); 1452 | blocks.add(new BlockAndValidity(b82, true, false, b82.getHash(), chainHeadHeight + 28, "b82")); 1453 | spendableOutputs.offer(b82.getCoinbaseOutput()); 1454 | 1455 | HashSet post82Mempool = new HashSet(); 1456 | post82Mempool.add(new InventoryItem(InventoryItem.Type.Transaction, b78tx.getHash())); 1457 | post82Mempool.add(new InventoryItem(InventoryItem.Type.Transaction, b79tx.getHash())); 1458 | blocks.add(new MemoryPoolState(post82Mempool, "post-b82 tx resurrection")); 1459 | 1460 | // Test invalid opcodes in dead execution paths. 1461 | // -> b81 (26) -> b82 (27) -> b83 (28) 1462 | // b83 creates a tx which contains a transaction script with an invalid opcode in a dead execution path: 1463 | // OP_FALSE OP_IF OP_INVALIDOPCODE OP_ELSE OP_TRUE OP_ENDIF 1464 | // 1465 | TransactionOutPointWithValue out28 = spendableOutputs.poll(); Preconditions.checkState(out28 != null); 1466 | 1467 | NewBlock b83 = createNextBlock(b82, chainHeadHeight + 29, null, null); 1468 | { 1469 | Transaction tx1 = new Transaction(params); 1470 | tx1.addOutput(new TransactionOutput(params, tx1, out28.value, 1471 | new byte[]{OP_IF, (byte) OP_INVALIDOPCODE, OP_ELSE, OP_TRUE, OP_ENDIF})); 1472 | addOnlyInputToTransaction(tx1, out28, 0); 1473 | b83.addTransaction(tx1); 1474 | Transaction tx2 = new Transaction(params); 1475 | tx2.addOutput(new TransactionOutput(params, tx2, ZERO, new byte[]{OP_TRUE})); 1476 | tx2.addInput(new TransactionInput(params, tx2, new byte[]{OP_FALSE}, 1477 | new TransactionOutPoint(params, 0, tx1.getHash()))); 1478 | b83.addTransaction(tx2); 1479 | } 1480 | b83.solve(); 1481 | blocks.add(new BlockAndValidity(b83, true, false, b83.getHash(), chainHeadHeight + 29, "b83")); 1482 | spendableOutputs.offer(b83.getCoinbaseOutput()); 1483 | 1484 | // Reorg on/off blocks that have OP_RETURN in them (and try to spend them) 1485 | // -> b81 (26) -> b82 (27) -> b83 (28) -> b84 (29) -> b87 (30) -> b88 (31) 1486 | // \-> b85 (29) -> b86 (30) \-> b89 (32) 1487 | // 1488 | TransactionOutPointWithValue out29 = spendableOutputs.poll(); Preconditions.checkState(out29 != null); 1489 | TransactionOutPointWithValue out30 = spendableOutputs.poll(); Preconditions.checkState(out30 != null); 1490 | TransactionOutPointWithValue out31 = spendableOutputs.poll(); Preconditions.checkState(out31 != null); 1491 | TransactionOutPointWithValue out32 = spendableOutputs.poll(); Preconditions.checkState(out32 != null); 1492 | 1493 | NewBlock b84 = createNextBlock(b83, chainHeadHeight + 30, out29, null); 1494 | Transaction b84tx1 = new Transaction(params); 1495 | { 1496 | b84tx1.addOutput(new TransactionOutput(params, b84tx1, ZERO, new byte[]{OP_RETURN})); 1497 | b84tx1.addOutput(new TransactionOutput(params, b84tx1, ZERO, new byte[]{OP_TRUE})); 1498 | b84tx1.addOutput(new TransactionOutput(params, b84tx1, ZERO, new byte[]{OP_TRUE})); 1499 | b84tx1.addOutput(new TransactionOutput(params, b84tx1, ZERO, new byte[]{OP_TRUE})); 1500 | b84tx1.addOutput(new TransactionOutput(params, b84tx1, ZERO, new byte[]{OP_TRUE})); 1501 | addOnlyInputToTransaction(b84tx1, b84); 1502 | b84.addTransaction(b84tx1); 1503 | 1504 | Transaction tx2 = new Transaction(params); 1505 | tx2.addOutput(new TransactionOutput(params, tx2, ZERO, new byte[]{OP_RETURN})); 1506 | tx2.addOutput(new TransactionOutput(params, tx2, ZERO, new byte[]{OP_RETURN})); 1507 | tx2.addInput(new TransactionInput(params, tx2, new byte[]{OP_TRUE}, new TransactionOutPoint(params, 1, b84tx1))); 1508 | b84.addTransaction(tx2); 1509 | 1510 | Transaction tx3 = new Transaction(params); 1511 | tx3.addOutput(new TransactionOutput(params, tx3, ZERO, new byte[]{OP_RETURN})); 1512 | tx3.addOutput(new TransactionOutput(params, tx3, ZERO, new byte[]{OP_TRUE})); 1513 | tx3.addInput(new TransactionInput(params, tx3, new byte[]{OP_TRUE}, new TransactionOutPoint(params, 2, b84tx1))); 1514 | b84.addTransaction(tx3); 1515 | 1516 | Transaction tx4 = new Transaction(params); 1517 | tx4.addOutput(new TransactionOutput(params, tx4, ZERO, new byte[]{OP_TRUE})); 1518 | tx4.addOutput(new TransactionOutput(params, tx4, ZERO, new byte[]{OP_RETURN})); 1519 | tx4.addInput(new TransactionInput(params, tx4, new byte[]{OP_TRUE}, new TransactionOutPoint(params, 3, b84tx1))); 1520 | b84.addTransaction(tx4); 1521 | 1522 | Transaction tx5 = new Transaction(params); 1523 | tx5.addOutput(new TransactionOutput(params, tx5, ZERO, new byte[]{OP_RETURN})); 1524 | tx5.addInput(new TransactionInput(params, tx5, new byte[]{OP_TRUE}, new TransactionOutPoint(params, 4, b84tx1))); 1525 | b84.addTransaction(tx5); 1526 | } 1527 | b84.solve(); 1528 | blocks.add(new BlockAndValidity(b84, true, false, b84.getHash(), chainHeadHeight + 30, "b84")); 1529 | spendableOutputs.offer(b84.getCoinbaseOutput()); 1530 | 1531 | NewBlock b85 = createNextBlock(b83, chainHeadHeight + 30, out29, null); 1532 | blocks.add(new BlockAndValidity(b85, true, false, b84.getHash(), chainHeadHeight + 30, "b85")); 1533 | 1534 | NewBlock b86 = createNextBlock(b85, chainHeadHeight + 31, out30, null); 1535 | blocks.add(new BlockAndValidity(b86, true, false, b86.getHash(), chainHeadHeight + 31, "b86")); 1536 | 1537 | NewBlock b87 = createNextBlock(b84, chainHeadHeight + 31, out30, null); 1538 | blocks.add(new BlockAndValidity(b87, true, false, b86.getHash(), chainHeadHeight + 31, "b87")); 1539 | spendableOutputs.offer(b87.getCoinbaseOutput()); 1540 | 1541 | NewBlock b88 = createNextBlock(b87, chainHeadHeight + 32, out31, null); 1542 | blocks.add(new BlockAndValidity(b88, true, false, b88.getHash(), chainHeadHeight + 32, "b88")); 1543 | spendableOutputs.offer(b88.getCoinbaseOutput()); 1544 | 1545 | NewBlock b89 = createNextBlock(b88, chainHeadHeight + 33, out32, null); 1546 | { 1547 | Transaction tx = new Transaction(params); 1548 | tx.addOutput(new TransactionOutput(params, tx, ZERO, new byte[] {OP_TRUE})); 1549 | tx.addInput(new TransactionInput(params, tx, new byte[]{OP_TRUE}, new TransactionOutPoint(params, 0, b84tx1))); 1550 | b89.addTransaction(tx); 1551 | b89.solve(); 1552 | } 1553 | blocks.add(new BlockAndValidity(b89, false, true, b88.getHash(), chainHeadHeight + 32, "b89")); 1554 | 1555 | // The remaining tests arent designed to fit in the standard flow, and thus must always come last 1556 | // Add new tests here. 1557 | 1558 | //TODO: Explicitly address MoneyRange() checks 1559 | 1560 | if (!runBarelyExpensiveTests) { 1561 | if (outStream != null) 1562 | outStream.close(); 1563 | 1564 | // (finally) return the created chain 1565 | return ret; 1566 | } 1567 | 1568 | // Test massive reorgs (in terms of block count/size) 1569 | // -> b81 (26) -> b82 (27) -> b83 (28) -> b84 (29) -> b87 (30) -> b88 (31) -> lots of blocks -> b1000 1570 | // \-> b85 (29) -> b86 (30) \-> lots more blocks 1571 | // 1572 | NewBlock largeReorgFinal; 1573 | int LARGE_REORG_SIZE = 1008; // +/- a week of blocks 1574 | int largeReorgLastHeight = chainHeadHeight + 33 + LARGE_REORG_SIZE + 1; 1575 | { 1576 | NewBlock nextBlock = b88; 1577 | int nextHeight = chainHeadHeight + 33; 1578 | TransactionOutPointWithValue largeReorgOutput = out32; 1579 | for (int i = 0; i < LARGE_REORG_SIZE; i++) { 1580 | nextBlock = createNextBlock(nextBlock, nextHeight, largeReorgOutput, null); 1581 | Transaction tx = new Transaction(params); 1582 | byte[] outputScript = new byte[Block.MAX_BLOCK_SIZE - nextBlock.block.getMessageSize() - 65]; 1583 | Arrays.fill(outputScript, (byte) OP_FALSE); 1584 | tx.addOutput(new TransactionOutput(params, tx, ZERO, outputScript)); 1585 | addOnlyInputToTransaction(tx, nextBlock); 1586 | nextBlock.addTransaction(tx); 1587 | nextBlock.solve(); 1588 | blocks.add(new BlockAndValidity(nextBlock, true, false, nextBlock.getHash(), nextHeight++, "large reorg initial blocks " + i)); 1589 | spendableOutputs.offer(nextBlock.getCoinbaseOutput()); 1590 | largeReorgOutput = spendableOutputs.poll(); 1591 | } 1592 | NewBlock reorgBase = b88; 1593 | int reorgBaseHeight = chainHeadHeight + 33; 1594 | for (int i = 0; i < LARGE_REORG_SIZE; i++) { 1595 | reorgBase = createNextBlock(reorgBase, reorgBaseHeight++, null, null); 1596 | blocks.add(new BlockAndValidity(reorgBase, true, false, nextBlock.getHash(), nextHeight - 1, "large reorg reorg block " + i)); 1597 | } 1598 | reorgBase = createNextBlock(reorgBase, reorgBaseHeight, null, null); 1599 | blocks.add(new BlockAndValidity(reorgBase, true, false, reorgBase.getHash(), reorgBaseHeight, "large reorg reorging block")); 1600 | nextBlock = createNextBlock(nextBlock, nextHeight, null, null); 1601 | blocks.add(new BlockAndValidity(nextBlock, true, false, reorgBase.getHash(), nextHeight++, "large reorg second reorg initial")); 1602 | spendableOutputs.offer(nextBlock.getCoinbaseOutput()); 1603 | nextBlock = createNextBlock(nextBlock, nextHeight, null, null); spendableOutputs.poll(); 1604 | blocks.add(new BlockAndValidity(nextBlock, true, false, nextBlock.getHash(), nextHeight++, "large reorg second reorg")); 1605 | spendableOutputs.offer(nextBlock.getCoinbaseOutput()); 1606 | largeReorgFinal = nextBlock; 1607 | } 1608 | ret.maximumReorgBlockCount = Math.max(ret.maximumReorgBlockCount, LARGE_REORG_SIZE + 2); 1609 | 1610 | // Test massive reorgs (in terms of tx count) 1611 | // -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21) -> b1001 (22) -> lots of outputs -> lots of spends 1612 | // Reorg back to: 1613 | // -> b60 (17) -> b64 (18) -> b65 (19) -> b69 (20) -> b72 (21) -> b1001 (22) -> empty blocks 1614 | // 1615 | NewBlock b1001 = createNextBlock(largeReorgFinal, largeReorgLastHeight + 1, spendableOutputs.poll(), null); 1616 | blocks.add(new BlockAndValidity(b1001, true, false, b1001.getHash(), largeReorgLastHeight + 1, "b1001")); 1617 | spendableOutputs.offer(b1001.getCoinbaseOutput()); 1618 | int heightAfter1001 = largeReorgLastHeight + 2; 1619 | 1620 | if (runExpensiveTests) { 1621 | // No way you can fit this test in memory 1622 | Preconditions.checkArgument(blockStorageFile != null); 1623 | 1624 | NewBlock lastBlock = b1001; 1625 | TransactionOutPoint lastOutput = new TransactionOutPoint(params, 1, b1001.block.getTransactions().get(1).getHash()); 1626 | int blockCountAfter1001; 1627 | int nextHeight = heightAfter1001; 1628 | 1629 | List hashesToSpend = new LinkedList(); // all index 0 1630 | final int TRANSACTION_CREATION_BLOCKS = 100; 1631 | for (blockCountAfter1001 = 0; blockCountAfter1001 < TRANSACTION_CREATION_BLOCKS; blockCountAfter1001++) { 1632 | NewBlock block = createNextBlock(lastBlock, nextHeight++, null, null); 1633 | while (block.block.getMessageSize() < Block.MAX_BLOCK_SIZE - 500) { 1634 | Transaction tx = new Transaction(params); 1635 | tx.addInput(lastOutput.getHash(), lastOutput.getIndex(), OP_NOP_SCRIPT); 1636 | tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1637 | tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1638 | lastOutput = new TransactionOutPoint(params, 1, tx.getHash()); 1639 | hashesToSpend.add(tx.getHash()); 1640 | block.addTransaction(tx); 1641 | } 1642 | block.solve(); 1643 | blocks.add(new BlockAndValidity(block, true, false, block.getHash(), nextHeight-1, 1644 | "post-b1001 repeated transaction generator " + blockCountAfter1001 + "/" + TRANSACTION_CREATION_BLOCKS).setSendOnce(true)); 1645 | lastBlock = block; 1646 | } 1647 | 1648 | Iterator hashes = hashesToSpend.iterator(); 1649 | for (int i = 0; hashes.hasNext(); i++) { 1650 | NewBlock block = createNextBlock(lastBlock, nextHeight++, null, null); 1651 | while (block.block.getMessageSize() < Block.MAX_BLOCK_SIZE - 500 && hashes.hasNext()) { 1652 | Transaction tx = new Transaction(params); 1653 | tx.addInput(hashes.next(), 0, OP_NOP_SCRIPT); 1654 | tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1655 | block.addTransaction(tx); 1656 | } 1657 | block.solve(); 1658 | blocks.add(new BlockAndValidity(block, true, false, block.getHash(), nextHeight-1, 1659 | "post-b1001 repeated transaction spender " + i).setSendOnce(true)); 1660 | lastBlock = block; 1661 | blockCountAfter1001++; 1662 | } 1663 | 1664 | // Reorg back to b1001 + empty blocks 1665 | Sha256Hash firstHash = lastBlock.getHash(); 1666 | int height = nextHeight-1; 1667 | nextHeight = heightAfter1001; 1668 | lastBlock = b1001; 1669 | for (int i = 0; i < blockCountAfter1001; i++) { 1670 | NewBlock block = createNextBlock(lastBlock, nextHeight++, null, null); 1671 | blocks.add(new BlockAndValidity(block, true, false, firstHash, height, "post-b1001 empty reorg block " + i + "/" + blockCountAfter1001)); 1672 | lastBlock = block; 1673 | } 1674 | 1675 | // Try to spend from the other chain 1676 | NewBlock b1002 = createNextBlock(lastBlock, nextHeight, null, null); 1677 | { 1678 | Transaction tx = new Transaction(params); 1679 | tx.addInput(hashesToSpend.get(0), 0, OP_NOP_SCRIPT); 1680 | tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1681 | b1002.addTransaction(tx); 1682 | } 1683 | b1002.solve(); 1684 | blocks.add(new BlockAndValidity(b1002, false, true, firstHash, height, "b1002")); 1685 | 1686 | // Now actually reorg 1687 | NewBlock b1003 = createNextBlock(lastBlock, nextHeight, null, null); 1688 | blocks.add(new BlockAndValidity(b1003, true, false, b1003.getHash(), nextHeight, "b1003")); 1689 | 1690 | // Now try to spend again 1691 | NewBlock b1004 = createNextBlock(b1003, nextHeight + 1, null, null); 1692 | { 1693 | Transaction tx = new Transaction(params); 1694 | tx.addInput(hashesToSpend.get(0), 0, OP_NOP_SCRIPT); 1695 | tx.addOutput(ZERO, OP_TRUE_SCRIPT); 1696 | b1004.addTransaction(tx); 1697 | } 1698 | b1004.solve(); 1699 | blocks.add(new BlockAndValidity(b1004, false, true, b1003.getHash(), nextHeight, "b1004")); 1700 | 1701 | ret.maximumReorgBlockCount = Math.max(ret.maximumReorgBlockCount, blockCountAfter1001); 1702 | } 1703 | 1704 | if (outStream != null) 1705 | outStream.close(); 1706 | 1707 | // (finally) return the created chain 1708 | return ret; 1709 | } 1710 | 1711 | private byte uniquenessCounter = 0; 1712 | private NewBlock createNextBlock(Block baseBlock, int nextBlockHeight, @Nullable TransactionOutPointWithValue prevOut, 1713 | Coin additionalCoinbaseValue) throws ScriptException { 1714 | Integer height = blockToHeightMap.get(baseBlock.getHash()); 1715 | if (height != null) 1716 | checkState(height == nextBlockHeight - 1); 1717 | Coin coinbaseValue = FIFTY_COINS.shiftRight(nextBlockHeight / params.getSubsidyDecreaseBlockCount()) 1718 | .add((prevOut != null ? prevOut.value.subtract(SATOSHI) : ZERO)) 1719 | .add(additionalCoinbaseValue == null ? ZERO : additionalCoinbaseValue); 1720 | Block block = baseBlock.createNextBlockWithCoinbase(coinbaseOutKeyPubKey, coinbaseValue); 1721 | Transaction t = new Transaction(params); 1722 | if (prevOut != null) { 1723 | // Entirely invalid scriptPubKey to ensure we aren't pre-verifying too much 1724 | t.addOutput(new TransactionOutput(params, t, ZERO, new byte[] {(byte)(new Random().nextInt() & 0xff), uniquenessCounter++})); 1725 | // Spendable output 1726 | t.addOutput(new TransactionOutput(params, t, SATOSHI, new byte[] {OP_1})); 1727 | addOnlyInputToTransaction(t, prevOut); 1728 | block.addTransaction(t); 1729 | block.solve(); 1730 | } 1731 | return new NewBlock(block, prevOut == null ? null : new TransactionOutPointWithValue(t, 1)); 1732 | } 1733 | private NewBlock createNextBlock(NewBlock baseBlock, int nextBlockHeight, @Nullable TransactionOutPointWithValue prevOut, 1734 | Coin additionalCoinbaseValue) throws ScriptException { 1735 | return createNextBlock(baseBlock.block, nextBlockHeight, prevOut, additionalCoinbaseValue); 1736 | } 1737 | 1738 | private void addOnlyInputToTransaction(Transaction t, NewBlock block) throws ScriptException { 1739 | addOnlyInputToTransaction(t, block.getSpendableOutput(), TransactionInput.NO_SEQUENCE); 1740 | } 1741 | 1742 | private void addOnlyInputToTransaction(Transaction t, TransactionOutPointWithValue prevOut) throws ScriptException { 1743 | addOnlyInputToTransaction(t, prevOut, TransactionInput.NO_SEQUENCE); 1744 | } 1745 | 1746 | private void addOnlyInputToTransaction(Transaction t, TransactionOutPointWithValue prevOut, long sequence) throws ScriptException { 1747 | TransactionInput input = new TransactionInput(params, t, new byte[]{}, prevOut.outpoint); 1748 | input.setSequenceNumber(sequence); 1749 | t.addInput(input); 1750 | 1751 | if (prevOut.scriptPubKey.getChunks().get(0).equalsOpCode(OP_TRUE)) { 1752 | input.setScriptSig(new ScriptBuilder().op(OP_1).build()); 1753 | } else { 1754 | // Sign input 1755 | checkState(prevOut.scriptPubKey.isSentToRawPubKey()); 1756 | Sha256Hash hash = t.hashForSignature(0, prevOut.scriptPubKey, SigHash.ALL, false); 1757 | input.setScriptSig(ScriptBuilder.createInputScript( 1758 | new TransactionSignature(coinbaseOutKey.sign(hash), SigHash.ALL, false)) 1759 | ); 1760 | } 1761 | } 1762 | 1763 | /** 1764 | * Represents a block which is sent to the tested application and which the application must either reject or accept, 1765 | * depending on the flags in the rule 1766 | */ 1767 | class BlockAndValidity extends Rule { 1768 | Block block; 1769 | Sha256Hash blockHash; 1770 | boolean connects; 1771 | boolean throwsException; 1772 | boolean sendOnce; // We can throw away the memory for this block once we send it the first time (if bitcoind asks again, its broken) 1773 | Sha256Hash hashChainTipAfterBlock; 1774 | int heightAfterBlock; 1775 | 1776 | public BlockAndValidity(Block block, boolean connects, boolean throwsException, Sha256Hash hashChainTipAfterBlock, int heightAfterBlock, String blockName) { 1777 | super(blockName); 1778 | if (connects && throwsException) 1779 | throw new RuntimeException("A block cannot connect if an exception was thrown while adding it."); 1780 | this.block = block; 1781 | this.blockHash = block.getHash(); 1782 | this.connects = connects; 1783 | this.throwsException = throwsException; 1784 | this.hashChainTipAfterBlock = hashChainTipAfterBlock; 1785 | this.heightAfterBlock = heightAfterBlock; 1786 | 1787 | // Keep track of the set of blocks indexed by hash 1788 | hashHeaderMap.put(block.getHash(), block.cloneAsHeader()); 1789 | 1790 | // Double-check that we are always marking any given block at the same height 1791 | Integer height = blockToHeightMap.get(hashChainTipAfterBlock); 1792 | if (height != null) 1793 | checkState(height == heightAfterBlock); 1794 | else 1795 | blockToHeightMap.put(hashChainTipAfterBlock, heightAfterBlock); 1796 | } 1797 | 1798 | public BlockAndValidity(NewBlock block, boolean connects, boolean throwsException, Sha256Hash hashChainTipAfterBlock, int heightAfterBlock, String blockName) { 1799 | this(block.block, connects, throwsException, hashChainTipAfterBlock, heightAfterBlock, blockName); 1800 | coinbaseBlockMap.put(block.getCoinbaseOutput().outpoint.getHash(), block.getHash()); 1801 | Integer blockHeight = blockToHeightMap.get(block.block.getPrevBlockHash()); 1802 | if (blockHeight != null) { 1803 | blockHeight++; 1804 | for (Transaction t : block.block.getTransactions()) 1805 | for (TransactionInput in : t.getInputs()) { 1806 | Sha256Hash blockSpendingHash = coinbaseBlockMap.get(in.getOutpoint().getHash()); 1807 | checkState(blockSpendingHash == null || blockToHeightMap.get(blockSpendingHash) == null || 1808 | blockToHeightMap.get(blockSpendingHash) == blockHeight - params.getSpendableCoinbaseDepth()); 1809 | } 1810 | } 1811 | } 1812 | 1813 | public BlockAndValidity setSendOnce(boolean sendOnce) { 1814 | this.sendOnce = sendOnce; 1815 | return this; 1816 | } 1817 | } 1818 | } 1819 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | BitcoindComparisonTool.jar is a tool that uses the bitcoinj library 2 | to generate very-low-difficulty blockchains that test edge-cases in 3 | block chain logic. 4 | 5 | Full implementations of the Bitcoin protocol can use it to help 6 | test that their logic for handling valid/invalid blocks matches 7 | the reference implementation. 8 | 9 | Improvements are welcome; the source code used to generate the blocks 10 | is in FullBlockTestGenerator.java. The source that drives the tool can 11 | be found at 12 | https://github.com/TheBlueMatt/bitcoinj/blob/blocktester/core/src/test/java/org/bitcoinj/core/BitcoindComparisonTool.java 13 | -------------------------------------------------------------------------------- /pull-tests-f56eec3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TheBlueMatt/test-scripts/211c2e72c4b2d74bb3a2d524a87622eec0d5a47a/pull-tests-f56eec3.jar --------------------------------------------------------------------------------