mirror of
https://github.com/jwinterm/grin-wallet.git
synced 2026-10-17 07:11:36 +02:00
Connection timeout (#765)
This commit is contained in:
+7
-3
@@ -140,7 +140,7 @@ where
|
||||
///
|
||||
/// // A NodeClient must first be created to handle communication between
|
||||
/// // the wallet and the node.
|
||||
/// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap();
|
||||
/// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None, wallet_config.api_request_timeout()).unwrap();
|
||||
///
|
||||
/// // impls::DefaultWalletImpl is provided for convenience in instantiating the wallet
|
||||
/// // It contains the LMDBBackend, DefaultLCProvider (lifecycle) and ExtKeychain used
|
||||
@@ -506,8 +506,12 @@ macro_rules! doctest_helper_setup_doc_env_foreign {
|
||||
wallet_config.data_file_dir = dir.to_owned();
|
||||
let pw = ZeroingString::from("");
|
||||
|
||||
let node_client =
|
||||
HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap();
|
||||
let node_client = HTTPNodeClient::new(
|
||||
&wallet_config.check_node_api_http_addr,
|
||||
None,
|
||||
wallet_config.api_request_timeout(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut wallet =
|
||||
Box::new(DefaultWalletImpl::<HTTPNodeClient>::new(node_client.clone()).unwrap())
|
||||
as Box<
|
||||
|
||||
+7
-3
@@ -147,7 +147,7 @@ where
|
||||
///
|
||||
/// // A NodeClient must first be created to handle communication between
|
||||
/// // the wallet and the node.
|
||||
/// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap();
|
||||
/// let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None, wallet_config.api_request_timeout()).unwrap();
|
||||
///
|
||||
/// // impls::DefaultWalletImpl is provided for convenience in instantiating the wallet
|
||||
/// // It contains the WalletBackend, DefaultLCProvider (lifecycle) and ExtKeychain used
|
||||
@@ -2610,8 +2610,12 @@ macro_rules! doctest_helper_setup_doc_env {
|
||||
wallet_config.data_file_dir = dir.to_owned();
|
||||
let pw = ZeroingString::from("");
|
||||
|
||||
let node_client =
|
||||
HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap();
|
||||
let node_client = HTTPNodeClient::new(
|
||||
&wallet_config.check_node_api_http_addr,
|
||||
None,
|
||||
wallet_config.api_request_timeout(),
|
||||
)
|
||||
.unwrap();
|
||||
let mut wallet =
|
||||
Box::new(DefaultWalletImpl::<HTTPNodeClient>::new(node_client.clone()).unwrap())
|
||||
as Box<
|
||||
|
||||
@@ -70,6 +70,13 @@ fn comments() -> HashMap<String, String> {
|
||||
"check_node_api_http_addr".to_string(),
|
||||
"
|
||||
#where the wallet should find a running node
|
||||
"
|
||||
.to_string(),
|
||||
);
|
||||
retval.insert(
|
||||
"node_api_request_timeout_secs".to_string(),
|
||||
"
|
||||
#total timeout for requests to node API
|
||||
"
|
||||
.to_string(),
|
||||
);
|
||||
@@ -252,6 +259,22 @@ fn comments() -> HashMap<String, String> {
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
retval.insert(
|
||||
"request_timeout_secs".to_string(),
|
||||
"
|
||||
#Tor request timeout in seconds
|
||||
"
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
retval.insert(
|
||||
"bootstrap_timeout_secs".to_string(),
|
||||
"
|
||||
#Tor bootstrap timeout in seconds
|
||||
"
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
retval.insert(
|
||||
"[tor.bridge]".to_string(),
|
||||
"
|
||||
|
||||
+47
-3
@@ -14,12 +14,12 @@
|
||||
|
||||
//! Public types for config modules
|
||||
|
||||
use crate::core::global::ChainTypes;
|
||||
use crate::util::logger::LoggingConfig;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::core::global::ChainTypes;
|
||||
use crate::util::logger::LoggingConfig;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Command-line wallet configuration
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
@@ -37,6 +37,8 @@ pub struct WalletConfig {
|
||||
/// The api address of a running server node against which transaction inputs
|
||||
/// will be checked during send
|
||||
pub check_node_api_http_addr: String,
|
||||
/// Request timeout for requests to node API.
|
||||
pub node_api_request_timeout_secs: Option<u64>,
|
||||
/// Whether to include foreign API endpoints on the Owner API
|
||||
pub owner_api_include_foreign: Option<bool>,
|
||||
/// The directory in which wallet files are stored
|
||||
@@ -65,6 +67,7 @@ impl Default for WalletConfig {
|
||||
api_secret_path: Some(".owner_api_secret".to_string()),
|
||||
node_api_secret_path: Some(".foreign_api_secret".to_string()),
|
||||
check_node_api_http_addr: "http://127.0.0.1:3413".to_string(),
|
||||
node_api_request_timeout_secs: Some(Self::NODE_API_REQUEST_TIMEOUT_SECS),
|
||||
owner_api_include_foreign: Some(false),
|
||||
data_file_dir: ".".to_string(),
|
||||
no_commit_cache: Some(false),
|
||||
@@ -77,6 +80,9 @@ impl Default for WalletConfig {
|
||||
}
|
||||
|
||||
impl WalletConfig {
|
||||
/// Default Node API request timeout in seconds.
|
||||
pub const NODE_API_REQUEST_TIMEOUT_SECS: u64 = 60;
|
||||
|
||||
/// API Listen address
|
||||
pub fn api_listen_addr(&self) -> String {
|
||||
format!("127.0.0.1:{}", self.api_listen_port)
|
||||
@@ -108,6 +114,15 @@ impl WalletConfig {
|
||||
self.accept_fee_base
|
||||
.unwrap_or_else(|| WalletConfig::default_accept_fee_base())
|
||||
}
|
||||
|
||||
/// Node API requests timeout.
|
||||
pub fn api_request_timeout(&self) -> Duration {
|
||||
Duration::from_secs(
|
||||
self.node_api_request_timeout_secs
|
||||
.filter(|s| *s > 0)
|
||||
.unwrap_or(Self::NODE_API_REQUEST_TIMEOUT_SECS),
|
||||
)
|
||||
}
|
||||
}
|
||||
/// Error type wrapping config errors.
|
||||
#[derive(Debug)]
|
||||
@@ -172,6 +187,10 @@ pub struct TorConfig {
|
||||
pub socks_proxy_addr: String,
|
||||
/// Send configuration directory
|
||||
pub send_config_dir: String,
|
||||
/// Total timeout for request in seconds.
|
||||
pub request_timeout_secs: Option<u64>,
|
||||
/// Timeout for bootstrap in seconds.
|
||||
pub bootstrap_timeout_secs: Option<u64>,
|
||||
/// Tor bridge config
|
||||
#[serde(default)]
|
||||
pub bridge: TorBridgeConfig,
|
||||
@@ -188,6 +207,8 @@ impl Default for TorConfig {
|
||||
use_tor_listener: true,
|
||||
socks_proxy_addr: "127.0.0.1:59050".to_owned(),
|
||||
send_config_dir: ".".into(),
|
||||
request_timeout_secs: Some(Self::REQUEST_TIMEOUT_SECS),
|
||||
bootstrap_timeout_secs: Some(Self::BOOTSTRAP_TIMEOUT_SECS),
|
||||
bridge: TorBridgeConfig::default(),
|
||||
proxy: TorProxyConfig::default(),
|
||||
}
|
||||
@@ -195,6 +216,11 @@ impl Default for TorConfig {
|
||||
}
|
||||
|
||||
impl TorConfig {
|
||||
/// Tor request timeout in seconds.
|
||||
const REQUEST_TIMEOUT_SECS: u64 = 60;
|
||||
/// Tor bootstrap timeout in seconds.
|
||||
const BOOTSTRAP_TIMEOUT_SECS: u64 = 60;
|
||||
|
||||
/// Check if attempt to send over Tor is needed using provided possible argument at priority.
|
||||
pub fn send_tor(&self, skip_arg: Option<bool>) -> bool {
|
||||
if let Some(skip_tor) = skip_arg {
|
||||
@@ -202,6 +228,24 @@ impl TorConfig {
|
||||
}
|
||||
!self.skip_send_attempt.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Request timeout.
|
||||
pub fn request_timeout(&self) -> Duration {
|
||||
Duration::from_secs(
|
||||
self.request_timeout_secs
|
||||
.filter(|s| *s > 0)
|
||||
.unwrap_or(Self::REQUEST_TIMEOUT_SECS),
|
||||
)
|
||||
}
|
||||
|
||||
/// Bootstrap timeout.
|
||||
pub fn bootstrap_timeout(&self) -> Duration {
|
||||
Duration::from_secs(
|
||||
self.bootstrap_timeout_secs
|
||||
.filter(|s| *s > 0)
|
||||
.unwrap_or(Self::BOOTSTRAP_TIMEOUT_SECS),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Tor Bridge Config
|
||||
|
||||
@@ -22,6 +22,7 @@ use crate::error::Error;
|
||||
use crate::impls::PathToSlatepack;
|
||||
use crate::impls::SlateGetter as _;
|
||||
use crate::keychain;
|
||||
use crate::libwallet::api_impl::types::update_tx_slate_state;
|
||||
use crate::libwallet::{
|
||||
self, InitTxArgs, IssueInvoiceTxArgs, NodeClient, PaymentProof, Slate, SlateState, Slatepack,
|
||||
SlatepackAddress, Slatepacker, SlatepackerArgs, WalletLCProvider,
|
||||
@@ -40,7 +41,6 @@ use std::sync::Arc;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use uuid::Uuid;
|
||||
use grin_wallet_libwallet::api_impl::types::update_tx_slate_state;
|
||||
|
||||
fn show_recovery_phrase(phrase: ZeroingString) {
|
||||
println!("Your recovery phrase is:");
|
||||
|
||||
@@ -25,7 +25,6 @@ use crate::util::secp::key::SecretKey;
|
||||
use crate::util::{from_hex, static_secp_instance, to_base64, Mutex};
|
||||
use futures::channel::oneshot;
|
||||
use grin_wallet_api::JsonId;
|
||||
use grin_wallet_config::types::{TorBridgeConfig, TorProxyConfig};
|
||||
use grin_wallet_util::OnionV3Address;
|
||||
use hyper::body;
|
||||
use hyper::header::HeaderValue;
|
||||
@@ -88,18 +87,16 @@ fn init_tor_listener(
|
||||
sec_key: SecretKey,
|
||||
tor_dir: String,
|
||||
addr: &str,
|
||||
bridge: TorBridgeConfig,
|
||||
tor_proxy: TorProxyConfig,
|
||||
tor_config: TorConfig,
|
||||
) -> Result<Tor, Error> {
|
||||
info!("Starting external Tor Process listener.");
|
||||
|
||||
let mut process = tor_process::TorProcess::new();
|
||||
let tor_timeout = tor_config.bootstrap_timeout().as_secs();
|
||||
|
||||
let mut hm_tor_bridge: HashMap<String, String> = HashMap::new();
|
||||
let mut tor_timeout = 20;
|
||||
if bridge.bridge_line.is_some() {
|
||||
tor_timeout = 40;
|
||||
let bridge_config = tor_bridge::TorBridge::try_from(bridge)
|
||||
if tor_config.bridge.bridge_line.is_some() {
|
||||
let bridge_config = tor_bridge::TorBridge::try_from(tor_config.bridge)
|
||||
.map_err(|e| Error::TorConfig(format!("{}", e).into()))?;
|
||||
hm_tor_bridge = bridge_config
|
||||
.to_hashmap()
|
||||
@@ -107,8 +104,8 @@ fn init_tor_listener(
|
||||
}
|
||||
|
||||
let mut hm_tor_poxy: HashMap<String, String> = HashMap::new();
|
||||
if tor_proxy.transport.is_some() || tor_proxy.allowed_port.is_some() {
|
||||
let proxy_config = tor_proxy::TorProxy::try_from(tor_proxy)
|
||||
if tor_config.proxy.transport.is_some() || tor_config.proxy.allowed_port.is_some() {
|
||||
let proxy_config = tor_proxy::TorProxy::try_from(tor_config.proxy)
|
||||
.map_err(|e| Error::TorConfig(format!("{}", e).into()))?;
|
||||
hm_tor_poxy = proxy_config
|
||||
.to_hashmap()
|
||||
@@ -323,13 +320,7 @@ where
|
||||
let res = if use_integrated {
|
||||
start_tor_service(sec_key, &tor_dir, addr, tor_config.clone())
|
||||
} else {
|
||||
init_tor_listener(
|
||||
sec_key,
|
||||
tor_dir,
|
||||
addr,
|
||||
tor_config.bridge.clone(),
|
||||
tor_config.proxy.clone(),
|
||||
)
|
||||
init_tor_listener(sec_key, tor_dir, addr, tor_config)
|
||||
};
|
||||
match res {
|
||||
Ok(service) => {
|
||||
|
||||
+12
-12
@@ -12,15 +12,6 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use grin_wallet_config::TorConfig;
|
||||
use serde::Serialize;
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::client_utils::{Client, ClientError};
|
||||
use crate::libwallet::slate_versions::{SlateVersion, VersionedSlate};
|
||||
use crate::libwallet::{Error, Slate};
|
||||
@@ -30,6 +21,14 @@ use crate::tor::process::TorProcess;
|
||||
use crate::tor::proxy::TorProxy;
|
||||
use crate::tor::{config as tor_config, Tor};
|
||||
use crate::SlateSender;
|
||||
use grin_wallet_config::TorConfig;
|
||||
use serde::Serialize;
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::net::SocketAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct TorSlateSender {
|
||||
@@ -104,7 +103,7 @@ impl TorSlateSender {
|
||||
path.push("torrc");
|
||||
tor.torrc_path(path.to_str().unwrap())
|
||||
.working_dir(tor_dir.to_str().unwrap())
|
||||
.timeout(20)
|
||||
.timeout(config.bootstrap_timeout().as_secs())
|
||||
.completion_percent(100)
|
||||
.launch()
|
||||
.map_err(|e| Error::TorProcess(format!("{:?}", e)))?;
|
||||
@@ -183,14 +182,15 @@ impl TorSlateSender {
|
||||
SocketAddr::V4(self.config.socks_proxy_addr.parse().map_err(|_| {
|
||||
ClientError::Internal("Socks proxy address is not set".to_string())
|
||||
})?);
|
||||
let client = Client::with_proxy(socks_proxy_addr, "socks5h://")
|
||||
let timeout = self.config.request_timeout();
|
||||
let client = Client::with_proxy(socks_proxy_addr, "socks5h://", timeout)
|
||||
.map_err(|_| ClientError::Internal("Unable to create http client".into()))?;
|
||||
let req = client.create_post_request(url, None, &input)?;
|
||||
let res = client.send_request(req)?;
|
||||
res
|
||||
} else {
|
||||
if let Some(client) = &self.tor.client {
|
||||
tor_post(client.clone(), &input, url)
|
||||
tor_post(client.clone(), &self.config, &input, url)
|
||||
.map_err(|e| ClientError::RequestError(format!("{:?}", e)))?
|
||||
} else {
|
||||
return Err(ClientError::Internal("Tor is not configured".to_string()));
|
||||
|
||||
@@ -52,22 +52,26 @@ pub struct Client {
|
||||
|
||||
impl Client {
|
||||
/// New client
|
||||
pub fn new() -> Result<Self, Error> {
|
||||
Self::build(None)
|
||||
pub fn new(request_timeout: Duration) -> Result<Self, Error> {
|
||||
Self::build(None, request_timeout)
|
||||
}
|
||||
|
||||
pub fn with_proxy(socks_proxy_addr: SocketAddr, scheme: &'static str) -> Result<Self, Error> {
|
||||
Self::build(Some((socks_proxy_addr, scheme)))
|
||||
pub fn with_proxy(
|
||||
socks_proxy_addr: SocketAddr,
|
||||
scheme: &'static str,
|
||||
request_timeout: Duration,
|
||||
) -> Result<Self, Error> {
|
||||
Self::build(Some((socks_proxy_addr, scheme)), request_timeout)
|
||||
}
|
||||
|
||||
fn build(proxy: Option<(SocketAddr, &str)>) -> Result<Self, Error> {
|
||||
fn build(proxy: Option<(SocketAddr, &str)>, request_timeout: Duration) -> Result<Self, Error> {
|
||||
let mut headers = HeaderMap::new();
|
||||
headers.insert(USER_AGENT, HeaderValue::from_static("grin-client"));
|
||||
headers.insert(ACCEPT, HeaderValue::from_static("application/json"));
|
||||
headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
|
||||
|
||||
let mut builder = ClientBuilder::new()
|
||||
.timeout(Duration::from_secs(20))
|
||||
.timeout(request_timeout)
|
||||
.use_rustls_tls()
|
||||
.default_headers(headers);
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
//! Client functions, implementations of the NodeClient trait
|
||||
|
||||
use super::resp_types::*;
|
||||
use crate::api::{self, LocatedTxKernel, OutputListing, OutputPrintable};
|
||||
use crate::client_utils::json_rpc::*;
|
||||
use crate::client_utils::{Client, RUNTIME};
|
||||
use crate::core::core::{Transaction, TxKernel};
|
||||
use crate::libwallet;
|
||||
@@ -26,9 +28,7 @@ use futures::TryStreamExt;
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use super::resp_types::*;
|
||||
use crate::client_utils::json_rpc::*;
|
||||
use std::time::Duration;
|
||||
|
||||
const ENDPOINT: &str = "/v2/foreign";
|
||||
|
||||
@@ -45,8 +45,9 @@ impl HTTPNodeClient {
|
||||
pub fn new(
|
||||
node_url: &str,
|
||||
node_api_secret: Option<String>,
|
||||
request_timeout: Duration,
|
||||
) -> Result<HTTPNodeClient, libwallet::Error> {
|
||||
Self::new_proxy(node_url, node_api_secret, None)
|
||||
Self::new_proxy(node_url, node_api_secret, None, request_timeout)
|
||||
}
|
||||
|
||||
/// Create a new client with proxy
|
||||
@@ -54,16 +55,17 @@ impl HTTPNodeClient {
|
||||
node_url: &str,
|
||||
node_api_secret: Option<String>,
|
||||
proxy: Option<(SocketAddr, &'static str)>,
|
||||
request_timeout: Duration,
|
||||
) -> Result<HTTPNodeClient, libwallet::Error> {
|
||||
let client = if let Some((a, s)) = proxy {
|
||||
Client::with_proxy(a, s)
|
||||
Client::with_proxy(a, s, request_timeout)
|
||||
} else {
|
||||
Client::new()
|
||||
Client::new(request_timeout)
|
||||
};
|
||||
Ok(HTTPNodeClient {
|
||||
client: client.map_err(|_| libwallet::Error::Node)?,
|
||||
node_url: node_url.to_owned(),
|
||||
node_api_secret: node_api_secret,
|
||||
node_api_secret,
|
||||
node_version_info: None,
|
||||
})
|
||||
}
|
||||
@@ -107,18 +109,25 @@ impl NodeClient for HTTPNodeClient {
|
||||
fn node_url(&self) -> &str {
|
||||
&self.node_url
|
||||
}
|
||||
fn node_api_secret(&self) -> Option<String> {
|
||||
self.node_api_secret.clone()
|
||||
}
|
||||
|
||||
fn set_node_url(&mut self, node_url: &str) {
|
||||
self.node_url = node_url.to_owned();
|
||||
}
|
||||
|
||||
fn node_api_secret(&self) -> Option<String> {
|
||||
self.node_api_secret.clone()
|
||||
}
|
||||
|
||||
fn set_node_api_secret(&mut self, node_api_secret: Option<String>) {
|
||||
self.node_api_secret = node_api_secret;
|
||||
}
|
||||
|
||||
/// Posts a transaction to a grin node
|
||||
fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), libwallet::Error> {
|
||||
let params = json!([tx, fluff]);
|
||||
self.send_json_request::<serde_json::Value>("push_transaction", ¶ms)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_version_info(&mut self) -> Option<NodeVersionInfo> {
|
||||
if let Some(v) = self.node_version_info.as_ref() {
|
||||
return Some(v.clone());
|
||||
@@ -135,30 +144,23 @@ impl NodeClient for HTTPNodeClient {
|
||||
// If node isn't available, allow offline functions
|
||||
// unfortunately have to parse string due to error structure
|
||||
let err_string = format!("{}", e);
|
||||
if err_string.contains("404") {
|
||||
return Some(NodeVersionInfo {
|
||||
return if err_string.contains("404") {
|
||||
Some(NodeVersionInfo {
|
||||
node_version: "1.0.0".into(),
|
||||
block_header_version: 1,
|
||||
verified: Some(false),
|
||||
});
|
||||
})
|
||||
} else {
|
||||
error!("Unable to contact Node to get version info: {}, check your node is running", e);
|
||||
warn!("Warning: a) Node is offline, or b) 'node_api_secret_path' in 'grin-wallet.toml' is set incorrectly");
|
||||
return None;
|
||||
}
|
||||
None
|
||||
};
|
||||
}
|
||||
};
|
||||
self.node_version_info = Some(retval.clone());
|
||||
Some(retval)
|
||||
}
|
||||
|
||||
/// Posts a transaction to a grin node
|
||||
fn post_tx(&self, tx: &Transaction, fluff: bool) -> Result<(), libwallet::Error> {
|
||||
let params = json!([tx, fluff]);
|
||||
self.send_json_request::<serde_json::Value>("push_transaction", ¶ms)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return the chain tip from a given node
|
||||
fn get_chain_tip(&self) -> Result<(u64, String), libwallet::Error> {
|
||||
let result = self.send_json_request::<GetTipResp>("get_tip", &serde_json::Value::Null)?;
|
||||
@@ -222,7 +224,7 @@ impl NodeClient for HTTPNodeClient {
|
||||
.collect();
|
||||
|
||||
// going to leave this here even though we're moving
|
||||
// to the json RPC api to keep the functionality of
|
||||
// to the JSON RPC api to keep the functionality of
|
||||
// parallelizing larger requests. Will raise default
|
||||
// from 200 to 500, however
|
||||
let chunk_default = 500;
|
||||
@@ -420,8 +422,8 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
// Wallet will "push" a transaction to node, serializing the transaction as json.
|
||||
// We are testing the json structure is what we expect here.
|
||||
// Wallet will "push" a transaction to node, serializing the transaction as JSON.
|
||||
// We are testing the JSON structure is what we expect here.
|
||||
#[test]
|
||||
fn test_transaction_json_ser_deser() {
|
||||
let tx1 = tx1i1o_v2_compatible();
|
||||
|
||||
+19
-19
@@ -160,12 +160,10 @@ pub fn start_tor_client(tor_dir: &str, config: TorConfig) -> Result<Tor, Error>
|
||||
})
|
||||
}
|
||||
|
||||
/// Tor request timeout in milliseconds.
|
||||
const REQUEST_TIMEOUT_MS: u64 = 60000;
|
||||
|
||||
/// Make POST request with provided client.
|
||||
pub fn tor_post<IN>(
|
||||
client: Arc<TorClient<TokioNativeTlsRuntime>>,
|
||||
tor_config: &TorConfig,
|
||||
input: &IN,
|
||||
url: &str,
|
||||
) -> Result<String, Error>
|
||||
@@ -183,12 +181,13 @@ where
|
||||
Some(h) => h,
|
||||
}
|
||||
.to_string();
|
||||
let timeout = tor_config.request_timeout();
|
||||
let res: Result<String, Error> = thread::spawn(move || {
|
||||
let c = client.clone();
|
||||
client.runtime().block_on(async move {
|
||||
let res = c
|
||||
.runtime()
|
||||
.timeout(Duration::from_millis(REQUEST_TIMEOUT_MS), async {
|
||||
.timeout(timeout, async {
|
||||
let stream = c
|
||||
.connect((host, url.port_u16().unwrap_or(80)))
|
||||
.await
|
||||
@@ -238,21 +237,18 @@ where
|
||||
res
|
||||
}
|
||||
|
||||
/// Client Bootstrap timeout in milliseconds.
|
||||
const BOOTSTRAP_TIMEOUT_MS: u64 = 60000;
|
||||
|
||||
/// Create Tor client.
|
||||
fn init_client(
|
||||
state_path: &PathBuf,
|
||||
cache_path: &PathBuf,
|
||||
config: TorConfig,
|
||||
tor_config: TorConfig,
|
||||
reuse_client: bool,
|
||||
) -> Result<(Arc<TorClient<TokioNativeTlsRuntime>>, TorClientConfig), Error> {
|
||||
let mut builder = TorClientConfigBuilder::from_directories(&state_path, cache_path);
|
||||
builder.address_filter().allow_onion_addrs(true);
|
||||
|
||||
// Configure bridge.
|
||||
if let Some(bridge_line) = config.bridge.bridge_line {
|
||||
if let Some(bridge_line) = tor_config.bridge.bridge_line.as_ref() {
|
||||
let bridge: BridgeConfigBuilder = bridge_line
|
||||
.parse()
|
||||
.map_err(|e| Error::TorConfig(format!("{:?}", e)))?;
|
||||
@@ -266,7 +262,11 @@ fn init_client(
|
||||
}
|
||||
Some(t) => {
|
||||
// Now configure bridge transport. (Requires the "pt-client" feature)
|
||||
let bin_path = config.bridge.bridge_bin_path.unwrap_or(t.to_owned());
|
||||
let bin_path = tor_config
|
||||
.bridge
|
||||
.bridge_bin_path
|
||||
.clone()
|
||||
.unwrap_or(t.to_owned());
|
||||
let mut transport = TransportConfigBuilder::default();
|
||||
transport
|
||||
.protocols(vec![t
|
||||
@@ -294,7 +294,7 @@ fn init_client(
|
||||
*cached_client_config = None;
|
||||
}
|
||||
}
|
||||
let res = launch_client(config.clone());
|
||||
let res = launch_client(config.clone(), &tor_config);
|
||||
return match res {
|
||||
Ok(client) => {
|
||||
cached_client_config.replace((client.clone(), config.clone()));
|
||||
@@ -304,7 +304,7 @@ fn init_client(
|
||||
};
|
||||
}
|
||||
|
||||
let res = launch_client(config.clone());
|
||||
let res = launch_client(config.clone(), &tor_config);
|
||||
match res {
|
||||
Ok(client) => Ok((client, config)),
|
||||
Err(e) => Err(e),
|
||||
@@ -312,13 +312,17 @@ fn init_client(
|
||||
}
|
||||
|
||||
/// Launch tor client from provided configuration.
|
||||
fn launch_client(config: TorClientConfig) -> Result<Arc<TorClient<TokioNativeTlsRuntime>>, Error> {
|
||||
fn launch_client(
|
||||
client_config: TorClientConfig,
|
||||
tor_config: &TorConfig,
|
||||
) -> Result<Arc<TorClient<TokioNativeTlsRuntime>>, Error> {
|
||||
let r = runtime()?;
|
||||
let client = TorClient::with_runtime(r)
|
||||
.config(config)
|
||||
.config(client_config)
|
||||
.create_unbootstrapped()
|
||||
.map_err(|e| Error::TorProcess(format!("{:?}", e)))?;
|
||||
let c = client.clone();
|
||||
let timeout = tor_config.bootstrap_timeout();
|
||||
let res = client.runtime().block_on(async move {
|
||||
let bootstrap = async || {
|
||||
return match c.bootstrap().await {
|
||||
@@ -339,11 +343,7 @@ fn launch_client(config: TorClientConfig) -> Result<Arc<TorClient<TokioNativeTls
|
||||
Err(e) => Err(e),
|
||||
};
|
||||
};
|
||||
match c
|
||||
.runtime()
|
||||
.timeout(Duration::from_millis(BOOTSTRAP_TIMEOUT_MS), bootstrap())
|
||||
.await
|
||||
{
|
||||
match c.runtime().timeout(timeout, bootstrap()).await {
|
||||
Ok(r) => match r {
|
||||
Err(e) => Err(Error::TorProcess(format!("{:?}", e))),
|
||||
Ok(_) => Ok(c),
|
||||
|
||||
+12
-11
@@ -51,13 +51,13 @@ extern crate timer;
|
||||
|
||||
use regex::Regex;
|
||||
use std::fs::{self, File};
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use std::path::{Path, MAIN_SEPARATOR};
|
||||
use std::process::{Child, ChildStdout, Command, Stdio};
|
||||
use std::sync::mpsc::channel;
|
||||
use std::thread;
|
||||
use std::{cmp, io};
|
||||
use sysinfo::{Process, ProcessExt, System, SystemExt};
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -83,7 +83,7 @@ pub struct TorProcess {
|
||||
args: Vec<String>,
|
||||
torrc_path: Option<String>,
|
||||
completion_percent: u8,
|
||||
timeout: u32,
|
||||
timeout: u64,
|
||||
working_dir: Option<String>,
|
||||
pub stdout: Option<BufReader<ChildStdout>>,
|
||||
pub process: Option<Child>,
|
||||
@@ -96,8 +96,8 @@ impl TorProcess {
|
||||
tor_cmd: TOR_EXE_NAME.to_string(),
|
||||
args: vec![],
|
||||
torrc_path: None,
|
||||
completion_percent: 100 as u8,
|
||||
timeout: 0 as u32,
|
||||
completion_percent: 100,
|
||||
timeout: 0,
|
||||
working_dir: None,
|
||||
stdout: None,
|
||||
process: None,
|
||||
@@ -137,7 +137,7 @@ impl TorProcess {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn timeout(&mut self, timeout: u32) -> &mut Self {
|
||||
pub fn timeout(&mut self, timeout: u64) -> &mut Self {
|
||||
self.timeout = timeout;
|
||||
self
|
||||
}
|
||||
@@ -198,10 +198,11 @@ impl TorProcess {
|
||||
let stdout_timeout_tx = stdout_tx.clone();
|
||||
|
||||
let timer = timer::Timer::new();
|
||||
let _guard =
|
||||
timer.schedule_with_delay(chrono::Duration::seconds(self.timeout as i64), move || {
|
||||
stdout_timeout_tx.send(Err(Error::Timeout)).unwrap_or(());
|
||||
});
|
||||
// Keep this below chrono's DateTime range used by timer.
|
||||
let timeout = chrono::Duration::seconds(cmp::min(self.timeout, u32::MAX as u64) as i64);
|
||||
let _guard = timer.schedule_with_delay(timeout, move || {
|
||||
stdout_timeout_tx.send(Err(Error::Timeout)).unwrap_or(());
|
||||
});
|
||||
let stdout_thread = thread::spawn(move || {
|
||||
stdout_tx
|
||||
.send(Self::parse_tor_stdout(stdout, completion_percent))
|
||||
@@ -225,8 +226,8 @@ impl TorProcess {
|
||||
mut stdout: BufReader<ChildStdout>,
|
||||
completion_perc: u8,
|
||||
) -> Result<BufReader<ChildStdout>, Error> {
|
||||
let re_bootstrap = Regex::new(r"^\[notice\] Bootstrapped (?P<perc>[0-9]+)%(.*): ")
|
||||
.map_err(Error::Regex)?;
|
||||
let re_bootstrap =
|
||||
Regex::new(r"^\[notice] Bootstrapped (?P<perc>[0-9]+)%(.*): ").map_err(Error::Regex)?;
|
||||
|
||||
let timestamp_len = "May 16 02:50:08.792".len();
|
||||
let mut warnings = Vec::new();
|
||||
|
||||
@@ -281,7 +281,7 @@ impl LocalServerContainer {
|
||||
let _ = fs::create_dir_all(self.wallet_config.clone().data_file_dir);
|
||||
let r = wallet::WalletSeed::init_file(&self.wallet_config, 32, None, "");
|
||||
|
||||
let client_n = HTTPNodeClient::new(&self.wallet_config.check_node_api_http_addr, None);
|
||||
let client_n = HTTPNodeClient::new(&self.wallet_config.check_node_api_http_addr, None, std::time::Duration::from_secs(60));
|
||||
|
||||
if let Err(_e) = r {
|
||||
//panic!("Error initializing wallet seed: {}", e);
|
||||
@@ -354,7 +354,7 @@ impl LocalServerContainer {
|
||||
let keychain: keychain::ExtKeychain = wallet_seed
|
||||
.derive_keychain(false)
|
||||
.expect("Failed to derive keychain from seed file and passphrase.");
|
||||
let client_n = HTTPNodeClient::new(&config.check_node_api_http_addr, None);
|
||||
let client_n = HTTPNodeClient::new(&config.check_node_api_http_addr, None, std::time::Duration::from_secs(60));
|
||||
let mut wallet = LMDBBackend::new(config.clone(), "", client_n)
|
||||
.unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, config));
|
||||
wallet.keychain = Some(keychain);
|
||||
@@ -382,7 +382,7 @@ impl LocalServerContainer {
|
||||
.derive_keychain(false)
|
||||
.expect("Failed to derive keychain from seed file and passphrase.");
|
||||
|
||||
let client_n = HTTPNodeClient::new(&config.check_node_api_http_addr, None);
|
||||
let client_n = HTTPNodeClient::new(&config.check_node_api_http_addr, None, std::time::Duration::from_secs(60));
|
||||
let client_w = HTTPWalletCommAdapter::new();
|
||||
|
||||
let max_outputs = 500;
|
||||
|
||||
@@ -908,7 +908,7 @@ fn replicate_tx_fluff_failure() {
|
||||
|
||||
// Create Wallet 1 (Mining Input) and start it listening
|
||||
// Wallet 1 post to another node, just for fun
|
||||
let client1 = HTTPNodeClient::new("http://127.0.0.1:23003", None);
|
||||
let client1 = HTTPNodeClient::new("http://127.0.0.1:23003", None, std::time::Duration::from_secs(60));
|
||||
let client1_w = HTTPWalletCommAdapter::new();
|
||||
let wallet1 = create_wallet("target/tmp/tx_fluff/wallet1", client1.clone());
|
||||
let _wallet1_handle = thread::spawn(move || {
|
||||
@@ -917,7 +917,7 @@ fn replicate_tx_fluff_failure() {
|
||||
});
|
||||
|
||||
// Create Wallet 2 (Recipient) and launch
|
||||
let client2 = HTTPNodeClient::new("http://127.0.0.1:23001", None);
|
||||
let client2 = HTTPNodeClient::new("http://127.0.0.1:23001", None, std::time::Duration::from_secs(60));
|
||||
let wallet2 = create_wallet("target/tmp/tx_fluff/wallet2", client2.clone());
|
||||
let _wallet2_handle = thread::spawn(move || {
|
||||
controller::foreign_listener(wallet2, "127.0.0.1:33001", None)
|
||||
|
||||
@@ -161,6 +161,8 @@ fn real_main() -> i32 {
|
||||
|
||||
global::init_global_accept_fee_base(config.members.as_ref().unwrap().wallet.accept_fee_base());
|
||||
let wallet_config = config.clone().members.unwrap().wallet;
|
||||
let node_client = HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None).unwrap();
|
||||
let timeout = wallet_config.api_request_timeout();
|
||||
let node_client =
|
||||
HTTPNodeClient::new(&wallet_config.check_node_api_http_addr, None, timeout).unwrap();
|
||||
cmd::wallet_command(&args, config, node_client)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user