From 50fc30ec430c715963c1384aa5f9dbce87bc756d Mon Sep 17 00:00:00 2001 From: plebhash Date: Sun, 26 May 2024 14:17:57 -0300 Subject: [PATCH] standardize roles CLI --- roles/Cargo.lock | 338 ++++++++++++++++-- roles/jd-client/Cargo.toml | 3 +- roles/jd-client/src/args.rs | 81 ++--- roles/jd-client/src/lib/error.rs | 96 +++-- .../lib/{proxy_config.rs => jdc_config.rs} | 4 +- roles/jd-client/src/lib/job_declarator/mod.rs | 6 +- roles/jd-client/src/lib/mod.rs | 2 +- roles/jd-client/src/lib/status.rs | 49 +-- .../src/lib/upstream_sv2/upstream.rs | 20 +- roles/jd-client/src/main.rs | 62 ++-- roles/jd-server/Cargo.toml | 3 +- roles/jd-server/src/args.rs | 28 ++ roles/jd-server/src/lib/error.rs | 10 + roles/jd-server/src/lib/jds_config.rs | 88 +++++ roles/jd-server/src/lib/job_declarator/mod.rs | 17 +- roles/jd-server/src/lib/mod.rs | 23 +- roles/jd-server/src/lib/status.rs | 3 + roles/jd-server/src/main.rs | 102 +----- roles/mining-proxy/Cargo.toml | 3 +- roles/mining-proxy/src/args.rs | 28 ++ roles/mining-proxy/src/lib/error.rs | 22 +- roles/mining-proxy/src/lib/mod.rs | 14 +- roles/mining-proxy/src/lib/proxy_config.rs | 14 + roles/mining-proxy/src/lib/upstream_mining.rs | 16 +- roles/mining-proxy/src/main.rs | 99 +---- roles/pool/Cargo.toml | 3 +- roles/pool/src/args.rs | 29 ++ roles/pool/src/lib/error.rs | 8 + roles/pool/src/lib/mining_pool/mod.rs | 71 ++-- roles/pool/src/lib/mod.rs | 1 + roles/pool/src/lib/pool_config.rs | 57 +++ roles/pool/src/lib/status.rs | 3 + roles/pool/src/main.rs | 102 +----- roles/translator/Cargo.toml | 4 +- roles/translator/src/args.rs | 81 ++--- .../src/lib/downstream_sv1/diff_management.rs | 44 +-- .../src/lib/downstream_sv1/downstream.rs | 12 +- roles/translator/src/lib/error.rs | 122 +++---- roles/translator/src/lib/mod.rs | 2 +- roles/translator/src/lib/proxy/bridge.rs | 26 +- roles/translator/src/lib/status.rs | 79 ++-- .../lib/{proxy_config.rs => tproxy_config.rs} | 2 +- .../src/lib/upstream_sv2/diff_management.rs | 12 +- .../src/lib/upstream_sv2/upstream.rs | 39 +- .../lib/upstream_sv2/upstream_connection.rs | 6 +- roles/translator/src/main.rs | 19 +- 46 files changed, 1032 insertions(+), 821 deletions(-) rename roles/jd-client/src/lib/{proxy_config.rs => jdc_config.rs} (97%) create mode 100644 roles/jd-server/src/args.rs create mode 100644 roles/jd-server/src/lib/jds_config.rs create mode 100644 roles/mining-proxy/src/args.rs create mode 100644 roles/mining-proxy/src/lib/proxy_config.rs create mode 100644 roles/pool/src/args.rs create mode 100644 roles/pool/src/lib/pool_config.rs rename roles/translator/src/lib/{proxy_config.rs => tproxy_config.rs} (98%) diff --git a/roles/Cargo.lock b/roles/Cargo.lock index 1c0dc4d8f..3cfcdac27 100644 --- a/roles/Cargo.lock +++ b/roles/Cargo.lock @@ -52,12 +52,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ahash" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" - [[package]] name = "ahash" version = "0.7.8" @@ -316,6 +310,17 @@ version = "4.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" +[[package]] +name = "async-trait" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -437,6 +442,9 @@ name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -594,7 +602,7 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" [[package]] name = "codec_sv2" -version = "1.0.1" +version = "1.1.0" dependencies = [ "binary_sv2", "buffer_sv2", @@ -628,6 +636,46 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "config" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +dependencies = [ + "async-trait", + "convert_case", + "json5", + "lazy_static", + "nom", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml", + "yaml-rust", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + [[package]] name = "const_sv2" version = "1.0.0" @@ -635,6 +683,15 @@ dependencies = [ "secp256k1 0.28.2", ] +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "cpufeatures" version = "0.2.12" @@ -650,6 +707,12 @@ version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + [[package]] name = "crypto-common" version = "0.1.6" @@ -696,6 +759,15 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "env_logger" version = "0.7.1" @@ -800,7 +872,7 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "framing_sv2" -version = "1.0.0" +version = "1.1.0" dependencies = [ "binary_sv2", "buffer_sv2", @@ -995,23 +1067,19 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.7.2" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash 0.3.8", - "autocfg", + "ahash", + "serde", ] [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash 0.7.8", - "serde", -] +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] name = "hashbrown" @@ -1207,7 +1275,9 @@ dependencies = [ "async-recursion 0.3.2", "binary_sv2", "buffer_sv2", + "clap", "codec_sv2", + "config", "error_handling", "framing_sv2", "futures", @@ -1218,7 +1288,6 @@ dependencies = [ "serde", "stratum-common", "tokio", - "toml", "tracing", "tracing-subscriber", ] @@ -1230,7 +1299,9 @@ dependencies = [ "async-channel 1.9.0", "binary_sv2", "buffer_sv2", + "clap", "codec_sv2", + "config", "const_sv2", "error_handling", "hashbrown 0.11.2", @@ -1246,7 +1317,6 @@ dependencies = [ "serde_json", "stratum-common", "tokio", - "toml", "tracing", "tracing-subscriber", ] @@ -1268,9 +1338,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "key-utils" -version = "1.0.0" +version = "1.1.0" dependencies = [ "bs58", "secp256k1 0.28.2", @@ -1298,6 +1379,12 @@ version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -1335,6 +1422,12 @@ version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + [[package]] name = "mining-device" version = "0.1.1" @@ -1366,7 +1459,9 @@ dependencies = [ "async-recursion 0.3.2", "binary_sv2", "buffer_sv2", + "clap", "codec_sv2", + "config", "const_sv2", "futures", "key-utils", @@ -1377,7 +1472,6 @@ dependencies = [ "serde", "stratum-common", "tokio", - "toml", "tracing", "tracing-subscriber", ] @@ -1443,6 +1537,16 @@ dependencies = [ "secp256k1 0.28.2", ] +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1512,6 +1616,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "ordered-multimap" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" +dependencies = [ + "dlv-list", + "hashbrown 0.13.2", +] + [[package]] name = "overload" version = "0.1.1" @@ -1547,6 +1661,57 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.61", +] + +[[package]] +name = "pest_meta" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" +dependencies = [ + "once_cell", + "pest", + "sha2 0.10.8", +] + [[package]] name = "pin-project" version = "1.1.5" @@ -1652,7 +1817,9 @@ dependencies = [ "async-recursion 1.1.1", "binary_sv2", "buffer_sv2", + "clap", "codec_sv2", + "config", "const_sv2", "error_handling", "hex", @@ -1665,7 +1832,6 @@ dependencies = [ "serde", "stratum-common", "tokio", - "toml", "tracing", "tracing-subscriber", ] @@ -1780,7 +1946,7 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "roles_logic_sv2" -version = "1.0.0" +version = "1.1.0" dependencies = [ "binary_sv2", "chacha20poly1305", @@ -1796,6 +1962,18 @@ dependencies = [ "tracing", ] +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64", + "bitflags 2.5.0", + "serde", + "serde_derive", +] + [[package]] name = "rpc_sv2" version = "1.0.0" @@ -1810,6 +1988,16 @@ dependencies = [ "stratum-common", ] +[[package]] +name = "rust-ini" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -1925,6 +2113,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + [[package]] name = "serde_sv2" version = "1.0.0" @@ -2105,6 +2302,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.61", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -2115,6 +2332,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tokio" version = "1.37.0" @@ -2160,11 +2386,36 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.6" -source = "git+https://github.com/diondokter/toml-rs?rev=c4161aa#c4161aa70202b3992dbec79b76e7a8659713b604" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" dependencies = [ - "hashbrown 0.7.2", + "indexmap", "serde", + "serde_spanned", + "toml_datetime", + "winnow", ] [[package]] @@ -2263,7 +2514,9 @@ dependencies = [ "async-std", "binary_sv2", "buffer_sv2", + "clap", "codec_sv2", + "config", "error_handling", "framing_sv2", "futures", @@ -2279,7 +2532,6 @@ dependencies = [ "sv1_api", "tokio", "tokio-util", - "toml", "tracing", "tracing-subscriber", ] @@ -2296,12 +2548,24 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + [[package]] name = "universal-hash" version = "0.5.1" @@ -2603,6 +2867,24 @@ version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +[[package]] +name = "winnow" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +dependencies = [ + "memchr", +] + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "zeroize" version = "1.7.0" diff --git a/roles/jd-client/Cargo.toml b/roles/jd-client/Cargo.toml index 4c79016d0..08e03bcec 100644 --- a/roles/jd-client/Cargo.toml +++ b/roles/jd-client/Cargo.toml @@ -23,9 +23,10 @@ roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-s serde = { version = "1.0.89", default-features = false, features = ["derive", "alloc"] } futures = "0.3.25" tokio = { version = "1", features = ["full"] } -toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" } tracing = { version = "0.1" } tracing-subscriber = { version = "0.3" } error_handling = { version = "1.0.0", path = "../../utils/error-handling" } nohash-hasher = "0.2.0" key-utils = { version = "^1.0.0", path = "../../utils/key-utils" } +clap = { version = "^4.5.4", features = ["derive"] } +config = { version = "0.14.0", features = ["toml"] } \ No newline at end of file diff --git a/roles/jd-client/src/args.rs b/roles/jd-client/src/args.rs index 7802351c3..e06d149f6 100644 --- a/roles/jd-client/src/args.rs +++ b/roles/jd-client/src/args.rs @@ -1,68 +1,29 @@ -use std::path::PathBuf; +use crate::lib::{error::JdcResult, jdc_config::JdcConfig}; -#[derive(Debug)] -pub struct Args { - pub config_path: PathBuf, -} - -enum ArgsState { - Next, - ExpectPath, - Done, -} +use clap::Parser; -enum ArgsResult { - Config(PathBuf), - None, - Help(String), +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(short, long, help = "Path to TOML configuration file")] + config_path: String, } -impl Args { - const DEFAULT_CONFIG_PATH: &'static str = "jdc-config.toml"; - const HELP_MSG: &'static str = "Usage: -h/--help, -c/--config "; - - pub fn from_args() -> Result { - let cli_args = std::env::args(); - - if cli_args.len() == 1 { - println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH); - println!("{}\n", Self::HELP_MSG); +#[allow(clippy::result_large_err)] +pub fn process_cli_args<'a>() -> JdcResult<'a, JdcConfig> { + let args = Args::parse(); + let config = match config::Config::builder() + .add_source(config::File::with_name(&args.config_path)) + .build() + { + Ok(cfg) => cfg, + Err(e) => { + tracing::error!("{:?}", e); + std::process::exit(1) } + }; - let config_path = cli_args - .scan(ArgsState::Next, |state, item| { - match std::mem::replace(state, ArgsState::Done) { - ArgsState::Next => match item.as_str() { - "-c" | "--config" => { - *state = ArgsState::ExpectPath; - Some(ArgsResult::None) - } - "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())), - _ => { - *state = ArgsState::Next; + let jdc_config: JdcConfig = config.try_deserialize()?; - Some(ArgsResult::None) - } - }, - ArgsState::ExpectPath => { - let path = PathBuf::from(item.clone()); - if !path.exists() { - return Some(ArgsResult::Help(format!( - "Error: File '{}' does not exist!", - path.display() - ))); - } - Some(ArgsResult::Config(path)) - } - ArgsState::Done => None, - } - }) - .last(); - let config_path = match config_path { - Some(ArgsResult::Config(p)) => p, - Some(ArgsResult::Help(h)) => return Err(h), - _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH), - }; - Ok(Self { config_path }) - } + Ok(jdc_config) } diff --git a/roles/jd-client/src/lib/error.rs b/roles/jd-client/src/lib/error.rs index 685137457..84ea3c523 100644 --- a/roles/jd-client/src/lib/error.rs +++ b/roles/jd-client/src/lib/error.rs @@ -3,7 +3,7 @@ use std::fmt; use roles_logic_sv2::mining_sv2::{ExtendedExtranonce, NewExtendedMiningJob, SetCustomMiningJob}; use stratum_common::bitcoin::util::uint::ParseLengthError; -pub type ProxyResult<'a, T> = core::result::Result>; +pub type JdcResult<'a, T> = core::result::Result>; #[derive(Debug)] pub enum ChannelSendError<'a> { @@ -26,12 +26,9 @@ pub enum ChannelSendError<'a> { } #[derive(Debug)] -pub enum Error<'a> { +pub enum JdcError<'a> { VecToSlice32(Vec), - /// Errors on bad CLI argument input. - BadCliArgs, - /// Errors on bad `toml` deserialize. - BadTomlDeserialize(toml::de::Error), + ConfigError(config::ConfigError), /// Errors from `binary_sv2` crate. BinarySv2(binary_sv2::Error), /// Errors on bad noise handshake. @@ -58,12 +55,11 @@ pub enum Error<'a> { Infallible(std::convert::Infallible), } -impl<'a> fmt::Display for Error<'a> { +impl<'a> fmt::Display for JdcError<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use Error::*; + use JdcError::*; match self { - BadCliArgs => write!(f, "Bad CLI arg input"), - BadTomlDeserialize(ref e) => write!(f, "Bad `toml` deserialize: `{:?}`", e), + ConfigError(e) => write!(f, "Config error: {:?}", e), BinarySv2(ref e) => write!(f, "Binary SV2 error: `{:?}`", e), CodecNoise(ref e) => write!(f, "Noise error: `{:?}", e), FramingSv2(ref e) => write!(f, "Framing SV2 error: `{:?}`", e), @@ -83,57 +79,57 @@ impl<'a> fmt::Display for Error<'a> { } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { + fn from(e: config::ConfigError) -> JdcError<'a> { + JdcError::ConfigError(e) + } +} + +impl<'a> From for JdcError<'a> { fn from(e: binary_sv2::Error) -> Self { - Error::BinarySv2(e) + JdcError::BinarySv2(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: codec_sv2::noise_sv2::Error) -> Self { - Error::CodecNoise(e) + JdcError::CodecNoise(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: framing_sv2::Error) -> Self { - Error::FramingSv2(e) + JdcError::FramingSv2(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: std::io::Error) -> Self { - Error::Io(e) + JdcError::Io(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: std::num::ParseIntError) -> Self { - Error::ParseInt(e) + JdcError::ParseInt(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: roles_logic_sv2::errors::Error) -> Self { - Error::RolesSv2Logic(e) - } -} - -impl<'a> From for Error<'a> { - fn from(e: toml::de::Error) -> Self { - Error::BadTomlDeserialize(e) + JdcError::RolesSv2Logic(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: async_channel::RecvError) -> Self { - Error::ChannelErrorReceiver(e) + JdcError::ChannelErrorReceiver(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: tokio::sync::broadcast::error::RecvError) -> Self { - Error::TokioChannelErrorRecv(e) + JdcError::TokioChannelErrorRecv(e) } } @@ -156,38 +152,38 @@ impl<'a> From for Error<'a> { // *** CHANNEL SENDER ERRORS *** impl<'a> From>> - for Error<'a> + for JdcError<'a> { fn from( e: async_channel::SendError>, ) -> Self { - Error::ChannelErrorSender(ChannelSendError::SubmitSharesExtended(e)) + JdcError::ChannelErrorSender(ChannelSendError::SubmitSharesExtended(e)) } } impl<'a> From>> - for Error<'a> + for JdcError<'a> { fn from(e: async_channel::SendError>) -> Self { - Error::ChannelErrorSender(ChannelSendError::SetNewPrevHash(e)) + JdcError::ChannelErrorSender(ChannelSendError::SetNewPrevHash(e)) } } -impl<'a> From> for Error<'a> { +impl<'a> From> for JdcError<'a> { fn from(e: async_channel::SendError<(ExtendedExtranonce, u32)>) -> Self { - Error::ChannelErrorSender(ChannelSendError::Extranonce(e)) + JdcError::ChannelErrorSender(ChannelSendError::Extranonce(e)) } } -impl<'a> From>> for Error<'a> { +impl<'a> From>> for JdcError<'a> { fn from(e: async_channel::SendError>) -> Self { - Error::ChannelErrorSender(ChannelSendError::NewExtendedMiningJob(e)) + JdcError::ChannelErrorSender(ChannelSendError::NewExtendedMiningJob(e)) } } -impl<'a> From>> for Error<'a> { +impl<'a> From>> for JdcError<'a> { fn from(e: async_channel::SendError>) -> Self { - Error::ChannelErrorSender(ChannelSendError::SetCustomMiningJob(e)) + JdcError::ChannelErrorSender(ChannelSendError::SetCustomMiningJob(e)) } } @@ -197,7 +193,7 @@ impl<'a> roles_logic_sv2::template_distribution_sv2::SetNewPrevHash<'a>, Vec, )>, - > for Error<'a> + > for JdcError<'a> { fn from( e: async_channel::SendError<( @@ -205,24 +201,24 @@ impl<'a> Vec, )>, ) -> Self { - Error::ChannelErrorSender(ChannelSendError::NewTemplate(e)) + JdcError::ChannelErrorSender(ChannelSendError::NewTemplate(e)) } } -impl<'a> From> for Error<'a> { +impl<'a> From> for JdcError<'a> { fn from(e: Vec) -> Self { - Error::VecToSlice32(e) + JdcError::VecToSlice32(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: ParseLengthError) -> Self { - Error::Uint256Conversion(e) + JdcError::Uint256Conversion(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for JdcError<'a> { fn from(e: std::convert::Infallible) -> Self { - Error::Infallible(e) + JdcError::Infallible(e) } } diff --git a/roles/jd-client/src/lib/proxy_config.rs b/roles/jd-client/src/lib/jdc_config.rs similarity index 97% rename from roles/jd-client/src/lib/proxy_config.rs rename to roles/jd-client/src/lib/jdc_config.rs index 89c97a7be..98be0f243 100644 --- a/roles/jd-client/src/lib/proxy_config.rs +++ b/roles/jd-client/src/lib/jdc_config.rs @@ -25,7 +25,7 @@ impl TryFrom<&CoinbaseOutput> for CoinbaseOutput_ { } #[derive(Debug, Deserialize, Clone)] -pub struct ProxyConfig { +pub struct JdcConfig { pub downstream_address: String, pub downstream_port: u16, pub max_supported_version: u16, @@ -82,7 +82,7 @@ where } } -pub fn get_coinbase_output(config: &ProxyConfig) -> Result, Error> { +pub fn get_coinbase_output(config: &JdcConfig) -> Result, Error> { let mut result = Vec::new(); for coinbase_output_pool in &config.coinbase_outputs { let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?; diff --git a/roles/jd-client/src/lib/job_declarator/mod.rs b/roles/jd-client/src/lib/job_declarator/mod.rs index abaf852ca..bc6fb856b 100644 --- a/roles/jd-client/src/lib/job_declarator/mod.rs +++ b/roles/jd-client/src/lib/job_declarator/mod.rs @@ -37,7 +37,7 @@ pub type StdFrame = StandardSv2Frame; mod setup_connection; use setup_connection::SetupConnectionHandler; -use super::{error::Error, proxy_config::ProxyConfig, upstream_sv2::Upstream}; +use super::{error::JdcError, jdc_config::JdcConfig, upstream_sv2::Upstream}; #[derive(Debug, Clone)] pub struct LastDeclareJob { @@ -80,10 +80,10 @@ impl JobDeclarator { pub async fn new( address: SocketAddr, authority_public_key: [u8; 32], - config: ProxyConfig, + config: JdcConfig, up: Arc>, task_collector: Arc>>, - ) -> Result>, Error<'static>> { + ) -> Result>, JdcError<'static>> { let stream = tokio::net::TcpStream::connect(address).await?; let initiator = Initiator::from_raw_k(authority_public_key)?; let (mut receiver, mut sender, _, _) = diff --git a/roles/jd-client/src/lib/mod.rs b/roles/jd-client/src/lib/mod.rs index 489759420..5828fab6f 100644 --- a/roles/jd-client/src/lib/mod.rs +++ b/roles/jd-client/src/lib/mod.rs @@ -1,7 +1,7 @@ pub mod downstream; pub mod error; +pub mod jdc_config; pub mod job_declarator; -pub mod proxy_config; pub mod status; pub mod template_receiver; pub mod upstream_sv2; diff --git a/roles/jd-client/src/lib/status.rs b/roles/jd-client/src/lib/status.rs index 44e6056d2..f94af5c76 100644 --- a/roles/jd-client/src/lib/status.rs +++ b/roles/jd-client/src/lib/status.rs @@ -1,4 +1,4 @@ -use super::error::{self, Error}; +use super::error::{self, JdcError}; #[derive(Debug)] pub enum Sender { @@ -35,8 +35,8 @@ impl Clone for Sender { #[derive(Debug)] pub enum State<'a> { - DownstreamShutdown(Error<'a>), - UpstreamShutdown(Error<'a>), + DownstreamShutdown(JdcError<'a>), + UpstreamShutdown(JdcError<'a>), UpstreamRogue, Healthy(String), } @@ -48,7 +48,7 @@ pub struct Status<'a> { async fn send_status( sender: &Sender, - e: error::Error<'static>, + e: error::JdcError<'static>, outcome: error_handling::ErrorBranch, ) -> error_handling::ErrorBranch { match sender { @@ -87,51 +87,52 @@ async fn send_status( // this is called by `error_handling::handle_result!` pub async fn handle_error( sender: &Sender, - e: error::Error<'static>, + e: error::JdcError<'static>, ) -> error_handling::ErrorBranch { tracing::error!("Error: {:?}", &e); match e { - Error::VecToSlice32(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, - // Errors on bad CLI argument input. - Error::BadCliArgs => send_status(sender, e, error_handling::ErrorBranch::Break).await, - // Errors on bad `toml` deserialize. - Error::BadTomlDeserialize(_) => { + JdcError::VecToSlice32(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } + JdcError::ConfigError(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } // Errors from `binary_sv2` crate. - Error::BinarySv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + JdcError::BinarySv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Errors on bad noise handshake. - Error::CodecNoise(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + JdcError::CodecNoise(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Errors from `framing_sv2` crate. - Error::FramingSv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + JdcError::FramingSv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Errors on bad `TcpStream` connection. - Error::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + JdcError::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Errors on bad `String` to `int` conversion. - Error::ParseInt(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + JdcError::ParseInt(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Errors from `roles_logic_sv2` crate. - Error::RolesSv2Logic(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, - Error::UpstreamIncoming(_) => { + JdcError::RolesSv2Logic(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } + JdcError::UpstreamIncoming(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } - Error::SubprotocolMining(_) => { + JdcError::SubprotocolMining(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } // Locking Errors - Error::PoisonLock => send_status(sender, e, error_handling::ErrorBranch::Break).await, + JdcError::PoisonLock => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Channel Receiver Error - Error::ChannelErrorReceiver(_) => { + JdcError::ChannelErrorReceiver(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } - Error::TokioChannelErrorRecv(_) => { + JdcError::TokioChannelErrorRecv(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } // Channel Sender Errors - Error::ChannelErrorSender(_) => { + JdcError::ChannelErrorSender(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } - Error::Uint256Conversion(_) => { + JdcError::Uint256Conversion(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } - Error::Infallible(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + JdcError::Infallible(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, } } diff --git a/roles/jd-client/src/lib/upstream_sv2/upstream.rs b/roles/jd-client/src/lib/upstream_sv2/upstream.rs index 857cbd308..dd471b785 100644 --- a/roles/jd-client/src/lib/upstream_sv2/upstream.rs +++ b/roles/jd-client/src/lib/upstream_sv2/upstream.rs @@ -2,8 +2,8 @@ use super::super::downstream::DownstreamMiningNode as Downstream; use super::super::{ error::{ - Error::{CodecNoise, PoisonLock, UpstreamIncoming}, - ProxyResult, + JdcError::{CodecNoise, PoisonLock, UpstreamIncoming}, + JdcResult, }, status, upstream_sv2::{EitherFrame, Message, StdFrame}, @@ -127,13 +127,13 @@ pub struct Upstream { } impl Upstream { - pub async fn send(self_: &Arc>, sv2_frame: StdFrame) -> ProxyResult<'static, ()> { + pub async fn send(self_: &Arc>, sv2_frame: StdFrame) -> JdcResult<'static, ()> { let sender = self_ .safe_lock(|s| s.sender.clone()) .map_err(|_| PoisonLock)?; let either_frame = sv2_frame.into(); sender.send(either_frame).await.map_err(|e| { - super::super::error::Error::ChannelErrorSender( + super::super::error::JdcError::ChannelErrorSender( super::super::error::ChannelSendError::General(e.to_string()), ) })?; @@ -153,7 +153,7 @@ impl Upstream { tx_status: status::Sender, task_collector: Arc>>, pool_chaneger_trigger: Arc>, - ) -> ProxyResult<'static, Arc>> { + ) -> JdcResult<'static, Arc>> { // Connect to the SV2 Upstream role retry connection every 5 seconds. let socket = loop { match TcpStream::connect(address).await { @@ -204,7 +204,7 @@ impl Upstream { self_: Arc>, min_version: u16, max_version: u16, - ) -> ProxyResult<'static, ()> { + ) -> JdcResult<'static, ()> { // Get the `SetupConnection` message with Mining Device information (currently hard coded) let setup_connection = Self::get_setup_connection_message(min_version, max_version, true)?; @@ -264,7 +264,7 @@ impl Upstream { coinbase_tx_outs: Vec, coinbase_tx_locktime: u32, template_id: u64, - ) -> ProxyResult<'static, ()> { + ) -> JdcResult<'static, ()> { info!("Sending set custom mining job"); let request_id = self_.safe_lock(|s| s.req_ids.next()).unwrap(); let channel_id = loop { @@ -310,7 +310,7 @@ impl Upstream { /// Parses the incoming SV2 message from the Upstream role and routes the message to the /// appropriate handler. #[allow(clippy::result_large_err)] - pub fn parse_incoming(self_: Arc>) -> ProxyResult<'static, ()> { + pub fn parse_incoming(self_: Arc>) -> JdcResult<'static, ()> { let (recv, tx_status) = self_ .safe_lock(|s| (s.receiver.clone(), s.tx_status.clone())) .map_err(|_| PoisonLock)?; @@ -327,7 +327,7 @@ impl Upstream { let message_type = incoming .get_header() - .ok_or(super::super::error::Error::FramingSv2( + .ok_or(super::super::error::JdcError::FramingSv2( framing_sv2::Error::ExpectedSv2Frame, )); @@ -404,7 +404,7 @@ impl Upstream { min_version: u16, max_version: u16, is_work_selection_enabled: bool, - ) -> ProxyResult<'static, SetupConnection<'static>> { + ) -> JdcResult<'static, SetupConnection<'static>> { let endpoint_host = "0.0.0.0".to_string().into_bytes().try_into()?; let vendor = String::new().try_into()?; let hardware_version = String::new().try_into()?; diff --git a/roles/jd-client/src/main.rs b/roles/jd-client/src/main.rs index ac246987e..b21788666 100644 --- a/roles/jd-client/src/main.rs +++ b/roles/jd-client/src/main.rs @@ -4,15 +4,9 @@ mod args; mod lib; use lib::{ - error::{Error, ProxyResult}, - job_declarator::JobDeclarator, - proxy_config::ProxyConfig, - status, - template_receiver::TemplateRx, - PoolChangerTrigger, + job_declarator::JobDeclarator, status, template_receiver::TemplateRx, PoolChangerTrigger, }; -use args::Args; use async_channel::{bounded, unbounded}; use futures::{select, FutureExt}; use roles_logic_sv2::utils::Mutex; @@ -26,20 +20,6 @@ use tokio::task::AbortHandle; use tracing::{error, info}; -/// Process CLI args, if any. -#[allow(clippy::result_large_err)] -fn process_cli_args<'a>() -> ProxyResult<'a, ProxyConfig> { - let args = match Args::from_args() { - Ok(cfg) => cfg, - Err(help) => { - error!("{}", help); - return Err(Error::BadCliArgs); - } - }; - let config_file = std::fs::read_to_string(args.config_path)?; - Ok(toml::from_str::(&config_file)?) -} - /// TODO on the setup phase JDC must send a random nonce to bitcoind and JDS used for the tx /// hashlist /// @@ -105,7 +85,7 @@ async fn main() { let task_collector = Arc::new(Mutex::new(vec![])); - let proxy_config = match process_cli_args() { + let jdc_config = match args::process_cli_args() { Ok(p) => p, Err(_) => return, }; @@ -115,19 +95,19 @@ async fn main() { let task_collector = task_collector.clone(); let tx_status = tx_status.clone(); - if let Some(upstream) = proxy_config.upstreams.get(upstream_index) { + if let Some(upstream) = jdc_config.upstreams.get(upstream_index) { let initialize = initialize_jd( tx_status.clone(), task_collector, upstream.clone(), - proxy_config.timeout, + jdc_config.timeout, ); tokio::task::spawn(initialize); } else { let initialize = initialize_jd_as_solo_miner( tx_status.clone(), task_collector, - proxy_config.timeout, + jdc_config.timeout, ); tokio::task::spawn(initialize); } @@ -205,8 +185,8 @@ async fn initialize_jd_as_solo_miner( task_collector: Arc>>, timeout: Duration, ) { - let proxy_config = process_cli_args().unwrap(); - let miner_tx_out = lib::proxy_config::get_coinbase_output(&proxy_config).unwrap(); + let proxy_config = args::process_cli_args().unwrap(); + let miner_tx_out = lib::jdc_config::get_coinbase_output(&proxy_config).unwrap(); // When Downstream receive a share that meets bitcoin target it transformit in a // SubmitSolution and send it to the TemplateReceiver @@ -258,11 +238,11 @@ async fn initialize_jd_as_solo_miner( async fn initialize_jd( tx_status: async_channel::Sender>, task_collector: Arc>>, - upstream_config: lib::proxy_config::Upstream, + upstream_config: lib::jdc_config::Upstream, timeout: Duration, ) { - let proxy_config = process_cli_args().unwrap(); - let test_only_do_not_send_solution_to_tp = proxy_config + let jdc_config = args::process_cli_args().unwrap(); + let test_only_do_not_send_solution_to_tp = jdc_config .test_only_do_not_send_solution_to_tp .unwrap_or(false); @@ -312,8 +292,8 @@ async fn initialize_jd( match lib::upstream_sv2::Upstream::setup_connection( upstream.clone(), - proxy_config.min_supported_version, - proxy_config.max_supported_version, + jdc_config.min_supported_version, + jdc_config.max_supported_version, ) .await { @@ -326,12 +306,12 @@ async fn initialize_jd( // Format `Downstream` connection address let downstream_addr = SocketAddr::new( - IpAddr::from_str(&proxy_config.downstream_address).unwrap(), - proxy_config.downstream_port, + IpAddr::from_str(&jdc_config.downstream_address).unwrap(), + jdc_config.downstream_port, ); // Initialize JD part - let mut parts = proxy_config.tp_address.split(':'); + let mut parts = jdc_config.tp_address.split(':'); let ip_tp = parts.next().unwrap().to_string(); let port_tp = parts.next().unwrap().parse::().unwrap(); @@ -341,7 +321,7 @@ async fn initialize_jd( let jd = match JobDeclarator::new( SocketAddr::new(IpAddr::from_str(ip_jd.as_str()).unwrap(), port_jd), upstream_config.authority_pubkey.into_bytes(), - proxy_config.clone(), + jdc_config.clone(), upstream.clone(), task_collector.clone(), ) @@ -363,10 +343,10 @@ async fn initialize_jd( downstream_addr, Some(upstream), send_solution, - proxy_config.withhold, - proxy_config.authority_public_key, - proxy_config.authority_secret_key, - proxy_config.cert_validity_sec, + jdc_config.withhold, + jdc_config.authority_public_key, + jdc_config.authority_secret_key, + jdc_config.cert_validity_sec, task_collector.clone(), status::Sender::Downstream(tx_status.clone()), vec![], @@ -384,7 +364,7 @@ async fn initialize_jd( task_collector, Arc::new(Mutex::new(PoolChangerTrigger::new(timeout))), vec![], - proxy_config.tp_authority_public_key, + jdc_config.tp_authority_public_key, test_only_do_not_send_solution_to_tp, ) .await; diff --git a/roles/jd-server/Cargo.toml b/roles/jd-server/Cargo.toml index 6f55ece06..6d344cc9d 100644 --- a/roles/jd-server/Cargo.toml +++ b/roles/jd-server/Cargo.toml @@ -21,7 +21,6 @@ noise_sv2 = { version = "1.1.0", path = "../../protocols/v2/noise-sv2" } rand = "0.8.4" roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" } tokio = { version = "1", features = ["full"] } -toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" } tracing = { version = "0.1" } tracing-subscriber = "0.3" error_handling = { version = "1.0.0", path = "../../utils/error-handling" } @@ -32,3 +31,5 @@ hashbrown = { version = "0.11", default-features = false, features = ["ahash", " key-utils = { version = "^1.0.0", path = "../../utils/key-utils" } rpc_sv2 = { version = "1.0.0", path = "../roles-utils/rpc" } hex = "0.4.3" +clap = { version = "^4.5.4", features = ["derive"] } +config = { version = "0.14.0", features = ["toml"] } \ No newline at end of file diff --git a/roles/jd-server/src/args.rs b/roles/jd-server/src/args.rs new file mode 100644 index 000000000..b7bc68bfe --- /dev/null +++ b/roles/jd-server/src/args.rs @@ -0,0 +1,28 @@ +use crate::lib::{error::JdsResult, jds_config::JdsConfig}; +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(short, long, help = "Path to TOML configuration file")] + config_path: String, +} + +#[allow(clippy::result_large_err)] +pub fn process_cli_args() -> JdsResult { + let args = Args::parse(); + let config = match config::Config::builder() + .add_source(config::File::with_name(&args.config_path)) + .build() + { + Ok(cfg) => cfg, + Err(e) => { + tracing::error!("{:?}", e); + std::process::exit(1) + } + }; + + let jds_config: JdsConfig = config.try_deserialize()?; + + Ok(jds_config) +} diff --git a/roles/jd-server/src/lib/error.rs b/roles/jd-server/src/lib/error.rs index 7b58c7593..265807def 100644 --- a/roles/jd-server/src/lib/error.rs +++ b/roles/jd-server/src/lib/error.rs @@ -8,8 +8,11 @@ use roles_logic_sv2::parsers::Mining; use crate::mempool::error::JdsMempoolError; +pub type JdsResult = core::result::Result; + #[derive(std::fmt::Debug)] pub enum JdsError { + ConfigError(config::ConfigError), Io(std::io::Error), ChannelSend(Box), ChannelRecv(async_channel::RecvError), @@ -30,6 +33,7 @@ impl std::fmt::Display for JdsError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use JdsError::*; match self { + ConfigError(e) => write!(f, "Config error: {:?}", e), Io(ref e) => write!(f, "I/O error: `{:?}", e), ChannelSend(ref e) => write!(f, "Channel send failed: `{:?}`", e), ChannelRecv(ref e) => write!(f, "Channel recv failed: `{:?}`", e), @@ -52,6 +56,12 @@ impl std::fmt::Display for JdsError { } } +impl From for JdsError { + fn from(e: config::ConfigError) -> JdsError { + JdsError::ConfigError(e) + } +} + impl From for JdsError { fn from(e: std::io::Error) -> JdsError { JdsError::Io(e) diff --git a/roles/jd-server/src/lib/jds_config.rs b/roles/jd-server/src/lib/jds_config.rs new file mode 100644 index 000000000..f2adb9b0b --- /dev/null +++ b/roles/jd-server/src/lib/jds_config.rs @@ -0,0 +1,88 @@ +use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}; +use roles_logic_sv2::{errors::Error, utils::CoinbaseOutput as CoinbaseOutput_}; +use serde::Deserialize; +use std::{ + convert::{TryFrom, TryInto}, + time::Duration, +}; +use stratum_common::bitcoin::{Script, TxOut}; + +pub fn get_coinbase_output(config: &JdsConfig) -> Result, Error> { + let mut result = Vec::new(); + for coinbase_output_pool in &config.coinbase_outputs { + let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?; + let output_script: Script = coinbase_output.try_into()?; + result.push(TxOut { + value: 0, + script_pubkey: output_script, + }); + } + match result.is_empty() { + true => Err(Error::EmptyCoinbaseOutputs), + _ => Ok(result), + } +} + +impl TryFrom<&CoinbaseOutput> for CoinbaseOutput_ { + type Error = Error; + + fn try_from(pool_output: &CoinbaseOutput) -> Result { + match pool_output.output_script_type.as_str() { + "P2PK" | "P2PKH" | "P2WPKH" | "P2SH" | "P2WSH" | "P2TR" => Ok(CoinbaseOutput_ { + output_script_type: pool_output.clone().output_script_type, + output_script_value: pool_output.clone().output_script_value, + }), + _ => Err(Error::UnknownOutputScriptType), + } + } +} + +#[derive(Debug, Deserialize, Clone)] +pub struct CoinbaseOutput { + output_script_type: String, + output_script_value: String, +} + +#[derive(Debug, Deserialize, Clone)] +pub struct JdsConfig { + pub listen_jd_address: String, + pub authority_public_key: Secp256k1PublicKey, + pub authority_secret_key: Secp256k1SecretKey, + pub cert_validity_sec: u64, + pub coinbase_outputs: Vec, + pub core_rpc_url: String, + pub core_rpc_port: u16, + pub core_rpc_user: String, + pub core_rpc_pass: String, + #[serde(deserialize_with = "duration_from_toml")] + pub mempool_update_interval: Duration, +} + +fn duration_from_toml<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + #[derive(Deserialize)] + struct Helper { + unit: String, + value: u64, + } + + let helper = Helper::deserialize(deserializer)?; + match helper.unit.as_str() { + "seconds" => Ok(Duration::from_secs(helper.value)), + "secs" => Ok(Duration::from_secs(helper.value)), + "s" => Ok(Duration::from_secs(helper.value)), + "milliseconds" => Ok(Duration::from_millis(helper.value)), + "millis" => Ok(Duration::from_millis(helper.value)), + "ms" => Ok(Duration::from_millis(helper.value)), + "microseconds" => Ok(Duration::from_micros(helper.value)), + "micros" => Ok(Duration::from_micros(helper.value)), + "us" => Ok(Duration::from_micros(helper.value)), + "nanoseconds" => Ok(Duration::from_nanos(helper.value)), + "nanos" => Ok(Duration::from_nanos(helper.value)), + "ns" => Ok(Duration::from_nanos(helper.value)), + // ... add other units as needed + _ => Err(serde::de::Error::custom("Unsupported duration unit")), + } +} diff --git a/roles/jd-server/src/lib/job_declarator/mod.rs b/roles/jd-server/src/lib/job_declarator/mod.rs index 56d56223c..c56a1c111 100644 --- a/roles/jd-server/src/lib/job_declarator/mod.rs +++ b/roles/jd-server/src/lib/job_declarator/mod.rs @@ -1,5 +1,7 @@ pub mod message_handler; -use super::{error::JdsError, mempool::JDsMempool, status, Configuration, EitherFrame, StdFrame}; +use super::{ + error::JdsError, jds_config::JdsConfig, mempool::JDsMempool, status, EitherFrame, StdFrame, +}; use async_channel::{Receiver, Sender}; use binary_sv2::{B0255, U256}; use codec_sv2::{Frame, HandshakeRole, Responder}; @@ -69,7 +71,7 @@ impl JobDeclaratorDownstream { pub fn new( receiver: Receiver, sender: Sender, - config: &Configuration, + config: &JdsConfig, mempool: Arc>, sender_add_txs_to_mempool: Sender, ) -> Self { @@ -81,9 +83,10 @@ impl JobDeclaratorDownstream { known_transactions: vec![], unknown_transactions: vec![], }; - super::get_coinbase_output(config).expect("Invalid coinbase output in config")[0] - .consensus_encode(&mut coinbase_output) - .expect("Invalid coinbase output in config"); + super::jds_config::get_coinbase_output(config).expect("Invalid coinbase output in config") + [0] + .consensus_encode(&mut coinbase_output) + .expect("Invalid coinbase output in config"); Self { receiver, @@ -411,7 +414,7 @@ pub struct JobDeclarator {} impl JobDeclarator { pub async fn start( - config: Configuration, + config: JdsConfig, status_tx: crate::status::Sender, mempool: Arc>, new_block_sender: Sender, @@ -431,7 +434,7 @@ impl JobDeclarator { } async fn accept_incoming_connection( _self_: Arc>, - config: Configuration, + config: JdsConfig, status_tx: crate::status::Sender, mempool: Arc>, new_block_sender: Sender, diff --git a/roles/jd-server/src/lib/mod.rs b/roles/jd-server/src/lib/mod.rs index a76c80cf1..a679195fe 100644 --- a/roles/jd-server/src/lib/mod.rs +++ b/roles/jd-server/src/lib/mod.rs @@ -1,4 +1,5 @@ pub mod error; +pub mod jds_config; pub mod job_declarator; pub mod mempool; pub mod status; @@ -9,32 +10,12 @@ use roles_logic_sv2::{ errors::Error, parsers::PoolMessages as JdsMessages, utils::CoinbaseOutput as CoinbaseOutput_, }; use serde::Deserialize; -use std::{ - convert::{TryFrom, TryInto}, - time::Duration, -}; -use stratum_common::bitcoin::{Script, TxOut}; +use std::{convert::TryFrom, time::Duration}; pub type Message = JdsMessages<'static>; pub type StdFrame = StandardSv2Frame; pub type EitherFrame = StandardEitherFrame; -pub fn get_coinbase_output(config: &Configuration) -> Result, Error> { - let mut result = Vec::new(); - for coinbase_output_pool in &config.coinbase_outputs { - let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?; - let output_script: Script = coinbase_output.try_into()?; - result.push(TxOut { - value: 0, - script_pubkey: output_script, - }); - } - match result.is_empty() { - true => Err(Error::EmptyCoinbaseOutputs), - _ => Ok(result), - } -} - impl TryFrom<&CoinbaseOutput> for CoinbaseOutput_ { type Error = Error; diff --git a/roles/jd-server/src/lib/status.rs b/roles/jd-server/src/lib/status.rs index 83a50026f..e76d7bbcd 100644 --- a/roles/jd-server/src/lib/status.rs +++ b/roles/jd-server/src/lib/status.rs @@ -98,6 +98,9 @@ async fn send_status( pub async fn handle_error(sender: &Sender, e: JdsError) -> error_handling::ErrorBranch { tracing::debug!("Error: {:?}", &e); match e { + JdsError::ConfigError(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } JdsError::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, JdsError::ChannelSend(_) => { //This should be a continue because if we fail to send to 1 downstream we should continue diff --git a/roles/jd-server/src/main.rs b/roles/jd-server/src/main.rs index 9d56b491f..f22874c7d 100644 --- a/roles/jd-server/src/main.rs +++ b/roles/jd-server/src/main.rs @@ -1,7 +1,7 @@ #![allow(special_module_name)] use crate::lib::{ mempool::{self, error::JdsMempoolError}, - status, Configuration, + status, }; use async_channel::{bounded, unbounded, Receiver, Sender}; use error_handling::handle_result; @@ -9,102 +9,22 @@ use roles_logic_sv2::utils::Mutex; use std::{ops::Sub, sync::Arc}; use tokio::{select, task}; use tracing::{error, info, warn}; +mod args; mod lib; use lib::job_declarator::JobDeclarator; -mod args { - use std::path::PathBuf; - - #[derive(Debug)] - pub struct Args { - pub config_path: PathBuf, - } - - enum ArgsState { - Next, - ExpectPath, - Done, - } - - enum ArgsResult { - Config(PathBuf), - None, - Help(String), - } - - impl Args { - const DEFAULT_CONFIG_PATH: &'static str = "jds-config.toml"; - const HELP_MSG: &'static str = - "Usage: -h/--help, -c/--config "; - - pub fn from_args() -> Result { - let cli_args = std::env::args(); - - if cli_args.len() == 1 { - println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH); - println!("{}\n", Self::HELP_MSG); - } - - let config_path = cli_args - .scan(ArgsState::Next, |state, item| { - match std::mem::replace(state, ArgsState::Done) { - ArgsState::Next => match item.as_str() { - "-c" | "--config" => { - *state = ArgsState::ExpectPath; - Some(ArgsResult::None) - } - "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())), - _ => { - *state = ArgsState::Next; - - Some(ArgsResult::None) - } - }, - ArgsState::ExpectPath => Some(ArgsResult::Config(PathBuf::from(item))), - ArgsState::Done => None, - } - }) - .last(); - let config_path = match config_path { - Some(ArgsResult::Config(p)) => p, - Some(ArgsResult::Help(h)) => return Err(h), - _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH), - }; - Ok(Self { config_path }) - } - } -} - #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); - let args = match args::Args::from_args() { - Ok(cfg) => cfg, - Err(help) => { - error!("{}", help); - return; - } - }; - - // Load config - let config: Configuration = match std::fs::read_to_string(&args.config_path) { - Ok(c) => match toml::from_str(&c) { - Ok(c) => c, - Err(e) => { - error!("Failed to parse config: {}", e); - return; - } - }, - Err(e) => { - error!("Failed to read config: {}", e); - return; - } + let jds_config = match args::process_cli_args() { + Ok(p) => p, + Err(_) => return, }; - let url = config.core_rpc_url.clone() + ":" + &config.core_rpc_port.clone().to_string(); - let username = config.core_rpc_user.clone(); - let password = config.core_rpc_pass.clone(); + let url = jds_config.core_rpc_url.clone() + ":" + &jds_config.core_rpc_port.clone().to_string(); + let username = jds_config.core_rpc_user.clone(); + let password = jds_config.core_rpc_pass.clone(); // TODO should we manage what to do when the limit is reaced? let (new_block_sender, new_block_receiver): (Sender, Receiver) = bounded(10); let mempool = Arc::new(Mutex::new(mempool::JDsMempool::new( @@ -113,7 +33,7 @@ async fn main() { password, new_block_receiver, ))); - let mempool_update_interval = config.mempool_update_interval; + let mempool_update_interval = jds_config.mempool_update_interval; let mempool_cloned_ = mempool.clone(); let (status_tx, status_rx) = unbounded(); let sender = status::Sender::Downstream(status_tx.clone()); @@ -183,9 +103,9 @@ async fn main() { }); }; - info!("Jds INITIALIZING with config: {:?}", &args.config_path); + info!("Jds INITIALIZING"); - let cloned = config.clone(); + let cloned = jds_config.clone(); let mempool_cloned = mempool.clone(); let (sender_add_txs_to_mempool, receiver_add_txs_to_mempool) = unbounded(); task::spawn(async move { diff --git a/roles/mining-proxy/Cargo.toml b/roles/mining-proxy/Cargo.toml index 951645fde..c966b8918 100644 --- a/roles/mining-proxy/Cargo.toml +++ b/roles/mining-proxy/Cargo.toml @@ -25,8 +25,9 @@ once_cell = "1.12.0" roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" } serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false } tokio = { version = "1", features = ["full"] } -toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" } tracing = {version = "0.1"} tracing-subscriber = {version = "0.3"} nohash-hasher = "0.2.0" key-utils = { version = "^1.0.0", path = "../../utils/key-utils" } +clap = { version = "^4.5.4", features = ["derive"] } +config = { version = "0.14.0", features = ["toml"] } \ No newline at end of file diff --git a/roles/mining-proxy/src/args.rs b/roles/mining-proxy/src/args.rs new file mode 100644 index 000000000..96208ee43 --- /dev/null +++ b/roles/mining-proxy/src/args.rs @@ -0,0 +1,28 @@ +use crate::lib::{error::ProxyResult, proxy_config::ProxyConfig}; +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(short, long, help = "Path to TOML configuration file")] + config_path: String, +} + +#[allow(clippy::result_large_err)] +pub fn process_cli_args() -> ProxyResult { + let args = Args::parse(); + let config = match config::Config::builder() + .add_source(config::File::with_name(&args.config_path)) + .build() + { + Ok(cfg) => cfg, + Err(e) => { + tracing::error!("{:?}", e); + std::process::exit(1) + } + }; + + let proxy_config: ProxyConfig = config.try_deserialize()?; + + Ok(proxy_config) +} diff --git a/roles/mining-proxy/src/lib/error.rs b/roles/mining-proxy/src/lib/error.rs index b5c900bfd..8df5a6b7b 100644 --- a/roles/mining-proxy/src/lib/error.rs +++ b/roles/mining-proxy/src/lib/error.rs @@ -6,17 +6,33 @@ use std::net::SocketAddr; pub type Message = PoolMessages<'static>; pub type EitherFrame = StandardEitherFrame; +pub type ProxyResult = core::result::Result; + #[derive(Debug)] #[allow(clippy::large_enum_variant)] #[allow(clippy::enum_variant_names)] -pub enum Error { +pub enum ProxyError { + ConfigError(config::ConfigError), + Io(std::io::Error), SendError(SendError), UpstreamNotAvailabe(SocketAddr), SetupConnectionError(String), } -impl From> for Error { +impl From for ProxyError { + fn from(e: config::ConfigError) -> ProxyError { + ProxyError::ConfigError(e) + } +} + +impl From for ProxyError { + fn from(e: std::io::Error) -> ProxyError { + ProxyError::Io(e) + } +} + +impl From> for ProxyError { fn from(error: SendError) -> Self { - Error::SendError(error) + ProxyError::SendError(error) } } diff --git a/roles/mining-proxy/src/lib/mod.rs b/roles/mining-proxy/src/lib/mod.rs index b9a9fd2f8..227244a62 100644 --- a/roles/mining-proxy/src/lib/mod.rs +++ b/roles/mining-proxy/src/lib/mod.rs @@ -1,5 +1,6 @@ pub mod downstream_mining; pub mod error; +pub mod proxy_config; pub mod upstream_mining; use once_cell::sync::OnceCell; @@ -96,21 +97,10 @@ pub enum ChannelKind { Extended, } -#[derive(Debug, Deserialize, Clone)] -pub struct Config { - pub upstreams: Vec, - pub listen_address: String, - pub listen_mining_port: u16, - pub max_supported_version: u16, - pub min_supported_version: u16, - downstream_share_per_minute: f32, - expected_total_downstream_hr: f32, - reconnect: bool, -} pub async fn initialize_r_logic( upstreams: &[UpstreamMiningValues], group_id: Arc>, - config: Config, + config: proxy_config::ProxyConfig, ) -> RLogic { let channel_ids = Arc::new(Mutex::new(Id::new())); let mut upstream_mining_nodes = Vec::with_capacity(upstreams.len()); diff --git a/roles/mining-proxy/src/lib/proxy_config.rs b/roles/mining-proxy/src/lib/proxy_config.rs new file mode 100644 index 000000000..db063a3e2 --- /dev/null +++ b/roles/mining-proxy/src/lib/proxy_config.rs @@ -0,0 +1,14 @@ +use super::UpstreamMiningValues; +use serde::Deserialize; + +#[derive(Debug, Deserialize, Clone)] +pub struct ProxyConfig { + pub upstreams: Vec, + pub listen_address: String, + pub listen_mining_port: u16, + pub max_supported_version: u16, + pub min_supported_version: u16, + pub downstream_share_per_minute: f32, + pub expected_total_downstream_hr: f32, + pub reconnect: bool, +} diff --git a/roles/mining-proxy/src/lib/upstream_mining.rs b/roles/mining-proxy/src/lib/upstream_mining.rs index 61a5d0f31..48aec9285 100644 --- a/roles/mining-proxy/src/lib/upstream_mining.rs +++ b/roles/mining-proxy/src/lib/upstream_mining.rs @@ -274,7 +274,7 @@ impl UpstreamMiningNode { pub async fn send( self_mutex: Arc>, sv2_frame: StdFrame, - ) -> Result<(), super::error::Error> { + ) -> Result<(), super::error::ProxyError> { let (has_sv2_connection, mut connection, address) = self_mutex .safe_lock(|self_| { ( @@ -333,7 +333,7 @@ impl UpstreamMiningNode { } } - async fn receive(self_mutex: Arc>) -> Result { + async fn receive(self_mutex: Arc>) -> Result { let mut connection = self_mutex .safe_lock(|self_| self_.connection.clone()) .unwrap(); @@ -343,7 +343,7 @@ impl UpstreamMiningNode { Err(_) => { let address = self_mutex.safe_lock(|s| s.address).unwrap(); error!("Upstream node {} is not available", address); - Err(super::error::Error::UpstreamNotAvailabe(address)) + Err(super::error::ProxyError::UpstreamNotAvailabe(address)) } }, None => { @@ -353,7 +353,7 @@ impl UpstreamMiningNode { } } - async fn connect(self_mutex: Arc>) -> Result<(), super::error::Error> { + async fn connect(self_mutex: Arc>) -> Result<(), super::error::ProxyError> { let has_connection = self_mutex .safe_lock(|self_| self_.connection.is_some()) .unwrap(); @@ -365,7 +365,7 @@ impl UpstreamMiningNode { .unwrap(); let socket = TcpStream::connect(address).await.map_err(|_| { error!("Upstream node {} is not available", address); - super::error::Error::UpstreamNotAvailabe(address) + super::error::ProxyError::UpstreamNotAvailabe(address) })?; info!( "Connected to upstream node {}: now handling noise handshake", @@ -597,7 +597,7 @@ impl UpstreamMiningNode { flags: Option, min_version: u16, max_version: u16, - ) -> Result<(), super::error::Error> { + ) -> Result<(), super::error::ProxyError> { let flags = flags.unwrap_or(0b0000_0000_0000_0000_0000_0000_0000_0110); let (frame, downstream_hr) = self_mutex .safe_lock(|self_| { @@ -650,7 +650,9 @@ impl UpstreamMiningNode { let error_message = std::str::from_utf8(m.error_code.inner_as_ref()) .unwrap() .to_string(); - Err(super::error::Error::SetupConnectionError(error_message)) + Err(super::error::ProxyError::SetupConnectionError( + error_message, + )) } } Ok(_) => todo!(), diff --git a/roles/mining-proxy/src/main.rs b/roles/mining-proxy/src/main.rs index 0725c189b..778a288d0 100644 --- a/roles/mining-proxy/src/main.rs +++ b/roles/mining-proxy/src/main.rs @@ -18,75 +18,12 @@ //! A Downstream that signal the incapacity to handle group channels can open only one channel. //! #![allow(special_module_name)] +mod args; mod lib; -use lib::Config; use roles_logic_sv2::utils::{GroupId, Mutex}; use std::{net::SocketAddr, sync::Arc}; -use tracing::{error, info}; - -mod args { - use std::path::PathBuf; - - #[derive(Debug)] - pub struct Args { - pub config_path: PathBuf, - } - - enum ArgsState { - Next, - ExpectPath, - Done, - } - - enum ArgsResult { - Config(PathBuf), - None, - Help(String), - } - - impl Args { - const DEFAULT_CONFIG_PATH: &'static str = "proxy-config.toml"; - const HELP_MSG: &'static str = - "Usage: -h/--help, -c/--config "; - - pub fn from_args() -> Result { - let cli_args = std::env::args(); - - if cli_args.len() == 1 { - println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH); - println!("{}\n", Self::HELP_MSG); - } - - let config_path = cli_args - .scan(ArgsState::Next, |state, item| { - match std::mem::replace(state, ArgsState::Done) { - ArgsState::Next => match item.as_str() { - "-c" | "--config" => { - *state = ArgsState::ExpectPath; - Some(ArgsResult::None) - } - "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())), - _ => { - *state = ArgsState::Next; - - Some(ArgsResult::None) - } - }, - ArgsState::ExpectPath => Some(ArgsResult::Config(PathBuf::from(item))), - ArgsState::Done => None, - } - }) - .last(); - let config_path = match config_path { - Some(ArgsResult::Config(p)) => p, - Some(ArgsResult::Help(h)) => return Err(h), - _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH), - }; - Ok(Self { config_path }) - } - } -} +use tracing::info; /// 1. the proxy scan all the upstreams and map them /// 2. donwstream open a connetcion with proxy @@ -101,39 +38,29 @@ mod args { #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); - let args = match args::Args::from_args() { - Ok(cfg) => cfg, - Err(help) => { - error!("{}", help); - return; - } - }; - - // Scan all the upstreams and map them - let config_file = std::fs::read_to_string(args.config_path.clone()) - .unwrap_or_else(|_| panic!("Can not open {:?}", args.config_path)); - let config = match toml::from_str::(&config_file) { - Ok(cfg) => cfg, - Err(e) => { - error!("Failed to parse config file: {}", e); - return; - } + let proxy_config = match args::process_cli_args() { + Ok(p) => p, + Err(_) => return, }; let group_id = Arc::new(Mutex::new(GroupId::new())); lib::ROUTING_LOGIC .set(Mutex::new( - lib::initialize_r_logic(&config.upstreams, group_id, config.clone()).await, + lib::initialize_r_logic(&proxy_config.upstreams, group_id, proxy_config.clone()).await, )) .expect("BUG: Failed to set ROUTING_LOGIC"); info!("PROXY INITIALIZING"); - lib::initialize_upstreams(config.min_supported_version, config.max_supported_version).await; + lib::initialize_upstreams( + proxy_config.min_supported_version, + proxy_config.max_supported_version, + ) + .await; info!("PROXY INITIALIZED"); // Wait for downstream connection let socket = SocketAddr::new( - config.listen_address.parse().unwrap(), - config.listen_mining_port, + proxy_config.listen_address.parse().unwrap(), + proxy_config.listen_mining_port, ); info!("PROXY INITIALIZED"); diff --git a/roles/pool/Cargo.toml b/roles/pool/Cargo.toml index 3b62c74e1..6ebe5219d 100644 --- a/roles/pool/Cargo.toml +++ b/roles/pool/Cargo.toml @@ -23,13 +23,14 @@ rand = "0.8.4" roles_logic_sv2 = { version = "^1.0.0", path = "../../protocols/v2/roles-logic-sv2" } serde = { version = "1.0.89", features = ["derive", "alloc"], default-features = false } tokio = { version = "1", features = ["full"] } -toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" } tracing = { version = "0.1" } tracing-subscriber = "0.3" async-recursion = "1.0.0" error_handling = { version = "1.0.0", path = "../../utils/error-handling" } nohash-hasher = "0.2.0" key-utils = { version = "^1.0.0", path = "../../utils/key-utils" } +clap = { version = "^4.5.4", features = ["derive"] } +config = { version = "0.14.0", features = ["toml"] } [dev-dependencies] hex = "0.4.3" diff --git a/roles/pool/src/args.rs b/roles/pool/src/args.rs new file mode 100644 index 000000000..1f6963966 --- /dev/null +++ b/roles/pool/src/args.rs @@ -0,0 +1,29 @@ +use crate::lib::{error::PoolResult, pool_config::PoolConfig}; + +use clap::Parser; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(short, long, help = "Path to TOML configuration file")] + config_path: String, +} + +#[allow(clippy::result_large_err)] +pub fn process_cli_args() -> PoolResult { + let args = Args::parse(); + let config = match config::Config::builder() + .add_source(config::File::with_name(&args.config_path)) + .build() + { + Ok(cfg) => cfg, + Err(e) => { + tracing::error!("{:?}", e); + std::process::exit(1) + } + }; + + let pool_config: PoolConfig = config.try_deserialize()?; + + Ok(pool_config) +} diff --git a/roles/pool/src/lib/error.rs b/roles/pool/src/lib/error.rs index ead10b8fa..a5624cdb0 100644 --- a/roles/pool/src/lib/error.rs +++ b/roles/pool/src/lib/error.rs @@ -8,6 +8,7 @@ use roles_logic_sv2::parsers::Mining; #[derive(std::fmt::Debug)] pub enum PoolError { + ConfigError(config::ConfigError), Io(std::io::Error), ChannelSend(Box), ChannelRecv(async_channel::RecvError), @@ -22,10 +23,17 @@ pub enum PoolError { Sv2ProtocolError((u32, Mining<'static>)), } +impl From for PoolError { + fn from(e: config::ConfigError) -> PoolError { + PoolError::ConfigError(e) + } +} + impl std::fmt::Display for PoolError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use PoolError::*; match self { + ConfigError(e) => write!(f, "Config error: {:?}", e), Io(ref e) => write!(f, "I/O error: `{:?}", e), ChannelSend(ref e) => write!(f, "Channel send failed: `{:?}`", e), ChannelRecv(ref e) => write!(f, "Channel recv failed: `{:?}`", e), diff --git a/roles/pool/src/lib/mining_pool/mod.rs b/roles/pool/src/lib/mining_pool/mod.rs index e189c5406..414618452 100644 --- a/roles/pool/src/lib/mining_pool/mod.rs +++ b/roles/pool/src/lib/mining_pool/mod.rs @@ -1,5 +1,6 @@ use super::{ error::{PoolError, PoolResult}, + pool_config::PoolConfig, status, }; use async_channel::{Receiver, Sender}; @@ -28,10 +29,7 @@ use std::{ net::SocketAddr, sync::Arc, }; -use stratum_common::{ - bitcoin::{Script, TxOut}, - secp256k1, -}; +use stratum_common::secp256k1; use tokio::{net::TcpListener, task}; use tracing::{debug, error, info, warn}; @@ -43,23 +41,6 @@ pub mod message_handler; pub type Message = PoolMessages<'static>; pub type StdFrame = StandardSv2Frame; pub type EitherFrame = StandardEitherFrame; - -pub fn get_coinbase_output(config: &Configuration) -> Result, Error> { - let mut result = Vec::new(); - for coinbase_output_pool in &config.coinbase_outputs { - let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?; - let output_script: Script = coinbase_output.try_into()?; - result.push(TxOut { - value: 0, - script_pubkey: output_script, - }); - } - match result.is_empty() { - true => Err(Error::EmptyCoinbaseOutputs), - _ => Ok(result), - } -} - #[derive(Debug, Deserialize, Clone)] pub struct CoinbaseOutput { output_script_type: String, @@ -338,7 +319,7 @@ impl Pool { async fn accept_incoming_connection( self_: Arc>, - config: Configuration, + config: PoolConfig, ) -> PoolResult<()> { let status_tx = self_.safe_lock(|s| s.status_tx.clone())?; let listener = TcpListener::bind(&config.listen_address).await?; @@ -514,7 +495,7 @@ impl Pool { } pub fn start( - config: Configuration, + config: PoolConfig, new_template_rx: Receiver>, new_prev_hash_rx: Receiver>, solution_sender: Sender>, @@ -529,7 +510,7 @@ impl Pool { end: extranonce_len, }; let ids = Arc::new(Mutex::new(roles_logic_sv2::utils::GroupId::new())); - let pool_coinbase_outputs = get_coinbase_output(&config); + let pool_coinbase_outputs = super::pool_config::get_coinbase_output(&config); info!("PUB KEY: {:?}", pool_coinbase_outputs); let extranonces = ExtendedExtranonce::new(range_0, range_1, range_2); let creator = JobsCreators::new(extranonce_len as u8); @@ -664,16 +645,27 @@ mod test { bitcoin::{util::psbt::serialize::Serialize, Transaction, Witness}, }; + use super::super::pool_config::PoolConfig; + // this test is used to verify the `coinbase_tx_prefix` and `coinbase_tx_suffix` values tested against in // message generator `stratum/test/message-generator/test/pool-sri-test-extended.json` #[test] fn test_coinbase_outputs_from_config() { // Load config - let config: super::Configuration = toml::from_str( - &std::fs::read_to_string("./config-examples/pool-config-local-tp-example.toml") - .unwrap(), - ) - .unwrap(); + let config = match config::Config::builder() + .add_source(config::File::with_name( + "./config-examples/pool-config-local-tp-example.toml", + )) + .build() + { + Ok(cfg) => cfg, + Err(e) => { + tracing::error!("{:?}", e); + std::process::exit(1) + } + }; + + let pool_config: PoolConfig = config.try_deserialize().unwrap(); // template from message generator test (mock TP template) let _extranonce_len = 3; let coinbase_prefix = vec![3, 76, 163, 38, 0]; @@ -683,15 +675,16 @@ mod test { let _coinbase_tx_value_remaining: u64 = 625000000; let _coinbase_tx_outputs_count = 0; let coinbase_tx_locktime = 0; - let coinbase_tx_outputs: Vec = super::get_coinbase_output(&config).unwrap(); + let coinbase_tx_outputs: Vec = + super::super::pool_config::get_coinbase_output(&pool_config).unwrap(); // extranonce len set to max_extranonce_size in `ChannelFactory::new_extended_channel()` let extranonce_len = 32; // build coinbase TX from 'job_creator::coinbase()' let mut bip34_bytes = get_bip_34_bytes(coinbase_prefix.try_into().unwrap()); - let script_prefix_length = bip34_bytes.len() + config.pool_signature.as_bytes().len(); - bip34_bytes.extend_from_slice(config.pool_signature.as_bytes()); + let script_prefix_length = bip34_bytes.len() + pool_config.pool_signature.as_bytes().len(); + bip34_bytes.extend_from_slice(pool_config.pool_signature.as_bytes()); bip34_bytes.extend_from_slice(&vec![0; extranonce_len as usize]); let witness = match bip34_bytes.len() { 0 => Witness::from_vec(vec![]), @@ -776,13 +769,13 @@ mod test { _ => 2, }; let r = encoded[4 // tx version - + segwit_bytes - + 1 // number of inputs TODO can be also 3 - + 32 // prev OutPoint - + 4 // index - + 1 // bytes in script TODO can be also 3 - + script_prefix_len // bip34_bytes - + (extranonce_len as usize)..] + + segwit_bytes + + 1 // number of inputs TODO can be also 3 + + 32 // prev OutPoint + + 4 // index + + 1 // bytes in script TODO can be also 3 + + script_prefix_len // bip34_bytes + + (extranonce_len as usize)..] .to_vec(); r.try_into().unwrap() } diff --git a/roles/pool/src/lib/mod.rs b/roles/pool/src/lib/mod.rs index 2d8417842..b12ca52e5 100644 --- a/roles/pool/src/lib/mod.rs +++ b/roles/pool/src/lib/mod.rs @@ -1,4 +1,5 @@ pub mod error; pub mod mining_pool; +pub mod pool_config; pub mod status; pub mod template_receiver; diff --git a/roles/pool/src/lib/pool_config.rs b/roles/pool/src/lib/pool_config.rs new file mode 100644 index 000000000..f76444f25 --- /dev/null +++ b/roles/pool/src/lib/pool_config.rs @@ -0,0 +1,57 @@ +use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey}; +use roles_logic_sv2::{errors::Error, utils::CoinbaseOutput as CoinbaseOutput_}; +use serde::Deserialize; +use std::convert::{TryFrom, TryInto}; +use stratum_common::bitcoin::{Script, TxOut}; + +pub fn get_coinbase_output(config: &PoolConfig) -> Result, Error> { + let mut result = Vec::new(); + for coinbase_output_pool in &config.coinbase_outputs { + let coinbase_output: CoinbaseOutput_ = coinbase_output_pool.try_into()?; + let output_script: Script = coinbase_output.try_into()?; + result.push(TxOut { + value: 0, + script_pubkey: output_script, + }); + } + match result.is_empty() { + true => Err(Error::EmptyCoinbaseOutputs), + _ => Ok(result), + } +} + +#[derive(Debug, Deserialize, Clone)] +pub struct CoinbaseOutput { + output_script_type: String, + output_script_value: String, +} + +impl TryFrom<&CoinbaseOutput> for CoinbaseOutput_ { + type Error = Error; + + fn try_from(pool_output: &CoinbaseOutput) -> Result { + match pool_output.output_script_type.as_str() { + "TEST" | "P2PK" | "P2PKH" | "P2WPKH" | "P2SH" | "P2WSH" | "P2TR" => { + Ok(CoinbaseOutput_ { + output_script_type: pool_output.clone().output_script_type, + output_script_value: pool_output.clone().output_script_value, + }) + } + _ => Err(Error::UnknownOutputScriptType), + } + } +} + +#[derive(Debug, Deserialize, Clone)] +pub struct PoolConfig { + pub listen_address: String, + pub tp_address: String, + pub tp_authority_public_key: Option, + pub authority_public_key: Secp256k1PublicKey, + pub authority_secret_key: Secp256k1SecretKey, + pub cert_validity_sec: u64, + pub coinbase_outputs: Vec, + pub pool_signature: String, + #[cfg(feature = "test_only_allow_unencrypted")] + pub test_only_listen_adress_plain: String, +} diff --git a/roles/pool/src/lib/status.rs b/roles/pool/src/lib/status.rs index f9bd7a4bc..43179c7e7 100644 --- a/roles/pool/src/lib/status.rs +++ b/roles/pool/src/lib/status.rs @@ -114,6 +114,9 @@ async fn send_status( pub async fn handle_error(sender: &Sender, e: PoolError) -> error_handling::ErrorBranch { tracing::debug!("Error: {:?}", &e); match e { + PoolError::ConfigError(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } PoolError::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, PoolError::ChannelSend(_) => { //This should be a continue because if we fail to send to 1 downstream we should continue diff --git a/roles/pool/src/main.rs b/roles/pool/src/main.rs index 169243c23..aabfe1d6d 100644 --- a/roles/pool/src/main.rs +++ b/roles/pool/src/main.rs @@ -2,103 +2,21 @@ use async_channel::{bounded, unbounded}; use tracing::{error, info, warn}; +mod args; mod lib; use lib::{ - mining_pool::{get_coinbase_output, Configuration, Pool}, - status, - template_receiver::TemplateRx, + mining_pool::Pool, pool_config::get_coinbase_output, status, template_receiver::TemplateRx, }; use tokio::select; -mod args { - use std::path::PathBuf; - - #[derive(Debug)] - pub struct Args { - pub config_path: PathBuf, - } - - enum ArgsState { - Next, - ExpectPath, - Done, - } - - enum ArgsResult { - Config(PathBuf), - None, - Help(String), - } - - impl Args { - const DEFAULT_CONFIG_PATH: &'static str = "pool-config.toml"; - const HELP_MSG: &'static str = - "Usage: -h/--help, -c/--config "; - - pub fn from_args() -> Result { - let cli_args = std::env::args(); - - if cli_args.len() == 1 { - println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH); - println!("{}\n", Self::HELP_MSG); - } - - let config_path = cli_args - .scan(ArgsState::Next, |state, item| { - match std::mem::replace(state, ArgsState::Done) { - ArgsState::Next => match item.as_str() { - "-c" | "--config" => { - *state = ArgsState::ExpectPath; - Some(ArgsResult::None) - } - "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())), - _ => { - *state = ArgsState::Next; - - Some(ArgsResult::None) - } - }, - ArgsState::ExpectPath => Some(ArgsResult::Config(PathBuf::from(item))), - ArgsState::Done => None, - } - }) - .last(); - let config_path = match config_path { - Some(ArgsResult::Config(p)) => p, - Some(ArgsResult::Help(h)) => return Err(h), - _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH), - }; - Ok(Self { config_path }) - } - } -} - #[tokio::main] async fn main() { tracing_subscriber::fmt::init(); - let args = match args::Args::from_args() { - Ok(cfg) => cfg, - Err(help) => { - error!("{}", help); - return; - } - }; - - // Load config - let config: Configuration = match std::fs::read_to_string(&args.config_path) { - Ok(c) => match toml::from_str(&c) { - Ok(c) => c, - Err(e) => { - error!("Failed to parse config: {}", e); - return; - } - }, - Err(e) => { - error!("Failed to read config: {}", e); - return; - } + let pool_config = match args::process_cli_args() { + Ok(p) => p, + Err(_) => return, }; let (status_tx, status_rx) = unbounded(); @@ -106,8 +24,8 @@ async fn main() { let (s_prev_hash, r_prev_hash) = bounded(10); let (s_solution, r_solution) = bounded(10); let (s_message_recv_signal, r_message_recv_signal) = bounded(10); - info!("Pool INITIALIZING with config: {:?}", &args.config_path); - let coinbase_output_result = get_coinbase_output(&config); + info!("Pool INITIALIZING"); + let coinbase_output_result = get_coinbase_output(&pool_config); let coinbase_output_len = match coinbase_output_result { Ok(coinbase_output) => coinbase_output.len() as u32, Err(err) => { @@ -115,9 +33,9 @@ async fn main() { return; } }; - let tp_authority_public_key = config.tp_authority_public_key; + let tp_authority_public_key = pool_config.tp_authority_public_key; let template_rx_res = TemplateRx::connect( - config.tp_address.parse().unwrap(), + pool_config.tp_address.parse().unwrap(), s_new_t, s_prev_hash, r_solution, @@ -134,7 +52,7 @@ async fn main() { } let pool = Pool::start( - config.clone(), + pool_config.clone(), r_new_t, r_prev_hash, s_solution, diff --git a/roles/translator/Cargo.toml b/roles/translator/Cargo.toml index 182370cbd..e6327050c 100644 --- a/roles/translator/Cargo.toml +++ b/roles/translator/Cargo.toml @@ -26,7 +26,6 @@ serde = { version = "1.0.89", default-features = false, features = ["derive", "a serde_json = { version = "1.0.64", default-features = false, features = ["alloc"] } futures = "0.3.25" tokio = { version = "1", features = ["full"] } -toml = { version = "0.5.6", git = "https://github.com/diondokter/toml-rs", default-features = false, rev = "c4161aa" } tracing = { version = "0.1" } tracing-subscriber = { version = "0.3" } v1 = { version = "^1.0.0", path = "../../protocols/v1", package="sv1_api" } @@ -34,7 +33,8 @@ error_handling = { version = "1.0.0", path = "../../utils/error-handling" } key-utils = { version = "^1.0.0", path = "../../utils/key-utils" } tokio-util = { version = "0.7.10", features = ["codec"] } async-compat = "0.2.1" - +clap = { version = "^4.5.4", features = ["derive"] } +config = { version = "0.14.0", features = ["toml"] } [dev-dependencies] diff --git a/roles/translator/src/args.rs b/roles/translator/src/args.rs index bf5e51c19..2408a1d2c 100644 --- a/roles/translator/src/args.rs +++ b/roles/translator/src/args.rs @@ -1,68 +1,29 @@ -use std::path::PathBuf; +use crate::lib::{error::TProxyResult, tproxy_config::TProxyConfig}; -#[derive(Debug)] -pub struct Args { - pub config_path: PathBuf, -} - -enum ArgsState { - Next, - ExpectPath, - Done, -} +use clap::Parser; -enum ArgsResult { - Config(PathBuf), - None, - Help(String), +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(short, long, help = "Path to TOML configuration file")] + config_path: String, } -impl Args { - const DEFAULT_CONFIG_PATH: &'static str = "proxy-config.toml"; - const HELP_MSG: &'static str = "Usage: -h/--help, -c/--config "; - - pub fn from_args() -> Result { - let cli_args = std::env::args(); - - if cli_args.len() == 1 { - println!("Using default config path: {}", Self::DEFAULT_CONFIG_PATH); - println!("{}\n", Self::HELP_MSG); +#[allow(clippy::result_large_err)] +pub fn process_cli_args<'a>() -> TProxyResult<'a, TProxyConfig> { + let args = Args::parse(); + let config = match config::Config::builder() + .add_source(config::File::with_name(&args.config_path)) + .build() + { + Ok(cfg) => cfg, + Err(e) => { + tracing::error!("{:?}", e); + std::process::exit(1) } + }; - let config_path = cli_args - .scan(ArgsState::Next, |state, item| { - match std::mem::replace(state, ArgsState::Done) { - ArgsState::Next => match item.as_str() { - "-c" | "--config" => { - *state = ArgsState::ExpectPath; - Some(ArgsResult::None) - } - "-h" | "--help" => Some(ArgsResult::Help(Self::HELP_MSG.to_string())), - _ => { - *state = ArgsState::Next; + let proxy_config: TProxyConfig = config.try_deserialize()?; - Some(ArgsResult::None) - } - }, - ArgsState::ExpectPath => { - let path = PathBuf::from(item.clone()); - if !path.exists() { - return Some(ArgsResult::Help(format!( - "Error: File '{}' does not exist!", - path.display() - ))); - } - Some(ArgsResult::Config(path)) - } - ArgsState::Done => None, - } - }) - .last(); - let config_path = match config_path { - Some(ArgsResult::Config(p)) => p, - Some(ArgsResult::Help(h)) => return Err(h), - _ => PathBuf::from(Self::DEFAULT_CONFIG_PATH), - }; - Ok(Self { config_path }) - } + Ok(proxy_config) } diff --git a/roles/translator/src/lib/downstream_sv1/diff_management.rs b/roles/translator/src/lib/downstream_sv1/diff_management.rs index eb8f0af38..c170481db 100644 --- a/roles/translator/src/lib/downstream_sv1/diff_management.rs +++ b/roles/translator/src/lib/downstream_sv1/diff_management.rs @@ -1,6 +1,6 @@ use super::{Downstream, DownstreamMessages, SetDownstreamTarget}; -use super::super::error::{Error, ProxyResult}; +use super::super::error::{TProxyError, TProxyResult}; use roles_logic_sv2::utils::Mutex; use std::{ops::Div, sync::Arc}; use v1::json_rpc; @@ -14,7 +14,7 @@ impl Downstream { pub async fn init_difficulty_management( self_: Arc>, init_target: &[u8], - ) -> ProxyResult<'static, ()> { + ) -> TProxyResult<'static, ()> { let (connection_id, upstream_difficulty_config, miner_hashrate) = self_ .safe_lock(|d| { let timestamp_secs = std::time::SystemTime::now() @@ -29,13 +29,13 @@ impl Downstream { d.difficulty_mgmt.min_individual_miner_hashrate, ) }) - .map_err(|_e| Error::PoisonLock)?; + .map_err(|_e| TProxyError::PoisonLock)?; // add new connection hashrate to channel hashrate upstream_difficulty_config .safe_lock(|u| { u.channel_nominal_hashrate += miner_hashrate; }) - .map_err(|_e| Error::PoisonLock)?; + .map_err(|_e| TProxyError::PoisonLock)?; // update downstream target with bridge let init_target = binary_sv2::U256::try_from(init_target.to_vec())?; Self::send_message_upstream( @@ -52,7 +52,9 @@ impl Downstream { /// Called before a miner disconnects so we can remove the miner's hashrate from the aggregated channel hashrate #[allow(clippy::result_large_err)] - pub fn remove_miner_hashrate_from_channel(self_: Arc>) -> ProxyResult<'static, ()> { + pub fn remove_miner_hashrate_from_channel( + self_: Arc>, + ) -> TProxyResult<'static, ()> { self_ .safe_lock(|d| { d.upstream_difficulty_config @@ -64,9 +66,9 @@ impl Downstream { u.channel_nominal_hashrate = 0.0; } }) - .map_err(|_e| Error::PoisonLock) + .map_err(|_e| TProxyError::PoisonLock) }) - .map_err(|_e| Error::PoisonLock)??; + .map_err(|_e| TProxyError::PoisonLock)??; Ok(()) } @@ -74,11 +76,11 @@ impl Downstream { /// difficulty to the miner pub async fn try_update_difficulty_settings( self_: Arc>, - ) -> ProxyResult<'static, ()> { + ) -> TProxyResult<'static, ()> { let (diff_mgmt, channel_id) = self_ .clone() .safe_lock(|d| (d.difficulty_mgmt.clone(), d.connection_id)) - .map_err(|_e| Error::PoisonLock)?; + .map_err(|_e| TProxyError::PoisonLock)?; tracing::debug!( "Time of last diff update: {:?}", diff_mgmt.timestamp_of_last_update @@ -92,7 +94,7 @@ impl Downstream { diff_mgmt.shares_per_minute.into(), ) { Ok(target) => target.to_vec(), - Err(v) => return Err(Error::TargetError(v)), + Err(v) => return Err(TProxyError::TargetError(v)), }; if let Some(new_hash_rate) = Self::update_miner_hashrate(self_.clone(), prev_target.clone())? @@ -102,7 +104,7 @@ impl Downstream { diff_mgmt.shares_per_minute.into(), ) { Ok(target) => target, - Err(v) => return Err(Error::TargetError(v)), + Err(v) => return Err(TProxyError::TargetError(v)), }; tracing::debug!("New target from hashrate: {:?}", new_target.inner_as_ref()); let message = Self::get_set_difficulty(new_target.to_vec())?; @@ -124,7 +126,7 @@ impl Downstream { /// calculates the target according to the current stored hashrate of the miner #[allow(clippy::result_large_err)] - pub fn hash_rate_to_target(self_: Arc>) -> ProxyResult<'static, Vec> { + pub fn hash_rate_to_target(self_: Arc>) -> TProxyResult<'static, Vec> { self_ .safe_lock(|d| { match roles_logic_sv2::utils::hash_rate_to_target( @@ -132,20 +134,20 @@ impl Downstream { d.difficulty_mgmt.shares_per_minute.into(), ) { Ok(target) => Ok(target.to_vec()), - Err(e) => Err(Error::TargetError(e)), + Err(e) => Err(TProxyError::TargetError(e)), } }) - .map_err(|_e| Error::PoisonLock)? + .map_err(|_e| TProxyError::PoisonLock)? } /// increments the number of shares since the last difficulty update #[allow(clippy::result_large_err)] - pub(super) fn save_share(self_: Arc>) -> ProxyResult<'static, ()> { + pub(super) fn save_share(self_: Arc>) -> TProxyResult<'static, ()> { self_ .safe_lock(|d| { d.difficulty_mgmt.submits_since_last_update += 1; }) - .map_err(|_e| Error::PoisonLock)?; + .map_err(|_e| TProxyError::PoisonLock)?; Ok(()) } @@ -153,7 +155,7 @@ impl Downstream { /// difficulty for the Downstream role and creates the SV1 `mining.set_difficulty` message to /// be sent to the Downstream role. #[allow(clippy::result_large_err)] - pub(super) fn get_set_difficulty(target: Vec) -> ProxyResult<'static, json_rpc::Message> { + pub(super) fn get_set_difficulty(target: Vec) -> TProxyResult<'static, json_rpc::Message> { let value = Downstream::difficulty_from_target(target)?; tracing::debug!("Difficulty from target: {:?}", value); let set_target = v1::methods::server_to_client::SetDifficulty { value }; @@ -164,7 +166,7 @@ impl Downstream { /// Converts target received by the `SetTarget` SV2 message from the Upstream role into the /// difficulty for the Downstream role sent via the SV1 `mining.set_difficulty` message. #[allow(clippy::result_large_err)] - pub(super) fn difficulty_from_target(mut target: Vec) -> ProxyResult<'static, f64> { + pub(super) fn difficulty_from_target(mut target: Vec) -> TProxyResult<'static, f64> { // reverse because target is LE and this function relies on BE target.reverse(); let target = target.as_slice(); @@ -199,7 +201,7 @@ impl Downstream { pub fn update_miner_hashrate( self_: Arc>, miner_target: Vec, - ) -> ProxyResult<'static, Option> { + ) -> TProxyResult<'static, Option> { self_ .safe_lock(|d| { let timestamp_secs = std::time::SystemTime::now() @@ -287,7 +289,7 @@ impl Downstream { Ok(None) } }) - .map_err(|_e| Error::PoisonLock)? + .map_err(|_e| TProxyError::PoisonLock)? } /// Helper function to check if target is set to zero for some reason (typically happens when @@ -304,7 +306,7 @@ impl Downstream { #[cfg(test)] mod test { - use crate::proxy_config::{DownstreamDifficultyConfig, UpstreamDifficultyConfig}; + use crate::tproxy_config::{DownstreamDifficultyConfig, UpstreamDifficultyConfig}; use async_channel::unbounded; use binary_sv2::U256; use rand::{thread_rng, Rng}; diff --git a/roles/translator/src/lib/downstream_sv1/downstream.rs b/roles/translator/src/lib/downstream_sv1/downstream.rs index ddf74fe58..ba1c3a99c 100644 --- a/roles/translator/src/lib/downstream_sv1/downstream.rs +++ b/roles/translator/src/lib/downstream_sv1/downstream.rs @@ -1,8 +1,8 @@ use crate::{ downstream_sv1, - error::ProxyResult, - proxy_config::{DownstreamDifficultyConfig, UpstreamDifficultyConfig}, + error::TProxyResult, status, + tproxy_config::{DownstreamDifficultyConfig, UpstreamDifficultyConfig}, }; use async_channel::{bounded, Receiver, Sender}; use async_std::{ @@ -22,7 +22,7 @@ use roles_logic_sv2::{ utils::Mutex, }; -use crate::error::Error; +use crate::error::TProxyError; use futures::select; use tokio_util::codec::{FramedRead, LinesCodec}; @@ -181,7 +181,7 @@ impl Downstream { handle_result!(tx_status_reader, res); } Some(Err(_)) => { - handle_result!(tx_status_reader, Err(Error::Sv1MessageTooLong)); + handle_result!(tx_status_reader, Err(TProxyError::Sv1MessageTooLong)); } None => { handle_result!(tx_status_reader, Err( @@ -375,7 +375,7 @@ impl Downstream { async fn handle_incoming_sv1( self_: Arc>, message_sv1: json_rpc::Message, - ) -> Result<(), super::super::error::Error<'static>> { + ) -> Result<(), super::super::error::TProxyError<'static>> { // `handle_message` in `IsServer` trait + calls `handle_request` // TODO: Map err from V1Error to Error::V1Error let response = self_.safe_lock(|s| s.handle_message(message_sv1)).unwrap(); @@ -417,7 +417,7 @@ impl Downstream { pub(super) async fn send_message_upstream( self_: Arc>, msg: DownstreamMessages, - ) -> ProxyResult<'static, ()> { + ) -> TProxyResult<'static, ()> { let sender = self_.safe_lock(|s| s.tx_sv1_bridge.clone()).unwrap(); debug!("To Bridge: {:?}", msg); let _ = sender.send(msg).await; diff --git a/roles/translator/src/lib/error.rs b/roles/translator/src/lib/error.rs index debad1819..36f60b741 100644 --- a/roles/translator/src/lib/error.rs +++ b/roles/translator/src/lib/error.rs @@ -7,7 +7,7 @@ use v1::server_to_client::{Notify, SetDifficulty}; use stratum_common::bitcoin::util::uint::ParseLengthError; -pub type ProxyResult<'a, T> = core::result::Result>; +pub type TProxyResult<'a, T> = core::result::Result>; #[derive(Debug)] pub enum ChannelSendError<'a> { @@ -32,14 +32,14 @@ pub enum ChannelSendError<'a> { } #[derive(Debug)] -pub enum Error<'a> { +pub enum TProxyError<'a> { VecToSlice32(Vec), + ConfigError(config::ConfigError), /// Errors on bad CLI argument input. + #[allow(dead_code)] BadCliArgs, /// Errors on bad `serde_json` serialize/deserialize. BadSerdeJson(serde_json::Error), - /// Errors on bad `toml` deserialize. - BadTomlDeserialize(toml::de::Error), /// Errors from `binary_sv2` crate. BinarySv2(binary_sv2::Error), /// Errors on bad noise handshake. @@ -77,13 +77,13 @@ pub enum Error<'a> { Sv1MessageTooLong, } -impl<'a> fmt::Display for Error<'a> { +impl<'a> fmt::Display for TProxyError<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use Error::*; + use TProxyError::*; match self { + ConfigError(e) => write!(f, "Config error: {:?}", e), BadCliArgs => write!(f, "Bad CLI arg input"), BadSerdeJson(ref e) => write!(f, "Bad serde json: `{:?}`", e), - BadTomlDeserialize(ref e) => write!(f, "Bad `toml` deserialize: `{:?}`", e), BinarySv2(ref e) => write!(f, "Binary SV2 error: `{:?}`", e), CodecNoise(ref e) => write!(f, "Noise error: `{:?}", e), FramingSv2(ref e) => write!(f, "Framing SV2 error: `{:?}`", e), @@ -117,125 +117,125 @@ impl<'a> fmt::Display for Error<'a> { } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { + fn from(e: config::ConfigError) -> TProxyError<'a> { + TProxyError::ConfigError(e) + } +} + +impl<'a> From for TProxyError<'a> { fn from(e: binary_sv2::Error) -> Self { - Error::BinarySv2(e) + TProxyError::BinarySv2(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: codec_sv2::noise_sv2::Error) -> Self { - Error::CodecNoise(e) + TProxyError::CodecNoise(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: framing_sv2::Error) -> Self { - Error::FramingSv2(e) + TProxyError::FramingSv2(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: std::io::Error) -> Self { - Error::Io(e) + TProxyError::Io(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: std::num::ParseIntError) -> Self { - Error::ParseInt(e) + TProxyError::ParseInt(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: roles_logic_sv2::errors::Error) -> Self { - Error::RolesSv2Logic(e) + TProxyError::RolesSv2Logic(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: serde_json::Error) -> Self { - Error::BadSerdeJson(e) - } -} - -impl<'a> From for Error<'a> { - fn from(e: toml::de::Error) -> Self { - Error::BadTomlDeserialize(e) + TProxyError::BadSerdeJson(e) } } -impl<'a> From> for Error<'a> { +impl<'a> From> for TProxyError<'a> { fn from(e: v1::error::Error<'a>) -> Self { - Error::V1Protocol(e) + TProxyError::V1Protocol(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: async_channel::RecvError) -> Self { - Error::ChannelErrorReceiver(e) + TProxyError::ChannelErrorReceiver(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: tokio::sync::broadcast::error::RecvError) -> Self { - Error::TokioChannelErrorRecv(e) + TProxyError::TokioChannelErrorRecv(e) } } //*** LOCK ERRORS *** -impl<'a, T> From> for Error<'a> { +impl<'a, T> From> for TProxyError<'a> { fn from(_e: PoisonError) -> Self { - Error::PoisonLock + TProxyError::PoisonLock } } // *** CHANNEL SENDER ERRORS *** impl<'a> From>> - for Error<'a> + for TProxyError<'a> { fn from( e: async_channel::SendError>, ) -> Self { - Error::ChannelErrorSender(ChannelSendError::SubmitSharesExtended(e)) + TProxyError::ChannelErrorSender(ChannelSendError::SubmitSharesExtended(e)) } } impl<'a> From>> - for Error<'a> + for TProxyError<'a> { fn from(e: async_channel::SendError>) -> Self { - Error::ChannelErrorSender(ChannelSendError::SetNewPrevHash(e)) + TProxyError::ChannelErrorSender(ChannelSendError::SetNewPrevHash(e)) } } -impl<'a> From>> for Error<'a> { +impl<'a> From>> for TProxyError<'a> { fn from(e: tokio::sync::broadcast::error::SendError>) -> Self { - Error::ChannelErrorSender(ChannelSendError::Notify(e)) + TProxyError::ChannelErrorSender(ChannelSendError::Notify(e)) } } -impl<'a> From> for Error<'a> { +impl<'a> From> for TProxyError<'a> { fn from(e: async_channel::SendError) -> Self { - Error::ChannelErrorSender(ChannelSendError::V1Message(e)) + TProxyError::ChannelErrorSender(ChannelSendError::V1Message(e)) } } -impl<'a> From> for Error<'a> { +impl<'a> From> for TProxyError<'a> { fn from(e: async_channel::SendError<(ExtendedExtranonce, u32)>) -> Self { - Error::ChannelErrorSender(ChannelSendError::Extranonce(e)) + TProxyError::ChannelErrorSender(ChannelSendError::Extranonce(e)) } } -impl<'a> From>> for Error<'a> { +impl<'a> From>> for TProxyError<'a> { fn from(e: async_channel::SendError>) -> Self { - Error::ChannelErrorSender(ChannelSendError::NewExtendedMiningJob(e)) + TProxyError::ChannelErrorSender(ChannelSendError::NewExtendedMiningJob(e)) } } -impl<'a> From>> for Error<'a> { +impl<'a> From>> for TProxyError<'a> { fn from(e: async_channel::SendError>) -> Self { - Error::ChannelErrorSender(ChannelSendError::SetCustomMiningJob(e)) + TProxyError::ChannelErrorSender(ChannelSendError::SetCustomMiningJob(e)) } } @@ -245,7 +245,7 @@ impl<'a> roles_logic_sv2::template_distribution_sv2::SetNewPrevHash<'a>, Vec, )>, - > for Error<'a> + > for TProxyError<'a> { fn from( e: async_channel::SendError<( @@ -253,36 +253,36 @@ impl<'a> Vec, )>, ) -> Self { - Error::ChannelErrorSender(ChannelSendError::NewTemplate(e)) + TProxyError::ChannelErrorSender(ChannelSendError::NewTemplate(e)) } } -impl<'a> From> for Error<'a> { +impl<'a> From> for TProxyError<'a> { fn from(e: Vec) -> Self { - Error::VecToSlice32(e) + TProxyError::VecToSlice32(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: ParseLengthError) -> Self { - Error::Uint256Conversion(e) + TProxyError::Uint256Conversion(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: SetDifficulty) -> Self { - Error::SetDifficultyToMessage(e) + TProxyError::SetDifficultyToMessage(e) } } -impl<'a> From for Error<'a> { +impl<'a> From for TProxyError<'a> { fn from(e: std::convert::Infallible) -> Self { - Error::Infallible(e) + TProxyError::Infallible(e) } } -impl<'a> From> for Error<'a> { +impl<'a> From> for TProxyError<'a> { fn from(e: Mining<'a>) -> Self { - Error::Sv2ProtocolError(e) + TProxyError::Sv2ProtocolError(e) } } diff --git a/roles/translator/src/lib/mod.rs b/roles/translator/src/lib/mod.rs index 2075e4569..e4ab83b76 100644 --- a/roles/translator/src/lib/mod.rs +++ b/roles/translator/src/lib/mod.rs @@ -1,7 +1,7 @@ pub mod downstream_sv1; pub mod error; pub mod proxy; -pub mod proxy_config; pub mod status; +pub mod tproxy_config; pub mod upstream_sv2; pub mod utils; diff --git a/roles/translator/src/lib/proxy/bridge.rs b/roles/translator/src/lib/proxy/bridge.rs index 22aeaa18f..fd4ed0e02 100644 --- a/roles/translator/src/lib/proxy/bridge.rs +++ b/roles/translator/src/lib/proxy/bridge.rs @@ -15,8 +15,8 @@ use v1::{client_to_server::Submit, server_to_client, utils::HexU32Be}; use super::super::{ downstream_sv1::{DownstreamMessages, SetDownstreamTarget, SubmitShareWithChannelId}, error::{ - Error::{self, PoisonLock}, - ProxyResult, + TProxyError::{self, PoisonLock}, + TProxyResult, }, status, }; @@ -114,7 +114,7 @@ impl Bridge { pub fn on_new_sv1_connection( &mut self, hash_rate: f32, - ) -> ProxyResult<'static, OpenSv1Downstream> { + ) -> TProxyResult<'static, OpenSv1Downstream> { match self.channel_factory.new_extended_channel(0, hash_rate, 0) { Ok(messages) => { for message in messages { @@ -141,12 +141,12 @@ impl Bridge { } } Err(_) => { - return Err(Error::SubprotocolMining( + return Err(TProxyError::SubprotocolMining( "Bridge: failed to open new extended channel".to_string(), )) } }; - Err(Error::SubprotocolMining( + Err(TProxyError::SubprotocolMining( "Bridge: Invalid mining message when opening downstream connection".to_string(), )) } @@ -191,7 +191,7 @@ impl Bridge { fn handle_update_downstream_target( self_: Arc>, new_target: SetDownstreamTarget, - ) -> ProxyResult<'static, ()> { + ) -> TProxyResult<'static, ()> { self_ .safe_lock(|b| { b.channel_factory @@ -205,7 +205,7 @@ impl Bridge { async fn handle_submit_shares( self_: Arc>, share: SubmitShareWithChannelId, - ) -> ProxyResult<'static, ()> { + ) -> TProxyResult<'static, ()> { let (tx_sv2_submit_shares_ext, target_mutex, tx_status) = self_ .safe_lock(|s| { ( @@ -276,16 +276,16 @@ impl Bridge { channel_id: u32, sv1_submit: Submit, version_rolling_mask: Option, - ) -> ProxyResult<'static, SubmitSharesExtended<'static>> { + ) -> TProxyResult<'static, SubmitSharesExtended<'static>> { let last_version = self .channel_factory .last_valid_job_version() - .ok_or(Error::RolesSv2Logic(RolesLogicError::NoValidJob))?; + .ok_or(TProxyError::RolesSv2Logic(RolesLogicError::NoValidJob))?; let version = match (sv1_submit.version_bits, version_rolling_mask) { // regarding version masking see https://github.com/slushpool/stratumprotocol/blob/master/stratum-extensions.mediawiki#changes-in-request-miningsubmit (Some(vb), Some(mask)) => (last_version & !mask.0) | (vb.0 & mask.0), (None, None) => last_version, - _ => return Err(Error::V1Protocol(v1::error::Error::InvalidSubmission)), + _ => return Err(TProxyError::V1Protocol(v1::error::Error::InvalidSubmission)), }; let mining_device_extranonce: Vec = sv1_submit.extra_nonce2.into(); let extranonce2 = mining_device_extranonce; @@ -305,7 +305,7 @@ impl Bridge { self_: Arc>, sv2_set_new_prev_hash: SetNewPrevHash<'static>, tx_sv1_notify: broadcast::Sender>, - ) -> Result<(), Error<'static>> { + ) -> TProxyResult<'static, ()> { while !crate::upstream_sv2::upstream::IS_NEW_JOB_HANDLED .load(std::sync::atomic::Ordering::SeqCst) { @@ -403,7 +403,7 @@ impl Bridge { self_: Arc>, sv2_new_extended_mining_job: NewExtendedMiningJob<'static>, tx_sv1_notify: broadcast::Sender>, - ) -> Result<(), Error<'static>> { + ) -> Result<(), TProxyError<'static>> { // convert to non segwit jobs so we dont have to depend if miner's support segwit or not self_ .safe_lock(|s| { @@ -427,7 +427,7 @@ impl Bridge { .map_err(|_| PoisonLock)?; // last_p_hash is an Option so we need to map to the correct error type to be handled - let last_p_hash = last_p_hash_option.ok_or(Error::RolesSv2Logic( + let last_p_hash = last_p_hash_option.ok_or(TProxyError::RolesSv2Logic( RolesLogicError::JobIsNotFutureButPrevHashNotPresent, ))?; diff --git a/roles/translator/src/lib/status.rs b/roles/translator/src/lib/status.rs index 3ecbcc634..2c7750136 100644 --- a/roles/translator/src/lib/status.rs +++ b/roles/translator/src/lib/status.rs @@ -1,4 +1,4 @@ -use crate::error::{self, Error}; +use crate::error::{self, TProxyError}; #[derive(Debug)] pub enum Sender { @@ -45,9 +45,9 @@ impl Clone for Sender { #[derive(Debug)] pub enum State<'a> { - DownstreamShutdown(Error<'a>), - BridgeShutdown(Error<'a>), - UpstreamShutdown(Error<'a>), + DownstreamShutdown(TProxyError<'a>), + BridgeShutdown(TProxyError<'a>), + UpstreamShutdown(TProxyError<'a>), Healthy(String), } @@ -58,7 +58,7 @@ pub struct Status<'a> { async fn send_status( sender: &Sender, - e: error::Error<'static>, + e: error::TProxyError<'static>, outcome: error_handling::ErrorBranch, ) -> error_handling::ErrorBranch { match sender { @@ -104,64 +104,81 @@ async fn send_status( // this is called by `error_handling::handle_result!` pub async fn handle_error( sender: &Sender, - e: error::Error<'static>, + e: error::TProxyError<'static>, ) -> error_handling::ErrorBranch { tracing::error!("Error: {:?}", &e); match e { - Error::VecToSlice32(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + TProxyError::ConfigError(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } + TProxyError::VecToSlice32(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } // Errors on bad CLI argument input. - Error::BadCliArgs => send_status(sender, e, error_handling::ErrorBranch::Break).await, + TProxyError::BadCliArgs => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Errors on bad `serde_json` serialize/deserialize. - Error::BadSerdeJson(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, - // Errors on bad `toml` deserialize. - Error::BadTomlDeserialize(_) => { + TProxyError::BadSerdeJson(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } // Errors from `binary_sv2` crate. - Error::BinarySv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + TProxyError::BinarySv2(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } // Errors on bad noise handshake. - Error::CodecNoise(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + TProxyError::CodecNoise(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } // Errors from `framing_sv2` crate. - Error::FramingSv2(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + TProxyError::FramingSv2(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } //If the pool sends the tproxy an invalid extranonce - Error::InvalidExtranonce(_) => { + TProxyError::InvalidExtranonce(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } // Errors on bad `TcpStream` connection. - Error::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + TProxyError::Io(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Errors on bad `String` to `int` conversion. - Error::ParseInt(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, + TProxyError::ParseInt(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } // Errors from `roles_logic_sv2` crate. - Error::RolesSv2Logic(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, - Error::UpstreamIncoming(_) => { + TProxyError::RolesSv2Logic(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } + TProxyError::UpstreamIncoming(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } // SV1 protocol library error - Error::V1Protocol(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, - Error::SubprotocolMining(_) => { + TProxyError::V1Protocol(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } + TProxyError::SubprotocolMining(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } // Locking Errors - Error::PoisonLock => send_status(sender, e, error_handling::ErrorBranch::Break).await, + TProxyError::PoisonLock => send_status(sender, e, error_handling::ErrorBranch::Break).await, // Channel Receiver Error - Error::ChannelErrorReceiver(_) => { + TProxyError::ChannelErrorReceiver(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } - Error::TokioChannelErrorRecv(_) => { + TProxyError::TokioChannelErrorRecv(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } // Channel Sender Errors - Error::ChannelErrorSender(_) => { + TProxyError::ChannelErrorSender(_) => { + send_status(sender, e, error_handling::ErrorBranch::Break).await + } + TProxyError::Uint256Conversion(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } - Error::Uint256Conversion(_) => { + TProxyError::SetDifficultyToMessage(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } - Error::SetDifficultyToMessage(_) => { + TProxyError::Infallible(_) => { send_status(sender, e, error_handling::ErrorBranch::Break).await } - Error::Infallible(_) => send_status(sender, e, error_handling::ErrorBranch::Break).await, - Error::Sv2ProtocolError(ref inner) => { + TProxyError::Sv2ProtocolError(ref inner) => { match inner { // dont notify main thread just continue roles_logic_sv2::parsers::Mining::SubmitSharesError(_) => { @@ -170,10 +187,10 @@ pub async fn handle_error( _ => send_status(sender, e, error_handling::ErrorBranch::Break).await, } } - Error::TargetError(_) => { + TProxyError::TargetError(_) => { send_status(sender, e, error_handling::ErrorBranch::Continue).await } - Error::Sv1MessageTooLong => { + TProxyError::Sv1MessageTooLong => { send_status(sender, e, error_handling::ErrorBranch::Break).await } } diff --git a/roles/translator/src/lib/proxy_config.rs b/roles/translator/src/lib/tproxy_config.rs similarity index 98% rename from roles/translator/src/lib/proxy_config.rs rename to roles/translator/src/lib/tproxy_config.rs index d0a835726..b660eff06 100644 --- a/roles/translator/src/lib/proxy_config.rs +++ b/roles/translator/src/lib/tproxy_config.rs @@ -2,7 +2,7 @@ use key_utils::Secp256k1PublicKey; use serde::Deserialize; #[derive(Debug, Deserialize, Clone)] -pub struct ProxyConfig { +pub struct TProxyConfig { pub upstream_address: String, pub upstream_port: u16, pub upstream_authority_pubkey: Secp256k1PublicKey, diff --git a/roles/translator/src/lib/upstream_sv2/diff_management.rs b/roles/translator/src/lib/upstream_sv2/diff_management.rs index 830bf28d8..9bc5be575 100644 --- a/roles/translator/src/lib/upstream_sv2/diff_management.rs +++ b/roles/translator/src/lib/upstream_sv2/diff_management.rs @@ -1,7 +1,7 @@ use super::Upstream; use super::super::{ - error::{Error::PoisonLock, ProxyResult}, + error::{TProxyError::PoisonLock, TProxyResult}, upstream_sv2::{EitherFrame, Message, StdFrame}, }; use binary_sv2::u256_from_int; @@ -12,7 +12,7 @@ use std::{sync::Arc, time::Duration}; impl Upstream { /// this function checks if the elapsed time since the last update has surpassed the config - pub(super) async fn try_update_hashrate(self_: Arc>) -> ProxyResult<'static, ()> { + pub(super) async fn try_update_hashrate(self_: Arc>) -> TProxyResult<'static, ()> { let (channel_id_option, diff_mgmt, tx_frame) = self_ .safe_lock(|u| { ( @@ -22,9 +22,9 @@ impl Upstream { ) }) .map_err(|_e| PoisonLock)?; - let channel_id = channel_id_option.ok_or(super::super::error::Error::RolesSv2Logic( - RolesLogicError::NotFoundChannelId, - ))?; + let channel_id = channel_id_option.ok_or( + super::super::error::TProxyError::RolesSv2Logic(RolesLogicError::NotFoundChannelId), + )?; let (timeout, new_hashrate) = diff_mgmt .safe_lock(|d| (d.channel_diff_update_interval, d.channel_nominal_hashrate)) .map_err(|_e| PoisonLock)?; @@ -39,7 +39,7 @@ impl Upstream { let frame: EitherFrame = either_frame.into(); tx_frame.send(frame).await.map_err(|e| { - super::super::error::Error::ChannelErrorSender( + super::super::error::TProxyError::ChannelErrorSender( super::super::error::ChannelSendError::General(e.to_string()), ) })?; diff --git a/roles/translator/src/lib/upstream_sv2/upstream.rs b/roles/translator/src/lib/upstream_sv2/upstream.rs index f6d192f75..2da5cf9c1 100644 --- a/roles/translator/src/lib/upstream_sv2/upstream.rs +++ b/roles/translator/src/lib/upstream_sv2/upstream.rs @@ -1,11 +1,11 @@ use crate::{ downstream_sv1::Downstream, error::{ - Error::{CodecNoise, InvalidExtranonce, PoisonLock, UpstreamIncoming}, - ProxyResult, + TProxyError::{CodecNoise, InvalidExtranonce, PoisonLock, UpstreamIncoming}, + TProxyResult, }, - proxy_config::UpstreamDifficultyConfig, status, + tproxy_config::UpstreamDifficultyConfig, upstream_sv2::{EitherFrame, Message, StdFrame, UpstreamConnection}, }; use async_channel::{Receiver, Sender}; @@ -124,7 +124,7 @@ impl Upstream { tx_status: status::Sender, target: Arc>>, difficulty_config: Arc>, - ) -> ProxyResult<'static, Arc>> { + ) -> TProxyResult<'static, Arc>> { // Connect to the SV2 Upstream role retry connection every 5 seconds. let socket = loop { match TcpStream::connect(address).await { @@ -179,7 +179,7 @@ impl Upstream { self_: Arc>, min_version: u16, max_version: u16, - ) -> ProxyResult<'static, ()> { + ) -> TProxyResult<'static, ()> { // Get the `SetupConnection` message with Mining Device information (currently hard coded) let setup_connection = Self::get_setup_connection_message(min_version, max_version, false)?; let mut connection = self_ @@ -257,7 +257,7 @@ impl Upstream { /// Parses the incoming SV2 message from the Upstream role and routes the message to the /// appropriate handler. #[allow(clippy::result_large_err)] - pub fn parse_incoming(self_: Arc>) -> ProxyResult<'static, ()> { + pub fn parse_incoming(self_: Arc>) -> TProxyResult<'static, ()> { let clone = self_.clone(); let ( tx_frame, @@ -300,7 +300,7 @@ impl Upstream { let message_type = incoming .get_header() - .ok_or(super::super::error::Error::FramingSv2( + .ok_or(super::super::error::TProxyError::FramingSv2( framing_sv2::Error::ExpectedSv2Frame, )); @@ -337,7 +337,7 @@ impl Upstream { handle_result!( tx_status, tx_frame.send(frame).await.map_err(|e| { - super::super::error::Error::ChannelErrorSender( + super::super::error::TProxyError::ChannelErrorSender( super::super::error::ChannelSendError::General(e.to_string()), ) }) @@ -439,26 +439,29 @@ impl Upstream { #[allow(clippy::result_large_err)] fn get_job_id( self_: &Arc>, - ) -> Result>, super::super::error::Error<'static>> - { + ) -> Result< + Result>, + super::super::error::TProxyError<'static>, + > { self_ .safe_lock(|s| { if s.is_work_selection_enabled() { s.last_job_id - .ok_or(super::super::error::Error::RolesSv2Logic( + .ok_or(super::super::error::TProxyError::RolesSv2Logic( RolesLogicError::NoValidTranslatorJob, )) } else { - s.job_id.ok_or(super::super::error::Error::RolesSv2Logic( - RolesLogicError::NoValidJob, - )) + s.job_id + .ok_or(super::super::error::TProxyError::RolesSv2Logic( + RolesLogicError::NoValidJob, + )) } }) .map_err(|_e| PoisonLock) } #[allow(clippy::result_large_err)] - pub fn handle_submit(self_: Arc>) -> ProxyResult<'static, ()> { + pub fn handle_submit(self_: Arc>) -> TProxyResult<'static, ()> { let clone = self_.clone(); let (tx_frame, receiver, tx_status) = clone .safe_lock(|s| { @@ -478,7 +481,7 @@ impl Upstream { let channel_id = self_ .safe_lock(|s| { s.channel_id - .ok_or(super::super::error::Error::RolesSv2Logic( + .ok_or(super::super::error::TProxyError::RolesSv2Logic( RolesLogicError::NotFoundChannelId, )) }) @@ -499,7 +502,7 @@ impl Upstream { handle_result!( tx_status, tx_frame.send(frame).await.map_err(|e| { - super::super::error::Error::ChannelErrorSender( + super::super::error::TProxyError::ChannelErrorSender( super::super::error::ChannelSendError::General(e.to_string()), ) }) @@ -521,7 +524,7 @@ impl Upstream { min_version: u16, max_version: u16, is_work_selection_enabled: bool, - ) -> ProxyResult<'static, SetupConnection<'static>> { + ) -> TProxyResult<'static, SetupConnection<'static>> { let endpoint_host = "0.0.0.0".to_string().into_bytes().try_into()?; let vendor = String::new().try_into()?; let hardware_version = String::new().try_into()?; diff --git a/roles/translator/src/lib/upstream_sv2/upstream_connection.rs b/roles/translator/src/lib/upstream_sv2/upstream_connection.rs index 49392b78e..b563ac91e 100644 --- a/roles/translator/src/lib/upstream_sv2/upstream_connection.rs +++ b/roles/translator/src/lib/upstream_sv2/upstream_connection.rs @@ -1,4 +1,4 @@ -use super::{super::error::ProxyResult, EitherFrame, StdFrame}; +use super::{super::error::TProxyResult, EitherFrame, StdFrame}; use async_channel::{Receiver, Sender}; /// Handles the sending and receiving of messages to and from an SV2 Upstream role (most typically @@ -18,10 +18,10 @@ pub struct UpstreamConnection { impl UpstreamConnection { /// Send a SV2 message to the Upstream role - pub async fn send(&mut self, sv2_frame: StdFrame) -> ProxyResult<'static, ()> { + pub async fn send(&mut self, sv2_frame: StdFrame) -> TProxyResult<'static, ()> { let either_frame = sv2_frame.into(); self.sender.send(either_frame).await.map_err(|e| { - super::super::error::Error::ChannelErrorSender( + super::super::error::TProxyError::ChannelErrorSender( super::super::error::ChannelSendError::General(e.to_string()), ) })?; diff --git a/roles/translator/src/main.rs b/roles/translator/src/main.rs index c1307a5a2..014e09693 100644 --- a/roles/translator/src/main.rs +++ b/roles/translator/src/main.rs @@ -2,10 +2,8 @@ mod args; mod lib; -use args::Args; -use error::{Error, ProxyResult}; -use lib::{downstream_sv1, error, proxy, proxy_config, status, upstream_sv2}; -use proxy_config::ProxyConfig; +use args::process_cli_args; +use lib::{downstream_sv1, error, proxy, status, tproxy_config, upstream_sv2}; use roles_logic_sv2::utils::Mutex; use async_channel::{bounded, unbounded}; @@ -21,19 +19,6 @@ use v1::server_to_client; use crate::status::{State, Status}; use tracing::{debug, error, info}; -/// Process CLI args, if any. -#[allow(clippy::result_large_err)] -fn process_cli_args<'a>() -> ProxyResult<'a, ProxyConfig> { - let args = match Args::from_args() { - Ok(cfg) => cfg, - Err(help) => { - error!("{}", help); - return Err(Error::BadCliArgs); - } - }; - let config_file = std::fs::read_to_string(args.config_path)?; - Ok(toml::from_str::(&config_file)?) -} #[tokio::main] async fn main() {