Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
99aee1e
feat(ghost-lock): Taproot custody policies for the three Lock lanes
defenwycke Sep 5, 2026
87570fa
feat(wraith): denomination ladder and deterministic payment decomposi…
defenwycke Sep 5, 2026
8684987
feat(wraith): spend attestations and self-proving double-sign fraud p…
defenwycke Sep 5, 2026
8c55019
feat(wraith): price seats from a live fee rate instead of pinning them
defenwycke Sep 5, 2026
6a0bb5c
feat(wraith): enforce the once-per-coin rule, with a durability contract
defenwycke Sep 5, 2026
9074236
feat(wraith): seat admission — price and detect Sybil rounds
defenwycke Sep 5, 2026
c713e99
fix(wraith): stop publishing the round's input-to-output mapping
defenwycke Sep 5, 2026
7197794
fix(wraith): shuffle round inputs, and key prevouts by outpoint
defenwycke Sep 5, 2026
96d0b5b
feat(wraith): adversarial privacy harness — and it immediately found one
defenwycke Sep 5, 2026
e2cf3a9
feat(wraith): probe API responses for identity leakage, sweep every e…
defenwycke Sep 5, 2026
6cf1d04
feat(wraith): ladder rounds — no fee output, no fixed denomination
defenwycke Sep 5, 2026
7209526
feat(wraith): answer the input-selection question, against my own int…
defenwycke Sep 5, 2026
48e390a
feat(wraith): bridge Ladder::plan to a round contribution
defenwycke Sep 6, 2026
542490c
feat(wraith): price anonymity sets, and refuse to sell one that isn't…
defenwycke Sep 6, 2026
3ab9543
feat(wraith): liquidity lane — the bond ceiling and a tier-priced spread
defenwycke Sep 6, 2026
753e23c
feat(wraith): standing order schedule, and the exposure number is cum…
defenwycke Sep 6, 2026
78eabe3
feat(wraith): oblivious mailbox — the tag width is the recipient's an…
defenwycke Sep 6, 2026
cf83b55
feat(wraith): what a participant checks before signing
defenwycke Sep 6, 2026
6b80bbe
feat(wraith): refuse the overnight tidy-up that undoes the round
defenwycke Sep 6, 2026
ed1856d
feat(wraith): "you can always leave alone" is currently false — model…
defenwycke Sep 6, 2026
c47ad4d
feat(wraith): pin the sighash that makes pre-sign verification mean a…
defenwycke Sep 6, 2026
c6078b3
fix(wraith): one source for the vbyte arithmetic — I reintroduced #698
defenwycke Sep 6, 2026
f6ace05
fix(wraith): a canonical round minimum — and my launch advice reasone…
defenwycke Sep 6, 2026
792e90a
fix(wraith): tie the exit analysis to the crate that owns the delay
defenwycke Sep 6, 2026
487ef57
fix(wraith): finish the constant consolidation, and check the dust claim
defenwycke Sep 6, 2026
a34c04f
test(wraith): prove the refusals actually refuse
defenwycke Sep 6, 2026
5374274
fix(wraith): no panics and no wrapping in the money paths
defenwycke Sep 6, 2026
24096fa
chore: instrument mutation harness with exit codes
defenwycke Sep 6, 2026
fabc59d
fix(test): mutation harness was testing stale builds
defenwycke Sep 6, 2026
f61d459
fix(test): require two agreeing runs per mutation
defenwycke Sep 6, 2026
82246c9
perf(test): force rebuild by dropping the fingerprint, not by running…
defenwycke Sep 6, 2026
a8f798d
docs(test): the mutation harness is now fast and deterministic
defenwycke Sep 6, 2026
82f0d9d
feat(wraith): enforce the two behaviours the exit guarantee depends on
defenwycke Sep 6, 2026
d6ec571
fix(wraith): plan_participation could not express who gets paid
defenwycke Sep 6, 2026
8e155f6
feat(wraith): commit-reveal beacon — the sanctioned interim, honestly…
defenwycke Sep 6, 2026
7a47df9
docs(wraith): label the grindable beacon that election is currently w…
defenwycke Sep 6, 2026
69b8989
feat(wraith): make "forgot to verify" unrepresentable for a joining c…
defenwycke Sep 6, 2026
e9d7ee2
feat(wraith): quorum health, because stranding is silent
defenwycke Sep 6, 2026
194adcb
feat(wraith): detect roster divergence, and lag the snapshot that cau…
defenwycke Sep 6, 2026
a5e7894
feat(wraith): bind a session to the epoch it opened in
defenwycke Sep 6, 2026
ba8ab43
fix(pool): the coordinator roster cannot agree, so publish a commitment
defenwycke Sep 6, 2026
c01316c
feat(wraith): /inputs accepts a whole ladder, not one coin
defenwycke Sep 6, 2026
ea78159
feat(ghost-lock): four lanes — Savings, Spending, Cash, Investments
defenwycke Sep 6, 2026
743b5c9
feat(wraith): count entities, not seats — and refuse to sign an unver…
defenwycke Sep 6, 2026
ec8b595
feat(wraith): seats that do not exist to be taken
defenwycke Sep 6, 2026
2e0ebeb
feat(wraith): neither side chooses which round you land in
defenwycke Sep 6, 2026
c11fadd
fix(wraith): the split floor was decoration — a surviving mutant foun…
defenwycke Sep 6, 2026
45f3fe2
refactor(wraith): make the split-floor margin a build failure, not a …
defenwycke Sep 6, 2026
b896ea1
feat(wraith): enforce composition at the join, not just in a module
defenwycke Sep 6, 2026
78cab0c
feat(wraith): produce the clusters every ancestry rule was reading
defenwycke Sep 6, 2026
9c52136
feat(wraith): serve the entity count, so a wallet has something to check
defenwycke Sep 6, 2026
3ea0f17
feat(wraith): the participant recounts the set and refuses an over-claim
defenwycke Sep 6, 2026
9c2f1e2
feat(wraith): the recount runs on the real response, not only in tests
defenwycke Sep 6, 2026
9959e89
fix(pool): the roster is declared facts now, not this node's sockets
defenwycke Sep 6, 2026
a23a4c9
feat(wraith): multi-anchor beacon, and an ordering with no seat count
defenwycke Sep 6, 2026
3699d22
test(wraith): the tier's bytes bind, not merely its length
defenwycke Sep 6, 2026
254c85b
feat(pool): the election judges what a node proved, not what it claims
defenwycke Sep 6, 2026
c696aac
feat(wraith): derived round placement, wired end to end
defenwycke Sep 6, 2026
d900c3f
feat(wraith): say when placement is not actually running
defenwycke Sep 6, 2026
d6f3811
feat(wallet): the anonymity panel — entities, not seats
defenwycke Sep 6, 2026
dfdc2e6
fix(wallet): the wallet signed whatever it was handed
defenwycke Sep 6, 2026
cc93e06
fix(wallet): a signature that voids the inspection is now caught
defenwycke Sep 6, 2026
667dd7f
feat(wallet): enforce the once-per-coin rule, durably
defenwycke Sep 6, 2026
ed64187
fix(wallet): make skipping the checks a compile error
defenwycke Sep 6, 2026
bbaa6f4
style(wallet): clippy clean, correcting the previous commit's claim
defenwycke Sep 6, 2026
2befd94
feat(wallet): a refusal the wallet can render, not a sentence
defenwycke Sep 6, 2026
34b2e28
feat(wallet): confirm by stating a floor, not by dismissing a dialog
defenwycke Sep 6, 2026
a25e531
docs(ghost-lock): say which lock crate this is
defenwycke Sep 6, 2026
336c5ce
feat(wallet): a Ghost Lock as four lanes and one balance
defenwycke Sep 6, 2026
0db8bb2
feat(wallet): daemon reports a Ghost Lock's four lanes and its total
defenwycke Sep 6, 2026
ae8f3ad
feat(wallet): show pending balances beside settled, never inside
defenwycke Sep 6, 2026
5e87f06
feat(wallet): the four-lane Lock view, with the total on top
defenwycke Sep 6, 2026
14cde16
feat(wallet): view a Ghost Lock's lanes from the Locks screen
defenwycke Sep 6, 2026
4b998de
feat(ghost-lock): MuSig2 key aggregation — and aggregation is not a c…
defenwycke Sep 6, 2026
dba28b2
feat(wallet): derive the aggregates, dropping the form from five keys…
defenwycke Sep 6, 2026
33cfc93
feat(wallet): remember a Ghost Lock, so the form stops being the truth
defenwycke Sep 6, 2026
50c8788
feat(wallet): saved Locks are pickable, and live in the daemon
defenwycke Sep 6, 2026
2395374
feat(wallet): demolish the old Ghost Lock, and finish the job
defenwycke Sep 6, 2026
9723472
style(wallet): drop the blank lines the demolition left in the Tauri …
defenwycke Sep 6, 2026
ef7b3b4
fix(ci): the three gates the demolition broke, and two rustdoc links
defenwycke Sep 7, 2026
27ed0ed
refactor(wallet): drop the wallet's client for a lock it can no longe…
defenwycke Sep 7, 2026
a4ba3d8
Merge remote-tracking branch 'origin/main' into feat/locks-wraith-wallet
defenwycke Sep 7, 2026
f04a4a4
chore: refresh ghost-lock's version in the lockfile after the main merge
defenwycke Sep 7, 2026
4f92025
docs(wallet): the daemon comment still claimed a ceremony it no longe…
defenwycke Sep 7, 2026
2612347
feat(wallet): private entry — fund a Lock lane with a round's output
defenwycke Sep 7, 2026
49dc397
feat(cli): `wraith lock` — the Lock commands the CLI could render but…
defenwycke Sep 7, 2026
9862b4d
feat(wallet): the GUI can ask where a round should pay, and says why …
defenwycke Sep 7, 2026
8b6be7e
feat(ghost-lock): MuSig2 signing — the half that needs no transport
defenwycke Sep 7, 2026
9282e51
feat(ghost-lock): air-gapped MuSig2 — the device verifies, it is neve…
defenwycke Sep 7, 2026
d00a497
feat(wallet): host orchestration for air-gapped Lock signing
defenwycke Sep 7, 2026
0f5d794
feat(ghost-lock-signer): the offline device, and a test that one exists
defenwycke Sep 7, 2026
745107d
feat(ghost-lock-signer): a seed phrase, not a hex key on disk
defenwycke Sep 7, 2026
23a3184
feat(ghost-lock-signer): `generate` — OS entropy, with dice mixed in
defenwycke Sep 7, 2026
bd41fe5
feat(wallet): an Offline device screen for the air-gapped signing cer…
defenwycke Sep 7, 2026
76c1369
feat(ghost-lock): escape-leaf spends — leaving alone, after the delay
defenwycke Sep 7, 2026
8a10c3e
feat(wallet): wire the escape spends — `lock escape-plan` and `lock e…
defenwycke Sep 7, 2026
5da09f4
feat(wraith): the quorum's half of a Spending spend, and its right to…
defenwycke Sep 7, 2026
77dc26b
test(ghost-lock): pin that Cash is a plain BIP86 output
defenwycke Sep 7, 2026
622f95e
feat(ghost-lock): the heir can claim, and the backup device can recover
defenwycke Sep 7, 2026
cefd077
feat(ghost-lock-signer): `claim` — the heir and the backup device can…
defenwycke Sep 7, 2026
70c8dfe
feat(wallet): "Leaving alone" in the GUI — the owner escapes
defenwycke Sep 7, 2026
eca58b1
feat(wraith): per-Lock quorum keys, a velocity cap, and active-only c…
defenwycke Sep 7, 2026
11d4441
feat(wraith-coordinator): serve Ghost Lock co-signing over HTTP
defenwycke Sep 7, 2026
19569d1
feat(wraith-coordinator): durable co-sign ledgers, and config to turn…
defenwycke Sep 7, 2026
b4d20da
feat(wallet): ask the quorum to co-sign — Spending works end to end
defenwycke Sep 7, 2026
fa1d302
test(wraith-coordinator): the real binary co-signs a real Lock
defenwycke Sep 7, 2026
c2ce1cf
fix(wallet): the GSP health check bypassed the proxy, and the doc sai…
defenwycke Sep 7, 2026
dbda0c5
fix(wallet): a send fee of zero was a claim the wallet could not make
defenwycke Sep 7, 2026
3cf502c
feat(wallet): a chain backend that is the owner's own node
defenwycke Sep 7, 2026
a12a0be
feat(wallet): the owner's own node is the chain backend when there is…
defenwycke Sep 7, 2026
dca1e3e
wallet: balance and history from the node, not from an operator
defenwycke Sep 8, 2026
44af8e3
wallet: an on-chain payment you can actually make
defenwycke Sep 8, 2026
8002dfc
wallet: remove the L2 surface — the wallet talks to your node now
defenwycke Sep 8, 2026
7a8e5c9
delete Ghost Pay, the GSP, and the old ghost-locks crate
defenwycke Sep 8, 2026
c31e7d6
wallet: read blocks, so money arriving shows up
defenwycke Sep 8, 2026
8b40088
wallet: detect silent payments locally, and fix a misattribution bug
defenwycke Sep 8, 2026
3e07396
wallet: a birth height for restores, and per-wallet records
defenwycke Sep 8, 2026
dfbc633
wallet: send silent payments, not only receive them
defenwycke Sep 8, 2026
024d415
wallet: coordinator discovery, chain-anchored but not trustless
defenwycke Sep 8, 2026
7720774
fix: concurrent mixes silently lost signing-ledger authorisations
defenwycke Sep 8, 2026
e949f92
fix: the lost-update bug was in seven stores, not one
defenwycke Sep 8, 2026
2f8808d
fix: a round below the wallet's floor cost the coin it refused
defenwycke Sep 8, 2026
f6e2e6c
fix: a second wraithd could take the endpoint from a running one
defenwycke Sep 8, 2026
d7136e4
fix: give Ghost Locks their own key space and enforce the compartment…
defenwycke Sep 8, 2026
fe9d95b
fix: no Lock spend may reach outside the lane it is signing
defenwycke Sep 8, 2026
4c9f9e8
test: drive a Ghost Lock escape spend on chain
defenwycke Sep 8, 2026
7be73f2
test: drive the air-gapped Savings spend against a real backup device
defenwycke Sep 8, 2026
206f1f4
test: run the wallet smoke suite on signet as well as regtest
defenwycke Sep 8, 2026
1c07e30
test: make signet mining survive its own proof-of-work
defenwycke Sep 8, 2026
58b19be
test: say why the suite aborted, and survive the idle auto-lock
defenwycke Sep 8, 2026
965270a
test: align the summary columns
defenwycke Sep 8, 2026
0b31bc5
fix: break the quorum key's circular derivation so the Spending lane …
defenwycke Sep 8, 2026
fa3d274
fix: stop the coordinator's co-signing ledger landing in the repo
defenwycke Sep 8, 2026
761d828
test: surface what the CLI said when it fails
defenwycke Sep 8, 2026
b60f2dd
fix: say where the Lock co-signing ledgers actually are
defenwycke Sep 8, 2026
5bd8dfd
fix: the cosign mock still expected the old wire field
defenwycke Sep 8, 2026
635eaae
fix: Cash lane coins were unspendable, and require the co-signing led…
defenwycke Sep 8, 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
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ env:
# pure-Rust jobs below and built on their own; everything else gets full coverage.
WORKSPACE_EXCLUDES: --workspace --exclude wraith-wallet-gui --exclude ghost-tap-desktop
# System packages the Rust workspace needs: Cap'n Proto (bitcoin-core-sv2 build
# script) and SQLite (ghost-storage / ghost-pay).
# script) and SQLite (ghost-storage).
LINUX_DEPS: libsqlite3-dev capnproto libcapnp-dev
# What the Tauri desktop crates need on top: webkit2gtk is the webview, and `patchelf` is
# used by the bundler. A superset of LINUX_DEPS so the one install script covers both.
Expand Down Expand Up @@ -185,8 +185,6 @@ jobs:
run: .github/scripts/install-linux-deps.sh
- name: Run integration tests
run: |
# bond_e2e execs the real ghost-pay binary and asserts it exists.
cargo build -p ghost-pay
cargo test $WORKSPACE_EXCLUDES --tests \
--exclude ghost-mpc \
--exclude mpc-xproc-harness \
Expand Down
33 changes: 15 additions & 18 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
if: runner.os == 'Linux'
timeout-minutes: 10
env:
# ghost-pool/ghost-pay (Rust) need libsqlite3 + capnproto (the SV2
# ghost-pool (Rust) needs libsqlite3 + capnproto (the SV2
# stratum-core dep). The Linux job ALSO builds ghostd (the C++ Bitcoin
# Core daemon) below, which needs the standard Core build deps: a
# compiler + CMake + pkgconf, libevent, boost, and libzmq. WITH_ZMQ is
Expand Down Expand Up @@ -138,23 +138,20 @@ jobs:
# release artifacts here.
- name: Build
run: |
# CRITICAL: BOTH ghost-pool AND ghost-pay must be built with their own
# zk-production feature so the released binaries can run on mainnet.
# Without it, is_production_mode() is false and the binary aborts at
# startup ("MAINNET SECURITY: ZK consensus on mainnet requires trusted
# setup parameters"), so every curl|bash install crash-loops. ghost-pay
# has a SEPARATE `zk-production` feature (ghost-zkp/zk-production) — it is
# NOT enabled transitively by ghost-pool/zk-production, so it must be
# listed explicitly. zk-production is a compile-time flag with no
# build-time artefacts (params load at runtime), so this is safe.
# CRITICAL: ghost-pool must be built with its zk-production feature so
# the released binary can run on mainnet. Without it,
# is_production_mode() is false and the binary aborts at startup
# ("MAINNET SECURITY: ZK consensus on mainnet requires trusted setup
# parameters"), so every curl|bash install crash-loops. zk-production
# is a compile-time flag with no build-time artefacts (params load at
# runtime), so this is safe.
cargo build --release --target ${{ matrix.target }} \
--features ghost-pool/zk-production,ghost-pay/zk-production \
-p ghost-pool -p ghost-cli -p ghost-pay -p ghost-gsp-bin \
--features ghost-pool/zk-production \
-p ghost-pool -p ghost-cli \
-p translator_sv2 -p pool_sv2 -p jd_client_sv2 -p jd_server_sv2

# Build ghostd (the C++ Bitcoin Core daemon) so all THREE node binaries
# (ghost-pool + ghost-pay + ghostd) ship in ONE signed release at ONE
# version and can never drift apart. Linux only — the pool/elder fleet is
# Build ghostd (the C++ Bitcoin Core daemon) so the node binaries ship in
# ONE signed release at ONE version and can never drift apart. Linux only — the pool/elder fleet is
# Linux, and a Bitcoin Core build is neither needed nor attempted on the
# macOS targets.
#
Expand Down Expand Up @@ -203,16 +200,16 @@ jobs:
mkdir -p dist

# Copy binaries (check actual names from target directory)
for bin in ghost-pool ghost-cli ghost-pay ghost-gsp translator_sv2 pool_sv2 jd_client_sv2 ghost-light-wallet ghost-light-wallet-tui; do
for bin in ghost-pool ghost-cli translator_sv2 pool_sv2 jd_client_sv2 ghost-light-wallet ghost-light-wallet-tui; do
if [ -f "target/${{ matrix.target }}/release/${bin}${{ matrix.suffix }}" ]; then
cp "target/${{ matrix.target }}/release/${bin}${{ matrix.suffix }}" dist/
fi
done

# ghostd (C++) is built only on the Linux target (step above). Stage it
# into the SAME dist/ so it lands inside the linux tarball alongside
# ghost-pool + ghost-pay and is covered — with zero extra signing logic
# — by the existing SHA256SUMS + GPG signature over the tarball.
# ghost-pool and is covered — with zero extra signing logic — by the
# existing SHA256SUMS + GPG signature over the tarball.
if [ -f "ghost-core/build/bin/ghostd" ]; then
cp "ghost-core/build/bin/ghostd" dist/
fi
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,9 @@ docker/regtest-cluster/bin/
# were committed by accident in 8b77fb352 because the tests populate this directory and a
# `git add -A` swept it in. They are build products, not source: the harness fetches them.
tests/integration-sv2/template-provider/

# Coordinator Lock co-signing state. `--lock-ledger-dir` defaults to the
# working directory, so running a coordinator from the repo root drops these
# here. They are runtime state and must never be committed.
lock-cosigned-coins.json
lock-cosign-spends.json
Loading
Loading