From 05a446d895494438026d71d0aff7926cb16a9129 Mon Sep 17 00:00:00 2001 From: naliyi <154817482+naliyi@users.noreply.github.com> Date: Fri, 4 Sep 2026 08:09:28 +0000 Subject: [PATCH 1/5] build: bump nmilat to v0.2.7, fixing a relay-side PoW mismatch drop Upstream fix in ohstr/nmilat#10: relay ingestion unconditionally rejected any event whose nonce tag overclaimed its NIP-13 difficulty, regardless of strictPow/--strict-pow (that flag only ever governed ncli's own read-side check, never the destination relay's). Also picks up the go1.26.8 bump nmilat v0.2.6 already required. --- CHANGELOG.md | 10 ++++++++++ go.mod | 4 ++-- go.sum | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cce5de..7333e9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [Unreleased] + +### Fixed + +- `apply stream`/`sync` no longer silently drop an event at the destination + relay just because its `nonce` tag overclaims its NIP-13 difficulty -- + regardless of `strictPow`/`--strict-pow`, since that setting only ever + governed ncli's own read-side check, never the relay's. Bumps + `github.com/ohstr/nmilat` to v0.2.7, which fixes this on the relay side. + ## [0.4.5] ### Added diff --git a/go.mod b/go.mod index 9ec2407..b58674f 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ohstr/ncli -go 1.26.1 +go 1.26.8 require ( github.com/btcsuite/btcd/btcec/v2 v2.3.4 @@ -69,7 +69,7 @@ require ( github.com/charmbracelet/bubbles v1.0.0 github.com/charmbracelet/bubbletea v1.3.10 github.com/charmbracelet/lipgloss v1.1.0 - github.com/ohstr/nmilat v0.2.5 + github.com/ohstr/nmilat v0.2.7 golang.org/x/sync v0.20.0 golang.org/x/sys v0.45.0 golang.org/x/term v0.43.0 diff --git a/go.sum b/go.sum index e823f05..c00139f 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,8 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= -github.com/ohstr/nmilat v0.2.5 h1:Gza6dDyPP+6VIoZSVd9WfSYl3VH65eEqaPm0znu3APs= -github.com/ohstr/nmilat v0.2.5/go.mod h1:jWIyGhWgCuWv+cDZ0hdivvCmYjSh8bTxnk54NxXtqvA= +github.com/ohstr/nmilat v0.2.7 h1:i+pt8Kd8TBqYW7MgQjqGU8jRgMF4ChnSJnVc2d2uL0w= +github.com/ohstr/nmilat v0.2.7/go.mod h1:+6B0CT40RAJmnZESl1sBukc07RkdyPn5/EQ8ROVof0Y= github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= From d06dbbfa57feb09b723416252929ba21cd4db71e Mon Sep 17 00:00:00 2001 From: naliyi <154817482+naliyi@users.noreply.github.com> Date: Fri, 4 Sep 2026 08:14:24 +0000 Subject: [PATCH 2/5] docs: clarify strictPow only governs ncli's own side, and pow.strict now also catches self-contradictory nonce tags Directly informed by the nmilat v0.2.7 bump: previously any nmilat relay rejected a self-contradictory nonce tag unconditionally, so this distinction didn't matter in practice. Now that it's gated behind Limitation.StrictPow, the relay-side pow.strict doc needed to say what it actually covers, and apply's strictPow doc needed the caveat that it never reached the destination relay's own decision anyway -- the actual root cause of the original bug report. --- README.md | 16 ++++++++++++---- skills/ncli-apply/SKILL.md | 7 +++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5b7a226..54c4630 100644 --- a/README.md +++ b/README.md @@ -232,13 +232,15 @@ ncli find --search "jack" -k 1 -l 5 -s localhost:5500 ``` Require NIP-13 proof-of-work on published events with a `pow:` block — -`min: 0` (the default) accepts everything; a non-zero `min` is advertised to -clients via NIP-11 either way, and `strict: true` is what actually turns on -rejecting events that fall short: +`min: 0` (the default) accepts everything, including an event whose `nonce` +tag lies about its own difficulty; a non-zero `min` is advertised to clients +via NIP-11 either way, and `strict: true` is what actually turns on +rejecting events, both ones that fall short of `min` and ones whose `nonce` +tag doesn't match reality regardless of `min`: ```yaml pow: - strict: false # true rejects under-difficulty events; false just advertises min + strict: false # true rejects under-difficulty/self-contradictory nonce tags; false accepts either min: 20 # required leading-zero-bit difficulty; 0 = no requirement ``` @@ -518,6 +520,12 @@ true` field (both kinds support it) to reject it instead — the flag, when passed explicitly, overrides whatever the spec file says. A `trusted: true` flow is never subject to this check either way. +This only governs ncli's own read-side judgment on events it pulls from a +`from` flow — it has no effect on what a `to` relay independently decides +once ncli forwards an event to it. A relay you don't control may still +reject a bad-PoW event on its own terms regardless of `strictPow` here; see +its own `pow:` config (above) if you also operate that relay. + **`stream`** — tail events live, forwarding everything matching `filters` from every `from` flow to every `to` flow until interrupted (any number of sources and destinations, mixed relays/stores): diff --git a/skills/ncli-apply/SKILL.md b/skills/ncli-apply/SKILL.md index 579b4d8..29b4744 100644 --- a/skills/ncli-apply/SKILL.md +++ b/skills/ncli-apply/SKILL.md @@ -43,6 +43,13 @@ Failures counter); for `sync` it's silently dropped from the pulled batch `trusted: true` flow is never subject to this check, regardless of `strictPow` — same as it already skips signature verification. +`strictPow` only governs `apply`'s own judgment on events read from a +`from` flow. It has no bearing on what a `to` relay independently decides +once `apply` forwards an event to it — a relay you don't control can still +reject a bad-PoW event on its own terms (its own `pow:`/`strict` config, or +just NIP-13 validation baked into its ingestion path) no matter what +`strictPow` is set to here. + | kind | what it does | writes anything? | |---|---|---| | `stream` | Tails live events matching `filters` from every `from` flow to every `to` flow, until interrupted | Yes, continuously | From b899ff55827de7bd45cb605508094ca9b45f0fe5 Mon Sep 17 00:00:00 2001 From: naliyi <154817482+naliyi@users.noreply.github.com> Date: Fri, 4 Sep 2026 08:16:32 +0000 Subject: [PATCH 3/5] docs: trim strictPow/pow.strict clarifications to match terse existing style --- README.md | 20 +++++++++----------- skills/ncli-apply/SKILL.md | 8 +++----- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 54c4630..331ad8f 100644 --- a/README.md +++ b/README.md @@ -232,15 +232,14 @@ ncli find --search "jack" -k 1 -l 5 -s localhost:5500 ``` Require NIP-13 proof-of-work on published events with a `pow:` block — -`min: 0` (the default) accepts everything, including an event whose `nonce` -tag lies about its own difficulty; a non-zero `min` is advertised to clients -via NIP-11 either way, and `strict: true` is what actually turns on -rejecting events, both ones that fall short of `min` and ones whose `nonce` -tag doesn't match reality regardless of `min`: +`min: 0` (the default) accepts everything, even a lying `nonce` tag; a +non-zero `min` is advertised via NIP-11 either way, and `strict: true` is +what actually rejects events, both under-difficulty ones and ones whose +`nonce` tag doesn't match reality: ```yaml pow: - strict: false # true rejects under-difficulty/self-contradictory nonce tags; false accepts either + strict: false # true rejects under-difficulty and self-contradictory nonce tags min: 20 # required leading-zero-bit difficulty; 0 = no requirement ``` @@ -520,11 +519,10 @@ true` field (both kinds support it) to reject it instead — the flag, when passed explicitly, overrides whatever the spec file says. A `trusted: true` flow is never subject to this check either way. -This only governs ncli's own read-side judgment on events it pulls from a -`from` flow — it has no effect on what a `to` relay independently decides -once ncli forwards an event to it. A relay you don't control may still -reject a bad-PoW event on its own terms regardless of `strictPow` here; see -its own `pow:` config (above) if you also operate that relay. +This only governs ncli's own read-side check — it has no effect on what a +`to` relay decides once ncli forwards the event. A relay you don't control +may still reject it on its own terms; see its `pow:` config above if you +operate it. **`stream`** — tail events live, forwarding everything matching `filters` from every `from` flow to every `to` flow until interrupted (any number of diff --git a/skills/ncli-apply/SKILL.md b/skills/ncli-apply/SKILL.md index 29b4744..0d3b169 100644 --- a/skills/ncli-apply/SKILL.md +++ b/skills/ncli-apply/SKILL.md @@ -43,11 +43,9 @@ Failures counter); for `sync` it's silently dropped from the pulled batch `trusted: true` flow is never subject to this check, regardless of `strictPow` — same as it already skips signature verification. -`strictPow` only governs `apply`'s own judgment on events read from a -`from` flow. It has no bearing on what a `to` relay independently decides -once `apply` forwards an event to it — a relay you don't control can still -reject a bad-PoW event on its own terms (its own `pow:`/`strict` config, or -just NIP-13 validation baked into its ingestion path) no matter what +`strictPow` only governs `apply`'s own read-side check — it has no bearing +on what a `to` relay decides once `apply` forwards the event. A relay you +don't control can still reject it on its own terms, no matter what `strictPow` is set to here. | kind | what it does | writes anything? | From 25ffb6d824e8e703d65917fbedc0791c521b0b90 Mon Sep 17 00:00:00 2001 From: naliyi <154817482+naliyi@users.noreply.github.com> Date: Fri, 4 Sep 2026 08:23:39 +0000 Subject: [PATCH 4/5] docs: shorten README's --strict-pow blurb, point to skills/ncli-apply for the full detail --- README.md | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 331ad8f..ffd8fca 100644 --- a/README.md +++ b/README.md @@ -510,19 +510,14 @@ composes-into-CI/scripts convention as `miner check`. [`examples/apply/`](examples/apply/) — the snippets below are trimmed to the essentials. -`--strict-pow` is a flag on `apply` (default `false`) that applies to both -`stream` and `sync`: since NIP-13 proof-of-work is optional per event, an -untrusted event with a `nonce` tag that doesn't meet its declared -difficulty is accepted by default, same as one with no `nonce` tag at all. -Enable strict checking either via the flag or the spec's own `strictPow: -true` field (both kinds support it) to reject it instead — the flag, when -passed explicitly, overrides whatever the spec file says. A `trusted: true` -flow is never subject to this check either way. - -This only governs ncli's own read-side check — it has no effect on what a -`to` relay decides once ncli forwards the event. A relay you don't control -may still reject it on its own terms; see its `pow:` config above if you -operate it. +`--strict-pow` (default `false`) makes `apply` reject an untrusted event +whose `nonce` tag doesn't meet its declared PoW difficulty, instead of +accepting it — settable via the flag or the spec's own `strictPow: true` +field, flag wins when passed explicitly. + +See [`skills/ncli-apply/SKILL.md`](skills/ncli-apply/SKILL.md) for the full +walkthrough, including `trusted: true` exemptions and why this doesn't +govern what a `to` relay independently decides. **`stream`** — tail events live, forwarding everything matching `filters` from every `from` flow to every `to` flow until interrupted (any number of From 775f379db7813719646f90bbe53c6922b30ea567 Mon Sep 17 00:00:00 2001 From: naliyi <154817482+naliyi@users.noreply.github.com> Date: Fri, 4 Sep 2026 08:24:29 +0000 Subject: [PATCH 5/5] docs: point to skill for relay-side PoW topic, drop the why --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ffd8fca..8ec4bda 100644 --- a/README.md +++ b/README.md @@ -516,8 +516,8 @@ accepting it — settable via the flag or the spec's own `strictPow: true` field, flag wins when passed explicitly. See [`skills/ncli-apply/SKILL.md`](skills/ncli-apply/SKILL.md) for the full -walkthrough, including `trusted: true` exemptions and why this doesn't -govern what a `to` relay independently decides. +walkthrough, including `trusted: true` exemptions and relay-side PoW +enforcement. **`stream`** — tail events live, forwarding everything matching `filters` from every `from` flow to every `to` flow until interrupted (any number of