Skip to content

Commit

Permalink
fix Stratum protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielKrawisz committed Sep 22, 2022
1 parent 507220c commit 7ce4195
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 55 deletions.
2 changes: 1 addition & 1 deletion extern/data
2 changes: 1 addition & 1 deletion include/gigamonkey/stratum/mining.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

namespace Gigamonkey::Stratum {

using job_id = uint32;
using job_id = string;

using worker_name = string;

Expand Down
3 changes: 2 additions & 1 deletion include/gigamonkey/stratum/mining_notify.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion include/gigamonkey/stratum/mining_submit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 2 additions & 2 deletions include/gigamonkey/stratum/mining_subscribe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
24 changes: 12 additions & 12 deletions include/gigamonkey/stratum/stratum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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());
Expand All @@ -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);
}

Expand All @@ -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);
}

Expand Down
53 changes: 23 additions & 30 deletions src/gigamonkey/stratum/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,37 @@ 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<bytes> 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) {
if (!j.is_string()) return false;
string str(j);
if (str.size() != 64) return false;
ptr<bytes> 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);
}

bool read(const json& j, bytes& x) {
if (!j.is_string()) return false;
string str(j);
ptr<bytes> b = encoding::hex::read(str);
if (b != nullptr) return false;
if (b == nullptr) return false;
x = *b;
return true;
}
Expand All @@ -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) {
Expand All @@ -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);
}

Expand All @@ -81,14 +73,14 @@ namespace Gigamonkey::Stratum::mining {
string str(j);
if (str.size() != 8) return false;
ptr<bytes> 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<uint32_little>(x)}, encoding::hex::lower);
}

Expand All @@ -97,14 +89,14 @@ namespace Gigamonkey::Stratum::mining {
string str(j);
if (str.size() != 8) return false;
ptr<bytes> 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);
}

Expand All @@ -113,18 +105,18 @@ namespace Gigamonkey::Stratum::mining {
string str(j);
if (str.size() != 8) return false;
ptr<bytes> 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;
Expand All @@ -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);
}

Expand All @@ -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() ||
Expand All @@ -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)};
}

Expand Down
6 changes: 2 additions & 4 deletions src/gigamonkey/stratum/mining_subscribe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@ 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]);
}

subscription::operator json() const {
parameters p;
p.resize(2);
p[0] = method_to_string(Method);
p[1] = session_id::serialize(ID);
p[1] = ID;
return p;
}

Expand Down
43 changes: 40 additions & 3 deletions test/testStratum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -124,8 +161,8 @@ namespace Gigamonkey::Stratum::mining {
std::vector<request_test_case> request_test_cases{{23, {"dk", 2}}, {45, {"dk"}}};

std::vector<response_test_case> 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);
Expand Down Expand Up @@ -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};
Expand Down

0 comments on commit 7ce4195

Please sign in to comment.