Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

multi: add endpoints for best mainchain and sidechain hashes #42

Merged
merged 4 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
}
}