Skip to content

Commit 00c39eb

Browse files
committed
dgb: M3 RPC request-shape SSOT + standalone regression guard
Factor the two oracle-pinned external-RPC contract values out of rpc.cpp into a pure, dependency-light header (coin/rpc_request.hpp) so they have a single source of truth and can be guarded by a standalone test that does NOT link the boost::beast/jsonrpccxx transport (never enters the dgb OBJECT lib): - DGB_MIN_DAEMON_VERSION / daemon_version_acceptable(): getnetworkinfo [version] accept floor, conformed to oracle frstrtr/p2pool-dgb-scrypt VERSION_CHECK == 82202 (DigiByte Core 7.17.2). - make_gbt_request(): getblocktemplate body {rules:[...],algo:scrypt} -- segwit rule mandatory, scrypt is a SEPARATE algo param, never a rule. rpc.cpp now consumes the header (behaviour-identical: version compare and GBT body unchanged on the wire). Adds test/rpc_request_test.cpp (8 gtest cases) pinning the floor accept/reject boundary (82202 ok / 82201,71700 reject) and the GBT shape incl. the Path-A scrypt-as-rule regression. Standalone build-verified: g++ -std=c++20, link libgtest -> 8/8 PASS; rpc.cpp -fsyntax-only EXIT=0. No CMake/OBJECT-lib wiring (deferred post land-stack); additive coin-layer source only.
1 parent 24515a7 commit 00c39eb

3 files changed

Lines changed: 143 additions & 11 deletions

File tree

src/impl/dgb/coin/rpc.cpp

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <impl/dgb/config_pool.hpp>
44
#include <impl/dgb/coin/softfork_check.hpp>
5+
#include <impl/dgb/coin/rpc_request.hpp>
56

67
#include <core/log.hpp>
78
#include <core/hash.hpp>
@@ -19,12 +20,7 @@ static const char* DGB_GENESIS_MAIN =
1920
static const char* DGB_GENESIS_TEST =
2021
"308ea0711d5763be2995670dd9ca9872753561285a84da1d58be58acaa822252";
2122

22-
// Minimum acceptable digibyted getnetworkinfo[\"version\"] int.
23-
// Floor conformed to oracle frstrtr/p2pool-dgb-scrypt networks/digibyte.py:
24-
// VERSION_CHECK = lambda v: None if 82202 <= v else \"...Upgrade to 7.17.2 or newer!\"
25-
// i.e. DigiByte Core 7.17.2 (oracle HEAD 22761e7). Same getnetworkinfo version field
26-
// the oracle gates on, so the comparison below is byte-for-byte oracle-equivalent.
27-
static constexpr int DGB_MIN_DAEMON_VERSION = 82202;
23+
// DGB_MIN_DAEMON_VERSION / make_gbt_request: see impl/dgb/coin/rpc_request.hpp (oracle SSOT).
2824

2925
NodeRPC::NodeRPC(io::io_context* context, dgb::interfaces::Node* coin, bool testnet)
3026
: m_context(context), IS_TESTNET(testnet), m_resolver(*context), m_stream(*context),
@@ -223,7 +219,7 @@ bool NodeRPC::check()
223219
try
224220
{
225221
auto networkinfo = getnetworkinfo();
226-
bool version_check_result = (DGB_MIN_DAEMON_VERSION <= networkinfo["version"].get<int>());
222+
bool version_check_result = daemon_version_acceptable(networkinfo["version"].get<int>());
227223
if (!version_check_result)
228224
{
229225
LOG_ERROR << "DigiByte daemon too old! Upgrade!";
@@ -408,10 +404,8 @@ bool NodeRPC::submit_block_hex(const std::string& block_hex, bool ignore_failure
408404

409405
nlohmann::json NodeRPC::getblocktemplate(std::vector<std::string> rules)
410406
{
411-
// DGB GBT: segwit rule set is mandatory (digibyted rejects otherwise), and
412-
// the mining algorithm is a separate top-level param. V36 is Scrypt-only.
413-
nlohmann::json j = nlohmann::json::object({{"rules", rules}, {"algo", "scrypt"}});
414-
return CallAPIMethod("getblocktemplate", {j});
407+
// Body shape (segwit rule + separate Scrypt algo param) is the rpc_request.hpp SSOT.
408+
return CallAPIMethod("getblocktemplate", {make_gbt_request(rules)});
415409
}
416410

417411
nlohmann::json NodeRPC::getnetworkinfo()

src/impl/dgb/coin/rpc_request.hpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#pragma once
2+
3+
// ---------------------------------------------------------------------------
4+
// dgb::coin -- M3 RPC request-shape SSOT (pure, dependency-light).
5+
//
6+
// Single source of truth for the two oracle-pinned external-RPC contract
7+
// values that NodeRPC::check()/getwork() depend on, factored out of rpc.cpp
8+
// so a standalone test TU can guard them WITHOUT linking the boost::beast /
9+
// jsonrpccxx transport (i.e. without entering the dgb OBJECT lib):
10+
//
11+
// 1. DGB_MIN_DAEMON_VERSION -- the getnetworkinfo["version"] accept floor,
12+
// conformed to oracle frstrtr/p2pool-dgb-scrypt networks/digibyte.py
13+
// VERSION_CHECK (82202 == DigiByte Core 7.17.2, oracle HEAD 22761e7).
14+
// 2. make_gbt_request() -- DigiByte getblocktemplate body. DGB GBT requires
15+
// the "segwit" rule AND a SEPARATE top-level "algo" param; V36 is
16+
// Scrypt-only so algo is always "scrypt". "scrypt" is the mining
17+
// algorithm, NOT a BIP9 rule -- the prior Path-A stub note rules=
18+
// ["scrypt"] was wrong; the shape is {"rules":[...],"algo":"scrypt"}.
19+
//
20+
// Header-only + nlohmann-only: includes nothing from the transport stack, so
21+
// it builds on master today and the guard test is a clean standalone link.
22+
// ---------------------------------------------------------------------------
23+
24+
#include <string>
25+
#include <vector>
26+
27+
#include <nlohmann/json.hpp>
28+
29+
namespace dgb
30+
{
31+
32+
namespace coin
33+
{
34+
35+
// Minimum acceptable digibyted getnetworkinfo["version"] int (oracle-equivalent
36+
// to p2pool-dgb-scrypt VERSION_CHECK: floor 82202 == DigiByte Core 7.17.2).
37+
inline constexpr int DGB_MIN_DAEMON_VERSION = 82202;
38+
39+
// True iff a daemon advertising getnetworkinfo["version"]==v clears the floor.
40+
inline bool daemon_version_acceptable(int version)
41+
{
42+
return DGB_MIN_DAEMON_VERSION <= version;
43+
}
44+
45+
// Build the DigiByte getblocktemplate request body: segwit rule(s) plus the
46+
// mandatory separate Scrypt algo param. V36 c2pool-dgb is Scrypt-only.
47+
inline nlohmann::json make_gbt_request(const std::vector<std::string>& rules)
48+
{
49+
return nlohmann::json::object({{"rules", rules}, {"algo", "scrypt"}});
50+
}
51+
52+
} // namespace coin
53+
54+
} // namespace dgb
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// ---------------------------------------------------------------------------
2+
// dgb M3 RPC request-shape regression guard.
3+
//
4+
// Pins the two oracle-conformed external-RPC contract values that NodeRPC
5+
// depends on, BEFORE the deferred wiring (CMake + OBJECT-lib reg + ctor swap)
6+
// lands post-#145 and rpc.cpp finally CI-links. Guards against silent drift of:
7+
//
8+
// 1. the getnetworkinfo["version"] accept floor (oracle p2pool-dgb-scrypt
9+
// VERSION_CHECK == 82202, DigiByte Core 7.17.2), and
10+
// 2. the getblocktemplate body shape: DGB requires the "segwit" rule AND a
11+
// SEPARATE top-level "algo":"scrypt" param -- "scrypt" must NOT leak into
12+
// the rules array (the prior Path-A stub bug rules=["scrypt"]).
13+
//
14+
// Links ONLY the pure SSOT header (rpc_request.hpp) + nlohmann + gtest -- no
15+
// boost::beast/jsonrpccxx transport, so it builds standalone without entering
16+
// the dgb OBJECT lib.
17+
// ---------------------------------------------------------------------------
18+
19+
#include <gtest/gtest.h>
20+
21+
#include <impl/dgb/coin/rpc_request.hpp>
22+
23+
using namespace dgb::coin;
24+
25+
// --- Daemon-version accept floor (oracle VERSION_CHECK 82202) ---------------
26+
27+
TEST(DgbRpcRequest, VersionFloorIsOracleValue)
28+
{
29+
EXPECT_EQ(DGB_MIN_DAEMON_VERSION, 82202); // DigiByte Core 7.17.2
30+
}
31+
32+
TEST(DgbRpcRequest, VersionAtFloorAccepts)
33+
{
34+
EXPECT_TRUE(daemon_version_acceptable(82202));
35+
}
36+
37+
TEST(DgbRpcRequest, VersionAboveFloorAccepts)
38+
{
39+
EXPECT_TRUE(daemon_version_acceptable(82203));
40+
EXPECT_TRUE(daemon_version_acceptable(90000));
41+
}
42+
43+
TEST(DgbRpcRequest, VersionBelowFloorRejects)
44+
{
45+
EXPECT_FALSE(daemon_version_acceptable(82201));
46+
EXPECT_FALSE(daemon_version_acceptable(71700)); // old placeholder floor
47+
EXPECT_FALSE(daemon_version_acceptable(0));
48+
}
49+
50+
// --- getblocktemplate request body shape ------------------------------------
51+
52+
TEST(DgbRpcRequest, GbtCarriesSeparateScryptAlgo)
53+
{
54+
auto j = make_gbt_request({"segwit"});
55+
ASSERT_TRUE(j.contains("algo"));
56+
EXPECT_EQ(j["algo"].get<std::string>(), "scrypt");
57+
}
58+
59+
TEST(DgbRpcRequest, GbtRulesContainSegwit)
60+
{
61+
auto j = make_gbt_request({"segwit"});
62+
ASSERT_TRUE(j.contains("rules"));
63+
ASSERT_TRUE(j["rules"].is_array());
64+
ASSERT_EQ(j["rules"].size(), 1u);
65+
EXPECT_EQ(j["rules"][0].get<std::string>(), "segwit");
66+
}
67+
68+
TEST(DgbRpcRequest, ScryptIsAlgoNotRule)
69+
{
70+
// Regression guard for the Path-A bug: "scrypt" is the mining algorithm,
71+
// NOT a BIP9 rule -- it must never appear in the rules array.
72+
auto j = make_gbt_request({"segwit"});
73+
for (const auto& r : j["rules"])
74+
EXPECT_NE(r.get<std::string>(), "scrypt");
75+
}
76+
77+
TEST(DgbRpcRequest, GbtPreservesCallerRulesAndForcesScrypt)
78+
{
79+
auto j = make_gbt_request({"segwit", "!extra"});
80+
ASSERT_EQ(j["rules"].size(), 2u);
81+
EXPECT_EQ(j["rules"][0].get<std::string>(), "segwit");
82+
EXPECT_EQ(j["rules"][1].get<std::string>(), "!extra");
83+
EXPECT_EQ(j["algo"].get<std::string>(), "scrypt");
84+
}

0 commit comments

Comments
 (0)