Skip to content

Commit b8903fd

Browse files
authored
Merge pull request #447 from frstrtr/dash/s8-dual-arm-plan
dash(s8): WonBlock dual-arm delivery plan + reached-network verdict
2 parents e07b2c4 + 7eda6a8 commit b8903fd

4 files changed

Lines changed: 393 additions & 2 deletions

File tree

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ jobs:
7272
test_threading test_weights \
7373
test_header_chain test_mempool test_template_builder \
7474
test_doge_chain test_compact_blocks test_dash_x11_kat \
75-
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding \
75+
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm \
7676
test_multiaddress_pplns test_pplns_stress \
7777
test_hash_link test_decay_pplns \
7878
test_pplns_consensus \
@@ -205,7 +205,7 @@ jobs:
205205
test_threading test_weights \
206206
test_header_chain test_mempool test_template_builder \
207207
test_doge_chain test_compact_blocks test_dash_x11_kat \
208-
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding \
208+
test_dash_header_chain test_dash_block_replay test_dash_conformance test_dash_subsidy test_dash_mempool test_dash_simplifiedmns test_dash_quorum test_dash_quorum_root test_dash_mn_state test_dash_embedded_gbt test_dash_smldiff test_dash_p2p_messages test_dash_p2p_connection test_dash_p2p_node test_dash_node_interface test_dash_config test_dash_broadcaster test_dash_broadcaster_full test_dash_share_hash_link test_dash_block_relay test_dash_rpc_request test_dash_rpc_conf test_dash_block_producer test_dash_embedded_relay_e2e test_dash_block_relay_plan test_dash_version_activation_latch test_dash_block_relay_binding test_dash_block_relay_dual_arm \
209209
test_hash_link test_decay_pplns \
210210
test_pplns_consensus \
211211
test_v36_script_sorting test_v36_cross_impl_refhash \
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#pragma once
2+
3+
// Phase S8 — WonBlock dual-arm delivery plan + reached-network verdict (LEAF).
4+
//
5+
// THE last PURE rung before the operator-gated broadcaster_full keystone. The
6+
// binding (block_relay_binding.hpp) joins the live broadcaster pool to the
7+
// planner and yields an AnnouncePlan (one inv frame + the live slot keys). A won
8+
// block must reach the network by EITHER of two independent arms:
9+
//
10+
// [won block] --+-- embedded-P2P arm -- inv fan-out to live pool slots
11+
// +-- dashd submitblock -- raw-block RPC fallback
12+
//
13+
// This leaf decides, as INERT data, WHICH arms a given won block is armed on,
14+
// and (separately) evaluates whether the block actually REACHED the network once
15+
// the keystone has executed both arms and reported their results. It performs no
16+
// I/O: it opens no socket, drives no io_context, issues no RPC, recomputes no
17+
// hash. The keystone walks the plan, writes the inv frames onto the live slots'
18+
// sockets, calls dashd submitblock with the raw bytes, collects the per-arm
19+
// results, and hands them back to evaluate() for the won-block-reaches-network
20+
// verdict. That transmit + RPC is the keystone's operator-gated concern; the
21+
// DECISION of arms and the verdict LOGIC are pure and unit-testable here, with
22+
// zero sockets and zero live dashd, like every sibling leaf.
23+
//
24+
// SCOPE / NON-CONSENSUS: single dash tree, header-only, socket-free. The raw
25+
// block bytes are an OPAQUE, caller-supplied blob (the won block as captured for
26+
// submission, the same span the broadcaster's submit_block_raw_all / FanOutHook
27+
// already consume) -- they are carried verbatim, NOT re-serialized here, and no
28+
// consensus value is computed or altered.
29+
30+
#include "block_relay_binding.hpp"
31+
#include "block_relay_plan.hpp"
32+
33+
#include <core/uint256.hpp>
34+
35+
#include <cstddef>
36+
#include <span>
37+
#include <utility>
38+
#include <vector>
39+
40+
namespace dash
41+
{
42+
43+
// The dual-arm delivery plan for ONE won block: the embedded-P2P fan-out plan
44+
// plus the raw block bytes for the dashd submitblock fallback, each tagged with
45+
// whether that arm is armed. The submitblock arm is armed whenever raw bytes are
46+
// present, INDEPENDENT of live-slot count -- so a won block with zero live peers
47+
// still ships via dashd. The P2P arm is armed only when the live pool is
48+
// non-empty. Both arms are INERT: nothing is transmitted until the keystone
49+
// walks this plan.
50+
struct DualArmPlan
51+
{
52+
AnnouncePlan p2p; // inv frame + live slot keys
53+
std::vector<unsigned char> submitblock_bytes; // raw won block (opaque)
54+
bool p2p_armed{false}; // live pool non-empty
55+
bool submitblock_armed{false}; // raw bytes present
56+
57+
// True if the block is armed on at least one arm -- i.e. there is some path
58+
// to the network. A won block recorded with no live peers and no raw bytes is
59+
// a dead end (caller error); both arms then report false.
60+
bool any_armed() const { return p2p_armed || submitblock_armed; }
61+
};
62+
63+
// The post-execution verdict: did the won block actually reach the network? The
64+
// keystone fills this in AFTER it has driven both arms, from the real results:
65+
// * p2p_acks -- how many live slots accepted the inv fan-out (>=1 relayed)
66+
// * submitblock_ok -- dashd accepted the raw block via the RPC fallback
67+
// reached_network is the OR of the two arms: a single successful arm suffices.
68+
struct DeliveryVerdict
69+
{
70+
std::size_t p2p_acks{0};
71+
bool submitblock_ok{false};
72+
73+
bool reached_network() const { return p2p_acks > 0 || submitblock_ok; }
74+
};
75+
76+
// Builds dual-arm delivery plans over a binding (which owns the live-pool view
77+
// and the relay book). Stateless and pure: opens no socket, recomputes no hash.
78+
class DualArmPlanner
79+
{
80+
public:
81+
explicit DualArmPlanner(WonBlockRelayBinding& binding) : m_binding(binding) {}
82+
83+
// Record the won block (via the binding -> planner -> relay) and build its
84+
// dual-arm plan against the broadcaster's CURRENT live slots. The raw bytes
85+
// are carried verbatim for the dashd submitblock arm and copied into the
86+
// plan so it outlives the caller's buffer. The P2P arm is armed iff the live
87+
// fan-out is non-empty; the submitblock arm is armed iff raw bytes were
88+
// supplied. The block records even when BOTH would be disarmed (recording is
89+
// decoupled from delivery), so a peer connecting later can still getdata it.
90+
DualArmPlan plan(const uint256& hash,
91+
WonBlockRelay::BlockType block,
92+
std::span<const unsigned char> raw_block_bytes)
93+
{
94+
DualArmPlan out;
95+
out.p2p = m_binding.plan_announce(hash, std::move(block));
96+
out.submitblock_bytes.assign(raw_block_bytes.begin(), raw_block_bytes.end());
97+
out.p2p_armed = out.p2p.fanout() > 0;
98+
out.submitblock_armed = !out.submitblock_bytes.empty();
99+
return out;
100+
}
101+
102+
// Pure verdict evaluator: given the per-arm results the keystone observed,
103+
// decide whether the won block reached the network. Static -- it depends only
104+
// on the reported results, not on any pool state.
105+
static DeliveryVerdict evaluate(std::size_t p2p_acks, bool submitblock_ok)
106+
{
107+
DeliveryVerdict v;
108+
v.p2p_acks = p2p_acks;
109+
v.submitblock_ok = submitblock_ok;
110+
return v;
111+
}
112+
113+
private:
114+
WonBlockRelayBinding& m_binding;
115+
};
116+
117+
} // namespace dash

test/CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,16 @@ if (BUILD_TESTING AND GTest_FOUND)
553553
target_link_libraries(test_dash_block_relay_binding PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
554554
gtest_add_tests(test_dash_block_relay_binding "" AUTO)
555555

556+
add_executable(test_dash_block_relay_dual_arm test_dash_block_relay_dual_arm.cpp)
557+
target_link_libraries(test_dash_block_relay_dual_arm PRIVATE
558+
GTest::gtest_main GTest::gtest
559+
dash_x11 core
560+
nlohmann_json::nlohmann_json
561+
${Boost_LIBRARIES}
562+
)
563+
target_link_libraries(test_dash_block_relay_dual_arm PRIVATE c2pool_payout c2pool_hashrate c2pool_merged_mining) # OBJECT-lib SCC direct-naming (#22/#39)
564+
gtest_add_tests(test_dash_block_relay_dual_arm "" AUTO)
565+
556566
add_executable(test_compact_blocks test_compact_blocks.cpp)
557567
target_link_libraries(test_compact_blocks PRIVATE
558568
GTest::gtest_main GTest::gtest

0 commit comments

Comments
 (0)