Skip to content

Commit 2dded36

Browse files
authored
Merge pull request #180 from frstrtr/nmc/p1b-check-proof-chain-leg
nmc(P1b): wire AuxPow::check_proof chain-merkle leg (step 1) + KATs
2 parents fa93959 + d80ed51 commit 2dded36

3 files changed

Lines changed: 82 additions & 5 deletions

File tree

src/impl/nmc/coin/header_chain.hpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -193,14 +193,16 @@ struct AuxPow {
193193
/// Result of a (future) AuxPow verification.
194194
enum class CheckResult {
195195
NOT_IMPLEMENTED_P0, //!< P0 leaf — verification path not built yet
196+
INCOMPLETE, //!< P1b — merkle leg(s) wired; steps 2/3/4 pending
196197
VALID,
197198
INVALID,
198199
};
199200

200201
/// Verify that this AuxPow actually proves work for `aux_block_hash`
201202
/// against the given expected aux chain id.
202203
///
203-
/// P0-DEFER: NOT IMPLEMENTED in P0. The real implementation must, against
204+
/// P1b: step 1 (chain-merkle leg) is wired below via aux_merkle_root().
205+
/// The FULL implementation must, against
204206
/// a properly-pinned Namecoin chainparams:
205207
/// 1. recompute the merged-mining merkle root from `chain_merkle_branch`
206208
/// + `chain_merkle_index` starting at `aux_block_hash`, and confirm
@@ -216,10 +218,31 @@ struct AuxPow {
216218
/// Until all four steps exist, NMC MUST NOT block-validate off this leaf.
217219
CheckResult check_proof(const uint256& aux_block_hash,
218220
int32_t expected_chain_id) const {
219-
// P0-DEFER: structural stub. Deliberately performs NO verification.
220-
(void)aux_block_hash;
221-
(void)expected_chain_id;
222-
return CheckResult::NOT_IMPLEMENTED_P0;
221+
// P1b — chain-merkle leg (step 1). Walk the aux (NMC) block hash up
222+
// through chain_merkle_branch/chain_merkle_index to reconstruct the
223+
// merged-mining merkle root via aux_merkle_root(). The remaining steps
224+
// are NOT built yet: step 2 (confirm that root is committed in the
225+
// parent coinbase MM marker, with the chain_id/slot binding), step 3
226+
// (parent-coinbase tx-merkle leg — needs the witness-stripped BTC
227+
// coinbase txid), step 4 (parent PoW vs target, consumed from the btc
228+
// tree READ-ONLY). A structurally-consistent chain-merkle walk therefore
229+
// returns INCOMPLETE, never VALID — NMC still MUST NOT block-validate
230+
// off this leaf.
231+
(void)expected_chain_id; // step-2 (chain_id/slot) binding lands later
232+
233+
if (chain_merkle_index < 0)
234+
return CheckResult::INVALID; // negative slot index is malformed
235+
236+
try {
237+
// Reconstructed MM root; its commitment check is step 2 (pending).
238+
(void)aux_merkle_root(
239+
aux_block_hash, chain_merkle_branch,
240+
static_cast<uint32_t>(chain_merkle_index));
241+
} catch (const std::invalid_argument&) {
242+
return CheckResult::INVALID; // branch index out of range for depth
243+
}
244+
245+
return CheckResult::INCOMPLETE;
223246
}
224247
};
225248

src/impl/nmc/test/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ if (BUILD_TESTING AND GTest_FOUND)
1919
# share/coin libs are needed -- this KAT only folds with core::Hash.
2020
target_link_libraries(nmc_auxpow_merkle_test PRIVATE
2121
c2pool_payout c2pool_merged_mining c2pool_hashrate c2pool_storage)
22+
# P1b: the check_proof KATs construct AuxPow, whose parent_coinbase member
23+
# is an nmc::coin::MutableTransaction with an out-of-line ctor -> link the
24+
# nmc_coin lib (transaction.cpp). Still no node/pool/share libs (none exist).
25+
target_link_libraries(nmc_auxpow_merkle_test PRIVATE nmc_coin)
2226

2327
include(GoogleTest)
2428
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})

src/impl/nmc/test/auxpow_merkle_test.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
namespace {
3636

3737
using nmc::coin::aux_merkle_root;
38+
using nmc::coin::AuxPow;
3839

3940
// Build a uint256 whose first byte is `b` (rest zero) — distinct, legible leaves.
4041
static uint256 leaf_of(unsigned char b)
@@ -100,4 +101,53 @@ TEST(NmcAuxMerkle, IndexTooLargeForBranchThrows)
100101
EXPECT_THROW(aux_merkle_root(leaf, {sib}, 2u), std::invalid_argument);
101102
}
102103

104+
105+
// ---------------------------------------------------------------------------
106+
// P1b: AuxPow::check_proof chain-merkle leg (step 1) wiring.
107+
//
108+
// check_proof() now reconstructs the merged-mining merkle root from the aux
109+
// block hash through chain_merkle_branch/index via aux_merkle_root(). Steps 2
110+
// (MM-marker commitment), 3 (parent-coinbase tx-merkle leg) and 4 (parent PoW)
111+
// are NOT built, so a structurally-consistent walk returns INCOMPLETE — never
112+
// VALID. A malformed slot index (negative, or wider than the branch depth)
113+
// returns INVALID. These KATs pin exactly that boundary so the leg can never
114+
// silently regress into asserting VALID before the rest of the proof exists.
115+
// ---------------------------------------------------------------------------
116+
117+
TEST(NmcAuxCheckProof, ChainLegStructurallyValidIsIncomplete)
118+
{
119+
AuxPow ap;
120+
ap.chain_merkle_branch = {leaf_of(0xbe)};
121+
ap.chain_merkle_index = 0;
122+
EXPECT_EQ(ap.check_proof(leaf_of(0x01), /*expected_chain_id=*/1),
123+
AuxPow::CheckResult::INCOMPLETE);
124+
}
125+
126+
TEST(NmcAuxCheckProof, EmptyChainBranchIsIncompleteNeverValid)
127+
{
128+
AuxPow ap; // empty branch, index 0 => identity walk, still not provable
129+
EXPECT_EQ(ap.check_proof(leaf_of(0x07), 1),
130+
AuxPow::CheckResult::INCOMPLETE);
131+
EXPECT_NE(ap.check_proof(leaf_of(0x07), 1),
132+
AuxPow::CheckResult::VALID);
133+
}
134+
135+
TEST(NmcAuxCheckProof, NegativeChainIndexIsInvalid)
136+
{
137+
AuxPow ap;
138+
ap.chain_merkle_branch = {leaf_of(0x0a)};
139+
ap.chain_merkle_index = -1;
140+
EXPECT_EQ(ap.check_proof(leaf_of(0x02), 1),
141+
AuxPow::CheckResult::INVALID);
142+
}
143+
144+
TEST(NmcAuxCheckProof, ChainIndexTooWideForDepthIsInvalid)
145+
{
146+
AuxPow ap;
147+
ap.chain_merkle_branch = {leaf_of(0x0a)}; // depth 1 => max index 1
148+
ap.chain_merkle_index = 2;
149+
EXPECT_EQ(ap.check_proof(leaf_of(0x02), 1),
150+
AuxPow::CheckResult::INVALID);
151+
}
152+
103153
} // namespace

0 commit comments

Comments
 (0)