-
Notifications
You must be signed in to change notification settings - Fork 17
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hypercore Header DEP #34
Changes from 2 commits
f0a4869
96db1ff
913a0b6
1a22f61
5569167
a412d3e
a100c71
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
|
||
Title: **DEP-0000: Hypercore Header** | ||
|
||
Short Name: `0000-hypercore-header` | ||
|
||
Type: Standard | ||
|
||
Status: Undefined (as of 2018-06-26) | ||
|
||
Github PR: (add HTTPS link here after PR is opened) | ||
|
||
Authors: [Paul Frazee](https://github.com/pfrazee), [Mathias Buus](https://github.com/mafintosh) | ||
|
||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
The Dat protocol supports a variety of data structures on top of the hypercore append-only logs, including key-value stores (hyperdb) and file archives (hyperdrive). In order for a program to read the data structure within a hypercore, it must know which structure it is reading. This DEP specifies a "header" entry which can be placed at the first entry of a hypercore in order to provide identifying information. This header also supports custom data for the data-structure, and may be expanded in future DEPs to provide additional standard data. | ||
|
||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
At time of writing, Dat's standard data structures are being expanded upon (hyperdb) while existing data structures are being updated with breaking changes (hyperdrive). In order for these changes to be deployed smoothly to the network, it's important that the following needs be met: | ||
|
||
1. Programs should correctly identify the data structure type and version within a hypercore. This will enable the program to use the correct handling code (eg hyperdb, hyperdrive-v1, hyperdrive-v2). | ||
2. Programs should abort processing a hypercore if they lack support for the type or version of the data structure. | ||
|
||
|
||
# Usage Documentation | ||
[usage-documentation]: #usage-documentation | ||
|
||
The "header" is the first entry in a hypercore. It includes a `type` and an optional `extension` which can contain data-structure-specific data. | ||
|
||
A program that is reading a hypercore will examine the `type` to determine how to process the hypercore. | ||
|
||
```js | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have a soft preference for using pseudo code rather than literal javascript in the DEPs. In additional to being more implementation-agnostic, an argument against using actual code is that it comes with an implication that this exact API is stable, or that this exact code is the canonical code that people should always copy/paste into their applications even years down the line. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Okay I'll rewrite with that in mind. |
||
function loadCorrectStructure (hypercore, cb) { | ||
readHeader(hypercore, (err, header) => { | ||
if (err) return cb(err) | ||
|
||
if (!header) { | ||
// no header present - treat as a hypercore | ||
return cb(null, hypercore) | ||
} | ||
|
||
switch (header.type) { | ||
case 'hyperdrive': | ||
return cb(null, createHyperdriveV1(hypercore, header)) | ||
case 'hyperdrive-v2': | ||
return cb(null, createHyperdriveV2(hypercore, header)) | ||
case 'hyperdb': | ||
return cb(null, createHyperdbV1(hypercore, header)) | ||
case '': | ||
return cb(null, hypercore) // no structure, treat as a hypercore | ||
// ... | ||
default: | ||
return cb(new Error('Unsupported: ' + header.type)) | ||
} | ||
}) | ||
} | ||
``` | ||
|
||
The `type` string should be unique to the data structure (refer to existing DEPs to avoid conflicts). When a breaking change is made to the data-structure, it should be given a new `type` string. For example, the `"hyperdrive"` type string will be updated to `"hyperdrive-v2"` for its second version. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this imply that the Some common aesthetically pleasing separators would be To propose something concrete, lets say dash ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm okay with some conventions but I'm not sure I want to standardize a syntax. Just not sure it's worth it. Reason being:
This is totally reasonable, but you then need to interpret |
||
|
||
The `header.extension` is an optional blob of bytes. It can be used by the data structure to store custom data. In `"hyperdrive"` (v1) it is used to specify the key of the content hypercore. It is also valid to encode a protobuf message into the extension field, and therefore it's simple to add additional fields. | ||
|
||
|
||
# Reference Documentation | ||
[reference-documentation]: #reference-documentation | ||
|
||
The header message should be written as the first entry of the hypercore. It is not required that all hypercores possess a header. | ||
|
||
The header message has the following protobuf schema: | ||
|
||
```protobuf | ||
message HypercoreHeader { | ||
required string type = 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm starting to wonder if we should call this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Noting that this can be updated without any backwards compat issues because of protobuf There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
optional bytes extension = 2; | ||
} | ||
``` | ||
|
||
Data structures should not add additional fields to the `HypercoreHeader`. They should put any additional data into the `extension`. This is easy to do with protobuf's nested messages. For example: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should implementations fail fast on additional fields, or should they ignore additional fields? The later is future-compatible, the former is not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ignore, probably. I'll add a note. |
||
|
||
```protobuf | ||
message MyCustomHeader { | ||
message AdditionalData { | ||
required string foo = 1; | ||
required uint64 bar = 2; | ||
} | ||
required string type = 1; | ||
optional AdditionalData extension = 2; | ||
} | ||
``` | ||
|
||
|
||
# Rationale and alternatives | ||
[alternatives]: #alternatives | ||
|
||
This standard is backwards compatible with v1 of hyperdrive, which used an `Index` message as the first entry in the metadata hypercore. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, :party:! |
||
|
||
An alternative approach is to simply attempt to process a given hypercore with all known message encodings. However, this is time-consuming and error-prone, and may not accurately capture the *version* of a data-structure. | ||
|
||
|
||
# Changelog | ||
[changelog]: #changelog | ||
|
||
- 2018-06-26: First complete draft submitted for review | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the example of
hyperdrive-v1
is somewhat at odds with the example ofhyperdrive
throughout the rest of the article. Might be best to pick one and stick with it?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed that we should change it to
hyperdrive