Skip to content

Commit f9b318c

Browse files
committed
New interface
1 parent db4554f commit f9b318c

File tree

9 files changed

+1437
-1013
lines changed

9 files changed

+1437
-1013
lines changed

Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "electrum-client"
3-
version = "0.1.0-beta.6"
3+
version = "0.2.0-beta.1"
44
authors = ["Alekos Filini <[email protected]>"]
55
license = "MIT"
66
homepage = "https://github.com/MagicalBitcoin/rust-electrum-client"
@@ -18,7 +18,6 @@ path = "src/lib.rs"
1818

1919
[dependencies]
2020
log = "^0.4"
21-
env_logger = "0.7"
2221
bitcoin = { version = "0.23", features = ["use-serde"] }
2322
serde = { version = "^1.0", features = ["derive"] }
2423
serde_json = { version = "^1.0" }

examples/plaintext.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
extern crate electrum_client;
22

3-
use electrum_client::Client;
3+
use electrum_client::{Client, ElectrumApi};
44

55
fn main() {
6-
let client = Client::new("kirsche.emzy.de:50001").unwrap();
6+
let client = Client::new("tcp://electrum.blockstream.info:50001", None).unwrap();
77
let res = client.server_features();
88
println!("{:#?}", res);
99
}

examples/ssl.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
extern crate electrum_client;
22

3-
use electrum_client::Client;
3+
use electrum_client::{Client, ElectrumApi};
44

55
fn main() {
6-
let client = Client::new_ssl("electrum2.hodlister.co:50002", true).unwrap();
6+
let client = Client::new("ssl://electrum.blockstream.info:50002", None).unwrap();
77
let res = client.server_features();
88
println!("{:#?}", res);
99
}

examples/tor.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
extern crate electrum_client;
22

3-
use electrum_client::Client;
3+
use electrum_client::{Client, ElectrumApi};
44

55
fn main() {
66
// NOTE: This assumes Tor is running localy, with an unauthenticated Socks5 listening at
77
// localhost:9050
88

9-
let client = Client::new_proxy("ozahtqwp25chjdjd.onion:50001", "127.0.0.1:9050").unwrap();
9+
let client = Client::new("tcp://explorernuoc63nb.onion:110", Some("127.0.0.1:9050")).unwrap();
1010
let res = client.server_features();
1111
println!("{:#?}", res);
1212

1313
// works both with onion v2/v3 (if your Tor supports them)
14-
let client = Client::new_proxy(
15-
"v7gtzf7nua6hdmb2wtqaqioqmesdb4xrlly4zwr7bvayxv2bpg665pqd.onion:50001",
16-
"127.0.0.1:9050",
14+
let client = Client::new(
15+
"tcp://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion:110",
16+
Some("127.0.0.1:9050"),
1717
)
1818
.unwrap();
1919
let res = client.server_features();

src/api.rs

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
//! Electrum APIs
2+
3+
use std::convert::TryInto;
4+
5+
use bitcoin::consensus::encode::{deserialize, serialize};
6+
use bitcoin::{BlockHeader, Script, Transaction, Txid};
7+
8+
use batch::Batch;
9+
use types::*;
10+
11+
/// API calls exposed by an Electrum client
12+
pub trait ElectrumApi {
13+
/// Gets the block header for height `height`.
14+
fn block_header(&self, height: usize) -> Result<BlockHeader, Error> {
15+
Ok(deserialize(&self.block_header_raw(height)?)?)
16+
}
17+
18+
/// Subscribes to notifications for new block headers, by sending a `blockchain.headers.subscribe` call.
19+
fn block_headers_subscribe(&self) -> Result<HeaderNotification, Error> {
20+
self.block_headers_subscribe_raw()?.try_into()
21+
}
22+
23+
/// Tries to pop one queued notification for a new block header that we might have received.
24+
/// Returns `None` if there are no items in the queue.
25+
fn block_headers_pop(&self) -> Result<Option<HeaderNotification>, Error> {
26+
self.block_headers_pop_raw()?
27+
.map(|raw| raw.try_into())
28+
.transpose()
29+
}
30+
31+
/// Gets the transaction with `txid`. Returns an error if not found.
32+
fn transaction_get(&self, txid: &Txid) -> Result<Transaction, Error> {
33+
Ok(deserialize(&self.transaction_get_raw(txid)?)?)
34+
}
35+
36+
/// Batch version of [`transaction_get`](#method.transaction_get).
37+
///
38+
/// Takes a list of `txids` and returns a list of transactions.
39+
fn batch_transaction_get<'t, I>(&self, txids: I) -> Result<Vec<Transaction>, Error>
40+
where
41+
I: IntoIterator<Item = &'t Txid>,
42+
{
43+
self.batch_transaction_get_raw(txids)?
44+
.iter()
45+
.map(|s| Ok(deserialize(s)?))
46+
.collect()
47+
}
48+
49+
/// Batch version of [`block_header`](#method.block_header).
50+
///
51+
/// Takes a list of `heights` of blocks and returns a list of headers.
52+
fn batch_block_header<'s, I>(&self, heights: I) -> Result<Vec<BlockHeader>, Error>
53+
where
54+
I: IntoIterator<Item = u32>,
55+
{
56+
self.batch_block_header_raw(heights)?
57+
.iter()
58+
.map(|s| Ok(deserialize(s)?))
59+
.collect()
60+
}
61+
62+
/// Broadcasts a transaction to the network.
63+
fn transaction_broadcast(&self, tx: &Transaction) -> Result<Txid, Error> {
64+
let buffer: Vec<u8> = serialize(tx);
65+
self.transaction_broadcast_raw(&buffer)
66+
}
67+
68+
/// Execute a queue of calls stored in a [`Batch`](../batch/struct.Batch.html) struct. Returns
69+
/// `Ok()` **only if** all of the calls are successful. The order of the JSON `Value`s returned
70+
/// reflects the order in which the calls were made on the `Batch` struct.
71+
fn batch_call(&self, batch: Batch) -> Result<Vec<serde_json::Value>, Error>;
72+
73+
/// Subscribes to notifications for new block headers, by sending a `blockchain.headers.subscribe` call and
74+
/// returns the current tip as raw bytes instead of deserializing them.
75+
fn block_headers_subscribe_raw(&self) -> Result<RawHeaderNotification, Error>;
76+
77+
/// Tries to pop one queued notification for a new block header that we might have received.
78+
/// Returns a the header in raw bytes if a notification is found in the queue, None otherwise.
79+
fn block_headers_pop_raw(&self) -> Result<Option<RawHeaderNotification>, Error>;
80+
81+
/// Gets the raw bytes of block header for height `height`.
82+
fn block_header_raw(&self, height: usize) -> Result<Vec<u8>, Error>;
83+
84+
/// Tries to fetch `count` block headers starting from `start_height`.
85+
fn block_headers(&self, start_height: usize, count: usize) -> Result<GetHeadersRes, Error>;
86+
87+
/// Estimates the fee required in **Satoshis per kilobyte** to confirm a transaction in `number` blocks.
88+
fn estimate_fee(&self, number: usize) -> Result<f64, Error>;
89+
90+
/// Returns the minimum accepted fee by the server's node in **Bitcoin, not Satoshi**.
91+
fn relay_fee(&self) -> Result<f64, Error>;
92+
93+
/// Subscribes to notifications for activity on a specific *scriptPubKey*.
94+
///
95+
/// Returns a [`ScriptStatus`](../types/type.ScriptStatus.html) when successful that represents
96+
/// the current status for the requested script.
97+
///
98+
/// Returns [`Error::AlreadySubscribed`](../types/enum.Error.html#variant.AlreadySubscribed) if
99+
/// already subscribed to the script.
100+
fn script_subscribe(&self, script: &Script) -> Result<Option<ScriptStatus>, Error>;
101+
102+
/// Subscribes to notifications for activity on a specific *scriptPubKey*.
103+
///
104+
/// Returns a `bool` with the server response when successful.
105+
///
106+
/// Returns [`Error::NotSubscribed`](../types/enum.Error.html#variant.NotSubscribed) if
107+
/// not subscribed to the script.
108+
fn script_unsubscribe(&self, script: &Script) -> Result<bool, Error>;
109+
110+
/// Tries to pop one queued notification for a the requested script. Returns `None` if there are no items in the queue.
111+
fn script_pop(&self, script: &Script) -> Result<Option<ScriptStatus>, Error>;
112+
113+
/// Returns the balance for a *scriptPubKey*.
114+
fn script_get_balance(&self, script: &Script) -> Result<GetBalanceRes, Error>;
115+
116+
/// Batch version of [`script_get_balance`](#method.script_get_balance).
117+
///
118+
/// Takes a list of scripts and returns a list of balance responses.
119+
fn batch_script_get_balance<'s, I>(&self, scripts: I) -> Result<Vec<GetBalanceRes>, Error>
120+
where
121+
I: IntoIterator<Item = &'s Script>;
122+
123+
/// Returns the history for a *scriptPubKey*
124+
fn script_get_history(&self, script: &Script) -> Result<Vec<GetHistoryRes>, Error>;
125+
126+
/// Batch version of [`script_get_history`](#method.script_get_history).
127+
///
128+
/// Takes a list of scripts and returns a list of history responses.
129+
fn batch_script_get_history<'s, I>(&self, scripts: I) -> Result<Vec<Vec<GetHistoryRes>>, Error>
130+
where
131+
I: IntoIterator<Item = &'s Script>;
132+
133+
/// Returns the list of unspent outputs for a *scriptPubKey*
134+
fn script_list_unspent(&self, script: &Script) -> Result<Vec<ListUnspentRes>, Error>;
135+
136+
/// Batch version of [`script_list_unspent`](#method.script_list_unspent).
137+
///
138+
/// Takes a list of scripts and returns a list of a list of utxos.
139+
fn batch_script_list_unspent<'s, I>(
140+
&self,
141+
scripts: I,
142+
) -> Result<Vec<Vec<ListUnspentRes>>, Error>
143+
where
144+
I: IntoIterator<Item = &'s Script>;
145+
146+
/// Gets the raw bytes of a transaction with `txid`. Returns an error if not found.
147+
fn transaction_get_raw(&self, txid: &Txid) -> Result<Vec<u8>, Error>;
148+
149+
/// Batch version of [`transaction_get_raw`](#method.transaction_get_raw).
150+
///
151+
/// Takes a list of `txids` and returns a list of transactions raw bytes.
152+
fn batch_transaction_get_raw<'t, I>(&self, txids: I) -> Result<Vec<Vec<u8>>, Error>
153+
where
154+
I: IntoIterator<Item = &'t Txid>;
155+
156+
/// Batch version of [`block_header_raw`](#method.block_header_raw).
157+
///
158+
/// Takes a list of `heights` of blocks and returns a list of block header raw bytes.
159+
fn batch_block_header_raw<'s, I>(&self, heights: I) -> Result<Vec<Vec<u8>>, Error>
160+
where
161+
I: IntoIterator<Item = u32>;
162+
163+
/// Batch version of [`estimate_fee`](#method.estimate_fee).
164+
///
165+
/// Takes a list of `numbers` of blocks and returns a list of fee required in
166+
/// **Satoshis per kilobyte** to confirm a transaction in the given number of blocks.
167+
fn batch_estimate_fee<'s, I>(&self, numbers: I) -> Result<Vec<f64>, Error>
168+
where
169+
I: IntoIterator<Item = usize>;
170+
171+
/// Broadcasts the raw bytes of a transaction to the network.
172+
fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error>;
173+
174+
/// Returns the merkle path for the transaction `txid` confirmed in the block at `height`.
175+
fn transaction_get_merkle(&self, txid: &Txid, height: usize) -> Result<GetMerkleRes, Error>;
176+
177+
/// Returns the capabilities of the server.
178+
fn server_features(&self) -> Result<ServerFeaturesRes, Error>;
179+
180+
/// Pings the server. This method can also be used as a "dummy" call to trigger the processing
181+
/// of incoming block header or script notifications.
182+
fn ping(&self) -> Result<(), Error>;
183+
184+
#[cfg(feature = "debug-calls")]
185+
/// Returns the number of network calls made since the creation of the client.
186+
fn calls_made(&self) -> usize;
187+
}

0 commit comments

Comments
 (0)