From 4fff37ad02a6e7fe409b6186e36ef3a1800cfcf8 Mon Sep 17 00:00:00 2001 From: Andre Staltz Date: Wed, 25 Oct 2023 19:09:19 +0300 Subject: [PATCH] refuse re-adding a dataful ghost msg --- lib/ghosts.js | 29 +++++++++++++++++++++++++++++ lib/index.js | 44 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/lib/ghosts.js b/lib/ghosts.js index e82f816..5ebc31b 100644 --- a/lib/ghosts.js +++ b/lib/ghosts.js @@ -151,6 +151,35 @@ class Ghosts { }) } + /** + * @param {string} tangleID + * @param {string} msgID + * @param {CB} cb + */ + remove(tangleID, msgID, cb) { + this.#loaded.onReady(() => { + if (!this.#maps.has(tangleID)) return cb() + + const map = /** @type {Map} */ (this.#maps.get(tangleID)) + if (!map.has(msgID)) return cb() + + const newMap = new Map(map) + newMap.delete(msgID) + + atomic.writeFile( + this.#path(tangleID), + this.#serialize(newMap), + Ghosts.encodingOpts, + (/** @type {any} */ err) => { + // prettier-ignore + if (err) return cb(new Error('GhostDB.save() failed to write ghost file', { cause: err })) + this.#maps.set(tangleID, newMap) + cb() + } + ) + }) + } + /** * @param {string} tangleID * @returns {Map} diff --git a/lib/index.js b/lib/index.js index e3be55d..b487d34 100644 --- a/lib/index.js +++ b/lib/index.js @@ -355,21 +355,25 @@ function initDB(peer, config) { try { accountTangle = getAccountTangle(rec) } catch (err) { - // prettier-ignore - return new Error('Failed to identify the account of this msg', { cause: err }) + return new Error('Unknown account tangle owning this msg', { cause: err }) } const pubkeys = getPubkeysInAccount(accountTangle) + // Don't accept ghosts to come back, unless they are trail msgs + if (!!rec.msg.data && ghosts.read(tangleID).has(rec.id)) { + return new Error('Refusing a ghost msg to come back') + } + let err if ((err = MsgV3.validate(rec.msg, tangle, pubkeys, rec.id, tangleID))) { - return new Error('Failed msg validation', { cause: err }) + return new Error('Invalid msg', { cause: err }) } // Account tangle related validations if (rec.msg.metadata.account === ACCOUNT_SELF) { const validAccountTangle = /** @type {Tangle} */ (accountTangle) if ((err = validateAccountMsg(rec.msg, validAccountTangle))) { - return new Error('Failed msg account validation', { cause: err }) + return new Error('Invalid account msg', { cause: err }) } } @@ -410,10 +414,16 @@ function initDB(peer, config) { return cb(new Error('add() failed to verify msg', { cause: err })) } - logAppend(msgID, msg, (err, rec) => { - if (err) return cb(new Error('add() failed in the log', { cause: err })) - onRecordAdded.set(rec) - cb(null, rec) + // The majority of cases don't have ghosts to be removed, but this operation + // is silent and cheap if there are no ghosts. + removeGhost(tangleID, msgID, (err) => { + // prettier-ignore + if (err) return cb(new Error('add() failed to remove ghost', { cause: err })) + logAppend(msgID, msg, (err, rec) => { + if (err) return cb(new Error('add() failed in the log', { cause: err })) + onRecordAdded.set(rec) + cb(null, rec) + }) }) } @@ -962,6 +972,24 @@ function initDB(peer, config) { }) } + /** + * @param {MsgID} tangleID + * @param {MsgID} msgID + * @param {CB} cb + */ + function removeGhost(tangleID, msgID, cb) { + // prettier-ignore + if (typeof tangleID !== 'string') return cb(new Error('ghosts.remove() requires tangleID in the 1st arg')) + // prettier-ignore + if (typeof msgID !== 'string') return cb(new Error('ghosts.remove() requires msgID in the 2nd arg')) + + ghosts.remove(tangleID, msgID, (err) => { + // prettier-ignore + if (err) cb(new Error('ghosts.remove() failed to save to disk', { cause: err })) + else cb() + }) + } + /** * @param {MsgID} tangleID * @returns {Array}