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
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
test_mweb_builder \
test_address_resolution test_compute_share_target \
test_utxo test_dgb_subsidy test_dgb_coinbase_value dgb_share_test dgb_redistribute_test dgb_block_assembly_test dgb_header_sample_build_test dgb_header_ingest_test dgb_mempool_ingest_test \
dgb_gentx_coinbase_test dgb_connection_coinbase_test dgb_pplns_payout_split_test nmc_auxpow_merkle_test nmc_template_builder_test nmc_auxpow_wire_test nmc_reconstruct_won_block_test dgb_gentx_share_path_test dgb_conn_pplns_producer_test dgb_other_tx_resolver_test \
dgb_gentx_coinbase_test dgb_connection_coinbase_test dgb_pplns_payout_split_test nmc_auxpow_merkle_test nmc_template_builder_test nmc_auxpow_wire_test nmc_reconstruct_won_block_test nmc_mempool_name_test dgb_gentx_share_path_test dgb_conn_pplns_producer_test dgb_other_tx_resolver_test \
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_reconstruct_closure_test dgb_gentx_unpack_test dgb_work_source_test dgb_template_builder_test dgb_embedded_coin_node_test dgb_embedded_tx_select_test dgb_template_other_txs_test dgb_coinbase_value_parity_test dgb_submit_classify_test dgb_aux_parent_coinbase_parity_test dgb_template_capture_test dgb_aux_doge_db_commitment_bind_test dgb_aux_doge_dc_proof_test dgb_aux_doge_bind_parsers_test \
rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \
dgb_coin_node_seam_test dgb_block_broadcast_test dgb_won_block_dispatch_test dgb_forced_won_share_dualpath_test dgb_scrypt_pow_test dgb_nonce_grinder_test dgb_regrind_block_test dgb_won_block_finalize_test dgb_share_target_genesis_test dgb_pool_msg_wire_test dgb_get_shares_walk_test dgb_download_stops_test dgb_think_p1_walk_bounds_test dgb_think_p1_desired_emit_test dgb_think_p6_desired_cutoff_test dgb_think_p4_head_keys_test dgb_think_p3_best_head_test dgb_g1_oracle_byte_parity_test dgb_think_p2_walk_bounds_test dgb_expected_time_to_block_test dgb_pool_efficiency_test dgb_think_p5_best_share_punish_test v37_test \
Expand Down Expand Up @@ -213,7 +213,7 @@ jobs:
test_mweb_builder \
test_address_resolution test_compute_share_target \
test_utxo test_dgb_subsidy test_dgb_coinbase_value dgb_share_test dgb_redistribute_test dgb_block_assembly_test dgb_header_sample_build_test dgb_header_ingest_test dgb_mempool_ingest_test \
dgb_gentx_coinbase_test dgb_connection_coinbase_test dgb_pplns_payout_split_test nmc_auxpow_merkle_test nmc_template_builder_test nmc_auxpow_wire_test nmc_reconstruct_won_block_test dgb_gentx_share_path_test dgb_conn_pplns_producer_test dgb_other_tx_resolver_test \
dgb_gentx_coinbase_test dgb_connection_coinbase_test dgb_pplns_payout_split_test nmc_auxpow_merkle_test nmc_template_builder_test nmc_auxpow_wire_test nmc_reconstruct_won_block_test nmc_mempool_name_test dgb_gentx_share_path_test dgb_conn_pplns_producer_test dgb_other_tx_resolver_test \
dgb_other_tx_assembler_test dgb_reconstruct_won_block_test dgb_reconstruct_closure_test dgb_gentx_unpack_test dgb_work_source_test dgb_template_builder_test dgb_embedded_coin_node_test dgb_embedded_tx_select_test dgb_template_other_txs_test dgb_coinbase_value_parity_test dgb_submit_classify_test dgb_aux_parent_coinbase_parity_test dgb_template_capture_test dgb_aux_doge_db_commitment_bind_test dgb_aux_doge_dc_proof_test dgb_aux_doge_bind_parsers_test \
rpc_request_test softfork_check_test genesis_check_test algo_select_test digishield_walk_test header_chain_test \
dgb_coin_node_seam_test dgb_block_broadcast_test dgb_won_block_dispatch_test dgb_forced_won_share_dualpath_test dgb_scrypt_pow_test dgb_nonce_grinder_test dgb_regrind_block_test dgb_won_block_finalize_test dgb_share_target_genesis_test dgb_pool_msg_wire_test dgb_get_shares_walk_test dgb_download_stops_test dgb_think_p1_walk_bounds_test dgb_think_p1_desired_emit_test dgb_think_p6_desired_cutoff_test dgb_think_p4_head_keys_test dgb_think_p3_best_head_test dgb_g1_oracle_byte_parity_test dgb_think_p2_walk_bounds_test dgb_expected_time_to_block_test dgb_pool_efficiency_test dgb_think_p5_best_share_punish_test test_coin_broadcaster test_multiaddress_pplns test_pplns_stress \
Expand Down
105 changes: 104 additions & 1 deletion src/impl/nmc/coin/mempool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,52 @@ namespace coin {
// MAX_MONEY, consensus.h COINBASE_MATURITY.
static constexpr core::coin::ChainLimits NMC_LIMITS = {2'100'000'000'000'000LL, 100, 0};

// ─── Namecoin name operations (PB) ────────────────────────
//
// Namecoin extends Bitcoin with three name operations encoded as a prefix on an
// output scriptPubKey, gated by a distinguishing tx-version marker. c2pool is a
// merge-miner, NOT a name registry: it RELAYS name txs into the block template
// WITHOUT performing name-db consensus validation (no expiry / no
// name_new->name_firstupdate linkage / no duplicate-name checks). namecoind owns
// name-db consensus. The trust is SPV-trust in the configured daemon backend:
// a name tx is only consensus-TRUSTED when sourced from the trusted
// namecoind-backed mempool/GBT (TxSource::Daemon), NOT from arbitrary peer relay
// (integrator §4 caveat 1). PB records the daemon-vs-relay provenance per entry
// and admits both; binding the trust to the daemon source is a PF KAT item.
//
// Reference: namecoin-core script/names.cpp CNameScript; primitives/transaction.h
// NAMECOIN_TX_VERSION / getNamecoinVersion().

// Namecoin name-tx version marker. Namecoin packs the name version into the high
// 16 bits of nVersion; getNamecoinVersion() == NAMECOIN_TX_VERSION (0x7100)
// distinguishes a name tx from a bare Bitcoin tx that merely starts an output
// with OP_1..OP_3 (segwit v1+/taproot, bare multisig).
static constexpr int32_t NAMECOIN_TX_VERSION = 0x7100;
inline int32_t name_version(int32_t nVersion) { return (nVersion >> 16) & 0xffff; }

// Name-op prefix opcodes (namecoin-core reuses OP_1/OP_2/OP_3).
enum : unsigned char {
OP_NAME_NEW = 0x51, // OP_1
OP_NAME_FIRSTUPDATE = 0x52, // OP_2
OP_NAME_UPDATE = 0x53, // OP_3
};

enum class NameOp : uint8_t { None = 0, New, FirstUpdate, Update };

// Provenance of an admitted tx. A name tx is consensus-TRUSTED only when
// daemon-sourced (SPV-trust boundary); a PeerRelay name tx is admitted but not
// trusted — PF enforces the binding (integrator §4 caveat 1).
enum class TxSource : uint8_t { Daemon = 0, PeerRelay };

inline const char* name_op_str(NameOp op) {
switch (op) {
case NameOp::New: return "name_new";
case NameOp::FirstUpdate: return "name_firstupdate";
case NameOp::Update: return "name_update";
default: return "none";
}
}

// ─── MempoolEntry ────────────────────────────────────────────────────────────

struct MempoolEntry {
Expand All @@ -53,6 +99,10 @@ struct MempoolEntry {
uint64_t fee{0}; // satoshi (computed from UTXO when available)
bool fee_known{false}; // true when fee was computed from UTXO lookups
time_t time_added{0};
NameOp name_op{NameOp::None}; // Namecoin name op class (PB), None for plain tx
TxSource source{TxSource::PeerRelay}; // provenance: daemon-trusted vs peer-relay

bool is_name() const { return name_op != NameOp::None; }

double feerate() const {
uint32_t vsize = (weight + 3) / 4; // ceil(weight/4)
Expand Down Expand Up @@ -83,6 +133,28 @@ inline void compute_tx_weight(const MutableTransaction& tx,
weight = base_size * 4 + witness_size;
}

/// Classify a transaction as a Namecoin name operation WITHOUT name-db
/// validation. A name tx is identified by the Namecoin version marker AND a
/// leading name opcode on one of its output scripts; the version gate prevents
/// false-positives against bare OP_1..OP_3 outputs (taproot / multisig) in plain
/// Bitcoin txs. Returns the FIRST name op found, else NameOp::None. Full
/// CNameScript structural + name-db validation is namecoind's job (SPV-trust).
inline NameOp classify_name_op(const MutableTransaction& tx) {
if (name_version(tx.version) != NAMECOIN_TX_VERSION)
return NameOp::None;
for (const auto& out : tx.vout) {
const auto& d = out.scriptPubKey.m_data;
if (d.empty()) continue;
switch (d[0]) {
case OP_NAME_NEW: return NameOp::New;
case OP_NAME_FIRSTUPDATE: return NameOp::FirstUpdate;
case OP_NAME_UPDATE: return NameOp::Update;
default: break;
}
}
return NameOp::None;
}

// ─── Mempool ─────────────────────────────────────────────────────────────────

class Mempool {
Expand Down Expand Up @@ -122,7 +194,8 @@ class Mempool {
/// When utxo is non-null, computes fee = sum(input_values) - sum(output_values).
/// Falls back to fee_known=false if any input is missing from the UTXO set
/// or from a parent mempool transaction (chain-of-unconfirmed / CPFP).
bool add_tx(const MutableTransaction& tx, core::coin::UTXOViewCache* utxo) {
bool add_tx(const MutableTransaction& tx, core::coin::UTXOViewCache* utxo,
TxSource source = TxSource::PeerRelay) {
uint256 txid = compute_txid(tx);

std::lock_guard<std::mutex> lock(m_mutex);
Expand All @@ -137,6 +210,18 @@ class Mempool {
compute_tx_weight(tx, entry.base_size, entry.witness_size, entry.weight);
entry.time_added = std::time(nullptr);

// PB: classify Namecoin name ops and record provenance. Name txs are
// RELAYED into the template without name-db validation (SPV-trust in the
// daemon source); namecoind owns name consensus.
entry.source = source;
entry.name_op = classify_name_op(tx);
if (entry.name_op != NameOp::None) {
LOG_INFO << "[EMB-NMC] Mempool: admit " << name_op_str(entry.name_op)
<< " (relay WITHOUT name-db validation; namecoind owns name consensus)"
<< " src=" << (source == TxSource::Daemon ? "daemon" : "peer-relay")
<< " txid=" << txid.GetHex().substr(0, 16);
}

// Compute fee from UTXO + mempool parent lookups
compute_fee_locked(entry, utxo);

Expand Down Expand Up @@ -314,6 +399,24 @@ class Mempool {
return sum;
}

/// Count of admitted Namecoin name-operation txs currently in the pool.
size_t name_op_count() const {
std::lock_guard<std::mutex> lock(m_mutex);
size_t n = 0;
for (const auto& [txid, e] : m_pool) if (e.is_name()) ++n;
return n;
}

/// Count of name-op txs sourced from the trusted daemon backend (the only
/// ones PF will treat as consensus-trusted; SPV-trust boundary).
size_t trusted_name_op_count() const {
std::lock_guard<std::mutex> lock(m_mutex);
size_t n = 0;
for (const auto& [txid, e] : m_pool)
if (e.is_name() && e.source == TxSource::Daemon) ++n;
return n;
}

std::optional<MempoolEntry> get_entry(const uint256& txid) const {
std::lock_guard<std::mutex> lock(m_mutex);
auto it = m_pool.find(txid);
Expand Down
12 changes: 12 additions & 0 deletions src/impl/nmc/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,22 @@ if (BUILD_TESTING AND GTest_FOUND)
c2pool_payout c2pool_merged_mining c2pool_hashrate c2pool_storage)
target_link_libraries(nmc_reconstruct_won_block_test PRIVATE nmc_coin)

# P1 PB: Namecoin name-operation relay KATs (coin/mempool.hpp name_* path +
# fee flow through template_builder.hpp). Same SCC the sibling tests link
# (core + nmc_coin for the out-of-line MutableTransaction ctor).
add_executable(nmc_mempool_name_test nmc_mempool_name_test.cpp)
target_link_libraries(nmc_mempool_name_test PRIVATE
GTest::gtest_main GTest::gtest
core nlohmann_json::nlohmann_json)
target_link_libraries(nmc_mempool_name_test PRIVATE
c2pool_payout c2pool_merged_mining c2pool_hashrate c2pool_storage)
target_link_libraries(nmc_mempool_name_test PRIVATE nmc_coin)

include(GoogleTest)
include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR})
gtest_add_tests(nmc_auxpow_merkle_test "" AUTO)
gtest_add_tests(nmc_template_builder_test "" AUTO)
gtest_add_tests(nmc_auxpow_wire_test "" AUTO)
gtest_add_tests(nmc_reconstruct_won_block_test "" AUTO)
gtest_add_tests(nmc_mempool_name_test "" AUTO)
endif()
Loading
Loading