Skip to content

feat: port payjoin core to no_std#1615

Open
caarloshenriq wants to merge 5 commits into
payjoin:masterfrom
caarloshenriq:feat/payjoin-nostd
Open

feat: port payjoin core to no_std#1615
caarloshenriq wants to merge 5 commits into
payjoin:masterfrom
caarloshenriq:feat/payjoin-nostd

Conversation

@caarloshenriq

Copy link
Copy Markdown
Contributor

Summary

This is a implementation of no_std support for the payjoin crate,
enabling its use on embedded devices

As discussed in #942, running payjoin logic on a hardware signer enables
stronger security guarantees: the device can verify the fallback transaction,
compare it against the payjoin proposal, and only sign previously-approved
inputs — without trusting the host machine.

Feature Architecture

A new v2-std feature was introduced to separate the state machine logic
from networking dependencies:

Feature Description
alloc bare metal support, state machine logic only
v2 async payjoin session logic without networking
v2-std v2 + networking (url, ohttp, hpke, bhttp, http)
std full std support with tokio, serde_json, bitcoin/base64

Verified Build Targets

  • cargo build -p payjoin --no-default-features --features v2,alloc
  • cargo build -p payjoin --no-default-features --features v2,alloc --target thumbv7em-none-eabihf-p payjoin
  • cargo build -p payjoin --no-default-features --features v2,std

Notes for Reviewers

Please review commit by commit:

refactor: introduce no_std/alloc feature split in payjoin core
The main structural change — replaces std:: with core::/alloc:: and gates std-only deps behind #[cfg(feature = "std")] or #[cfg(feature = "v2-std")].

fix: gate v2 std-only code behind cfg features
Extends gating to v2 send/receive and persist. Key decisions: HasReplyableError now carries fallback_tx in both configs to preserve fallback through replay; MaybeSuccessTransition::deconstruct uses Save instead of SaveAndClose on success.

fix: update payjoin-ffi for no_std feature split
Minimal FFI updates to match new AsyncSessionPersister bounds.

fix: restore OHTTP test constants and enable v2 feature in test utils
KEM, KEY_ID, SYMMETRIC were dropped upstream without updating internal tests. Restores them in payjoin-test-utils/src/v2.rs.

chore: update CI, lock files and flake for no_std targets
Adds thumbv7em-none-eabihf to CI and ARM cross-toolchain to the Nix dev shell.

AI Assistance

This implementation was developed with AI assistance (Claude, Anthropic).

Pull Request Checklist

Please confirm the following before requesting review:

@coveralls

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 27080196308

Coverage decreased (-0.5%) to 84.823%

Details

  • Coverage decreased (-0.5%) from the base build.
  • Patch coverage: 104 uncovered changes across 14 files (353 of 457 lines covered, 77.24%).
  • 56 coverage regressions across 6 files.

Uncovered Changes

Top 10 Files by Coverage Impact Changed Covered %
payjoin/src/core/send/v2/mod.rs 51 27 52.94%
payjoin/src/core/persist.rs 141 127 90.07%
payjoin/src/core/uri/v2.rs 50 36 72.0%
payjoin/src/core/send/v2/error.rs 11 0 0.0%
payjoin/src/core/receive/v2/mod.rs 19 10 52.63%
payjoin/src/core/send/error.rs 22 14 63.64%
payjoin/src/core/ohttp.rs 7 1 14.29%
payjoin/src/core/uri/mod.rs 105 100 95.24%
payjoin/src/core/error.rs 6 2 33.33%
payjoin/src/core/time.rs 5 1 20.0%
Total (22 files) 457 353 77.24%

Coverage Regressions

56 previously-covered lines in 6 files lost coverage.

File Lines Losing Coverage Coverage
payjoin/src/core/persist.rs 31 92.5%
payjoin/src/core/receive/v2/mod.rs 16 88.5%
payjoin/src/core/receive/v2/error.rs 4 38.18%
payjoin/src/core/send/v2/error.rs 2 30.23%
payjoin/src/core/uri/error.rs 2 4.55%
payjoin/src/core/send/error.rs 1 42.79%

Coverage Stats

Coverage Status
Relevant Lines: 14720
Covered Lines: 12486
Line Coverage: 84.82%
Coverage Strength: 371.16 hits per line

💛 - Coveralls

@DanGould

DanGould commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Great to see this take off here. My biggest question is about v2-std which expresses that it's about "networking" but really it's the wire serialization. Is it possible to use the library without that? I'm not sure it is.

@benalleng benalleng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like a good start, though there are some feature organizations I have some questions about.

Comment thread payjoin/Cargo.toml
Comment thread payjoin-test-utils/Cargo.toml Outdated
Comment thread payjoin/Cargo.toml Outdated
Comment thread flake.nix Outdated
Comment thread flake.nix Outdated
Comment on lines +306 to +310
DOTNET_ROOT = "${dotnetSdk}/share/dotnet";
DOTNET_CLI_TELEMETRY_OPTOUT = "1";
CC_wasm32_unknown_unknown = "${pkgs.llvmPackages.clang-unwrapped}/bin/clang";
AR_wasm32_unknown_unknown = "${pkgs.llvmPackages.bintools-unwrapped}/bin/llvm-ar";
CC_thumbv7em_none_eabihf = "arm-none-eabi-gcc";

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here they seem language specific.

Comment thread payjoin/Cargo.toml Outdated
@benalleng benalleng linked an issue Jun 8, 2026 that may be closed by this pull request
@benalleng benalleng removed a link to an issue Jun 8, 2026
Comment thread .github/workflows/rust.yml Outdated
- name: "Build embedded target"
env:
CC_thumbv7em_none_eabihf: arm-none-eabi-gcc
run: cargo build -p payjoin --no-default-features --features "alloc,v2" --target thumbv7em-none-eabihf -Zbuild-std=core,alloc

@benalleng benalleng Jun 10, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be done with a nix develop .#embedded -c cargo build or maybe setup a way to use nix build .#checks.x86_64-linux.embedded

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added in c0c2149

@caarloshenriq

Copy link
Copy Markdown
Contributor Author

My biggest question is about v2-std which expresses that it's about "networking" but really it's the wire serialization. Is it possible to use the library without that? I'm not sure it is.

After reviewing the code, v2-std as a standalone feature had no clear use case, any consumer that needs OHTTP networking will reach for v2-ohttp or io, and v2-std alone didn't even compile correctly due to untested feature combinations. I've collapsed v2-std into v2-ohttp, simplifying the feature hierarchy to: allocv2v2-ohttpio.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants