@Test public void getLargeBlock() throws Exception { connect(); Block b1 = createFakeBlock(blockStore).block; blockChain.add(b1); Block b2 = makeSolvedTestBlock(b1); Transaction t = new Transaction(unitTestParams); t.addInput(b1.getTransactions().get(0).getOutput(0)); t.addOutput( new TransactionOutput( unitTestParams, t, BigInteger.ZERO, new byte[Block.MAX_BLOCK_SIZE - 1000])); b2.addTransaction(t); // Request the block. Future<Block> resultFuture = peer.getBlock(b2.getHash()); assertFalse(resultFuture.isDone()); // Peer asks for it. GetDataMessage message = (GetDataMessage) outbound(writeTarget); assertEquals(message.getItems().get(0).hash, b2.getHash()); assertFalse(resultFuture.isDone()); // Peer receives it. inbound(writeTarget, b2); Block b = resultFuture.get(); assertEquals(b, b2); }
@Test public void testGetOpenTransactionOutputs() throws Exception { final int UNDOABLE_BLOCKS_STORED = 10; store = createStore(params, UNDOABLE_BLOCKS_STORED); chain = new FullPrunedBlockChain(params, store); // Check that we aren't accidentally leaving any references // to the full StoredUndoableBlock's lying around (ie memory leaks) ECKey outKey = new ECKey(); int height = 1; // Build some blocks on genesis block to create a spendable output Block rollingBlock = params .getGenesisBlock() .createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++); chain.add(rollingBlock); Transaction transaction = rollingBlock.getTransactions().get(0); TransactionOutPoint spendableOutput = new TransactionOutPoint(params, 0, transaction.getHash()); byte[] spendableOutputScriptPubKey = transaction.getOutputs().get(0).getScriptBytes(); for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) { rollingBlock = rollingBlock.createNextBlockWithCoinbase( Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++); chain.add(rollingBlock); } rollingBlock = rollingBlock.createNextBlock(null); // Create bitcoin spend of 1 BTC. ECKey toKey = new ECKey(); Coin amount = Coin.valueOf(100000000); Address address = new Address(params, toKey.getPubKeyHash()); Coin totalAmount = Coin.ZERO; Transaction t = new Transaction(params); t.addOutput(new TransactionOutput(params, t, amount, toKey)); t.addSignedInput(spendableOutput, new Script(spendableOutputScriptPubKey), outKey); rollingBlock.addTransaction(t); rollingBlock.solve(); chain.add(rollingBlock); totalAmount = totalAmount.add(amount); List<UTXO> outputs = store.getOpenTransactionOutputs(Lists.newArrayList(address)); assertNotNull(outputs); assertEquals("Wrong Number of Outputs", 1, outputs.size()); UTXO output = outputs.get(0); assertEquals("The address is not equal", address.toString(), output.getAddress()); assertEquals("The amount is not equal", totalAmount, output.getValue()); outputs = null; output = null; try { store.close(); } catch (Exception e) { } }
@Test public void testUpdateLength() { NetworkParameters params = UnitTestParams.get(); Block block = params .getGenesisBlock() .createNextBlockWithCoinbase( Block.BLOCK_VERSION_GENESIS, new ECKey().getPubKey(), Block.BLOCK_HEIGHT_GENESIS); assertEquals(block.bitcoinSerialize().length, block.length); final int origBlockLen = block.length; Transaction tx = new Transaction(params); // this is broken until the transaction has > 1 input + output (which is required anyway...) // assertTrue(tx.length == tx.bitcoinSerialize().length && tx.length == 8); byte[] outputScript = new byte[10]; Arrays.fill(outputScript, (byte) ScriptOpCodes.OP_FALSE); tx.addOutput(new TransactionOutput(params, null, Coin.SATOSHI, outputScript)); tx.addInput( new TransactionInput( params, null, new byte[] {(byte) ScriptOpCodes.OP_FALSE}, new TransactionOutPoint(params, 0, Sha256Hash.of(new byte[] {1})))); int origTxLength = 8 + 2 + 8 + 1 + 10 + 40 + 1 + 1; assertEquals(tx.bitcoinSerialize().length, tx.length); assertEquals(origTxLength, tx.length); block.addTransaction(tx); assertEquals(block.bitcoinSerialize().length, block.length); assertEquals(origBlockLen + tx.length, block.length); block .getTransactions() .get(1) .getInputs() .get(0) .setScriptBytes(new byte[] {(byte) ScriptOpCodes.OP_FALSE, (byte) ScriptOpCodes.OP_FALSE}); assertEquals(block.length, origBlockLen + tx.length); assertEquals(tx.length, origTxLength + 1); block.getTransactions().get(1).getInputs().get(0).setScriptBytes(new byte[] {}); assertEquals(block.length, block.bitcoinSerialize().length); assertEquals(block.length, origBlockLen + tx.length); assertEquals(tx.length, origTxLength - 1); block .getTransactions() .get(1) .addInput( new TransactionInput( params, null, new byte[] {(byte) ScriptOpCodes.OP_FALSE}, new TransactionOutPoint(params, 0, Sha256Hash.of(new byte[] {1})))); assertEquals(block.length, origBlockLen + tx.length); assertEquals(tx.length, origTxLength + 41); // - 1 + 40 + 1 + 1 }
@Test public void skipScripts() throws Exception { store = createStore(params, 10); chain = new FullPrunedBlockChain(params, store); // Check that we aren't accidentally leaving any references // to the full StoredUndoableBlock's lying around (ie memory leaks) ECKey outKey = new ECKey(); int height = 1; // Build some blocks on genesis block to create a spendable output Block rollingBlock = params .getGenesisBlock() .createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++); chain.add(rollingBlock); TransactionOutput spendableOutput = rollingBlock.getTransactions().get(0).getOutput(0); for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) { rollingBlock = rollingBlock.createNextBlockWithCoinbase( Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++); chain.add(rollingBlock); } rollingBlock = rollingBlock.createNextBlock(null); Transaction t = new Transaction(params); t.addOutput(new TransactionOutput(params, t, FIFTY_COINS, new byte[] {})); TransactionInput input = t.addInput(spendableOutput); // Invalid script. input.clearScriptBytes(); rollingBlock.addTransaction(t); rollingBlock.solve(); chain.setRunScripts(false); try { chain.add(rollingBlock); } catch (VerificationException e) { fail(); } try { store.close(); } catch (Exception e) { } }
@Test public void testUTXOProviderWithWallet() throws Exception { final int UNDOABLE_BLOCKS_STORED = 10; store = createStore(params, UNDOABLE_BLOCKS_STORED); chain = new FullPrunedBlockChain(params, store); // Check that we aren't accidentally leaving any references // to the full StoredUndoableBlock's lying around (ie memory leaks) ECKey outKey = new ECKey(); int height = 1; // Build some blocks on genesis block to create a spendable output. Block rollingBlock = params .getGenesisBlock() .createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++); chain.add(rollingBlock); Transaction transaction = rollingBlock.getTransactions().get(0); TransactionOutPoint spendableOutput = new TransactionOutPoint(params, 0, transaction.getHash()); byte[] spendableOutputScriptPubKey = transaction.getOutputs().get(0).getScriptBytes(); for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) { rollingBlock = rollingBlock.createNextBlockWithCoinbase( Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++); chain.add(rollingBlock); } rollingBlock = rollingBlock.createNextBlock(null); // Create 1 BTC spend to a key in this wallet (to ourselves). Wallet wallet = new Wallet(params); assertEquals( "Available balance is incorrect", Coin.ZERO, wallet.getBalance(Wallet.BalanceType.AVAILABLE)); assertEquals( "Estimated balance is incorrect", Coin.ZERO, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); wallet.setUTXOProvider(store); ECKey toKey = wallet.freshReceiveKey(); Coin amount = Coin.valueOf(100000000); Transaction t = new Transaction(params); t.addOutput(new TransactionOutput(params, t, amount, toKey)); t.addSignedInput(spendableOutput, new Script(spendableOutputScriptPubKey), outKey); rollingBlock.addTransaction(t); rollingBlock.solve(); chain.add(rollingBlock); // Create another spend of 1/2 the value of BTC we have available using the wallet (store coin // selector). ECKey toKey2 = new ECKey(); Coin amount2 = amount.divide(2); Address address2 = new Address(params, toKey2.getPubKeyHash()); Wallet.SendRequest req = Wallet.SendRequest.to(address2, amount2); wallet.completeTx(req); wallet.commitTx(req.tx); Coin fee = req.fee; // There should be one pending tx (our spend). assertEquals( "Wrong number of PENDING.4", 1, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); Coin totalPendingTxAmount = Coin.ZERO; for (Transaction tx : wallet.getPendingTransactions()) { totalPendingTxAmount = totalPendingTxAmount.add(tx.getValueSentToMe(wallet)); } // The availbale balance should be the 0 (as we spent the 1 BTC that's pending) and estimated // should be 1/2 - fee BTC assertEquals( "Available balance is incorrect", Coin.ZERO, wallet.getBalance(Wallet.BalanceType.AVAILABLE)); assertEquals( "Estimated balance is incorrect", amount2.subtract(fee), wallet.getBalance(Wallet.BalanceType.ESTIMATED)); assertEquals("Pending tx amount is incorrect", amount2.subtract(fee), totalPendingTxAmount); try { store.close(); } catch (Exception e) { } }
@Test public void testFinalizedBlocks() throws Exception { final int UNDOABLE_BLOCKS_STORED = 10; store = createStore(params, UNDOABLE_BLOCKS_STORED); chain = new FullPrunedBlockChain(params, store); // Check that we aren't accidentally leaving any references // to the full StoredUndoableBlock's lying around (ie memory leaks) ECKey outKey = new ECKey(); int height = 1; // Build some blocks on genesis block to create a spendable output Block rollingBlock = params .getGenesisBlock() .createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++); chain.add(rollingBlock); TransactionOutPoint spendableOutput = new TransactionOutPoint(params, 0, rollingBlock.getTransactions().get(0).getHash()); byte[] spendableOutputScriptPubKey = rollingBlock.getTransactions().get(0).getOutputs().get(0).getScriptBytes(); for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) { rollingBlock = rollingBlock.createNextBlockWithCoinbase( Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++); chain.add(rollingBlock); } WeakReference<UTXO> out = new WeakReference<UTXO>( store.getTransactionOutput(spendableOutput.getHash(), spendableOutput.getIndex())); rollingBlock = rollingBlock.createNextBlock(null); Transaction t = new Transaction(params); // Entirely invalid scriptPubKey t.addOutput(new TransactionOutput(params, t, FIFTY_COINS, new byte[] {})); t.addSignedInput(spendableOutput, new Script(spendableOutputScriptPubKey), outKey); rollingBlock.addTransaction(t); rollingBlock.solve(); chain.add(rollingBlock); WeakReference<StoredUndoableBlock> undoBlock = new WeakReference<StoredUndoableBlock>(store.getUndoBlock(rollingBlock.getHash())); StoredUndoableBlock storedUndoableBlock = undoBlock.get(); assertNotNull(storedUndoableBlock); assertNull(storedUndoableBlock.getTransactions()); WeakReference<TransactionOutputChanges> changes = new WeakReference<TransactionOutputChanges>(storedUndoableBlock.getTxOutChanges()); assertNotNull(changes.get()); storedUndoableBlock = null; // Blank the reference so it can be GCd. // Create a chain longer than UNDOABLE_BLOCKS_STORED for (int i = 0; i < UNDOABLE_BLOCKS_STORED; i++) { rollingBlock = rollingBlock.createNextBlock(null); chain.add(rollingBlock); } // Try to get the garbage collector to run System.gc(); assertNull(undoBlock.get()); assertNull(changes.get()); assertNull(out.get()); try { store.close(); } catch (Exception e) { } }