use serde::Deserialize;
use std::{
net::SocketAddr,
path::{Path, PathBuf},
str::FromStr,
};
use stratum_apps::{
config_helpers::{opt_path_from_toml, CoinbaseRewardScript},
key_utils::{Secp256k1PublicKey, Secp256k1SecretKey},
stratum_core::bitcoin::{Amount, TxOut},
tp_type::TemplateProviderType,
utils::types::{SharesBatchSize, SharesPerMinute},
};
#[derive(Debug, Deserialize, Clone)]
pub struct JobDeclaratorClientConfig {
listening_address: SocketAddr,
max_supported_version: u16,
min_supported_version: u16,
authority_public_key: Secp256k1PublicKey,
authority_secret_key: Secp256k1SecretKey,
cert_validity_sec: u64,
template_provider_type: TemplateProviderType,
upstreams: Vec<Upstream>,
pub coinbase_reward_script: CoinbaseRewardScript,
jdc_signature: String,
#[serde(default, deserialize_with = "opt_path_from_toml")]
log_file: Option<PathBuf>,
user_identity: String,
shares_per_minute: SharesPerMinute,
share_batch_size: SharesBatchSize,
#[serde(deserialize_with = "deserialize_jdc_mode", default)]
pub mode: ConfigJDCMode,
#[serde(default)]
supported_extensions: Vec<u16>,
#[serde(default)]
required_extensions: Vec<u16>,
#[serde(default)]
monitoring_address: Option<SocketAddr>,
#[serde(default)]
monitoring_cache_refresh_secs: Option<u64>,
#[serde(default = "default_reserved_downstream_rollable_extranonce_size")]
reserved_downstream_rollable_extranonce_size: u8,
}
pub const DEFAULT_RESERVED_DOWNSTREAM_ROLLABLE_EXTRANONCE_SIZE: u8 = 8;
fn default_reserved_downstream_rollable_extranonce_size() -> u8 {
DEFAULT_RESERVED_DOWNSTREAM_ROLLABLE_EXTRANONCE_SIZE
}
impl JobDeclaratorClientConfig {
#[allow(clippy::too_many_arguments)]
pub fn new(
listening_address: SocketAddr,
protocol_config: ProtocolConfig,
user_identity: String,
shares_per_minute: SharesPerMinute,
shares_batch_size: SharesBatchSize,
pool_config: PoolConfig,
cert_validity_sec: u64,
template_provider_type: TemplateProviderType,
upstreams: Vec<Upstream>,
jdc_signature: String,
jdc_mode: Option<ConfigJDCMode>,
supported_extensions: Vec<u16>,
required_extensions: Vec<u16>,
monitoring_address: Option<SocketAddr>,
monitoring_cache_refresh_secs: Option<u64>,
reserved_downstream_rollable_extranonce_size: Option<u8>,
) -> Self {
Self {
listening_address,
max_supported_version: protocol_config.max_supported_version,
min_supported_version: protocol_config.min_supported_version,
authority_public_key: pool_config.authority_public_key,
authority_secret_key: pool_config.authority_secret_key,
cert_validity_sec,
template_provider_type,
upstreams,
coinbase_reward_script: protocol_config.coinbase_reward_script,
jdc_signature,
log_file: None,
user_identity,
shares_per_minute,
share_batch_size: shares_batch_size,
mode: jdc_mode.unwrap_or_default(),
supported_extensions,
required_extensions,
monitoring_address,
monitoring_cache_refresh_secs,
reserved_downstream_rollable_extranonce_size:
reserved_downstream_rollable_extranonce_size
.unwrap_or(DEFAULT_RESERVED_DOWNSTREAM_ROLLABLE_EXTRANONCE_SIZE),
}
}
pub fn monitoring_address(&self) -> Option<SocketAddr> {
self.monitoring_address
}
pub fn monitoring_cache_refresh_secs(&self) -> Option<u64> {
self.monitoring_cache_refresh_secs
}
pub fn listening_address(&self) -> &SocketAddr {
&self.listening_address
}
pub fn upstreams(&self) -> &Vec<Upstream> {
&self.upstreams
}
pub fn authority_public_key(&self) -> &Secp256k1PublicKey {
&self.authority_public_key
}
pub fn authority_secret_key(&self) -> &Secp256k1SecretKey {
&self.authority_secret_key
}
pub fn cert_validity_sec(&self) -> u64 {
self.cert_validity_sec
}
pub fn template_provider_type(&self) -> &TemplateProviderType {
&self.template_provider_type
}
pub fn min_supported_version(&self) -> u16 {
self.min_supported_version
}
pub fn max_supported_version(&self) -> u16 {
self.max_supported_version
}
pub fn jdc_signature(&self) -> &str {
&self.jdc_signature
}
pub fn get_txout(&self) -> TxOut {
TxOut {
value: Amount::from_sat(0),
script_pubkey: self.coinbase_reward_script.script_pubkey().to_owned(),
}
}
pub fn log_file(&self) -> Option<&Path> {
self.log_file.as_deref()
}
pub fn set_log_file(&mut self, log_file: Option<PathBuf>) {
if let Some(log_file) = log_file {
self.log_file = Some(log_file);
}
}
pub fn user_identity(&self) -> &str {
&self.user_identity
}
pub fn shares_per_minute(&self) -> SharesPerMinute {
self.shares_per_minute
}
pub fn share_batch_size(&self) -> SharesBatchSize {
self.share_batch_size
}
pub fn supported_extensions(&self) -> &[u16] {
&self.supported_extensions
}
pub fn required_extensions(&self) -> &[u16] {
&self.required_extensions
}
pub fn reserved_downstream_rollable_extranonce_size(&self) -> u8 {
self.reserved_downstream_rollable_extranonce_size
}
}
#[derive(Debug, Deserialize, Clone, Copy, Default, PartialEq)]
#[serde(rename_all = "UPPERCASE")]
pub enum ConfigJDCMode {
#[default]
FullTemplate,
CoinbaseOnly,
SoloMining,
}
impl std::str::FromStr for ConfigJDCMode {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_uppercase().as_str() {
"COINBASEONLY" => Ok(ConfigJDCMode::CoinbaseOnly),
"SOLOMINING" => Ok(ConfigJDCMode::SoloMining),
_ => Ok(ConfigJDCMode::FullTemplate),
}
}
}
fn deserialize_jdc_mode<'de, D>(deserializer: D) -> Result<ConfigJDCMode, D::Error>
where
D: serde::Deserializer<'de>,
{
let s: String = String::deserialize(deserializer)?;
Ok(ConfigJDCMode::from_str(&s).unwrap_or_default())
}
pub struct PoolConfig {
authority_public_key: Secp256k1PublicKey,
authority_secret_key: Secp256k1SecretKey,
}
impl PoolConfig {
pub fn new(
authority_public_key: Secp256k1PublicKey,
authority_secret_key: Secp256k1SecretKey,
) -> Self {
Self {
authority_public_key,
authority_secret_key,
}
}
}
pub struct ProtocolConfig {
max_supported_version: u16,
min_supported_version: u16,
coinbase_reward_script: CoinbaseRewardScript,
}
impl ProtocolConfig {
pub fn new(
max_supported_version: u16,
min_supported_version: u16,
coinbase_reward_script: CoinbaseRewardScript,
) -> Self {
Self {
max_supported_version,
min_supported_version,
coinbase_reward_script,
}
}
}
#[derive(Debug, Deserialize, Clone)]
pub struct Upstream {
pub authority_pubkey: Secp256k1PublicKey,
pub pool_address: String,
pub pool_port: u16,
pub jds_address: String,
pub jds_port: u16,
}
impl Upstream {
pub fn new(
authority_pubkey: Secp256k1PublicKey,
pool_address: String,
pool_port: u16,
jds_address: String,
jds_port: u16,
) -> Self {
Self {
authority_pubkey,
pool_address,
pool_port,
jds_address,
jds_port,
}
}
}