use std::str::FromStr;
use dialoguer::Input as InputPrompt;
use minotari_app_grpc::{
authentication::ClientAuthenticationInterceptor,
tari_rpc::{
Block,
NewBlockTemplate,
NewBlockTemplateRequest,
base_node_client::BaseNodeClient,
sha_p2_pool_client::ShaP2PoolClient,
},
};
use tari_common::configuration::{
Network,
bootstrap::{ApplicationType, grpc_default_port},
};
use tari_common_types::tari_address::TariAddress;
use thiserror::Error;
use tonic::{
Code,
codegen::InterceptedService,
transport::{Channel, Uri},
};
#[derive(Debug, Error)]
pub enum ParseInputError {
#[error("Could not convert data:{0}")]
WalletPaymentAddress(String),
#[error("Could not convert data:{0}")]
BaseNodeSocketAddress(String),
}
pub fn prompt_for_base_node_address(network: Network) -> Result<String, ParseInputError> {
loop {
let mut address = InputPrompt::<String>::new()
.with_prompt("Please enter 'base-node-grpc-address' ('quit' or 'exit' to quit) ")
.default(format!(
"http://127.0.0.1:{}",
grpc_default_port(ApplicationType::BaseNode, network)
))
.interact()
.unwrap();
process_quit(&address);
if Uri::from_str(&address).is_err() {
println!(" Error - base node address '{address}' not valid");
continue;
}
address = address.trim().to_string();
return Ok(address);
}
}
pub fn prompt_for_p2pool_address() -> Result<String, ParseInputError> {
loop {
let mut address = InputPrompt::<String>::new()
.with_prompt("Please enter 'p2pool-grpc-address' ('quit' or 'exit' to quit) ")
.default(format!("http://127.0.0.1:{}", 18145))
.interact()
.unwrap();
process_quit(&address);
if Uri::from_str(&address).is_err() {
println!(" Error - p2pool address '{address}' not valid");
continue;
}
address = address.trim().to_string();
return Ok(address);
}
}
pub fn wallet_payment_address(
config_wallet_payment_address: String,
network: Network,
) -> Result<TariAddress, ParseInputError> {
match TariAddress::from_str(&config_wallet_payment_address) {
Ok(address) => {
if address == TariAddress::default() {
println!();
loop {
let mut address = InputPrompt::<String>::new()
.with_prompt("Please enter 'wallet-payment-address' ('quit' or 'exit' to quit) ")
.interact()
.unwrap();
process_quit(&address);
address = address.trim().to_string();
let wallet_address: Result<TariAddress, String> = address.parse().map_err(|e| format!("{e:?}"));
match wallet_address {
Ok(val) => {
if val.network() == network {
return Ok(val);
} else {
println!(
" Error - wallet payment address '{address}' does not match miner network \
'{network}'"
);
}
},
Err(e) => println!(" Error - wallet payment address '{address}' not valid ({e})"),
}
}
}
if address.network() != network {
return Err(ParseInputError::WalletPaymentAddress(format!(
"Wallet payment address '{config_wallet_payment_address}' does not match miner network '{network}'"
)));
}
Ok(address)
},
Err(err) => Err(ParseInputError::WalletPaymentAddress(format!(
"Wallet payment address '{config_wallet_payment_address}' not valid ({err})"
))),
}
}
pub fn process_quit(command: &str) {
if command.to_uppercase() == "QUIT" || command.to_uppercase() == "EXIT" {
println!("\nUser requested quit (Press 'Enter')");
wait_for_keypress();
std::process::exit(0);
}
}
pub fn wait_for_keypress() {
use std::io::{Read, stdin};
let mut stdin = stdin();
let buf: &mut [u8] = &mut [0; 2];
let _unused = stdin.read(buf).expect("Error reading keypress");
}
pub type BaseNodeGrpcClient = BaseNodeClient<InterceptedService<Channel, ClientAuthenticationInterceptor>>;
pub type ShaP2PoolGrpcClient = ShaP2PoolClient<InterceptedService<Channel, ClientAuthenticationInterceptor>>;
pub async fn verify_base_node_grpc_mining_responses(
node_conn: &mut BaseNodeGrpcClient,
pow_algo_request: NewBlockTemplateRequest,
) -> Result<(), String> {
let get_new_block_template = node_conn.get_new_block_template(pow_algo_request).await;
if let Err(e) = get_new_block_template &&
e.code() == Code::PermissionDenied
{
return Err("'get_new_block_template'".to_string());
}
let get_tip_info = node_conn.get_tip_info(minotari_app_grpc::tari_rpc::Empty {}).await;
if let Err(e) = get_tip_info &&
e.code() == Code::PermissionDenied
{
return Err("'get_tip_info'".to_string());
}
let block_result = node_conn.get_new_block(NewBlockTemplate::default()).await;
if let Err(e) = block_result &&
e.code() == Code::PermissionDenied
{
return Err("'get_new_block'".to_string());
}
if let Err(e) = node_conn.submit_block(Block::default()).await &&
e.code() == Code::PermissionDenied
{
return Err("'submit_block'".to_string());
}
Ok(())
}