rosetta_server_bitcoin/
lib.rs1use anyhow::Result;
2use bitcoincore_rpc_async::{Auth, Client, RpcApi};
3use rosetta_server::crypto::address::Address;
4use rosetta_server::crypto::PublicKey;
5use rosetta_server::types::{
6 Block, BlockIdentifier, CallRequest, Coin, PartialBlockIdentifier, Transaction,
7 TransactionIdentifier,
8};
9use rosetta_server::{BlockchainClient, BlockchainConfig};
10use serde_json::Value;
11
12pub struct BitcoinClient {
13 config: BlockchainConfig,
14 client: Client,
15 genesis_block: BlockIdentifier,
16}
17
18#[async_trait::async_trait]
19impl BlockchainClient for BitcoinClient {
20 type MetadataParams = ();
21 type Metadata = ();
22
23 fn create_config(network: &str) -> Result<BlockchainConfig> {
24 rosetta_config_bitcoin::config(network)
25 }
26
27 async fn new(config: BlockchainConfig, addr: &str) -> Result<Self> {
28 let client = Client::new(
29 addr.to_string(),
30 Auth::UserPass("rosetta".into(), "rosetta".into()),
31 )
32 .await?;
33 let genesis = client.get_block_hash(0).await?;
34 let genesis_block = BlockIdentifier {
35 index: 0,
36 hash: hex::encode(genesis.as_ref()),
37 };
38 Ok(Self {
39 config,
40 client,
41 genesis_block,
42 })
43 }
44
45 fn config(&self) -> &BlockchainConfig {
46 &self.config
47 }
48
49 fn genesis_block(&self) -> &BlockIdentifier {
50 &self.genesis_block
51 }
52
53 async fn node_version(&self) -> Result<String> {
54 let info = self.client.get_network_info().await?;
55 let major = info.version / 10000;
56 let rest = info.version % 10000;
57 let minor = rest / 100;
58 let patch = rest % 100;
59 Ok(format!("{major}.{minor}.{patch}"))
60 }
61
62 async fn current_block(&self) -> Result<BlockIdentifier> {
63 let index = self.client.get_block_count().await?;
64 let hash = self.client.get_block_hash(index).await?;
65 Ok(BlockIdentifier {
66 index,
67 hash: hex::encode(hash.as_ref()),
68 })
69 }
70
71 async fn balance(&self, _address: &Address, _block: &BlockIdentifier) -> Result<u128> {
72 todo!()
73 }
74
75 async fn coins(&self, _address: &Address, _block: &BlockIdentifier) -> Result<Vec<Coin>> {
76 todo!()
77 }
78
79 async fn faucet(&self, _address: &Address, _value: u128) -> Result<Vec<u8>> {
80 todo!()
81 }
82
83 async fn metadata(
84 &self,
85 _public_key: &PublicKey,
86 _options: &Self::MetadataParams,
87 ) -> Result<Self::Metadata> {
88 Ok(())
89 }
90
91 async fn submit(&self, _transaction: &[u8]) -> Result<Vec<u8>> {
92 todo!()
93 }
94
95 async fn block(&self, _block: &PartialBlockIdentifier) -> Result<Block> {
96 anyhow::bail!("not implemented")
97 }
98
99 async fn block_transaction(
100 &self,
101 _block: &BlockIdentifier,
102 _tx: &TransactionIdentifier,
103 ) -> Result<Transaction> {
104 anyhow::bail!("not implemented")
105 }
106
107 async fn call(&self, _req: &CallRequest) -> Result<Value> {
108 anyhow::bail!("not implemented")
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[tokio::test]
117 async fn test_network_list() -> Result<()> {
118 let config = rosetta_config_bitcoin::config("regtest")?;
119 rosetta_server::tests::network_list(config).await
120 }
121
122 #[tokio::test]
123 async fn test_network_options() -> Result<()> {
124 let config = rosetta_config_bitcoin::config("regtest")?;
125 rosetta_server::tests::network_options::<BitcoinClient>(config).await
126 }
127
128 #[tokio::test]
129 async fn test_network_status() -> Result<()> {
130 let config = rosetta_config_bitcoin::config("regtest")?;
131 rosetta_server::tests::network_status::<BitcoinClient>(config).await
132 }
133
134 #[tokio::test]
135 #[ignore]
136 async fn test_account() -> Result<()> {
137 let config = rosetta_config_bitcoin::config("regtest")?;
138 rosetta_server::tests::account(config).await
139 }
140
141 #[tokio::test]
142 #[ignore]
143 async fn test_construction() -> Result<()> {
144 let config = rosetta_config_bitcoin::config("regtest")?;
145 rosetta_server::tests::construction(config).await
146 }
147}