f1c51661df2d448db5bf06944b4cdb423f990e0d
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3a1611a92e
|
feat: add @quantus/codec, driving encode and decode from runtime metadata
The extension has to build a signing payload, assemble an extrinsic and decode
a call well enough to show a user what they are approving. The obvious route was
@polkadot/api's codec. That is closed, and quantus/api#1 carries the tested
evidence:
- @polkadot/types caps fixed arrays at 2048 bytes, and ML-DSA signatures are
[u8;5261] and [u8;7219], so every Quantus extrinsic trips it
- api.rpc.chain.getBlock throws on every block of this chain, at the timestamp
inherent, because it reads the extrinsic preamble byte as a version when the
top two bits are a type tag
- it *guesses* that signed extensions it does not recognise contribute nothing
to the signed payload
The third is why this is a package rather than a patch. The guess is right
today — the registry says ReversibleTransactionExtension and
WormholeProofRecorderExtension are empty on both halves — and it is right only
by luck. This chain's encoding has changed between runtimes, transactionVersion
has gone 2 -> 3 -> 6 across four upgrades, and when the guess stops holding the
wallet keeps signing: valid signatures over a payload missing bytes the runtime
put there, reported by the chain as BadProof, which is also what it reports for
a wrong key.
So nothing here names a pallet, a call, an extension or a signature scheme.
Every type id is read from metadata the node produced by running
Metadata_metadata against the runtime WASM in a given block's state, the same
oracle blackbeard.observer has been decoding against across four upgrade
boundaries. encode_extensions walks the declared extensions in order and refuses
to build a payload when one that encodes to something has no value supplied —
a wallet that cannot sign is a bug report, one that signs the wrong bytes is a
support case nobody diagnoses.
Proven end to end on Heisenberg at spec 148: a balances.transfer_keep_alive
built entirely here, signed by @quantus/crypto under QUANTUS_EXTRINSIC, included
at block 1050475 and read back from that block — inherent at index 0 included,
which is the block @polkadot/api cannot decode at all.
Two notes carried over from @quantus/crypto, both load-bearing: decode_checked
walks with scale_decode's IgnoreVisitor before scale_value touches the bytes,
because scale_value sizes a Vec from the length prefix before decoding an item
and an aborted allocation leaves no Err to catch; and the build needs binaryen
123, since 105 silently corrupts the output.
Closes #3
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f
|
||
|
|
b882f914e7
|
build(quantus-crypto): buildable, installable and tested as a package
The JS build now runs end to end and the built package has been consumed the way quantus/common will consume it. Four things had to be worked out. polkadot-dev-build-ts will not build this package. It returns early for any name not starting with @polkadot/, in both buildJs and when collecting locals for import rewriting. Renaming into someone else's scope to satisfy a string check would be worse than not using the tool, and nothing is lost: this package needs no deno variant, no rollup bundle, no cross-package import rewriting. A plain tsc build lives in scripts/build-quantus-js.sh, which also keeps `yarn build:js` byte-identical to upstream's behaviour. binaryen 105 silently breaks the wasm. Upstream pins version_105 (2021), which predates the externref tables wasm-bindgen 0.2.128 emits; wasm-opt "optimises" the table into something that fails at instantiation with `WebAssembly.Table. grow(): failed to grow table by 4`. The wasm is valid before wasm-opt and broken after, every cargo test still passes, and it only surfaces when a consumer tries to init. install-build-deps.sh now fetches binaryen 123 alongside, exactly as it does a second wasm-bindgen. The wasm-util dependency is imported deeply. Its package index re-exports packageDetect, whose only job is a side effect registering with @polkadot/util — a peer dependency we would inherit for nothing. base64 and fflate are pure functions with no dependencies, so the deep paths are both lighter and honest. ESM only, and the CJS scaffolding is removed. The consumers are ESM and the wasm-bindgen glue is ESM-only, so a CJS variant would mean a second generated glue or hand-written marshalling. Revisit if quantus/common's CJS build needs it. Also: the pack step must run after tsc, which clears build/; the checked-in bindings are refreshed by the build so they cannot drift; and both test suites are wired into the repo's test script, which previously ran wasm-crypto's only. The consumer test stages a real node_modules layout rather than testing in place, because in this repo node_modules/@polkadot/wasm-util symlinks to the package source, which carries no exports map — so a deep import resolves for a real consumer and fails here for reasons that have nothing to do with our package. Staging tests module resolution too, which is half of what can break in a published package. It is also what caught the binaryen fault. Post-wasm-opt: 234,292 raw / 109,649 zlib / 146,200 base64 — smaller than upstream's entire wasm-crypto blob (335,277 / 168,782 / 225,044). Refs quantus/wasm#1 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f |