diff --git a/src/client/rpc_api.rs b/src/client/rpc_api.rs index 8677174..1838431 100644 --- a/src/client/rpc_api.rs +++ b/src/client/rpc_api.rs @@ -17,7 +17,7 @@ use bitcoin::{ }; use bitcoincore_rpc::{ json::{ - self, GetRawTransactionResult, GetRawTransactionResultVin, + self, GetChainTipsResultStatus, GetRawTransactionResult, GetRawTransactionResultVin, GetRawTransactionResultVinScriptSig, GetRawTransactionResultVout, GetRawTransactionResultVoutScriptPubKey, GetTransactionResult, GetTransactionResultDetail, GetTransactionResultDetailCategory, GetTxOutResult, SignRawTransactionResult, WalletTxInfo, @@ -609,6 +609,33 @@ impl RpcApi for Client { errors: None, }) } + + #[tracing::instrument(skip_all)] + fn get_chain_tips(&self) -> bitcoincore_rpc::Result { + let height = self.ledger.get_block_height().unwrap(); + let hash = if height == 0 { + BlockHash::all_zeros() + } else { + self.ledger.get_block_with_height(height)?.block_hash() + }; + + let tip = json::GetChainTipsResultTip { + height: height as u64, + hash, + branch_length: height as usize, + status: GetChainTipsResultStatus::Active, + }; + + Ok(vec![tip]) + } + + #[tracing::instrument(skip_all)] + fn get_block_hash(&self, height: u64) -> bitcoincore_rpc::Result { + Ok(self + .ledger + .get_block_with_height(height as u32)? + .block_hash()) + } } #[cfg(test)] diff --git a/src/ledger/block.rs b/src/ledger/block.rs index 46c2ae3..56411c5 100644 --- a/src/ledger/block.rs +++ b/src/ledger/block.rs @@ -6,7 +6,7 @@ use crate::utils; use bitcoin::block::{Header, Version}; use bitcoin::consensus::{Decodable, Encodable}; use bitcoin::hashes::Hash; -use bitcoin::{Address, Block, BlockHash, CompactTarget, Transaction, Txid}; +use bitcoin::{Address, Block, BlockHash, CompactTarget, Transaction, TxMerkleNode, Txid}; use rusqlite::params; use std::str::FromStr; use std::time::{SystemTime, UNIX_EPOCH}; @@ -145,10 +145,7 @@ impl Ledger { } }; // Genesis block will also return a database error. Ignore that. - let body = match body { - Ok(b) => b, - Err(_) => Vec::new(), - }; + let body = body.unwrap_or_default(); match Block::consensus_decode(&mut body.as_slice()) { Ok(block) => Ok(block), @@ -163,6 +160,21 @@ impl Ledger { let mut encoded_hash: Vec = Vec::new(); hash.consensus_encode(&mut encoded_hash).unwrap(); + // Handle genesis block. + if hash == BlockHash::all_zeros() { + return Ok(Block { + header: Header { + version: Version::TWO, + prev_blockhash: BlockHash::all_zeros(), + merkle_root: TxMerkleNode::all_zeros(), + time: 0, + bits: CompactTarget::default(), + nonce: 0, + }, + txdata: vec![], + }); + } + let qr = match self.database.lock().unwrap().query_row( "SELECT body FROM blocks WHERE hash = ?1", params![encoded_hash], diff --git a/src/ledger/mod.rs b/src/ledger/mod.rs index 4b0120b..5867ff5 100644 --- a/src/ledger/mod.rs +++ b/src/ledger/mod.rs @@ -125,13 +125,13 @@ impl Ledger { ( height INTEGER NOT NULL, time INTEGER NOT NULL, - hash BLOB NOT NULL, + hash TEXT NOT NULL, coinbase TEXT NOT NULL, body BLOB NOT NULL CONSTRAINT height PRIMARY KEY ); - INSERT INTO blocks (height, time, hash, coinbase, body) VALUES (0, 500000000, 0, 0, 0); + INSERT INTO blocks (height, time, hash, coinbase, body) VALUES (0, 500000000, '00000000000000000000', 0, 0); CREATE TABLE mempool (