From bec809ab8e85dfaf15216496ce4edc7bae8b0db1 Mon Sep 17 00:00:00 2001 From: Jacek Sieka Date: Thu, 25 Aug 2022 10:08:04 +0200 Subject: [PATCH] Canonical JSON mapping This PR adds a canonical JSON mapping to the SSZ specification, documenting current usage of JSON in tests, API:s and simplifying future interop work between clients and adjacent specifications such as the Beacon API. The encoding is appropriate to use with YAML as well As an important property, this mapping contains a 1:1 mapping of SSZ type to JSON encoding - this allows round-tripping any object between JSON and SSZ based on the SSZ schema and usage of the core SSZ types alone. The encoding presented in this PR is used in tests and API:s with one exception: the `ParticipationFlags` type from the Altair spec - it is recommended we switch encoding in tests and eventually the beacon API to address this irregularity, so as to avoid a proliferation "special" primitive types in the SSZ spec that only appear in particular schemas (and thus making validating general-purpose `SSZ/JSON` parsers more complex) as well as differences in encoding between fields of the same SSZ type. --- ssz/simple-serialize.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/ssz/simple-serialize.md b/ssz/simple-serialize.md index 4ef64f2f2..77f0c9033 100644 --- a/ssz/simple-serialize.md +++ b/ssz/simple-serialize.md @@ -25,6 +25,7 @@ - [Merkleization](#merkleization) - [Summaries and expansions](#summaries-and-expansions) - [Implementations](#implementations) +- [Canonical JSON mapping](#canonical-json-mapping) @@ -256,3 +257,34 @@ We similarly define "summary types" and "expansion types". For example, [`Beacon ## Implementations See https://github.com/ethereum/eth2.0-specs/issues/2138 for a list of current known implementations. + +## JSON mapping + +The canonical JSON mapping assigns to each SSZ type a corresponding JSON encoding, enabling an SSZ schema to also define the JSON encoding. + +When decoding JSON data, all fields in the SSZ schema must be present with a value. Parsers may ignore additional JSON fields. + +| SSZ | JSON | Example | +| --- | --- | --- | +| `uintN` | string | `"0"` | +| `boolean` | bool | `false` | +| `Container` | object | `{ "field": ... }` | +| `Vector[type, N]` | array | `[element, ...]` | +| `Vector[uint8, N]` | hex-byte-string | `"0x1122"` | +| `Bitvector[N]` | hex-byte-string | `"0x1122"` | +| `List[type, N]` | array | `[element, ...]` | +| `List[uint8, N]` | hex-byte-string | `"0x1122"` | +| `Bitlist[N]` | hex-byte-string | `"0x1122"` | +| `Union[type_0, type_1, ...]` | selector-object | `{ "selector": number, "data": type_N }` | + +Integers are encoded as strings to avoid loss of precision in 64-bit values. + +Aliases are encoded as their underlying type (`byte` is thus encoded as `uint8`). + +`hex-byte-string` is a `0x`-prefixed hex encoding of byte data, as it would appear in an SSZ stream. + +`List` and `Vector` of `uint8` (and aliases thereof) are encoded as `hex-byte-string`. `Bitlist` and `Bitvector` similarly map their SSZ-byte encodings to a `hex-byte-string`. + +`Union` is encoded as an object with a `selector` and `data` field, where the contents of `data` change according to the selector. + +> This encoding is used in [beacon-APIs](https://github.com/ethereum/beacon-APIs) with one exception: the `ParticipationFlags` type for the `getStateV2` response, although it is an alias of `uint8`, is encoded as a list of numbers. Future versions of the beacon API may address this incompatibility.