Skip to content
Merged
Show file tree
Hide file tree
Changes from 57 commits
Commits
Show all changes
70 commits
Select commit Hold shift + click to select a range
4817d56
Add native mining pools with durable PPLNS
metaphorics Oct 26, 2026
51697e4
Retire mining jobs when the node applies a block
metaphorics Oct 26, 2026
33ad2cf
Recognize pool RPCs in the shipped inventory
metaphorics Oct 26, 2026
0c46a2f
Share the Stratum response envelope
metaphorics Oct 26, 2026
ba57559
Refresh the standalone template provider lock
metaphorics Oct 26, 2026
8887326
Gate pool-only SRI test deps on pool-sv2 and align DEP-02
metaphorics Oct 27, 2026
3e02ae4
Preserve share identity across retirement and version rolls in pool-l…
metaphorics Oct 27, 2026
3d35275
SV2 lane: harden share validation, delivery, timeouts, ledger locking
metaphorics Oct 27, 2026
8ae7497
Clarify final payout-script owner and suppress SV1 notification replies
metaphorics Oct 27, 2026
86b1498
SV2 lane docs: announce delivery follows per-connection state, not fresh
metaphorics Oct 27, 2026
1aabb22
Repair SV1 pool-core reservations, delivery, and submit ownership
metaphorics Oct 27, 2026
cee998c
SV2 lane fixup: compare applied-tip snapshots by Arc identity to clos…
metaphorics Oct 27, 2026
7339cb5
SV2 lane fixup: annotate lock-free reconcile closure error type
metaphorics Oct 27, 2026
78aba00
Harden pool submission and rejection handling
metaphorics Oct 27, 2026
092b55f
Extract SV1 submit failure mapping
metaphorics Oct 27, 2026
e1895bb
Extract SV1 credited admission path
metaphorics Oct 27, 2026
98765ef
Pass Stratum test prefixes by value
metaphorics Oct 27, 2026
f64c5cc
Keep SV1 notification test failures explicit
metaphorics Oct 27, 2026
782b9f7
Resolve final pool and SV1 lint findings
metaphorics Oct 27, 2026
9fe05a0
Read pool ledger tails through reverse seeks
metaphorics Oct 27, 2026
4b44c18
Construct pool prefix overflow errors lazily
metaphorics Oct 27, 2026
9da9e03
Align mining payload test controls
metaphorics Oct 27, 2026
c3917a7
Prove pool management RPC authentication
metaphorics Oct 27, 2026
306765c
Prove pool contract boundaries
metaphorics Oct 27, 2026
74eca75
Deduplicate pool balance and Stratum encoding paths
metaphorics Oct 27, 2026
86a5800
Close SV2 and payout validation review gaps
metaphorics Oct 27, 2026
6e3be6c
Decode share hash entries up to the full tuple length
gormes-agent[bot] Oct 28, 2026
5f3c4cf
Repay reward deficits before releasing payout reservations
gormes-agent[bot] Oct 28, 2026
7aac79b
Keep SV2 success deferred and walk reward windows by seq
metaphorics Oct 28, 2026
5804089
Keep SV2 block permits and drain deferred replies
metaphorics Oct 28, 2026
bd238ac
Reserve SV2 block permits after buffering a frame
metaphorics Oct 28, 2026
462402d
Merge main into stack/05-mining-pool
metaphorics Oct 28, 2026
de196fc
Merge main into stack/05-mining-pool
metaphorics Oct 28, 2026
a18d6ed
Adapt merged sync tests to branch ownership API
metaphorics Oct 28, 2026
6f63d96
Update lockfile after main integration
metaphorics Oct 28, 2026
48b895d
refactor(mining): consolidate pool crates under mining::pool
metaphorics Oct 28, 2026
daf2376
fix(pool-sv2): queue acks before dropping pending tickets
metaphorics Oct 28, 2026
2ec2170
fix(pool): unburn SV2 dedup keys dropped without durable record
metaphorics Oct 28, 2026
cd2cfb1
fix(pool-sv2): expire unacknowledged share tickets with unburn
metaphorics Oct 28, 2026
484563c
fix(pool-ledger): stream prune deletes in bounded batches
metaphorics Oct 28, 2026
7841a83
fix(pool-ledger): snapshot PPLNS window outside the writer lock
metaphorics Oct 28, 2026
3da004b
Merge main into stack/05-mining-pool
metaphorics Oct 28, 2026
b936fd8
Merge remote-tracking branch 'origin/main' into stack/05-mining-pool
metaphorics Oct 28, 2026
d4664de
fix(pool-sv2): track last parent per channel and force Future on mism…
metaphorics Oct 28, 2026
9bc4daf
fix(pool): cap fallback block work at network target
metaphorics Oct 28, 2026
e3758a0
fix(pool-ledger): validate generation inside write txn before Fail
metaphorics Oct 28, 2026
1291b85
fix(pool-ledger): derive share count from sequence metadata
metaphorics Oct 28, 2026
f8a6e58
fix(pool-ledger): bound reconcile units without holding chain fence
metaphorics Oct 28, 2026
a4f6da0
fix(pool): carry rejected outcome through completion to deferred reply
metaphorics Oct 28, 2026
88abef5
fix(pool): retain bounded submission recovery for Inconclusive
metaphorics Oct 28, 2026
3363747
Merge origin/main e86593807 into stack/05-mining-pool
metaphorics Oct 28, 2026
68af51e
Merge branch 'main' into stack/05-mining-pool
metaphoric-dev Oct 28, 2026
437b346
fix(pool-ledger): bound prune deletes with sequence lookups
metaphorics Oct 28, 2026
89fe602
fix(pool-ledger): demote matured rounds on canonical depth loss
metaphorics Oct 28, 2026
b7501bf
fix(pool-sv2): retain reaped worker panic through stop_join
metaphorics Oct 28, 2026
b324d32
Merge remote-tracking branch 'origin/stack/05-mining-pool' into stack…
metaphorics Oct 28, 2026
0938c6c
Merge branch 'main' into stack/05-mining-pool
metaphoric-dev Oct 28, 2026
e0294bd
Merge branch 'main' into stack/05-mining-pool
metaphoric-dev Oct 28, 2026
cb409f1
fix(pool-ledger): require confirmations for retained Confirmed payout
metaphorics Oct 28, 2026
ac15848
fix(pool): bound SV1 outbox with worst-case block charge
metaphorics Oct 28, 2026
13739af
fix(pool-sv2): keep deferred recovery charged to shared capacity
metaphorics Oct 28, 2026
ab30278
fix(pool-ledger): bound reconcile pages with key-cursor snapshot scans
metaphorics Oct 28, 2026
560310f
fix(pool-ledger): cap payout batches by serialized output weight
metaphorics Oct 28, 2026
9537779
fix(pool-ledger): confirm replacement payouts without spend index
metaphorics Oct 28, 2026
5c357be
style: format workspace for CI
metaphorics Oct 29, 2026
77f8cb1
fix(index): clear strict clippy findings
metaphorics Oct 29, 2026
0678980
fix(rpc): clear strict clippy findings
metaphorics Oct 29, 2026
f61055c
fix(node): clear strict clippy findings
metaphorics Oct 29, 2026
338d0ad
fix(p2p): clear clippy debt and wire addrv2
metaphorics Oct 29, 2026
46b584f
chore: refresh fuzz and template lockfiles
metaphorics Oct 29, 2026
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
363 changes: 334 additions & 29 deletions Cargo.lock

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ bitcoin-rs-e2e = { path = "e2e", version = "0.14.0" }
# Allocator. Defaults pull `secure` and `extended` overhead — disable for perf.
mimalloc = { version = ">=0.1.50, <0.2", default-features = false }

# --- Stratum V2 transport ------------------------------------------------------
# Pinned SRI release family (v1.12.0): these crates are semver-major-coupled
# and their wire layouts MUST move together. noise_sv2 2.0.0 is admitted with
# the narrow duplicate-crypto exception documented in deny.toml.
binary_sv2 = "=7.0.0"
framing_sv2 = "=8.0.0"
codec_sv2 = { version = "=7.0.0" }
noise_sv2 = "=2.0.0"
mining_sv2 = "=12.0.0"
common_messages_sv2 = "=9.0.0"

# Authority-key zeroization used by the SV2 Noise boundary.
zeroize = { version = ">=1.8.2, <2", default-features = false, features = ["alloc"] }

# --- Bitcoin ecosystem --------------------------------------------------------
# bitcoin 0.32 line; 0.33 is still beta. `default = [std, secp-recovery]`.
# Keep `bitcoinconsensus-std` out of the workspace-wide dependency: the
Expand Down
2 changes: 2 additions & 0 deletions bin/bitcoin-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ redb = ["bitcoin-rs-node/redb"]
kernel = ["bitcoin-rs-node/kernel"]
zmq = ["bitcoin-rs-node/zmq"]
silent-payments = ["bitcoin-rs-node/silent-payments"]
pool = ["bitcoin-rs-node/pool"]
pool-sv2 = ["bitcoin-rs-node/pool-sv2"]

[[test]]
name = "g17_dependency_direction"
Expand Down
2 changes: 1 addition & 1 deletion bin/bitcoin-rs/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
use anyhow::{Context as _, Result};
use bitcoin_rs_chainstate::ValidationMode;
use bitcoin_rs_node::options::{
parse_connect_endpoint, parse_network, parse_p2p_magic, parse_script_index,
PoolOverrides, parse_connect_endpoint, parse_network, parse_p2p_magic, parse_script_index,
parse_storage_backend, parse_validation_engine, parse_validation_mode,
};
use bitcoin_rs_node::{
Expand Down
8 changes: 4 additions & 4 deletions crates/chain/src/header_sync.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use bitcoin_rs_consensus::MAX_TIMEWARP;
use bitcoin_rs_primitives::{CompactTarget, Hash256, Network};

pub use pow::compact_is_met_by;
use pow::{compact_to_target, target_to_compact};
pub use pow::{compact_is_met_by, compact_to_target};
use pow::target_to_compact;

use crate::{
ChainError,
Expand Down Expand Up @@ -518,7 +518,7 @@ pub fn permitted_difficulty_transition(
/// overflowing shift folds to `ChainWork::ZERO` instead of surfacing
/// `pfOverflow`, and a sign-flagged encoding decodes to `ChainWork::ZERO`
/// instead of being rejected by name.
pub(crate) mod pow {
pub mod pow {
use bitcoin_rs_primitives::{CompactTarget, Hash256};

use crate::node::ChainWork;
Expand Down Expand Up @@ -549,7 +549,7 @@ pub(crate) mod pow {

/// Decodes a compact target, returning zero for negative encodings.
#[must_use]
pub(crate) fn compact_to_target(bits: CompactTarget) -> ChainWork {
pub fn compact_to_target(bits: CompactTarget) -> ChainWork {
let decoded = decode_compact(bits.to_consensus());
if decoded.negative {
ChainWork::ZERO
Expand Down
2 changes: 1 addition & 1 deletion crates/chain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub use deployment::{
};
pub use header_sync::{
AcceptHeaders, HeaderAdmission, HeaderValidationMode, accept_headers, block_work,
compact_is_met_by, current_unix_seconds, permitted_difficulty_transition,
compact_is_met_by, compact_to_target, current_unix_seconds, permitted_difficulty_transition,
validate_contextual_header, validate_pow,
};
pub use ibd::InitialBlockDownload;
Expand Down
39 changes: 39 additions & 0 deletions crates/mining/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,27 @@ compact_str.workspace = true
parking_lot.workspace = true
thiserror.workspace = true
tracing.workspace = true
bitcoin-rs-storage = { workspace = true, optional = true }
ruint = { workspace = true, optional = true }
sonic-rs = { workspace = true, optional = true }
sha2 = { workspace = true, optional = true }
# Pinned SRI release family; only the optional SV2 adapter uses Noise.
binary_sv2 = { workspace = true, optional = true }
framing_sv2 = { workspace = true, optional = true }
codec_sv2 = { workspace = true, features = ["noise_sv2"], optional = true }
noise_sv2 = { workspace = true, optional = true }
mining_sv2 = { workspace = true, optional = true }
common_messages_sv2 = { workspace = true, optional = true }
zeroize = { workspace = true, optional = true }

[features]
default = []
test-seam = []
pool = ["dep:bitcoin-rs-storage", "dep:ruint", "dep:sonic-rs", "dep:sha2"]
pool-sv2 = [
"pool", "dep:binary_sv2", "dep:framing_sv2", "dep:codec_sv2",
"dep:noise_sv2", "dep:mining_sv2", "dep:common_messages_sv2", "dep:zeroize",
]


[dev-dependencies]
Expand All @@ -37,6 +54,28 @@ criterion.workspace = true
# gateway replacement seam must arrive through the test-seam feature, the same
# way bitcoin-rs-p2p and bitcoin-rs-rpc opt in.
bitcoin-rs-mempool = { workspace = true, features = ["test-seam"] }
bitcoin-rs-mining = { workspace = true, features = ["test-seam"] }
bitcoin-rs-storage = { workspace = true, features = ["test-seam", "redb", "fjall"] }
tempfile.workspace = true
# Miner-side key generation uses the same version as the optional Noise graph.
secp256k1 = { version = "=0.28.2", default-features = false, features = ["std", "rand-std"] }
rand = { version = "0.8.5", default-features = false, features = ["std", "std_rng"] }

[[test]]
name = "pool_jobs"
required-features = ["pool"]

[[test]]
name = "pool_sv1"
required-features = ["pool"]

[[test]]
name = "pool_sv2"
required-features = ["pool-sv2"]

[[test]]
name = "pool_ledger"
required-features = ["pool", "test-seam"]

[[bench]]
name = "candidate"
Expand Down
10 changes: 10 additions & 0 deletions crates/mining/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,13 @@ against live fixture pools. It is a measurement seam, not a budget.

Part of [`bitcoin-rs`](../../README.md); see [`CONCEPTS.md`](../../CONCEPTS.md) for the
project vocabulary.

## Native pool

The `pool` feature adds `pool::JobBook`, `pool::PoolCore`, the SV1 server
in `pool::stratum::sv1`, and durable PPLNS accounting in `pool::ledger`.
`pool-sv2` additionally enables the Noise transport and SV2 protocol session
in `pool::stratum::sv2`. Both protocols use the same job/share owner and
`MiningControl` submission boundary. The node owns listener composition,
chain observations, storage construction, and shutdown. Neither feature
enables the runtime by itself. See [pool operation](../../docs/pool.md).
5 changes: 5 additions & 0 deletions crates/mining/src/bip22.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ use crate::{MiningControlError, MiningError};

const SIGOPS_LIMIT_REASON: &str = "bad-blk-sigops";

/// BIP22 reason for a block whose parent is no longer the best tip. The node
/// answers it for `ApplyError::PrevHashMismatch`; pool adapters read it as a
/// stale sibling instead of a defective block.
pub const STALE_PARENT_REASON: &str = "inconclusive-not-best-prevblk";

/// Core `GetRejectReason` strings for consensus failures (API-19).
pub fn consensus_reject_reason(error: &ConsensusError) -> CompactString {
CompactString::from(match error {
Expand Down
5 changes: 3 additions & 2 deletions crates/mining/src/coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use bitcoin_rs_primitives::{
use bitcoin_rs_script::push_int;
use thiserror::Error;

const MIN_COINBASE_SCRIPT_SIG_LEN: usize = 2;
use crate::template::CoinbaseBudget;

/// BIP141 `OP_RETURN` `PUSH36` `aa21a9ed` prefix. Core `MINIMUM_WITNESS_COMMITMENT` is 38 bytes.
const WITNESS_COMMITMENT_PREFIX: [u8; 6] = [0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed];

Expand Down Expand Up @@ -140,7 +141,7 @@ fn coinbase_script_sig(height: u32) -> Vec<u8> {
// Consensus rejects coinbase scriptSigs shorter than two bytes
// (`bad-cb-length`). Heights whose BIP34 prefix is a single opcode need a
// trailing OP_0, matching Bitcoin Core's `CreateNewBlock`.
if script.len() < MIN_COINBASE_SCRIPT_SIG_LEN {
if script.len() < CoinbaseBudget::MIN_SCRIPT_SIG_LEN {
script.push(0x00);
}
script
Expand Down
8 changes: 7 additions & 1 deletion crates/mining/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ mod policy;
/// Transport-neutral candidate assembly.
mod template;

pub use bip22::{chain_reject_reason, consensus_reject_reason, header_reject_reason};
pub use bip22::{
STALE_PARENT_REASON, chain_reject_reason, consensus_reject_reason, header_reject_reason,
};
pub use coinbase::{
MiningError, WITNESS_RESERVED_VALUE, needs_witness_reserved_value,
update_uncommitted_block_structures, witness_commitment_script,
Expand All @@ -46,3 +48,7 @@ pub use template::{
TemplateId, assemble_candidate, assemble_ordered_candidate, select_template_body,
select_template_body_after, solve_block,
};

/// Optional native mining pool protocols and accounting.
#[cfg(feature = "pool")]
pub mod pool;
21 changes: 21 additions & 0 deletions crates/mining/src/pool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//! Native mining pool jobs, protocols, and durable accounting.
//!
//! One JobBook owns job projection and share validation for both protocols.
//! Node composition supplies mining control, storage, and chain observations.
#![forbid(unsafe_code)]

mod core;
mod job;
pub mod ledger;
pub mod stratum;

pub use core::{
BlockOutcome, LedgerUnavailable, PoolCore, RecordOutcome, RefreshError, Refreshed, ShareLedger,
WorkerIdentity,
};
pub use job::{
AcceptedShare, BIP320_VERSION_MASK, BlockReceipt, BlockStatus, Extranonce, ExtranonceLayout,
FoundBlock, Installed, Job, JobBook, JobBookConfig, JobError, JobId,
MAX_COINBASE_SCRIPT_SIG_LEN, MAX_NTIME_FORWARD_SECS, Session, SessionId, ShareClass,
ShareError, ShareOutcome, ShareSubmission, ShareTarget, ShareWork, StaleReason, fetch_template,
};
Loading
Loading