Compare commits
No commits in common. "3018e64fb731aeb9f3600bc81f8e2c9721ceeacf" and "fe1c4ee2c8d9eb6a6a3e845d7597afd62170c712" have entirely different histories.
3018e64fb7
...
fe1c4ee2c8
1059
Cargo.lock
generated
1059
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,6 @@ edition = "2021"
|
|||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "0.22.1"
|
|
||||||
bs58 = "0.4.0"
|
bs58 = "0.4.0"
|
||||||
bytes = "1.2"
|
bytes = "1.2"
|
||||||
bitcoin = { version = "0.32.5" }
|
bitcoin = { version = "0.32.5" }
|
||||||
@ -21,13 +20,11 @@ hyper = { version = "1.3.1", features = ["http1","server"] }
|
|||||||
hyper-util = { version = "0.1.3", features = ["tokio"] }
|
hyper-util = { version = "0.1.3", features = ["tokio"] }
|
||||||
http-body-util = "0.1"
|
http-body-util = "0.1"
|
||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
openssl = { version = "0.10.74", features = ["vendored"] }
|
|
||||||
sha2 = "0.10.8"
|
sha2 = "0.10.8"
|
||||||
serde = { version = "1.0.152", features = ["derive"] }
|
serde = { version = "1.0.152", features = ["derive"] }
|
||||||
serde_json = "1.0.116"
|
serde_json = "1.0.116"
|
||||||
sqlite = "0.34.0"
|
sqlite = "0.34.0"
|
||||||
regex = "1.10.4"
|
regex = "1.10.4"
|
||||||
reqwest = { version = "0.12.24", features = ["json","socks"] }
|
|
||||||
tokio = { version = "1", features = ["rt", "net","macros","rt-multi-thread"] } # Keep only necessary runtime components
|
tokio = { version = "1", features = ["rt", "net","macros","rt-multi-thread"] } # Keep only necessary runtime components
|
||||||
zmq = "0.10.0"
|
zmq = "0.10.0"
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,6 @@ use bitcoincore_rpc_json::GetBlockchainInfoResult;
|
|||||||
use sqlite::{Value};
|
use sqlite::{Value};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use serde_json::json;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use log::{info,warn,error,trace,debug};
|
use log::{info,warn,error,trace,debug};
|
||||||
use zmq::{Context, Socket};
|
use zmq::{Context, Socket};
|
||||||
@ -20,18 +19,8 @@ use std::collections::HashMap;
|
|||||||
use hex;
|
use hex;
|
||||||
use std::error::Error as StdError;
|
use std::error::Error as StdError;
|
||||||
|
|
||||||
use reqwest::Client as rClient;
|
|
||||||
use openssl::hash::MessageDigest;
|
|
||||||
use openssl::pkey::{PKey};
|
|
||||||
use openssl::sign::Signer;
|
|
||||||
use base64::{engine::general_purpose, Engine as _};
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const LOCKTIME_THRESHOLD:i64 = 5000000;
|
const LOCKTIME_THRESHOLD:i64 = 5000000;
|
||||||
const VERSION:&str = "0.0.1";
|
|
||||||
#[derive(Debug, Clone,Serialize, Deserialize)]
|
#[derive(Debug, Clone,Serialize, Deserialize)]
|
||||||
struct MyConfig {
|
struct MyConfig {
|
||||||
zmq_listener: String,
|
zmq_listener: String,
|
||||||
@ -42,10 +31,8 @@ struct MyConfig {
|
|||||||
testnet: NetworkParams,
|
testnet: NetworkParams,
|
||||||
signet: NetworkParams,
|
signet: NetworkParams,
|
||||||
mainnet: NetworkParams,
|
mainnet: NetworkParams,
|
||||||
send_stats: bool,
|
|
||||||
url: String,
|
|
||||||
secret_code: String,
|
|
||||||
ssl_key_path: String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MyConfig {
|
impl Default for MyConfig {
|
||||||
@ -59,10 +46,6 @@ impl Default for MyConfig {
|
|||||||
testnet: get_network_params_default(Network::Testnet),
|
testnet: get_network_params_default(Network::Testnet),
|
||||||
signet: get_network_params_default(Network::Signet),
|
signet: get_network_params_default(Network::Signet),
|
||||||
mainnet: get_network_params_default(Network::Bitcoin),
|
mainnet: get_network_params_default(Network::Bitcoin),
|
||||||
send_stats: false,
|
|
||||||
url: "http://localhost/".to_string(),
|
|
||||||
secret_code: "xxx".to_string(),
|
|
||||||
ssl_key_path: "privkey.pem".to_string(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,9 +147,7 @@ fn get_client_from_cookie(url: &String,network: &NetworkParams)->Result<(Client,
|
|||||||
match Client::new(&url[..], Auth::CookieFile(cookie.into())) {
|
match Client::new(&url[..], Auth::CookieFile(cookie.into())) {
|
||||||
Ok(client) => {
|
Ok(client) => {
|
||||||
match client.get_blockchain_info(){
|
match client.get_blockchain_info(){
|
||||||
Ok(bcinfo) => {
|
Ok(bcinfo) => Ok((client,bcinfo)),
|
||||||
Ok((client,bcinfo))
|
|
||||||
},
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
Err(err.into())
|
Err(err.into())
|
||||||
}
|
}
|
||||||
@ -193,7 +174,7 @@ fn get_client(network: &NetworkParams) -> Result<(Client,GetBlockchainInfoResult
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async fn main_result(cfg: &MyConfig, network_params: &NetworkParams) -> Result<(), Error> {
|
fn main_result(cfg: &MyConfig, network_params: &NetworkParams) -> Result<(), Error> {
|
||||||
|
|
||||||
|
|
||||||
/*let url = args.next().expect("Usage: <rpc_url> <username> <password>");
|
/*let url = args.next().expect("Usage: <rpc_url> <username> <password>");
|
||||||
@ -220,7 +201,6 @@ async fn main_result(cfg: &MyConfig, network_params: &NetworkParams) -> Result<(
|
|||||||
//}
|
//}
|
||||||
//let average_time = time_sum/11;
|
//let average_time = time_sum/11;
|
||||||
info!("median time: {}",bcinfo.median_time);
|
info!("median time: {}",bcinfo.median_time);
|
||||||
//info!("height time: {}",bcinfo.median_time);
|
|
||||||
info!("blocks: {}",bcinfo.blocks);
|
info!("blocks: {}",bcinfo.blocks);
|
||||||
debug!("best block hash: {}",bcinfo.best_block_hash);
|
debug!("best block hash: {}",bcinfo.best_block_hash);
|
||||||
|
|
||||||
@ -296,60 +276,13 @@ async fn main_result(cfg: &MyConfig, network_params: &NetworkParams) -> Result<(
|
|||||||
let _ = db.execute(&sql);
|
let _ = db.execute(&sql);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let _ = send_stats_report(cfg, bcinfo).await;
|
|
||||||
}
|
}
|
||||||
Err(erx)=>{
|
Err(_)=>{
|
||||||
panic!("impossible to get client {}",erx)
|
panic!("impossible to get client")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn send_stats_report(cfg: &MyConfig, bcinfo: GetBlockchainInfoResult) -> Result<(),reqwest::Error>{
|
|
||||||
if cfg.send_stats {
|
|
||||||
debug!("sending report to welist");
|
|
||||||
let welist_url=env::var("WELIST_SERVER_URL").unwrap_or("https://welist.bitcoin-after.life".to_string());
|
|
||||||
|
|
||||||
let client = rClient::new();
|
|
||||||
let url = format!("{}/ping",welist_url);
|
|
||||||
let chain=bcinfo.chain.to_string().to_lowercase();
|
|
||||||
let message = format!("{0}{1}{2}{3}{4}",cfg.url,chain,bcinfo.blocks,bcinfo.median_time,bcinfo.best_block_hash);
|
|
||||||
let sign = sign_message(cfg.ssl_key_path.as_str(),&message.as_str());
|
|
||||||
let response = client.post(url)
|
|
||||||
.header("User-Agent", format!("bal-pusher/{}",VERSION))
|
|
||||||
.json(&json!(
|
|
||||||
{
|
|
||||||
"url": cfg.url,
|
|
||||||
"chain": chain,
|
|
||||||
"height": bcinfo.blocks,
|
|
||||||
"median_time": bcinfo.median_time,
|
|
||||||
"last_block_hash": bcinfo.best_block_hash,
|
|
||||||
"signature": sign,
|
|
||||||
}))
|
|
||||||
.send().await?;
|
|
||||||
let body = &(response.text().await?);
|
|
||||||
println!("Body: {}", body);
|
|
||||||
}else {
|
|
||||||
debug!("Not sending stats");
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
fn sign_message(private_key_path: &str, message: &str) -> String {
|
|
||||||
let key_data = fs::read(private_key_path).unwrap();
|
|
||||||
|
|
||||||
let private_key = PKey::private_key_from_pem(&key_data).unwrap();
|
|
||||||
|
|
||||||
let mut signer = Signer::new(MessageDigest::sha256(), &private_key).unwrap();
|
|
||||||
|
|
||||||
signer.update(message.as_bytes()).unwrap();
|
|
||||||
|
|
||||||
let firma = signer.sign_to_vec().unwrap();
|
|
||||||
|
|
||||||
let firma_b64 = general_purpose::STANDARD.encode(&firma);
|
|
||||||
|
|
||||||
firma_b64
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_env(cfg: &mut MyConfig){
|
fn parse_env(cfg: &mut MyConfig){
|
||||||
match env::var("BAL_PUSHER_ZMQ_LISTENER") {
|
match env::var("BAL_PUSHER_ZMQ_LISTENER") {
|
||||||
@ -372,27 +305,6 @@ fn parse_env(cfg: &mut MyConfig){
|
|||||||
cfg.bitcoin_dir = value;},
|
cfg.bitcoin_dir = value;},
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
}
|
}
|
||||||
match env::var("BAL_PUSHER_SEND_STATS") {
|
|
||||||
Ok(value) => {
|
|
||||||
cfg.send_stats = value.parse::<bool>().unwrap();
|
|
||||||
},
|
|
||||||
Err(_) => {},
|
|
||||||
}
|
|
||||||
match env::var("BAL_SERVER_URL") {
|
|
||||||
Ok(value) => {
|
|
||||||
cfg.url= value;},
|
|
||||||
Err(_) => {},
|
|
||||||
}
|
|
||||||
match env::var("WELIST_SECRET_CODE") {
|
|
||||||
Ok(value) => {
|
|
||||||
cfg.secret_code = value;},
|
|
||||||
Err(_) => {},
|
|
||||||
}
|
|
||||||
match env::var("SSL_KEY_PATH") {
|
|
||||||
Ok(value) => {
|
|
||||||
cfg.ssl_key_path = value;},
|
|
||||||
Err(_) => {},
|
|
||||||
}
|
|
||||||
cfg.regtest = parse_env_netconfig(cfg,"regtest");
|
cfg.regtest = parse_env_netconfig(cfg,"regtest");
|
||||||
cfg.signet = parse_env_netconfig(cfg,"signet");
|
cfg.signet = parse_env_netconfig(cfg,"signet");
|
||||||
cfg.testnet = parse_env_netconfig(cfg,"testnet");
|
cfg.testnet = parse_env_netconfig(cfg,"testnet");
|
||||||
@ -449,8 +361,8 @@ fn get_default_config()-> MyConfig {
|
|||||||
info!("Default configuration file path is: {:#?}", file);
|
info!("Default configuration file path is: {:#?}", file);
|
||||||
confy::load("bal-pusher",None).expect("cant_load")
|
confy::load("bal-pusher",None).expect("cant_load")
|
||||||
}
|
}
|
||||||
#[tokio::main]
|
|
||||||
async fn main()-> std::io::Result<()>{
|
fn main(){
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
let mut cfg: MyConfig = match env::var("BAL_PUSHER_CONFIG_FILE") {
|
let mut cfg: MyConfig = match env::var("BAL_PUSHER_CONFIG_FILE") {
|
||||||
Ok(value) => {
|
Ok(value) => {
|
||||||
@ -499,7 +411,7 @@ async fn main()-> std::io::Result<()>{
|
|||||||
|
|
||||||
socket.set_subscribe(b"").unwrap();
|
socket.set_subscribe(b"").unwrap();
|
||||||
|
|
||||||
let _ = main_result(&cfg,network_params).await;
|
let _ = main_result(&cfg,network_params);
|
||||||
info!("waiting new blocks..");
|
info!("waiting new blocks..");
|
||||||
let mut last_seq:Vec<u8>=[0;4].to_vec();
|
let mut last_seq:Vec<u8>=[0;4].to_vec();
|
||||||
loop {
|
loop {
|
||||||
@ -522,7 +434,7 @@ async fn main()-> std::io::Result<()>{
|
|||||||
if topic == b"hashblock" {
|
if topic == b"hashblock" {
|
||||||
info!("NEW BLOCK: {}", hex::encode(&body));
|
info!("NEW BLOCK: {}", hex::encode(&body));
|
||||||
//let cfg = cfg.clone();
|
//let cfg = cfg.clone();
|
||||||
let _ = main_result(&cfg,network_params).await;
|
let _ = main_result(&cfg,network_params);
|
||||||
}
|
}
|
||||||
thread::sleep(Duration::from_millis(100)); // Sleep for 100ms
|
thread::sleep(Duration::from_millis(100)); // Sleep for 100ms
|
||||||
}
|
}
|
||||||
|
|||||||
@ -117,13 +117,13 @@ async fn echo_info(
|
|||||||
info!("echo info!!!{}",param);
|
info!("echo info!!!{}",param);
|
||||||
let netconfig=MyConfig::get_net_config(cfg,param);
|
let netconfig=MyConfig::get_net_config(cfg,param);
|
||||||
if !netconfig.enabled {
|
if !netconfig.enabled {
|
||||||
debug!("network disabled {}",param);
|
trace!("network disabled");
|
||||||
return Ok(Response::new(full("network disabled")));
|
return Ok(Response::new(full("network disabled")));
|
||||||
}
|
}
|
||||||
let address = match netconfig.xpub{
|
let address = match netconfig.xpub{
|
||||||
false => {
|
false => {
|
||||||
let address = netconfig.address.to_string();
|
let address = netconfig.address.to_string();
|
||||||
trace!("is address: {}",&address);
|
info!("is address: {}",&address);
|
||||||
address
|
address
|
||||||
},
|
},
|
||||||
true => {
|
true => {
|
||||||
@ -134,8 +134,8 @@ async fn echo_info(
|
|||||||
let next = get_next_address_index(&db,&netconfig.name,&netconfig.address);
|
let next = get_next_address_index(&db,&netconfig.name,&netconfig.address);
|
||||||
let address = new_address_from_xpub(&netconfig.address,next.1,netconfig.network).unwrap();
|
let address = new_address_from_xpub(&netconfig.address,next.1,netconfig.network).unwrap();
|
||||||
save_new_address(&db,next.0,&address.0,&address.1,&remote_addr);
|
save_new_address(&db,next.0,&address.0,&address.1,&remote_addr);
|
||||||
debug!("save new address {} {}",address.0,address.1);
|
debug!("address {} {}",address.0,address.1);
|
||||||
trace!("next {} {}",next.0,next.1);
|
debug!("next {} {}",next.0,next.1);
|
||||||
address.0
|
address.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,10 +151,7 @@ async fn echo_info(
|
|||||||
};
|
};
|
||||||
trace!("address: {:#?}",info);
|
trace!("address: {:#?}",info);
|
||||||
match serde_json::to_string(&info){
|
match serde_json::to_string(&info){
|
||||||
Ok(json_data) => {
|
Ok(json_data) => Ok(Response::new(full(json_data))),
|
||||||
debug!("echo info reply: {}", json_data);
|
|
||||||
return Ok(Response::new(full(json_data)));
|
|
||||||
},
|
|
||||||
Err(err) => Ok(Response::new(full(format!("error:{}",err))))
|
Err(err) => Ok(Response::new(full(format!("error:{}",err))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -461,30 +458,23 @@ fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {
|
|||||||
.boxed()
|
.boxed()
|
||||||
}
|
}
|
||||||
fn parse_env(cfg: &Arc<Mutex<MyConfig>>){
|
fn parse_env(cfg: &Arc<Mutex<MyConfig>>){
|
||||||
for (key, value) in std::env::vars() {
|
|
||||||
debug!("ENVIRONMENT {key}: {value}");
|
|
||||||
}
|
|
||||||
let mut cfg_lock = cfg.lock().unwrap();
|
let mut cfg_lock = cfg.lock().unwrap();
|
||||||
if let Ok(value) = env::var("BAL_SERVER_DB_FILE") {
|
if let Ok(value) = env::var("BAL_SERVER_DB_FILE") {
|
||||||
debug!("BAL_SERVER_DB_FILE: {}",value);
|
|
||||||
cfg_lock.db_file = value;
|
cfg_lock.db_file = value;
|
||||||
}
|
}
|
||||||
if let Ok(value) = env::var("BAL_SERVER_BIND_ADDRESS") {
|
if let Ok(value) = env::var("BAL_SERVER_BIND_ADDRESS") {
|
||||||
debug!("BAL_SERVER_BIND_ADDRESS: {}",value);
|
|
||||||
cfg_lock.bind_address= value;
|
cfg_lock.bind_address= value;
|
||||||
}
|
}
|
||||||
if let Ok(value) = env::var("BAL_SERVER_BIND_PORT") {
|
if let Ok(value) = env::var("BAL_SERVER_BIND_PORT") {
|
||||||
debug!("BAL_SERVER_BIND_PORT: {}",value);
|
|
||||||
if let Ok(v) = value.parse::<u16>(){
|
if let Ok(v) = value.parse::<u16>(){
|
||||||
cfg_lock.bind_port = v;
|
cfg_lock.bind_port = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if let Ok(value) = env::var("BAL_SERVER_INFO"){
|
if let Ok(value) = env::var("BAL_SERVER_INFO"){
|
||||||
debug!("BAL_SERVER_INFO: {}",value);
|
|
||||||
cfg_lock.info = value;
|
cfg_lock.info = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg_lock = parse_env_netconfig(cfg_lock,"regtest");
|
cfg_lock = parse_env_netconfig(cfg_lock,"regtest");
|
||||||
cfg_lock = parse_env_netconfig(cfg_lock,"signet");
|
cfg_lock = parse_env_netconfig(cfg_lock,"signet");
|
||||||
cfg_lock = parse_env_netconfig(cfg_lock,"testnet");
|
cfg_lock = parse_env_netconfig(cfg_lock,"testnet");
|
||||||
@ -499,7 +489,6 @@ fn parse_env_netconfig<'a>(mut cfg_lock: MutexGuard<'a, MyConfig>, chain: &'a st
|
|||||||
&_ => &mut cfg_lock.mainnet,
|
&_ => &mut cfg_lock.mainnet,
|
||||||
};
|
};
|
||||||
if let Ok(value) = env::var(format!("BAL_SERVER_{}_ADDRESS",chain.to_uppercase())) {
|
if let Ok(value) = env::var(format!("BAL_SERVER_{}_ADDRESS",chain.to_uppercase())) {
|
||||||
debug!("BAL_SERVER_{}_ADDRESS: {}",chain.to_uppercase(),value);
|
|
||||||
cfg.address = value;
|
cfg.address = value;
|
||||||
if cfg.address.len() > 5 {
|
if cfg.address.len() > 5 {
|
||||||
if cfg.address[1..4] == *"pub" {
|
if cfg.address[1..4] == *"pub" {
|
||||||
@ -511,7 +500,6 @@ fn parse_env_netconfig<'a>(mut cfg_lock: MutexGuard<'a, MyConfig>, chain: &'a st
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(value) = env::var(format!("BAL_SERVER_{}_FIXED_FEE",chain.to_uppercase())) {
|
if let Ok(value) = env::var(format!("BAL_SERVER_{}_FIXED_FEE",chain.to_uppercase())) {
|
||||||
debug!("BAL_SERVER_{}_FIXED_FEE: {}",chain.to_uppercase(),value);
|
|
||||||
if let Ok(v) = value.parse::<u64>(){
|
if let Ok(v) = value.parse::<u64>(){
|
||||||
cfg.fixed_fee = v;
|
cfg.fixed_fee = v;
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/db.rs
15
src/db.rs
@ -131,17 +131,4 @@ pub fn execute_insert(db: &Connection,
|
|||||||
Ok(())
|
Ok(())
|
||||||
|
|
||||||
}
|
}
|
||||||
pub fn get_total_transaction_number(db: Connection, network: &String) -> Result<i64,Error> {
|
|
||||||
let mut stmt = db.prepare("SELECT COUNT(*) as total_number FROM tbl_tx where network = ?;").unwrap();
|
|
||||||
stmt.bind((1,Value::String(network.to_string()))).unwrap();
|
|
||||||
match stmt.next(){
|
|
||||||
Ok(State::Row)=>{
|
|
||||||
Ok(stmt.read::<i64,_>("total_number").unwrap())
|
|
||||||
},
|
|
||||||
Ok(sqlite::State::Done) => todo!(),
|
|
||||||
Err(err)=>Err(err)
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user