@Override protected void doneDownload() { LOG.info("Download done, now sending block numbers."); final int startBlockHeight = bitcoinBlockchain.getBestChainHeight(); messageService.send(new BlockNRBitcoinMessage((long) startBlockHeight, new Date().getTime())); bitcoinPeerGroup.addBlocksDownloadedEventListener((peer, block, filteredBlock, blocksLeft) -> { if (bitcoinBlockchain.getBestChainHeight() > startBlockHeight) { messageService.send(new BlockNRBitcoinMessage((long) bitcoinBlockchain.getBestChainHeight(), new Date().getTime())); } }); }
@Scheduled(fixedRate = 60000) public void reportBitcoinPeersConnected() { int amountConnectedPeers = bitcoinPeerGroup.numConnectedPeers(); int mostCommonChainHeight = bitcoinPeerGroup.getMostCommonChainHeight(); int bestChainHeight = bitcoinBlockchain.getBestChainHeight(); LOG.info("Bitcoin PeerGroup: amountConnectedPeers={} mostCommonChainHeight={} bestChainHeight={}", amountConnectedPeers, mostCommonChainHeight, bestChainHeight); } }
@Override protected void rollbackBlockStore(int height) throws BlockStoreException { lock.lock(); try { int currentHeight = getBestChainHeight(); checkArgument(height >= 0 && height <= currentHeight, "Bad height: %s", height); if (height == currentHeight) return; // nothing to do // Look for the block we want to be the new chain head StoredBlock newChainHead = blockStore.getChainHead(); while (newChainHead.getHeight() > height) { newChainHead = newChainHead.getPrev(blockStore); if (newChainHead == null) throw new BlockStoreException("Unreachable height"); } // Modify store directly blockStore.put(newChainHead); this.setChainHead(newChainHead); } finally { lock.unlock(); } }
@Override protected void rollbackBlockStore(int height) throws BlockStoreException { lock.lock(); try { int currentHeight = getBestChainHeight(); checkArgument(height >= 0 && height <= currentHeight, "Bad height: %s", height); if (height == currentHeight) return; // nothing to do // Look for the block we want to be the new chain head StoredBlock newChainHead = blockStore.getChainHead(); while (newChainHead.getHeight() > height) { newChainHead = newChainHead.getPrev(blockStore); if (newChainHead == null) throw new BlockStoreException("Unreachable height"); } // Modify store directly blockStore.put(newChainHead); this.setChainHead(newChainHead); } finally { lock.unlock(); } }
log.debug("Created block chain '{}' with height '{}'", blockChain, blockChain.getBestChainHeight());
@Override protected void rollbackBlockStore(int height) throws BlockStoreException { lock.lock(); try { int currentHeight = getBestChainHeight(); checkArgument(height >= 0 && height <= currentHeight, "Bad height: %s", height); if (height == currentHeight) return; // nothing to do // Look for the block we want to be the new chain head StoredBlock newChainHead = blockStore.getChainHead(); while (newChainHead.getHeight() > height) { newChainHead = newChainHead.getPrev(blockStore); if (newChainHead == null) throw new BlockStoreException("Unreachable height"); } // Modify store directly blockStore.put(newChainHead); this.setChainHead(newChainHead); } finally { lock.unlock(); } }
@Override protected void rollbackBlockStore(int height) throws BlockStoreException { lock.lock(); try { int currentHeight = getBestChainHeight(); checkArgument(height >= 0 && height <= currentHeight, "Bad height: %s", height); if (height == currentHeight) return; // nothing to do // Look for the block we want to be the new chain head StoredBlock newChainHead = blockStore.getChainHead(); while (newChainHead.getHeight() > height) { newChainHead = newChainHead.getPrev(blockStore); if (newChainHead == null) throw new BlockStoreException("Unreachable height"); } // Modify store directly blockStore.put(newChainHead); this.setChainHead(newChainHead); } finally { lock.unlock(); } }
int heightAtStart = kit.chain().getBestChainHeight(); System.out.println("Height at start is " + heightAtStart); request.tx.getConfidence().getDepthFuture(1).get(); int heightNow = kit.chain().getBestChainHeight(); System.out.println("Height after confirmation is " + heightNow); System.out.println("Result: took " + (heightNow - heightAtStart) + " blocks to confirm at this fee level");
@Test public void rollbackBlockStore() throws Exception { // This test simulates an issue on Android, that causes the VM to crash while receiving a block, so that the // block store is persisted but the wallet is not. Block b1 = PARAMS.getGenesisBlock().createNextBlock(coinbaseTo); Block b2 = b1.createNextBlock(coinbaseTo); // Add block 1, no frills. assertTrue(chain.add(b1)); assertEquals(b1.cloneAsHeader(), chain.getChainHead().getHeader()); assertEquals(1, chain.getBestChainHeight()); assertEquals(1, wallet.getLastBlockSeenHeight()); // Add block 2 while wallet is disconnected, to simulate crash. chain.removeWallet(wallet); assertTrue(chain.add(b2)); assertEquals(b2.cloneAsHeader(), chain.getChainHead().getHeader()); assertEquals(2, chain.getBestChainHeight()); assertEquals(1, wallet.getLastBlockSeenHeight()); // Add wallet back. This will detect the height mismatch and repair the damage done. chain.addWallet(wallet); assertEquals(b1.cloneAsHeader(), chain.getChainHead().getHeader()); assertEquals(1, chain.getBestChainHeight()); assertEquals(1, wallet.getLastBlockSeenHeight()); // Now add block 2 correctly. assertTrue(chain.add(b2)); assertEquals(b2.cloneAsHeader(), chain.getChainHead().getHeader()); assertEquals(2, chain.getBestChainHeight()); assertEquals(2, wallet.getLastBlockSeenHeight()); } }