Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/impl/nmc/coin/aux_chain_embedded.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,19 @@ class AuxChainEmbedded : public c2pool::merged::IAuxChainBackend
}

bool submit_aux_block(const uint256& block_hash, const std::string& auxpow_hex) override {
// Fallback (submitauxblock) path: embedded mode has no daemon to RPC,
// the frozen-block submit_block() + P2P relay is the primary route.
// PE broadcaster gate (integrator UID1610): the submitauxblock RPC route is
// external-namecoind-only and conditional - it is NOT a same-process fallback
// like BTC submitblock-to-bitcoind, so it does NOT satisfy the embedded leg.
// Embedded mode has no daemon to RPC, therefore this path cannot itself
// broadcast and MUST NOT claim success: the P2P relay via submit_block() is
// the one authoritative embedded route. Same never-silent-drop invariant as
// submit_block() - never claim a broadcast that did not occur (#162).
LOG_WARNING << "[MM:" << m_config.symbol << "] Embedded: submit_aux_block called"
<< " (fallback path) hash=" << block_hash.GetHex().substr(0, 16) << "..."
<< " (RPC fallback) hash=" << block_hash.GetHex().substr(0, 16) << "..."
<< " auxpow=" << auxpow_hex.size() / 2 << " bytes"
<< " - no daemon to submit to, relying on P2P relay";
return true;
<< " - no daemon to submit to; embedded RPC leg cannot broadcast,"
<< " returning false (P2P relay via submit_block is authoritative)";
return false;
}

std::string get_block_hex(const std::string& /*block_hash*/) override {
Expand Down
30 changes: 16 additions & 14 deletions src/impl/nmc/test/nmc_template_builder_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,15 +361,17 @@ TEST(NmcAuxChainEmbedded, SubmitBlockNeverSilentDropOnZeroPeers)
EXPECT_EQ(backend.get_block_hex("any"), hex); // hex still cached
}

// PE dual-path gate (integrator note #3): the FALLBACK leg. submit_block() above
// is the P2P-primary route; submit_aux_block() is the submitauxblock RPC fallback.
// In embedded mode there is no daemon to RPC, so the fallback acknowledges (the
// P2P relay leg is authoritative) WITHOUT claiming a daemon submission - and,
// crucially, unlike submit_block() it does NOT populate the block-hex cache.
// This pins the two legs as DISTINCT (P2P-primary cached vs RPC-fallback no-cache),
// the both-paths-fire gate proven at unit level ahead of the live .140 won-block
// soak (which is daemon-gated). A coin is not block-viable until both legs exist.
TEST(NmcAuxChainEmbedded, SubmitAuxBlockFallbackLegIsDistinctFromP2PRelay)
// PE broadcaster gate (integrator UID1610, supersedes note #3): the submitauxblock
// RPC leg. submit_block() above is the P2P-primary route. The submitauxblock RPC
// route is external-namecoind-only - it is NOT a same-process fallback like BTC
// submitblock-to-bitcoind, so it does NOT satisfy the embedded leg. In embedded
// mode there is no daemon to RPC, so this leg cannot itself broadcast and MUST
// surface false (never claim a broadcast that did not occur - same never-silent-
// drop invariant as submit_block). It also leaves the P2P block-hex cache untouched:
// the two legs are DISTINCT, not aliases. A won-block soak asserting green while
// this leg returned an unconditional true would be green-by-construction - the
// precise failure the broadcaster gate exists to catch.
TEST(NmcAuxChainEmbedded, SubmitAuxBlockRpcLegSurfacesFalseInEmbeddedMode)
{
HeaderChain chain(params_pinned());
Mempool pool;
Expand All @@ -378,11 +380,11 @@ TEST(NmcAuxChainEmbedded, SubmitAuxBlockFallbackLegIsDistinctFromP2PRelay)
uint256 aux_hash; aux_hash.SetNull();
const std::string auxpow_hex(120, static_cast<char>(0x64));

// Fallback leg acknowledges: embedded has no daemon, P2P relay is primary,
// so the caller is not hard-failed (the block already went out over P2P).
EXPECT_TRUE(backend.submit_aux_block(aux_hash, auxpow_hex));
// ...but the RPC-fallback leg leaves the P2P submit_block() hex cache UNTOUCHED:
// the two broadcaster legs are independent, not aliases of one path.
// Embedded RPC-fallback leg has no daemon to submit to: it cannot broadcast,
// so it MUST NOT claim success. P2P relay via submit_block() is authoritative.
EXPECT_FALSE(backend.submit_aux_block(aux_hash, auxpow_hex));
// ...and it leaves the P2P submit_block() hex cache UNTOUCHED: the two
// broadcaster legs are independent, not aliases of one path.
EXPECT_EQ(backend.get_block_hex("any"), std::string(""));
}

Expand Down
Loading