public StoredTransactionOutput getTransactionOutput(Sha256Hash hash, long index) throws BlockStoreException { maybeConnect(); PreparedStatement s = null; try { s = conn.get() .prepareStatement( "SELECT height, value, scriptBytes FROM openOutputs " + "WHERE hash = ? AND index = ?"); s.setBytes(1, hash.getBytes()); // index is actually an unsigned int s.setInt(2, (int) index); ResultSet results = s.executeQuery(); if (!results.next()) { return null; } // Parse it. int height = results.getInt(1); BigInteger value = new BigInteger(results.getBytes(2)); // Tell the StoredTransactionOutput that we are a coinbase, as that is encoded in height StoredTransactionOutput txout = new StoredTransactionOutput(hash, index, value, height, true, results.getBytes(3)); return txout; } catch (SQLException ex) { throw new BlockStoreException(ex); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); } } }
protected void bitcoinSerializeToStream(OutputStream stream) throws IOException { // Version, for some reason. Utils.uint32ToByteStreamLE(NetworkParameters.PROTOCOL_VERSION, stream); // Then a vector of block hashes. This is actually a "block locator", a set of block // identifiers that spans the entire chain with exponentially increasing gaps between // them, until we end up at the genesis block. See CBlockLocator::Set() stream.write(new VarInt(locator.size()).encode()); for (Sha256Hash hash : locator) { // Have to reverse as wire format is little endian. stream.write(Utils.reverseBytes(hash.getBytes())); } // Next, a block ID to stop at. stream.write(Utils.reverseBytes(stopHash.getBytes())); }
private static Sha256Hash calcHash(int height, int pos, List<Sha256Hash> hashes) { if (height == 0) { // Hash at height 0 is just the regular tx hash itself. return hashes.get(pos); } int h = height - 1; int p = pos * 2; Sha256Hash left = calcHash(h, p, hashes); // Calculate right hash if not beyond the end of the array - copy left hash otherwise. Sha256Hash right; if (p + 1 < getTreeWidth(hashes.size(), h)) { right = calcHash(h, p + 1, hashes); } else { right = left; } return combineLeftRight(left.getBytes(), right.getBytes()); }
@Override public void neoscoinSerializeToStream(OutputStream stream) throws IOException { uint32ToByteStreamLE(transactionCount, stream); stream.write(new VarInt(hashes.size()).encode()); for (Sha256Hash hash : hashes) stream.write(reverseBytes(hash.getBytes())); stream.write(new VarInt(matchedChildBits.length).encode()); stream.write(matchedChildBits); }
/** * Build a 'getblocks' message * * @param peer Destination peer * @param blockList Block hash list * @param stopBlock Stop block hash (Sha256Hash.ZERO_HASH to get all blocks) * @return 'getblocks' message */ public static Message buildGetBlocksMessage( Peer peer, List<Sha256Hash> blockList, Sha256Hash stopBlock) { // // Build the message payload // // The protocol version will be set to the lesser of our version and the peer version // SerializedBuffer msgBuffer = new SerializedBuffer(blockList.size() * 32 + 40); msgBuffer .putInt(Math.min(peer.getVersion(), NetParams.PROTOCOL_VERSION)) .putVarInt(blockList.size()); for (Sha256Hash hash : blockList) { msgBuffer.putBytes(Helper.reverseBytes(hash.getBytes())); } msgBuffer.putBytes(Helper.reverseBytes(stopBlock.getBytes())); // // Build the message // ByteBuffer buffer = MessageHeader.buildMessage("getblocks", msgBuffer); return new Message(buffer, peer, MessageHeader.MessageCommand.GETBLOCKS); }
public static byte[] hashForSignature( Transaction tx, int inputIndex, byte[] connectedScript, byte sigHashType) { byte[] serializedSig = serializeForSignature(tx, inputIndex, connectedScript, sigHashType); Sha256Hash hash = Sha256Hash.twiceOf(serializedSig); String hashHex = Utils.HEX.encode(hash.getBytes()); // check hash against the reference implementation inside of bitcoinj byte[] referenceImplementation = tx.hashForSignature(inputIndex, connectedScript, sigHashType).getBytes(); String referenceImplementationHex = Utils.HEX.encode(referenceImplementation); if (!hashHex.equals(referenceImplementationHex)) { logger.error("bitcoins: " + hashHex); logger.error("bitcoinj: " + referenceImplementationHex); throw new RuntimeException( "Difference between BitcoinJSignatureSerialization & Actual Bitcoinj\n" + "bitcoin-s: " + hashHex + "\n" + "bitcoin-j: " + referenceImplementationHex); } return hash.getBytes(); }
@Override void bitcoinSerializeToStream(OutputStream stream) throws IOException { Utils.uint32ToByteStreamLE(height, stream); stream.write(chainHead.getBytes()); stream.write(new VarInt(hits.length).encode()); stream.write(hits); stream.write(new VarInt(outputs.size()).encode()); for (TransactionOutput output : outputs) { // TODO: Allow these to be specified, if one day we care about sending this message ourselves // (currently it's just used for unit testing). Utils.uint32ToByteStreamLE(0L, stream); // Version Utils.uint32ToByteStreamLE(0L, stream); // Height output.bitcoinSerializeToStream(stream); } }
// default for testing void writeHeader(OutputStream stream) throws IOException { // try for cached write first if (headerBytesValid && bytes != null && bytes.length >= offset + HEADER_SIZE) { stream.write(bytes, offset, HEADER_SIZE); return; } // fall back to manual write maybeParseHeader(); Utils.uint32ToByteStreamLE(version, stream); stream.write(Utils.reverseBytes(prevBlockHash.getBytes())); stream.write(Utils.reverseBytes(getMerkleRoot().getBytes())); Utils.uint32ToByteStreamLE(time, stream); Utils.uint32ToByteStreamLE(difficultyTarget, stream); Utils.uint32ToByteStreamLE(nonce, stream); }
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; maybeConnect(); PreparedStatement s = null; try { s = conn.get() .prepareStatement( "SELECT chainWork, height, header, wasUndoable FROM headers WHERE hash = ?"); // We skip the first 4 bytes because (on prodnet) the minimum target has 4 0-bytes byte[] hashBytes = new byte[28]; System.arraycopy(hash.getBytes(), 3, hashBytes, 0, 28); s.setBytes(1, hashBytes); ResultSet results = s.executeQuery(); if (!results.next()) { return null; } // Parse it. if (wasUndoableOnly && !results.getBoolean(4)) return null; BigInteger chainWork = new BigInteger(results.getBytes(1)); int height = results.getInt(2); Block b = new Block(params, results.getBytes(3)); b.verifyHeader(); StoredBlock stored = new StoredBlock(b, chainWork, height); return stored; } catch (SQLException ex) { throw new BlockStoreException(ex); } catch (ProtocolException e) { // Corrupted database. throw new BlockStoreException(e); } catch (VerificationException e) { // Should not be able to happen unless the database contains bad // blocks. throw new BlockStoreException(e); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); } } }
public void setChainHead(StoredBlock chainHead) throws BlockStoreException { Sha256Hash hash = chainHead.getHeader().getHash(); this.chainHeadHash = hash; this.chainHeadBlock = chainHead; maybeConnect(); try { PreparedStatement s = conn.get().prepareStatement("UPDATE settings SET value = ? WHERE name = ?"); s.setString(2, CHAIN_HEAD_SETTING); s.setBytes(1, hash.getBytes()); s.executeUpdate(); s.close(); } catch (SQLException ex) { throw new BlockStoreException(ex); } }
@Override @Nullable public StoredBlock get(Sha256Hash hash) throws BlockStoreException { final MappedByteBuffer buffer = this.buffer; if (buffer == null) throw new BlockStoreException("Store closed"); lock.lock(); try { StoredBlock cacheHit = blockCache.get(hash); if (cacheHit != null) return cacheHit; if (notFoundCache.get(hash) != null) return null; // Starting from the current tip of the ring work backwards until we have either found the // block or // wrapped around. int cursor = getRingCursor(buffer); final int startingPoint = cursor; final int fileSize = getFileSize(); final byte[] targetHashBytes = hash.getBytes(); byte[] scratch = new byte[32]; do { cursor -= RECORD_SIZE; if (cursor < FILE_PROLOGUE_BYTES) { // We hit the start, so wrap around. cursor = fileSize - RECORD_SIZE; } // Cursor is now at the start of the next record to check, so read the hash and compare it. buffer.position(cursor); buffer.get(scratch); if (Arrays.equals(scratch, targetHashBytes)) { // Found the target. StoredBlock storedBlock = StoredBlock.deserializeCompact(params, buffer); blockCache.put(hash, storedBlock); return storedBlock; } } while (cursor != startingPoint); // Not found. notFoundCache.put(hash, notFoundMarker); return null; } catch (ProtocolException e) { throw new RuntimeException(e); // Cannot happen. } finally { lock.unlock(); } }
public void setVerifiedChainHead(StoredBlock chainHead) throws BlockStoreException { Sha256Hash hash = chainHead.getHeader().getHash(); this.verifiedChainHeadHash = hash; this.verifiedChainHeadBlock = chainHead; maybeConnect(); try { PreparedStatement s = conn.get().prepareStatement("UPDATE settings SET value = ? WHERE name = ?"); s.setString(2, VERIFIED_CHAIN_HEAD_SETTING); s.setBytes(1, hash.getBytes()); s.executeUpdate(); s.close(); } catch (SQLException ex) { throw new BlockStoreException(ex); } if (this.chainHeadBlock.getHeight() < chainHead.getHeight()) setChainHead(chainHead); removeUndoableBlocksWhereHeightIsLessThan(chainHead.getHeight() - fullStoreDepth); }
@Override public void put(StoredBlock block) throws BlockStoreException { final MappedByteBuffer buffer = this.buffer; if (buffer == null) throw new BlockStoreException("Store closed"); lock.lock(); try { int cursor = getRingCursor(buffer); if (cursor == getFileSize()) { // Wrapped around. cursor = FILE_PROLOGUE_BYTES; } buffer.position(cursor); Sha256Hash hash = block.getHeader().getHash(); notFoundCache.remove(hash); buffer.put(hash.getBytes()); block.serializeCompact(buffer); setRingCursor(buffer, buffer.position()); blockCache.put(hash, block); } finally { lock.unlock(); } }
public boolean hasUnspentOutputs(Sha256Hash hash, int numOutputs) throws BlockStoreException { maybeConnect(); PreparedStatement s = null; try { s = conn.get().prepareStatement("SELECT COUNT(*) FROM openOutputs WHERE hash = ?"); s.setBytes(1, hash.getBytes()); ResultSet results = s.executeQuery(); if (!results.next()) { throw new BlockStoreException("Got no results from a COUNT(*) query"); } int count = results.getInt(1); return count != 0; } catch (SQLException ex) { throw new BlockStoreException(ex); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); } } }
public StoredUndoableBlock getUndoBlock(Sha256Hash hash) throws BlockStoreException { maybeConnect(); PreparedStatement s = null; try { s = conn.get() .prepareStatement( "SELECT txOutChanges, transactions FROM undoableBlocks WHERE hash = ?"); // We skip the first 4 bytes because (on prodnet) the minimum target has 4 0-bytes byte[] hashBytes = new byte[28]; System.arraycopy(hash.getBytes(), 3, hashBytes, 0, 28); s.setBytes(1, hashBytes); ResultSet results = s.executeQuery(); if (!results.next()) { return null; } // Parse it. byte[] txOutChanges = results.getBytes(1); byte[] transactions = results.getBytes(2); StoredUndoableBlock block; if (txOutChanges == null) { int offset = 0; int numTxn = ((transactions[offset++] & 0xFF) << 0) | ((transactions[offset++] & 0xFF) << 8) | ((transactions[offset++] & 0xFF) << 16) | ((transactions[offset++] & 0xFF) << 24); List<Transaction> transactionList = new LinkedList<Transaction>(); for (int i = 0; i < numTxn; i++) { Transaction tx = new Transaction(params, transactions, offset); transactionList.add(tx); offset += tx.getMessageSize(); } block = new StoredUndoableBlock(hash, transactionList); } else { TransactionOutputChanges outChangesObject = new TransactionOutputChanges(new ByteArrayInputStream(txOutChanges)); block = new StoredUndoableBlock(hash, outChangesObject); } return block; } catch (SQLException ex) { throw new BlockStoreException(ex); } catch (NullPointerException e) { // Corrupted database. throw new BlockStoreException(e); } catch (ClassCastException e) { // Corrupted database. throw new BlockStoreException(e); } catch (ProtocolException e) { // Corrupted database. throw new BlockStoreException(e); } catch (IOException e) { // Corrupted database. throw new BlockStoreException(e); } finally { if (s != null) try { s.close(); } catch (SQLException e) { throw new BlockStoreException("Failed to close PreparedStatement"); } } }
@Override public void bitcoinSerializeToStream(OutputStream stream) throws IOException { stream.write(Utils.reverseBytes(hash.getBytes())); }
public static ByteString hashToByteString(Sha256Hash hash) { return ByteString.copyFrom(hash.getBytes()); }