Skip to content

Commit d8f23f4

Browse files
authored
getblockmeta: allow request by height (#73)
1 parent 0da2be9 commit d8f23f4

File tree

3 files changed

+85
-49
lines changed

3 files changed

+85
-49
lines changed

client/src/client.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@ pub struct Client {
3838

3939
/// A block structure containing validated transaction metadata
4040
/// relevant to the Spaces protocol
41-
#[derive(Clone, Serialize, Deserialize, Encode, Decode)]
41+
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
4242
pub struct BlockMeta {
4343
pub height: u32,
4444
pub tx_meta: Vec<TxEntry>,
4545
}
4646

47-
#[derive(Clone, Serialize, Deserialize, Encode, Decode)]
47+
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
4848
pub struct TxEntry {
4949
#[serde(flatten)]
5050
pub changeset: TxChangeSet,
5151
#[serde(skip_serializing_if = "Option::is_none", flatten)]
5252
pub tx: Option<TxData>,
5353
}
5454

55-
#[derive(Clone, Serialize, Deserialize, Encode, Decode)]
55+
#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
5656
pub struct TxData {
5757
pub position: u32,
5858
pub raw: Bytes,

client/src/rpc.rs

+81-45
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ pub struct RootAnchor {
8080
pub block: ChainAnchor,
8181
}
8282

83+
#[derive(Debug, Clone, Serialize, Deserialize)]
84+
#[serde(untagged)]
85+
pub enum HeightOrHash {
86+
Hash(BlockHash),
87+
Height(u32),
88+
}
89+
90+
#[derive(Debug, Clone, Serialize, Deserialize)]
91+
pub struct BlockMetaWithHash {
92+
pub hash: BlockHash,
93+
#[serde(flatten)]
94+
pub block_meta: BlockMeta,
95+
}
96+
8397
pub enum ChainStateCommand {
8498
CheckPackage {
8599
txs: Vec<String>,
@@ -105,8 +119,8 @@ pub enum ChainStateCommand {
105119
resp: Responder<anyhow::Result<Option<TxEntry>>>,
106120
},
107121
GetBlockMeta {
108-
block_hash: BlockHash,
109-
resp: Responder<anyhow::Result<Option<BlockMeta>>>,
122+
height_or_hash: HeightOrHash,
123+
resp: Responder<anyhow::Result<BlockMetaWithHash>>,
110124
},
111125
EstimateBid {
112126
target: usize,
@@ -179,8 +193,8 @@ pub trait Rpc {
179193
#[method(name = "getblockmeta")]
180194
async fn get_block_meta(
181195
&self,
182-
block_hash: BlockHash,
183-
) -> Result<Option<BlockMeta>, ErrorObjectOwned>;
196+
height_or_hash: HeightOrHash,
197+
) -> Result<BlockMetaWithHash, ErrorObjectOwned>;
184198

185199
#[method(name = "gettxmeta")]
186200
async fn get_tx_meta(&self, txid: Txid) -> Result<Option<TxEntry>, ErrorObjectOwned>;
@@ -602,19 +616,6 @@ impl WalletManager {
602616
Ok(())
603617
}
604618

605-
pub async fn get_block_hash(
606-
&self,
607-
client: &reqwest::Client,
608-
height: u32,
609-
) -> anyhow::Result<BlockId> {
610-
let hash = self
611-
.rpc
612-
.send_json(&client, &self.rpc.get_block_hash(height))
613-
.await?;
614-
615-
Ok(BlockId { height, hash })
616-
}
617-
618619
async fn get_wallet_start_block(&self, client: &reqwest::Client) -> anyhow::Result<BlockId> {
619620
let count: i32 = self
620621
.rpc
@@ -800,11 +801,11 @@ impl RpcServer for RpcServerImpl {
800801

801802
async fn get_block_meta(
802803
&self,
803-
block_hash: BlockHash,
804-
) -> Result<Option<BlockMeta>, ErrorObjectOwned> {
804+
height_or_hash: HeightOrHash,
805+
) -> Result<BlockMetaWithHash, ErrorObjectOwned> {
805806
let data = self
806807
.store
807-
.get_block_meta(block_hash)
808+
.get_block_meta(height_or_hash)
808809
.await
809810
.map_err(|error| ErrorObjectOwned::owned(-1, error.to_string(), None::<String>))?;
810811

@@ -1075,55 +1076,76 @@ impl AsyncChainState {
10751076
BlockHash::from_str(info.get("blockhash").and_then(|t| t.as_str()).ok_or_else(
10761077
|| anyhow!("Could not retrieve block hash for tx (is it in the mempool?)"),
10771078
)?)?;
1078-
let block = Self::get_indexed_block(index, &block_hash, client, rpc, chain_state).await?;
1079+
let block = Self::get_indexed_block(
1080+
index,
1081+
HeightOrHash::Hash(block_hash),
1082+
client,
1083+
rpc,
1084+
chain_state,
1085+
)
1086+
.await?;
10791087

1080-
if let Some(block) = block {
1081-
return Ok(block
1082-
.tx_meta
1083-
.into_iter()
1084-
.find(|tx| &tx.changeset.txid == txid));
1085-
}
1086-
Ok(None)
1088+
Ok(block
1089+
.block_meta
1090+
.tx_meta
1091+
.into_iter()
1092+
.find(|tx| &tx.changeset.txid == txid))
10871093
}
10881094

10891095
async fn get_indexed_block(
10901096
index: &mut Option<LiveSnapshot>,
1091-
block_hash: &BlockHash,
1097+
height_or_hash: HeightOrHash,
10921098
client: &reqwest::Client,
10931099
rpc: &BitcoinRpc,
10941100
chain_state: &mut LiveSnapshot,
1095-
) -> Result<Option<BlockMeta>, anyhow::Error> {
1101+
) -> Result<BlockMetaWithHash, anyhow::Error> {
10961102
let index = index
10971103
.as_mut()
10981104
.ok_or_else(|| anyhow!("block index must be enabled"))?;
1099-
let hash = BaseHash::from_slice(block_hash.as_ref());
1100-
let block: Option<BlockMeta> = index
1101-
.get(hash)
1102-
.context("Could not fetch block from index")?;
1105+
let hash = match height_or_hash {
1106+
HeightOrHash::Hash(hash) => hash,
1107+
HeightOrHash::Height(height) => rpc
1108+
.send_json(client, &rpc.get_block_hash(height))
1109+
.await
1110+
.map_err(|e| anyhow!("Could not retrieve block hash ({})", e))?,
1111+
};
11031112

1104-
if let Some(block_set) = block {
1105-
return Ok(Some(block_set));
1113+
if let Some(block_meta) = index
1114+
.get(BaseHash::from_slice(hash.as_ref()))
1115+
.context("Could not fetch block from index")?
1116+
{
1117+
return Ok(BlockMetaWithHash {
1118+
hash,
1119+
block_meta,
1120+
});
11061121
}
11071122

11081123
let info: serde_json::Value = rpc
1109-
.send_json(client, &rpc.get_block_header(block_hash))
1124+
.send_json(client, &rpc.get_block_header(&hash))
11101125
.await
11111126
.map_err(|e| anyhow!("Could not retrieve block ({})", e))?;
11121127

11131128
let height = info
11141129
.get("height")
11151130
.and_then(|t| t.as_u64())
1131+
.and_then(|h| u32::try_from(h).ok())
11161132
.ok_or_else(|| anyhow!("Could not retrieve block height"))?;
11171133

11181134
let tip = chain_state.tip.read().expect("read meta").clone();
1119-
if height > tip.height as u64 {
1135+
if height > tip.height {
11201136
return Err(anyhow!(
11211137
"Spaces is syncing at height {}, requested block height {}",
11221138
tip.height,
11231139
height
11241140
));
11251141
}
1126-
Ok(None)
1142+
Ok(BlockMetaWithHash {
1143+
hash,
1144+
block_meta: BlockMeta {
1145+
height,
1146+
tx_meta: Vec::new(),
1147+
},
1148+
})
11271149
}
11281150

11291151
pub async fn handle_command(
@@ -1171,10 +1193,18 @@ impl AsyncChainState {
11711193
.context("could not fetch spaceout");
11721194
let _ = resp.send(result);
11731195
}
1174-
ChainStateCommand::GetBlockMeta { block_hash, resp } => {
1175-
let res =
1176-
Self::get_indexed_block(block_index, &block_hash, client, rpc, chain_state)
1177-
.await;
1196+
ChainStateCommand::GetBlockMeta {
1197+
height_or_hash,
1198+
resp,
1199+
} => {
1200+
let res = Self::get_indexed_block(
1201+
block_index,
1202+
height_or_hash,
1203+
client,
1204+
rpc,
1205+
chain_state,
1206+
)
1207+
.await;
11781208
let _ = resp.send(res);
11791209
}
11801210
ChainStateCommand::GetTxMeta { txid, resp } => {
@@ -1482,10 +1512,16 @@ impl AsyncChainState {
14821512
resp_rx.await?
14831513
}
14841514

1485-
pub async fn get_block_meta(&self, block_hash: BlockHash) -> anyhow::Result<Option<BlockMeta>> {
1515+
pub async fn get_block_meta(
1516+
&self,
1517+
height_or_hash: HeightOrHash,
1518+
) -> anyhow::Result<BlockMetaWithHash> {
14861519
let (resp, resp_rx) = oneshot::channel();
14871520
self.sender
1488-
.send(ChainStateCommand::GetBlockMeta { block_hash, resp })
1521+
.send(ChainStateCommand::GetBlockMeta {
1522+
height_or_hash,
1523+
resp,
1524+
})
14891525
.await?;
14901526
resp_rx.await?
14911527
}

protocol/src/validate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use crate::{
1717
#[derive(Debug, Clone)]
1818
pub struct Validator {}
1919

20-
#[derive(Clone)]
20+
#[derive(Debug, Clone)]
2121
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
2222
#[cfg_attr(feature = "bincode", derive(Encode, Decode))]
2323
/// A `TxChangeSet` captures all resulting state changes.

0 commit comments

Comments
 (0)