Skip to content

Commit 5b231e7

Browse files
authored
Merge pull request #410 from frstrtr/dash/share-target-validity-conform
dash: restore share-target validity guard (target>MAX_TARGET) — conform vs p2pool-dash oracle
2 parents 41c5947 + b06c196 commit 5b231e7

2 files changed

Lines changed: 48 additions & 3 deletions

File tree

src/impl/dash/share_check.hpp

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,23 @@ inline std::vector<unsigned char> compute_gentx_before_refhash()
158158
return result;
159159
}
160160

161+
// ── check_share_target_valid (Dash v16) ─────────────────────────────
162+
// Conformance with p2pool-dash oracle data.py Share.__init__:
163+
// if self.target > net.MAX_TARGET: raise PeerMisbehavingError('share target invalid')
164+
// The claimed share target must be no easier than the network share-diff floor
165+
// (params.max_target == net.MAX_TARGET); a zero target is likewise invalid. This is
166+
// a structural validity guard on share_info['bits'], independent of the PoW check.
167+
// v36 3-bucket: the GUARD is v36-native SHARED validation (Bucket 2 — cross-coin
168+
// identical); only the per-coin max_target constant differs (a consensus param, not
169+
// an isolation primitive).
170+
inline void check_share_target_valid(const uint256& target, const core::CoinParams& params)
171+
{
172+
if (target.IsNull())
173+
throw std::invalid_argument("share target is zero");
174+
if (target > params.max_target)
175+
throw std::invalid_argument("share target invalid");
176+
}
177+
161178
// ── share_init_verify (Dash v16) ─────────────────────────────────────────────
162179
// Verifies PoW, hash_link, merkle_link. Returns share hash (SHA256d of header).
163180
inline uint256 share_init_verify(const DashShare& share,
@@ -167,6 +184,10 @@ inline uint256 share_init_verify(const DashShare& share,
167184
if (share.m_coinbase.m_data.size() < 2 || share.m_coinbase.m_data.size() > 100)
168185
throw std::invalid_argument("bad coinbase size");
169186

187+
// ── Share target validity (oracle: target > MAX_TARGET → "share target invalid") ──
188+
// Unconditional — NOT gated by check_pow, matching p2pool-dash Share.__init__.
189+
check_share_target_valid(chain::bits_to_target(share.m_bits), params);
190+
170191
// ── Compute ref_hash ──
171192
PackStream ref_stream;
172193
{
@@ -269,9 +290,6 @@ inline uint256 share_init_verify(const DashShare& share,
269290
if (check_pow)
270291
{
271292
uint256 target = chain::bits_to_target(share.m_bits);
272-
if (target.IsNull())
273-
throw std::invalid_argument("share target is zero");
274-
275293
if (share_hash > target)
276294
throw std::invalid_argument("share PoW hash does not meet target");
277295
}

test/test_dash_conformance.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,33 @@ TEST(DashConformanceDifficulty, BitsToDifficultyMatchesP2poolDash) {
367367
}
368368
}
369369

370+
// ── Pillar-3 conformance: share-target validity guard vs p2pool-dash oracle ──
371+
// Oracle data.py Share.__init__ rejects `self.target > net.MAX_TARGET`
372+
// ("share target invalid") AND a zero target. c2pool share_init_verify previously
373+
// enforced only the zero case — no share-diff-floor upper bound. This pins the
374+
// restored guard against the mainnet floor (params.max_target == 0xFFFF*2**208).
375+
TEST(DashConformanceShareTarget, RejectsTargetEasierThanFloorAndZero) {
376+
core::CoinParams params;
377+
params.max_target = dash::PoolConfig::max_target(); // 00000000ffff00..00
378+
379+
const uint256 floor = params.max_target;
380+
381+
// exactly at the floor -> accepted (boundary, not "> floor")
382+
EXPECT_NO_THROW(dash::check_share_target_valid(floor, params));
383+
384+
// strictly harder (numerically smaller target) -> accepted
385+
uint256 harder; harder.SetHex("000000000000ffff000000000000000000000000000000000000000000000000");
386+
EXPECT_NO_THROW(dash::check_share_target_valid(harder, params));
387+
388+
// strictly easier than the floor (numerically larger) -> rejected
389+
uint256 easier; easier.SetHex("00000001ffff0000000000000000000000000000000000000000000000000000");
390+
EXPECT_THROW(dash::check_share_target_valid(easier, params), std::invalid_argument);
391+
392+
// zero target -> rejected
393+
uint256 zero;
394+
EXPECT_THROW(dash::check_share_target_valid(zero, params), std::invalid_argument);
395+
}
396+
370397
// ── PPLNS payout-SET equality conformance (S6 slice 6) ───────────────────────
371398
// The miner-facing output of the whole sharechain is the PPLNS payout SET:
372399
// the {scriptPubKey -> amount} map a coinbase pays. For DASH to be value-

0 commit comments

Comments
 (0)