Repository navigation
fix(docs): run the Python quickstart offline and make it match the SDK - #200
Conversation
|
@aratass Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
truthixify
left a comment
There was a problem hiding this comment.
The documented Python flow runs fully offline and matches the pinned TypeScript vectors on all 18 checks. Approved.
Running the quickstart against vectors from the SDK showed it could not work:
- scalar * G came from Ed25519PrivateKey.from_private_bytes(), which hashes
and clamps the input, so stealth addresses never matched the SDK and
sign_with_scalar produced signatures that do not verify.
- The view tag hashed the shared secret under the v2 prefix. The v2 tag is
SHA-256("wraith:stellar:view-tag:v2:" || R || V)[0], with no ECDH.
- fetch_announcements filtered on two-topic events and read a map value, but
the v2 announcer emits four topics and a (stealth, R, metadata) tuple.
It now pages through getEvents with the cursor.
- announce() used scheme 1; the deployed v2 announcer asserts scheme 2.
- Step 6b used simulate_transaction(...).transaction instead of
prepare_transaction(). Step 7 called a nonexistent add_signature() and
left too little XLM for the base reserve; it now merges the account.
The guide now targets testnet, where the contracts live, pins stellar-sdk
16.1.0, cryptography 50.0.2 and httpx 0.28.1, and drops every no-check fence.
scripts/python-quickstart/run_quickstart.py extracts wraith_crypto.py and the steps from guides/quickstarts/python.mdx and runs them in page order. The RPC, Horizon and Soroban calls go to fakes that serve recorded v2 announcer events and verify each transaction's signatures. Results are checked against vectors.json, generated from the pinned SDK by generate-vectors.ts (--check in CI), and Step 6a against an independent libsodium derivation. requirements.txt pins the full dependency tree; --bootstrap builds a venv with it. check:snippets-extended now runs check:python-quickstart. Closes wraith-protocol#188
cf4f9bc to
978ba13
Compare
|
Rebased on develop after #199 merged; the package.json scripts and CONTRIBUTING sections from both PRs are kept. check:snippets (with check:api-examples), check:python-quickstart, nav-coverage, contract-registry and redirects-and-anchors pass locally. |
truthixify
left a comment
There was a problem hiding this comment.
The rebased branch remains correct. The pinned offline quickstart ran all six published steps, matched 18 SDK vector checks, paged all five v2 events, rejected the decoy, and verified both transaction signatures.
Closes #188.
Summary
Running the quickstart showed that its crypto and RPC code could not work, so this PR fixes the guide and then executes it in CI.
What was broken (each confirmed against vectors from the pinned SDK):
_ed25519_point_addcomputedscalar * GwithEd25519PrivateKey.from_private_bytes(scalar), which hashes and clamps its input. Stealth addresses never matched the SDK, the scanner found 0 of 2 SDK payments, andsign_with_scalarproduced signatures that fail ed25519 verification.SHA-256("wraith:stellar:view-tag:v2:" || R || V)[0](architecture/view-tag-scanner.mdx, SDKcomputeAnnouncementViewTag), with no ECDH.fetch_announcementsfiltered on two-topic events and read the value as a map with an.xdrfield. The v2 announcer emits("announce", scheme_id, view_tag_bucket, metadata_kind)with a(stealth_address, R, metadata)value, and the RPC returns base64 strings. It now pages throughgetEventswith the cursor.announce()was called with scheme 1. The deployed v2 announcer (scripts/contract-registry.json) assertsscheme_id == 2.simulate_transaction(...).transaction(no such attribute) instead of callingprepare_transaction, and importedSorobanServerfrom the wrong module. Step 7 called a nonexistentadd_signature()and paid out 9 of 10 XLM, below the base reserve. It now appends aDecoratedSignatureand merges the stealth account.The fixture (
scripts/python-quickstart/):run_quickstart.pybuildswraith_crypto.pyfrom the# wraith_crypto.pyfence (plus# Add to wraith_crypto.py) and runs every other Python fence in page order in one session, so the published code is the code under test. Tracebacks point at MDX lines.httpx.postanswersgetLatestLedgerand serves recorded v2 announcer events two pergetEventspage, so the cursor loop runs. Fakes forstellar_sdk.ServerandSorobanServercheck the network passphrase, sequence numbers andprepare_transactionbefore signing, and verify every signature, including the scalar-signed merge in Step 7.vectors.jsonis generated from the pinned@wraith-protocol/sdk1.4.5 primitives bygenerate-vectors.ts(--checkin CI): keys, meta-address, stealth addresses, five events (two payments to the reader, two to someone else, one decoy that passes the view tag and must fail the address check), matches with private scalars, and asignWithScalarsignature. I also checked the vectors against the SDK's currentdevelop(generateStealthAddress,scanAnnouncements,signWithScalar): identical.requirements.txtpins the full dependency tree, frozen from a clean Python 3.11 environment. The runner refuses other versions, and--bootstrapbuilds a venv with the pins undernode_modules/.cache.check:snippets-extended, the CI job with Python 3.11, now runscheck:python-quickstart. All 9 Python fences run and nono-checkremains on the page. A fence can only be skipped if it is markedpython Pseudocode no-check.Verification
pnpm check:snippets-extended,check:snippets,check:placeholders,check:nav-coverage,check:contract-registry,check:compatibility-matrix,check:redirects-and-anchors,test:redirects-and-anchorsandnode localization-qa.cjspass.announce, a single-pagefetch_announcements, a broken Step 7 import, andno-checkon a Python fence.Summary of the run: