mirror of https://codeberg.org/pzp/pzp-dict.git
add isRoot() and isGhostable()
This commit is contained in:
parent
30365793a7
commit
b08f9baee9
68
lib/index.js
68
lib/index.js
|
@ -21,6 +21,11 @@ const PREFIX = 'record_v1__'
|
|||
* update: Record<string, any>,
|
||||
* supersedes: Array<MsgID>,
|
||||
* }} RecordData
|
||||
* @typedef {{
|
||||
* record?: {
|
||||
* ghostSpan?: number
|
||||
* }
|
||||
* }} Config
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -65,11 +70,13 @@ function assertDBPlugin(peer) {
|
|||
|
||||
/**
|
||||
* @param {{ db: PPPPPDB | null, close: ClosableHook }} peer
|
||||
* @param {any} config
|
||||
* @param {Config} config
|
||||
*/
|
||||
function initRecord(peer, config) {
|
||||
assertDBPlugin(peer)
|
||||
|
||||
const ghostSpan = config.record?.ghostSpan ?? 32
|
||||
|
||||
//#region state
|
||||
let accountID = /** @type {string | null} */ (null)
|
||||
let loadPromise = /** @type {Promise<void> | null} */ (null)
|
||||
|
@ -398,6 +405,63 @@ function initRecord(peer, config) {
|
|||
return record
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {Msg} msg
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isRoot(msg) {
|
||||
return isValidRecordMoot(msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {MsgID} ghostableMsgID
|
||||
* @param {MsgID} tangleID
|
||||
*/
|
||||
function isGhostable(ghostableMsgID, tangleID) {
|
||||
if (ghostableMsgID === tangleID) return false
|
||||
|
||||
assertDBPlugin(peer)
|
||||
const tangle = peer.db.getTangle(tangleID)
|
||||
const msg = peer.db.get(ghostableMsgID)
|
||||
|
||||
// prettier-ignore
|
||||
if (!tangle || tangle.size === 0) throw new Error(`isGhostable() tangleID "${tangleID}" is empty`)
|
||||
// prettier-ignore
|
||||
if (!msg) throw new Error(`isGhostable() msgID "${ghostableMsgID}" does not exist in the database`)
|
||||
// prettier-ignore
|
||||
if (!isValidRecordMoot(tangle.root)) throw new Error(`isGhostable() tangleID "${tangleID}" is not a record`)
|
||||
|
||||
// Discover field roots
|
||||
const fieldRootIDs = new Set()
|
||||
const msgIDs = tangle.topoSort()
|
||||
for (const msgID of msgIDs) {
|
||||
const msg = peer.db.get(msgID)
|
||||
if (!msg?.data) continue
|
||||
for (const supersededMsgID of msg.data.supersedes) {
|
||||
fieldRootIDs.delete(supersededMsgID)
|
||||
}
|
||||
fieldRootIDs.add(msgID)
|
||||
}
|
||||
|
||||
// Get minimum depth of all field roots
|
||||
let minFieldRootDepth = Infinity
|
||||
for (const fieldRootID of fieldRootIDs) {
|
||||
const depth = tangle.getDepth(fieldRootID)
|
||||
if (depth < minFieldRootDepth) minFieldRootDepth = depth
|
||||
// field roots are not ghostables
|
||||
if (fieldRootID === ghostableMsgID) return false
|
||||
// msgs suceeding field roots are not ghostables
|
||||
if (tangle.precedes(fieldRootID, ghostableMsgID)) return false
|
||||
}
|
||||
|
||||
const minGhostDepth = minFieldRootDepth - ghostSpan
|
||||
const ghostableMsgDepth = msg.metadata.tangles[tangleID].depth
|
||||
if (ghostableMsgDepth >= minGhostDepth) return true
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @public
|
||||
* @param {string} subdomain
|
||||
|
@ -453,6 +517,8 @@ function initRecord(peer, config) {
|
|||
load,
|
||||
update,
|
||||
read,
|
||||
isRoot,
|
||||
isGhostable,
|
||||
getFieldRoots,
|
||||
getMinRequiredDepth,
|
||||
squeeze,
|
||||
|
|
|
@ -16,7 +16,11 @@ const aliceKeypair = Keypair.generate('ed25519', 'alice')
|
|||
let peer
|
||||
let aliceID
|
||||
test('setup', async (t) => {
|
||||
peer = createPeer({ keypair: aliceKeypair, path: DIR })
|
||||
peer = createPeer({
|
||||
keypair: aliceKeypair,
|
||||
path: DIR,
|
||||
record: { ghostSpan: 4 },
|
||||
})
|
||||
|
||||
await peer.db.loaded()
|
||||
|
||||
|
@ -130,6 +134,33 @@ test('Record squeeze', async (t) => {
|
|||
assert.deepEqual(fieldRoots6, fieldRoots5, 'fieldRoots')
|
||||
})
|
||||
|
||||
test('Record isRoot', (t) => {
|
||||
const moot = MsgV3.createMoot(aliceID, 'record_v1__profile', aliceKeypair)
|
||||
assert.ok(peer.record.isRoot(moot), 'isRoot')
|
||||
})
|
||||
|
||||
test('Record isGhostable', (t) => {
|
||||
const moot = MsgV3.createMoot(aliceID, 'record_v1__profile', aliceKeypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
||||
const tangle = peer.db.getTangle(mootID)
|
||||
const msgIDs = tangle.topoSort()
|
||||
|
||||
const fieldRoots = peer.record.getFieldRoots('profile')
|
||||
assert.deepEqual(fieldRoots.age, [msgIDs[7]])
|
||||
|
||||
// Remember from the setup, that ghostSpan=4
|
||||
assert.equal(msgIDs.length, 8);
|
||||
assert.equal(peer.record.isGhostable(msgIDs[0], mootID), false) // moot
|
||||
assert.equal(peer.record.isGhostable(msgIDs[1], mootID), false)
|
||||
assert.equal(peer.record.isGhostable(msgIDs[2], mootID), false)
|
||||
assert.equal(peer.record.isGhostable(msgIDs[3], mootID), true) // in ghostSpan
|
||||
assert.equal(peer.record.isGhostable(msgIDs[4], mootID), true) // in ghostSpan
|
||||
assert.equal(peer.record.isGhostable(msgIDs[5], mootID), true) // in ghostSpan
|
||||
assert.equal(peer.record.isGhostable(msgIDs[6], mootID), true) // in ghostSpan
|
||||
assert.equal(peer.record.isGhostable(msgIDs[7], mootID), false) // field root
|
||||
})
|
||||
|
||||
test('Record receives old branched update', async (t) => {
|
||||
const moot = MsgV3.createMoot(aliceID, 'record_v1__profile', aliceKeypair)
|
||||
const mootID = MsgV3.getMsgID(moot)
|
||||
|
|
Loading…
Reference in New Issue