From 3ab7d985501ec7c7d5b8706746460c8e814117e9 Mon Sep 17 00:00:00 2001 From: Andre Staltz Date: Tue, 18 Apr 2023 18:40:52 +0300 Subject: [PATCH] validate is synchronous --- lib/feed-v1/tangle.js | 4 ++ lib/feed-v1/validation.js | 33 ++++++------ lib/plugin.js | 15 +++--- test/feed-v1-invalid-prev.test.js | 89 +++++++++++++++---------------- test/feed-v1-validate.test.js | 45 +++++++--------- 5 files changed, 93 insertions(+), 93 deletions(-) diff --git a/lib/feed-v1/tangle.js b/lib/feed-v1/tangle.js index 3f52f2d..18dd5bc 100644 --- a/lib/feed-v1/tangle.js +++ b/lib/feed-v1/tangle.js @@ -222,6 +222,10 @@ class Tangle { return path } + size() { + return this.#depth.size + } + getMaxDepth() { return this.#maxDepth } diff --git a/lib/feed-v1/validation.js b/lib/feed-v1/validation.js index 289de52..2295b96 100644 --- a/lib/feed-v1/validation.js +++ b/lib/feed-v1/validation.js @@ -110,6 +110,7 @@ function validateTangle(msg, tangle, tangleId) { } } let minDiff = Infinity + let countPrevUnknown = 0 for (const p of prev) { if (typeof p !== 'string') { // prettier-ignore @@ -121,8 +122,8 @@ function validateTangle(msg, tangle, tangleId) { } if (!tangle.has(p)) { - // prettier-ignore - return new Error('invalid message: prev ' + p + ' is not locally known, on feed: ' + msg.metadata.who); + countPrevUnknown += 1 + continue } const prevDepth = tangle.getDepth(p) @@ -133,13 +134,23 @@ function validateTangle(msg, tangle, tangleId) { } if (diff < minDiff) minDiff = diff } - if (minDiff !== 1) { + + if (countPrevUnknown === prev.length) { + // prettier-ignore + return new Error('invalid message: all prev are locally unknown, on feed: ' + msg.metadata.who) + } + + if (countPrevUnknown === 0 && minDiff !== 1) { // prettier-ignore return new Error('invalid message: depth must be the largest prev depth plus one'); } } -function validateTangleRoot(msg, tangleId) { +function validateTangleRoot(msg, msgHash, tangleId) { + if (msgHash !== tangleId) { + // prettier-ignore + return new Error('invalid message: tangle root hash must match tangleId, on feed: ' + msg.metadata.who); + } if (msg.metadata.tangles[tangleId]) { // prettier-ignore return new Error('invalid message: tangle root must not have self tangle data, on feed: ' + msg.metadata.who); @@ -190,12 +201,12 @@ function validateContent(msg) { // FIXME: validateDepth should be +1 of the max of prev depth -function validateSync(msg, tangle, msgHash, rootHash) { +function validate(msg, tangle, msgHash, rootHash) { let err if ((err = validateShape(msg))) return err if ((err = validateWho(msg))) return err - if (msgHash === rootHash) { - if ((err = validateTangleRoot(msg))) return err + if (tangle.size() === 0) { + if ((err = validateTangleRoot(msg, msgHash, rootHash))) return err } else { if ((err = validateTangle(msg, tangle, rootHash))) return err } @@ -203,14 +214,6 @@ function validateSync(msg, tangle, msgHash, rootHash) { if ((err = validateSignature(msg))) return err } -function validate(msg, tangle, msgHash, rootHash, cb) { - let err - if ((err = validateSync(msg, tangle, msgHash, rootHash))) { - return cb(err) - } - cb() -} - // function validateBatch(nativeMsgs, prevNativeMsg, hmacKey, cb) { // let err // let prev = prevNativeMsg diff --git a/lib/plugin.js b/lib/plugin.js index 64fff75..1b63f92 100644 --- a/lib/plugin.js +++ b/lib/plugin.js @@ -189,19 +189,22 @@ exports.init = function initDB(peer, config) { const tangle = new DBTangle(tangleRootHash, records()) const msgHash = FeedV1.getMsgHash(msg) - FeedV1.validate(msg, tangle, msgHash, tangleRootHash, validationCB) - function validationCB(err) { + // TODO: optimize this. Perhaps have a Map() of msgHash -> record + let rec + if ((rec = getRecord(msgHash))) return cb(null, rec) + + let err + if ((err = FeedV1.validate(msg, tangle, msgHash, tangleRootHash))) { // prettier-ignore - if (err) return cb(new Error('add() failed validation for feed format v1', {cause: err})) - logAppend(msgHash, msg, logAppendCB) + return cb(new Error('add() failed validation for feed format v1', {cause: err})) } - function logAppendCB(err, rec) { + logAppend(msgHash, msg, (err, rec) => { if (err) return cb(new Error('add() failed in the log', { cause: err })) onRecordAdded.set(rec) cb(null, rec) - } + }) } function create(opts, cb) { diff --git a/test/feed-v1-invalid-prev.test.js b/test/feed-v1-invalid-prev.test.js index a890096..e183f2d 100644 --- a/test/feed-v1-invalid-prev.test.js +++ b/test/feed-v1-invalid-prev.test.js @@ -23,11 +23,10 @@ tape('invalid msg with non-array prev', (t) => { msg.metadata.tangles[rootHash].prev = null const msgHash = FeedV1.getMsgHash(msg) - FeedV1.validate(msg, tangle, msgHash, rootHash, (err) => { - t.ok(err, 'invalid 2nd msg throws') - t.match(err.message, /prev must be an array/, 'invalid 2nd msg description') - t.end() - }) + const err = FeedV1.validate(msg, tangle, msgHash, rootHash) + t.ok(err, 'invalid 2nd msg throws') + t.match(err.message, /prev must be an array/, 'invalid 2nd msg description') + t.end() }) tape('invalid msg with bad prev', (t) => { @@ -62,15 +61,14 @@ tape('invalid msg with bad prev', (t) => { msg2.metadata.tangles[rootHash].prev = [1234] const msgHash2 = FeedV1.getMsgHash(msg2) - FeedV1.validate(msg2, tangle, msgHash2, rootHash, (err) => { - t.ok(err, 'invalid 2nd msg throws') - t.match( - err.message, - /prev must contain strings/, - 'invalid 2nd msg description' - ) - t.end() - }) + const err = FeedV1.validate(msg2, tangle, msgHash2, rootHash) + t.ok(err, 'invalid 2nd msg throws') + t.match( + err.message, + /prev must contain strings/, + 'invalid 2nd msg description' + ) + t.end() }) tape('invalid msg with URI in prev', (t) => { @@ -107,15 +105,14 @@ tape('invalid msg with URI in prev', (t) => { msg2.metadata.tangles[rootHash].depth = 1 msg2.metadata.tangles[rootHash].prev = [fakeMsgKey1] - FeedV1.validate(msg2, tangle, msgHash2, rootHash, (err) => { - t.ok(err, 'invalid 2nd msg throws') - t.match( - err.message, - /prev must not contain URIs/, - 'invalid 2nd msg description' - ) - t.end() - }) + const err = FeedV1.validate(msg2, tangle, msgHash2, rootHash) + t.ok(err, 'invalid 2nd msg throws') + t.match( + err.message, + /prev must not contain URIs/, + 'invalid 2nd msg description' + ) + t.end() }) tape('invalid msg with unknown prev', (t) => { @@ -148,8 +145,9 @@ tape('invalid msg with unknown prev', (t) => { }) const unknownMsgHash = FeedV1.getMsgHash(unknownMsg) - const tangle2 = new FeedV1.Tangle(rootHash) - tangle2.add(rootHash, rootMsg) + const fakeRootHash = 'ABCDEabcde' + rootHash.substring(10) + const tangle2 = new FeedV1.Tangle(fakeRootHash) + tangle2.add(fakeRootHash, rootMsg) tangle2.add(unknownMsgHash, unknownMsg) const msg2 = FeedV1.create({ @@ -157,20 +155,19 @@ tape('invalid msg with unknown prev', (t) => { content: { text: 'Hello world!' }, type: 'post', tangles: { - [rootHash]: tangle2 + [rootHash]: tangle2, }, }) const msgHash2 = FeedV1.getMsgHash(msg2) - FeedV1.validate(msg2, tangle, msgHash2, rootHash, (err) => { - t.ok(err, 'invalid 2nd msg throws') - t.match( - err.message, - /prev .+ is not locally known/, - 'invalid 2nd msg description' - ) - t.end() - }) + const err = FeedV1.validate(msg2, tangle, msgHash2, rootHash) + t.ok(err, 'invalid 2nd msg throws') + t.match( + err.message, + /all prev are locally unknown/, + 'invalid 2nd msg description' + ) + t.end() }) tape('invalid feed msg with a different who', (t) => { @@ -192,10 +189,9 @@ tape('invalid feed msg with a different who', (t) => { }) const msgHash = FeedV1.getMsgHash(msg) - FeedV1.validate(msg, feedTangle, msgHash, rootHash, (err) => { - t.match(err.message, /who ".*" does not match feed who/, 'invalid feed msg') - t.end() - }) + const err = FeedV1.validate(msg, feedTangle, msgHash, rootHash) + t.match(err.message, /who ".*" does not match feed who/, 'invalid feed msg') + t.end() }) tape('invalid feed msg with a different type', (t) => { @@ -216,12 +212,11 @@ tape('invalid feed msg with a different type', (t) => { }) const msgHash = FeedV1.getMsgHash(msg) - FeedV1.validate(msg, feedTangle, msgHash, rootHash, (err) => { - t.match( - err.message, - /type "comment" does not match feed type "post"/, - 'invalid feed msg' - ) - t.end() - }) + const err = FeedV1.validate(msg, feedTangle, msgHash, rootHash) + t.match( + err.message, + /type "comment" does not match feed type "post"/, + 'invalid feed msg' + ) + t.end() }) diff --git a/test/feed-v1-validate.test.js b/test/feed-v1-validate.test.js index 4c8dc96..b64afc1 100644 --- a/test/feed-v1-validate.test.js +++ b/test/feed-v1-validate.test.js @@ -9,13 +9,11 @@ tape('validate root msg', (t) => { const rootMsg = FeedV1.createRoot(keys, 'post') const rootHash = FeedV1.getMsgHash(rootMsg) const tangle = new FeedV1.Tangle(rootHash) - tangle.add(rootHash, rootMsg) - FeedV1.validate(rootMsg, tangle, rootHash, rootHash, (err) => { - if (err) console.log(err) - t.error(err, 'valid root msg') - t.end() - }) + const err = FeedV1.validate(rootMsg, tangle, rootHash, rootHash) + if (err) console.log(err) + t.error(err, 'valid root msg') + t.end() }) tape('validate 2nd msg with existing root', (t) => { @@ -37,11 +35,10 @@ tape('validate 2nd msg with existing root', (t) => { const msgHash1 = FeedV1.getMsgHash(msg1) tangle.add(msgHash1, msg1) - FeedV1.validate(msg1, tangle, msgHash1, rootHash, (err) => { - if (err) console.log(err) - t.error(err, 'valid 2nd msg') - t.end() - }) + const err = FeedV1.validate(msg1, tangle, msgHash1, rootHash) + if (err) console.log(err) + t.error(err, 'valid 2nd msg') + t.end() }) tape('validate 2nd forked msg', (t) => { @@ -75,11 +72,10 @@ tape('validate 2nd forked msg', (t) => { tangle.add(msgHash1A, msg1A) tangle.add(msgHash1B, msg1B) - FeedV1.validate(msg1B, tangle, msgHash1B, rootHash, (err) => { - if (err) console.log(err) - t.error(err, 'valid 2nd forked msg') - t.end() - }) + const err = FeedV1.validate(msg1B, tangle, msgHash1B, rootHash) + if (err) console.log(err) + t.error(err, 'valid 2nd forked msg') + t.end() }) tape('invalid msg with unknown previous', (t) => { @@ -104,13 +100,12 @@ tape('invalid msg with unknown previous', (t) => { msg1.metadata.tangles[rootHash].prev = [fakeMsgHash] - FeedV1.validate(msg1, tangle, msgHash1, rootHash, (err) => { - t.ok(err, 'invalid 2nd msg throws') - t.match( - err.message, - /prev .+ is not locally known/, - 'invalid 2nd msg description' - ) - t.end() - }) + const err = FeedV1.validate(msg1, tangle, msgHash1, rootHash) + t.ok(err, 'invalid 2nd msg throws') + t.match( + err.message, + /all prev are locally unknown/, + 'invalid 2nd msg description' + ) + t.end() })