AEX 7
AEX: 7
Title: Data Serialization
Author: Andreas Gassmann (@AndreasGassmann), Alessandro De Carli (@dcale)
License: BSD-3-Clause
Discussions-To: TBD
Status: Draft
Type: Standards Track
Created: 2019-05-13
Simple Summary
This document defines a serialization standard to facilitate data transfer between DApps, Wallets and devices.
Motivation
Data needs to be transferred between different apps and devices. Those apps may or may not be located on the same device. The transport layer used by those apps is unknown and will not be part of this AEX. However, since many of the transport layers can only transfer a limited amount of data (eg. QR codes, Bluetooth, NFC, URLs), the data should always be encoded in a standardized and space efficient way.
The data serialization protocol in this AEX aims to provide a solution with the following goals in mind:
- Easy understand and implement
- Space efficient
- Make sure to not transmit redundant information, send only what is necessary
- Allow airgapped Apps such as AirGap Vault to properly display all necessary information when signing a transaction
Specification
Serialization - RLP
Basic description of RLP.
We use RLP for the following reasons:
- RLP is being used throughout the crypto space, with Aeternity adapting RLP as well after Ethereum
- It is able to serialize and deserialize data in a predictable way
- Easy to understand and implement
- Encoded Data as Binary, size-efficient
Encoding
The resulting string will be encoded with base58
because it is URL-safe, which is important for some transport layers.
Transport Layers
The different transport layers are not part of this AEX, but we should keep the following transport layers in mind:
- QR Codes
- Deeplinking / URLs
- Clipboard copy/paste
- Push Notifications
- WebSockets
- Webhooks
- Bluetooth
- NFC
Example
[
1, // ProtocolVersion
1, // SerializationType: Full or Chunked
[
// Array of Messages
[
1, // MessageVersion
2, // MessageType
"ae", // Protocol
"payload" // Payload depending on the MessageType
],
[
1, // MessageVersion
3, // MessageType
"ae", // Protocol
"payload" // Payload depending on the MessageType
]
]
];
This example would result in the following, base58 encoded, string:
2hDLW1FiwvQs5ofPUgi5CgAJKDWiNncCoETXf7DGdkkDmrhN3z
The payload can be another RLP array, depending on the MessageType
.
Paging / Chunks
While the transport layer is not part of this AEX, we have to think about how we can split up a request if it doesn't fit into one "packet", depending on the transport layer.
The protocol should offer a "chunking" functionality where the user can pass a maximum size per chunk.
function serialize(rlp, maxChunkSizeInByte): string[] {}
function deserialize(chunks): any[] {}
const chunks = serialize(rlp, 1024);
const deserializedRlp = deserialize(chunks);
[
1, // Protocol Version
1, // SerializationType: Full or Chunked
[
1, // Current Page
4, // Number of pages
"payload of current chunk as string"
]
];
Message Types
This standard allows for new message types to be added by every application. But ideally, we should provide a set of commonly used types so they can be re-used between different apps. Some of the default types could be:
- MetadataRequest (Information about the app, like name, version, url)
- MetadataResponse
- AccountShareRequest
- AccountShareResponse
- TransactionSignRequest
- TransactionSignResponse
- MessageSignRequest
- MessageSignResponse
Versioning
There are 2 different kinds of versions:
- Protocol Version: Defines the version of the sync protocol. If this does not match, then the request most likely cannot be processed.
- Message Version: This version is specific to a currency and message type. This allows us to add additional functionality (new message types), without breaking existing (unchanged) message types.
Looking at the MessageVersion
, MessageType
and ProtcolIdentifier
together, we can determine if we can handle that specific request or not.
Rationale
We use RLP over more commonly used standards like JSON or XML because it's more space efficient.
We encode the resulting string with base58
so it will be compatible with URLs.
Adding an ID to the Request
It might make sense to include a random ID for all "Requests", and then send this ID back with the "Responses". This would allow the initiating application to provide additional context info for that specific request. However, we decided against that because it means that not the complete state is contained in the data that is sent. There are scenarios where the recipient of the Response is not the same application / device that initiated the request.
Example:
- User uses web extension to prepare a transaction
- User scans prepared transaction QR with mobile phone to sign
- User broadcasts the transaction on the mobile phone directly
So in this example, the ID would be useless to the broadcasting app on the phone because the context would be missing.
Implementation
There is currently one working implementation inside the airgap-coin-lib, which uses this scheme to facilitate communication between online and offline devices.