Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
6be7a6c
Add the receiver PIR restore client
czarcas7ic Oct 8, 2026
06685a8
Pin the receiver crates to wallet-pir's main
czarcas7ic Oct 10, 2026
7689449
Require a current recent set from every provider
czarcas7ic Oct 10, 2026
7b786b9
Refresh the Enhance routing before each note-data batch
czarcas7ic Oct 10, 2026
36e3df5
Merge the slot-filling and SQLite store fixes
czarcas7ic Oct 10, 2026
aa479cb
Restore the receiver-client references with the client
czarcas7ic Oct 10, 2026
35bb356
Merge the restore watch change
czarcas7ic Oct 10, 2026
dfa2c55
Stop reading recent sets in restore sweeps
czarcas7ic Oct 10, 2026
5ae2a92
Require a seen set for every provider with sets
czarcas7ic Oct 10, 2026
0103145
Merge the slot-filling round-3 merge
czarcas7ic Oct 10, 2026
627c0f5
Cover a seen hit across a rejected payment and a later miss
czarcas7ic Oct 10, 2026
335237c
Stop the sweep run when leasing an attempt fails
czarcas7ic Oct 10, 2026
2cba164
Merge the restored-address issuance gate
czarcas7ic Oct 10, 2026
6059530
Merge the restored-account issuance gate
czarcas7ic Oct 10, 2026
56c1d4d
Merge the restored lookahead seen check
czarcas7ic Oct 10, 2026
7acd0fd
Merge the restored lookahead that stays ahead of issued keys
czarcas7ic Oct 10, 2026
c57dce8
Merge the round-4 SQLite fixes into the receiver client
czarcas7ic Oct 10, 2026
422938c
Cover a deferred payment replaced by a later publication
czarcas7ic Oct 10, 2026
b994e58
Sweep one batch per account in each run
czarcas7ic Oct 10, 2026
693ef90
Name the account of each deferred sweep key
czarcas7ic Oct 10, 2026
a460f05
Merge the exact-input refund and seen-set fixes
czarcas7ic Oct 10, 2026
a1e359c
Stop the sweep run when the PIR session fails to open
czarcas7ic Oct 10, 2026
7dc580e
Merge the round-6 SQLite fixes
czarcas7ic Oct 10, 2026
bb62c90
Check the network of fetched seen sets
czarcas7ic Oct 10, 2026
fa8bd17
Pin transparent PIR to the receiver's wallet-pir revision
czarcas7ic Oct 10, 2026
be6f0b5
Flag a package resolved from two git sources
czarcas7ic Oct 10, 2026
b1c1939
Check every requested position in returned note data
czarcas7ic Oct 10, 2026
1dbea92
Count only note data requests that name positions
czarcas7ic Oct 10, 2026
2454f85
Merge the restore receipt retrieval note
czarcas7ic Oct 10, 2026
7dbda8c
Merge the restored dynamic memo retrieval fix
czarcas7ic Oct 10, 2026
5a86b57
Merge the round-8 SQLite fixes
czarcas7ic Oct 10, 2026
7423ae8
Skip the note source when a sweep needs no positions
czarcas7ic Oct 10, 2026
4728d95
Merge the round-9 SQLite fixes
czarcas7ic Oct 10, 2026
2bb2d44
Merge the unreadable refund memo retention fix
czarcas7ic Oct 11, 2026
4732d73
Merge the round-10 SQLite fixes
czarcas7ic Oct 11, 2026
2eb63ac
Merge main into the receiver restore client
czarcas7ic Oct 11, 2026
091c60f
Merge the round-12 fixes from the slot-filling branch
czarcas7ic Oct 11, 2026
860aae3
Merge the zero exact-output refund fix
czarcas7ic Oct 11, 2026
4f22415
Stop the sweep when the note source cannot serve the chain
czarcas7ic Oct 11, 2026
bf7d27a
Release spend evidence only at the current tip
czarcas7ic Oct 11, 2026
b65a4b8
Sweep a repeated account only once
czarcas7ic Oct 11, 2026
86f35aa
Merge the received-note dynamic key index
czarcas7ic Oct 11, 2026
6de9eb9
Revalidate the chain point before releasing spend evidence
czarcas7ic Oct 11, 2026
9017590
Merge the incomplete-deposit wording and the reservation limit
czarcas7ic Oct 11, 2026
1ecb146
Merge the completion-limit reopen fix
czarcas7ic Oct 11, 2026
72f66c4
Merge the refund-owed completion-limit fix
czarcas7ic Oct 11, 2026
34179ec
Merge the delayed-status completion-limit fix
czarcas7ic Oct 11, 2026
851e61d
Merge the structural completion-limit closure
czarcas7ic Oct 11, 2026
c717501
Merge the frozen closed-key deadline
czarcas7ic Oct 11, 2026
f9774f5
Merge the graph root, PRF note and pending-recovery guard
czarcas7ic Oct 11, 2026
691e9d9
Match a publication's end position to the wallet's anchor tree
czarcas7ic Oct 11, 2026
e2f7f31
Recheck the fully scanned height before releasing spend evidence
czarcas7ic Oct 11, 2026
bfce96d
Merge the round-16 key lifecycle and snapshot fixes
czarcas7ic Oct 11, 2026
5b0cebe
Merge the transaction key snapshot fix
czarcas7ic Oct 11, 2026
dc037b2
Reject sweeps of a publication without provider seen sets
czarcas7ic Oct 11, 2026
c37511c
Continue a sweep's application after a before-birthday payment
czarcas7ic Oct 11, 2026
d99d58c
Merge the slot-filling note
czarcas7ic Oct 11, 2026
7f0fa01
Note why a sweep ignores seen-feed dates
czarcas7ic Oct 11, 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
2 changes: 1 addition & 1 deletion .github/workflows/verify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
strategy:
fail-fast: false
matrix:
config: [default, orchard, transparent, transparent-import, sqlite, enhance-wallet, enhance, transparent-pir, transparent-pir-sqlite, transparent-pir-testing]
config: [default, orchard, transparent, transparent-import, sqlite, enhance-wallet, enhance, transparent-pir, transparent-pir-sqlite, transparent-pir-testing, pir-receiver]
env:
WALLET_LIB_BUILD_ROOT: ${{ github.workspace }}/target/dev-lanes
steps:
Expand Down
95 changes: 85 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ members = [
"zakura/transaction-status",
"zakura/pir-transparent",
"zakura/dynamic-ivk",
"zakura/pir-receiver",
]

resolver = "2"
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ regeneration command, separate from ordinary builds.
The [dynamic IVK](zakura/dynamic-ivk/README.md) crate provides shared
derivation of receiving keys that keep an account's spending authority with their
own incoming viewing keys, and refund memo helpers, with an Ironwood proof test for
mixed ordinary, refund, and incoming inputs.
mixed ordinary, refund, and incoming inputs. The unpublished
[receiver PIR](zakura/pir-receiver/README.md) crate runs the restore sweeps that
find payments to those keys through a receiver directory.

## How the rewiring works

Expand Down
2 changes: 1 addition & 1 deletion librustzcash/zcash_client_sqlite/src/wallet/dynamic_ivk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
//! [`WalletDb::begin_receive_operation`], [`WalletDb::finish_receive_operation`] and
//! [`WalletDb::start_receive_operation`].
//! - [`WalletDb::record_operation_status`] for each provider status of either.
//! - The [`DynamicIvkWrite`] sweep steps for restore sweeps, and
//! - `zakura_pir_receiver::sweep` for restore sweeps, and
//! [`WalletDb::recheck_dynamic_key_history`] when the user asks to recheck swaps.
//!
//! [`DynamicIvkRead`]: zcash_client_backend::data_api::dynamic_ivk::DynamicIvkRead
Expand Down
2 changes: 1 addition & 1 deletion manifests/sources.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ vendored_directory = "librustzcash"
vendor_branch = "vendor/librustzcash"
upstream_manifest = "librustzcash/upstream-workspace.toml"
# `zakura/` members are added here as they are written.
extra_members = ["wallet-lib", "zakura/pir-enhance", "zakura/pir-enhance-types", "zakura/pir-native", "zakura/pir-status", "zakura/transaction-status", "zakura/pir-transparent", "zakura/dynamic-ivk"]
extra_members = ["wallet-lib", "zakura/pir-enhance", "zakura/pir-enhance-types", "zakura/pir-native", "zakura/pir-status", "zakura/transaction-status", "zakura/pir-transparent", "zakura/dynamic-ivk", "zakura/pir-receiver"]
# The backend selector. Named separately because the verification scripts have
# to build it one backend at a time, unlike every other member.
facade = "wallet-lib"
Expand Down
3 changes: 2 additions & 1 deletion scripts/dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

ROOT = Path(__file__).resolve().parents[1]
CONFIGS = {
"default": (["--workspace", "--exclude", "zakura-wallet-lib", "--exclude", "zakura-pir-enhance", "--exclude", "zakura-pir-transparent"], []),
"default": (["--workspace", "--exclude", "zakura-wallet-lib", "--exclude", "zakura-pir-enhance", "--exclude", "zakura-pir-transparent", "--exclude", "zakura-pir-receiver"], []),
"orchard": (["-p", "zakura-client-backend", "-p", "zakura-client-sqlite"], ["orchard", "test-dependencies"]),
"transparent": (["-p", "zakura-client-backend", "-p", "zakura-client-sqlite"], ["orchard", "transparent-inputs", "test-dependencies", "unstable"]),
"transparent-import": (["-p", "zakura-client-backend", "-p", "zakura-client-sqlite"], ["orchard", "transparent-inputs", "transparent-key-import", "test-dependencies", "unstable"]),
Expand All @@ -25,6 +25,7 @@
"transparent-pir": (["-p", "zakura-pir-transparent"], ["wallet"]),
"transparent-pir-sqlite": (["-p", "zakura-pir-transparent"], ["sqlite"]),
"transparent-pir-testing": (["-p", "zakura-pir-transparent"], ["sqlite", "testing"]),
"pir-receiver": (["-p", "zakura-pir-receiver"], ["wallet"]),
}
VERIFY = ("zakura-graph", "wallet-lib-modes", "vendor-ancestry")

Expand Down
17 changes: 14 additions & 3 deletions scripts/verify-zakura-graph.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ PY
cargo check --manifest-path "$repo_root/Cargo.toml" \
--workspace --exclude "$facade" --all-targets --all-features --locked

# No development lane builds the transparent PIR adapter without `wallet`: its
# tests serve shards in process, so the `default` lane leaves it out.
# No development lane builds the transparent PIR adapter or the receiver PIR
# client without `wallet`: their tests serve shards or directories in process,
# so the `default` lane leaves them out.
cargo check --manifest-path "$repo_root/Cargo.toml" \
-p zakura-pir-transparent --lib --locked
-p zakura-pir-transparent -p zakura-pir-receiver --lib --locked

cargo metadata --locked --manifest-path "$repo_root/Cargo.toml" \
--format-version 1 --all-features \
Expand Down Expand Up @@ -101,6 +102,16 @@ for name, found in sorted(versions.items()):
if len(found) > 1 and (name.startswith("zakura-") or name in expected_packages):
problems.append(f"{name}: {len(found)} versions in the graph: {sorted(found)}")

# Two git sources of one name are separate crates even at one version. Checked
# over the whole workspace graph, where the PIR clients share wallet-pir crates.
git_sources = defaultdict(set)
for package in packages.values():
if (package["source"] or "").startswith("git+"):
git_sources[package["name"]].add(package["source"])
for name, found in sorted(git_sources.items()):
if len(found) > 1:
problems.append(f"{name}: {len(found)} git sources in the graph: {sorted(found)}")

missing = expected_packages - versions.keys()
for name in sorted(missing):
problems.append(f"{name}: vendored crate is not in the resolved graph")
Expand Down
5 changes: 3 additions & 2 deletions zakura/dynamic-ivk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ owns reservation, persistence, coverage, lifecycle, and note selection. There is
no alternate balance store in this crate.

The SQLite backend implements this contract with its `orchard` feature: durable
key registration, scanning, completion, and restore sweeps. Its rustdoc, starting
at `zcash_client_sqlite::wallet::dynamic_ivk`, documents the calls a wallet makes.
key registration, scanning, completion, and the restore sweeps that
`zakura-pir-receiver` runs. Its rustdoc, starting at
`zcash_client_sqlite::wallet::dynamic_ivk`, documents the calls a wallet makes.

Software PCZT signing of dynamic-key notes works through the same builder.
Hardware signers need firmware qualification before dynamic keys are enabled for
Expand Down
16 changes: 16 additions & 0 deletions zakura/pir-receiver/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Changelog

## [Unreleased]

### Added

- `sweep`, behind the `wallet` feature, which runs a restored wallet's
receiver-directory sweeps of its dynamic keys for any store implementing the
backend's `DynamicIvkWrite`, with `Transport`, `NoteSource`, `EnhanceNotes`, `WriteLock`,
`Swept`, `Error` and `MAINNET_GENESIS`. It reads a publication's labeled filter
sets `paid` and each provider's `seen`. The receiver PIR client moved here from
Vizor.
- `fetch_seen` and `Seen`: a publication's swap provider seen sets, which a wallet
checks before issuing a swap address. A publication without seen sets, or in which
a provider with sets lacks a dated seen set, is malformed, for `fetch_seen` and
`sweep` alike. They need no `wallet` feature.
47 changes: 47 additions & 0 deletions zakura/pir-receiver/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
[package]
name = "zakura-pir-receiver"
version = "0.0.1-rc0"
publish = false
description = "Restore sweeps of dynamic IVKs through a receiver directory over PIR"
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
readme = "README.md"

[features]
default = []
## The restore sweep, over a wallet store's dynamic IVK traits.
wallet = ["dep:futures-util", "dep:thiserror", "dep:zakura-pir-enhance", "dep:zakura-dynamic-ivk", "dep:zcash_client_backend", "dep:zcash_protocol"]

[dependencies]
futures-util = { version = "0.3", optional = true }
thiserror = { version = "2", optional = true }
zakura-pir-enhance = { version = "=0.0.1-rc1", path = "../pir-enhance", features = ["wallet"], optional = true }
zakura-dynamic-ivk = { version = "=0.0.1-rc0", path = "../dynamic-ivk", optional = true }
zcash_client_backend = { workspace = true, features = ["orchard"], optional = true }
zcash_protocol = { workspace = true, optional = true }
# The receiver crates come from wallet-pir's `main`.
receiver-directory = { git = "https://github.com/valargroup/wallet-pir", rev = "9d2cbda0b4336258cfce76ca8ee77b095daa7fd7" }
receiver-pir = { git = "https://github.com/valargroup/wallet-pir", rev = "9d2cbda0b4336258cfce76ca8ee77b095daa7fd7" }

[dev-dependencies]
axum = "0.7"
base64.workspace = true
hex.workspace = true
orchard.workspace = true
receiver-pir = { git = "https://github.com/valargroup/wallet-pir", rev = "9d2cbda0b4336258cfce76ca8ee77b095daa7fd7", features = ["server"] }
receiver-pir-server = { git = "https://github.com/valargroup/wallet-pir", rev = "9d2cbda0b4336258cfce76ca8ee77b095daa7fd7" }
rusqlite = { workspace = true, features = ["hooks"] }
serde_json.workspace = true
sha2.workspace = true
tokio = { workspace = true, features = ["macros", "rt"] }
tower = { workspace = true, features = ["util"] }
zcash_client_backend = { workspace = true, features = ["orchard", "test-dependencies"] }
zcash_client_sqlite = { path = "../../librustzcash/zcash_client_sqlite", package = "zakura-client-sqlite", features = ["orchard", "test-dependencies"] }
zcash_note_encryption.workspace = true
zcash_primitives.workspace = true

[[test]]
name = "sweep"
required-features = ["wallet"]
Loading
Loading