diff --git a/extern/data b/extern/data index 22f5b4da..da675047 160000 --- a/extern/data +++ b/extern/data @@ -1 +1 @@ -Subproject commit 22f5b4da12f67e57cf4d621997a6ec06954ca937 +Subproject commit da675047683dde5348ce2a1375ae1769e5a79643 diff --git a/include/gigamonkey/stratum/mining.hpp b/include/gigamonkey/stratum/mining.hpp index f9d11f89..be3b8acb 100644 --- a/include/gigamonkey/stratum/mining.hpp +++ b/include/gigamonkey/stratum/mining.hpp @@ -11,7 +11,7 @@ namespace Gigamonkey::Stratum { - using job_id = uint32; + using job_id = string; using worker_name = string; diff --git a/include/gigamonkey/stratum/mining_notify.hpp b/include/gigamonkey/stratum/mining_notify.hpp index 0425fe59..ff34de33 100644 --- a/include/gigamonkey/stratum/mining_notify.hpp +++ b/include/gigamonkey/stratum/mining_notify.hpp @@ -12,7 +12,8 @@ namespace Gigamonkey::Stratum::mining { // Representation of a Stratum notify message. - struct notify : notification { + struct notify : notification { + struct parameters { job_id JobID; diff --git a/include/gigamonkey/stratum/mining_submit.hpp b/include/gigamonkey/stratum/mining_submit.hpp index f5973ddf..1df6f371 100644 --- a/include/gigamonkey/stratum/mining_submit.hpp +++ b/include/gigamonkey/stratum/mining_submit.hpp @@ -31,7 +31,7 @@ namespace Gigamonkey::Stratum::mining { inline submit_request::submit_request(message_id id, const share& x) : request{id, mining_submit, serialize(x)} {} bool inline submit_request::valid(const request& r) { - return deserialize(r).valid(); + return r.valid() && deserialize(r.params()).valid(); } bool inline submit_request::valid() const { diff --git a/include/gigamonkey/stratum/mining_subscribe.hpp b/include/gigamonkey/stratum/mining_subscribe.hpp index fb5b0dcc..0d939c16 100644 --- a/include/gigamonkey/stratum/mining_subscribe.hpp +++ b/include/gigamonkey/stratum/mining_subscribe.hpp @@ -11,10 +11,10 @@ namespace Gigamonkey::Stratum::mining { struct subscription { method Method; - session_id ID; + string ID; subscription() : Method{unset}, ID{} {} - subscription(method m, session_id id) : Method{m}, ID{id} {} + subscription(method m, string id) : Method{m}, ID{id} {} explicit subscription(const json&); explicit operator json() const; diff --git a/include/gigamonkey/stratum/stratum.hpp b/include/gigamonkey/stratum/stratum.hpp index 77c9db91..f1acf998 100644 --- a/include/gigamonkey/stratum/stratum.hpp +++ b/include/gigamonkey/stratum/stratum.hpp @@ -31,7 +31,7 @@ namespace Gigamonkey::Stratum { notification(); notification(Stratum::method m, const parameters& p); - explicit notification(const json& j) : json{j} {} + explicit notification(const json& j) : json(j) {} }; struct request : json { @@ -50,7 +50,7 @@ namespace Gigamonkey::Stratum { request(); request(message_id id, Stratum::method m, const parameters& p); - explicit request(const json& j) : json{j} {} + explicit request(const json& j) : json(j) {} }; struct response : json { @@ -72,7 +72,7 @@ namespace Gigamonkey::Stratum { response(); response(message_id id, const json& p); response(message_id id, const json& p, const Stratum::error& e); - explicit response(const json& j) : json{j} {} + explicit response(const json& j) : json(j) {} bool is_error() const { return bool(error()); @@ -85,23 +85,23 @@ namespace Gigamonkey::Stratum { inline request::request(message_id id, Stratum::method m, const parameters& p) : json{{"id", id}, {"method", method_to_string(m)}, {"params", p}} {} - inline bool request::valid(const json& j) { + bool inline request::valid(const json& j) { return request::method(j) != unset && j.contains("params") && j["params"].is_array() && j.contains("id") && message_id::valid(j["id"]); } - inline bool request::valid() const { + bool inline request::valid() const { return valid(*this); } - inline message_id request::id() const { + message_id inline request::id() const { return id(*this); } - inline Stratum::method request::method() const { + Stratum::method inline request::method() const { return method(*this); } - inline parameters request::params() const { + parameters inline request::params() const { return params(*this); } @@ -110,19 +110,19 @@ namespace Gigamonkey::Stratum { inline notification::notification(Stratum::method m, const parameters& p) : json{{"id", nullptr}, {"method"}, {"params", p}} {} - inline bool notification::valid(const json& j) { + bool inline notification::valid(const json& j) { return notification::method(j) != unset && j.contains("params") && j["params"].is_array() && j.contains("id") && j["id"].is_null(); } - inline bool notification::valid() const { + bool inline notification::valid() const { return valid(*this); } - inline Stratum::method notification::method() const { + Stratum::method inline notification::method() const { return method(*this); } - inline parameters notification::params() const { + parameters inline notification::params() const { return params(*this); } diff --git a/src/gigamonkey/stratum/mining.cpp b/src/gigamonkey/stratum/mining.cpp index b9aaddc3..009fb25c 100644 --- a/src/gigamonkey/stratum/mining.cpp +++ b/src/gigamonkey/stratum/mining.cpp @@ -7,24 +7,16 @@ namespace Gigamonkey::Stratum::mining { namespace { - inline encoding::hex::fixed<4> write_job_id(const job_id& x) { - return encoding::hex::write(uint32_big{x}, encoding::hex::lower); - } - bool read_job_id(const json& j, job_id& x) { if (!j.is_string()) return false; - string str(j); - if (str.size() != 8) return false; - ptr b = encoding::hex::read(str); - if (b != nullptr) return false; - uint32_big n; - std::copy(b->begin(), b->end(), n.begin()); - x = uint32(n); + x = string(j); return true; } - inline encoding::hex::fixed<32> write(const uint256& x) { - return encoding::hex::write(x, encoding::hex::lower); + encoding::hex::fixed<32> inline write(const uint256& x) { + uint256 z = x; + for (int i = 0; i < 32; i+=4) std::reverse(z.begin() + i, z.begin() + i + 3); + return encoding::hex::write(z, encoding::hex::lower); } bool read(const json& j, uint256& x) { @@ -32,12 +24,12 @@ namespace Gigamonkey::Stratum::mining { string str(j); if (str.size() != 64) return false; ptr b = encoding::hex::read(str); - if (b != nullptr) return false; - std::copy(b->begin(), b->end(), x.begin()); + if (b == nullptr) return false; + for (int i = 0; i < 8; i++) for (int j = 0; j < 4; j++) x[4 * i + j] = *(b->begin() + 4 * (i + 1) - j - 1); return true; } - inline encoding::hex::string write(const bytes& b) { + encoding::hex::string inline write(const bytes& b) { return encoding::hex::write(b, encoding::hex::lower); } @@ -45,7 +37,7 @@ namespace Gigamonkey::Stratum::mining { if (!j.is_string()) return false; string str(j); ptr b = encoding::hex::read(str); - if (b != nullptr) return false; + if (b == nullptr) return false; x = *b; return true; } @@ -61,7 +53,7 @@ namespace Gigamonkey::Stratum::mining { return p; } - inline bool read(const json& j, Merkle::digests& x) { + bool inline read(const json& j, Merkle::digests& x) { if (!j.is_array()) return false; x = {}; for (json d : j) { @@ -72,7 +64,7 @@ namespace Gigamonkey::Stratum::mining { return true; } - inline encoding::hex::fixed<4> write(const int32_little& x) { + encoding::hex::fixed<4> inline write(const int32_little& x) { return encoding::hex::write(x, encoding::hex::lower); } @@ -81,14 +73,14 @@ namespace Gigamonkey::Stratum::mining { string str(j); if (str.size() != 8) return false; ptr b = encoding::hex::read(str); - if (b != nullptr) return false; + if (b == nullptr) return false; int32_big n; std::copy(b->begin(), b->end(), n.begin()); x = int32_little(n); return true; } - inline encoding::hex::fixed<4> write(const work::compact& x) { + encoding::hex::fixed<4> inline write(const work::compact& x) { return encoding::hex::write(uint32_big{static_cast(x)}, encoding::hex::lower); } @@ -97,14 +89,14 @@ namespace Gigamonkey::Stratum::mining { string str(j); if (str.size() != 8) return false; ptr b = encoding::hex::read(str); - if (b != nullptr) return false; + if (b == nullptr) return false; uint32_big n; std::copy(b->begin(), b->end(), n.begin()); x = work::compact(uint32_little(n)); return true; } - inline encoding::hex::fixed<4> write(const Bitcoin::timestamp& x) { + encoding::hex::fixed<4> inline write(const Bitcoin::timestamp& x) { return encoding::hex::write(uint32_big{x.Value}, encoding::hex::lower); } @@ -113,18 +105,18 @@ namespace Gigamonkey::Stratum::mining { string str(j); if (str.size() != 8) return false; ptr b = encoding::hex::read(str); - if (b != nullptr) return false; + if (b == nullptr) return false; uint32_big n; std::copy(b->begin(), b->end(), n.begin()); x = Bitcoin::timestamp(uint32_little(n)); return true; } - inline encoding::hex::fixed<8> write(const uint64_big& x) { + encoding::hex::fixed<8> inline write(const uint64_big& x) { return encoding::hex::write(x, encoding::hex::lower); } - inline bool read(const json& j, uint64_big& x) { + bool inline read(const json& j, uint64_big& x) { if (!j.is_string()) return false; string str(j); if (str.size() != 16) return false; @@ -133,7 +125,7 @@ namespace Gigamonkey::Stratum::mining { return true; } - inline encoding::hex::fixed<4> write(const nonce& x) { + encoding::hex::fixed<4> inline write(const nonce& x) { return encoding::hex::write(uint32_big{x}, encoding::hex::lower); } @@ -151,11 +143,12 @@ namespace Gigamonkey::Stratum::mining { } parameters notify::serialize(const parameters& p) { - return Stratum::parameters{write_job_id(p.JobID), write(p.Digest), write(p.GenerationTx1), write(p.GenerationTx2), + return Stratum::parameters{p.JobID, write(p.Digest), write(p.GenerationTx1), write(p.GenerationTx2), write(p.Path), write(p.Version), write(p.Target), write(p.Now), p.Clean}; } notify::parameters notify::deserialize(const Stratum::parameters& n) { + parameters p; if (n.size() != 9 || !n[8].is_boolean() || @@ -174,10 +167,10 @@ namespace Gigamonkey::Stratum::mining { } parameters submit_request::serialize(const share& Share) { - if (Share.Share.Bits) return parameters{Share.Name, write_job_id(Share.JobID), write(Share.Share.ExtraNonce2), + if (Share.Share.Bits) return parameters{Share.Name, Share.JobID, write(Share.Share.ExtraNonce2), write(Share.Share.Timestamp), write(Share.Share.Nonce), write(*Share.Share.Bits)}; - return parameters{Share.Name, write_job_id(Share.JobID), write(Share.Share.ExtraNonce2), + return parameters{Share.Name, Share.JobID, write(Share.Share.ExtraNonce2), write(Share.Share.Timestamp), write(Share.Share.Nonce)}; } diff --git a/src/gigamonkey/stratum/mining_subscribe.cpp b/src/gigamonkey/stratum/mining_subscribe.cpp index 67e04ab1..02bdec48 100644 --- a/src/gigamonkey/stratum/mining_subscribe.cpp +++ b/src/gigamonkey/stratum/mining_subscribe.cpp @@ -7,9 +7,7 @@ namespace Gigamonkey::Stratum::mining { subscription::subscription(const json& j) : subscription{} { if (!(j.is_array() && j.size() == 2 && j[0].is_string())) return; - auto id = session_id::deserialize(j[1]); - if (!id) return; - ID = *id; + ID = j[1]; Method = method_from_string(j[0]); } @@ -17,7 +15,7 @@ namespace Gigamonkey::Stratum::mining { parameters p; p.resize(2); p[0] = method_to_string(Method); - p[1] = session_id::serialize(ID); + p[1] = ID; return p; } diff --git a/test/testStratum.cpp b/test/testStratum.cpp index 6944df25..1fc092c1 100644 --- a/test/testStratum.cpp +++ b/test/testStratum.cpp @@ -35,6 +35,43 @@ namespace Gigamonkey::Stratum { EXPECT_EQ(id_b, *j_id_b); } + TEST(StratumTest, TestStratumPuzzle) { + + mining::subscribe_response subscribe_response{json::parse( + R"({"id": 1, "result": [ [ ["mining.set_difficulty", "b4b6693b72a50c7116db18d6497cac52"], ["mining.notify", "ae6812eb4cd7735a302a8a9dd95cf71f"]], "08000002", 4], "error": null})")}; + + mining::subscribe_response::parameters srparams = subscribe_response.result(); + + EXPECT_TRUE(subscribe_response.valid()); + + mining::notify notify{json::parse( + R"({"params": + ["bf", "4d16b6f85af6e2198f44ae2a6de67f78487ae5611b77c6c0440b921e00000000", + "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff20020862062f503253482f04b8864e5008", + "072f736c7573682f000000000100f2052a010000001976a914d23fcdf86f7e756a64a7a9688ef9903327048ed988ac00000000", + [], "00000002", "1c2ac4af", "504e86b9", false], + "id": null, "method": "mining.notify"})")}; + + EXPECT_TRUE(notify.valid()); + + mining::submit_request submit_request{json::parse( + R"({"params": ["slush.miner1", "bf", "00000001", "504e86ed", "b2957c02"], + "id": 4, "method": "mining.submit"})")}; + + EXPECT_TRUE(submit_request.valid()); + + digest256 expected_block_hash{"32abdc31d947623a2482144f92dbc092a84fd8ee6e2b5ae60f87762000000000"}; + digest256 expected_prev_hash{"f8b6164d19e2f65a2aae448f787fe66d61e57a48c0c6771b1e920b4400000000"}; + + proof p{worker{"Daniel", subscribe_response.result().ExtraNonce}, notify.params(), submit_request.params()}; + + EXPECT_TRUE(p.valid()); + work::string z = work::proof(p).string(); + EXPECT_EQ(expected_block_hash, z.hash()); + EXPECT_EQ(z.Digest, expected_prev_hash); + + } + } namespace Gigamonkey::Stratum::mining { @@ -124,8 +161,8 @@ namespace Gigamonkey::Stratum::mining { std::vector request_test_cases{{23, {"dk", 2}}, {45, {"dk"}}}; std::vector response_test_cases { - {23, {{subscription{mining_set_difficulty, 1}, subscription{mining_notify, 2}}, {7, 8}}}, - {45, {{subscription{mining_notify, 3}}, {30, 8}}}}; + {23, {{subscription{mining_set_difficulty, "1"}, subscription{mining_notify, "2"}}, {7, 8}}}, + {45, {{subscription{mining_notify, "3"}}, {30, 8}}}}; for (const auto& i : request_test_cases) for (const auto& j : request_test_cases) { auto request_i = subscribe_request(i); @@ -241,7 +278,7 @@ namespace Gigamonkey::Stratum::mining { } TEST(StratumTest, TestStratumProof) { - job_id jid = 2333; + job_id jid = "2333"; extranonce en{1, 8}; int32_little version = 2; Bitcoin::timestamp timestamp{3};