Skip to content

Commit 1fd5f5f

Browse files
committed
Use version in heartbeat messages, add RPCs to get blocks/bmm inclusions, bump version for release
1 parent 9e0b842 commit 1fd5f5f

File tree

13 files changed

+245
-24
lines changed

13 files changed

+245
-24
lines changed

Cargo.lock

Lines changed: 9 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ authors = [
1616
edition = "2021"
1717
license-file = "LICENSE.txt"
1818
publish = false
19-
version = "0.10.12"
19+
version = "0.11.0"
2020

2121
[workspace.dependencies]
2222
anyhow = "1.0.72"

app/rpc_server.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,33 @@ impl RpcServer for RpcServerImpl {
9090
Ok(mnemonic.to_string())
9191
}
9292

93+
async fn get_block(
94+
&self,
95+
block_hash: thunder::types::BlockHash,
96+
) -> RpcResult<Option<thunder::types::Block>> {
97+
let Some(header) = self
98+
.app
99+
.node
100+
.try_get_header(block_hash)
101+
.map_err(custom_err)?
102+
else {
103+
return Ok(None);
104+
};
105+
let body = self.app.node.get_body(block_hash).map_err(custom_err)?;
106+
let block = thunder::types::Block { header, body };
107+
Ok(Some(block))
108+
}
109+
110+
async fn get_bmm_inclusions(
111+
&self,
112+
block_hash: thunder::types::BlockHash,
113+
) -> RpcResult<Vec<bitcoin::BlockHash>> {
114+
self.app
115+
.node
116+
.get_bmm_inclusions(block_hash)
117+
.map_err(custom_err)
118+
}
119+
93120
async fn get_new_address(&self) -> RpcResult<Address> {
94121
self.app
95122
.wallet

cli/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ pub enum Command {
2424
FormatDepositAddress { address: Address },
2525
/// Generate a mnemonic seed phrase
2626
GenerateMnemonic,
27+
/// Get the block with specified block hash, if it exists
28+
GetBlock {
29+
block_hash: thunder::types::BlockHash,
30+
},
31+
/// Get mainchain blocks that commit to a specified block hash
32+
GetBmmInclusions {
33+
block_hash: thunder::types::BlockHash,
34+
},
2735
/// Get a new address
2836
GetNewAddress,
2937
/// Get wallet addresses, sorted by base58 encoding
@@ -118,6 +126,15 @@ impl Cli {
118126
Command::FormatDepositAddress { address } => {
119127
rpc_client.format_deposit_address(address).await?
120128
}
129+
Command::GetBlock { block_hash } => {
130+
let block = rpc_client.get_block(block_hash).await?;
131+
serde_json::to_string_pretty(&block)?
132+
}
133+
Command::GetBmmInclusions { block_hash } => {
134+
let bmm_inclusions =
135+
rpc_client.get_bmm_inclusions(block_hash).await?;
136+
serde_json::to_string_pretty(&bmm_inclusions)?
137+
}
121138
Command::GenerateMnemonic => rpc_client.generate_mnemonic().await?,
122139
Command::GetNewAddress => {
123140
let address = rpc_client.get_new_address().await?;

lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ rayon = "1.7.0"
3737
rcgen = "0.13.2"
3838
rustls = { version = "0.23.21", default-features = false, features = ["ring"] }
3939
rustreexo = { workspace = true, features = ["with-serde"] }
40+
semver = { version = "1.0.25", features = ["serde"] }
4041
serde = { workspace = true, features = ["derive"] }
4142
serde_json = { workspace = true }
4243
serde_with = { version = "3.4.0" }

lib/authorization.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use borsh::BorshSerialize;
22
use rayon::iter::{IntoParallelRefIterator as _, ParallelIterator as _};
33
use serde::{Deserialize, Serialize};
4+
use utoipa::ToSchema;
45

56
use crate::types::{
67
Address, AuthorizedTransaction, Body, GetAddress, Transaction, Verify,
@@ -47,12 +48,21 @@ where
4748
}
4849

4950
#[derive(
50-
BorshSerialize, Debug, Clone, Deserialize, Eq, PartialEq, Serialize,
51+
BorshSerialize,
52+
Debug,
53+
Clone,
54+
Deserialize,
55+
Eq,
56+
PartialEq,
57+
Serialize,
58+
ToSchema,
5159
)]
5260
pub struct Authorization {
5361
#[borsh(serialize_with = "borsh_serialize_verifying_key")]
62+
#[schema(value_type = String)]
5463
pub verifying_key: VerifyingKey,
5564
#[borsh(serialize_with = "borsh_serialize_signature")]
65+
#[schema(value_type = String)]
5666
pub signature: Signature,
5767
}
5868

lib/net/peer.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::{
2323
state::{self, State},
2424
types::{
2525
hash, proto::mainchain, AuthorizedTransaction, BlockHash, BmmResult,
26-
Body, Hash, Header, Tip, Txid,
26+
Body, Hash, Header, Tip, Txid, Version, VERSION,
2727
},
2828
};
2929

@@ -103,11 +103,10 @@ pub struct TipInfo {
103103
total_work: Work,
104104
}
105105

106-
#[derive(
107-
BorshSerialize, Clone, Copy, Debug, Default, Deserialize, Serialize,
108-
)]
106+
#[derive(BorshSerialize, Clone, Copy, Debug, Deserialize, Serialize)]
109107
pub struct PeerState {
110108
tip_info: Option<TipInfo>,
109+
version: Version,
111110
}
112111

113112
/// Unique identifier for a peer state
@@ -1200,8 +1199,10 @@ impl ConnectionTask {
12001199
total_work,
12011200
})
12021201
};
1203-
let heartbeat_msg =
1204-
Request::Heartbeat(PeerState { tip_info });
1202+
let heartbeat_msg = Request::Heartbeat(PeerState {
1203+
tip_info,
1204+
version: *VERSION,
1205+
});
12051206
task_set.spawn({
12061207
let connection = self.connection.clone();
12071208
let response_tx = response_tx.clone();

lib/node/mod.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -368,27 +368,44 @@ where
368368
&self,
369369
block_hash: BlockHash,
370370
) -> Result<Option<Body>, Error> {
371-
let txn = self.env.read_txn()?;
372-
Ok(self.archive.try_get_body(&txn, block_hash)?)
371+
let rotxn = self.env.read_txn()?;
372+
Ok(self.archive.try_get_body(&rotxn, block_hash)?)
373373
}
374374

375375
pub fn get_body(&self, block_hash: BlockHash) -> Result<Body, Error> {
376-
let txn = self.env.read_txn()?;
377-
Ok(self.archive.get_body(&txn, block_hash)?)
376+
let rotxn = self.env.read_txn()?;
377+
Ok(self.archive.get_body(&rotxn, block_hash)?)
378+
}
379+
380+
pub fn get_bmm_inclusions(
381+
&self,
382+
block_hash: BlockHash,
383+
) -> Result<Vec<bitcoin::BlockHash>, Error> {
384+
let rotxn = self.env.read_txn()?;
385+
let bmm_inclusions = self
386+
.archive
387+
.get_bmm_results(&rotxn, block_hash)?
388+
.into_iter()
389+
.filter_map(|(block_hash, bmm_res)| match bmm_res {
390+
BmmResult::Verified => Some(block_hash),
391+
BmmResult::Failed => None,
392+
})
393+
.collect();
394+
Ok(bmm_inclusions)
378395
}
379396

380397
pub fn get_all_transactions(
381398
&self,
382399
) -> Result<Vec<AuthorizedTransaction>, Error> {
383-
let txn = self.env.read_txn()?;
384-
let transactions = self.mempool.take_all(&txn)?;
400+
let rotxn = self.env.read_txn()?;
401+
let transactions = self.mempool.take_all(&rotxn)?;
385402
Ok(transactions)
386403
}
387404

388405
/// Get total sidechain wealth in Bitcoin
389406
pub fn get_sidechain_wealth(&self) -> Result<bitcoin::Amount, Error> {
390-
let txn = self.env.read_txn()?;
391-
Ok(self.state.sidechain_wealth(&txn)?)
407+
let rotxn = self.env.read_txn()?;
408+
Ok(self.state.sidechain_wealth(&rotxn)?)
392409
}
393410

394411
pub fn get_transactions(

lib/types/hashes.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,27 @@ impl std::fmt::Debug for BlockHash {
6363
}
6464
}
6565

66+
impl FromStr for BlockHash {
67+
type Err = hex::FromHexError;
68+
fn from_str(s: &str) -> Result<Self, Self::Err> {
69+
Hash::from_hex(s).map(Self)
70+
}
71+
}
72+
73+
impl utoipa::PartialSchema for BlockHash {
74+
fn schema() -> utoipa::openapi::RefOr<utoipa::openapi::schema::Schema> {
75+
let obj =
76+
utoipa::openapi::Object::with_type(utoipa::openapi::Type::String);
77+
utoipa::openapi::RefOr::T(utoipa::openapi::Schema::Object(obj))
78+
}
79+
}
80+
81+
impl utoipa::ToSchema for BlockHash {
82+
fn name() -> std::borrow::Cow<'static, str> {
83+
std::borrow::Cow::Borrowed("BlockHash")
84+
}
85+
}
86+
6687
#[derive(
6788
BorshSerialize,
6889
Clone,

lib/types/mod.rs

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,25 @@ where
109109
}
110110

111111
#[derive(
112-
BorshSerialize, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize,
112+
BorshSerialize,
113+
Clone,
114+
Debug,
115+
Deserialize,
116+
Eq,
117+
Hash,
118+
PartialEq,
119+
Serialize,
120+
ToSchema,
113121
)]
114122
pub struct Header {
115123
pub merkle_root: MerkleRoot,
116124
pub prev_side_hash: Option<BlockHash>,
117125
#[borsh(serialize_with = "borsh_serialize_bitcoin_block_hash")]
126+
#[schema(value_type = schema::BitcoinBlockHash)]
118127
pub prev_main_hash: bitcoin::BlockHash,
119128
/// Utreexo roots
120129
#[borsh(serialize_with = "borsh_serialize_utreexo_roots")]
130+
#[schema(value_type = Vec<schema::UtreexoNodeHash>)]
121131
pub roots: Vec<BitcoinNodeHash>,
122132
}
123133

@@ -351,3 +361,50 @@ pub struct Tip {
351361
#[borsh(serialize_with = "borsh_serialize_bitcoin_block_hash")]
352362
pub main_block_hash: bitcoin::BlockHash,
353363
}
364+
365+
/// Semver-compatible version
366+
#[derive(
367+
BorshSerialize,
368+
Clone,
369+
Copy,
370+
Debug,
371+
Deserialize,
372+
Eq,
373+
Hash,
374+
PartialEq,
375+
Serialize,
376+
)]
377+
pub struct Version {
378+
pub major: u64,
379+
pub minor: u64,
380+
pub patch: u64,
381+
}
382+
383+
impl From<semver::Version> for Version {
384+
fn from(version: semver::Version) -> Self {
385+
let semver::Version {
386+
major,
387+
minor,
388+
patch,
389+
pre: _,
390+
build: _,
391+
} = version;
392+
Self {
393+
major,
394+
minor,
395+
patch,
396+
}
397+
}
398+
}
399+
400+
// Do not make this public outside of this crate, as it could break semver
401+
pub(crate) static VERSION: LazyLock<Version> = LazyLock::new(|| {
402+
const VERSION_STR: &str = env!("CARGO_PKG_VERSION");
403+
semver::Version::parse(VERSION_STR).unwrap().into()
404+
});
405+
406+
#[derive(Clone, Debug, Deserialize, Serialize, ToSchema)]
407+
pub struct Block {
408+
pub header: Header,
409+
pub body: Body,
410+
}

0 commit comments

Comments
 (0)