Skip to content

Commit f9f0510

Browse files
committed
dgb(test): lock CoinNode submit/seam contract (#82 RPC-fallback half)
Pin the embedded-primary / external-digibyted-RPC-fallback contract of dgb::coin::CoinNode (core::coin::ICoinNode) that the won-block dispatch relies on: web_server submits a solved block via m_coin_node->submit_block_hex(), which forwards to NodeRPC::submitblock (the external-daemon fallback that MUST persist alongside embedded). Three invariants, mirroring impl/bch/test/coin_node_seam_test.cpp: 1. no source -> empty WorkView, no throw 2. embedded, no rpc -> WorkView sourced from embedded 3. no rpc sink -> submit_block_hex == false (!m_rpc guard, no crash) The live submitblock call + m_on_block_found tracker callback are wired by the DGB run-loop standup (main_dgb.cpp is selftest-only today); that is the remaining #82 slice and is out of scope here (rpc=nullptr). Registered in test/CMakeLists.txt AND both build.yml --target allowlists (avoids the #143 NOT_BUILT-sentinel trap). 3/3 PASS, build EXIT=0.
1 parent 81fef6a commit f9f0510

3 files changed

Lines changed: 109 additions & 0 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ jobs:
6969
test_address_resolution test_compute_share_target \
7070
test_utxo test_dgb_subsidy dgb_share_test \
7171
rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \
72+
dgb_coin_node_seam_test \
7273
v37_test \
7374
-j$(nproc)
7475
@@ -197,6 +198,7 @@ jobs:
197198
test_address_resolution test_compute_share_target \
198199
test_utxo test_dgb_subsidy dgb_share_test \
199200
rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \
201+
dgb_coin_node_seam_test \
200202
test_coin_broadcaster test_multiaddress_pplns test_pplns_stress \
201203
v37_test \
202204
-j$(nproc)

src/impl/dgb/test/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,19 @@ if (BUILD_TESTING AND GTest_FOUND)
1717
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
1818
gtest_add_tests(dgb_share_test "" AUTO)
1919

20+
# --- #82 broadcaster-gate: CoinNode submit/seam contract -----------------
21+
# Links the dgb OBJECT lib (coin_node.cpp) like dgb_share_test so the live
22+
# CoinNode::submit_block_hex !m_rpc guard + embedded WorkView slice are
23+
# build- and run-verified. Pins the external-digibyted RPC fallback half of
24+
# the won-block dispatch (web_server -> ICoinNode::submit_block_hex).
25+
add_executable(dgb_coin_node_seam_test coin_node_seam_test.cpp)
26+
target_link_libraries(dgb_coin_node_seam_test PRIVATE
27+
GTest::gtest_main GTest::gtest
28+
core dgb
29+
c2pool_payout c2pool_merged_mining c2pool_hashrate c2pool_storage
30+
dgb_coin pool sharechain)
31+
gtest_add_tests(dgb_coin_node_seam_test "" AUTO)
32+
2033
# --- M3 RPC-transport standalone regression guards ---------------------
2134
# Header-only guards over the external-daemon RPC coin-layer SSOTs
2235
# (rpc_request.hpp request-shape + version floor + genesis identity, and
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// ---------------------------------------------------------------------------
2+
// dgb::coin::CoinNode seam-contract test (#82 broadcaster-gate, RPC-fallback
3+
// half).
4+
//
5+
// Locks the embedded-primary / external-RPC-fallback contract of the DGB
6+
// CoinNode seam (core::coin::ICoinNode) that the won-block dispatch depends on.
7+
// web_server.cpp submits a solved block through exactly this seam:
8+
// m_coin_node->submit_block_hex(hex, false) (core/web_server.cpp)
9+
// which forwards to NodeRPC::submitblock (the external-digibyted fallback that
10+
// MUST persist alongside the embedded path). This test pins the three
11+
// invariants that path relies on, so a regression here is caught before it can
12+
// silently break block submission:
13+
// 1. no work source at all -> empty WorkView, no throw
14+
// 2. embedded present, no RPC -> WorkView sourced from embedded;
15+
// is_embedded()=true, has_rpc()=false
16+
// 3. submit_block_hex w/ no RPC sink -> false (the !m_rpc guard, NOT a throw
17+
// and NOT a crash dereferencing null)
18+
//
19+
// SCOPE: the no-RPC guard + embedded WorkView slice only. The LIVE submitblock
20+
// RPC call and the m_on_block_found tracker callback are wired by the DGB
21+
// run-loop standup (NodeBridge + web_server; main_dgb.cpp is selftest-only
22+
// today) -- that is the remaining #82 slice and is NOT exercised here (rpc=
23+
// nullptr in every case). p2pool-merged-v36 surface: NONE (pure local seam).
24+
//
25+
// Mirrors src/impl/bch/test/coin_node_seam_test.cpp; written gtest-style to
26+
// match the sibling dgb tests (gtest_add_tests AUTO). MUST appear in BOTH the
27+
// test/CMakeLists.txt registration AND the build.yml --target allowlist or it
28+
// becomes a #143-style NOT_BUILT sentinel that reds master.
29+
// ---------------------------------------------------------------------------
30+
31+
#include <gtest/gtest.h>
32+
33+
#include <string>
34+
35+
#include "../coin/coin_node.hpp"
36+
37+
namespace {
38+
39+
// Minimal embedded work source: returns a recognisable WorkData so the test can
40+
// prove the seam moved THIS object's agnostic slice into the WorkView.
41+
class FakeEmbedded : public dgb::coin::CoinNodeInterface {
42+
public:
43+
int calls = 0;
44+
45+
dgb::coin::rpc::WorkData getwork() override {
46+
++calls;
47+
dgb::coin::rpc::WorkData wd;
48+
wd.m_data = nlohmann::json{{"marker", "embedded-dgb"}};
49+
wd.m_hashes.push_back(uint256(static_cast<uint64_t>(0xab)));
50+
wd.m_latency = 42;
51+
return wd;
52+
}
53+
54+
nlohmann::json getblockchaininfo() override { return nlohmann::json::object(); }
55+
bool is_synced() const override { return true; }
56+
};
57+
58+
} // namespace
59+
60+
// 1) No work source configured -> empty view, no throw (1:1 btc/bch/ltc ref).
61+
TEST(DgbCoinNodeSeam, NoSourceEmptyView) {
62+
dgb::coin::CoinNode n(nullptr, nullptr);
63+
EXPECT_FALSE(n.is_embedded());
64+
EXPECT_FALSE(n.has_rpc());
65+
core::coin::WorkView v = n.get_work_view();
66+
EXPECT_TRUE(v.m_data.is_null() || v.m_data.empty());
67+
EXPECT_TRUE(v.m_hashes.empty());
68+
EXPECT_EQ(v.m_latency, 0);
69+
}
70+
71+
// 2) Embedded preferred, no RPC fallback wired -> view comes from embedded.
72+
TEST(DgbCoinNodeSeam, EmbeddedSourcedView) {
73+
FakeEmbedded emb;
74+
dgb::coin::CoinNode n(&emb, /*rpc=*/nullptr);
75+
EXPECT_TRUE(n.is_embedded());
76+
EXPECT_FALSE(n.has_rpc());
77+
core::coin::WorkView v = n.get_work_view();
78+
EXPECT_EQ(emb.calls, 1); // embedded WAS the source
79+
ASSERT_TRUE(v.m_data.contains("marker"));
80+
EXPECT_EQ(v.m_data["marker"], "embedded-dgb");
81+
EXPECT_EQ(v.m_hashes.size(), 1u);
82+
EXPECT_EQ(v.m_latency, 42);
83+
}
84+
85+
// 3) No RPC sink -> submit_block_hex returns false (the !m_rpc guard), not a
86+
// throw and not a null-deref crash. This is the won-block fallback contract.
87+
TEST(DgbCoinNodeSeam, SubmitNoRpcReturnsFalse) {
88+
FakeEmbedded emb;
89+
dgb::coin::CoinNode n(&emb, /*rpc=*/nullptr);
90+
EXPECT_FALSE(n.submit_block_hex("00", /*ignore_failure=*/true));
91+
92+
dgb::coin::CoinNode bare(nullptr, nullptr);
93+
EXPECT_FALSE(bare.submit_block_hex("00", /*ignore_failure=*/false));
94+
}

0 commit comments

Comments
 (0)