Skip to content

v2#7

Merged
bitjson merged 4 commits intomasterfrom
v2
Apr 20, 2023
Merged

v2#7
bitjson merged 4 commits intomasterfrom
v2

Conversation

@bitjson
Copy link
Owner

@bitjson bitjson commented Apr 13, 2023

Fixes #6

This PR includes an assortment of corrections I've run into while experimenting since the v1 release. They're generally small changes, but they still require a version increase as they're not all backward compatible.

One key insight reflected in several locations is that objects are generally safer than arrays in data formats that might be revised by multiple parties. With an array, a git commit that inserts an item cannot be safely merged with another git commit that references array items by number. Because maps explicitly assign an index to each item, they also tend to be more resilient and easier for humans to work with in simple editing tools. This PR doesn't completely remove array use from the BCMR schema, but arrays are reserved only for fields requiring a simple list of strings.

  • Extensions have stricter limits: strings, or objects of strings (up to two dimensions), rather than the previous unknown value. This makes implementation in a variety of programming languages far safer and more consistent without compromising expressiveness. (Extensions that might have unwittingly used arrays will also now be implemented using objects, gaining the benefits of objects mentioned above.)
  • Introduces the concept of chains and a defaultChain, allowing registries to differentiate identities/tokens using mainnet vs. chipnet, testnet4, or any potential future splits. Registries focused on BCH mainnet can basically ignore this stuff entirely, but now it's at least possible for registries to differentiate between networks.
  • Simplified a registry's view of time – v1 attempted to support conveying information about migrations in terms of on-chain locktime (MTP or block height). This added significant complexity for effectively no end-user benefit: registries are an application layer standard for wallets/clients that most certainly operate in real-world time. Supporting conversion (estimation) between on-chain time and real-world time is non-trivial for clients and may actually never be used by identity holders or token issuers – in the vast majority of cases, it's more desirable for all client UIs to reflect some change at approximately the same time (e.g. midnight UTC) rather than waiting for some unpredictable on-chain "time" to be confirmed. Even if an on-chain protocol does actually upgrade at a particular on-chain time (and clients will care to indicate the on-chain migration period, rather than just pretend it happened at some precise real-world time), registries should simply indicate estimated start/end timestamps that offer a reasonable estimate for when the MTP/block height will be reached. In effect, we're tasking the registry/issuer with the "on-chain time estimation" work so that every wallet/client can avoid rewriting the same, possibly-never-used code.
  • As part of time simplification + migration from complex arrays to objects, the identities field is now an object rather than an array, keyed by ISO string times. This both simplifies usage and makes the format easier to grok. IdentitySnapshot.time.{begin/complete} is now replaced with an optional migrated timestamp, removing a lot of visual noise from the format.
  • token.nfts.fields is now optional, also reducing noise
  • token.nfts.parse now uses a standard transaction context, eliminating some undefined behavior and simplifying implementation. (Some discussion here.)

@bitjson
Copy link
Owner Author

bitjson commented Apr 14, 2023

Hey @mr-zwets and @A60AB5450353F40E – I know you both have done some some experimenting with the v1 JSON schema so far, I'd love to get your thoughts on these updates!

@mr-zwets
Copy link
Contributor

Hi, thanks for pinging me! I just went over the changes and I think the simplified view of time in a registry is a great change! I'm not sure I fully get the rational for changing from arrays to objects (maps?) but one thing I worry about is that getting the latest identity snapshot becomes less easy as you can't get the last index of the array but instead have to compare all the timestamp keys on an object?

token.nfts.fields is optional but token.nfts.parse.types.[bottomAltStackItemHex].fields is not, is this intentional?

Currently types: { [bottomAltStackItemHex: string]: {}} is not an exported member, I have found it useful to create an export type nftTypes to use to validate this types object separately, as it is pretty deeply nested and will often be programmatically created. I found this practical but not sure if that means something could be improved.

One thing I do hope is that wallets will not have to support both bcmr versions with different parsing rules. I assume because it wasn't used on mainnet that the old standard can just be dropped?

@bitjson
Copy link
Owner Author

bitjson commented Apr 14, 2023

Awesome, thanks for the review @mr-zwets!

Ah, I failed to mention another implementation concern on timestamps – the v1 schema had two potentially-conflicting ways to represent snapshot ordering information. Since identities was an array, there's an implied snapshot order, but each snapshot also had a time.begin value. So it was possible to write a "malformed" registry where the array order doesn't match the true order when snapshots are sorted by time.begin. So by allowing for a "suggested sorting" via array order, the v1 schema was likely encourage implementation inconsistencies: many clients would just look at index 0 and 1 instead of the more "correct" option of validating the array's sort order while importing the registry, and erroring if a mismatch is found. The object-based structure can still be sorted by timestamp for convenient reading, but it no longer gives the illusion of being (safely) pre-sorted. And unfortunately, there's no way to both encode data as an array and include a refined timestamp within that data without introducing a potential for inconsistency. (I should add that some of this also makes more sense when we consider BCMRs to require a "canonical encoding" for use cases like a deterministic "registry version hash" or deterministic messages between two mutually-untrusting wallet signers.)

Re mandatory fields: ah, just an oversight, thanks!

And thanks also for the recommendation to assign proper names to some of the complex types, I hadn't fought with that yet, but definitely important that we export early and often. Fixed in e89183b 🚀

@bitjson
Copy link
Owner Author

bitjson commented Apr 15, 2023

Ok, examples/fungible-token.json added, some other items polished: https://github.com/bitjson/chip-bcmr/blob/373322b98861b5d080b167701a990a3ba108d9c7/examples/fungible-token.json

Still working on additional examples.

@bitjson
Copy link
Owner Author

bitjson commented Apr 15, 2023

Ah, I didn't respond to @mr-zwets question on supporting the v1 schema – yeah, I think v1 should definitely be dropped completely. In a sense, it only ever supported chipnet since the format can't even indicate what chain it's talking about.

We can worry a bit more about backwards compatibility after this major version. I'm hopeful we've found a lot of the issues for now though, and future changes will generally just add new, optional fields. (And/or use extensions rather than changing the standard!)

@bitjson
Copy link
Owner Author

bitjson commented Apr 20, 2023

I think this is pretty solid, so merging now. I'll work on a few additional examples in other PRs.

@bitjson bitjson merged commit 0135305 into master Apr 20, 2023
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.

Make the 'fields' key of nfts optional in the bcmr schema

2 participants