Skip to content

Commit e56fe92

Browse files
authored
Merge pull request #810 from frstrtr/dash/embedded-superblock-govsync
dash(embedded): daemonless superblock payee sourcing via govsync (governance triggers)
2 parents d7b5013 + 343729a commit e56fe92

17 files changed

Lines changed: 2521 additions & 19 deletions

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ jobs:
144144
core_test sharechain_test share_test btc_share_test \
145145
test_threading test_weights \
146146
test_header_chain test_mempool test_template_builder \
147-
test_doge_chain test_compact_blocks test_dash_x11_kat 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_underfill_guard 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 test_dash_coinbase_parity test_dash_coinbase_muldiv test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state test_dash_coin_state_maintainer test_dash_node_embedded_wire test_dash_node_reception_wire test_dash_get_work test_dash_stratum_work_source \
147+
test_doge_chain test_compact_blocks test_dash_x11_kat 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_underfill_guard 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 test_dash_coinbase_parity test_dash_coinbase_muldiv test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state test_dash_coin_state_maintainer test_dash_node_embedded_wire test_dash_node_reception_wire test_dash_get_work test_dash_stratum_work_source test_dash_superblock \
148148
test_multiaddress_pplns test_pplns_stress \
149149
test_hash_link test_decay_pplns \
150150
test_pplns_consensus \
@@ -332,7 +332,7 @@ jobs:
332332
test_threading test_weights \
333333
test_header_chain test_mempool test_template_builder \
334334
test_doge_chain test_compact_blocks test_dash_x11_kat \
335-
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_underfill_guard 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 test_dash_coinbase_parity test_dash_coinbase_muldiv test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state test_dash_coin_state_maintainer test_dash_node_embedded_wire test_dash_node_reception_wire test_dash_get_work test_dash_stratum_work_source \
335+
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_underfill_guard 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 test_dash_coinbase_parity test_dash_coinbase_muldiv test_dash_donation_combined test_dash_g3_assembled test_dash_work_target test_dash_work_job_targets test_dash_stratum_binding test_dash_job_notify_roundtrip test_dash_cb_payee test_dash_stratum_notify_roundtrip test_dash_poolnode_messages test_dash_peer test_dash_share_tracker test_dash_node test_dash_share_messages test_dash_stratum_extranonce_split test_dash_stratum_submit_reassembly test_dash_difficulty_parity test_dash_auto_ratchet test_dash_min_protocol_gate test_dash_work_source test_dash_node_coin_state test_dash_coin_state_maintainer test_dash_node_embedded_wire test_dash_node_reception_wire test_dash_get_work test_dash_stratum_work_source test_dash_superblock \
336336
test_hash_link test_decay_pplns \
337337
test_pplns_consensus \
338338
test_v36_script_sorting test_v36_cross_impl_refhash \

src/c2pool/main_dash.cpp

Lines changed: 103 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@
7575
#include <impl/dash/coin/tip_ingest.hpp> // wire_tip_ingest (leg 2)
7676
#include <impl/dash/coin/block_connect_ingest.hpp> // wire_block_connect_ingest (leg 3)
7777
#include <impl/dash/coin/mn_list_ingest.hpp> // wire_mn_list_ingest (leg 4)
78+
#include <impl/dash/coin/govsync_ingest.hpp> // wire_govobject_ingest / wire_govvote_ingest (E-SUPERBLOCK)
79+
#include <impl/dash/coin/superblock.hpp> // get_superblock_payments / superblock_budget (E-SUPERBLOCK)
7880
#include <impl/dash/coin/mn_seed.hpp> // E2c: RPC protx-list MN-set seed (parse_protx_list_seed)
7981
#include <impl/dash/node.hpp> // dash::Node — sharechain pool-node (NodeBridge<NodeImpl,Legacy,Actual>)
8082
#include <impl/dash/config.hpp> // dash::Config (PoolConfig/CoinConfig)
@@ -436,7 +438,8 @@ int run_node(bool testnet, const std::string& rpc_endpoint,
436438
const std::string& external_ip,
437439
const std::string& coin_p2p_magic_hex,
438440
bool force_won_block,
439-
const std::string& operator_message_blob_hex)
441+
const std::string& operator_message_blob_hex,
442+
bool embedded_superblock)
440443
{
441444
namespace io = boost::asio;
442445

@@ -2202,6 +2205,17 @@ int run_node(bool testnet, const std::string& rpc_endpoint,
22022205
coin_feed_subs.push_back(
22032206
c2pool::dash::wire_mnlistdiff_ingest(coin_state, *maintainer));
22042207

2208+
// Legs 6-7 (E-SUPERBLOCK — DAEMONLESS SUPERBLOCK PAYEE SOURCING): the
2209+
// governance-object + vote feed off the coin-P2P govsync leg. govobj
2210+
// triggers advance the GovernanceStore (winning-trigger schedule);
2211+
// govobjvote funding votes feed the tally (counted only when verified —
2212+
// see the vote-verifier seam below). This is what lets the embedded arm
2213+
// serve a SUPERBLOCK height daemonlessly instead of falling back.
2214+
coin_feed_subs.push_back(
2215+
c2pool::dash::wire_govobject_ingest(coin_state, *maintainer));
2216+
coin_feed_subs.push_back(
2217+
c2pool::dash::wire_govvote_ingest(coin_state, *maintainer));
2218+
22052219
// getmnlistd base tracker: the block hash the local SML is current at.
22062220
// Cold start = ZERO (full snapshot). Each accepted mnlistdiff advances
22072221
// it to diff.blockHash so the NEXT request is an incremental diff off
@@ -2356,6 +2370,78 @@ int run_node(bool testnet, const std::string& rpc_endpoint,
23562370
[sb_cycle](uint32_t next_height) {
23572371
return dash::coin::is_superblock_height(next_height, sb_cycle);
23582372
});
2373+
2374+
// E-SUPERBLOCK: daemonless superblock payee provider. At a superblock
2375+
// height the provider resolves the winning governance trigger's
2376+
// budget-valid (script, amount) schedule from the GovernanceStore the
2377+
// govsync legs (6-7) feed, so the embedded arm can serve the correct
2378+
// superblock coinbase WITHOUT dashd. superblock_schedule() returns
2379+
// nullopt when there is no trigger-confident winner (unfunded OR
2380+
// under-synced OR over-budget OR the R6 desync latch fired) — the
2381+
// NodeCoinState guard then FAILS CLOSED to the reward-safe dashd
2382+
// fallback (never guesses payees).
2383+
//
2384+
// Enabled ONLY under --embedded-superblock (opt-in, default OFF). With
2385+
// it OFF, set_require_superblock_provider(false) preserves the prior
2386+
// reward-safe behaviour EXACTLY (every superblock height falls back).
2387+
//
2388+
// FAIL-CLOSED BY CONSTRUCTION until vote-verify lands, TRIPLY:
2389+
// 1. the funding tally counts only votes the maintainer's
2390+
// vote-verifier accepts — and that verifier is UNSET here.
2391+
// (Follow-up contract: BLS by the voting MN's OPERATOR key
2392+
// over govvote_signature_hash — dashcore verifies TRIGGER
2393+
// funding votes against pubKeyOperator, NOT the
2394+
// ECDSA/keyIDVoting path, which is proposal-only. See
2395+
// CoinStateMaintainer::set_vote_verifier.)
2396+
// 2. the weighted tally needs the vote-weight/membership seam
2397+
// (GovernanceStore::set_vote_weight_fn) — also UNSET here
2398+
// (the DIP-4 SML lacks collateral outpoints; needs the full
2399+
// DMN view).
2400+
// 3. the R5 govsync-completeness gate
2401+
// (set_superblock_sync_complete_fn) is NOT wired — the
2402+
// NodeCoinState guard refuses the serve path structurally,
2403+
// so landing vote-verify alone can never open it.
2404+
// The parse/selection/template-emit logic is proven by the KATs;
2405+
// flipping this fully live is gated on vote-verify + completeness
2406+
// + a funded-superblock soak.
2407+
{
2408+
const int64_t budget_cycle = sb_cycle;
2409+
// Chain-strict trigger parsing + dashcore threshold inputs:
2410+
// min-quorum is chainparams nGovernanceMinQuorum; the
2411+
// threshold itself re-derives from the weighted SML count on
2412+
// every accepted mnlistdiff (maintainer reseed — dashcore
2413+
// nAbsVoteReq = max(minQuorum, weighted/10)). Cross-checkable
2414+
// against dashd getgovernanceinfo.fundingthreshold.
2415+
maintainer->set_gov_params(
2416+
testnet, testnet ? dash::coin::DASH_GOV_MIN_QUORUM_TESTNET
2417+
: dash::coin::DASH_GOV_MIN_QUORUM_MAINNET);
2418+
// Superblock ctx for the R6 coinbase cross-check + executed-
2419+
// cycle pruning on the block-connect leg.
2420+
maintainer->set_superblock_ctx(
2421+
[sb_cycle](uint32_t h) {
2422+
return dash::coin::is_superblock_height(h, sb_cycle);
2423+
},
2424+
[budget_cycle](uint32_t h) {
2425+
return dash::coin::superblock_budget(
2426+
h, static_cast<int>(budget_cycle));
2427+
});
2428+
node_coin_state.set_superblock_provider(
2429+
[maint = maintainer.get()](uint32_t next_height)
2430+
-> std::optional<std::vector<dash::coin::SuperblockPayment>> {
2431+
return maint->superblock_schedule(next_height);
2432+
});
2433+
node_coin_state.set_require_superblock_provider(embedded_superblock);
2434+
// NOTE deliberately NOT set: set_superblock_sync_complete_fn
2435+
// (R5). Until a govsync-completeness proof exists, superblock
2436+
// heights refuse the embedded arm even with the flag on.
2437+
if (embedded_superblock)
2438+
LOG_INFO << "[E-SUPERBLOCK] daemonless superblock arm ENABLED "
2439+
"(--embedded-superblock); superblock heights served "
2440+
"from govsync triggers when trigger-confident, else "
2441+
"fail closed to dashd. Vote-verify (BLS operator) + "
2442+
"completeness gate pending => currently fails "
2443+
"closed until pinned.";
2444+
}
23592445
}
23602446

23612447
// E4 re-soak fix (constant −66,966,830-duff creditPool bias): the
@@ -2767,6 +2853,18 @@ int run_node(bool testnet, const std::string& rpc_endpoint,
27672853
auto tip_entry = hc->tip();
27682854
const uint256 tip = tip_entry ? tip_entry->hash : uint256::ZERO;
27692855
cp->send_getmnlistd(*sml_base, tip);
2856+
// E-SUPERBLOCK: prime the governance object/vote sync (triggers
2857+
// + funding votes) so a superblock height can be served
2858+
// daemonlessly. Zero nProp + empty filter => request all.
2859+
// Handshake-only today — there is NO tip-change re-prime yet.
2860+
// KNOWN GAP (pre-enable requirement): dashcore answers govsync
2861+
// with INVENTORY (MSG_GOVERNANCE_OBJECT/_VOTE invs), not
2862+
// direct govobj/govobjvote messages, and our inv handler does
2863+
// not getdata governance types — so this leg is currently
2864+
// INERT (an extra fail-closed layer: the store stays empty).
2865+
// The inv-driven getdata + per-object vote sync + periodic
2866+
// re-prime co-land with vote-verify before any enable.
2867+
cp->send_govsync();
27702868
});
27712869

27722870
std::cout << "[run] E2a live-feed wired: header-chain(" << hdr_db
@@ -3430,6 +3528,7 @@ int main(int argc, char** argv)
34303528
bool embedded_mainnet = false; // --embedded-mainnet: gate-lift, allow the daemonless embedded template arm on MAINNET (byte-parity proven; default OFF = dashd fallback)
34313529
std::string coin_p2p_magic = ""; // --coin-p2p-magic HEX: override the embedded CoinClient wire magic (e.g. regtest fcc1b7dc); default mainnet/testnet
34323530
bool force_won_block = false; // --regtest-force-won-block: fail-closed regtest E5 harness (drive one real won block through the run-path dual-path)
3531+
bool embedded_superblock = false; // --embedded-superblock: OPT-IN daemonless superblock payee sourcing via govsync (E-SUPERBLOCK); default OFF = superblock heights fall back to dashd (reward-safe)
34333532
std::string stratum_host = "0.0.0.0"; // --stratum [HOST:]PORT bind interface (default all)
34343533
uint16_t stratum_port = 0; // 0 disables the Stratum accept-loop; --stratum sets it
34353534
bool embedded_utxo = false; // --embedded-utxo: arm the E2b UTXO/fee lane (opt-in)
@@ -3500,6 +3599,8 @@ int main(int argc, char** argv)
35003599
coin_p2p_magic = argv[++i];
35013600
else if (std::strcmp(argv[i], "--regtest-force-won-block") == 0)
35023601
force_won_block = true;
3602+
else if (std::strcmp(argv[i], "--embedded-superblock") == 0)
3603+
embedded_superblock = true;
35033604
else if (std::strcmp(argv[i], "--embedded-utxo") == 0)
35043605
embedded_utxo = true;
35053606
else if ((std::strcmp(argv[i], "--give-author") == 0 ||
@@ -3620,7 +3721,7 @@ int main(int argc, char** argv)
36203721
coin_zmq_hashblock,
36213722
external_ip,
36223723
coin_p2p_magic, force_won_block,
3623-
operator_message_blob_hex);
3724+
operator_message_blob_hex, embedded_superblock);
36243725
}
36253726
return run_selftest();
36263727
}

src/core/address_utils.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,24 @@ std::string address_to_hash160(const std::string& address, std::string& addr_typ
116116
carry >>= 8;
117117
}
118118
}
119+
// P2SH version-byte whitelist. Chain-agnostic: an address whose
120+
// version byte is a known P2SH prefix of ANY supported coin yields a
121+
// P2SH script; everything else falls through to P2PKH. This is safe
122+
// only while no supported coin uses one of these bytes as its P2PKH
123+
// version — verified against upstream chainparams:
124+
// 0x05 BTC/BCH-legacy mainnet P2SH ('3')
125+
// 0x32 LTC mainnet P2SH ('M') 0x3a LTC testnet P2SH ('Q')
126+
// 0x16 DOGE mainnet P2SH ('9'/'A')
127+
// 0xc4 BTC/LTC/DOGE/DGB testnet P2SH ('2')
128+
// 0x10 DASH mainnet P2SH ('7') 0x13 DASH testnet P2SH ('8'/'9')
129+
// P2PKH versions in use (must never appear above): 0x00 BTC, 0x30 LTC,
130+
// 0x1e DOGE/DGB, 0x4c DASH, 0x8c DASH-testnet, 0x6f BTC/LTC-testnet.
131+
// (DASH bytes verified against dashpay/dash chainparams.cpp: mainnet
132+
// SCRIPT_ADDRESS=16, testnet/devnet/regtest SCRIPT_ADDRESS=19.)
119133
uint8_t version = decoded[0];
120134
if (version == 0x32 || version == 0x05 || version == 0x3a ||
121-
version == 0xc4 || version == 0x16) {
135+
version == 0xc4 || version == 0x16 || version == 0x10 ||
136+
version == 0x13) {
122137
addr_type = "p2sh";
123138
} else {
124139
addr_type = "p2pkh";

0 commit comments

Comments
 (0)