Skip to content

Commit

Permalink
Create the basics for a json-rpc client lib
Browse files Browse the repository at this point in the history
This commit adds a trait with all possible json-rpc methods exposed by
florestad, as well as all the types returned by it.

Specific implementations should use some networking lib like jsonrpc or
reqwest to actually implement the trait methods and make a concrete
implementation.
  • Loading branch information
Davidson-Souza committed Jan 17, 2024
1 parent a648209 commit 1700855
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 0 deletions.
115 changes: 115 additions & 0 deletions crates/floresta-cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX license specifier: MIT

//! # floresta-cli - A command line interface for florestad
//!
//! Florestad is a lightweight Bitcoin full node, built with libfloresta. It gives
//! you complete control over your Bitcoin node with a simple json-rpc interface that
//! may be used either from command line or programmatically. This crate provides a
//! ready-to-use library for interacting with florestad's json-rpc interface in your rust
//! application.

mod rpc_types;

use bitcoin::block::Header as BlockHeader;
use bitcoin::BlockHash;
use bitcoin::Txid;
use rpc_types::*;
use serde_json::Value;

type Result<T> = std::result::Result<T, rpc_types::Error>;

/// A trait specifying all possible methods for floresta's json-rpc
pub trait FlorestaRPC {
/// Get the BIP158 filter for a given block height
///
/// BIP158 filters are a compact representation of the set of transactions in a block,
/// designed for efficient light client synchronization. This method returns the filter
/// for a given block height, encoded as a hexadecimal string.
/// You need to have enabled block filters by setting the `blockfilters=1` option
fn get_block_filter(&self, heigth: u32) -> Result<String>;
/// Returns general information about the chain we are on
///
/// This method returns a bunch of information about the chain we are on, including
/// the current height, the best block hash, the difficulty, and whether we are
/// currently in IBD (Initial Block Download) mode.
fn get_blockchain_info(&self) -> Result<GetBlockchainInfoRes>;
/// Returns the hash of the block at the given height
///
/// This method returns the hash of the block at the given height. If the height is
/// invalid, an error is returned.
fn get_block_hash(&self, height: u32) -> Result<BlockHash>;
/// Returns the block header for the given block hash
///
/// This method returns the block header for the given block hash, as defined
/// in the Bitcoin protocol specification. A header contains the block's version,
/// the previous block hash, the merkle root, the timestamp, the difficulty target,
/// and the nonce.
fn get_block_header(&self, hash: BlockHash) -> Result<BlockHeader>;
/// Gets a transaction from the blockchain
///
/// This method returns a transaction that's cached in our wallet. If the verbosity flag is
/// set to false, the transaction is returned as a hexadecimal string. If the verbosity
/// flag is set to true, the transaction is returned as a json object.
fn get_transaction(&self, tx_id: Txid, verbosity: Option<bool>) -> Result<Value>;
/// Returns the proof that one or more transactions were included in a block
///
/// This method returns the Merkle proof, showing that a transaction was included in a block.
/// The pooof is returned as a vector hexadecimal string.
fn get_tx_proof(&self, tx_id: Txid) -> Result<Vec<String>>;
/// Loads up a descriptor into the wallet
///
/// This method loads up a descriptor into the wallet. If the rescan option is not None,
/// the wallet will be rescanned for transactions matching the descriptor. If you have
/// compact block filters enabled, this process will be much faster and use less bandwidth.
/// The rescan parameter is the height at which to start the rescan, and should be at least
/// as old as the oldest transaction this descriptor could have been used in.
fn load_descriptor(&self, descriptor: String, rescan: Option<u32>) -> Result<()>;
/// Trigger a rescan of the wallet
///
/// This method triggers a rescan of the wallet. If you have compact block filters enabled,
/// this process will be much faster and use less bandwidth. If you don't have compact block
/// filters, we'll need to download the entire blockchain again, which will take a while.
/// The rescan parameter is the height at which to start the rescan, and should be at least
/// as old as the oldest transaction this descriptor could have been used in.
fn rescan(&self, rescan: u32) -> Result<bool>;
/// Returns the current height of the blockchain
fn get_height(&self) -> Result<u32>;
/// Sends a hex-encoded transaction to the network
///
/// This method sends a transaction to the network. The transaction should be encoded as a
/// hexadecimal string. If the transaction is valid, it will be broadcast to the network, and
/// return the transaction id. If the transaction is invalid, an error will be returned.
fn send_raw_transaction(&self, tx: String) -> Result<Txid>;
/// Gets the current accumulator for the chain we're on
///
/// This method returns the current accumulator for the chain we're on. The accumulator is
/// a set of roots, that let's us prove that a UTXO exists in the chain. This method returns
/// a vector of hexadecimal strings, each of which is a root in the accumulator.
fn get_roots(&self) -> Result<Vec<String>>;
/// Gets information about the peers we're connected with
///
/// This method returns information about the peers we're connected with. This includes
/// the peer's IP address, the peer's version, the peer's user agent, and the peer's
/// current height.
fn get_peer_info(&self) -> Result<Vec<PeerInfo>>;
/// Returns a block, given a block hash
///
/// This method returns a block, given a block hash. If the verbosity flag is 0, the block
/// is returned as a hexadecimal string. If the verbosity flag is 1, the block is returned
/// as a json object.
fn get_block(&self, hash: BlockHash, verbosity: Option<u8>) -> Result<Value>;
/// Finds an specific utxo in the chain
///
/// You can use this to look for a utxo. If it exists, it will return the amount and
/// scriptPubKey of this utxo. It returns an empty object if the utxo doesn't exist.
/// You must have enabled block filters by setting the `blockfilters=1` option.
fn get_tx_out(&self, tx_id: Txid, outpoint: u32) -> Result<Value>;
/// Stops the florestad process
///
/// This can be used to gracefully stop the florestad process.
fn stop(&self) -> Result<bool>;
/// Tells florestad to connect with a peer
///
/// You can use this to connect with a given node, providing it's IP address and port.
fn add_node(&self, node: String) -> Result<bool>;
}
115 changes: 115 additions & 0 deletions crates/floresta-cli/src/rpc_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use serde::Deserialize;
use serde::Serialize;

#[derive(Deserialize, Serialize)]
pub struct GetBlockchainInfoRes {
pub best_block: String,
pub height: u32,
pub ibd: bool,
pub validated: u32,
pub latest_work: String,
pub latest_block_time: u32,
pub leaf_count: u32,
pub root_count: u32,
pub root_hashes: Vec<String>,
pub chain: String,
pub progress: f32,
pub difficulty: u64,
}

#[derive(Deserialize, Serialize)]
pub struct RawTxJson {
pub in_active_chain: bool,
pub hex: String,
pub txid: String,
pub hash: String,
pub size: u32,
pub vsize: u32,
pub weight: u32,
pub version: u32,
pub locktime: u32,
pub vin: Vec<TxInJson>,
pub vout: Vec<TxOutJson>,
pub blockhash: String,
pub confirmations: u32,
pub blocktime: u32,
pub time: u32,
}

#[derive(Deserialize, Serialize)]
pub struct TxOutJson {
pub value: u64,
pub n: u32,
pub script_pub_key: ScriptPubKeyJson,
}

#[derive(Deserialize, Serialize)]
pub struct ScriptPubKeyJson {
pub asm: String,
pub hex: String,
pub req_sigs: u32,
#[serde(rename = "type")]
pub type_: String,
pub address: String,
}

#[derive(Deserialize, Serialize)]
pub struct TxInJson {
pub txid: String,
pub vout: u32,
pub script_sig: ScriptSigJson,
pub sequence: u32,
pub witness: Vec<String>,
}

#[derive(Deserialize, Serialize)]
pub struct ScriptSigJson {
pub asm: String,
pub hex: String,
}

#[derive(Deserialize, Serialize)]
pub struct BlockJson {
pub hash: String,
pub confirmations: u32,
pub strippedsize: usize,
pub size: usize,
pub weight: usize,
pub height: u32,
pub version: i32,
#[serde(rename = "versionHex")]
pub version_hex: String,
pub merkleroot: String,
pub tx: Vec<String>,
pub time: u32,
pub mediantime: u32,
pub nonce: u32,
pub bits: String,
pub difficulty: u128,
pub chainwork: String,
pub n_tx: usize,
pub previousblockhash: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub nextblockhash: Option<String>,
}

#[derive(Debug)]
pub enum Error {
TxNotFound,
InvalidDescriptor,
BlockNotFound,
Chain,
InvalidPort,
InvalidAddress,
Node,
NoBlockFilters,
InvalidNetwork,
}

#[derive(Deserialize, Serialize)]
pub struct PeerInfo {
pub address: String,
pub services: String,
pub user_agent: String,
pub initial_height: u32,
}

0 comments on commit 1700855

Please sign in to comment.