Add a String to Monero ConnectionErrors debugging the issue

We're reaching this in CI so there must be some issue present.
This commit is contained in:
Luke Parker 2023-11-03 05:45:31 -04:00
parent a2089c61fb
commit 4c9e3b085b
No known key found for this signature in database
4 changed files with 45 additions and 28 deletions

View file

@ -26,8 +26,8 @@ mod binaries {
let hash = loop {
match rpc.get_block_hash(block_i).await {
Ok(hash) => break hash,
Err(RpcError::ConnectionError) => {
println!("get_block_hash ConnectionError");
Err(RpcError::ConnectionError(e)) => {
println!("get_block_hash ConnectionError: {e}");
continue;
}
Err(e) => panic!("couldn't get block {block_i}'s hash: {e:?}"),
@ -42,8 +42,8 @@ mod binaries {
let res: BlockResponse = loop {
match rpc.json_rpc_call("get_block", Some(json!({ "hash": hex::encode(hash) }))).await {
Ok(res) => break res,
Err(RpcError::ConnectionError) => {
println!("get_block ConnectionError");
Err(RpcError::ConnectionError(e)) => {
println!("get_block ConnectionError: {e}");
continue;
}
Err(e) => panic!("couldn't get block {block_i} via block.hash(): {e:?}"),
@ -85,8 +85,8 @@ mod binaries {
.await
{
Ok(txs) => break txs,
Err(RpcError::ConnectionError) => {
println!("get_transactions ConnectionError");
Err(RpcError::ConnectionError(e)) => {
println!("get_transactions ConnectionError: {e}");
continue;
}
Err(e) => panic!("couldn't call get_transactions: {e:?}"),
@ -190,8 +190,8 @@ mod binaries {
.await
{
Ok(outs) => break outs,
Err(RpcError::ConnectionError) => {
println!("get_outs ConnectionError");
Err(RpcError::ConnectionError(e)) => {
println!("get_outs ConnectionError: {e}");
continue;
}
Err(e) => panic!("couldn't connect to RPC to get outs: {e:?}"),

View file

@ -1,7 +1,11 @@
use core::str::FromStr;
use async_trait::async_trait;
use digest_auth::AuthContext;
use hyper::{header::HeaderValue, Request, service::Service, client::connect::HttpConnector, Client};
use hyper::{
Uri, header::HeaderValue, Request, service::Service, client::connect::HttpConnector, Client,
};
use hyper_rustls::{HttpsConnector, HttpsConnectorBuilder};
use crate::rpc::{RpcError, RpcConnection, Rpc};
@ -41,7 +45,7 @@ impl HttpRpc {
let url_clone = url;
let split_url = url_clone.split('@').collect::<Vec<_>>();
if split_url.len() != 2 {
Err(RpcError::ConnectionError)?;
Err(RpcError::ConnectionError("invalid amount of login specifications".to_string()))?;
}
let mut userpass = split_url[0];
url = split_url[1].to_string();
@ -50,20 +54,20 @@ impl HttpRpc {
if userpass.contains("://") {
let split_userpass = userpass.split("://").collect::<Vec<_>>();
if split_userpass.len() != 2 {
Err(RpcError::ConnectionError)?;
Err(RpcError::ConnectionError("invalid amount of protocol specifications".to_string()))?;
}
url = split_userpass[0].to_string() + "://" + &url;
userpass = split_userpass[1];
}
let split_userpass = userpass.split(':').collect::<Vec<_>>();
if split_userpass.len() != 2 {
Err(RpcError::ConnectionError)?;
if split_userpass.len() > 2 {
Err(RpcError::ConnectionError("invalid amount of passwords".to_string()))?;
}
Authentication::Authenticated(
https_builder,
split_userpass[0].to_string(),
split_userpass[1].to_string(),
split_userpass.get(1).unwrap_or(&"").to_string(),
)
} else {
Authentication::Unauthenticated(Client::builder().build(https_builder))
@ -93,23 +97,28 @@ impl HttpRpc {
Authentication::Unauthenticated(client) => client
.request(request(self.url.clone() + "/" + route))
.await
.map_err(|_| RpcError::ConnectionError)?,
.map_err(|e| RpcError::ConnectionError(e.to_string()))?,
Authentication::Authenticated(https_builder, user, pass) => {
let connection = https_builder
.clone()
.call(self.url.parse().map_err(|_| RpcError::ConnectionError)?)
.call(
self
.url
.parse()
.map_err(|e: <Uri as FromStr>::Err| RpcError::ConnectionError(e.to_string()))?,
)
.await
.map_err(|_| RpcError::ConnectionError)?;
.map_err(|e| RpcError::ConnectionError(e.to_string()))?;
let (mut requester, connection) = hyper::client::conn::http1::handshake(connection)
.await
.map_err(|_| RpcError::ConnectionError)?;
.map_err(|e| RpcError::ConnectionError(e.to_string()))?;
let connection_task = tokio::spawn(connection);
connection_task_handle = Some(connection_task.abort_handle());
let mut response = requester
.send_request(request("/".to_string() + route))
.await
.map_err(|_| RpcError::ConnectionError)?;
.map_err(|e| RpcError::ConnectionError(e.to_string()))?;
// Only provide authentication if this daemon actually expects it
if let Some(header) = response.headers().get("www-authenticate") {
let mut request = request("/".to_string() + route);
@ -135,11 +144,13 @@ impl HttpRpc {
);
// Wait for the connection to be ready again
requester.ready().await.map_err(|_| RpcError::ConnectionError)?;
requester.ready().await.map_err(|e| RpcError::ConnectionError(e.to_string()))?;
// Make the request with the response challenge
response =
requester.send_request(request).await.map_err(|_| RpcError::ConnectionError)?;
response = requester
.send_request(request)
.await
.map_err(|e| RpcError::ConnectionError(e.to_string()))?;
}
response
@ -164,13 +175,13 @@ impl HttpRpc {
let mut body = response.into_body();
while res.len() < length {
let Some(data) = body.data().await else { break };
res.extend(data.map_err(|_| RpcError::ConnectionError)?.as_ref());
res.extend(data.map_err(|e| RpcError::ConnectionError(e.to_string()))?.as_ref());
}
*/
let res = hyper::body::to_bytes(response.into_body())
.await
.map_err(|_| RpcError::ConnectionError)?
.map_err(|e| RpcError::ConnectionError(e.to_string()))?
.to_vec();
if let Some(connection_task) = connection_task_handle {
@ -188,6 +199,6 @@ impl RpcConnection for HttpRpc {
// TODO: Make this timeout configurable
tokio::time::timeout(core::time::Duration::from_secs(30), self.inner_post(route, body))
.await
.map_err(|_| RpcError::ConnectionError)?
.map_err(|e| RpcError::ConnectionError(e.to_string()))?
}
}

View file

@ -57,8 +57,8 @@ struct TransactionsResponse {
pub enum RpcError {
#[cfg_attr(feature = "std", error("internal error ({0})"))]
InternalError(&'static str),
#[cfg_attr(feature = "std", error("connection error"))]
ConnectionError,
#[cfg_attr(feature = "std", error("connection error ({0})"))]
ConnectionError(String),
#[cfg_attr(feature = "std", error("invalid node ({0})"))]
InvalidNode(&'static str),
#[cfg_attr(feature = "std", error("unsupported protocol version ({0})"))]

View file

@ -182,6 +182,9 @@ impl PartialEq for Monero {
impl Eq for Monero {}
fn map_rpc_err(err: RpcError) -> NetworkError {
if let RpcError::ConnectionError(e) = &err {
log::debug!("Monero ConnectionError: {e}");
}
if let RpcError::InvalidNode(reason) = &err {
log::error!("Monero RpcError::InvalidNode({reason})");
}
@ -599,7 +602,10 @@ impl Network for Monero {
async fn publish_transaction(&self, tx: &Self::Transaction) -> Result<(), NetworkError> {
match self.rpc.publish_transaction(tx).await {
Ok(_) => Ok(()),
Err(RpcError::ConnectionError) => Err(NetworkError::ConnectionError)?,
Err(RpcError::ConnectionError(e)) => {
log::debug!("Monero ConnectionError: {e}");
Err(NetworkError::ConnectionError)?
}
// TODO: Distinguish already in pool vs double spend (other signing attempt succeeded) vs
// invalid transaction
Err(e) => panic!("failed to publish TX {}: {e}", hex::encode(tx.hash())),