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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ goPool is a **from-scratch Golang solo Bitcoin mining pool**. It connects direct
- **Operator controls**: optional admin panel for live settings updates, persist-to-disk controls, log tooling, and guarded reboot action.
- **Storage and backups**: SQLite state store with atomic snapshots and optional Backblaze B2 upload workflow.
- **Auth/integrations**: optional Clerk auth flows, saved-worker pages, Discord notification toggles, and one-time worker linking codes.
- **Performance options**: fast-path Stratum decode/encode toggles, socket buffer tuning, optional SIMD JSON/hash paths, and built-in profiling hooks.
- **Performance options**: Stratum socket buffer tuning, optional SIMD JSON/hash paths, and built-in profiling hooks.

## Direct Go libraries and licenses

Expand Down
4 changes: 0 additions & 4 deletions config_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,6 @@ func buildTuningFileConfig(cfg Config) tuningFileConfig {
SavedWorkerHistoryFlushIntervalSec: new(int(cfg.SavedWorkerHistoryFlushInterval / time.Second)),
},
Stratum: tuningStratumConfig{
FastDecodeEnabled: new(cfg.StratumFastDecodeEnabled),
FastEncodeEnabled: new(cfg.StratumFastEncodeEnabled),
TCPReadBufferBytes: new(cfg.StratumTCPReadBufferBytes),
TCPWriteBufferBytes: new(cfg.StratumTCPWriteBufferBytes),
},
Expand Down Expand Up @@ -203,8 +201,6 @@ func (cfg Config) Effective() EffectiveConfig {
GitHubURL: cfg.GitHubURL,
ServerLocation: cfg.ServerLocation,
StratumTLSListen: cfg.StratumTLSListen,
StratumFastDecodeEnabled: cfg.StratumFastDecodeEnabled,
StratumFastEncodeEnabled: cfg.StratumFastEncodeEnabled,
SafeMode: cfg.SafeMode,
CKPoolEmulate: cfg.CKPoolEmulate,
StratumTCPReadBufferBytes: cfg.StratumTCPReadBufferBytes,
Expand Down
6 changes: 2 additions & 4 deletions config_examples.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func baseConfigDocComments() []byte {
# - [stratum].stratum_password_enabled: Require miners to send a password on authorize (requires restart).
# - [stratum].stratum_password: Password string checked against mining.authorize params (requires restart).
# - [stratum].stratum_password_public: Show the stratum password on the public connect panel (requires restart).
# - [stratum].safe_mode: Force conservative compatibility/safety behavior (disables fast-path Stratum tuning and unsafe debug/public-RPC toggles).
# - [stratum].safe_mode: Force conservative compatibility/safety behavior (disables unsafe debug/public-RPC toggles).
# - Runtime override: --safe-mode=true/false
#
# Logging
Expand Down Expand Up @@ -144,7 +144,7 @@ func tuningConfigDocComments() []byte {
# - template_extra_nonce2_size: Template extranonce2 byte length used in generated jobs (requires restart).
# - job_entropy: Entropy bytes added to per-job coinbase tags (requires restart).
# - coinbase_scriptsig_max_bytes: Maximum allowed coinbase scriptSig size in bytes (requires restart).
# - difficulty_step_granularity: Quantize difficulty to 2^(k/N) steps (N=1 power-of-two, N=2 half, N=3 third, N=4 quarter). Higher values are finer; requires restart.
# - difficulty_step_granularity: Quantize difficulty to 2^(k/N) steps (N=1 power-of-two, N=4 quarter, N=10 tenth-step default). Higher values are finer; requires restart.
#
# Hashrate ([hashrate])
# - hashrate_ema_tau_seconds: EMA time constant for per-connection hashrate smoothing (seconds; requires restart).
Expand All @@ -156,8 +156,6 @@ func tuningConfigDocComments() []byte {
# - enabled/max_ping_ms/min_peers: Optional cleanup of high-latency peers.
#
# Stratum tuning ([stratum])
# - fast_decode_enabled: Enable fast-path decoding/sniffing for common Stratum methods (restart to apply).
# - fast_encode_enabled: Enable fast-path response encoding for common Stratum responses (restart to apply).
# - tcp_read_buffer_bytes / tcp_write_buffer_bytes: Socket buffer sizes in bytes (0 = OS default; restart to apply).
#
#
Expand Down
6 changes: 2 additions & 4 deletions config_file_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,8 @@ type tuningHashrateConfig struct {
}

type tuningStratumConfig struct {
FastDecodeEnabled *bool `toml:"fast_decode_enabled"`
FastEncodeEnabled *bool `toml:"fast_encode_enabled"`
TCPReadBufferBytes *int `toml:"tcp_read_buffer_bytes"`
TCPWriteBufferBytes *int `toml:"tcp_write_buffer_bytes"`
TCPReadBufferBytes *int `toml:"tcp_read_buffer_bytes"`
TCPWriteBufferBytes *int `toml:"tcp_write_buffer_bytes"`
}

type tuningFileConfig struct {
Expand Down
6 changes: 0 additions & 6 deletions config_load.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,12 +632,6 @@ func applyPolicyConfig(cfg *Config, fc policyFileConfig) {
}

func applyTuningConfig(cfg *Config, fc tuningFileConfig) {
if fc.Stratum.FastDecodeEnabled != nil {
cfg.StratumFastDecodeEnabled = *fc.Stratum.FastDecodeEnabled
}
if fc.Stratum.FastEncodeEnabled != nil {
cfg.StratumFastEncodeEnabled = *fc.Stratum.FastEncodeEnabled
}
if fc.Stratum.TCPReadBufferBytes != nil {
cfg.StratumTCPReadBufferBytes = *fc.Stratum.TCPReadBufferBytes
}
Expand Down
31 changes: 31 additions & 0 deletions config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,37 @@ func TestAutoConfigureAcceptRateLimits_SteadyStateAbove1000Capped(t *testing.T)
}
}

func TestLoadTuningFile_IgnoresRemovedStratumFastPathKeys(t *testing.T) {
path := filepath.Join(t.TempDir(), "tuning.toml")
data := []byte(`
[stratum]
fast_decode_enabled = true
fast_encode_enabled = true
tcp_read_buffer_bytes = 131072
tcp_write_buffer_bytes = 262144
`)
if err := os.WriteFile(path, data, 0o644); err != nil {
t.Fatalf("write tuning file: %v", err)
}

loaded, ok, err := loadTuningFile(path)
if err != nil {
t.Fatalf("loadTuningFile returned error for legacy fast-path keys: %v", err)
}
if !ok || loaded == nil {
t.Fatalf("expected tuning file to load")
}

cfg := defaultConfig()
applyTuningConfig(&cfg, *loaded)
if cfg.StratumTCPReadBufferBytes != 131072 {
t.Fatalf("StratumTCPReadBufferBytes = %d, want 131072", cfg.StratumTCPReadBufferBytes)
}
if cfg.StratumTCPWriteBufferBytes != 262144 {
t.Fatalf("StratumTCPWriteBufferBytes = %d, want 262144", cfg.StratumTCPWriteBufferBytes)
}
}

func TestRewriteConfigFile_BackupAndAtomic(t *testing.T) {
tmpDir := t.TempDir()
cfgPath := filepath.Join(tmpDir, "config.toml")
Expand Down
10 changes: 1 addition & 9 deletions config_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,6 @@ type Config struct {
StratumPasswordEnabled bool
StratumPassword string
StratumPasswordPublic bool // show password in public connect panel when enabled
// Stratum fast decode: enables lightweight request sniffing for common methods
// (e.g. mining.submit/mining.subscribe/mining.ping) to reduce allocations.
StratumFastDecodeEnabled bool
// Stratum fast encode: enables canned/manual JSON encoding for common Stratum
// responses to reduce allocations (encode path only).
StratumFastEncodeEnabled bool
// Safe mode: force conservative compatibility/safety-oriented runtime behavior.
SafeMode bool
// CKPool compatibility mode: advertise a minimal CKPool-style subscribe
Expand Down Expand Up @@ -154,7 +148,7 @@ type Config struct {

LockSuggestedDifficulty bool // keep suggested difficulty instead of vardiff
EnforceSuggestedDifficultyLimits bool // ban/disconnect when suggest_* outside min/max
DifficultyStepGranularity int // 1=pow2, 2=half, 3=third, 4=quarter steps
DifficultyStepGranularity int // quantize to 2^(k/N) steps; default N=10
HashrateEMATauSeconds float64 // EMA time constant for hashrate
HashrateCumulativeEnabled bool // blend per-connection EMA with cumulative hashrate (display)
HashrateRecentCumulativeEnabled bool // allow short-horizon cumulative (vardiff window) to influence display
Expand Down Expand Up @@ -208,8 +202,6 @@ type EffectiveConfig struct {
GitHubURL string `json:"github_url,omitempty"`
ServerLocation string `json:"server_location,omitempty"`
StratumTLSListen string `json:"stratum_tls_listen,omitempty"`
StratumFastDecodeEnabled bool `json:"stratum_fast_decode_enabled"`
StratumFastEncodeEnabled bool `json:"stratum_fast_encode_enabled"`
SafeMode bool `json:"safe_mode,omitempty"`
CKPoolEmulate bool `json:"ckpool_emulate"`
StratumTCPReadBufferBytes int `json:"stratum_tcp_read_buffer_bytes,omitempty"`
Expand Down
2 changes: 1 addition & 1 deletion const.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ const (
defaultVarDiffStep = 2
defaultVarDiffDampingFactor = 0.7
defaultVarDiffRetargetDelay = 30 * time.Second
defaultDifficultyStepGranularity = 4
defaultDifficultyStepGranularity = 10
vardiffAdaptiveMinWindow = 30 * time.Second
vardiffAdaptiveMaxWindow = 4 * time.Minute
vardiffAdaptiveHighShareCount = 24.0
Expand Down
2 changes: 1 addition & 1 deletion data/config/examples/config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# - [stratum].stratum_password_enabled: Require miners to send a password on authorize (requires restart).
# - [stratum].stratum_password: Password string checked against mining.authorize params (requires restart).
# - [stratum].stratum_password_public: Show the stratum password on the public connect panel (requires restart).
# - [stratum].safe_mode: Force conservative compatibility/safety behavior (disables fast-path Stratum tuning and unsafe debug/public-RPC toggles).
# - [stratum].safe_mode: Force conservative compatibility/safety behavior (disables unsafe debug/public-RPC toggles).
# - Runtime override: --safe-mode=true/false
#
# Logging
Expand Down
8 changes: 2 additions & 6 deletions data/config/examples/tuning.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# - template_extra_nonce2_size: Template extranonce2 byte length used in generated jobs (requires restart).
# - job_entropy: Entropy bytes added to per-job coinbase tags (requires restart).
# - coinbase_scriptsig_max_bytes: Maximum allowed coinbase scriptSig size in bytes (requires restart).
# - difficulty_step_granularity: Quantize difficulty to 2^(k/N) steps (N=1 power-of-two, N=2 half, N=3 third, N=4 quarter). Higher values are finer; requires restart.
# - difficulty_step_granularity: Quantize difficulty to 2^(k/N) steps (N=1 power-of-two, N=4 quarter, N=10 tenth-step default). Higher values are finer; requires restart.
#
# Hashrate ([hashrate])
# - hashrate_ema_tau_seconds: EMA time constant for per-connection hashrate smoothing (seconds; requires restart).
Expand All @@ -38,8 +38,6 @@
# - enabled/max_ping_ms/min_peers: Optional cleanup of high-latency peers.
#
# Stratum tuning ([stratum])
# - fast_decode_enabled: Enable fast-path decoding/sniffing for common Stratum methods (restart to apply).
# - fast_encode_enabled: Enable fast-path response encoding for common Stratum responses (restart to apply).
# - tcp_read_buffer_bytes / tcp_write_buffer_bytes: Socket buffer sizes in bytes (0 = OS default; restart to apply).
#
#
Expand All @@ -61,7 +59,7 @@

[mining]
coinbase_scriptsig_max_bytes = 100
difficulty_step_granularity = 4
difficulty_step_granularity = 10
disable_pool_job_entropy = false
extranonce2_size = 4
job_entropy = 4
Expand All @@ -87,7 +85,5 @@
stratum_messages_per_minute = 0

[stratum]
fast_decode_enabled = false
fast_encode_enabled = false
tcp_read_buffer_bytes = 0
tcp_write_buffer_bytes = 0
4 changes: 2 additions & 2 deletions data/templates/admin.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@
<div class="label"><label class="label" style="font-weight:500;margin:0;display:flex;align-items:center;gap:8px;"><input type="checkbox" name="enforce_suggested_difficulty_limits" value="1" {{if .Settings.EnforceSuggestedDifficultyLimits}}checked{{end}}><span>enforce_suggested_difficulty_limits</span></label><div class="label-note">Reject/ban suggested difficulties outside configured min/max bounds. Applies on live apply.</div></div>
</div>
<div>
<div class="label">difficulty_step_granularity<div class="label-note">Difficulty quantization granularity for mining.set_difficulty (1=power-of-two, 2=half, 3=third, 4=quarter). Applies on live apply.</div></div>
<div class="label">difficulty_step_granularity<div class="label-note">Difficulty quantization granularity for mining.set_difficulty (1=power-of-two, 4=quarter, 10=tenth-step default). Applies on live apply.</div></div>
<input name="difficulty_step_granularity" type="number" min="1" class="textfield" value="{{.Settings.DifficultyStepGranularity}}">
</div>
</div>
Expand Down Expand Up @@ -459,7 +459,7 @@
<div class="card">
<div class="label">Reload UI assets</div>
<p class="text-sm" style="margin:4px 0 10px 0;">
Reloads HTML templates and cached static files from disk without restarting the pool.
Re-parses embedded HTML templates and refreshes the embedded static cache without restarting the pool.
</p>
{{if .AdminReloadError}}
<p class="text-sm" style="color:#f88d8d;">{{.AdminReloadError}}</p>
Expand Down
16 changes: 15 additions & 1 deletion data/templates/hashrate_graph_script.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,21 @@
return `${val.toFixed(2)} ${units[idx]}`;
}

function formatSmallDifficulty(value) {
let prec = Math.ceil(-Math.log10(value)) + 2;
prec = Math.min(8, Math.max(3, prec));
const scale = 10 ** prec;
const trunc = Math.floor(value * scale) / scale;
let s = trunc.toFixed(prec);
s = s.replace(/\.?0+$/, '');
if (s === '0') return value.toPrecision(3).replace(/\.?0+(e|$)/, '$1');
return s;
}

function formatDifficultyGraph(diff) {
const value = Number(diff || 0);
if (!Number.isFinite(value) || value <= 0) return '0';
if (value < 1) return formatSmallDifficulty(value);
if (value < 1000) return value.toFixed(0);
const units = ['K', 'M', 'G', 'T', 'P', 'E'];
let scaled = value;
Expand Down Expand Up @@ -435,7 +447,9 @@
function primeHashrateGraphHistory(history) {
let hRows = [];
let bRows = [];
let compactHistory = false;
if (history && typeof history === 'object' && !Array.isArray(history) && Array.isArray(history.hq)) {
compactHistory = true;
hRows = decodeCompactWorkerSeries(history, 'hq', 'h0', 'h1').rows;
bRows = decodeCompactWorkerSeries(history, 'bq', 'b0', 'b1').rows;
} else if (Array.isArray(history)) {
Expand All @@ -449,7 +463,7 @@
if ((!Array.isArray(hRows) || hRows.length === 0) && (!Array.isArray(bRows) || bRows.length === 0)) {
return false;
}
if (!historyPrimed) {
if (!historyPrimed || compactHistory) {
historyHashrateRows = Array.isArray(hRows) ? hRows : [];
}
historyBestRows = Array.isArray(bRows) ? bRows : [];
Expand Down
33 changes: 31 additions & 2 deletions data/templates/layout.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -134,13 +134,42 @@ document.addEventListener('click', function(e) {
if (!copyable) return;

const text = copyable.dataset.copy || copyable.textContent;
navigator.clipboard.writeText(text).then(function() {
function fallbackCopy(value) {
const ta = document.createElement('textarea');
ta.value = value;
ta.setAttribute('readonly', '');
ta.style.position = 'fixed';
ta.style.opacity = '0';
document.body.appendChild(ta);
ta.select();
try {
return document.execCommand('copy');
} finally {
document.body.removeChild(ta);
}
}

function flashCopied() {
const original = copyable.style.background;
copyable.style.background = 'var(--accent-soft)';
setTimeout(function() {
copyable.style.background = original;
}, 200);
}).catch(function(err) {
}

const canUseClipboard = navigator.clipboard && typeof navigator.clipboard.writeText === 'function';
const copyPromise = canUseClipboard
? navigator.clipboard.writeText(text)
: new Promise(function(resolve, reject) {
try {
fallbackCopy(text);
resolve();
} catch (err) {
reject(err);
}
});

copyPromise.then(flashCopied).catch(function(err) {
console.error('Failed to copy:', err);
});
});
Expand Down
20 changes: 13 additions & 7 deletions data/templates/node.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -218,13 +218,19 @@
item.className = 'peer-entry';
const pingLabel = peer.ping_ms > 0 ? `${peer.ping_ms.toFixed(1)} ms` : '--';
const connectedLabel = formatDurationLabel(peer.connected_at);
item.innerHTML = `
<div class="peer-label">${peer.display}</div>
<div class="peer-meta">
<span>Ping ${pingLabel}</span>
<span>Time ${connectedLabel}</span>
</div>
`;
const label = document.createElement('div');
label.className = 'peer-label';
label.textContent = peer.display || '--';
const meta = document.createElement('div');
meta.className = 'peer-meta';
const ping = document.createElement('span');
ping.textContent = `Ping ${pingLabel}`;
const connected = document.createElement('span');
connected.textContent = `Time ${connectedLabel}`;
meta.appendChild(ping);
meta.appendChild(connected);
item.appendChild(label);
item.appendChild(meta);
grid.appendChild(item);
});
peerListEl.appendChild(grid);
Expand Down
Loading
Loading