private void initFromDb() throws BlockStoreException { Sha256Hash hash = Sha256Hash.wrap(batchGet(getKey(KeyType.CHAIN_HEAD_SETTING))); this.chainHeadBlock = get(hash); this.chainHeadHash = hash; if (this.chainHeadBlock == null) { throw new BlockStoreException("corrupt database block store - head block not found"); } hash = Sha256Hash.wrap(batchGet(getKey(KeyType.VERIFIED_CHAIN_HEAD_SETTING))); this.verifiedChainHeadBlock = get(hash); this.verifiedChainHeadHash = hash; if (this.verifiedChainHeadBlock == null) { throw new BlockStoreException("corrupt databse block store - verified head block not found"); } }
@Override public void setChainHead(StoredBlock chainHead) throws BlockStoreException { if (instrument) beginMethod("setChainHead"); Sha256Hash hash = chainHead.getHeader().getHash(); this.chainHeadHash = hash; this.chainHeadBlock = chainHead; batchPut(getKey(KeyType.CHAIN_HEAD_SETTING), hash.getBytes()); if (instrument) endMethod("setChainHead"); }
@Override public void setVerifiedChainHead(StoredBlock chainHead) throws BlockStoreException { if (instrument) beginMethod("setVerifiedChainHead"); Sha256Hash hash = chainHead.getHeader().getHash(); this.verifiedChainHeadHash = hash; this.verifiedChainHeadBlock = chainHead; batchPut(getKey(KeyType.VERIFIED_CHAIN_HEAD_SETTING), hash.getBytes()); if (this.chainHeadBlock.getHeight() < chainHead.getHeight()) setChainHead(chainHead); removeUndoableBlocksWhereHeightIsLessThan(chainHead.getHeight() - fullStoreDepth); if (instrument) endMethod("setVerifiedChainHead"); }
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. } }
public StoredBlock get(Sha256Hash hash, boolean wasUndoableOnly) throws BlockStoreException { // Optimize for chain head if (chainHeadHash != null && chainHeadHash.equals(hash)) return chainHeadBlock; if (verifiedChainHeadHash != null && verifiedChainHeadHash.equals(hash)) return verifiedChainHeadBlock; if (instrument) beginMethod("get");// ignore optimised case as not interesting for // tuning. boolean undoableResult; byte[] result = batchGet(getKey(KeyType.HEADERS_ALL, hash)); if (result == null) { if (instrument) endMethod("get"); return null; } undoableResult = (result[96] == 1 ? true : false); if (wasUndoableOnly && !undoableResult) { if (instrument) endMethod("get"); return null; } // TODO Should I chop the last byte off? Seems to work with it left // there... StoredBlock stored = StoredBlock.deserializeCompact(params, ByteBuffer.wrap(result)); stored.getHeader().verifyHeader(); if (instrument) endMethod("get"); return stored; }
private void openDB() { Options options = new Options(); options.createIfMissing(true); // options.compressionType(CompressionType.NONE); options.cacheSize(leveldbReadCache); options.writeBufferSize(leveldbWriteCache); options.maxOpenFiles(10000); // options.blockSize(1024*1024*50); try { db = factory.open(new File(filename), options); } catch (IOException e) { throw new RuntimeException("Can not open DB", e); } utxoCache = new LRUCache(openOutCache, 0.75f); try { if (batchGet(getKey(KeyType.CREATED)) == null) { createNewStore(params); } else { initFromDb(); } } catch (BlockStoreException e) { throw new RuntimeException("Can not init/load db", e); } }
@Override public void removeUnspentTransactionOutput(UTXO out) throws BlockStoreException { if (instrument) beginMethod("removeUnspentTransactionOutput"); byte[] key = getTxKey(KeyType.OPENOUT_ALL, out.getHash(), (int) out.getIndex()); batchDelete(key); endMethod("removeUnspentTransactionOutput"); return; } catch (ScriptException e) { if (instrument) endMethod("removeUnspentTransactionOutput"); return; bb.put(out.getHash().getBytes()); bb.putInt((int) out.getIndex()); batchDelete(bb.array()); endMethod("removeUnspentTransactionOutput");
beginMethod("addUnspentTransactionOutput"); byte[] key = getTxKey(KeyType.OPENOUT_ALL, out.getHash(), (int) out.getIndex()); batchPut(key, bos.toByteArray()); if (out.getAddress() == null || out.getAddress().equals("")) { if (instrument) endMethod("addUnspentTransactionOutput"); return; } else { } catch (AddressFormatException e) { if (instrument) endMethod("addUnspentTransactionOutput"); return; bb.putInt((int) out.getIndex()); byte[] value = new byte[0]; batchPut(bb.array(), value); if (instrument) endMethod("addUnspentTransactionOutput");
@Override public UTXO getTransactionOutput(Sha256Hash hash, long index) throws BlockStoreException { if (instrument) beginMethod("getTransactionOutput"); byte[] key = getTxKey(KeyType.OPENOUT_ALL, hash, (int) index); endMethod("getTransactionOutput"); return result; hit++; if (instrument) endMethod("getTransactionOutput"); return result; byte[] inbytes = batchGet(key); if (inbytes == null) { if (instrument) endMethod("getTransactionOutput"); return null; endMethod("getTransactionOutput"); return txout; } catch (DBException e) { log.error("Exception in getTransactionOutput.", e); if (instrument) endMethod("getTransactionOutput"); } catch (IOException e) { log.error("Exception in getTransactionOutput.", e); if (instrument)
uncommitedDeletes = null; if (instrument) beginMethod("commitDatabaseBatchWrite"); endMethod("commitDatabaseBatchWrite"); dumpStats(); if (verifiedChainHeadBlock.getHeight() == exitBlock) { System.err.println("Exit due to exitBlock set");
@Override public boolean hasUnspentOutputs(Sha256Hash hash, int numOutputs) throws BlockStoreException { if (instrument) beginMethod("hasUnspentOutputs"); hasCall++; if (!bloom.wasAdded(hash)) { if (instrument) endMethod("hasUnspentOutputs"); hasFalse++; return false; byte[] key = getTxKey(KeyType.OPENOUT_ALL, hash); byte[] subResult = new byte[key.length]; DBIterator iterator = db.iterator(); endMethod("hasUnspentOutputs"); return true; } else { endMethod("hasUnspentOutputs"); return false; endMethod("hasUnspentOutputs"); return false;
@Override public void beginDatabaseBatchWrite() throws BlockStoreException { // This is often called twice in row! But they are not nested // transactions! // We just ignore the second call. if (!autoCommit) { return; } if (instrument) beginMethod("beginDatabaseBatchWrite"); batch = db.createWriteBatch(); uncommited = new HashMap<>(); uncommitedDeletes = new HashSet<>(); utxoUncommittedCache = new HashMap<>(); utxoUncommittedDeletedCache = new HashSet<>(); autoCommit = false; if (instrument) endMethod("beginDatabaseBatchWrite"); }
void removeUndoableBlocksWhereHeightIsLessThan(int height) { if (height < 0) return; DBIterator iterator = db.iterator(); ByteBuffer keyBuf = ByteBuffer.allocate(5); keyBuf.put((byte) KeyType.HEIGHT_UNDOABLEBLOCKS.ordinal()); keyBuf.putInt(height); for (iterator.seek(keyBuf.array()); iterator.hasNext(); iterator.next()) { byte[] bytekey = iterator.peekNext().getKey(); ByteBuffer buff = ByteBuffer.wrap(bytekey); buff.get(); // Just remove byte from buffer. int keyHeight = buff.getInt(); byte[] hashbytes = new byte[32]; buff.get(hashbytes, 4, 28); if (keyHeight > height) break; batchDelete(getKey(KeyType.UNDOABLEBLOCKS_ALL, hashbytes)); batchDelete(bytekey); } try { iterator.close(); } catch (IOException e) { log.error("Error closing iterator", e); } }
@Override public StoredBlock get(Sha256Hash hash) throws BlockStoreException { return get(hash, false); }
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 void setVerifiedChainHead(StoredBlock chainHead) throws BlockStoreException { if (instrument) beginMethod("setVerifiedChainHead"); Sha256Hash hash = chainHead.getHeader().getHash(); this.verifiedChainHeadHash = hash; this.verifiedChainHeadBlock = chainHead; batchPut(getKey(KeyType.VERIFIED_CHAIN_HEAD_SETTING), hash.getBytes()); if (this.chainHeadBlock.getHeight() < chainHead.getHeight()) setChainHead(chainHead); removeUndoableBlocksWhereHeightIsLessThan(chainHead.getHeight() - fullStoreDepth); if (instrument) endMethod("setVerifiedChainHead"); }
public StoredBlock get(Sha256Hash hash, boolean wasUndoableOnly) throws BlockStoreException { // Optimize for chain head if (chainHeadHash != null && chainHeadHash.equals(hash)) return chainHeadBlock; if (verifiedChainHeadHash != null && verifiedChainHeadHash.equals(hash)) return verifiedChainHeadBlock; if (instrument) beginMethod("get");// ignore optimised case as not interesting for // tuning. boolean undoableResult; byte[] result = batchGet(getKey(KeyType.HEADERS_ALL, hash)); if (result == null) { if (instrument) endMethod("get"); return null; } undoableResult = (result[96] == 1 ? true : false); if (wasUndoableOnly && !undoableResult) { if (instrument) endMethod("get"); return null; } // TODO Should I chop the last byte off? Seems to work with it left // there... StoredBlock stored = StoredBlock.deserializeCompact(params, ByteBuffer.wrap(result)); stored.getHeader().verifyHeader(); if (instrument) endMethod("get"); return stored; }
private void openDB() { Options options = new Options(); options.createIfMissing(true); // options.compressionType(CompressionType.NONE); options.cacheSize(leveldbReadCache); options.writeBufferSize(leveldbWriteCache); options.maxOpenFiles(10000); // options.blockSize(1024*1024*50); try { db = factory.open(new File(filename), options); } catch (IOException e) { throw new RuntimeException("Can not open DB", e); } utxoCache = new LRUCache(openOutCache, 0.75f); try { if (batchGet(getKey(KeyType.CREATED)) == null) { createNewStore(params); } else { initFromDb(); } } catch (BlockStoreException e) { throw new RuntimeException("Can not init/load db", e); } }
@Override public void removeUnspentTransactionOutput(UTXO out) throws BlockStoreException { if (instrument) beginMethod("removeUnspentTransactionOutput"); byte[] key = getTxKey(KeyType.OPENOUT_ALL, out.getHash(), (int) out.getIndex()); batchDelete(key); endMethod("removeUnspentTransactionOutput"); return; } catch (ScriptException e) { if (instrument) endMethod("removeUnspentTransactionOutput"); return; bb.put(out.getHash().getBytes()); bb.putInt((int) out.getIndex()); batchDelete(bb.array()); endMethod("removeUnspentTransactionOutput");
beginMethod("addUnspentTransactionOutput"); byte[] key = getTxKey(KeyType.OPENOUT_ALL, out.getHash(), (int) out.getIndex()); batchPut(key, bos.toByteArray()); if (out.getAddress() == null || out.getAddress().equals("")) { if (instrument) endMethod("addUnspentTransactionOutput"); return; } else { } catch (AddressFormatException e) { if (instrument) endMethod("addUnspentTransactionOutput"); return; bb.putInt((int) out.getIndex()); byte[] value = new byte[0]; batchPut(bb.array(), value); if (instrument) endMethod("addUnspentTransactionOutput");