mirror of
https://github.com/romanz/electrs.git
synced 2024-11-19 01:43:29 +01:00
WiP
This commit is contained in:
parent
2657db6a21
commit
4ba7e0092d
@ -9,6 +9,7 @@ arrayref = "0.3.4"
|
||||
bincode = "1.0.0"
|
||||
bitcoin = "0.12"
|
||||
crossbeam = "0.3.2"
|
||||
error-chain = "0.11"
|
||||
itertools = "0.7.8"
|
||||
log = "0.4"
|
||||
pbr = "1.0.0"
|
||||
|
@ -7,7 +7,7 @@ extern crate zmq;
|
||||
|
||||
use argparse::{ArgumentParser, StoreFalse};
|
||||
use std::fs::OpenOptions;
|
||||
use indexrs::{daemon, index, store, waiter};
|
||||
use indexrs::{daemon, index, rpc, store, waiter};
|
||||
|
||||
fn setup_logging() {
|
||||
use simplelog::*;
|
||||
@ -68,6 +68,7 @@ fn run_server(config: Config) {
|
||||
{
|
||||
crossbeam::scope(|scope| {
|
||||
scope.spawn(|| handle_queries(&store, &daemon));
|
||||
scope.spawn(|| rpc::serve());
|
||||
if config.enable_indexing {
|
||||
loop {
|
||||
if store.read_header(&waiter.wait()).is_none() {
|
||||
|
@ -1,3 +1,5 @@
|
||||
#![recursion_limit = "1024"]
|
||||
|
||||
extern crate bincode;
|
||||
extern crate bitcoin;
|
||||
extern crate crypto;
|
||||
@ -12,12 +14,17 @@ extern crate zmq;
|
||||
#[macro_use]
|
||||
extern crate arrayref;
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
#[macro_use]
|
||||
extern crate serde_json;
|
||||
|
||||
pub mod daemon;
|
||||
pub mod index;
|
||||
pub mod rpc;
|
||||
pub mod store;
|
||||
pub mod waiter;
|
||||
|
||||
|
131
src/rpc.rs
Normal file
131
src/rpc.rs
Normal file
@ -0,0 +1,131 @@
|
||||
use serde_json::{from_str, Number, Value};
|
||||
|
||||
use std::net::{SocketAddr, TcpListener, TcpStream};
|
||||
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
|
||||
error_chain!{}
|
||||
|
||||
fn blockchain_headers_subscribe() -> Result<Value> {
|
||||
Ok(json!({}))
|
||||
}
|
||||
|
||||
fn server_version() -> Result<Value> {
|
||||
Ok(json!(["LES 0.1.0", "1.2"]))
|
||||
}
|
||||
|
||||
fn server_banner() -> Result<Value> {
|
||||
Ok(json!("Welcome to Local Electrum Server!\n"))
|
||||
}
|
||||
|
||||
fn server_donation_address() -> Result<Value> {
|
||||
Ok(json!("No, thanks :)\n"))
|
||||
}
|
||||
|
||||
fn server_peers_subscribe() -> Result<Value> {
|
||||
Ok(json!([]))
|
||||
}
|
||||
|
||||
fn mempool_get_fee_histogram() -> Result<Value> {
|
||||
Ok(json!([])) // TODO: consult with actual mempool
|
||||
}
|
||||
|
||||
fn blockchain_estimatefee(_params: &[&str]) -> Result<Value> {
|
||||
Ok(json!(1e-5)) // TODO: consult with actual mempool
|
||||
}
|
||||
|
||||
fn blockchain_scripthash_subscribe(_params: &[&str]) -> Result<Value> {
|
||||
Ok(json!("HEX_STATUS"))
|
||||
}
|
||||
|
||||
fn blockchain_scripthash_get_history(_params: &[&str]) -> Result<Value> {
|
||||
Ok(json!([])) // TODO: list of {tx_hash: "ABC", height: 123}
|
||||
}
|
||||
|
||||
fn blockchain_transaction_get(_params: &[&str]) -> Result<Value> {
|
||||
Ok(json!("HEX_TX")) // TODO: list of {tx_hash: "ABC", height: 123}
|
||||
}
|
||||
|
||||
fn blockchain_transaction_get_merkle(_params: &[&str]) -> Result<Value> {
|
||||
Ok(json!({"block_height": 123, "merkle": ["A", "B", "C"], "pos": 45}))
|
||||
}
|
||||
|
||||
fn handle_command(method: &str, params_values: &[Value], id: &Number) -> Result<Value> {
|
||||
let mut params = Vec::<&str>::new();
|
||||
for value in params_values {
|
||||
if let Some(s) = value.as_str() {
|
||||
params.push(s);
|
||||
} else {
|
||||
bail!("invalid param: {:?}", value);
|
||||
}
|
||||
}
|
||||
let result = match method {
|
||||
"blockchain.headers.subscribe" => blockchain_headers_subscribe(),
|
||||
"server.version" => server_version(),
|
||||
"server.banner" => server_banner(),
|
||||
"server.donation_address" => server_donation_address(),
|
||||
"server.peers.subscribe" => server_peers_subscribe(),
|
||||
"mempool.get_fee_histogram" => mempool_get_fee_histogram(),
|
||||
"blockchain.estimatefee" => blockchain_estimatefee(¶ms),
|
||||
"blockchain.scripthash.subscribe" => blockchain_scripthash_subscribe(¶ms),
|
||||
"blockchain.scripthash.get_history" => blockchain_scripthash_get_history(¶ms),
|
||||
"blockchain.transaction.get" => blockchain_transaction_get(¶ms),
|
||||
"blockchain.transaction.get_merkle" => blockchain_transaction_get_merkle(¶ms),
|
||||
&_ => bail!("unknown method {} {:?}", method, params),
|
||||
}?;
|
||||
let reply = json!({"jsonrpc": "2.0", "id": id, "result": result});
|
||||
Ok(reply)
|
||||
}
|
||||
|
||||
fn handle_client(mut stream: TcpStream, addr: SocketAddr) -> Result<()> {
|
||||
let mut reader = BufReader::new(stream
|
||||
.try_clone()
|
||||
.chain_err(|| "failed to clone TcpStream")?);
|
||||
let mut line = String::new();
|
||||
|
||||
loop {
|
||||
line.clear();
|
||||
reader
|
||||
.read_line(&mut line)
|
||||
.chain_err(|| "failed to read a request")?;
|
||||
if line.is_empty() {
|
||||
break;
|
||||
}
|
||||
let line = line.trim_right();
|
||||
let cmd: Value = from_str(line).chain_err(|| "invalid JSON format")?;
|
||||
|
||||
let reply = match (cmd.get("method"), cmd.get("params"), cmd.get("id")) {
|
||||
(
|
||||
Some(&Value::String(ref method)),
|
||||
Some(&Value::Array(ref params)),
|
||||
Some(&Value::Number(ref id)),
|
||||
) => handle_command(method, params, id)?,
|
||||
_ => bail!("invalid command: {}", cmd),
|
||||
};
|
||||
|
||||
info!("[{}] {} -> {}", addr, cmd, reply);
|
||||
let mut line = reply.to_string();
|
||||
line.push_str("\n");
|
||||
stream
|
||||
.write_all(line.as_bytes())
|
||||
.chain_err(|| "failed to send response")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn serve() {
|
||||
let listener = TcpListener::bind("127.0.0.1:50001").unwrap();
|
||||
loop {
|
||||
let (stream, addr) = listener.accept().unwrap();
|
||||
info!("[{}] connected peer", addr);
|
||||
match handle_client(stream, addr) {
|
||||
Ok(()) => info!("[{}] disconnected peer", addr),
|
||||
Err(ref e) => {
|
||||
error!("[{}] {}", addr, e);
|
||||
for e in e.iter().skip(1) {
|
||||
error!("caused by: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
tools/client.py
Normal file
47
tools/client.py
Normal file
@ -0,0 +1,47 @@
|
||||
import hashlib
|
||||
import sys
|
||||
|
||||
from logbook import Logger, StreamHandler
|
||||
|
||||
from pycoin.coins.bitcoin.networks import BitcoinMainnet
|
||||
import pycoin.ui.key_from_text
|
||||
import pycoin.key
|
||||
|
||||
import zmq
|
||||
|
||||
script_for_address = BitcoinMainnet.ui.script_for_address
|
||||
|
||||
log = Logger(__name__)
|
||||
|
||||
|
||||
def main():
|
||||
c = zmq.Context()
|
||||
s = c.socket(zmq.REQ)
|
||||
s.connect('ipc:///tmp/indexrs.rpc')
|
||||
|
||||
xpub, = sys.argv[1:]
|
||||
total = 0
|
||||
k = pycoin.ui.key_from_text.key_from_text(xpub)
|
||||
for change in (0, 1):
|
||||
empty = 0
|
||||
for n in range(100):
|
||||
address = k.subkey(change).subkey(n).address()
|
||||
script = script_for_address(address)
|
||||
script_hash = hashlib.sha256(script).digest()
|
||||
s.send(script_hash)
|
||||
res = s.recv()
|
||||
b = float(res)
|
||||
total += b
|
||||
if b:
|
||||
log.info('{}/{} => {} has {:11.8f} BTC',
|
||||
change, n, address, b)
|
||||
empty = 0
|
||||
else:
|
||||
empty += 1
|
||||
if empty >= 10:
|
||||
break
|
||||
log.info('total balance: {} BTC', total)
|
||||
|
||||
if __name__ == '__main__':
|
||||
with StreamHandler(sys.stderr, level='INFO').applicationbound():
|
||||
main()
|
Loading…
Reference in New Issue
Block a user