@Override public void receiveFromBlock(Transaction tx, StoredBlock block, AbstractBlockChain.NewBlockType blockType, int relativityOffset) throws VerificationException { //Log.d("TransactionIsInBlock",block.toString()); synchronized (transactions) { countTransactions++; transactions.add(tx); if (transactions.size() >= 30) { transactions.remove(10); } } if(System.currentTimeMillis()-lastTimestamp>1000) { refreshUI(); lastTimestamp = System.currentTimeMillis(); } }
private void refresh(final StoredBlock storedBlock){ runOnUiThread(new Runnable() { @Override public void run() { // Update info mDataset.clear(); if(storedBlock!=null){ mDataset.put("Hash",storedBlock.getHeader().getHashAsString()); mDataset.put("Height",String.valueOf(storedBlock.getHeight())); //mDataset.put("Prev",storedBlock.getPrev(blockStore).getHeader().getHashAsString()); mDataset.put("MerkleRoot",storedBlock.getHeader().getMerkleRoot().toString()); mDataset.put("DifficultyTarget",String.valueOf(storedBlock.getHeader().getDifficultyTarget())); mDataset.put("Nonce",String.valueOf(storedBlock.getHeader().getNonce())); mDataset.put("Date",storedBlock.getHeader().getTime().toLocaleString()); mDataset.put("Version",String.valueOf(storedBlock.getHeader().getVersion())); mDataset.put("Work",String.valueOf(storedBlock.getHeader().getWork())); //mDataset.put("Transactions",String.valueOf(storedBlock.getHeader().getTransactions().size())); mAdapter.notifyDataSetChanged(); } } }); }
public SQLiteBlockStore(NetworkParameters params, Context context) throws BlockStoreException { this.params = params; blocksDataSource = new BlocksDataSource(context); blocksDataSource.open(); if (blocksDataSource.count()==0){ createNewBlockStore(params); } else{ try { DBBlock block = blocksDataSource.getLast(); Block b = new Block(params, block.getHeader()); StoredBlock s = build(b); this.chainHead = s.getHeader().getHash(); } catch (Exception e) { throw new BlockStoreException("Invalid BlockStore chainHead"); } } blocksDataSource.close(); }
@Override public synchronized void put(StoredBlock block) throws BlockStoreException { blocksDataSource.open(); Sha256Hash hash = block.getHeader().getHash(); try { blocksDataSource.getHash(hash.toString()); } catch (Exception e) { DBBlock dbBlock = new DBBlock(); dbBlock.setHash(hash.toString()); dbBlock.setHeight(block.getHeight()); dbBlock.setHeader(block.getHeader().bitcoinSerialize()); dbBlock.setChainWork(block.getChainWork()); blocksDataSource.insert(dbBlock); } blocksDataSource.close(); }
@Override public synchronized StoredBlock get(Sha256Hash hash) throws BlockStoreException { if(hash==null) throw new BlockStoreException("Invalid hash"); blocksDataSource.open(); DBBlock block = null; try { block = blocksDataSource.getHash(hash.toString()); } catch (Exception e) { blocksDataSource.close(); return null; } Block b = new Block(params, block.getHeader()); StoredBlock s = build(b); blocksDataSource.close(); return s; }
public static long currentBitcoinBIP113Time(BlockChain bc) { StoredBlock headBlock = bc.getChainHead(); StoredBlock iteratingBlock = headBlock; long[] blockTimeStamps = new long[11]; for(int i=0; i < 11; i++) { blockTimeStamps[i] = iteratingBlock.getHeader().getTimeSeconds(); try { iteratingBlock = iteratingBlock.getPrev(bc.getBlockStore()); } catch (BlockStoreException e) { e.printStackTrace(); } } Arrays.sort(blockTimeStamps); System.out.println("current bitcoinbip113time yielded " + new Date(blockTimeStamps[5]*1000)); return blockTimeStamps[5]; }
/** * Initialize the version tally from the block store. Note this does not * search backwards past the start of the block store, so if starting from * a checkpoint this may not fill the window. * * @param blockStore block store to load blocks from. * @param chainHead current chain tip. */ public void initialize(final BlockStore blockStore, final StoredBlock chainHead) throws BlockStoreException { StoredBlock versionBlock = chainHead; final Stack<Long> versions = new Stack<>(); // We don't know how many blocks back we can go, so load what we can first versions.push(versionBlock.getHeader().getVersion()); for (int headOffset = 0; headOffset < versionWindow.length; headOffset++) { versionBlock = versionBlock.getPrev(blockStore); if (null == versionBlock) { break; } versions.push(versionBlock.getHeader().getVersion()); } // Replay the versions into the tally while (!versions.isEmpty()) { add(versions.pop()); } }
/** * Called by the {@link BlockChain} when we receive a new filtered block that contains a transactions previously * received by a call to {@link #receivePending}.<p> * * This is necessary for the internal book-keeping Wallet does. When a transaction is received that sends us * coins it is added to a pool so we can use it later to create spends. When a transaction is received that * consumes outputs they are marked as spent so they won't be used in future.<p> * * A transaction that spends our own coins can be received either because a spend we created was accepted by the * network and thus made it into a block, or because our keys are being shared between multiple instances and * some other node spent the coins instead. We still have to know about that to avoid accidentally trying to * double spend.<p> * * A transaction may be received multiple times if is included into blocks in parallel chains. The blockType * parameter describes whether the containing block is on the main/best chain or whether it's on a presently * inactive side chain. We must still record these transactions and the blocks they appear in because a future * block might change which chain is best causing a reorganize. A re-org can totally change our balance! */ @Override public boolean notifyTransactionIsInBlock(Sha256Hash txHash, StoredBlock block, BlockChain.NewBlockType blockType, int relativityOffset) throws VerificationException { lock.lock(); try { Transaction tx = transactions.get(txHash); if (tx == null) { tx = riskDropped.get(txHash); if (tx != null) { // If this happens our risk analysis is probably wrong and should be improved. log.info("Risk analysis dropped tx {} but was included in block anyway", tx.getHash()); } else { // False positive that was broadcast to us and ignored by us because it was irrelevant to our keys. return false; } } receive(tx, block, blockType, relativityOffset); return true; } finally { lock.unlock(); } }
private void createNewStore(NetworkParameters params) throws BlockStoreException { try { // Set up the genesis block. When we start out fresh, it is by // definition the top of the chain. StoredBlock storedGenesisHeader = new StoredBlock(params.getGenesisBlock().cloneAsHeader(), params.getGenesisBlock().getWork(), 0); // The coinbase in the genesis block is not spendable. This is // because of how the reference client inits // its database - the genesis transaction isn't actually in the db // so its spent flags can never be updated. List<Transaction> genesisTransactions = Lists.newLinkedList(); StoredUndoableBlock storedGenesis = new StoredUndoableBlock(params.getGenesisBlock().getHash(), genesisTransactions); beginDatabaseBatchWrite(); put(storedGenesisHeader, storedGenesis); setChainHead(storedGenesisHeader); setVerifiedChainHead(storedGenesisHeader); batchPut(getKey(KeyType.CREATED), bytes("done")); commitDatabaseBatchWrite(); } catch (VerificationException e) { throw new RuntimeException(e); // Cannot happen. } }
@Override public List<StoredBlock> getRecentBlocks(final int maxBlocks) { final List<StoredBlock> blocks = new ArrayList<StoredBlock>(maxBlocks); try { StoredBlock block = blockChain.getChainHead(); while (block != null) { blocks.add(block); if (blocks.size() >= maxBlocks) break; block = block.getPrev(blockStore); } } catch (final BlockStoreException x) { // swallow } return blocks; }
@Override public void onBlockMenuClick(final View view, final StoredBlock block) { final PopupMenu popupMenu = new PopupMenu(activity, view); popupMenu.inflate(R.menu.blocks_context); popupMenu.getMenu().findItem(R.id.blocks_context_browse).setVisible(Constants.ENABLE_BROWSE); popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(final MenuItem item) { switch (item.getItemId()) { case R.id.blocks_context_browse: final String blockHash = block.getHeader().getHashAsString(); final Uri blockExplorerUri = config.getBlockExplorer(); log.info("Viewing block {} on {}", blockHash, blockExplorerUri); startActivity(new Intent(Intent.ACTION_VIEW, Uri.withAppendedPath(blockExplorerUri, "block/" + blockHash))); return true; } return false; } }); popupMenu.show(); }
/** * Initialize the version tally from the block store. Note this does not * search backwards past the start of the block store, so if starting from * a checkpoint this may not fill the window. * * @param blockStore block store to load blocks from. * @param chainHead current chain tip. */ public void initialize(final BlockStore blockStore, final StoredBlock chainHead) throws BlockStoreException { StoredBlock versionBlock = chainHead; final Stack<Long> versions = new Stack<Long>(); // We don't know how many blocks back we can go, so load what we can first versions.push(versionBlock.getHeader().getVersion()); for (int headOffset = 0; headOffset < versionWindow.length; headOffset++) { versionBlock = versionBlock.getPrev(blockStore); if (null == versionBlock) { break; } versions.push(versionBlock.getHeader().getVersion()); } // Replay the versions into the tally while (!versions.isEmpty()) { add(versions.pop()); } }
@Test public void testInitialize() throws BlockStoreException { final BlockStore blockStore = new MemoryBlockStore(PARAMS); final BlockChain chain = new BlockChain(PARAMS, blockStore); // Build a historical chain of version 2 blocks long timeSeconds = 1231006505; StoredBlock chainHead = null; for (int height = 0; height < PARAMS.getMajorityWindow(); height++) { chainHead = FakeTxBuilder.createFakeBlock(blockStore, 2, timeSeconds, height).storedBlock; assertEquals(2, chainHead.getHeader().getVersion()); timeSeconds += 60; } VersionTally instance = new VersionTally(PARAMS); instance.initialize(blockStore, chainHead); assertEquals(PARAMS.getMajorityWindow(), instance.getCountAtOrAbove(2).intValue()); }
@Test public void testCategory2WithChange() throws Exception { // Specifically target case 2 with significant change // Generate a ton of small outputs StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, OTHER_ADDRESS), BigInteger.ONE, 1); int i = 0; while (i <= CENT.divide(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10))) { Transaction tx = createFakeTxWithChangeAddress(PARAMS, Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10), myAddress, OTHER_ADDRESS); tx.getInput(0).setSequenceNumber(i++); // Keep every transaction unique wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); } // The selector will choose 2 with MIN_TX_FEE fee SendRequest request1 = SendRequest.to(OTHER_ADDRESS, CENT.add(SATOSHI)); request1.ensureMinRequiredFee = true; wallet.completeTx(request1); assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request1.tx.getFee()); assertEquals(request1.tx.getInputs().size(), i); // We should have spent all inputs assertEquals(2, request1.tx.getOutputs().size()); // and gotten change back }
@Override public void onBlockMenuClick(final View view, final StoredBlock block) { final PopupMenu popupMenu = new PopupMenu(activity, view); popupMenu.inflate(R.menu.blocks_context); popupMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(final MenuItem item) { switch (item.getItemId()) { case R.id.blocks_context_browse: startActivity(new Intent(Intent.ACTION_VIEW, Uri.withAppendedPath(config.getBlockExplorer(), "block/" + block.getHeader().getHashAsString()))); return true; } return false; } }); popupMenu.show(); }
protected void initBlockHashCache() throws BlockStoreException { blockHashCache = new ConcurrentHashMap<Integer, Sha256Hash>(72000); StoredBlock blockPointer = chain.getChainHead(); int headHeight = blockPointer.getHeight(); int reorgSafety = 120; int newestHeight = headHeight - reorgSafety; int oldestHeight = headHeight - 36000 - reorgSafety; // 36000 = name expiration while (blockPointer.getHeight() >= oldestHeight) { if (blockPointer.getHeight() <= newestHeight) { blockHashCache.put(new Integer(blockPointer.getHeight()), blockPointer.getHeader().getHash()); } blockPointer = blockPointer.getPrev(store); } }
public Sha256Hash getBlockHash(int height) throws BlockStoreException { Sha256Hash maybeResult = blockHashCache.get(new Integer(height)); if (maybeResult != null) { return maybeResult; } // If we got this far, the block height is uncached. // This could be because the block is immature, // or it could be because the cache is only initialized on initial startup. StoredBlock blockPointer = chain.getChainHead(); while (blockPointer.getHeight() != height) { blockPointer = blockPointer.getPrev(store); } return blockPointer.getHeader().getHash(); }
@Override public void notifyNewBestBlock (StoredBlock block) throws VerificationException { // TODO: use BIP 113 timestamps if ( (new Date().getTime() / 1000 ) - block.getHeader().getTimeSeconds() > 366 * 24 * 60 * 60) { log.debug("NameDB skipping block at height " + block.getHeight() + " due to timestamp " + block.getHeader().getTimeSeconds()); return; } log.debug("NameDB started processing new best block at height " + block.getHeight()); try { putBlockChain(getSafeBlock(block)); } catch (Exception e) { log.error("NameDB Exception while processing new best block", e); throw new VerificationException(e); } log.debug("NameDB finished processing new best block at height " + block.getHeight()); }
@Override public void reorganize(StoredBlock splitPoint, List<StoredBlock> oldBlocks, List<StoredBlock> newBlocks) throws VerificationException { // TODO: use BIP 113 timestamps if ( (new Date().getTime() / 1000 ) - newBlocks.get(0).getHeader().getTimeSeconds() > 366 * 24 * 60 * 60) { return; } setChainHead(splitPoint.getHeight() - 12); try { putBlockChain(getSafeBlock(newBlocks.get(0))); } catch (Exception e) { log.error("Exception during NameDB reorganize", e); throw new VerificationException(e); } log.warn("Finished NameDB reorganize, height " + newBlocks.get(0).getHeight()); }
@Override public void notifyNewBestBlock(StoredBlock block) throws VerificationException { WalletObservable walletObservable = ewApplication.getWalletObservable(); //Log.d(TAG, "notifyNewBestBlock " + block.getHeight()); EWWalletService ewWalletService = ewApplication.getEwWalletService(); if(ewWalletService!=null) { Wallet wallet = ewWalletService.getWallet(); if(wallet.getPendingTransactions().size()==0 && walletObservable.isPending() ) { //TODO check if it's right!!! walletObservable.setState(WalletObservable.State.SYNCED); walletObservable.notifyObservers(); } //if(walletObservable.isPending()) ewWalletService.refreshNextsAndAlias(); //Log.i(TAG, "" + walletObservable ); } }
public static StoredBlock getLastBlockForAlgo(StoredBlock block, int algo, BlockStore blockStore) { for(;;) { if(block == null || block.getHeader().getPrevBlockHash().equals(Sha256Hash.ZERO_HASH)) return null; if(block.getHeader().getAlgo() == algo) return block; try { block = block.getPrev(blockStore); } catch(BlockStoreException x) { return null; } } }
private void blockNumNotify(Subscriber sub, StoredBlock blk) { try { JSONObject reply = new JSONObject(); JSONArray crap = new JSONArray(); crap.put(blk.getHeight()); reply.put("params", crap); reply.put("id", JSONObject.NULL); reply.put("method", "blockchain.numblocks.subscribe"); sub.sendReply(reply); } catch(org.json.JSONException e) { throw new RuntimeException(e); } }
public void populateBlockData(StoredBlock blk, JSONObject block_data) throws org.json.JSONException { Block header = blk.getHeader(); block_data.put("nonce", header.getNonce()); block_data.put("prev_block_hash", header.getPrevBlockHash().toString()); block_data.put("timestamp", header.getTimeSeconds()); block_data.put("merkle_root", header.getMerkleRoot().toString()); block_data.put("block_height", blk.getHeight()); block_data.put("version",header.getVersion()); block_data.put("bits", header.getDifficultyTarget()); //block_data.put("utxo_root", jelly.getUtxoTrieMgr().getRootHash(header.getHash())); }
public StoredBlock getChainHead() throws org.bitcoinj.store.BlockStoreException { StoredBlock head_blk = file_db.getSpecialBlockStoreMap().get("head"); StoredBlock curr = head_blk; int stepback=0; if (file_db.getBlockSavedMap()==null) throw new RuntimeException("BlockMap is null"); while((!file_db.getBlockSavedMap().containsKey(curr.getHeader().getHash())) && (curr.getHeight()>=1)) { int step_size=10; if (curr.getHeight() < 1000) step_size=1; for(int i=0; i<step_size; i++) { stepback++; curr = curr.getPrev(this); } } setChainHead(curr); jelly.getEventLog().alarm("Current Head: " + curr.getHeader().getHash().toString() + " - " + curr.getHeight() + " stepback " + stepback); return curr; }
public void setChainHead(StoredBlock block) throws org.bitcoinj.store.BlockStoreException { Sha256Hash hash = block.getHeader().getHash(); //if (jelly.isUpToDate() || (block.getHeight() % 100 == 0)) { file_db.getSpecialBlockStoreMap().put("head", block); } if (jelly.getBlockChainCache() != null) { jelly.getBlockChainCache().update(jelly, block); } if (jelly.getHeaderChunkAgent()!=null) { jelly.getHeaderChunkAgent().poke(block.getHeight()); } }
public boolean equals (StoredBlock storedBlock){ if (storedBlock == null ) return false; return storedBlock.getHeight() == this.height && storedBlock.getHeader().getHashAsString().equals(this.hash) && storedBlock.getHeader().getMerkleRoot().toString().equals(this.merkleroot) && storedBlock.getHeader().getNonce() == this.nonce && storedBlock.getHeader().getTimeSeconds() == this.time && //storedBlock.getHeader().getTransactions().size() == this.tx.size() && storedBlock.getHeader().getVersion() == this.version; }
public synchronized void createNewBlockStore(NetworkParameters params) throws BlockStoreException { // Set up the genesis block. When we start out fresh, it is by definition the top of the chain. Block genesis = params.getGenesisBlock().cloneAsHeader(); StoredBlock storedGenesis = new StoredBlock(genesis, genesis.getWork(), 0); this.chainHead = storedGenesis.getHeader().getHash(); this.put(storedGenesis); }
public synchronized void put(StoredBlock block) throws BlockStoreException { ensureOpen(); try { Sha256Hash hash = block.getHeader().getHash(); checkState(blockMap.get(hash) == null, "Attempt to insert duplicate"); // Append to the end of the file. The other fields in StoredBlock will be recalculated when it's reloaded. byte[] bytes = block.getHeader().bitcoinSerialize(); file.write(bytes); blockMap.put(hash, block); } catch (IOException e) { throw new BlockStoreException(e); } }
public synchronized void setChainHead(StoredBlock chainHead) throws BlockStoreException { ensureOpen(); try { this.chainHead = chainHead.getHeader().getHash(); // Write out new hash to the first 32 bytes of the file past one (first byte is version number). file.getChannel().write(ByteBuffer.wrap(this.chainHead.getBytes()), 1); } catch (IOException e) { throw new BlockStoreException(e); } }