stratum.rs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::collections::HashMap;
  19. use darkfi::rpc::{
  20. jsonrpc::{ErrorCode, JsonError, JsonResponse, JsonResult},
  21. util::JsonValue,
  22. };
  23. use uuid::Uuid;
  24. use super::MiningProxy;
  25. /// Algo string representing Monero's RandomX
  26. pub const RANDOMX_ALGO: &str = "rx/0";
  27. impl MiningProxy {
  28. /// Stratum login method. `darkfi-mmproxy` will check that it is a valid worker
  29. /// login, and will also search for `RANDOMX_ALGO`.
  30. /// TODO: More proper error codes
  31. pub async fn stratum_login(&self, id: u16, params: JsonValue) -> JsonResult {
  32. let params = params.get::<Vec<JsonValue>>().unwrap();
  33. if params.len() != 1 || !params[0].is_object() {
  34. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  35. }
  36. let params = params[0].get::<HashMap<String, JsonValue>>().unwrap();
  37. if !params.contains_key("login") ||
  38. !params.contains_key("pass") ||
  39. !params.contains_key("agent") ||
  40. !params.contains_key("algo")
  41. {
  42. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  43. }
  44. let Some(login) = params["login"].get::<String>() else {
  45. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  46. };
  47. let Some(pass) = params["pass"].get::<String>() else {
  48. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  49. };
  50. let Some(agent) = params["agent"].get::<String>() else {
  51. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  52. };
  53. let Some(algos) = params["algo"].get::<Vec<JsonValue>>() else {
  54. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  55. };
  56. // We'll only support rx/0 algo.
  57. let mut found_xmr_algo = false;
  58. for algo in algos {
  59. if !algo.is_string() {
  60. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  61. }
  62. if algo.get::<String>().unwrap() == RANDOMX_ALGO {
  63. found_xmr_algo = true;
  64. break
  65. }
  66. }
  67. if !found_xmr_algo {
  68. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  69. }
  70. // Check valid login
  71. let Some(known_pass) = self.logins.get(login) else {
  72. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  73. };
  74. if known_pass != pass {
  75. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  76. }
  77. // Login success, generate UUID
  78. let uuid = Uuid::new_v4();
  79. todo!()
  80. }
  81. pub async fn stratum_submit(&self, id: u16, params: JsonValue) -> JsonResult {
  82. todo!()
  83. }
  84. /// Non standard but widely supported protocol extension. Miner sends `keepalived`
  85. /// to prevent connection timeout.
  86. pub async fn stratum_keepalived(&self, id: u16, params: JsonValue) -> JsonResult {
  87. let params = params.get::<Vec<JsonValue>>().unwrap();
  88. if params.len() != 1 || !params[0].is_object() {
  89. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  90. }
  91. let params = params[0].get::<HashMap<String, JsonValue>>().unwrap();
  92. if !params.contains_key("id") {
  93. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  94. }
  95. let Some(uuid) = params["id"].get::<String>() else {
  96. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  97. };
  98. if self.workers.read().await.contains_key(uuid) {
  99. return JsonResponse::new(
  100. JsonValue::Object(HashMap::from([(
  101. "status".to_string(),
  102. JsonValue::String("KEEPALIVED".to_string()),
  103. )])),
  104. id,
  105. )
  106. .into()
  107. }
  108. return JsonError::new(ErrorCode::InvalidParams, None, id).into()
  109. }
  110. }