Skip to content

Commit f200b7f

Browse files
committed
Implements retry, timeout, socks credential and others fixes
Retry works by checking if an non-protocol error happened during the call, if so an attempt to take a write lock on the client is made and a new client attempted if both operationare succesfull the old_client is substituted with the new one. Timeout is a single parameter for connect,read and write TCP timeouts, special handling is required for the following situation: cannot set a timeout with a proxy and cannot set timeout with multipl SocketAddrs Since configurations parameter grow, a Config struct with a builder has been introduced Some new errors variant has been introduced Errors in reading input in the reader thread now warns other eventual threads with ChannelMessage::Error Add github actions equivalent to travis cause travis is slow
1 parent c1f4e9d commit f200b7f

File tree

11 files changed

+471
-120
lines changed

11 files changed

+471
-120
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
on: [push, pull_request]
2+
3+
name: CI
4+
5+
jobs:
6+
7+
test-fmt:
8+
name: Test
9+
runs-on: ubuntu-20.04
10+
env:
11+
TEST_ELECTRUM_SERVER: electrum.blockstream.info:50001
12+
#TEST_ELECTRUM_SERVER: bitcoin.aranguren.org:50001
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v2
16+
- name: Cache
17+
uses: actions/cache@v2
18+
with:
19+
path: |
20+
~/.cargo/registry
21+
~/.cargo/git
22+
target
23+
key: ${{ runner.os }}-cargo-${{ github.job }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }}
24+
- name: Install rustup
25+
run: curl https://sh.rustup.rs -sSf | sh -s -- -y
26+
- name: Set default toolchain
27+
run: $HOME/.cargo/bin/rustup default stable
28+
- name: Set profile
29+
run: $HOME/.cargo/bin/rustup set profile minimal
30+
- name: Fmt
31+
run: cargo fmt -- --check --verbose
32+
- name: Test
33+
run: cargo test --verbose --all
34+
- run: cargo check --verbose --features=use-openssl
35+
- run: cargo check --verbose --no-default-features --features=proxy
36+
- run: cargo check --verbose --no-default-features --features=minimal
37+
- run: cargo check --verbose --no-default-features --features=minimal,debug-calls
38+
- run: cargo check --verbose --no-default-features --features=proxy,use-openssl
39+
- run: cargo check --verbose --no-default-features --features=proxy,use-rustls

examples/plaintext.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ extern crate electrum_client;
33
use electrum_client::{Client, ElectrumApi};
44

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

examples/ssl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ extern crate electrum_client;
33
use electrum_client::{Client, ElectrumApi};
44

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

examples/tor.rs

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

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

55
fn main() {
66
// NOTE: This assumes Tor is running localy, with an unauthenticated Socks5 listening at
77
// localhost:9050
8+
let proxy = Socks5Config::new("127.0.0.1:9050");
9+
let config = ConfigBuilder::new().socks5(Some(proxy)).unwrap().build();
810

9-
let client = Client::new("tcp://explorernuoc63nb.onion:110", Some("127.0.0.1:9050")).unwrap();
11+
let client = Client::from_config("tcp://explorernuoc63nb.onion:110", config.clone()).unwrap();
1012
let res = client.server_features();
1113
println!("{:#?}", res);
1214

1315
// works both with onion v2/v3 (if your Tor supports them)
14-
let client = Client::new(
16+
let client = Client::from_config(
1517
"tcp://explorerzydxu5ecjrkwceayqybizmpjjznk5izmitf2modhcusuqlid.onion:110",
16-
Some("127.0.0.1:9050"),
18+
config,
1719
)
1820
.unwrap();
1921
let res = client.server_features();

src/api.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub trait ElectrumApi {
3838
/// Takes a list of `txids` and returns a list of transactions.
3939
fn batch_transaction_get<'t, I>(&self, txids: I) -> Result<Vec<Transaction>, Error>
4040
where
41-
I: IntoIterator<Item = &'t Txid>,
41+
I: IntoIterator<Item = &'t Txid> + Clone,
4242
{
4343
self.batch_transaction_get_raw(txids)?
4444
.iter()
@@ -49,9 +49,9 @@ pub trait ElectrumApi {
4949
/// Batch version of [`block_header`](#method.block_header).
5050
///
5151
/// 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>
52+
fn batch_block_header<I>(&self, heights: I) -> Result<Vec<BlockHeader>, Error>
5353
where
54-
I: IntoIterator<Item = u32>,
54+
I: IntoIterator<Item = u32> + Clone,
5555
{
5656
self.batch_block_header_raw(heights)?
5757
.iter()
@@ -68,7 +68,7 @@ pub trait ElectrumApi {
6868
/// Execute a queue of calls stored in a [`Batch`](../batch/struct.Batch.html) struct. Returns
6969
/// `Ok()` **only if** all of the calls are successful. The order of the JSON `Value`s returned
7070
/// 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>;
71+
fn batch_call(&self, batch: &Batch) -> Result<Vec<serde_json::Value>, Error>;
7272

7373
/// Subscribes to notifications for new block headers, by sending a `blockchain.headers.subscribe` call and
7474
/// returns the current tip as raw bytes instead of deserializing them.
@@ -118,7 +118,7 @@ pub trait ElectrumApi {
118118
/// Takes a list of scripts and returns a list of balance responses.
119119
fn batch_script_get_balance<'s, I>(&self, scripts: I) -> Result<Vec<GetBalanceRes>, Error>
120120
where
121-
I: IntoIterator<Item = &'s Script>;
121+
I: IntoIterator<Item = &'s Script> + Clone;
122122

123123
/// Returns the history for a *scriptPubKey*
124124
fn script_get_history(&self, script: &Script) -> Result<Vec<GetHistoryRes>, Error>;
@@ -128,7 +128,7 @@ pub trait ElectrumApi {
128128
/// Takes a list of scripts and returns a list of history responses.
129129
fn batch_script_get_history<'s, I>(&self, scripts: I) -> Result<Vec<Vec<GetHistoryRes>>, Error>
130130
where
131-
I: IntoIterator<Item = &'s Script>;
131+
I: IntoIterator<Item = &'s Script> + Clone;
132132

133133
/// Returns the list of unspent outputs for a *scriptPubKey*
134134
fn script_list_unspent(&self, script: &Script) -> Result<Vec<ListUnspentRes>, Error>;
@@ -141,7 +141,7 @@ pub trait ElectrumApi {
141141
scripts: I,
142142
) -> Result<Vec<Vec<ListUnspentRes>>, Error>
143143
where
144-
I: IntoIterator<Item = &'s Script>;
144+
I: IntoIterator<Item = &'s Script> + Clone;
145145

146146
/// Gets the raw bytes of a transaction with `txid`. Returns an error if not found.
147147
fn transaction_get_raw(&self, txid: &Txid) -> Result<Vec<u8>, Error>;
@@ -151,22 +151,22 @@ pub trait ElectrumApi {
151151
/// Takes a list of `txids` and returns a list of transactions raw bytes.
152152
fn batch_transaction_get_raw<'t, I>(&self, txids: I) -> Result<Vec<Vec<u8>>, Error>
153153
where
154-
I: IntoIterator<Item = &'t Txid>;
154+
I: IntoIterator<Item = &'t Txid> + Clone;
155155

156156
/// Batch version of [`block_header_raw`](#method.block_header_raw).
157157
///
158158
/// 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>
159+
fn batch_block_header_raw<I>(&self, heights: I) -> Result<Vec<Vec<u8>>, Error>
160160
where
161-
I: IntoIterator<Item = u32>;
161+
I: IntoIterator<Item = u32> + Clone;
162162

163163
/// Batch version of [`estimate_fee`](#method.estimate_fee).
164164
///
165165
/// Takes a list of `numbers` of blocks and returns a list of fee required in
166166
/// **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>
167+
fn batch_estimate_fee<I>(&self, numbers: I) -> Result<Vec<f64>, Error>
168168
where
169-
I: IntoIterator<Item = usize>;
169+
I: IntoIterator<Item = usize> + Clone;
170170

171171
/// Broadcasts the raw bytes of a transaction to the network.
172172
fn transaction_broadcast_raw(&self, raw_tx: &[u8]) -> Result<Txid, Error>;

src/batch.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ impl Batch {
6363
self.calls
6464
.push((String::from("blockchain.block.header"), params));
6565
}
66+
67+
/// Returns an iterator on the batch
68+
pub fn iter(&self) -> BatchIter {
69+
BatchIter {
70+
batch: self,
71+
index: 0,
72+
}
73+
}
6674
}
6775

6876
impl std::iter::IntoIterator for Batch {
@@ -74,6 +82,21 @@ impl std::iter::IntoIterator for Batch {
7482
}
7583
}
7684

85+
pub struct BatchIter<'a> {
86+
batch: &'a Batch,
87+
index: usize,
88+
}
89+
90+
impl<'a> std::iter::Iterator for BatchIter<'a> {
91+
type Item = &'a (String, Vec<Param>);
92+
93+
fn next(&mut self) -> Option<Self::Item> {
94+
let val = self.batch.calls.get(self.index);
95+
self.index += 1;
96+
val
97+
}
98+
}
99+
77100
impl std::default::Default for Batch {
78101
fn default() -> Self {
79102
Batch { calls: Vec::new() }

0 commit comments

Comments
 (0)