Skip to content

Commit

Permalink
multi: add endpoints for best mainchain and sidechain hashes (#42)
Browse files Browse the repository at this point in the history
* multi: add endpoints for best mainchain and sidechain hashes

* human-readable serialization for block hashes

* dev: fmt code

* fixups

---------

Co-authored-by: Ash Manning <[email protected]>
  • Loading branch information
torkelrogstad and Ash-L2L authored Feb 27, 2025
1 parent d26f458 commit 58fe8ba
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 8 deletions.
23 changes: 23 additions & 0 deletions app/rpc_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,29 @@ impl RpcServer for RpcServerImpl {
Ok(Some(block))
}

async fn get_best_sidechain_block_hash(
&self,
) -> RpcResult<Option<thunder::types::BlockHash>> {
self.app.node.try_get_tip().map_err(custom_err)
}

async fn get_best_mainchain_block_hash(
&self,
) -> RpcResult<Option<bitcoin::BlockHash>> {
let Some(sidechain_hash) =
self.app.node.try_get_tip().map_err(custom_err)?
else {
// No sidechain tip, so no best mainchain block hash.
return Ok(None);
};
let block_hash = self
.app
.node
.get_best_main_verification(sidechain_hash)
.map_err(custom_err)?;
Ok(Some(block_hash))
}

async fn get_bmm_inclusions(
&self,
block_hash: thunder::types::BlockHash,
Expand Down
12 changes: 12 additions & 0 deletions cli/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ pub enum Command {
FormatDepositAddress { address: Address },
/// Generate a mnemonic seed phrase
GenerateMnemonic,
/// Get the best mainchain block hash
GetBestMainchainBlockHash,
/// Get the best sidechain block hash
GetBestSidechainBlockHash,
/// Get the block with specified block hash, if it exists
GetBlock {
block_hash: thunder::types::BlockHash,
Expand Down Expand Up @@ -137,6 +141,14 @@ where
let block = rpc_client.get_block(block_hash).await?;
serde_json::to_string_pretty(&block)?
}
Command::GetBestMainchainBlockHash => {
let block_hash = rpc_client.get_best_mainchain_block_hash().await?;
serde_json::to_string_pretty(&block_hash)?
}
Command::GetBestSidechainBlockHash => {
let block_hash = rpc_client.get_best_sidechain_block_hash().await?;
serde_json::to_string_pretty(&block_hash)?
}
Command::GetBmmInclusions { block_hash } => {
let bmm_inclusions =
rpc_client.get_bmm_inclusions(block_hash).await?;
Expand Down
15 changes: 15 additions & 0 deletions lib/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@ where
Ok(utxos)
}

pub fn try_get_tip(&self) -> Result<Option<BlockHash>, Error> {
let rotxn = self.env.read_txn().map_err(EnvError::from)?;
let tip = self.state.try_get_tip(&rotxn).map_err(DbError::from)?;
Ok(tip)
}

pub fn get_tip_accumulator(&self) -> Result<Accumulator, Error> {
let rotxn = self.env.read_txn().map_err(EnvError::from)?;
Ok(self.state.get_accumulator(&rotxn)?)
Expand Down Expand Up @@ -398,6 +404,15 @@ where
Ok(self.archive.get_body(&rotxn, block_hash)?)
}

pub fn get_best_main_verification(
&self,
hash: BlockHash,
) -> Result<bitcoin::BlockHash, Error> {
let rotxn = self.env.read_txn().map_err(EnvError::from)?;
let hash = self.archive.get_best_main_verification(&rotxn, hash)?;
Ok(hash)
}

pub fn get_bmm_inclusions(
&self,
block_hash: BlockHash,
Expand Down
2 changes: 1 addition & 1 deletion lib/types/hashes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ pub type Hash = [u8; BLAKE3_LENGTH];
PartialOrd,
Serialize,
)]
pub struct BlockHash(pub Hash);
pub struct BlockHash(#[serde(with = "serde_hexstr_human_readable")] pub Hash);

impl From<Hash> for BlockHash {
fn from(other: Hash) -> Self {
Expand Down
22 changes: 21 additions & 1 deletion rpc-api/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ pub trait Rpc {
#[method(name = "connect_peer")]
async fn connect_peer(
&self,
#[open_api_method_arg(schema(PartialSchema = "schema::SocketAddr"))]
#[open_api_method_arg(schema(
PartialSchema = "thunder_schema::SocketAddr"
))]
addr: SocketAddr,
) -> RpcResult<()>;

Expand Down Expand Up @@ -74,6 +76,24 @@ pub trait Rpc {
block_hash: thunder::types::BlockHash,
) -> RpcResult<Vec<bitcoin::BlockHash>>;

/// Get the best mainchain block hash known by Thunder
#[open_api_method(output_schema(
PartialSchema = "schema::Optional<thunder_schema::BitcoinBlockHash>"
))]
#[method(name = "get_best_mainchain_block_hash")]
async fn get_best_mainchain_block_hash(
&self,
) -> RpcResult<Option<bitcoin::BlockHash>>;

/// Get the best sidechain block hash known by Thunder
#[open_api_method(output_schema(
PartialSchema = "schema::Optional<thunder::types::BlockHash>"
))]
#[method(name = "get_best_sidechain_block_hash")]
async fn get_best_sidechain_block_hash(
&self,
) -> RpcResult<Option<thunder::types::BlockHash>>;

/// Get a new address
#[method(name = "get_new_address")]
async fn get_new_address(&self) -> RpcResult<Address>;
Expand Down
23 changes: 17 additions & 6 deletions rpc-api/schema.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
//! Schemas for OpenAPI
use std::marker::PhantomData;

use utoipa::{
openapi::{self, RefOr, Schema},
PartialSchema, ToSchema,
Expand Down Expand Up @@ -29,11 +31,20 @@ impl PartialSchema for OpenApi {
}
}

pub struct SocketAddr;

impl PartialSchema for SocketAddr {
fn schema() -> RefOr<Schema> {
let obj = utoipa::openapi::Object::with_type(openapi::Type::String);
RefOr::T(Schema::Object(obj))
/// Optional `T`
pub struct Optional<T>(PhantomData<T>);

impl<T> PartialSchema for Optional<T>
where
T: PartialSchema,
{
fn schema() -> openapi::RefOr<openapi::schema::Schema> {
openapi::schema::OneOf::builder()
.item(
openapi::schema::Object::builder()
.schema_type(openapi::schema::Type::Null),
)
.item(T::schema())
.into()
}
}

0 comments on commit 58fe8ba

Please sign in to comment.