rename identity to account

This commit is contained in:
Andre Staltz 2023-08-08 16:33:36 +03:00
parent 557ea2252c
commit af4325ef94
No known key found for this signature in database
GPG Key ID: 9EDE23EA7E8A4890
27 changed files with 479 additions and 492 deletions

View File

@ -11,8 +11,8 @@ const Obz = require('obz')
const Keypair = require('ppppp-keypair') const Keypair = require('ppppp-keypair')
const MsgV3 = require('./msg-v3') const MsgV3 = require('./msg-v3')
const { const {
SIGNATURE_TAG_IDENTITY_ADD, SIGNATURE_TAG_ACCOUNT_ADD,
IDENTITY_SELF, ACCOUNT_SELF,
} = require('./msg-v3/constants') } = require('./msg-v3/constants')
const { ReadyGate } = require('./utils') const { ReadyGate } = require('./utils')
const { decrypt } = require('./encryption') const { decrypt } = require('./encryption')
@ -22,8 +22,8 @@ const { decrypt } = require('./encryption')
* @typedef {import('ppppp-keypair').KeypairPublicSlice} KeypairPublicSlice * @typedef {import('ppppp-keypair').KeypairPublicSlice} KeypairPublicSlice
* @typedef {import('ppppp-keypair').KeypairPrivateSlice} KeypairPrivateSlice * @typedef {import('ppppp-keypair').KeypairPrivateSlice} KeypairPrivateSlice
* @typedef {import('./msg-v3').Msg} Msg * @typedef {import('./msg-v3').Msg} Msg
* @typedef {import('./msg-v3').IdentityData} IdentityData * @typedef {import('./msg-v3').AccountData} AccountData
* @typedef {import('./msg-v3').IdentityPower} IdentityPower * @typedef {import('./msg-v3').AccountPower} AccountPower
* @typedef {import('./encryption').EncryptionFormat} EncryptionFormat * @typedef {import('./encryption').EncryptionFormat} EncryptionFormat
* *
* @typedef {Buffer | Uint8Array} B4A * @typedef {Buffer | Uint8Array} B4A
@ -281,21 +281,21 @@ function initDB(peer, config) {
// row, because it creates a new Map() each time. Perhaps with QuickLRU // row, because it creates a new Map() each time. Perhaps with QuickLRU
const tangle = new DBTangle(tangleRootHash, records()) const tangle = new DBTangle(tangleRootHash, records())
// Find which pubkeys are authorized to sign this msg given the identity: // Find which pubkeys are authorized to sign this msg given the account:
const pubkeys = new Set() const pubkeys = new Set()
const identity = getIdentityId(rec) const accountID = getAccountID(rec)
let identityTangle = /** @type {DBTangle | null} */ (null) let accountTangle = /** @type {DBTangle | null} */ (null)
if (identity && !MsgV3.isRoot(msg)) { if (accountID && !MsgV3.isRoot(msg)) {
identityTangle = new DBTangle(identity, records()) accountTangle = new DBTangle(accountID, records())
if (!identityTangle.has(identity)) { if (!accountTangle.has(accountID)) {
// prettier-ignore // prettier-ignore
return cb(new Error('add() failed because the identity tangle is unknown')) return cb(new Error('add() failed because the account tangle is unknown'))
} }
// TODO: prune the identityTangle beyond msg.metadata.identityTips // TODO: prune the accountTangle beyond msg.metadata.accountTips
for (const msgHash of identityTangle.topoSort()) { for (const msgHash of accountTangle.topoSort()) {
const msg = get(msgHash) const msg = get(msgHash)
if (!msg?.data) continue if (!msg?.data) continue
/** @type {IdentityData} */ /** @type {AccountData} */
const data = msg.data const data = msg.data
if (data.action !== 'add') continue if (data.action !== 'add') continue
if (data.add.key.purpose !== 'sig') continue if (data.add.key.purpose !== 'sig') continue
@ -309,14 +309,14 @@ function initDB(peer, config) {
return cb(new Error('add() failed msg validation', { cause: err })) return cb(new Error('add() failed msg validation', { cause: err }))
} }
// Identity tangle related validations // Account tangle related validations
if (msg.metadata.identity === IDENTITY_SELF && identityTangle) { if (msg.metadata.account === ACCOUNT_SELF && accountTangle) {
/** @type {IdentityData} */ /** @type {AccountData} */
const data = msg.data const data = msg.data
if (data.action === 'add') { if (data.action === 'add') {
// Does this msg.pubkey have the "add" power? // Does this msg.pubkey have the "add" power?
const keypair = { curve: 'ed25519', public: msg.pubkey } const keypair = { curve: 'ed25519', public: msg.pubkey }
const powers = getIdentityPowers(identityTangle, keypair) const powers = getAccountPowers(accountTangle, keypair)
if (!powers.has('add')) { if (!powers.has('add')) {
// prettier-ignore // prettier-ignore
return cb(new Error('add() failed because this msg.pubkey does not have "add" power')) return cb(new Error('add() failed because this msg.pubkey does not have "add" power'))
@ -333,17 +333,17 @@ function initDB(peer, config) {
} }
/** /**
* @param {{ keypair?: Keypair; identity: string; domain: string; }} opts * @param {{ keypair?: Keypair; account: string; domain: string; }} opts
* @param {CB<string>} cb * @param {CB<string>} cb
*/ */
function initializeFeed(opts, cb) { function initializeFeed(opts, cb) {
const keypair = opts.keypair ?? config.keypair const keypair = opts.keypair ?? config.keypair
const { identity, domain } = opts const { account, domain } = opts
const feedRootHash = getFeedId(identity, domain) const feedRootHash = getFeedId(account, domain)
if (feedRootHash) return cb(null, feedRootHash) if (feedRootHash) return cb(null, feedRootHash)
const feedRoot = MsgV3.createRoot(identity, domain, keypair) const feedRoot = MsgV3.createRoot(account, domain, keypair)
add(feedRoot, MsgV3.getMsgHash(feedRoot), (err, rec) => { add(feedRoot, MsgV3.getMsgHash(feedRoot), (err, rec) => {
// prettier-ignore // prettier-ignore
if (err) return cb(new Error('initializeFeed() failed to add root', { cause: err })); if (err) return cb(new Error('initializeFeed() failed to add root', { cause: err }));
@ -353,27 +353,27 @@ function initDB(peer, config) {
} }
/** /**
* Public the identity ID from the given record. * Public the account ID from the given record.
* *
* @param {Pick<RecPresent, 'msg' | 'hash'>} rec * @param {Pick<RecPresent, 'msg' | 'hash'>} rec
* @returns {string | null} * @returns {string | null}
*/ */
function getIdentityId(rec) { function getAccountID(rec) {
if (!rec.msg) return null if (!rec.msg) return null
if (rec.msg.metadata.identity === IDENTITY_SELF) { if (rec.msg.metadata.account === ACCOUNT_SELF) {
for (const tangleId in rec.msg.metadata.tangles) { for (const tangleId in rec.msg.metadata.tangles) {
return tangleId return tangleId
} }
return rec.hash return rec.hash
} else if (rec.msg.metadata.identity) { } else if (rec.msg.metadata.account) {
return rec.msg.metadata.identity return rec.msg.metadata.account
} else { } else {
return null return null
} }
} }
/** /**
* Find the identity that contains this `keypair` (or the implicit * Find the account that contains this `keypair` (or the implicit
* config.keypair) under the given `domain`. * config.keypair) under the given `domain`.
* *
* @public * @public
@ -383,9 +383,9 @@ function initDB(peer, config) {
* }} opts * }} opts
* @param {CB<string>} cb * @param {CB<string>} cb
*/ */
function findIdentity(opts, cb) { function findAccount(opts, cb) {
// prettier-ignore // prettier-ignore
if (!opts.domain) return cb(new Error('identity.find() requires a `domain`')) if (!opts.domain) return cb(new Error('account.find() requires a `domain`'))
const keypair = opts?.keypair ?? config.keypair const keypair = opts?.keypair ?? config.keypair
const domain = opts.domain const domain = opts.domain
@ -394,43 +394,43 @@ function initDB(peer, config) {
if (!rec) continue if (!rec) continue
if (!rec.msg) continue if (!rec.msg) continue
if (!rec.msg.data) continue if (!rec.msg.data) continue
if (rec.msg.metadata.identity !== IDENTITY_SELF) continue if (rec.msg.metadata.account !== ACCOUNT_SELF) continue
if (rec.msg.metadata.domain !== domain) continue if (rec.msg.metadata.domain !== domain) continue
const data = /** @type {IdentityData} */ (rec.msg.data) const data = /** @type {AccountData} */ (rec.msg.data)
if (data.action === 'add' && data.add.key.bytes === keypair.public) { if (data.action === 'add' && data.add.key.bytes === keypair.public) {
const identityId = getIdentityId(rec) const accountId = getAccountID(rec)
if (identityId) { if (accountId) {
cb(null, identityId) cb(null, accountId)
} else { } else {
// prettier-ignore // prettier-ignore
cb(new Error(`identity.find() failed to find ID in ${JSON.stringify(rec.msg)}`)) cb(new Error(`account.find() failed to find ID in ${JSON.stringify(rec.msg)}`))
} }
return return
} }
} }
// prettier-ignore // prettier-ignore
const err = new Error(`identity.find() failed for pubkey=${keypair.public} domain=${domain}`, { cause: 'ENOENT' }); const err = new Error(`account.find() failed for pubkey=${keypair.public} domain=${domain}`, { cause: 'ENOENT' });
cb(err) cb(err)
} }
/** /**
* Does this `identity` have this `keypair` (or the implicit config.keypair)? * Does this `account` have this `keypair` (or the implicit config.keypair)?
* *
* @public * @public
* @param {{ * @param {{
* keypair?: KeypairPublicSlice; * keypair?: KeypairPublicSlice;
* identity: string; * account: string;
* }} opts * }} opts
* @returns {boolean} * @returns {boolean}
*/ */
function identityHas(opts) { function accountHas(opts) {
const keypair = opts?.keypair ?? config.keypair const keypair = opts?.keypair ?? config.keypair
const identityTangle = new DBTangle(opts.identity, records()) const accountTangle = new DBTangle(opts.account, records())
for (const msgHash of identityTangle.topoSort()) { for (const msgHash of accountTangle.topoSort()) {
const msg = get(msgHash) const msg = get(msgHash)
if (!msg?.data) continue if (!msg?.data) continue
/** @type {IdentityData} */ /** @type {AccountData} */
const data = msg.data const data = msg.data
if (data.action !== 'add') continue if (data.action !== 'add') continue
if (data.add.key.algorithm !== keypair.curve) continue if (data.add.key.algorithm !== keypair.curve) continue
@ -442,7 +442,7 @@ function initDB(peer, config) {
} }
/** /**
* Create an identity (root msg) for the given `keypair` (or the implicit * Create an account (root msg) for the given `keypair` (or the implicit
* config.keypair) under this `domain`. * config.keypair) under this `domain`.
* *
* @public * @public
@ -453,23 +453,23 @@ function initDB(peer, config) {
* }} opts * }} opts
* @param {CB<string>} cb * @param {CB<string>} cb
*/ */
function createIdentity(opts, cb) { function createAccount(opts, cb) {
// prettier-ignore // prettier-ignore
if (!opts.domain) return cb(new Error('identity.create() requires a `domain`')) if (!opts.domain) return cb(new Error('account.create() requires a `domain`'))
const keypair = opts?.keypair ?? config.keypair const keypair = opts?.keypair ?? config.keypair
const domain = opts.domain const domain = opts.domain
let msg let msg
try { try {
msg = MsgV3.createIdentity(keypair, domain, opts?._nonce) msg = MsgV3.createAccount(keypair, domain, opts?._nonce)
} catch (err) { } catch (err) {
return cb(new Error('identity.create() failed', { cause: err })) return cb(new Error('account.create() failed', { cause: err }))
} }
const msgHash = MsgV3.getMsgHash(msg) const msgHash = MsgV3.getMsgHash(msg)
logAppend(msgHash, msg, (err, rec) => { logAppend(msgHash, msg, (err, rec) => {
// prettier-ignore // prettier-ignore
if (err) return cb(new Error('identity.create() failed in the log', { cause: err })) if (err) return cb(new Error('account.create() failed in the log', { cause: err }))
onRecordAdded.set(rec) onRecordAdded.set(rec)
const recHash = /** @type {string} */ (rec.hash) const recHash = /** @type {string} */ (rec.hash)
cb(null, recHash) cb(null, recHash)
@ -477,7 +477,7 @@ function initDB(peer, config) {
} }
/** /**
* Find or create an identity (root msg) for the given `keypair` (or the * Find or create an account (root msg) for the given `keypair` (or the
* implicit config.keypair) under this `domain`. * implicit config.keypair) under this `domain`.
* *
* @public * @public
@ -488,29 +488,29 @@ function initDB(peer, config) {
* }} opts * }} opts
* @param {CB<string>} cb * @param {CB<string>} cb
*/ */
function findOrCreateIdentity(opts, cb) { function findOrCreateAccount(opts, cb) {
findIdentity(opts, (err, identityId) => { findAccount(opts, (err, accountID) => {
if (err?.cause === 'ENOENT') { if (err?.cause === 'ENOENT') {
createIdentity(opts, cb) createAccount(opts, cb)
} else if (err) { } else if (err) {
cb(err) cb(err)
} else { } else {
cb(null, identityId) cb(null, accountID)
} }
}) })
} }
/** /**
* @param {DBTangle} identityTangle * @param {DBTangle} accountTangle
* @param {KeypairPublicSlice} keypair * @param {KeypairPublicSlice} keypair
* @returns {Set<IdentityPower>} * @returns {Set<AccountPower>}
*/ */
function getIdentityPowers(identityTangle, keypair) { function getAccountPowers(accountTangle, keypair) {
const powers = new Set() const powers = new Set()
for (const msgHash of identityTangle.topoSort()) { for (const msgHash of accountTangle.topoSort()) {
const msg = get(msgHash) const msg = get(msgHash)
if (!msg?.data) continue if (!msg?.data) continue
/** @type {IdentityData} */ /** @type {AccountData} */
const data = msg.data const data = msg.data
if (data.action !== 'add') continue if (data.action !== 'add') continue
if (data.add.key.algorithm !== keypair.curve) continue if (data.add.key.algorithm !== keypair.curve) continue
@ -526,22 +526,22 @@ function initDB(peer, config) {
/** /**
* Create a consent signature for the given `keypair` (or the implicit * Create a consent signature for the given `keypair` (or the implicit
* config.keypair) to be added to the given `identity`. * config.keypair) to be added to the given `account`.
* *
* @public * @public
* @param {{ * @param {{
* keypair?: KeypairPrivateSlice; * keypair?: KeypairPrivateSlice;
* identity: string; * account: string;
* }} opts * }} opts
* @returns {string} * @returns {string}
*/ */
function consentToIdentity(opts) { function consentToAccount(opts) {
// prettier-ignore // prettier-ignore
if (!opts.identity) throw new Error('identity.consent() requires an `identity`') if (!opts.account) throw new Error('account.consent() requires an `account`')
const keypair = opts?.keypair ?? config.keypair const keypair = opts?.keypair ?? config.keypair
const signableBuf = b4a.from( const signableBuf = b4a.from(
SIGNATURE_TAG_IDENTITY_ADD + base58.decode(opts.identity), SIGNATURE_TAG_ACCOUNT_ADD + base58.decode(opts.account),
'utf8' 'utf8'
) )
return Keypair.sign(keypair, signableBuf) return Keypair.sign(keypair, signableBuf)
@ -549,13 +549,13 @@ function initDB(peer, config) {
/** /**
* Add the given `keypair` (or the implicit config.keypair) to the given * Add the given `keypair` (or the implicit config.keypair) to the given
* `identity`, authorized by the given `consent` (or implicitly created on the * `account`, authorized by the given `consent` (or implicitly created on the
* fly if the `keypair` contains the private key) with the following `powers` * fly if the `keypair` contains the private key) with the following `powers`
* (defaulting to no powers). * (defaulting to no powers).
* *
* @param {{ * @param {{
* identity: string; * account: string;
* powers?: Array<IdentityPower>; * powers?: Array<AccountPower>;
* _disobey?: true; * _disobey?: true;
* } & ({ * } & ({
* keypair: KeypairPublicSlice & {private?: never}; * keypair: KeypairPublicSlice & {private?: never};
@ -566,20 +566,20 @@ function initDB(peer, config) {
* })} opts * })} opts
* @param {CB<Rec>} cb * @param {CB<Rec>} cb
*/ */
function addToIdentity(opts, cb) { function addToAccount(opts, cb) {
if (!opts) return cb(new Error('identity.add() requires an `opts`')) if (!opts) return cb(new Error('account.add() requires an `opts`'))
// prettier-ignore // prettier-ignore
if (!opts.identity) return cb(new Error('identity.add() requires a `identity`')) if (!opts.account) return cb(new Error('account.add() requires a `account`'))
// prettier-ignore // prettier-ignore
if (!opts.keypair) return cb(new Error('identity.add() requires a `keypair`')) if (!opts.keypair) return cb(new Error('account.add() requires a `keypair`'))
// prettier-ignore // prettier-ignore
if (!opts.keypair.public) return cb(new Error('identity.add() requires a `keypair` with `public`')) if (!opts.keypair.public) return cb(new Error('account.add() requires a `keypair` with `public`'))
let consent = /** @type {string} */ (opts.consent) let consent = /** @type {string} */ (opts.consent)
if (typeof opts.consent === 'undefined') { if (typeof opts.consent === 'undefined') {
if (opts.keypair.private) { if (opts.keypair.private) {
consent = consentToIdentity(opts) consent = consentToAccount(opts)
} else { } else {
return cb(new Error('identity.add() requires a `consent`')) return cb(new Error('account.add() requires a `consent`'))
} }
} }
const obeying = !opts._disobey const obeying = !opts._disobey
@ -588,20 +588,20 @@ function initDB(peer, config) {
// Verify consent: // Verify consent:
const signableBuf = b4a.from( const signableBuf = b4a.from(
SIGNATURE_TAG_IDENTITY_ADD + base58.decode(opts.identity) SIGNATURE_TAG_ACCOUNT_ADD + base58.decode(opts.account)
) )
if (obeying && !Keypair.verify(addedKeypair, signableBuf, consent)) { if (obeying && !Keypair.verify(addedKeypair, signableBuf, consent)) {
// prettier-ignore // prettier-ignore
return cb(new Error('identity.add() failed because the consent is invalid')) return cb(new Error('account.add() failed because the consent is invalid'))
} }
// Verify powers of the signingKeypair: // Verify powers of the signingKeypair:
const identityTangle = new DBTangle(opts.identity, records()) const accountTangle = new DBTangle(opts.account, records())
if (obeying) { if (obeying) {
const signingPowers = getIdentityPowers(identityTangle, signingKeypair) const signingPowers = getAccountPowers(accountTangle, signingKeypair)
if (!signingPowers.has('add')) { if (!signingPowers.has('add')) {
// prettier-ignore // prettier-ignore
return cb(new Error('identity.add() failed because the signing keypair does not have the "add" power')) return cb(new Error('account.add() failed because the signing keypair does not have the "add" power'))
} }
} }
@ -609,24 +609,24 @@ function initDB(peer, config) {
if (obeying && opts.powers) { if (obeying && opts.powers) {
if (!Array.isArray(opts.powers)) { if (!Array.isArray(opts.powers)) {
// prettier-ignore // prettier-ignore
return cb(new Error('identity.add() failed because opts.powers is not an array')) return cb(new Error('account.add() failed because opts.powers is not an array'))
} }
for (const power of opts.powers) { for (const power of opts.powers) {
if (power !== 'add' && power !== 'del' && power !== 'box') { if (power !== 'add' && power !== 'del' && power !== 'box') {
// prettier-ignore // prettier-ignore
return cb(new Error(`identity.add() failed because opts.powers contains an unknown power "${power}"`)) return cb(new Error(`account.add() failed because opts.powers contains an unknown power "${power}"`))
} }
// TODO check against duplicates // TODO check against duplicates
} }
} }
const identityRoot = get(opts.identity) const accountRoot = get(opts.account)
if (!identityRoot) { if (!accountRoot) {
// prettier-ignore // prettier-ignore
return cb(new Error(`identity.add() failed because the identity root "${opts.identity}" is unknown`)) return cb(new Error(`account.add() failed because the account root "${opts.account}" is unknown`))
} }
/** @type {IdentityData} */ /** @type {AccountData} */
const data = { const data = {
action: 'add', action: 'add',
add: { add: {
@ -642,14 +642,14 @@ function initDB(peer, config) {
// Fill-in tangle opts: // Fill-in tangle opts:
const fullOpts = { const fullOpts = {
identity: IDENTITY_SELF, account: ACCOUNT_SELF,
identityTips: null, accountTips: null,
tangles: { tangles: {
[opts.identity]: identityTangle, [opts.account]: accountTangle,
}, },
keypair: signingKeypair, keypair: signingKeypair,
data, data,
domain: identityRoot.metadata.domain, domain: accountRoot.metadata.domain,
} }
// Create the actual message: // Create the actual message:
@ -657,13 +657,13 @@ function initDB(peer, config) {
try { try {
msg = MsgV3.create(fullOpts) msg = MsgV3.create(fullOpts)
} catch (err) { } catch (err) {
return cb(new Error('identity.add() failed', { cause: err })) return cb(new Error('account.add() failed', { cause: err }))
} }
const msgHash = MsgV3.getMsgHash(msg) const msgHash = MsgV3.getMsgHash(msg)
logAppend(msgHash, msg, (err, rec) => { logAppend(msgHash, msg, (err, rec) => {
// prettier-ignore // prettier-ignore
if (err) return cb(new Error('identity.add() failed to append the log', { cause: err })) if (err) return cb(new Error('account.add() failed to append the log', { cause: err }))
onRecordAdded.set(rec) onRecordAdded.set(rec)
cb(null, rec) cb(null, rec)
}) })
@ -675,7 +675,7 @@ function initDB(peer, config) {
* encryptionFormat?: string; * encryptionFormat?: string;
* data: any; * data: any;
* domain: string; * domain: string;
* identity: string; * account: string;
* tangles?: Array<string>; * tangles?: Array<string>;
* }} opts * }} opts
* @param {CB<Rec>} cb * @param {CB<Rec>} cb
@ -692,8 +692,8 @@ function initDB(peer, config) {
} }
if (!opts.data) return cb(new Error('feed.publish() requires a `data`')) if (!opts.data) return cb(new Error('feed.publish() requires a `data`'))
if (!opts.domain) return cb(new Error('feed.publish() requires a `domain`')) if (!opts.domain) return cb(new Error('feed.publish() requires a `domain`'))
if (!opts.identity) if (!opts.account)
return cb(new Error('feed.publish() requires a `identity`')) return cb(new Error('feed.publish() requires a `account`'))
initializeFeed(opts, (err, feedRootHash) => { initializeFeed(opts, (err, feedRootHash) => {
// prettier-ignore // prettier-ignore
@ -703,9 +703,9 @@ function initDB(peer, config) {
const tangleTemplates = opts.tangles ?? [] const tangleTemplates = opts.tangles ?? []
tangleTemplates.push(feedRootHash) tangleTemplates.push(feedRootHash)
const tangles = populateTangles(tangleTemplates) const tangles = populateTangles(tangleTemplates)
const identityTangle = new DBTangle(opts.identity, records()) const accountTangle = new DBTangle(opts.account, records())
const identityTips = [...identityTangle.getTips()] const accountTips = [...accountTangle.getTips()]
const fullOpts = { ...opts, tangles, identityTips, keypair } const fullOpts = { ...opts, tangles, accountTips, keypair }
// If opts ask for encryption, encrypt and put ciphertext in opts.data // If opts ask for encryption, encrypt and put ciphertext in opts.data
const recps = fullOpts.data.recps const recps = fullOpts.data.recps
@ -763,9 +763,9 @@ function initDB(peer, config) {
* @param {string} findDomain * @param {string} findDomain
*/ */
function getFeedId(id, findDomain) { function getFeedId(id, findDomain) {
const findIdentity = MsgV3.stripIdentity(id) const findAccount = MsgV3.stripAccount(id)
for (const rec of records()) { for (const rec of records()) {
if (rec.msg && MsgV3.isFeedRoot(rec.msg, findIdentity, findDomain)) { if (rec.msg && MsgV3.isFeedRoot(rec.msg, findAccount, findDomain)) {
return rec.hash return rec.hash
} }
} }
@ -851,13 +851,13 @@ function initDB(peer, config) {
installEncryptionFormat, installEncryptionFormat,
loaded, loaded,
add, add,
identity: { account: {
find: findIdentity, find: findAccount,
create: createIdentity, create: createAccount,
findOrCreate: findOrCreateIdentity, findOrCreate: findOrCreateAccount,
add: addToIdentity, add: addToAccount,
consent: consentToIdentity, consent: consentToAccount,
has: identityHas, has: accountHas,
}, },
feed: { feed: {
publish: publishToFeed, publish: publishToFeed,

View File

@ -1,10 +1,10 @@
module.exports = { module.exports = {
/** @type {'self'} */ /** @type {'self'} */
IDENTITY_SELF: 'self', ACCOUNT_SELF: 'self',
/** @type {'any'} */ /** @type {'any'} */
IDENTITY_ANY: 'any', ACCOUNT_ANY: 'any',
SIGNATURE_TAG_MSG_V3: ':msg-v3:', SIGNATURE_TAG_MSG_V3: ':msg-v3:',
SIGNATURE_TAG_IDENTITY_ADD: ':identity-add:', SIGNATURE_TAG_ACCOUNT_ADD: ':account-add:',
} }

View File

@ -45,12 +45,12 @@ function getMsgHash(x) {
* @returns {string} * @returns {string}
*/ */
function getMsgId(msg) { function getMsgId(msg) {
const { identity, domain } = msg.metadata const { account, domain } = msg.metadata
const msgHash = getMsgHash(msg) const msgHash = getMsgHash(msg)
if (domain) { if (domain) {
return `ppppp:message/v3/${identity}/${domain}/${msgHash}` return `ppppp:message/v3/${account}/${domain}/${msgHash}`
} else { } else {
return `ppppp:message/v3/${identity}/${msgHash}` return `ppppp:message/v3/${account}/${msgHash}`
} }
} }

View File

@ -6,7 +6,7 @@ const stringify = require('json-canon')
const Keypair = require('ppppp-keypair') const Keypair = require('ppppp-keypair')
// @ts-ignore // @ts-ignore
const union = require('set.prototype.union') const union = require('set.prototype.union')
const { stripIdentity } = require('./strip') const { stripAccount } = require('./strip')
const isFeedRoot = require('./is-feed-root') const isFeedRoot = require('./is-feed-root')
const { getMsgId, getMsgHash } = require('./get-msg-id') const { getMsgId, getMsgHash } = require('./get-msg-id')
const representData = require('./represent-data') const representData = require('./represent-data')
@ -18,8 +18,8 @@ const {
} = require('./validation') } = require('./validation')
const Tangle = require('./tangle') const Tangle = require('./tangle')
const { const {
IDENTITY_SELF, ACCOUNT_SELF,
IDENTITY_ANY, ACCOUNT_ANY,
SIGNATURE_TAG_MSG_V3, SIGNATURE_TAG_MSG_V3,
} = require('./constants') } = require('./constants')
const { isEmptyObject } = require('./util') const { isEmptyObject } = require('./util')
@ -43,8 +43,8 @@ const { isEmptyObject } = require('./util')
* metadata: { * metadata: {
* dataHash: string | null; * dataHash: string | null;
* dataSize: number; * dataSize: number;
* identity: string | (typeof IDENTITY_SELF) | (typeof IDENTITY_ANY); * account: string | (typeof ACCOUNT_SELF) | (typeof ACCOUNT_ANY);
* identityTips: Array<string> | null; * accountTips: Array<string> | null;
* tangles: Record<string, TangleMetadata>; * tangles: Record<string, TangleMetadata>;
* domain: string; * domain: string;
* v: 3; * v: 3;
@ -54,23 +54,12 @@ const { isEmptyObject } = require('./util')
* }} Msg * }} Msg
* *
* @typedef {{ * @typedef {{
* action: 'add', add: IdentityAdd * action: 'add', add: AccountAdd
* } | { * } | {
* action: 'del', del: IdentityDel * action: 'del', del: AccountDel
* }} IdentityData * }} AccountData
* *
* @typedef {'add' | 'del' | 'box'} IdentityPower * @typedef {'add' | 'del' | 'box'} AccountPower
*
* @typedef {{
* key: IdentityKey;
* nonce?: string;
* consent?: string;
* powers?: Array<IdentityPower>;
* }} IdentityAdd
*
* @typedef {{
* key: IdentityKey;
* }} IdentityDel
* *
* @typedef {{ * @typedef {{
* purpose: 'sig'; * purpose: 'sig';
@ -84,14 +73,25 @@ const { isEmptyObject } = require('./util')
* bytes: string; * bytes: string;
* }} BoxKey; * }} BoxKey;
* *
* @typedef {SigKey | BoxKey} IdentityKey * @typedef {SigKey | BoxKey} AccountKey
*
* @typedef {{
* key: AccountKey;
* nonce?: string;
* consent?: string;
* powers?: Array<AccountPower>;
* }} AccountAdd
*
* @typedef {{
* key: AccountKey;
* }} AccountDel
* *
* @typedef {{ * @typedef {{
* data: any; * data: any;
* domain: string; * domain: string;
* keypair: Keypair; * keypair: Keypair;
* identity: string | (typeof IDENTITY_SELF) | (typeof IDENTITY_ANY); * account: string | (typeof ACCOUNT_SELF) | (typeof ACCOUNT_ANY);
* identityTips: Array<string> | null; * accountTips: Array<string> | null;
* tangles: Record<string, Tangle>; * tangles: Record<string, Tangle>;
* }} CreateOpts * }} CreateOpts
*/ */
@ -108,8 +108,8 @@ function getFeedRootHash(id, domain) {
metadata: { metadata: {
dataHash: null, dataHash: null,
dataSize: 0, dataSize: 0,
identity: stripIdentity(id), account: stripAccount(id),
identityTips: null, accountTips: null,
tangles: {}, tangles: {},
domain, domain,
v: 3, v: 3,
@ -139,8 +139,8 @@ function create(opts) {
if (!opts.tangles) throw new Error('opts.tangles is required') if (!opts.tangles) throw new Error('opts.tangles is required')
const [dataHash, dataSize] = representData(opts.data) const [dataHash, dataSize] = representData(opts.data)
const identity = opts.identity const account = opts.account
const identityTips = opts.identityTips ? opts.identityTips.sort() : null const accountTips = opts.accountTips ? opts.accountTips.sort() : null
const tangles = /** @type {Msg['metadata']['tangles']} */ ({}) const tangles = /** @type {Msg['metadata']['tangles']} */ ({})
if (opts.tangles) { if (opts.tangles) {
@ -164,8 +164,8 @@ function create(opts) {
metadata: { metadata: {
dataHash, dataHash,
dataSize, dataSize,
identity, account,
identityTips, accountTips,
tangles, tangles,
domain: opts.domain, domain: opts.domain,
v: 3, v: 3,
@ -200,8 +200,8 @@ function createRoot(id, domain, keypair) {
metadata: { metadata: {
dataHash: null, dataHash: null,
dataSize: 0, dataSize: 0,
identity: id, account: id,
identityTips: null, accountTips: null,
tangles: {}, tangles: {},
domain, domain,
v: 3, v: 3,
@ -229,8 +229,8 @@ function getRandomNonce() {
* @param {string | (() => string)} nonce * @param {string | (() => string)} nonce
* @returns {Msg} * @returns {Msg}
*/ */
function createIdentity(keypair, domain, nonce = getRandomNonce) { function createAccount(keypair, domain, nonce = getRandomNonce) {
/** @type {IdentityData} */ /** @type {AccountData} */
const data = { const data = {
action: 'add', action: 'add',
add: { add: {
@ -246,8 +246,8 @@ function createIdentity(keypair, domain, nonce = getRandomNonce) {
return create({ return create({
data, data,
identity: IDENTITY_SELF, account: ACCOUNT_SELF,
identityTips: null, accountTips: null,
keypair, keypair,
tangles: {}, tangles: {},
domain, domain,
@ -285,9 +285,9 @@ module.exports = {
getFeedRootHash, getFeedRootHash,
create, create,
createRoot, createRoot,
createIdentity, createAccount,
erase, erase,
stripIdentity, stripAccount,
toPlaintextBuffer, toPlaintextBuffer,
fromPlaintextBuffer, fromPlaintextBuffer,
isRoot, isRoot,

View File

@ -1,4 +1,4 @@
const { stripIdentity } = require('./strip') const { stripAccount } = require('./strip')
const { isEmptyObject } = require('./util') const { isEmptyObject } = require('./util')
/** /**
@ -11,13 +11,13 @@ const { isEmptyObject } = require('./util')
* @param {string | 0} findDomain * @param {string | 0} findDomain
*/ */
function isFeedRoot(msg, id = 0, findDomain = 0) { function isFeedRoot(msg, id = 0, findDomain = 0) {
const { dataHash, dataSize, identity, identityTips, tangles, domain } = const { dataHash, dataSize, account, accountTips, tangles, domain } =
msg.metadata msg.metadata
if (dataHash !== null) return false if (dataHash !== null) return false
if (dataSize !== 0) return false if (dataSize !== 0) return false
if (id === 0 && !identity) return false if (id === 0 && !account) return false
if (id !== 0 && identity !== stripIdentity(id)) return false if (id !== 0 && account !== stripAccount(id)) return false
if (identityTips !== null) return false if (accountTips !== null) return false
if (!isEmptyObject(tangles)) return false if (!isEmptyObject(tangles)) return false
if (findDomain !== 0 && domain !== findDomain) return false if (findDomain !== 0 && domain !== findDomain) return false
return true return true

View File

@ -24,13 +24,13 @@ function stripMsgKey(msgKey) {
* @param {string} id * @param {string} id
* @returns {string} * @returns {string}
*/ */
function stripIdentity(id) { function stripAccount(id) {
if (id.startsWith('ppppp:identity/v3/') === false) return id if (id.startsWith('ppppp:account/v3/') === false) return id
const withoutPrefix = id.replace('ppppp:identity/v3/', '') const withoutPrefix = id.replace('ppppp:account/v3/', '')
return withoutPrefix.split('/')[0] return withoutPrefix.split('/')[0]
} }
module.exports = { module.exports = {
stripMsgKey, stripMsgKey,
stripIdentity, stripAccount,
} }

View File

@ -195,7 +195,7 @@ class Tangle {
const metadata = this.#rootMsg.metadata const metadata = this.#rootMsg.metadata
if (metadata.dataSize > 0) return false if (metadata.dataSize > 0) return false
if (metadata.dataHash !== null) return false if (metadata.dataHash !== null) return false
if (metadata.identityTips !== null) return false if (metadata.accountTips !== null) return false
return true return true
} }
@ -205,8 +205,8 @@ class Tangle {
console.trace('Tangle is missing root message') console.trace('Tangle is missing root message')
return null return null
} }
const { identity, domain } = this.#rootMsg.metadata const { account, domain } = this.#rootMsg.metadata
return { identity, domain } return { account, domain }
} }
/** /**

View File

@ -6,7 +6,7 @@ const stringify = require('json-canon')
const Tangle = require('./tangle') const Tangle = require('./tangle')
const representData = require('./represent-data') const representData = require('./represent-data')
const isFeedRoot = require('./is-feed-root') const isFeedRoot = require('./is-feed-root')
const { SIGNATURE_TAG_MSG_V3, IDENTITY_SELF } = require('./constants') const { SIGNATURE_TAG_MSG_V3, ACCOUNT_SELF } = require('./constants')
/** /**
* @typedef {import('.').Msg} Msg * @typedef {import('.').Msg} Msg
@ -34,14 +34,14 @@ function validateShape(msg) {
// prettier-ignore // prettier-ignore
return 'invalid message: must have metadata.dataSize\n' + JSON.stringify(msg) return 'invalid message: must have metadata.dataSize\n' + JSON.stringify(msg)
} }
if (!('identity' in msg.metadata)) { if (!('account' in msg.metadata)) {
return ( return (
'invalid message: must have metadata.identity\n' + JSON.stringify(msg) 'invalid message: must have metadata.account\n' + JSON.stringify(msg)
) )
} }
if (!('identityTips' in msg.metadata)) { if (!('accountTips' in msg.metadata)) {
// prettier-ignore // prettier-ignore
return 'invalid message: must have metadata.identityTips\n' + JSON.stringify(msg) return 'invalid message: must have metadata.accountTips\n' + JSON.stringify(msg)
} }
if (!('tangles' in msg.metadata)) { if (!('tangles' in msg.metadata)) {
return 'invalid message: must have metadata.tangles\n' + JSON.stringify(msg) return 'invalid message: must have metadata.tangles\n' + JSON.stringify(msg)
@ -85,17 +85,17 @@ function validatePubkey(msg) {
* @param {Set<string>} pubkeys * @param {Set<string>} pubkeys
* @returns {string | undefined} * @returns {string | undefined}
*/ */
function validateIdentityPubkey(msg, pubkeys) { function validateAccountPubkey(msg, pubkeys) {
// Unusual case: if the msg is a feed root, ignore the identity and pubkey // Unusual case: if the msg is a feed root, ignore the account and pubkey
if (isFeedRoot(msg)) return if (isFeedRoot(msg)) return
if ( if (
msg.metadata.identity && msg.metadata.account &&
msg.metadata.identity !== IDENTITY_SELF && msg.metadata.account !== ACCOUNT_SELF &&
!pubkeys.has(msg.pubkey) !pubkeys.has(msg.pubkey)
) { ) {
// prettier-ignore // prettier-ignore
return `invalid message: pubkey "${msg.pubkey}" should have been one of "${[...pubkeys]}" from the identity "${msg.metadata.identity}"\n` + JSON.stringify(msg) return `invalid message: pubkey "${msg.pubkey}" should have been one of "${[...pubkeys]}" from the account "${msg.metadata.account}"\n` + JSON.stringify(msg)
} }
} }
@ -187,14 +187,14 @@ function validateTangle(msg, tangle, tangleId) {
return `invalid message: depth "${depth}" should have been a positive integer\n` + JSON.stringify(msg) return `invalid message: depth "${depth}" should have been a positive integer\n` + JSON.stringify(msg)
} }
if (tangle.isFeed()) { if (tangle.isFeed()) {
const { identity, domain } = /** @type {FeedDetails} */ (tangle.getFeed()) const { account, domain } = /** @type {FeedDetails} */ (tangle.getFeed())
if (domain !== msg.metadata.domain) { if (domain !== msg.metadata.domain) {
// prettier-ignore // prettier-ignore
return `invalid message: domain "${msg.metadata.domain}" should have been feed domain "${domain}"\n` + JSON.stringify(msg) return `invalid message: domain "${msg.metadata.domain}" should have been feed domain "${domain}"\n` + JSON.stringify(msg)
} }
if (identity !== msg.metadata.identity) { if (account !== msg.metadata.account) {
// prettier-ignore // prettier-ignore
return `invalid message: identity "${msg.metadata.identity}" should have been feed identity "${identity}"\n` + JSON.stringify(msg) return `invalid message: account "${msg.metadata.account}" should have been feed account "${account}"\n` + JSON.stringify(msg)
} }
} }
let lastPrev = null let lastPrev = null
@ -329,7 +329,7 @@ function validate(msg, tangle, pubkeys, msgHash, rootHash) {
if ((err = validateDataSize(msg))) return err if ((err = validateDataSize(msg))) return err
if ((err = validateData(msg))) return err if ((err = validateData(msg))) return err
if ((err = validateDomain(msg.metadata.domain))) return err if ((err = validateDomain(msg.metadata.domain))) return err
if ((err = validateIdentityPubkey(msg, pubkeys))) return err if ((err = validateAccountPubkey(msg, pubkeys))) return err
if (tangle.size() === 0) { if (tangle.size() === 0) {
if ((err = validateTangleRoot(msg, msgHash, rootHash))) return err if ((err = validateTangleRoot(msg, msgHash, rootHash))) return err
} else { } else {

View File

@ -10,9 +10,9 @@ Background: https://github.com/ssbc/ssb2-discussion-forum/issues/24
- **Tangle Root** = the origin msg of a tangle - **Tangle Root** = the origin msg of a tangle
- **Tangle Tips** = tangle msgs that are not yet referenced by any other msg in the tangle - **Tangle Tips** = tangle msgs that are not yet referenced by any other msg in the tangle
- **Tangle ID** = Msg hash of the tangle's root msg - **Tangle ID** = Msg hash of the tangle's root msg
- **Identity tangle** = tangle with msgs that add (or remove?) asymmetric-crypto public keys - **Account tangle** = tangle with msgs that add (or remove?) asymmetric-crypto public keys
- **ID** = tangle ID of the identity tangle, refers to the "identity" of a person or a group - **Account ID** = tangle ID of the account tangle
- **Feed** = tangle with msgs authored by (any pubkey in) an identity - **Feed** = tangle with msgs authored by (any pubkey in) an account
- **Feed root** = a msg that is deterministically predictable and empty, so to allow others to pre-know its hash - **Feed root** = a msg that is deterministically predictable and empty, so to allow others to pre-know its hash
- **Feed ID** = ID of a feed (Msg ID of the feed's root msg) - **Feed ID** = ID of a feed (Msg ID of the feed's root msg)
@ -24,8 +24,8 @@ interface Msg {
metadata: { metadata: {
dataHash: ContentHash | null // blake3 hash of the `content` object serialized dataHash: ContentHash | null // blake3 hash of the `content` object serialized
dataSize: number // byte size (unsigned integer) of the `content` object serialized dataSize: number // byte size (unsigned integer) of the `content` object serialized
identity: string | 'self' | 'any' // blake3 hash of an identity tangle root msg, or the string 'self', or 'any' account: string | 'self' | 'any' // blake3 hash of an account tangle root msg, or the string 'self', or 'any'
identityTips: Array<string> | null // list of blake3 hashes of identity tangle tips, or null accountTips: Array<string> | null // list of blake3 hashes of account tangle tips, or null
tangles: { tangles: {
// for each tangle this msg belongs to, identified by the tangle's root // for each tangle this msg belongs to, identified by the tangle's root
[rootMsgHash: string]: { [rootMsgHash: string]: {
@ -41,20 +41,20 @@ interface Msg {
} }
``` ```
## Identity tangle msgs ## Account tangle msgs
Msgs in an identity tangle are special because they have empty `identity` and `identityTips` fields. Msgs in an account tangle are special because they have empty `account` and `accountTips` fields.
```typescript ```typescript
interface Msg { interface Msg {
data: IdentityData data: AccountData
metadata: { metadata: {
dataHash: ContentHash dataHash: ContentHash
dataSize: number dataSize: number
identity: 'self' // MUST be the string 'self' account: 'self' // MUST be the string 'self'
identityTips: null // MUST be null accountTips: null // MUST be null
tangles: { tangles: {
[identityTangleId: string]: { [accountTangleId: string]: {
depth: number // maximum distance (positive integer) from this msg to the root depth: number // maximum distance (positive integer) from this msg to the root
prev: Array<MsgHash> // list of msg hashes of existing msgs, unique set and ordered alphabetically prev: Array<MsgHash> // list of msg hashes of existing msgs, unique set and ordered alphabetically
} }
@ -66,23 +66,23 @@ interface Msg {
sig: Signature sig: Signature
} }
type IdentityData = type AccountData =
| { action: 'add', add: IdentityAdd } | { action: 'add', add: AccountAdd }
| { action: 'del', del: IdentityDel } | { action: 'del', del: AccountDel }
// "add" means this keypair can validly add more keypairs to the identity tangle // "add" means this keypair can validly add more keypairs to the account tangle
// "del" means this keypair can validly revoke other keypairs from the identity // "del" means this keypair can validly revoke other keypairs from the account
// "box" means the peer with this keypair should get access to the box keypair // "box" means the peer with this keypair should get access to the box keypair
type IdentityPower = 'add' | 'del' | 'box' type AccountPower = 'add' | 'del' | 'box'
type IdentityAdd = { type AccountAdd = {
key: Key key: Key
nonce?: string // nonce required only on the identity tangle's root nonce?: string // nonce required only on the account tangle's root
consent?: string // base58 encoded signature of the string `:identity-add:<ID>` where `<ID>` is the identity's ID, required only on non-root msgs consent?: string // base58 encoded signature of the string `:account-add:<ID>` where `<ID>` is the account's ID, required only on non-root msgs
identityPowers?: Array<IdentityPower> // list of powers granted to this key, defaults to [] accountPowers?: Array<AccountPower> // list of powers granted to this key, defaults to []
} }
type IdentityDel = { type AccountDel = {
key: Key key: Key
} }
@ -99,7 +99,7 @@ type Key =
} }
``` ```
Examples of `IdentityData`: Examples of `AccountData`:
- Registering the first signing pubkey: - Registering the first signing pubkey:
```json ```json
@ -115,19 +115,6 @@ Examples of `IdentityData`:
} }
} }
``` ```
- Registering a subidentity:
```json
{
"action": "add",
"add": {
"key": {
"purpose": "subidentity",
"algorithm": "tangle",
"bytes": "6yqq7iwyJEKdofJ3xpRLEq"
}
}
}
```
- Revoking a signing pubkey: - Revoking a signing pubkey:
```json ```json
{ {
@ -152,8 +139,8 @@ interface Msg {
metadata: { metadata: {
dataHash: null // MUST be null dataHash: null // MUST be null
dataSize: 0 // MUST be 0 dataSize: 0 // MUST be 0
identity: string // MUST be an ID account: string // MUST be an ID
identityTips: null // MUST be null accountTips: null // MUST be null
tangles: {} // MUST be empty object tangles: {} // MUST be empty object
domain: string domain: string
v: 2 v: 2
@ -163,7 +150,7 @@ interface Msg {
} }
``` ```
Thus, given a `identity` and a `domain`, any peer can construct the `metadata` part of the feed root msg, and thus can derive the "msg ID" for the root based on that `metadata`. Thus, given a `account` and a `domain`, any peer can construct the `metadata` part of the feed root msg, and thus can derive the "msg ID" for the root based on that `metadata`.
Given the root msg ID, any peer can thus refer to the feed tangle, because the root msg ID is the tangle ID for the feed tangle. Given the root msg ID, any peer can thus refer to the feed tangle, because the root msg ID is the tangle ID for the feed tangle.

View File

@ -21,10 +21,10 @@ test('add()', async (t) => {
await peer.db.loaded() await peer.db.loaded()
const identityMsg0 = MsgV3.createIdentity(keypair, 'person') const accountMsg0 = MsgV3.createAccount(keypair, 'person')
const id = MsgV3.getMsgHash(identityMsg0) const id = MsgV3.getMsgHash(accountMsg0)
await p(peer.db.add)(identityMsg0, id) await p(peer.db.add)(accountMsg0, id)
const rootMsg = MsgV3.createRoot(id, 'post', keypair) const rootMsg = MsgV3.createRoot(id, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
@ -38,8 +38,8 @@ test('add()', async (t) => {
keypair, keypair,
domain: 'post', domain: 'post',
data: { text: 'This is the first post!' }, data: { text: 'This is the first post!' },
identity: id, account: id,
identityTips: [id], accountTips: [id],
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
}, },

View File

@ -21,12 +21,12 @@ test('del', async (t) => {
await peer.db.loaded() await peer.db.loaded()
const id = await p(peer.db.identity.create)({ domain: 'person' }) const id = await p(peer.db.account.create)({ domain: 'person' })
const msgHashes = [] const msgHashes = []
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
const rec = await p(peer.db.feed.publish)({ const rec = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'post', domain: 'post',
data: { text: 'm' + i }, data: { text: 'm' + i },
}) })
@ -35,7 +35,7 @@ test('del', async (t) => {
const before = [] const before = []
for (const msg of peer.db.msgs()) { for (const msg of peer.db.msgs()) {
if (msg.data && msg.metadata.identity?.length > 4) { if (msg.data && msg.metadata.account?.length > 4) {
before.push(msg.data.text) before.push(msg.data.text)
} }
} }
@ -50,7 +50,7 @@ test('del', async (t) => {
const after = [] const after = []
for (const msg of peer.db.msgs()) { for (const msg of peer.db.msgs()) {
if (msg.data && msg.metadata.identity?.length > 4) { if (msg.data && msg.metadata.account?.length > 4) {
after.push(msg.data.text) after.push(msg.data.text)
} }
} }
@ -91,7 +91,7 @@ test('del', async (t) => {
assert.deepEqual( assert.deepEqual(
persistedMsgs persistedMsgs
.filter((msg) => msg.data && msg.metadata.identity?.length > 4) .filter((msg) => msg.data && msg.metadata.account?.length > 4)
.map((msg) => msg.data.text), .map((msg) => msg.data.text),
['m0', 'm1', 'm3', 'm4'], ['m0', 'm1', 'm3', 'm4'],
'msgs in disk after the delete' 'msgs in disk after the delete'

View File

@ -21,12 +21,12 @@ test('erase', async (t) => {
await peer.db.loaded() await peer.db.loaded()
const id = await p(peer.db.identity.create)({ domain: 'person' }) const id = await p(peer.db.account.create)({ domain: 'person' })
const msgHashes = [] const msgHashes = []
for (let i = 0; i < 5; i++) { for (let i = 0; i < 5; i++) {
const rec = await p(peer.db.feed.publish)({ const rec = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'post', domain: 'post',
data: { text: 'm' + i }, data: { text: 'm' + i },
}) })
@ -35,7 +35,7 @@ test('erase', async (t) => {
const before = [] const before = []
for (const msg of peer.db.msgs()) { for (const msg of peer.db.msgs()) {
if (msg.data && msg.metadata.identity?.length > 4) { if (msg.data && msg.metadata.account?.length > 4) {
before.push(msg.data.text) before.push(msg.data.text)
} }
} }
@ -50,7 +50,7 @@ test('erase', async (t) => {
const after = [] const after = []
for (const msg of peer.db.msgs()) { for (const msg of peer.db.msgs()) {
if (msg.data && msg.metadata.identity?.length > 4) { if (msg.data && msg.metadata.account?.length > 4) {
after.push(msg.data.text) after.push(msg.data.text)
} }
} }

View File

@ -25,7 +25,7 @@ test('setup', async (t) => {
await peer.db.loaded() await peer.db.loaded()
id = (await p(peer.db.identity.create)({domain: 'person'})) id = (await p(peer.db.account.create)({domain: 'person'}))
rootMsg = MsgV3.createRoot(id, 'post', keypair) rootMsg = MsgV3.createRoot(id, 'post', keypair)
rootHash = MsgV3.getMsgHash(rootMsg) rootHash = MsgV3.getMsgHash(rootMsg)

View File

@ -26,7 +26,7 @@ test('setup', async (t) => {
await peer.db.loaded() await peer.db.loaded()
id = (await p(peer.db.identity.create)({domain: 'person'})) id = (await p(peer.db.account.create)({domain: 'person'}))
rootMsg = MsgV3.createRoot(id, 'post', keypair) rootMsg = MsgV3.createRoot(id, 'post', keypair)
rootHash = MsgV3.getMsgHash(rootMsg) rootHash = MsgV3.getMsgHash(rootMsg)
}) })
@ -36,7 +36,7 @@ let rec1
let msgHash2 let msgHash2
test('feed.publish()', async (t) => { test('feed.publish()', async (t) => {
rec1 = await p(peer.db.feed.publish)({ rec1 = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'post', domain: 'post',
data: { text: 'I am 1st post' }, data: { text: 'I am 1st post' },
}) })
@ -55,7 +55,7 @@ test('feed.publish()', async (t) => {
msgHash1 = MsgV3.getMsgHash(rec1.msg) msgHash1 = MsgV3.getMsgHash(rec1.msg)
const rec2 = await p(peer.db.feed.publish)({ const rec2 = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'post', domain: 'post',
data: { text: 'I am 2nd post' }, data: { text: 'I am 2nd post' },
}) })
@ -80,8 +80,8 @@ test('add() forked then feed.publish() merged', async (t) => {
const msg3 = MsgV3.create({ const msg3 = MsgV3.create({
keypair, keypair,
identity: id, account: id,
identityTips: [id], accountTips: [id],
domain: 'post', domain: 'post',
data: { text: '3rd post forked from 1st' }, data: { text: '3rd post forked from 1st' },
tangles: { tangles: {
@ -93,7 +93,7 @@ test('add() forked then feed.publish() merged', async (t) => {
const msgHash3 = MsgV3.getMsgHash(rec3.msg) const msgHash3 = MsgV3.getMsgHash(rec3.msg)
const rec4 = await p(peer.db.feed.publish)({ const rec4 = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'post', domain: 'post',
data: { text: 'I am 4th post' }, data: { text: 'I am 4th post' },
}) })
@ -119,7 +119,7 @@ test('add() forked then feed.publish() merged', async (t) => {
test('feed.publish() encrypted with box', async (t) => { test('feed.publish() encrypted with box', async (t) => {
const recEncrypted = await p(peer.db.feed.publish)({ const recEncrypted = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'post', domain: 'post',
data: { text: 'I am chewing food', recps: [keypair.public] }, data: { text: 'I am chewing food', recps: [keypair.public] },
encryptionFormat: 'box', encryptionFormat: 'box',
@ -133,14 +133,14 @@ test('feed.publish() encrypted with box', async (t) => {
test('feed.publish() with tangles', async (t) => { test('feed.publish() with tangles', async (t) => {
const recA = await p(peer.db.feed.publish)({ const recA = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'comment', domain: 'comment',
data: { text: 'I am root' }, data: { text: 'I am root' },
}) })
assert.equal(recA.msg.data.text, 'I am root', 'root text correct') assert.equal(recA.msg.data.text, 'I am root', 'root text correct')
const recB = await p(peer.db.feed.publish)({ const recB = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'comment', domain: 'comment',
data: { text: 'I am comment 1' }, data: { text: 'I am comment 1' },
tangles: [recA.hash], tangles: [recA.hash],

View File

@ -25,10 +25,10 @@ test('setup', async (t) => {
await peer.db.loaded() await peer.db.loaded()
id = (await p(peer.db.identity.create)({domain: 'person'})) id = (await p(peer.db.account.create)({domain: 'person'}))
const rec1 = await p(peer.db.feed.publish)({ const rec1 = await p(peer.db.feed.publish)({
identity: id, account: id,
domain: 'post', domain: 'post',
data: { text: 'I am 1st post' }, data: { text: 'I am 1st post' },
}) })

View File

@ -26,7 +26,7 @@ test('setup', async (t) => {
await peer.db.loaded() await peer.db.loaded()
const id = (await p(peer.db.identity.create)({domain: 'person'})) const id = (await p(peer.db.account.create)({domain: 'person'}))
// Slow down append so that we can trigger msg creation in parallel // Slow down append so that we can trigger msg creation in parallel
const originalAppend = peer.db._getLog().append const originalAppend = peer.db._getLog().append
@ -36,7 +36,7 @@ test('setup', async (t) => {
rootPost = ( rootPost = (
await p(peer.db.feed.publish)({ await p(peer.db.feed.publish)({
identity: id, account: id,
keypair: keypairA, keypair: keypairA,
domain: 'comment', domain: 'comment',
data: { text: 'root' }, data: { text: 'root' },
@ -45,14 +45,14 @@ test('setup', async (t) => {
const [{ hash: reply1B }, { hash: reply1C }] = await Promise.all([ const [{ hash: reply1B }, { hash: reply1C }] = await Promise.all([
p(peer.db.feed.publish)({ p(peer.db.feed.publish)({
identity: id, account: id,
keypair: keypairB, keypair: keypairB,
domain: 'comment', domain: 'comment',
data: { text: 'reply 1B' }, data: { text: 'reply 1B' },
tangles: [rootPost], tangles: [rootPost],
}), }),
p(peer.db.feed.publish)({ p(peer.db.feed.publish)({
identity: id, account: id,
keypair: keypairC, keypair: keypairC,
domain: 'comment', domain: 'comment',
data: { text: 'reply 1C' }, data: { text: 'reply 1C' },
@ -64,7 +64,7 @@ test('setup', async (t) => {
reply2A = ( reply2A = (
await p(peer.db.feed.publish)({ await p(peer.db.feed.publish)({
identity: id, account: id,
keypair: keypairA, keypair: keypairA,
domain: 'comment', domain: 'comment',
data: { text: 'reply 2' }, data: { text: 'reply 2' },
@ -74,14 +74,14 @@ test('setup', async (t) => {
const [{ hash: reply3B }, { hash: reply3C }] = await Promise.all([ const [{ hash: reply3B }, { hash: reply3C }] = await Promise.all([
p(peer.db.feed.publish)({ p(peer.db.feed.publish)({
identity: id, account: id,
keypair: keypairB, keypair: keypairB,
domain: 'comment', domain: 'comment',
data: { text: 'reply 3B' }, data: { text: 'reply 3B' },
tangles: [rootPost], tangles: [rootPost],
}), }),
p(peer.db.feed.publish)({ p(peer.db.feed.publish)({
identity: id, account: id,
keypair: keypairC, keypair: keypairC,
domain: 'comment', domain: 'comment',
data: { text: 'reply 3C' }, data: { text: 'reply 3C' },

View File

@ -8,10 +8,10 @@ const SecretStack = require('secret-stack')
const caps = require('ppppp-caps') const caps = require('ppppp-caps')
const Keypair = require('ppppp-keypair') const Keypair = require('ppppp-keypair')
const DIR = path.join(os.tmpdir(), 'ppppp-db-identity-add') const DIR = path.join(os.tmpdir(), 'ppppp-db-account-add')
rimraf.sync(DIR) rimraf.sync(DIR)
test('identity.add()', async (t) => { test('account.add()', async (t) => {
const keypair1 = Keypair.generate('ed25519', 'alice') const keypair1 = Keypair.generate('ed25519', 'alice')
const keypair2 = Keypair.generate('ed25519', 'bob') const keypair2 = Keypair.generate('ed25519', 'bob')
@ -21,23 +21,23 @@ test('identity.add()', async (t) => {
.call(null, { keypair: keypair1, path: DIR }) .call(null, { keypair: keypair1, path: DIR })
await peer.db.loaded() await peer.db.loaded()
const id = await p(peer.db.identity.create)({ const id = await p(peer.db.account.create)({
keypair: keypair1, keypair: keypair1,
domain: 'person', domain: 'person',
}) })
assert.equal(peer.db.identity.has({ identity: id, keypair: keypair2 }), false) assert.equal(peer.db.account.has({ account: id, keypair: keypair2 }), false)
const consent = peer.db.identity.consent({ identity: id, keypair: keypair2 }) const consent = peer.db.account.consent({ account: id, keypair: keypair2 })
const identityRec1 = await p(peer.db.identity.add)({ const accountRec1 = await p(peer.db.account.add)({
identity: id, account: id,
keypair: keypair2, keypair: keypair2,
consent, consent,
powers: ['box'], powers: ['box'],
}) })
assert.ok(identityRec1, 'identityRec1 exists') assert.ok(accountRec1, 'accountRec1 exists')
const { hash, msg } = identityRec1 const { hash, msg } = accountRec1
assert.ok(hash, 'hash exists') assert.ok(hash, 'hash exists')
assert.deepEqual( assert.deepEqual(
msg.data, msg.data,
@ -55,8 +55,8 @@ test('identity.add()', async (t) => {
}, },
'msg.data.add NEW KEY' 'msg.data.add NEW KEY'
) )
assert.equal(msg.metadata.identity, 'self', 'msg.metadata.identity') assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
assert.equal(msg.metadata.identityTips, null, 'msg.metadata.identityTips') assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
assert.equal(msg.metadata.domain, 'person', 'msg.metadata.domain') assert.equal(msg.metadata.domain, 'person', 'msg.metadata.domain')
assert.deepEqual( assert.deepEqual(
msg.metadata.tangles, msg.metadata.tangles,
@ -65,12 +65,12 @@ test('identity.add()', async (t) => {
) )
assert.equal(msg.pubkey, keypair1.public, 'msg.pubkey OLD KEY') assert.equal(msg.pubkey, keypair1.public, 'msg.pubkey OLD KEY')
assert.equal(peer.db.identity.has({ identity: id, keypair: keypair2 }), true) assert.equal(peer.db.account.has({ account: id, keypair: keypair2 }), true)
await p(peer.close)() await p(peer.close)()
}) })
test('keypair with no "add" powers cannot identity.add()', async (t) => { test('keypair with no "add" powers cannot account.add()', async (t) => {
rimraf.sync(DIR) rimraf.sync(DIR)
const keypair1 = Keypair.generate('ed25519', 'alice') const keypair1 = Keypair.generate('ed25519', 'alice')
const keypair2 = Keypair.generate('ed25519', 'bob') const keypair2 = Keypair.generate('ed25519', 'bob')
@ -82,20 +82,20 @@ test('keypair with no "add" powers cannot identity.add()', async (t) => {
.call(null, { keypair: keypair1, path: DIR }) .call(null, { keypair: keypair1, path: DIR })
await peer1.db.loaded() await peer1.db.loaded()
const id = await p(peer1.db.identity.create)({ const id = await p(peer1.db.account.create)({
keypair: keypair1, keypair: keypair1,
domain: 'account', domain: 'account',
}) })
const msg1 = peer1.db.get(id) const msg1 = peer1.db.get(id)
const { msg: msg2 } = await p(peer1.db.identity.add)({ const { msg: msg2 } = await p(peer1.db.account.add)({
identity: id, account: id,
keypair: keypair2, keypair: keypair2,
powers: [], powers: [],
}) })
assert.equal(msg2.data.add.key.bytes, keypair2.public) assert.equal(msg2.data.add.key.bytes, keypair2.public)
assert.equal(peer1.db.identity.has({ identity: id, keypair: keypair2 }), true) assert.equal(peer1.db.account.has({ account: id, keypair: keypair2 }), true)
await p(peer1.close)() await p(peer1.close)()
rimraf.sync(DIR) rimraf.sync(DIR)
@ -111,8 +111,8 @@ test('keypair with no "add" powers cannot identity.add()', async (t) => {
// Test author-side power validation // Test author-side power validation
assert.rejects( assert.rejects(
p(peer2.db.identity.add)({ p(peer2.db.account.add)({
identity: id, account: id,
keypair: keypair3, keypair: keypair3,
powers: [], powers: [],
}), }),
@ -120,8 +120,8 @@ test('keypair with no "add" powers cannot identity.add()', async (t) => {
) )
// Make the author disobey power validation // Make the author disobey power validation
const { msg: msg3 } = await p(peer2.db.identity.add)({ const { msg: msg3 } = await p(peer2.db.account.add)({
identity: id, account: id,
keypair: keypair3, keypair: keypair3,
powers: [], powers: [],
_disobey: true, _disobey: true,
@ -150,7 +150,7 @@ test('keypair with no "add" powers cannot identity.add()', async (t) => {
await p(peer1again.close)() await p(peer1again.close)()
}) })
test('publish with a key in the identity', async (t) => { test('publish with a key in the account', async (t) => {
rimraf.sync(DIR) rimraf.sync(DIR)
const keypair1 = Keypair.generate('ed25519', 'alice') const keypair1 = Keypair.generate('ed25519', 'alice')
@ -163,40 +163,40 @@ test('publish with a key in the identity', async (t) => {
await peer.db.loaded() await peer.db.loaded()
const identity = await p(peer.db.identity.create)({ const account = await p(peer.db.account.create)({
keypair: keypair1, keypair: keypair1,
domain: 'person', domain: 'person',
}) })
const identityMsg0 = peer.db.get(identity) const accountMsg0 = peer.db.get(account)
// Consent is implicitly created because keypair2 has .private // Consent is implicitly created because keypair2 has .private
const identityRec1 = await p(peer.db.identity.add)({ const accountRec1 = await p(peer.db.account.add)({
identity, account,
keypair: keypair2, keypair: keypair2,
}) })
const postRec = await p(peer.db.feed.publish)({ const postRec = await p(peer.db.feed.publish)({
identity, account,
domain: 'post', domain: 'post',
data: { text: 'hello' }, data: { text: 'hello' },
keypair: keypair2, keypair: keypair2,
}) })
assert.equal(postRec.msg.data.text, 'hello', 'post text correct') assert.equal(postRec.msg.data.text, 'hello', 'post text correct')
const postsId = peer.db.feed.getId(identity, 'post') const postsId = peer.db.feed.getId(account, 'post')
assert.ok(postsId, 'postsId exists') assert.ok(postsId, 'postsId exists')
const recs = [...peer.db.records()] const recs = [...peer.db.records()]
assert.equal(recs.length, 4, '4 records') assert.equal(recs.length, 4, '4 records')
const [_identityRec0, _identityRec1, postsRoot, _post] = recs const [_accountRec0, _accountRec1, postsRoot, _post] = recs
assert.deepEqual(_identityRec0.msg, identityMsg0, 'identityMsg0') assert.deepEqual(_accountRec0.msg, accountMsg0, 'accountMsg0')
assert.deepEqual(_identityRec1.msg, identityRec1.msg, 'identityMsg1') assert.deepEqual(_accountRec1.msg, accountRec1.msg, 'accountMsg1')
assert.deepEqual( assert.deepEqual(
postsRoot.msg.metadata, postsRoot.msg.metadata,
{ {
dataHash: null, dataHash: null,
dataSize: 0, dataSize: 0,
identity, account,
identityTips: null, accountTips: null,
tangles: {}, tangles: {},
domain: 'post', domain: 'post',
v: 3, v: 3,
@ -218,8 +218,8 @@ test('publish with a key in the identity', async (t) => {
await carol.db.loaded() await carol.db.loaded()
await p(carol.db.add)(identityMsg0, identity) await p(carol.db.add)(accountMsg0, account)
await p(carol.db.add)(identityRec1.msg, identity) await p(carol.db.add)(accountRec1.msg, account)
await p(carol.db.add)(postsRoot.msg, postsId) await p(carol.db.add)(postsRoot.msg, postsId)
await p(carol.db.add)(postRec.msg, postsId) await p(carol.db.add)(postRec.msg, postsId)
// t.pass('carol added all messages successfully') // t.pass('carol added all messages successfully')

View File

@ -8,10 +8,10 @@ const SecretStack = require('secret-stack')
const caps = require('ppppp-caps') const caps = require('ppppp-caps')
const Keypair = require('ppppp-keypair') const Keypair = require('ppppp-keypair')
const DIR = path.join(os.tmpdir(), 'ppppp-db-identity-create') const DIR = path.join(os.tmpdir(), 'ppppp-db-account-create')
rimraf.sync(DIR) rimraf.sync(DIR)
test('identity.create() with just "domain"', async (t) => { test('account.create() with just "domain"', async (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const peer = SecretStack({ appKey: caps.shse }) const peer = SecretStack({ appKey: caps.shse })
.use(require('../lib')) .use(require('../lib'))
@ -19,12 +19,12 @@ test('identity.create() with just "domain"', async (t) => {
.call(null, { keypair, path: DIR }) .call(null, { keypair, path: DIR })
await peer.db.loaded() await peer.db.loaded()
const identity = await p(peer.db.identity.create)({ const account = await p(peer.db.account.create)({
domain: 'person', domain: 'person',
_nonce: 'MYNONCE', _nonce: 'MYNONCE',
}) })
assert.ok(identity, 'identityRec0 exists') assert.ok(account, 'accountRec0 exists')
const msg = peer.db.get(identity) const msg = peer.db.get(account)
assert.deepEqual( assert.deepEqual(
msg.data, msg.data,
{ {
@ -41,8 +41,8 @@ test('identity.create() with just "domain"', async (t) => {
}, },
'msg.data.add' 'msg.data.add'
) )
assert.equal(msg.metadata.identity, 'self', 'msg.metadata.identity') assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
assert.equal(msg.metadata.identityTips, null, 'msg.metadata.identityTips') assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
assert.deepEqual( assert.deepEqual(
Object.keys(msg.metadata.tangles), Object.keys(msg.metadata.tangles),
[], [],
@ -53,7 +53,7 @@ test('identity.create() with just "domain"', async (t) => {
await p(peer.close)() await p(peer.close)()
}) })
test('identity.create() with "keypair" and "domain"', async (t) => { test('account.create() with "keypair" and "domain"', async (t) => {
rimraf.sync(DIR) rimraf.sync(DIR)
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
@ -63,15 +63,15 @@ test('identity.create() with "keypair" and "domain"', async (t) => {
.call(null, { keypair, path: DIR }) .call(null, { keypair, path: DIR })
await peer.db.loaded() await peer.db.loaded()
const identity = await p(peer.db.identity.create)({ const account = await p(peer.db.account.create)({
keypair, keypair,
domain: 'person', domain: 'person',
}) })
assert.ok(identity, 'identity created') assert.ok(account, 'account created')
const msg = peer.db.get(identity) const msg = peer.db.get(account)
assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add') assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add')
assert.equal(msg.metadata.identity, 'self', 'msg.metadata.identity') assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
assert.equal(msg.metadata.identityTips, null, 'msg.metadata.identityTips') assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
assert.deepEqual( assert.deepEqual(
Object.keys(msg.metadata.tangles), Object.keys(msg.metadata.tangles),
[], [],
@ -82,7 +82,7 @@ test('identity.create() with "keypair" and "domain"', async (t) => {
await p(peer.close)() await p(peer.close)()
}) })
test('identity.find() can find', async (t) => { test('account.find() can find', async (t) => {
rimraf.sync(DIR) rimraf.sync(DIR)
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const domain = 'person' const domain = 'person'
@ -93,16 +93,16 @@ test('identity.find() can find', async (t) => {
.call(null, { keypair, path: DIR }) .call(null, { keypair, path: DIR })
await peer.db.loaded() await peer.db.loaded()
const identity = await p(peer.db.identity.create)({ keypair, domain }) const account = await p(peer.db.account.create)({ keypair, domain })
assert.ok(identity, 'identity created') assert.ok(account, 'account created')
const found = await p(peer.db.identity.find)({ keypair, domain }) const found = await p(peer.db.account.find)({ keypair, domain })
assert.equal(found, identity, 'found') assert.equal(found, account, 'found')
await p(peer.close)() await p(peer.close)()
}) })
test('identity.findOrCreate() can find', async (t) => { test('account.findOrCreate() can find', async (t) => {
rimraf.sync(DIR) rimraf.sync(DIR)
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const domain = 'person' const domain = 'person'
@ -113,16 +113,16 @@ test('identity.findOrCreate() can find', async (t) => {
.call(null, { keypair, path: DIR }) .call(null, { keypair, path: DIR })
await peer.db.loaded() await peer.db.loaded()
const identity = await p(peer.db.identity.create)({ keypair, domain }) const account = await p(peer.db.account.create)({ keypair, domain })
assert.ok(identity, 'identity created') assert.ok(account, 'account created')
const found = await p(peer.db.identity.findOrCreate)({ keypair, domain }) const found = await p(peer.db.account.findOrCreate)({ keypair, domain })
assert.equal(found, identity, 'found') assert.equal(found, account, 'found')
await p(peer.close)() await p(peer.close)()
}) })
test('identity.findOrCreate() can create', async (t) => { test('account.findOrCreate() can create', async (t) => {
rimraf.sync(DIR) rimraf.sync(DIR)
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const domain = 'person' const domain = 'person'
@ -135,18 +135,18 @@ test('identity.findOrCreate() can create', async (t) => {
await peer.db.loaded() await peer.db.loaded()
let gotError = false let gotError = false
await p(peer.db.identity.find)({ keypair, domain }).catch((err) => { await p(peer.db.account.find)({ keypair, domain }).catch((err) => {
assert.equal(err.cause, 'ENOENT') assert.equal(err.cause, 'ENOENT')
gotError = true gotError = true
}) })
assert.ok(gotError, 'identity not found') assert.ok(gotError, 'account not found')
const identity = await p(peer.db.identity.findOrCreate)({ keypair, domain }) const account = await p(peer.db.account.findOrCreate)({ keypair, domain })
assert.ok(identity, 'identity created') assert.ok(account, 'account created')
const msg = peer.db.get(identity) const msg = peer.db.get(account)
assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add') assert.equal(msg.data.add.key.bytes, keypair.public, 'msg.data.add')
assert.equal(msg.metadata.identity, 'self', 'msg.metadata.identity') assert.equal(msg.metadata.account, 'self', 'msg.metadata.account')
assert.equal(msg.metadata.identityTips, null, 'msg.metadata.identityTips') assert.equal(msg.metadata.accountTips, null, 'msg.metadata.accountTips')
assert.deepEqual( assert.deepEqual(
Object.keys(msg.metadata.tangles), Object.keys(msg.metadata.tangles),
[], [],

View File

@ -3,15 +3,15 @@ const assert = require('node:assert')
const Keypair = require('ppppp-keypair') const Keypair = require('ppppp-keypair')
const MsgV3 = require('../../lib/msg-v3') const MsgV3 = require('../../lib/msg-v3')
let identity let account
test('MsgV3.createIdentity()', (t) => { test('MsgV3.createAccount()', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const identityMsg0 = MsgV3.createIdentity(keypair, 'person', 'MYNONCE') const accountMsg0 = MsgV3.createAccount(keypair, 'person', 'MYNONCE')
console.log(JSON.stringify(identityMsg0, null, 2)) console.log(JSON.stringify(accountMsg0, null, 2))
assert.deepEqual( assert.deepEqual(
identityMsg0.data, accountMsg0.data,
{ {
action: 'add', action: 'add',
add: { add: {
@ -26,17 +26,17 @@ test('MsgV3.createIdentity()', (t) => {
}, },
'data' 'data'
) )
assert.equal(identityMsg0.metadata.dataHash, 'R5az9nC1CB3Afd5Q57HYRQ', 'hash') assert.equal(accountMsg0.metadata.dataHash, 'R5az9nC1CB3Afd5Q57HYRQ', 'hash')
assert.equal(identityMsg0.metadata.dataSize, 172, 'size') assert.equal(accountMsg0.metadata.dataSize, 172, 'size')
assert.equal(identityMsg0.metadata.identity, 'self', 'identity') assert.equal(accountMsg0.metadata.account, 'self', 'account')
assert.equal(identityMsg0.metadata.identityTips, null, 'identityTips') assert.equal(accountMsg0.metadata.accountTips, null, 'accountTips')
assert.deepEqual(identityMsg0.metadata.tangles, {}, 'tangles') assert.deepEqual(accountMsg0.metadata.tangles, {}, 'tangles')
assert.equal(identityMsg0.metadata.domain, 'person', 'domain') assert.equal(accountMsg0.metadata.domain, 'person', 'domain')
assert.equal(identityMsg0.metadata.v, 3, 'v') assert.equal(accountMsg0.metadata.v, 3, 'v')
assert.equal(identityMsg0.pubkey, keypair.public, 'pubkey') assert.equal(accountMsg0.pubkey, keypair.public, 'pubkey')
identity = MsgV3.getMsgHash(identityMsg0) account = MsgV3.getMsgHash(accountMsg0)
assert.equal(identity, 'GZJ1T864pFVHKJ2mRS2c5q', 'identity ID') assert.equal(account, 'J2SUr6XtJuFuTusNbagEW5', 'account ID')
}) })
let rootMsg = null let rootMsg = null
@ -44,21 +44,21 @@ let rootHash = null
test('MsgV3.createRoot()', (t) => { test('MsgV3.createRoot()', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
rootMsg = MsgV3.createRoot(identity, 'post', keypair) rootMsg = MsgV3.createRoot(account, 'post', keypair)
console.log(JSON.stringify(rootMsg, null, 2)) console.log(JSON.stringify(rootMsg, null, 2))
assert.equal(rootMsg.data, null, 'data') assert.equal(rootMsg.data, null, 'data')
assert.equal(rootMsg.metadata.dataHash, null, 'hash') assert.equal(rootMsg.metadata.dataHash, null, 'hash')
assert.equal(rootMsg.metadata.dataSize, 0, 'size') assert.equal(rootMsg.metadata.dataSize, 0, 'size')
assert.equal(rootMsg.metadata.identity, identity, 'identity') assert.equal(rootMsg.metadata.account, account, 'account')
assert.equal(rootMsg.metadata.identityTips, null, 'identityTips') assert.equal(rootMsg.metadata.accountTips, null, 'accountTips')
assert.deepEqual(rootMsg.metadata.tangles, {}, 'tangles') assert.deepEqual(rootMsg.metadata.tangles, {}, 'tangles')
assert.equal(rootMsg.metadata.domain, 'post', 'domain') assert.equal(rootMsg.metadata.domain, 'post', 'domain')
assert.equal(rootMsg.metadata.v, 3, 'v') assert.equal(rootMsg.metadata.v, 3, 'v')
assert.equal(rootMsg.pubkey, keypair.public, 'pubkey') assert.equal(rootMsg.pubkey, keypair.public, 'pubkey')
rootHash = MsgV3.getMsgHash(rootMsg) rootHash = MsgV3.getMsgHash(rootMsg)
assert.equal(rootHash, '4VfVj9DQArX5Vk6PVz5s5J', 'root hash') assert.equal(rootHash, 'VsBFptgidvAspk4xTKZx6c', 'root hash')
}) })
test('MsgV3.create()', (t) => { test('MsgV3.create()', (t) => {
@ -71,8 +71,8 @@ test('MsgV3.create()', (t) => {
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
keypair, keypair,
data, data,
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle1, [rootHash]: tangle1,
@ -86,8 +86,8 @@ test('MsgV3.create()', (t) => {
[ [
'dataHash', 'dataHash',
'dataSize', 'dataSize',
'identity', 'account',
'identityTips', 'accountTips',
'tangles', 'tangles',
'domain', 'domain',
'v', 'v',
@ -100,11 +100,11 @@ test('MsgV3.create()', (t) => {
'metadata.dataHash' 'metadata.dataHash'
) )
assert.deepEqual(msg1.metadata.dataSize, 23, 'metadata.dataSize') assert.deepEqual(msg1.metadata.dataSize, 23, 'metadata.dataSize')
assert.equal(msg1.metadata.identity, identity, 'metadata.identity') assert.equal(msg1.metadata.account, account, 'metadata.account')
assert.deepEqual( assert.deepEqual(
msg1.metadata.identityTips, msg1.metadata.accountTips,
[identity], [account],
'metadata.identityTips' 'metadata.accountTips'
) )
assert.deepEqual( assert.deepEqual(
Object.keys(msg1.metadata.tangles), Object.keys(msg1.metadata.tangles),
@ -126,15 +126,15 @@ test('MsgV3.create()', (t) => {
) )
assert.equal( assert.equal(
msg1.sig, msg1.sig,
'23CPZzKBAeRa6gb2ijwUJAd4VrYmokLSbQTmWEFMCiSogjViwqvms6ShyPq1UCzNWKAggmmJP4qETnVrY4iEMQ5J', '46CjqZzC8RAanRHnUKs147PMNFvrQcc9Y7a8tMP3s4qQubCtgYsypgzNA7XkSxM6vqRCe2ZBSKM2WR9AoHN3VoDz',
'sig' 'sig'
) )
const msgHash1 = 'kF6XHyi1LtJdttRDp54VM' const msgHash1 = 'R5G9WtDAQrco4FABRdvrUH'
assert.equal( assert.equal(
MsgV3.getMsgId(msg1), MsgV3.getMsgId(msg1),
`ppppp:message/v3/${identity}/post/${msgHash1}`, `ppppp:message/v3/${account}/post/${msgHash1}`,
'getMsgId' 'getMsgId'
) )
@ -147,8 +147,8 @@ test('MsgV3.create()', (t) => {
const msg2 = MsgV3.create({ const msg2 = MsgV3.create({
keypair, keypair,
data: data2, data: data2,
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle2, [rootHash]: tangle2,
@ -162,8 +162,8 @@ test('MsgV3.create()', (t) => {
[ [
'dataHash', 'dataHash',
'dataSize', 'dataSize',
'identity', 'account',
'identityTips', 'accountTips',
'tangles', 'tangles',
'domain', 'domain',
'v', 'v',
@ -176,11 +176,11 @@ test('MsgV3.create()', (t) => {
'metadata.dataHash' 'metadata.dataHash'
) )
assert.deepEqual(msg2.metadata.dataSize, 21, 'metadata.dataSize') assert.deepEqual(msg2.metadata.dataSize, 21, 'metadata.dataSize')
assert.equal(msg2.metadata.identity, identity, 'metadata.identity') assert.equal(msg2.metadata.account, account, 'metadata.account')
assert.deepEqual( assert.deepEqual(
msg2.metadata.identityTips, msg2.metadata.accountTips,
[identity], [account],
'metadata.identityTips' 'metadata.accountTips'
) )
assert.deepEqual( assert.deepEqual(
Object.keys(msg2.metadata.tangles), Object.keys(msg2.metadata.tangles),
@ -202,13 +202,13 @@ test('MsgV3.create()', (t) => {
) )
assert.equal( assert.equal(
msg2.sig, msg2.sig,
'tpMaMqV7t4hhYtLPZu7nFmUZej3pXVAYWf3pwXChThsQ8qT9Zxxym2TDDTUrT9VF7CNXRnLNoLMgYuZKAQrZ5bR', '31StEDDnoDoDtRi49L94XPTGXxNtDJa9QXSJTd4o3wBtFAJvfQA1RsHvunU4CxdY9iC69WnxnkaW6QryrztJZkiA',
'sig' 'sig'
) )
assert.deepEqual( assert.deepEqual(
MsgV3.getMsgId(msg2), MsgV3.getMsgId(msg2),
`ppppp:message/v3/${identity}/post/7W2nJCdpMeco7D8BYvRq7A`, `ppppp:message/v3/${account}/post/LxWgRRr4wXd29sLDNGNTkr`,
'getMsgId' 'getMsgId'
) )
}) })
@ -221,8 +221,8 @@ test('create() handles DAG tips correctly', (t) => {
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
keypair, keypair,
data: { text: '1' }, data: { text: '1' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -231,7 +231,7 @@ test('create() handles DAG tips correctly', (t) => {
const msgHash1 = MsgV3.getMsgHash(msg1) const msgHash1 = MsgV3.getMsgHash(msg1)
assert.deepEqual( assert.deepEqual(
msg1.metadata.tangles[rootHash].prev, msg1.metadata.tangles[rootHash].prev,
[MsgV3.getFeedRootHash(identity, 'post')], [MsgV3.getFeedRootHash(account, 'post')],
'msg1.prev is root' 'msg1.prev is root'
) )
@ -240,8 +240,8 @@ test('create() handles DAG tips correctly', (t) => {
const msg2A = MsgV3.create({ const msg2A = MsgV3.create({
keypair, keypair,
data: { text: '2A' }, data: { text: '2A' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -256,8 +256,8 @@ test('create() handles DAG tips correctly', (t) => {
const msg2B = MsgV3.create({ const msg2B = MsgV3.create({
keypair, keypair,
data: { text: '2B' }, data: { text: '2B' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -275,8 +275,8 @@ test('create() handles DAG tips correctly', (t) => {
const msg3 = MsgV3.create({ const msg3 = MsgV3.create({
keypair, keypair,
data: { text: '3' }, data: { text: '3' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -297,8 +297,8 @@ test('create() handles DAG tips correctly', (t) => {
const msg4 = MsgV3.create({ const msg4 = MsgV3.create({
keypair, keypair,
data: { text: '4' }, data: { text: '4' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,

View File

@ -5,15 +5,15 @@ const Keypair = require('ppppp-keypair')
const MsgV3 = require('../../lib/msg-v3') const MsgV3 = require('../../lib/msg-v3')
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const identity = MsgV3.getMsgHash( const account = MsgV3.getMsgHash(
MsgV3.createIdentity(keypair, 'person', 'MYNONCE') MsgV3.createAccount(keypair, 'person', 'MYNONCE')
) )
const pubkeys = new Set([keypair.public]) const pubkeys = new Set([keypair.public])
test('invalid msg with non-array prev', (t) => { test('invalid msg with non-array prev', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
@ -22,8 +22,8 @@ test('invalid msg with non-array prev', (t) => {
const msg = MsgV3.create({ const msg = MsgV3.create({
keypair, keypair,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -44,7 +44,7 @@ test('invalid msg with non-array prev', (t) => {
test('invalid msg with bad prev', (t) => { test('invalid msg with bad prev', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
@ -53,8 +53,8 @@ test('invalid msg with bad prev', (t) => {
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
keypair, keypair,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -66,8 +66,8 @@ test('invalid msg with bad prev', (t) => {
const msg2 = MsgV3.create({ const msg2 = MsgV3.create({
keypair, keypair,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -89,7 +89,7 @@ test('invalid msg with bad prev', (t) => {
test('invalid msg with URI in prev', (t) => { test('invalid msg with URI in prev', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
@ -98,8 +98,8 @@ test('invalid msg with URI in prev', (t) => {
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
keypair, keypair,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -111,8 +111,8 @@ test('invalid msg with URI in prev', (t) => {
const msg2 = MsgV3.create({ const msg2 = MsgV3.create({
keypair, keypair,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -132,7 +132,7 @@ test('invalid msg with URI in prev', (t) => {
test('invalid msg with unknown prev', (t) => { test('invalid msg with unknown prev', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
@ -141,8 +141,8 @@ test('invalid msg with unknown prev', (t) => {
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
keypair, keypair,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -154,8 +154,8 @@ test('invalid msg with unknown prev', (t) => {
const unknownMsg = MsgV3.create({ const unknownMsg = MsgV3.create({
keypair, keypair,
data: { text: 'Alien' }, data: { text: 'Alien' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -171,8 +171,8 @@ test('invalid msg with unknown prev', (t) => {
const msg2 = MsgV3.create({ const msg2 = MsgV3.create({
keypair, keypair,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle2, [rootHash]: tangle2,
@ -193,11 +193,11 @@ test('invalid feed msg with a different pubkey', (t) => {
const keypairA = Keypair.generate('ed25519', 'alice') const keypairA = Keypair.generate('ed25519', 'alice')
const keypairB = Keypair.generate('ed25519', 'bob') const keypairB = Keypair.generate('ed25519', 'bob')
const identityB = MsgV3.getMsgHash( const accountB = MsgV3.getMsgHash(
MsgV3.createIdentity(keypairB, 'person', 'MYNONCE') MsgV3.createAccount(keypairB, 'person', 'MYNONCE')
) )
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const feedTangle = new MsgV3.Tangle(rootHash) const feedTangle = new MsgV3.Tangle(rootHash)
feedTangle.add(rootHash, rootMsg) feedTangle.add(rootHash, rootMsg)
@ -205,8 +205,8 @@ test('invalid feed msg with a different pubkey', (t) => {
const msg = MsgV3.create({ const msg = MsgV3.create({
keypair: keypairB, keypair: keypairB,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity: identityB, account: accountB,
identityTips: [identityB], accountTips: [accountB],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: feedTangle, [rootHash]: feedTangle,
@ -218,7 +218,7 @@ test('invalid feed msg with a different pubkey', (t) => {
assert.ok(err, 'invalid msg throws') assert.ok(err, 'invalid msg throws')
assert.match( assert.match(
err, err,
/pubkey ".*" should have been one of ".*" from the identity ".*"/, /pubkey ".*" should have been one of ".*" from the account ".*"/,
'invalid msg' 'invalid msg'
) )
}) })
@ -226,7 +226,7 @@ test('invalid feed msg with a different pubkey', (t) => {
test('invalid feed msg with a different domain', (t) => { test('invalid feed msg with a different domain', (t) => {
const keypairA = Keypair.generate('ed25519', 'alice') const keypairA = Keypair.generate('ed25519', 'alice')
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const feedTangle = new MsgV3.Tangle(rootHash) const feedTangle = new MsgV3.Tangle(rootHash)
feedTangle.add(rootHash, rootMsg) feedTangle.add(rootHash, rootMsg)
@ -234,8 +234,8 @@ test('invalid feed msg with a different domain', (t) => {
const msg = MsgV3.create({ const msg = MsgV3.create({
keypair: keypairA, keypair: keypairA,
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'comment', domain: 'comment',
tangles: { tangles: {
[rootHash]: feedTangle, [rootHash]: feedTangle,
@ -255,7 +255,7 @@ test('invalid feed msg with a different domain', (t) => {
test('invalid feed msg with non-alphabetical prev', (t) => { test('invalid feed msg with non-alphabetical prev', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
@ -264,8 +264,8 @@ test('invalid feed msg with non-alphabetical prev', (t) => {
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
keypair, keypair,
data: { text: '1' }, data: { text: '1' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -276,8 +276,8 @@ test('invalid feed msg with non-alphabetical prev', (t) => {
const msg2 = MsgV3.create({ const msg2 = MsgV3.create({
keypair, keypair,
data: { text: '2' }, data: { text: '2' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -291,8 +291,8 @@ test('invalid feed msg with non-alphabetical prev', (t) => {
const msg3 = MsgV3.create({ const msg3 = MsgV3.create({
keypair, keypair,
data: { text: '3' }, data: { text: '3' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,
@ -320,7 +320,7 @@ test('invalid feed msg with non-alphabetical prev', (t) => {
test('invalid feed msg with duplicate prev', (t) => { test('invalid feed msg with duplicate prev', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
@ -329,8 +329,8 @@ test('invalid feed msg with duplicate prev', (t) => {
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
keypair, keypair,
data: { text: '1' }, data: { text: '1' },
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
tangles: { tangles: {
[rootHash]: tangle, [rootHash]: tangle,

View File

@ -5,19 +5,19 @@ const MsgV3 = require('../../lib/msg-v3')
test('lipmaa prevs', (t) => { test('lipmaa prevs', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const identity = MsgV3.getMsgHash( const account = MsgV3.getMsgHash(
MsgV3.createIdentity(keypair, 'person', 'MYNONCE') MsgV3.createAccount(keypair, 'person', 'MYNONCE')
) )
const data = { text: 'Hello world!' } const data = { text: 'Hello world!' }
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
tangle.add(rootHash, rootMsg) tangle.add(rootHash, rootMsg)
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {
@ -35,8 +35,8 @@ test('lipmaa prevs', (t) => {
) )
const msg2 = MsgV3.create({ const msg2 = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {
@ -54,8 +54,8 @@ test('lipmaa prevs', (t) => {
) )
const msg3 = MsgV3.create({ const msg3 = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {
@ -73,8 +73,8 @@ test('lipmaa prevs', (t) => {
) )
const msg4 = MsgV3.create({ const msg4 = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
keypair, keypair,
tangles: { tangles: {
@ -92,8 +92,8 @@ test('lipmaa prevs', (t) => {
) )
const msg5 = MsgV3.create({ const msg5 = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {
@ -111,8 +111,8 @@ test('lipmaa prevs', (t) => {
) )
const msg6 = MsgV3.create({ const msg6 = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {
@ -130,8 +130,8 @@ test('lipmaa prevs', (t) => {
) )
const msg7 = MsgV3.create({ const msg7 = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {

View File

@ -6,26 +6,26 @@ const MsgV3 = require('../../lib/msg-v3')
test('simple multi-author tangle', (t) => { test('simple multi-author tangle', (t) => {
const keypairA = Keypair.generate('ed25519', 'alice') const keypairA = Keypair.generate('ed25519', 'alice')
const keypairB = Keypair.generate('ed25519', 'bob') const keypairB = Keypair.generate('ed25519', 'bob')
const identityA = MsgV3.getMsgHash( const accountA = MsgV3.getMsgHash(
MsgV3.createIdentity(keypairA, 'person', 'alice') MsgV3.createAccount(keypairA, 'person', 'alice')
) )
const identityB = MsgV3.getMsgHash( const accountB = MsgV3.getMsgHash(
MsgV3.createIdentity(keypairB, 'person', 'bob') MsgV3.createAccount(keypairB, 'person', 'bob')
) )
const rootMsgA = MsgV3.createRoot(identityA, 'post', keypairA) const rootMsgA = MsgV3.createRoot(accountA, 'post', keypairA)
const rootHashA = MsgV3.getMsgHash(rootMsgA) const rootHashA = MsgV3.getMsgHash(rootMsgA)
const tangleA = new MsgV3.Tangle(rootHashA) const tangleA = new MsgV3.Tangle(rootHashA)
tangleA.add(rootHashA, rootMsgA) tangleA.add(rootHashA, rootMsgA)
const rootMsgB = MsgV3.createRoot(identityB, 'post', keypairB) const rootMsgB = MsgV3.createRoot(accountB, 'post', keypairB)
const rootHashB = MsgV3.getMsgHash(rootMsgB) const rootHashB = MsgV3.getMsgHash(rootMsgB)
const tangleB = new MsgV3.Tangle(rootHashB) const tangleB = new MsgV3.Tangle(rootHashB)
tangleB.add(rootHashB, rootMsgB) tangleB.add(rootHashB, rootMsgB)
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
identity: identityA, account: accountA,
identityTips: [identityA], accountTips: [accountA],
domain: 'post', domain: 'post',
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
tangles: { tangles: {
@ -44,8 +44,8 @@ test('simple multi-author tangle', (t) => {
tangleX.add(msgHash1, msg1) tangleX.add(msgHash1, msg1)
const msg2 = MsgV3.create({ const msg2 = MsgV3.create({
identity: identityB, account: accountB,
identityTips: [identityB], accountTips: [accountB],
domain: 'post', domain: 'post',
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
tangles: { tangles: {
@ -86,28 +86,28 @@ test('simple multi-author tangle', (t) => {
test('lipmaa in multi-author tangle', (t) => { test('lipmaa in multi-author tangle', (t) => {
const keypairA = Keypair.generate('ed25519', 'alice') const keypairA = Keypair.generate('ed25519', 'alice')
const keypairB = Keypair.generate('ed25519', 'bob') const keypairB = Keypair.generate('ed25519', 'bob')
const identityA = MsgV3.getMsgHash( const accountA = MsgV3.getMsgHash(
MsgV3.createIdentity(keypairA, 'person', 'alice') MsgV3.createAccount(keypairA, 'person', 'alice')
) )
const identityB = MsgV3.getMsgHash( const accountB = MsgV3.getMsgHash(
MsgV3.createIdentity(keypairB, 'person', 'bob') MsgV3.createAccount(keypairB, 'person', 'bob')
) )
const data = { text: 'Hello world!' } const data = { text: 'Hello world!' }
const rootMsgA = MsgV3.createRoot(identityA, 'post', keypairA) const rootMsgA = MsgV3.createRoot(accountA, 'post', keypairA)
const rootHashA = MsgV3.getMsgHash(rootMsgA) const rootHashA = MsgV3.getMsgHash(rootMsgA)
const tangleA = new MsgV3.Tangle(rootHashA) const tangleA = new MsgV3.Tangle(rootHashA)
tangleA.add(rootHashA, rootMsgA) tangleA.add(rootHashA, rootMsgA)
const rootMsgB = MsgV3.createRoot(identityB, 'post', keypairB) const rootMsgB = MsgV3.createRoot(accountB, 'post', keypairB)
const rootHashB = MsgV3.getMsgHash(rootMsgB) const rootHashB = MsgV3.getMsgHash(rootMsgB)
const tangleB = new MsgV3.Tangle(rootHashB) const tangleB = new MsgV3.Tangle(rootHashB)
tangleB.add(rootHashB, rootMsgB) tangleB.add(rootHashB, rootMsgB)
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
identity: identityA, account: accountA,
identityTips: [identityA], accountTips: [accountA],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {
@ -127,8 +127,8 @@ test('lipmaa in multi-author tangle', (t) => {
) )
const msg2 = MsgV3.create({ const msg2 = MsgV3.create({
identity: identityB, account: accountB,
identityTips: [identityB], accountTips: [accountB],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {
@ -148,8 +148,8 @@ test('lipmaa in multi-author tangle', (t) => {
) )
const msg3 = MsgV3.create({ const msg3 = MsgV3.create({
identity: identityB, account: accountB,
identityTips: [identityB], accountTips: [accountB],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {
@ -169,8 +169,8 @@ test('lipmaa in multi-author tangle', (t) => {
) )
const msg4 = MsgV3.create({ const msg4 = MsgV3.create({
identity: identityA, account: accountA,
identityTips: [identityA], accountTips: [accountA],
domain: 'post', domain: 'post',
data, data,
tangles: { tangles: {

View File

@ -5,12 +5,12 @@ const MsgV3 = require('../../lib/msg-v3')
test('validate root msg', (t) => { test('validate root msg', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const identity = MsgV3.getMsgHash( const account = MsgV3.getMsgHash(
MsgV3.createIdentity(keypair, 'person', 'alice') MsgV3.createAccount(keypair, 'person', 'alice')
) )
const pubkeys = new Set([keypair.public]) const pubkeys = new Set([keypair.public])
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
@ -18,67 +18,67 @@ test('validate root msg', (t) => {
assert.ifError(err, 'valid root msg') assert.ifError(err, 'valid root msg')
}) })
test('validate identity tangle', (t) => { test('validate account tangle', (t) => {
const pubkeys = new Set() const pubkeys = new Set()
const keypair1 = Keypair.generate('ed25519', 'alice') const keypair1 = Keypair.generate('ed25519', 'alice')
pubkeys.add(keypair1.public) pubkeys.add(keypair1.public)
const identityMsg0 = MsgV3.createIdentity(keypair1, 'person', 'alice') const accountMsg0 = MsgV3.createAccount(keypair1, 'person', 'alice')
const identity = MsgV3.getMsgHash(identityMsg0) const account = MsgV3.getMsgHash(accountMsg0)
const identityMsg0Hash = identity const accountMsg0Hash = account
const tangle = new MsgV3.Tangle(identity) const tangle = new MsgV3.Tangle(account)
let err = MsgV3.validate( let err = MsgV3.validate(
identityMsg0, accountMsg0,
tangle, tangle,
pubkeys, pubkeys,
identityMsg0Hash, accountMsg0Hash,
identity account
) )
assert.ifError(err, 'valid identity root msg') assert.ifError(err, 'valid account root msg')
tangle.add(identity, identityMsg0) tangle.add(account, accountMsg0)
const keypair2 = Keypair.generate('ed25519', 'bob') const keypair2 = Keypair.generate('ed25519', 'bob')
const identityMsg1 = MsgV3.create({ const accountMsg1 = MsgV3.create({
identity: 'self', account: 'self',
identityTips: null, accountTips: null,
domain: 'identity', domain: 'account',
data: { add: keypair2.public }, data: { add: keypair2.public },
tangles: { tangles: {
[identity]: tangle, [account]: tangle,
}, },
keypair: keypair1, // announcing keypair2 but signing with keypair1 keypair: keypair1, // announcing keypair2 but signing with keypair1
}) })
const identityMsg1Hash = MsgV3.getMsgHash(identityMsg1) const accountMsg1Hash = MsgV3.getMsgHash(accountMsg1)
err = MsgV3.validate( err = MsgV3.validate(
identityMsg1, accountMsg1,
tangle, tangle,
pubkeys, pubkeys,
identityMsg1Hash, accountMsg1Hash,
identity account
) )
assert.ifError(err, 'valid identity msg') assert.ifError(err, 'valid account msg')
}) })
test('validate 2nd msg with existing root', (t) => { test('validate 2nd msg with existing root', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const identity = MsgV3.getMsgHash( const account = MsgV3.getMsgHash(
MsgV3.createIdentity(keypair, 'person', 'alice') MsgV3.createAccount(keypair, 'person', 'alice')
) )
const pubkeys = new Set([keypair.public]) const pubkeys = new Set([keypair.public])
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
tangle.add(rootHash, rootMsg) tangle.add(rootHash, rootMsg)
const msg1 = MsgV3.create({ const msg1 = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
tangles: { tangles: {
@ -95,19 +95,19 @@ test('validate 2nd msg with existing root', (t) => {
test('validate 2nd forked msg', (t) => { test('validate 2nd forked msg', (t) => {
const keypair = Keypair.generate('ed25519', 'alice') const keypair = Keypair.generate('ed25519', 'alice')
const identity = MsgV3.getMsgHash( const account = MsgV3.getMsgHash(
MsgV3.createIdentity(keypair, 'person', 'alice') MsgV3.createAccount(keypair, 'person', 'alice')
) )
const pubkeys = new Set([keypair.public]) const pubkeys = new Set([keypair.public])
const rootMsg = MsgV3.createRoot(identity, 'post', keypair) const rootMsg = MsgV3.createRoot(account, 'post', keypair)
const rootHash = MsgV3.getMsgHash(rootMsg) const rootHash = MsgV3.getMsgHash(rootMsg)
const tangle = new MsgV3.Tangle(rootHash) const tangle = new MsgV3.Tangle(rootHash)
tangle.add(rootHash, rootMsg) tangle.add(rootHash, rootMsg)
const msg1A = MsgV3.create({ const msg1A = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
tangles: { tangles: {
@ -118,8 +118,8 @@ test('validate 2nd forked msg', (t) => {
const msgHash1A = MsgV3.getMsgHash(msg1A) const msgHash1A = MsgV3.getMsgHash(msg1A)
const msg1B = MsgV3.create({ const msg1B = MsgV3.create({
identity, account,
identityTips: [identity], accountTips: [account],
domain: 'post', domain: 'post',
data: { text: 'Hello world!' }, data: { text: 'Hello world!' },
tangles: { tangles: {

View File

@ -19,11 +19,11 @@ test('msgs() iterator', async (t) => {
await peer.db.loaded() await peer.db.loaded()
const identity = (await p(peer.db.identity.create)({domain: 'person'})) const account = (await p(peer.db.account.create)({domain: 'person'}))
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
await p(peer.db.feed.publish)({ await p(peer.db.feed.publish)({
identity, account,
domain: i % 2 === 0 ? 'post' : 'about', domain: i % 2 === 0 ? 'post' : 'about',
data: data:
i % 2 === 0 i % 2 === 0

View File

@ -19,7 +19,7 @@ test('onRecordAdded', async (t) => {
await peer.db.loaded() await peer.db.loaded()
const identity = (await p(peer.db.identity.create)({domain: 'person'})) const account = (await p(peer.db.account.create)({domain: 'person'}))
const listened = [] const listened = []
var remove = peer.db.onRecordAdded((ev) => { var remove = peer.db.onRecordAdded((ev) => {
@ -27,7 +27,7 @@ test('onRecordAdded', async (t) => {
}) })
const rec1 = await p(peer.db.feed.publish)({ const rec1 = await p(peer.db.feed.publish)({
identity, account,
domain: 'post', domain: 'post',
data: { text: 'I am hungry' }, data: { text: 'I am hungry' },
}) })
@ -36,7 +36,7 @@ test('onRecordAdded', async (t) => {
await p(setTimeout)(500) await p(setTimeout)(500)
assert.equal(listened.length, 3) assert.equal(listened.length, 3)
assert.equal(listened[0].msg.metadata.identity, 'self', 'identity root') assert.equal(listened[0].msg.metadata.account, 'self', 'account root')
assert.equal(listened[1].msg.data, null, 'root') assert.equal(listened[1].msg.data, null, 'root')
assert.equal(listened[1].msg.metadata.dataSize, 0, 'root') assert.equal(listened[1].msg.metadata.dataSize, 0, 'root')
assert.deepEqual(listened[2], rec1, 'actual record') assert.deepEqual(listened[2], rec1, 'actual record')

View File

@ -19,13 +19,13 @@ test('publish some msgs, close, re-open', async (t) => {
.call(null, { keypair, path: DIR }) .call(null, { keypair, path: DIR })
await peer.db.loaded() await peer.db.loaded()
const identity = await p(peer.db.identity.create)({ domain: 'person' }) const account = await p(peer.db.account.create)({ domain: 'person' })
// t.pass('opened db') // t.pass('opened db')
const msgHashes = [] const msgHashes = []
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
const rec = await p(peer.db.feed.publish)({ const rec = await p(peer.db.feed.publish)({
identity, account,
domain: 'post', domain: 'post',
data: { text: 'hello ' + i }, data: { text: 'hello ' + i },
}) })
@ -49,7 +49,7 @@ test('publish some msgs, close, re-open', async (t) => {
const texts = [] const texts = []
for (const msg of peer2.db.msgs()) { for (const msg of peer2.db.msgs()) {
if (!msg.data || !(msg.metadata.identity?.length > 4)) continue if (!msg.data || !(msg.metadata.account?.length > 4)) continue
texts.push(msg.data.text) texts.push(msg.data.text)
} }

View File

@ -18,11 +18,11 @@ test('records() iterator', async (t) => {
.call(null, { keypair, path: DIR }) .call(null, { keypair, path: DIR })
await peer.db.loaded() await peer.db.loaded()
const identity = (await p(peer.db.identity.create)({ domain: 'person' })) const account = (await p(peer.db.account.create)({ domain: 'person' }))
for (let i = 0; i < 6; i++) { for (let i = 0; i < 6; i++) {
await p(peer.db.feed.publish)({ await p(peer.db.feed.publish)({
identity, account,
domain: i % 2 === 0 ? 'post' : 'about', domain: i % 2 === 0 ? 'post' : 'about',
data: data:
i % 2 === 0 i % 2 === 0
@ -34,7 +34,7 @@ test('records() iterator', async (t) => {
let count = 0 let count = 0
for (const rec of peer.db.records()) { for (const rec of peer.db.records()) {
if (!rec.msg.data) continue if (!rec.msg.data) continue
if (rec.msg.metadata.identity === 'self') continue if (rec.msg.metadata.account === 'self') continue
assert.ok(rec.misc.size > rec.msg.metadata.dataSize, 'size > dataSize') assert.ok(rec.misc.size > rec.msg.metadata.dataSize, 'size > dataSize')
count++ count++
} }