@Test public void testCoinbaseHeightTestnet() throws Exception { // Testnet block 21066 (hash 0000000004053156021d8e42459d284220a7f6e087bf78f30179c3703ca4eefa) // contains a coinbase transaction whose height is two bytes, which is // shorter than we see in most other cases. Block block = TestNet3Params.get() .getDefaultSerializer() .makeBlock( ByteStreams.toByteArray(getClass().getResourceAsStream("block_testnet21066.dat"))); // Check block. assertEquals( "0000000004053156021d8e42459d284220a7f6e087bf78f30179c3703ca4eefa", block.getHashAsString()); block.verify(21066, EnumSet.of(Block.VerifyFlag.HEIGHT_IN_COINBASE)); // Testnet block 32768 (hash 000000007590ba495b58338a5806c2b6f10af921a70dbd814e0da3c6957c0c03) // contains a coinbase transaction whose height is three bytes, but could // fit in two bytes. This test primarily ensures script encoding checks // are applied correctly. block = TestNet3Params.get() .getDefaultSerializer() .makeBlock( ByteStreams.toByteArray(getClass().getResourceAsStream("block_testnet32768.dat"))); // Check block. assertEquals( "000000007590ba495b58338a5806c2b6f10af921a70dbd814e0da3c6957c0c03", block.getHashAsString()); block.verify(32768, EnumSet.of(Block.VerifyFlag.HEIGHT_IN_COINBASE)); }
@Test public void testProofOfWork() throws Exception { // This params accepts any difficulty target. NetworkParameters params = UnitTestParams.get(); Block block = params.getDefaultSerializer().makeBlock(blockBytes); block.setNonce(12346); try { block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(Block.VerifyFlag.class)); fail(); } catch (VerificationException e) { // Expected. } // Blocks contain their own difficulty target. The BlockChain verification mechanism is what // stops real blocks // from containing artificially weak difficulties. block.setDifficultyTarget(Block.EASIEST_DIFFICULTY_TARGET); // Now it should pass. block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(Block.VerifyFlag.class)); // Break the nonce again at the lower difficulty level so we can try solving for it. block.setNonce(1); try { block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(Block.VerifyFlag.class)); fail(); } catch (VerificationException e) { // Expected to fail as the nonce is no longer correct. } // Should find an acceptable nonce. block.solve(); block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(Block.VerifyFlag.class)); assertEquals(block.getNonce(), 2); }
@Test public void testBlockVerification() throws Exception { Block block = params.getDefaultSerializer().makeBlock(blockBytes); block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(Block.VerifyFlag.class)); assertEquals( "00000000a6e5eb79dcec11897af55e90cd571a4335383a3ccfbc12ec81085935", block.getHashAsString()); }
@Test public void nemesisBlockIsVerifiable() { // Arrange: final Block block = this.loadNemesisBlock(); // Assert: Assert.assertThat(block.verify(), IsEqual.equalTo(true)); }
private synchronized boolean add(Block block, boolean tryConnecting) throws BlockStoreException, VerificationException, ScriptException { if (System.currentTimeMillis() - statsLastTime > 1000) { // More than a second passed since last stats logging. log.info("{} blocks per second", statsBlocksAdded); statsLastTime = System.currentTimeMillis(); statsBlocksAdded = 0; } // We check only the chain head for double adds here to avoid potentially expensive block chain // misses. if (block.equals(chainHead.getHeader())) { // Duplicate add of the block at the top of the chain, can be a natural artifact of the // download process. return true; } // Prove the block is internally valid: hash is lower than target, merkle root is correct and so // on. try { block.verify(); } catch (VerificationException e) { log.error("Failed to verify block:", e); log.error(block.toString()); throw e; } // Try linking it to a place in the currently known blocks. StoredBlock storedPrev = blockStore.get(block.getPrevBlockHash()); if (storedPrev == null) { // We can't find the previous block. Probably we are still in the process of downloading the // chain and a // block was solved whilst we were doing it. We put it to one side and try to connect it later // when we // have more blocks. log.warn("Block does not connect: {}", block.getHashAsString()); unconnectedBlocks.add(block); return false; } else { // It connects to somewhere on the chain. Not necessarily the top of the best known chain. // // Create a new StoredBlock from this block. It will throw away the transaction data so when // block goes // out of scope we will reclaim the used memory. StoredBlock newStoredBlock = storedPrev.build(block); checkDifficultyTransitions(storedPrev, newStoredBlock); blockStore.put(newStoredBlock); // block.transactions may be null here if we received only a header and not a full block. This // does not // happen currently but might in future if getheaders is implemented. connectBlock(newStoredBlock, storedPrev, block.transactions); } if (tryConnecting) tryConnectingUnconnected(); statsBlocksAdded++; return true; }
@Test public void testBadTransactions() throws Exception { Block block = params.getDefaultSerializer().makeBlock(blockBytes); // Re-arrange so the coinbase transaction is not first. Transaction tx1 = block.transactions.get(0); Transaction tx2 = block.transactions.get(1); block.transactions.set(0, tx2); block.transactions.set(1, tx1); try { block.verify(Block.BLOCK_HEIGHT_GENESIS, EnumSet.noneOf(Block.VerifyFlag.class)); fail(); } catch (VerificationException e) { // We should get here. } }
@Test public void testReceiveCoinbaseTransaction() throws Exception { // Block 169482 (hash 0000000000000756935f1ee9d5987857b604046f846d3df56d024cdb5f368665) // contains coinbase transactions that are mining pool shares. // The private key MINERS_KEY is used to check transactions are received by a wallet correctly. // The address for this private key is 1GqtGtn4fctXuKxsVzRPSLmYWN1YioLi9y. final String MINING_PRIVATE_KEY = "5JDxPrBRghF1EvSBjDigywqfmAjpHPmTJxYtQTYJxJRHLLQA4mG"; final long BLOCK_NONCE = 3973947400L; final Coin BALANCE_AFTER_BLOCK = Coin.valueOf(22223642); final NetworkParameters PARAMS = MainNetParams.get(); Block block169482 = PARAMS .getDefaultSerializer() .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block169482.dat"))); // Check block. assertNotNull(block169482); block169482.verify(169482, EnumSet.noneOf(Block.VerifyFlag.class)); assertEquals(BLOCK_NONCE, block169482.getNonce()); StoredBlock storedBlock = new StoredBlock(block169482, BigInteger.ONE, 169482); // Nonsense work - not used in test. // Create a wallet contain the miner's key that receives a spend from a coinbase. ECKey miningKey = DumpedPrivateKey.fromBase58(PARAMS, MINING_PRIVATE_KEY).getKey(); assertNotNull(miningKey); Context context = new Context(PARAMS); Wallet wallet = new Wallet(context); wallet.importKey(miningKey); // Initial balance should be zero by construction. assertEquals(Coin.ZERO, wallet.getBalance()); // Give the wallet the first transaction in the block - this is the coinbase tx. List<Transaction> transactions = block169482.getTransactions(); assertNotNull(transactions); wallet.receiveFromBlock(transactions.get(0), storedBlock, NewBlockType.BEST_CHAIN, 0); // Coinbase transaction should have been received successfully but be unavailable to spend (too // young). assertEquals(BALANCE_AFTER_BLOCK, wallet.getBalance(BalanceType.ESTIMATED)); assertEquals(Coin.ZERO, wallet.getBalance(BalanceType.AVAILABLE)); }
@Test public void testReceiveCoinbaseTransaction() throws Exception { // Block 169482 (hash 0000000000000756935f1ee9d5987857b604046f846d3df56d024cdb5f368665) // contains coinbase transactions that are mining pool shares. // The private key MINERS_KEY is used to check transactions are received by a wallet correctly. byte[] blockAsBytes = getBytes(getClass().getResourceAsStream("block169482.dat")); // Create block 169482. Block block = new Block(params, blockAsBytes); // Check block. assertNotNull(block); block.verify(); assertEquals(BLOCK_NONCE, block.getNonce()); StoredBlock storedBlock = new StoredBlock( block, BigInteger.ONE, BLOCK_OF_INTEREST); // Nonsense work - not used in test. // Create a wallet contain the miner's key that receives a spend from a coinbase. ECKey miningKey = (new DumpedPrivateKey(params, MINING_PRIVATE_KEY)).getKey(); assertNotNull(miningKey); Wallet wallet = new Wallet(params); wallet.addKey(miningKey); // Initial balance should be zero by construction. assertEquals(BigInteger.ZERO, wallet.getBalance()); // Give the wallet the first transaction in the block - this is the coinbase tx. List<Transaction> transactions = block.getTransactions(); assertNotNull(transactions); wallet.receiveFromBlock(transactions.get(0), storedBlock, NewBlockType.BEST_CHAIN, 0); // Coinbase transaction should have been received successfully but be unavailable to spend (too // young). assertEquals(BALANCE_AFTER_BLOCK, wallet.getBalance(BalanceType.ESTIMATED)); assertEquals(BigInteger.ZERO, wallet.getBalance(BalanceType.AVAILABLE)); }