Test against mainnet servers

This commit is contained in:
Alekos Filini 2020-07-15 11:33:59 +02:00
parent f37bcd59e0
commit db4554f9e2
No known key found for this signature in database
GPG Key ID: 5E8AFC3034FDFA4F
35 changed files with 83 additions and 272 deletions

View File

@ -2,6 +2,9 @@ language: rust
rust:
- stable
# - 1.31.0 TODO: support the first 2018-edition toolchain
env:
- TEST_ELECTRUM_SERVER=electrum.blockstream.info:50001
- TEST_ELECTRUM_SERVER=bitcoin.aranguren.org:50001
before_script:
- rustup component add rustfmt
# Run tests and check a few combinations of features

View File

@ -9,9 +9,6 @@ documentation = "https://docs.rs/electrum-client/"
description = "Bitcoin Electrum client library. Supports plaintext, TLS and Onion servers."
keywords = ["bitcoin", "electrum"]
readme = "README.md"
exclude = [
"test_data/*",
]
# loosely based on https://github.com/evgeniy-scherbina/rust-electrumx-client

View File

@ -1,39 +1,9 @@
extern crate electrum_client;
extern crate env_logger;
use std::sync::Arc;
use std::thread;
use electrum_client::Client;
fn main() {
env_logger::init();
let client = Arc::new(Client::new("electrum.blockstream.info:50001").unwrap());
let mut handles = Vec::new();
/*let _client = Arc::clone(&client);
let handle = thread::spawn(move || {
_client.reader_thread().unwrap();
println!("reader thread exited");
});
handles.push(handle);*/
thread::sleep(std::time::Duration::from_secs(1));
for _ in 0..4 {
let client = Arc::clone(&client);
let handle = thread::spawn(move || {
let res = client.batch_estimate_fee(vec![1, 3, 6, 12]);
println!("{:?}", res);
});
handles.push(handle);
}
for h in handles {
h.join().unwrap();
}
let client = Client::new("kirsche.emzy.de:50001").unwrap();
let res = client.server_features();
println!("{:#?}", res);
}

View File

@ -3,7 +3,7 @@ extern crate electrum_client;
use electrum_client::Client;
fn main() {
let mut client = Client::new_ssl("electrum2.hodlister.co:50002", true).unwrap();
let client = Client::new_ssl("electrum2.hodlister.co:50002", true).unwrap();
let res = client.server_features();
println!("{:#?}", res);
}

View File

@ -6,12 +6,12 @@ fn main() {
// NOTE: This assumes Tor is running localy, with an unauthenticated Socks5 listening at
// localhost:9050
let mut client = Client::new_proxy("ozahtqwp25chjdjd.onion:50001", "127.0.0.1:9050").unwrap();
let client = Client::new_proxy("ozahtqwp25chjdjd.onion:50001", "127.0.0.1:9050").unwrap();
let res = client.server_features();
println!("{:#?}", res);
// works both with onion v2/v3 (if your Tor supports them)
let mut client = Client::new_proxy(
let client = Client::new_proxy(
"v7gtzf7nua6hdmb2wtqaqioqmesdb4xrlly4zwr7bvayxv2bpg665pqd.onion:50001",
"127.0.0.1:9050",
)

View File

@ -2,11 +2,11 @@
//!
//! This module contains definitions of all the complex data structures that are returned by calls
use core::sync::atomic::{AtomicUsize, Ordering};
use std::collections::{HashMap, HashSet, VecDeque};
use std::io::{BufRead, BufReader, Read, Write};
use std::mem::drop;
use std::net::{TcpStream, ToSocketAddrs};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{channel, Receiver, Sender};
use std::sync::{Mutex, TryLockError};
@ -102,7 +102,7 @@ where
script_notifications: Mutex<HashMap<ScriptHash, VecDeque<ScriptStatus>>>,
#[cfg(feature = "debug-calls")]
calls: usize,
calls: AtomicUsize,
}
impl<S> From<S> for Client<S>
@ -123,7 +123,7 @@ where
script_notifications: Mutex::new(HashMap::new()),
#[cfg(feature = "debug-calls")]
calls: 0,
calls: AtomicUsize::new(0),
}
}
}
@ -723,8 +723,14 @@ impl<S: Read + Write> Client<S> {
params,
);
let result = self.call(req)?;
let mut result: Vec<ListUnspentRes> = serde_json::from_value(result)?;
Ok(serde_json::from_value(result)?)
// This should not be necessary, since the protocol documentation says that the txs should
// be "in blockchain order" (https://electrumx.readthedocs.io/en/latest/protocol-methods.html#blockchain-scripthash-listunspent).
// However, elects seems to be ignoring this at the moment, so we'll sort again here just
// to make sure the result is consistent.
result.sort_unstable_by_key(|k| (k.height, k.tx_pos));
Ok(result)
}
/// Batch version of [`script_list_unspent`](#method.script_list_unspent).
@ -879,13 +885,13 @@ impl<S: Read + Write> Client<S> {
#[cfg(feature = "debug-calls")]
/// Returns the number of network calls made since the creation of the client.
pub fn calls_made(&self) -> usize {
self.calls
self.calls.load(Ordering::SeqCst)
}
#[inline]
#[cfg(feature = "debug-calls")]
fn increment_calls(&mut self) {
self.calls += 1;
fn increment_calls(&self) {
self.calls.fetch_add(1, Ordering::SeqCst);
}
#[inline]
@ -895,127 +901,76 @@ impl<S: Read + Write> Client<S> {
#[cfg(test)]
mod test {
use std::fs::File;
use std::io::Read;
use test_stream::TestStream;
use client::Client;
impl Client<TestStream> {
pub fn new_test(file: File) -> Self {
TestStream::new(file).into()
}
}
macro_rules! impl_test_prelude {
( $testcase:expr ) => {{
let data_in = File::open(format!("./test_data/{}.in", $testcase)).unwrap();
Client::new_test(data_in)
}};
}
macro_rules! impl_test_conclusion {
( $testcase:expr, $stream:expr ) => {
let mut data_out = File::open(format!("./test_data/{}.out", $testcase)).unwrap();
let mut buffer = Vec::new();
data_out.read_to_end(&mut buffer).unwrap();
let stream_buffer = $stream.stream().lock().unwrap().buffer.clone();
assert_eq!(
stream_buffer,
buffer,
"Expecting `{}`, got `{}`",
String::from_utf8_lossy(&buffer.to_vec()),
String::from_utf8_lossy(&stream_buffer)
);
};
fn get_test_server() -> String {
std::env::var("TEST_ELECTRUM_SERVER").unwrap_or("electrum.blockstream.info:50001".into())
}
#[test]
fn test_server_features_simple() {
let test_case = "server_features_simple";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let resp = client.server_features().unwrap();
assert_eq!(resp.server_version, "ElectrumX 1.0.17");
assert_eq!(
resp.genesis_hash,
[
0x00, 0x00, 0x00, 0x00, 0x09, 0x33, 0xEA, 0x01, 0xAD, 0x0E, 0xE9, 0x84, 0x20, 0x97,
0x79, 0xBA, 0xAE, 0xC3, 0xCE, 0xD9, 0x0F, 0xA3, 0xF4, 0x08, 0x71, 0x95, 0x26, 0xF8,
0xD7, 0x7F, 0x49, 0x43
]
0, 0, 0, 0, 0, 25, 214, 104, 156, 8, 90, 225, 101, 131, 30, 147, 79, 247, 99, 174,
70, 162, 166, 193, 114, 179, 241, 182, 10, 140, 226, 111
],
);
assert_eq!(resp.protocol_min, "1.0");
assert_eq!(resp.protocol_max, "1.0");
assert_eq!(resp.hash_function, Some("sha256".into()));
assert_eq!(resp.pruning, None);
impl_test_conclusion!(test_case, client.stream);
}
#[test]
fn test_relay_fee() {
let test_case = "relay_fee";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let resp = client.relay_fee().unwrap();
assert_eq!(resp, 123.4);
impl_test_conclusion!(test_case, client.stream);
assert_eq!(resp, 0.00001);
}
#[test]
fn test_estimate_fee() {
let test_case = "estimate_fee";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let resp = client.estimate_fee(10).unwrap();
assert_eq!(resp, 10.0);
impl_test_conclusion!(test_case, client.stream);
assert!(resp > 0.0);
}
#[test]
fn test_block_header() {
let test_case = "block_header";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let resp = client.block_header(500).unwrap();
assert_eq!(resp.version, 536870912);
assert_eq!(resp.time, 1578166214);
assert_eq!(resp.nonce, 0);
impl_test_conclusion!(test_case, client.stream);
let resp = client.block_header(0).unwrap();
assert_eq!(resp.version, 0x01);
assert_eq!(resp.time, 1231006505);
assert_eq!(resp.nonce, 0x7c2bac1d);
}
#[test]
fn test_block_headers() {
let test_case = "block_headers";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let resp = client.block_headers(100, 4).unwrap();
let resp = client.block_headers(0, 4).unwrap();
assert_eq!(resp.count, 4);
assert_eq!(resp.max, 2016);
assert_eq!(resp.headers.len(), 4);
assert_eq!(resp.headers[0].time, 1563694949);
impl_test_conclusion!(test_case, client.stream);
assert_eq!(resp.headers[0].time, 1231006505);
}
#[test]
fn test_script_get_balance() {
use std::str::FromStr;
let test_case = "script_get_balance";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let addr = bitcoin::Address::from_str("2N1xJCxBUXTDs6y8Sydz3axhAiXrrQwcosi").unwrap();
// Realistically nobody will ever spend from this address, so we can expect the balance to
// increase over time
let addr = bitcoin::Address::from_str("1CounterpartyXXXXXXXXXXXXXXXUWLpVr").unwrap();
let resp = client.script_get_balance(&addr.script_pubkey()).unwrap();
assert_eq!(resp.confirmed, 0);
assert_eq!(resp.unconfirmed, 130000000);
impl_test_conclusion!(test_case, client.stream);
assert!(resp.confirmed >= 213091301265);
}
#[test]
@ -1025,80 +980,67 @@ mod test {
use bitcoin::hashes::hex::FromHex;
use bitcoin::Txid;
let test_case = "script_get_history";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let addr = bitcoin::Address::from_str("2N1xJCxBUXTDs6y8Sydz3axhAiXrrQwcosi").unwrap();
// Mt.Gox hack address
let addr = bitcoin::Address::from_str("1FeexV6bAHb8ybZjqQMjJrcCrHGW9sb6uF").unwrap();
let resp = client.script_get_history(&addr.script_pubkey()).unwrap();
assert_eq!(resp.len(), 2);
assert!(resp.len() >= 328);
assert_eq!(
resp[0].tx_hash,
Txid::from_hex("a1aa2b52fb79641f918d44a27f51781c3c0c49f7ee0e4b14dbb37c722853f046")
Txid::from_hex("e67a0550848b7932d7796aeea16ab0e48a5cfe81c4e8cca2c5b03e0416850114")
.unwrap()
);
impl_test_conclusion!(test_case, client.stream);
}
#[test]
fn test_script_list_unspent() {
use std::str::FromStr;
use bitcoin::hashes::hex::FromHex;
use bitcoin::Txid;
use std::str::FromStr;
let test_case = "script_list_unspent";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let addr = bitcoin::Address::from_str("2N1xJCxBUXTDs6y8Sydz3axhAiXrrQwcosi").unwrap();
// Mt.Gox hack address
let addr = bitcoin::Address::from_str("1FeexV6bAHb8ybZjqQMjJrcCrHGW9sb6uF").unwrap();
let resp = client.script_list_unspent(&addr.script_pubkey()).unwrap();
assert_eq!(resp.len(), 2);
assert_eq!(resp[0].value, 30000000);
assert_eq!(resp[0].height, 0);
assert_eq!(resp[0].tx_pos, 1);
assert!(resp.len() >= 329);
assert_eq!(resp[0].value, 7995600000000);
assert_eq!(resp[0].height, 111194);
assert_eq!(resp[0].tx_pos, 0);
assert_eq!(
resp[0].tx_hash,
Txid::from_hex("a1aa2b52fb79641f918d44a27f51781c3c0c49f7ee0e4b14dbb37c722853f046")
Txid::from_hex("e67a0550848b7932d7796aeea16ab0e48a5cfe81c4e8cca2c5b03e0416850114")
.unwrap()
);
impl_test_conclusion!(test_case, client.stream);
}
#[test]
fn test_batch_script_list_unspent() {
use std::str::FromStr;
let test_case = "batch_script_list_unspent";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let script_1 = bitcoin::Address::from_str("2N1xJCxBUXTDs6y8Sydz3axhAiXrrQwcosi")
.unwrap()
.script_pubkey();
let script_2 = bitcoin::Address::from_str("2MyEi7dbTfQxo1M4hJaAzA2tgEJFQhYv5Au")
// Mt.Gox hack address
let script_1 = bitcoin::Address::from_str("1FeexV6bAHb8ybZjqQMjJrcCrHGW9sb6uF")
.unwrap()
.script_pubkey();
let resp = client
.batch_script_list_unspent(vec![&script_1, &script_2])
.unwrap();
assert_eq!(resp.len(), 2);
assert_eq!(resp[0].len(), 2);
assert_eq!(resp[1].len(), 1);
impl_test_conclusion!(test_case, client.stream);
let resp = client.batch_script_list_unspent(vec![&script_1]).unwrap();
assert_eq!(resp.len(), 1);
assert!(resp[0].len() >= 329);
}
#[test]
fn test_batch_estimate_fee() {
let test_case = "batch_estimate_fee";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let resp = client.batch_estimate_fee(vec![10, 20]).unwrap();
assert_eq!(resp[0], 10.0);
assert_eq!(resp[1], 20.0);
impl_test_conclusion!(test_case, client.stream);
assert_eq!(resp.len(), 2);
assert!(resp[0] > 0.0);
assert!(resp[1] > 0.0);
}
#[test]
@ -1106,41 +1048,16 @@ mod test {
use bitcoin::hashes::hex::FromHex;
use bitcoin::Txid;
let test_case = "transaction_get";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let resp = client
.transaction_get(
&Txid::from_hex("a1aa2b52fb79641f918d44a27f51781c3c0c49f7ee0e4b14dbb37c722853f046")
&Txid::from_hex("cc2ca076fd04c2aeed6d02151c447ced3d09be6fb4d4ef36cb5ed4e7a3260566")
.unwrap(),
)
.unwrap();
assert_eq!(resp.version, 2);
assert_eq!(resp.lock_time, 1376);
impl_test_conclusion!(test_case, client.stream);
}
#[test]
fn test_transaction_broadcast() {
use bitcoin::consensus::deserialize;
use bitcoin::hashes::hex::FromHex;
use bitcoin::Txid;
let test_case = "transaction_broadcast";
let mut client = impl_test_prelude!(test_case);
let buf = Vec::<u8>::from_hex("02000000000101f6cd5873d669cc2de550453623d9d10ed5b5ba906d81160ee3ab853ebcfffa0c0100000000feffffff02e22f82000000000017a914e229870f3af1b1a3aefc3452a4d2939b443e6eba8780c3c9010000000017a9145f859501ff79211aeb972633b782743dd3b31dab8702473044022046ff3b0618107e08bd25fb753e31542b8c23575d7e9faf43dd17f59727cfb9c902200a4f3837105808d810de01fcd63fb18e66a69026090dc72b66840d41e55c6bf3012103e531113bbca998f8d164235e3395db336d3ba03552d1bfaa83fd7cffe6e5c6c960050000").unwrap();
let tx: bitcoin::Transaction = deserialize(&buf).unwrap();
let resp = client.transaction_broadcast(&tx).unwrap();
assert_eq!(
resp,
Txid::from_hex("a1aa2b52fb79641f918d44a27f51781c3c0c49f7ee0e4b14dbb37c722853f046")
.unwrap()
);
impl_test_conclusion!(test_case, client.stream);
assert_eq!(resp.version, 1);
assert_eq!(resp.lock_time, 0);
}
#[test]
@ -1148,28 +1065,24 @@ mod test {
use bitcoin::hashes::hex::FromHex;
use bitcoin::Txid;
let test_case = "transaction_get_merkle";
let mut client = impl_test_prelude!(test_case);
let client = Client::new(get_test_server()).unwrap();
let resp = client
.transaction_get_merkle(
&Txid::from_hex("2d64851151550e8c4d337f335ee28874401d55b358a66f1bafab2c3e9f48773d")
&Txid::from_hex("cc2ca076fd04c2aeed6d02151c447ced3d09be6fb4d4ef36cb5ed4e7a3260566")
.unwrap(),
1234,
630000,
)
.unwrap();
assert_eq!(resp.block_height, 450538);
assert_eq!(resp.pos, 710);
assert_eq!(resp.merkle.len(), 11);
assert_eq!(resp.block_height, 630000);
assert_eq!(resp.pos, 0);
assert_eq!(resp.merkle.len(), 12);
assert_eq!(
resp.merkle[0],
[
0x71, 0x3D, 0x6C, 0x7E, 0x6C, 0xE7, 0xBB, 0xEA, 0x70, 0x8D, 0x61, 0x16, 0x22, 0x31,
0xEA, 0xA8, 0xEC, 0xB3, 0x1C, 0x4C, 0x5D, 0xD8, 0x4F, 0x81, 0xC2, 0x04, 0x09, 0xA9,
0x00, 0x69, 0xCB, 0x24
30, 10, 161, 245, 132, 125, 136, 198, 186, 138, 107, 216, 92, 22, 145, 81, 130,
126, 200, 65, 121, 158, 105, 111, 38, 151, 38, 147, 144, 224, 5, 218
]
);
impl_test_conclusion!(test_case, client.stream);
}
}

View File

@ -41,8 +41,6 @@ extern crate webpki_roots;
pub mod batch;
pub mod client;
mod stream;
#[cfg(test)]
mod test_stream;
pub mod types;
pub use batch::Batch;

View File

@ -31,10 +31,3 @@ impl<T: Read + Write> Clone for ClonableStream<T> {
ClonableStream(Arc::clone(&self.0))
}
}
#[cfg(test)]
impl<T: Read + Write> ClonableStream<T> {
pub fn stream(&self) -> Arc<Mutex<T>> {
Arc::clone(&self.0)
}
}

View File

@ -1,33 +0,0 @@
use std::io::{Read, Result, Write};
use std::fs::File;
pub struct TestStream {
pub file: File,
pub buffer: Vec<u8>,
}
impl TestStream {
pub fn new(file: File) -> Self {
TestStream {
file,
buffer: Vec::new(),
}
}
}
impl Read for TestStream {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
self.file.read(buf)
}
}
impl Write for TestStream {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
self.buffer.write(buf)
}
fn flush(&mut self) -> Result<()> {
self.buffer.flush()
}
}

View File

@ -1,2 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":10.0}
{"id":0,"jsonrpc":"2.0","result":20.0}

View File

@ -1,2 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.estimatefee","params":[10]}
{"jsonrpc":"2.0","id":1,"method":"blockchain.estimatefee","params":[20]}

View File

@ -1,2 +0,0 @@
{"id":1,"jsonrpc":"2.0","result":[{"height":0,"tx_hash":"83f5de2e6d7dfd5b582a5b2a3de4a5adb32c9cdca91473cf1fbcba76d56e4486","tx_pos":1,"value":100000000}]}
{"id":0,"jsonrpc":"2.0","result":[{"height":0,"tx_hash":"eb07e5d67565bad5231fd5aeeb16d0c2c53371265690642b943aa24c83ecae1d","tx_pos":0,"value":300000000},{"height":0,"tx_hash":"824f9a426d4b6a9b23c52901754a01017f3113ffdf3ed20c02747db85b161a40","tx_pos":0,"value":100000000}]}

View File

@ -1,2 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.scripthash.listunspent","params":["c60b02f19c2053efedddb804024edd3f05f181ac2f828384dff40d072d25d962"]}
{"jsonrpc":"2.0","id":1,"method":"blockchain.scripthash.listunspent","params":["97897cdd5b98fab0b99aa5f861cee45c597a1ab2fe90ea1a7cf234b029eb5883"]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":"000000207a8eb5cf562c0b013f03bf4be90318770510bcc57b918491b07f29f15a6433416fe34a556424483dad983f24f906a77638b4583688a0308c75d5bb9f31561e20c6e7105effff7f2000000000"}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.block.header","params":[500]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":{"count":4,"hex":"00000020a6b63c802e0bdeccfd6f4e132dfbad5822c563ef705b57267b1c05c07fb4bb066a95320ef101fba9911c3f4870cc8c3f8900cfa57384379635cba0466fb42bf36517345dffff7f200000000000000020cfa3201d443e007ec5edebbb2600c11ba04f07bd88056ad1ac402573ffe63473937fa56356c956cc4320cd8d98a3db17b845cffaf07158b5abcc7f914c85dcc66517345dffff7f200100000000000020a20ed7c06c55db6ec785d5578c32fb57c3db0bf1d3ef6c90a7af647d88add90df34090f37280af8b2e31f7857350947b1698a1a1742117eb1eff7d87c7fa9b986517345dffff7f2001000000000000207d475add1706bb3fceb22a45a9816ce156a8292a515bf4eeecf60e5aa9dc3007edf508bf9eb08dfa3d73d758e05e9f6730552277c5a249e6ba89ad7b50b4c93d6517345dffff7f2000000000","max":2016}}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.block.headers","params":[100,4]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":10.0}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.estimatefee","params":[10]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":123.4}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.relayfee","params":[]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":{"confirmed":0,"unconfirmed":130000000}}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.scripthash.get_balance","params":["c60b02f19c2053efedddb804024edd3f05f181ac2f828384dff40d072d25d962"]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":[{"height":0,"tx_hash":"a1aa2b52fb79641f918d44a27f51781c3c0c49f7ee0e4b14dbb37c722853f046"},{"height":0,"tx_hash":"f9b4649764b9e9b53641d8bad750b1e40329937f79ae192f9e84e4a7978267bc"}]}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.scripthash.get_history","params":["c60b02f19c2053efedddb804024edd3f05f181ac2f828384dff40d072d25d962"]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":[{"height":0,"tx_hash":"a1aa2b52fb79641f918d44a27f51781c3c0c49f7ee0e4b14dbb37c722853f046","tx_pos":1,"value":30000000},{"height":0,"tx_hash":"f9b4649764b9e9b53641d8bad750b1e40329937f79ae192f9e84e4a7978267bc","tx_pos":1,"value":100000000}]}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.scripthash.listunspent","params":["c60b02f19c2053efedddb804024edd3f05f181ac2f828384dff40d072d25d962"]}

View File

@ -1 +0,0 @@
{"id": 0, "method":"server.features", "result": {"genesis_hash": "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943","hosts": {"14.3.140.101": {"tcp_port": 51001, "ssl_port": 51002}},"protocol_max": "1.0","protocol_min": "1.0","pruning": null,"server_version": "ElectrumX 1.0.17","hash_function": "sha256"}}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"server.features","params":[]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":"a1aa2b52fb79641f918d44a27f51781c3c0c49f7ee0e4b14dbb37c722853f046"}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.transaction.broadcast","params":["02000000000101f6cd5873d669cc2de550453623d9d10ed5b5ba906d81160ee3ab853ebcfffa0c0100000000feffffff02e22f82000000000017a914e229870f3af1b1a3aefc3452a4d2939b443e6eba8780c3c9010000000017a9145f859501ff79211aeb972633b782743dd3b31dab8702473044022046ff3b0618107e08bd25fb753e31542b8c23575d7e9faf43dd17f59727cfb9c902200a4f3837105808d810de01fcd63fb18e66a69026090dc72b66840d41e55c6bf3012103e531113bbca998f8d164235e3395db336d3ba03552d1bfaa83fd7cffe6e5c6c960050000"]}

View File

@ -1 +0,0 @@
{"id":0,"jsonrpc":"2.0","result":"02000000000101f6cd5873d669cc2de550453623d9d10ed5b5ba906d81160ee3ab853ebcfffa0c0100000000feffffff02e22f82000000000017a914e229870f3af1b1a3aefc3452a4d2939b443e6eba8780c3c9010000000017a9145f859501ff79211aeb972633b782743dd3b31dab8702473044022046ff3b0618107e08bd25fb753e31542b8c23575d7e9faf43dd17f59727cfb9c902200a4f3837105808d810de01fcd63fb18e66a69026090dc72b66840d41e55c6bf3012103e531113bbca998f8d164235e3395db336d3ba03552d1bfaa83fd7cffe6e5c6c960050000"}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.transaction.get","params":["a1aa2b52fb79641f918d44a27f51781c3c0c49f7ee0e4b14dbb37c722853f046"]}

View File

@ -1 +0,0 @@
{"id": 0, "method": "blockchain.transaction.get_merkle", "result": {"merkle": ["713d6c7e6ce7bbea708d61162231eaa8ecb31c4c5dd84f81c20409a90069cb24", "03dbaec78d4a52fbaf3c7aa5d3fccd9d8654f323940716ddf5ee2e4bda458fde", "e670224b23f156c27993ac3071940c0ff865b812e21e0a162fe7a005d6e57851", "369a1619a67c3108a8850118602e3669455c70cdcdb89248b64cc6325575b885", "4756688678644dcb27d62931f04013254a62aeee5dec139d1aac9f7b1f318112", "7b97e73abc043836fd890555bfce54757d387943a6860e5450525e8e9ab46be5", "61505055e8b639b7c64fd58bce6fc5c2378b92e025a02583303f69930091b1c3", "27a654ff1895385ac14a574a0415d3bbba9ec23a8774f22ec20d53dd0b5386ff", "5312ed87933075e60a9511857d23d460a085f3b6e9e5e565ad2443d223cfccdc", "94f60b14a9f106440a197054936e6fb92abbd69d6059b38fdf79b33fc864fca0", "2d64851151550e8c4d337f335ee28874401d55b358a66f1bafab2c3e9f48773d"], "block_height": 450538, "pos": 710}}

View File

@ -1 +0,0 @@
{"jsonrpc":"2.0","id":0,"method":"blockchain.transaction.get_merkle","params":["2d64851151550e8c4d337f335ee28874401d55b358a66f1bafab2c3e9f48773d",1234]}