add metadata.v, rename metadata.proof to metadata.hash

This commit is contained in:
Andre Staltz 2023-04-17 18:39:33 +03:00
parent faa7b13c92
commit 3686f5de24
5 changed files with 34 additions and 20 deletions

View File

@ -39,10 +39,11 @@ function isEmptyObject(obj) {
* @typedef {Object} Msg * @typedef {Object} Msg
* @property {*} content * @property {*} content
* @property {Object} metadata * @property {Object} metadata
* @property {string} metadata.proof * @property {string} metadata.hash
* @property {number} metadata.size * @property {number} metadata.size
* @property {Record<string, TangleMetadata>} metadata.tangles * @property {Record<string, TangleMetadata>} metadata.tangles
* @property {string} metadata.type * @property {string} metadata.type
* @property {1} metadata.v
* @property {string} metadata.who * @property {string} metadata.who
* @property {string} sig * @property {string} sig
*/ */
@ -115,7 +116,7 @@ function create(opts) {
if ((err = validateType(opts.type))) throw err if ((err = validateType(opts.type))) throw err
if (!opts.tangles) throw new Error('opts.tangles is required') if (!opts.tangles) throw new Error('opts.tangles is required')
const [proof, size] = representContent(opts.content) const [hash, size] = representContent(opts.content)
const tangles = {} const tangles = {}
if (opts.tangles) { if (opts.tangles) {
@ -136,10 +137,11 @@ function create(opts) {
const msg = { const msg = {
content: opts.content, content: opts.content,
metadata: { metadata: {
proof, hash,
size, size,
tangles, tangles,
type: opts.type, type: opts.type,
v: 1,
who: stripAuthor(opts.keys.id), who: stripAuthor(opts.keys.id),
}, },
sig: '', sig: '',
@ -168,10 +170,11 @@ function createRoot(keys, type) {
const msg = { const msg = {
content: null, content: null,
metadata: { metadata: {
proof: '', hash: null,
size: 0, size: 0,
tangles: {}, tangles: {},
type, type,
v: 1,
who: stripAuthor(keys.id), who: stripAuthor(keys.id),
}, },
sig: '', sig: '',

View File

@ -167,7 +167,7 @@ class Tangle {
isFeed() { isFeed() {
if (this.#rootMsg.content) return false if (this.#rootMsg.content) return false
const metadata = this.#rootMsg.metadata const metadata = this.#rootMsg.metadata
return metadata.size === 0 && metadata.proof === '' return metadata.size === 0 && metadata.hash === null
} }
getFeed() { getFeed() {

View File

@ -2,6 +2,7 @@ const base58 = require('bs58')
const ed25519 = require('ssb-keys/sodium') const ed25519 = require('ssb-keys/sodium')
const stringify = require('fast-json-stable-stringify') const stringify = require('fast-json-stable-stringify')
const Tangle = require('./tangle') const Tangle = require('./tangle')
const representContent = require('./represent-content')
function validateShape(msg) { function validateShape(msg) {
if (!msg || typeof msg !== 'object') { if (!msg || typeof msg !== 'object') {
@ -13,11 +14,14 @@ function validateShape(msg) {
if (typeof msg.metadata.who === 'undefined') { if (typeof msg.metadata.who === 'undefined') {
return new Error('invalid message: must have metadata.who') return new Error('invalid message: must have metadata.who')
} }
if (msg.metadata.v !== 1) {
return new Error('invalid message: must have metadata.v 1')
}
if (typeof msg.metadata.tangles !== 'object') { if (typeof msg.metadata.tangles !== 'object') {
return new Error('invalid message: must have metadata.tangles') return new Error('invalid message: must have metadata.tangles')
} }
if (typeof msg.metadata.proof === 'undefined') { if (typeof msg.metadata.hash === 'undefined') {
return new Error('invalid message: must have metadata.proof') return new Error('invalid message: must have metadata.hash')
} }
if (typeof msg.metadata.size === 'undefined') { if (typeof msg.metadata.size === 'undefined') {
return new Error('invalid message: must have metadata.size') return new Error('invalid message: must have metadata.size')
@ -162,10 +166,8 @@ function validateType(type) {
} }
function validateContent(msg) { function validateContent(msg) {
// FIXME: if content exists, check it against `proof` and `size`
// FIXME: if content does not exist, do nothing
const { content } = msg const { content } = msg
if (!content) { if (content === null) {
return return
} }
if (Array.isArray(content)) { if (Array.isArray(content)) {
@ -175,6 +177,15 @@ function validateContent(msg) {
// prettier-ignore // prettier-ignore
return new Error('invalid message: content must be an object or string, on feed: ' + msg.metadata.who); return new Error('invalid message: content must be an object or string, on feed: ' + msg.metadata.who);
} }
const [hash, size] = representContent(content)
if (hash !== msg.metadata.hash) {
// prettier-ignore
return new Error('invalid message: content hash does not match metadata.hash, on feed: ' + msg.metadata.who);
}
if (size !== msg.metadata.size) {
// prettier-ignore
return new Error('invalid message: content size does not match metadata.size, on feed: ' + msg.metadata.who);
}
} }
// FIXME: validateDepth should be +1 of the max of prev depth // FIXME: validateDepth should be +1 of the max of prev depth

View File

@ -20,7 +20,7 @@ test('erase', async (t) => {
await peer.db.loaded() await peer.db.loaded()
const rootHash = 'PGwQiuwFnB7EySQHBit2mA' const rootHash = 'Nf2kuXAYsLBHEgU9eonYdn'
const msgHashes = [] const msgHashes = []
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
const rec = await p(peer.db.create)({ const rec = await p(peer.db.create)({

View File

@ -8,14 +8,14 @@ tape('FeedV1.createRoot()', (t) => {
const keys = generateKeypair('alice') const keys = generateKeypair('alice')
rootMsg = FeedV1.createRoot(keys, 'post') rootMsg = FeedV1.createRoot(keys, 'post')
t.equals(rootMsg.content, null, 'content') t.equals(rootMsg.content, null, 'content')
t.equals(rootMsg.metadata.proof, '', 'proof') t.equals(rootMsg.metadata.hash, null, 'hash')
t.equals(rootMsg.metadata.size, 0, 'size') t.equals(rootMsg.metadata.size, 0, 'size')
t.equals(rootMsg.metadata.type, 'post', 'type') t.equals(rootMsg.metadata.type, 'post', 'type')
t.equals(rootMsg.metadata.who, FeedV1.stripAuthor(keys.id), 'who') t.equals(rootMsg.metadata.who, FeedV1.stripAuthor(keys.id), 'who')
t.deepEquals(rootMsg.metadata.tangles, {}, 'tangles') t.deepEquals(rootMsg.metadata.tangles, {}, 'tangles')
rootHash = FeedV1.getMsgHash(rootMsg) rootHash = FeedV1.getMsgHash(rootMsg)
t.equals(rootHash, 'PGwQiuwFnB7EySQHBit2mA', 'root hash') t.equals(rootHash, 'Nf2kuXAYsLBHEgU9eonYdn', 'root hash')
t.end() t.end()
}) })
@ -36,7 +36,7 @@ tape('FeedV1.create()', (t) => {
}) })
t.deepEquals( t.deepEquals(
Object.keys(msg1.metadata), Object.keys(msg1.metadata),
['proof', 'size', 'tangles', 'type', 'who'], ['hash', 'size', 'tangles', 'type', 'v', 'who'],
'metadata fields' 'metadata fields'
) )
t.equals( t.equals(
@ -45,7 +45,7 @@ tape('FeedV1.create()', (t) => {
'metadata.who' 'metadata.who'
) )
t.equals(msg1.metadata.type, 'post', 'metadata.type') t.equals(msg1.metadata.type, 'post', 'metadata.type')
t.deepEquals(msg1.metadata.proof, '9R7XmBhHF5ooPg34j9TQcz', 'metadata.proof') t.deepEquals(msg1.metadata.hash, '9R7XmBhHF5ooPg34j9TQcz', 'metadata.hash')
t.deepEquals(Object.keys(msg1.metadata.tangles), [rootHash], 'tangles') t.deepEquals(Object.keys(msg1.metadata.tangles), [rootHash], 'tangles')
t.equals(msg1.metadata.tangles[rootHash].depth, 1, 'tangle depth') t.equals(msg1.metadata.tangles[rootHash].depth, 1, 'tangle depth')
t.deepEquals(msg1.metadata.tangles[rootHash].prev, [rootHash], 'tangle prev') t.deepEquals(msg1.metadata.tangles[rootHash].prev, [rootHash], 'tangle prev')
@ -54,7 +54,7 @@ tape('FeedV1.create()', (t) => {
console.log(msg1) console.log(msg1)
const msgHash1 = 'M31mLeV2wNDwp9ZRkkF8pL' const msgHash1 = 'SktCiaHrUxz2mXS1SRSDmj'
t.equals( t.equals(
FeedV1.getMsgId(msg1), FeedV1.getMsgId(msg1),
@ -79,7 +79,7 @@ tape('FeedV1.create()', (t) => {
}) })
t.deepEquals( t.deepEquals(
Object.keys(msg2.metadata), Object.keys(msg2.metadata),
['proof', 'size', 'tangles', 'type', 'who'], ['hash', 'size', 'tangles', 'type', 'v', 'who'],
'metadata keys' 'metadata keys'
) )
t.equals( t.equals(
@ -91,7 +91,7 @@ tape('FeedV1.create()', (t) => {
t.deepEquals(Object.keys(msg1.metadata.tangles), [rootHash], 'tangles') t.deepEquals(Object.keys(msg1.metadata.tangles), [rootHash], 'tangles')
t.equals(msg2.metadata.tangles[rootHash].depth, 2, 'tangle depth') t.equals(msg2.metadata.tangles[rootHash].depth, 2, 'tangle depth')
t.deepEquals(msg2.metadata.tangles[rootHash].prev, [msgHash1], 'tangle prev') t.deepEquals(msg2.metadata.tangles[rootHash].prev, [msgHash1], 'tangle prev')
t.deepEquals(msg2.metadata.proof, 'XuZEzH1Dhy1yuRMcviBBcN', 'metadata.proof') t.deepEquals(msg2.metadata.hash, 'XuZEzH1Dhy1yuRMcviBBcN', 'metadata.hash')
t.deepEquals(msg2.metadata.size, 21, 'metadata.size') t.deepEquals(msg2.metadata.size, 21, 'metadata.size')
t.deepEqual(msg2.content, content2, 'content is correct') t.deepEqual(msg2.content, content2, 'content is correct')
@ -99,7 +99,7 @@ tape('FeedV1.create()', (t) => {
t.deepEqual( t.deepEqual(
FeedV1.getMsgId(msg2), FeedV1.getMsgId(msg2),
'ppppp:message/v1/4mjQ5aJu378cEu6TksRG3uXAiKFiwGjYQtWAjfVjDAJW/post/MHLPVrHFzCLXVeXUkY1W4a', 'ppppp:message/v1/4mjQ5aJu378cEu6TksRG3uXAiKFiwGjYQtWAjfVjDAJW/post/Nej4ibHrxryTduWqDeCJE4',
'getMsgId' 'getMsgId'
) )
@ -122,7 +122,7 @@ tape('create() handles DAG tips correctly', (t) => {
const msgHash1 = FeedV1.getMsgHash(msg1) const msgHash1 = FeedV1.getMsgHash(msg1)
t.deepEquals( t.deepEquals(
msg1.metadata.tangles[rootHash].prev, msg1.metadata.tangles[rootHash].prev,
['PGwQiuwFnB7EySQHBit2mA'], ['Nf2kuXAYsLBHEgU9eonYdn'],
'msg1.prev is root' 'msg1.prev is root'
) )