Skip to content

feat(sdk): add transport-free CXX bindings for C++ embedders - #4620

Draft
PastaPastaPasta wants to merge 1 commit into
feat/request-driven-document-verificationfrom
feat/platform-cxx-embedder
Draft

feat(sdk): add transport-free CXX bindings for C++ embedders#4620
PastaPastaPasta wants to merge 1 commit into
feat/request-driven-document-verificationfrom
feat/platform-cxx-embedder

Conversation

@PastaPastaPasta

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

Third and last PR of the transport-free-embedder series; stacked on #4619 (review the last commit, feat(sdk): add transport-free CXX bindings for C++ embedders). Supersedes #4416. Draft until #4619 merges.

Dash Core's platform GUI (dashpay/dash#7512, #7623 onward) currently carries a private Rust/CXX bridge and pins individual Platform crates. This crate gives Platform ownership of that embedding surface: proof verification, DPP decoding and state-transition construction for an application that owns its own DAPI transport, quorum-key sync and private keys.

The earlier #4416 was withdrawn after review found (a) a malicious getDocuments response could abort the embedding process before the quorum signature was checked (fixed upstream in #4618), (b) cxx turns a Rust panic into a deterministic process abort and nothing caught them, (c) a second lockfile under standalone/ that had already drifted from the workspace pin so the documented --locked build failed, and (d) ~600 lines of test vectors duplicating the proof-verifier corpus.

What was done?

packages/rs-platform-cxx (dash-platform-cxx), a thin cxx bridge over the workspace's own crates: verification is drive-proof-verifier's FromProof impls including #4619's FromProof<GetDocumentsRequest>; document assembly is dash-platform-queries' builders; signing is dpp's Signer trait implemented over a C++ digest callback (WalletSigner) so private keys never cross the FFI; quorum keys and system contracts come from a ContextProvider the embedder feeds from its synced LLMQ state.

Trust boundary (every byte is untrusted DAPI output, and grovedb replay necessarily precedes the signature check):

  • every extern "Rust" entry point runs under catch_unwind and reports a panic as rust::Error; build.rs refuses panic = "abort" builds, where that guard would be compiled out;
  • requests, responses and decoder inputs are capped at verify::MAX_MESSAGE_BYTES before decoding; asset-lock transaction/islock bytes at 2 MiB;
  • set_context(network, platform_quorum_type, protocol_version, activation_height) records the network's Platform LLMQ type; a proof naming any other quorum type is refused before its key is looked up, so keys the embedder pushes for other purposes can never sign Platform state. update_quorum_keys replaces the whole set;
  • a response claiming a protocol version this build does not know is refused rather than verified under a guessed one; transitions are built and stored documents decoded under the network's protocol version from set_context, not PlatformVersion::latest();
  • the signer refuses non-ECDSA key types (the callback can only produce compact secp256k1 signatures); built transitions pass the same ensure_valid_state_transition_structure dash-sdk runs before broadcast.

Packaging follows the workspace's FFI crates: an ordinary member with no nested lockfile (embedders cargo vendor from the root and cargo build -p dash-platform-cxx), build.rs stages include/dash/platform/{ffi.h,signer.h} and include/rust/cxx.h under target/<profile>/ the way rs-sdk-ffi stages its cbindgen header, cxx = "1.0" unpinned. cxx rather than cbindgen because the surface is dominated by nested byte vectors and fallible calls; the README states that trade-off.

How Has This Been Tested?

  • 38 Rust tests: FromProof end-to-end positives over the shared proof-vector corpus (../rs-drive-proof-verifier/tests/vectors: identity nonce, contract nonce, contested active/finished/absent) plus negatives for tampered signature, unknown quorum hash, non-Platform quorum type, tampered block-id hash, tampered grovedb proof, each signed metadata field individually, unknown protocol version, request/proof identity mismatch, wrong-shape proof, oversized and garbage input; byte-exact state-transition builds against the rs-dpp-generated vectors plus non-ECDSA key, wrong signature size, invalid DPNS label refused before signing, signer refusal; decoders incl. oversized input.
  • scripts/cxx-smoke.sh (in CI) compiles tests/cxx_smoke.cc against the staged headers and archive and runs it: context setup, garbage input throws rust::Error rather than aborting, and all five st_build_* builders driven through the real bridge with a declining WalletSigner.
  • cargo clippy --all-targets --all-features -- -D warnings and cargo machete: clean. The transport-free CI cut asserts hyper/rustls/tower stay out of the crate's tree.

Breaking Changes

None for the workspace (new crate). For the Dash Core consumer of the withdrawn #4416: set_context gained two parameters and update_quorum_keys lost its per-call type; standalone/ and install.sh are gone (install from the staged include/ and libdash_platform_cxx.a).

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

@coderabbitai

coderabbitai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

packages/rs-platform-cxx (crate dash-platform-cxx) is the C++ embedding surface Dash Core's platform GUI consumes: proof verification over (request bytes, response bytes), DPP identity/document decoding, and state-transition construction with signing delegated to a C++ digest callback so private keys never cross the FFI. It is a thin cxx bridge over the workspace's own crates rather than a reimplementation: verification is drive-proof-verifier's FromProof impls (including the new request-driven FromProof<GetDocumentsRequest>), document assembly is dash-platform-queries' shared DPNS/DashPay builders, and signing implements dpp's Signer trait over the callback, exactly as rs-sdk-ffi does for Swift.

Trust boundary, since every input byte comes from an untrusted node and GroveDB replay necessarily runs before the quorum signature check: every extern Rust entry point runs under catch_unwind (cxx turns Result::Err into rust::Error but a panic reaching its shim aborts the embedding process); request/response bytes are capped before prost decoding; set_context records the network's Platform LLMQ type and any proof naming another quorum type is refused before a key lookup, so keys the embedder pushes for other purposes can never sign Platform state; a response claiming an unknown protocol version is refused instead of verified under a guessed one; the signer refuses non-ECDSA key types it cannot produce signatures for; transitions are structure-validated (as dash-sdk does before broadcast) and built under the network's protocol version from set_context rather than this build's latest.

Packaging follows the workspace's FFI crates: build.rs stages the generated bridge header, the cxx runtime header and the hand-written signer.h under target/<profile>/include/, so consumers vendor from the workspace root and install that tree plus the static archive. There is no nested manifest or second lockfile. Tests replay drive-proof-verifier's proof-vector corpus directly (the crate's own copies were byte-identical) and cover tampered signature/quorum/block-id/grovedb bytes, every signed metadata field, non-Platform quorum type, unknown protocol version, request/proof identity mismatch, wrong-shape proof, oversized and garbage input; tests/cxx_smoke.cc links and runs against the staged interface from C++ in CI.
@PastaPastaPasta
PastaPastaPasta force-pushed the feat/platform-cxx-embedder branch 2 times, most recently from 4a8b441 to b9451fd Compare September 8, 2026 14:49
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.

1 participant