Repository navigation
feat(sdk): read the identifier and bytes property type shorthands in long form on iOS and Android - #5358
Merged
QuantumExplorer merged 3 commits intoOct 9, 2026
Conversation
…long form `dash_sdk_data_contract_json_expand_property_type_shorthands` takes a contract as JSON and returns it with every `"type": "identifier"` and `"type": "bytes", "size": n` (protocol version 14) written as the byte array it stands for, in each document type schema and in the definitions, by DPP's own `DocumentType::expand_property_type_shorthands`. Platform stores and returns a contract as sent, so mobile clients reading property types from the fetched JSON saw an unknown type. The function is a view: the contract a client stores and sends is unchanged. It takes no SDK handle and runs at the latest protocol version without full validation, so a client holding only the JSON can call it. A shorthand can only be in a contract the network accepted at protocol version 14 or later. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y type shorthands `DataContractParser.parseDataContract` now reads the contract through the Rust long-form view, so an `identifier` or `bytes` property (top level, object member, typed array `items` or definition) is persisted as a byte array row and schema, and SwiftExampleApp offers the identifier or byte input for it. A top-level property written as `$ref` to `#/$defs/<name>` is read from that definition, as DPP reads it. The caller-stored `serializedContract` and `binarySerialization` keep the contract as sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y type shorthands `Contracts.expandPropertyTypeShorthands` bridges the rs-sdk-ffi view through a new JNI export, and KotlinExampleApp's `ParsedContract` reads the document type schemas from it, so the create and detail screens treat an `identifier` or `bytes` property as the byte array it stands for. The stored contract JSON stays as sent; without the native library (JVM unit tests) the view falls back to it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 26 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (12)
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. Comment |
Contributor
|
Waiting for bot review — coderabbitai not yet · thepastaclaw not yet. Wait for the missing reviews, or a writer can post |
QuantumExplorer
deleted the
claude/mobile-expand-property-type-shorthands
branch
October 9, 2026 12:54
This was referenced Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Basic explanation
What this does: Since #5355, a data contract may describe a field with a short spelling:
"type": "identifier"for a 32-byte identity or document id, and"type": "bytes", "size": 20for a fixed run of 20 bytes. Platform keeps the contract exactly as written, so the iOS and Android example apps received the short spelling and did not recognise it. This PR asks Rust to rewrite a fetched contract into the long spelling the apps already understand, and the apps read that rewritten copy. The contract they save stays as it was sent.Value: Contracts using the new shorthands show the right input in the iOS and Android apps: an identifier field asks for a base58 id, a
bytesfield shows its exact byte count, and a list of identifiers gets the list editor. The meaning of the shorthands stays in one place (Rust), so Swift and Kotlin cannot drift from consensus.Risks: Low. No consensus or Platform change: only the mobile SDKs and the FFI that serves them. Every contract the apps parse now makes one extra in-process round trip through Rust as JSON; if that ever fails, the apps log it and read the contract as sent, which is today's behaviour. Contracts without a shorthand come back with the same content. The new Android instrumented test was compiled but not run on a device.
Issue being fixed or feature implemented
Follow-up to #5355 (merged). Rust expands the shorthands through
DocumentType::expand_property_type_shorthands/expand_schema_defs_property_type_shorthands, but the contract is stored and returned as sent, so the contract JSON the mobile SDKs fetch holds"type": "identifier"/"type": "bytes".DataContractParser.parsePropertiesreadtype,byteArray,contentMediaType,minItems,maxItemsstraight from that JSON, so a shorthand property was persisted as typeidentifierorbyteswith no byte array flag.DocumentFieldsViewthen fell back to a generic text box, andDocumentTypedArraydid not recogniseitems: { "type": "identifier" }.ParsedContract(KotlinExampleApp) feeds the same raw schemas toCreateDocumentScreen,TypedArraysandDocumentTypeDetailsScreen, with the same result. (PropertyEntityis never populated, so it is not involved.)dash_sdk_data_contract_get_schema(rs-sdk-ffiutil.rs) also returns the schema as sent, but neither app calls it: both read the JSON returned by the fetch functions.Why Rust expands, not the Swift and Kotlin parsers
packages/swift-sdk/CLAUDE.mdandpackages/kotlin-sdk/CLAUDE.mdforbid re-implementing protocol rules on the mobile side. What a shorthand means (32 bytes, the identifier media type, that it is read on object members at any depth, typed arrayitemsand definitions but not insideenumorrefersTo) is consensus logic DPP already versions.propertyConstraintsprecedent (feat(platform)!: let property constraint rules read the bytes of byte arrays (PV14) #5336, feat(swift-sdk): decode the "bytes" propertyConstraints read kind #5339): the FFI derives a view from the contract with DPP's own code and the apps only marshal it.What was done?
dash_sdk_data_contract_json_expand_property_type_shorthands(contract_json)(data_contract/property_type_shorthands.rs). It takes a contract JSON and returns it with each document type schema (underdocumentSchemasordocuments) passed throughDocumentType::expand_property_type_shorthandsand the definitions (underschemaDefsor$defs) throughexpand_schema_defs_property_type_shorthands. Everything else is passed through. It takes no SDK handle and runs atPlatformVersion::latest()without full validation: the contract was already accepted by the network, a shorthand can only be in a contract accepted at protocol version 14 or later, and needing no handle lets code that holds only JSON call it.dash_sdk_data_contract_get_schemakeeps returning the schema as sent; its doc now says so and points at the new function.DataContractParser.parseDataContractfirst replacescontractDatawith the long-form view (expandingPropertyTypeShorthands(in:), which only marshals and falls back to the input on failure).schemaJSON,propertiesJSON, thePersistentPropertyrows andtypedArraysall read the long form, soDocumentFieldsViewandDocumentTypeDetailsViewneeded no change. A top-level property written{ "$ref": "#/$defs/<name>" }is now read from that definition, as DPP reads it; before, it was persisted as typeunknown. No@Modelstored property changed (doc comments only), so there is no schema version bump.QueriesNative.dataContractJsonExpandPropertyTypeShorthands, publicContracts.expandPropertyTypeShorthands(contractJson)(static, noSdkneeded), andParsedContract.fromin KotlinExampleApp reads the expanded JSON. JVM unit tests, which never load the native library, fall back to the JSON as sent.PersistentDataContract.serializedContract/binarySerialization(iOS),DataContractEntity.serializedContract(Android, still shown raw on the contract details screen), and Rust's own stored contract.Before / after
Contract fragment, fetched from Platform exactly as registered:
Before, the iOS parser persisted:
After:
The FFI call itself:
How Has This Been Tested?
cargo test -p rs-sdk-ffi --lib property_type_shorthands: 9 new tests pass (identifier and bytes at top level, object members, typed arrayitems,schemaDefs, thedocuments/$defskeys, a contract without shorthands returned as given, every other value passed through, null / non-UTF-8 / non-object input refused). Re-run after rebasing onto refactor(dpp)!: keep the property type shorthand expansion out of shipped generations #5357.cargo clippy -p rs-sdk-ffi --all-targets,cargo fmt --all -- --check: clean.cargo test -p rs-unified-sdk-jni: 43 pass;cargo check -p rs-unified-sdk-jniafter the rebase.build_ios.sh --target sim --profile dev, iPhone 17 simulator): newDataContractParserPropertyTypeShorthandTests(12 tests: each shorthand as a top-level property, an object member, typed arrayitemsand a$refdefinition, plus the contract's owndocuments/$defskeys, a long-form contract parsed exactly as before, the caller's contract left as sent, and the fallback for input that is not JSON) together with the existingDataContractParser*Tests,DocumentTypeImmutabilityTestsandDocumentTypedArrayElementInputTests: 102 tests, 0 failures.freeze_schema_models.py --checkpasses. SwiftExampleApp builds.:sdk:compileDebugKotlin,:sdk:compileDebugAndroidTestKotlin,:app:compileDebugKotlinpass;:app:testDebugUnitTest --tests 'org.dashfoundation.example.ui.contracts.*': 46 pass. New instrumentedPropertyTypeShorthandsFfiTest(expansion through JNI at every location, a long-form contract unchanged, error code mapping) compiles; not run, no device or emulator in this session.Breaking Changes
None. One new FFI and JNI function; existing functions are unchanged.
Checklist:
structure.rs, regeneratedgrovedb-structure.json, and checked the structure viewer link posted on this pull requestFor repository code-owners and collaborators only
🤖 Generated with Claude Code
PR Hygiene ·
748d12d/skip-botsproceeds without the ones not yet reported/self-reviewedkotlin-sdk(packages/kotlin-sdk/KotlinExampleApp/app/src/main/java/org/dashfoundation/example/ui/contracts/ContractJson.kt,packages/kotlin-sdk/sdk/src/androidTest/kotlin/org/dashfoundation/dashsdk/PropertyTypeShorthandsFfiTest.kt,packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/ffi/QueriesNative.ktand 1 more) — HashEngineeringrust-sdk-ffi(packages/rs-sdk-ffi/src/data_contract/mod.rs,packages/rs-sdk-ffi/src/data_contract/property_type_shorthands.rs,packages/rs-sdk-ffi/src/data_contract/util.rs) — lklimek or shumkovswift-sdk(packages/swift-sdk/Sources/SwiftDashSDK/Core/Utils/DataContractParser.swift,packages/swift-sdk/Sources/SwiftDashSDK/Core/Utils/DocumentTypedArray.swift,packages/swift-sdk/Sources/SwiftDashSDK/Persistence/Models/PersistentDocumentType.swiftand 1 more) — llbartekll or romchornyiWhen every merge requirement is met, the
PR Hygienecheck passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.