update to msg-v3 format

This commit is contained in:
Andre Staltz 2023-07-11 11:02:22 +03:00
parent 17b720cb60
commit 07f83677d4
No known key found for this signature in database
GPG Key ID: 9EDE23EA7E8A4890
7 changed files with 223 additions and 326 deletions

View File

@ -1,5 +1,5 @@
const { BloomFilter } = require('bloom-filters')
const MsgV2 = require('ppppp-db/msg-v2')
const MsgV3 = require('ppppp-db/msg-v3')
const p = require('util').promisify
const { isEmptyRange, estimateMsgCount } = require('./range')
const { parseGoal } = require('./goal')
@ -105,7 +105,7 @@ class Algorithm {
const filter = BloomFilter.create(2 * filterSize, 0.00001)
if (!isEmptyRange(range)) {
for (const msg of this.yieldMsgsIn(rootMsgHash, range)) {
filter.add('' + round + MsgV2.getMsgHash(msg))
filter.add('' + round + MsgV3.getMsgHash(msg))
}
}
for (const msgId of extraIds) {
@ -119,7 +119,7 @@ class Algorithm {
const remoteFilter = BloomFilter.fromJSON(remoteBloomJSON)
const missing = []
for (const msg of this.yieldMsgsIn(rootMsgHash, range)) {
const msgHash = MsgV2.getMsgHash(msg)
const msgHash = MsgV3.getMsgHash(msg)
if (!remoteFilter.has('' + round + msgHash)) {
missing.push(msgHash)
}
@ -166,7 +166,7 @@ class Algorithm {
const validNewMsgs = newMsgs
.filter((msg) => {
const depth = msg.metadata.tangles[rootMsgHash]?.depth ?? 0
if (depth === 0 && MsgV2.getMsgHash(msg) !== rootMsgHash) {
if (depth === 0 && MsgV3.getMsgHash(msg) !== rootMsgHash) {
return false // the rootMsg is the only acceptable depth-zero msg
}
if (!msg.data) {

View File

@ -36,13 +36,14 @@ module.exports = {
function createStream(remoteId, iamClient) {
// prettier-ignore
debug('Opening a stream with remote %s %s', iamClient ? 'server' : 'client', remoteId)
const stream = new SyncStream(peer.id, debug, goals, algo)
const stream = new SyncStream(peer.pubkey, debug, goals, algo)
streams.push(stream)
return stream
}
peer.on('rpc:connect', function onSyncRPCConnect(rpc, iamClient) {
if (rpc.id === peer.id) return // local client connecting to local server
// TODO: eliminate SSB base64 `.id`, use SHSE `.pubkey` instead
if (rpc.id === peer.pubkey) return // local client connecting to local server
if (!iamClient) return
const local = toPull.duplex(createStream(rpc.id, true))

View File

@ -36,15 +36,14 @@
"bs58": "^5.0.0",
"c8": "7",
"ppppp-db": "github:staltz/ppppp-db",
"ppppp-caps": "github:staltz/ppppp-caps",
"ppppp-keypair": "github:staltz/ppppp-keypair",
"prettier": "^2.6.2",
"pretty-quick": "^3.1.3",
"rimraf": "^4.4.0",
"secret-stack": "^6.4.1",
"secret-handshake-ext": "^0.0.7",
"ssb-box": "^1.0.1",
"ssb-caps": "^1.1.0",
"ssb-classic": "^1.1.0",
"ssb-keys": "^8.5.0",
"ssb-uri2": "^2.4.1",
"tap-arc": "^0.3.5",
"tape": "^5.6.3"
},

View File

@ -1,70 +1,41 @@
const test = require('tape')
const path = require('path')
const os = require('os')
const rimraf = require('rimraf')
const SecretStack = require('secret-stack')
const caps = require('ssb-caps')
const p = require('util').promisify
const p = require('node:util').promisify
const Keypair = require('ppppp-keypair')
const Algorithm = require('../lib/algorithm')
const { generateKeypair } = require('./util')
const { createPeer } = require('./util')
const createPeer = SecretStack({ appKey: caps.shs })
.use(require('ppppp-db'))
.use(require('ssb-box'))
.use(require('../lib'))
const ALICE_DIR = path.join(os.tmpdir(), 'dagsync-alice')
const BOB_DIR = path.join(os.tmpdir(), 'dagsync-bob')
const aliceKeys = generateKeypair('alice')
const bobKeys = generateKeypair('bob')
const carolKeypair = Keypair.generate('ed25519', 'carol')
test('sync a feed with goal=all', async (t) => {
rimraf.sync(ALICE_DIR)
rimraf.sync(BOB_DIR)
const alice = createPeer({
keys: aliceKeys,
path: ALICE_DIR,
})
const bob = createPeer({
keys: bobKeys,
path: BOB_DIR,
})
const alice = createPeer({ name: 'alice' })
const bob = createPeer({ name: 'bob' })
await alice.db.loaded()
const aliceGroupRec0 = await p(alice.db.group.create)({ _nonce: 'alice' })
const aliceId = aliceGroupRec0.hash
await p(alice.db.add)(aliceGroupRec0.msg, aliceId)
await bob.db.loaded()
const bobGroupRec0 = await p(bob.db.group.create)({ _nonce: 'bob' })
const bobId = bobGroupRec0.hash
await p(bob.db.add)(bobGroupRec0.msg, bobId)
const carolKeys = generateKeypair('carol')
const carolGroupRec0 = await p(alice.db.group.create)({
keys: carolKeys,
const carolID = await p(alice.db.identity.create)({
keypair: carolKeypair,
domain: 'account',
_nonce: 'carol',
})
const carolId = carolGroupRec0.hash
const carolIDMsg = alice.db.get(carolID)
// Bob knows Alice
await p(bob.db.add)(carolGroupRec0.msg, carolId)
// Bob knows Carol
await p(bob.db.add)(carolIDMsg, carolID)
const carolMsgs = []
for (let i = 1; i <= 10; i++) {
const rec = await p(alice.db.feed.publish)({
group: carolId,
type: 'post',
identity: carolID,
domain: 'post',
data: { text: 'm' + i },
keys: carolKeys,
keypair: carolKeypair,
})
carolMsgs.push(rec.msg)
}
t.pass('alice has msgs 1..10 from carol')
const carolPostsRootHash = alice.db.feed.getId(carolId, 'post')
const carolPostsRootHash = alice.db.feed.getId(carolID, 'post')
const carolPostsRootMsg = alice.db.get(carolPostsRootHash)
await p(bob.db.add)(carolPostsRootMsg, carolPostsRootHash)
@ -74,7 +45,7 @@ test('sync a feed with goal=all', async (t) => {
{
const arr = [...bob.db.msgs()]
.filter((msg) => msg.metadata.group === carolId && msg.data)
.filter((msg) => msg.metadata.identity === carolID && msg.data)
.map((msg) => msg.data.text)
t.deepEquals(
arr,
@ -95,7 +66,7 @@ test('sync a feed with goal=all', async (t) => {
{
const arr = [...bob.db.msgs()]
.filter((msg) => msg.metadata.group === carolId && msg.data)
.filter((msg) => msg.metadata.identity === carolID && msg.data)
.map((msg) => msg.data.text)
t.deepEquals(
arr,
@ -110,52 +81,35 @@ test('sync a feed with goal=all', async (t) => {
})
test('sync a feed with goal=newest', async (t) => {
rimraf.sync(ALICE_DIR)
rimraf.sync(BOB_DIR)
const alice = createPeer({
keys: aliceKeys,
path: ALICE_DIR,
})
const bob = createPeer({
keys: bobKeys,
path: BOB_DIR,
})
const alice = createPeer({ name: 'alice' })
const bob = createPeer({ name: 'bob' })
await alice.db.loaded()
const aliceGroupRec0 = await p(alice.db.group.create)({ _nonce: 'alice' })
const aliceId = aliceGroupRec0.hash
await p(alice.db.add)(aliceGroupRec0.msg, aliceId)
await bob.db.loaded()
const bobGroupRec0 = await p(bob.db.group.create)({ _nonce: 'bob' })
const bobId = bobGroupRec0.hash
await p(bob.db.add)(bobGroupRec0.msg, bobId)
const carolKeys = generateKeypair('carol')
const carolGroupRec0 = await p(alice.db.group.create)({
keys: carolKeys,
const carolID = await p(alice.db.identity.create)({
keypair: carolKeypair,
domain: 'account',
_nonce: 'carol',
})
const carolId = carolGroupRec0.hash
const carolIDMsg = alice.db.get(carolID)
// Bob knows Alice
await p(bob.db.add)(carolGroupRec0.msg, carolId)
// Bob knows Carol
await p(bob.db.add)(carolIDMsg, carolID)
const carolMsgs = []
for (let i = 1; i <= 10; i++) {
const rec = await p(alice.db.feed.publish)({
group: carolId,
type: 'post',
identity: carolID,
domain: 'post',
data: { text: 'm' + i },
keys: carolKeys,
keypair: carolKeypair,
})
carolMsgs.push(rec.msg)
}
t.pass('alice has msgs 1..10 from carol')
const carolPostsRootHash = alice.db.feed.getId(carolId, 'post')
const carolPostsRootHash = alice.db.feed.getId(carolID, 'post')
const carolPostsRootMsg = alice.db.get(carolPostsRootHash)
await p(bob.db.add)(carolPostsRootMsg, carolPostsRootHash)
@ -165,7 +119,7 @@ test('sync a feed with goal=newest', async (t) => {
{
const arr = [...bob.db.msgs()]
.filter((msg) => msg.metadata.group === carolId && msg.data)
.filter((msg) => msg.metadata.identity === carolID && msg.data)
.map((msg) => msg.data.text)
t.deepEquals(
arr,
@ -186,7 +140,7 @@ test('sync a feed with goal=newest', async (t) => {
{
const arr = [...bob.db.msgs()]
.filter((msg) => msg.metadata.group === carolId && msg.data)
.filter((msg) => msg.metadata.identity === carolID && msg.data)
.map((msg) => msg.data.text)
t.deepEquals(
arr,
@ -201,58 +155,41 @@ test('sync a feed with goal=newest', async (t) => {
})
test('sync a feed with goal=newest but too far behind', async (t) => {
rimraf.sync(ALICE_DIR)
rimraf.sync(BOB_DIR)
const alice = createPeer({
keys: aliceKeys,
path: ALICE_DIR,
})
const bob = createPeer({
keys: bobKeys,
path: BOB_DIR,
})
const alice = createPeer({ name: 'alice' })
const bob = createPeer({ name: 'bob' })
await alice.db.loaded()
const aliceGroupRec0 = await p(alice.db.group.create)({ _nonce: 'alice' })
const aliceId = aliceGroupRec0.hash
await p(alice.db.add)(aliceGroupRec0.msg, aliceId)
await bob.db.loaded()
const bobGroupRec0 = await p(bob.db.group.create)({ _nonce: 'bob' })
const bobId = bobGroupRec0.hash
await p(bob.db.add)(bobGroupRec0.msg, bobId)
const carolKeys = generateKeypair('carol')
const carolGroupRec0 = await p(alice.db.group.create)({
keys: carolKeys,
const carolID = await p(alice.db.identity.create)({
keypair: carolKeypair,
domain: 'account',
_nonce: 'carol',
})
const carolId = carolGroupRec0.hash
const carolIDMsg = alice.db.get(carolID)
// Bob knows Alice
await p(bob.db.add)(carolGroupRec0.msg, carolId)
// Bob knows Carol
await p(bob.db.add)(carolIDMsg, carolID)
const carolMsgs = []
for (let i = 1; i <= 10; i++) {
const rec = await p(alice.db.feed.publish)({
group: carolId,
type: 'post',
identity: carolID,
domain: 'post',
data: { text: 'm' + i },
keys: carolKeys,
keypair: carolKeypair,
})
carolMsgs.push(rec.msg)
}
const carolPostsRootHash = alice.db.feed.getId(carolId, 'post')
const carolPostsRootHash = alice.db.feed.getId(carolID, 'post')
const carolPostsRootMsg = alice.db.get(carolPostsRootHash)
const algo = new Algorithm(alice)
await algo.pruneNewest(carolPostsRootHash, 5)
{
const arr = [...alice.db.msgs()]
.filter((msg) => msg.metadata.group === carolId && msg.data)
.filter((msg) => msg.metadata.identity === carolID && msg.data)
.map((msg) => msg.data.text)
t.deepEquals(
arr,
@ -268,7 +205,7 @@ test('sync a feed with goal=newest but too far behind', async (t) => {
{
const arr = [...bob.db.msgs()]
.filter((msg) => msg.metadata.group === carolId && msg.data)
.filter((msg) => msg.metadata.identity === carolID && msg.data)
.map((msg) => msg.data.text)
t.deepEquals(arr, ['m1', 'm2'], 'bob has msgs 1..2 from carol')
}
@ -285,7 +222,7 @@ test('sync a feed with goal=newest but too far behind', async (t) => {
{
const arr = [...bob.db.msgs()]
.filter((msg) => msg.metadata.group === carolId && msg.data)
.filter((msg) => msg.metadata.identity === carolID && msg.data)
.map((msg) => msg.data.text)
t.deepEquals(
arr,

View File

@ -1,61 +1,47 @@
const test = require('tape')
const path = require('path')
const os = require('os')
const rimraf = require('rimraf')
const SecretStack = require('secret-stack')
const caps = require('ssb-caps')
const p = require('util').promisify
const { generateKeypair } = require('./util')
const Keypair = require('ppppp-keypair')
const { createPeer } = require('./util')
const createSSB = SecretStack({ appKey: caps.shs })
.use(require('ppppp-db'))
.use(require('ssb-box'))
.use(require('../lib'))
const ALICE_DIR = path.join(os.tmpdir(), 'dagsync-alice')
const BOB_DIR = path.join(os.tmpdir(), 'dagsync-bob')
const aliceKeys = generateKeypair('alice')
const bobKeys = generateKeypair('bob')
const aliceKeypair = Keypair.generate('ed25519', 'alice')
const bobKeys = Keypair.generate('ed25519', 'bob')
function getIdentity(iter) {
return [...iter]
.filter((msg) => msg.metadata.group === null && msg.data)
.filter((msg) => msg.metadata.identity === 'self' && msg.data)
.map((msg) => msg.data.add)
}
test('sync an identity tangle', async (t) => {
rimraf.sync(ALICE_DIR)
rimraf.sync(BOB_DIR)
const alice = createSSB({
keys: aliceKeys,
path: ALICE_DIR,
})
const bob = createSSB({
keys: bobKeys,
path: BOB_DIR,
})
const alice = createPeer({ name: 'alice', keypair: aliceKeypair })
const bob = createPeer({ name: 'bob', keypair: bobKeys })
await alice.db.loaded()
await bob.db.loaded()
// Alice's identity tangle
await alice.db.loaded()
const aliceGroupRec0 = await p(alice.db.group.create)({ _nonce: 'alice' })
const aliceId = aliceGroupRec0.hash
await p(alice.db.add)(aliceGroupRec0.msg, aliceId)
const aliceID = await p(alice.db.identity.create)({
domain: 'account',
_nonce: 'alice',
})
const aliceKeys1 = generateKeypair('alice1')
await p(alice.db.group.add)({ group: aliceId, keys: aliceKeys1 })
const aliceKeypair1 = Keypair.generate('ed25519', 'alice1')
await p(alice.db.identity.add)({
identity: aliceID,
keypair: aliceKeypair1,
})
const aliceKeys2 = generateKeypair('alice2')
await p(alice.db.group.add)({ group: aliceId, keys: aliceKeys2 })
const aliceKeypair2 = Keypair.generate('ed25519', 'alice2')
await p(alice.db.identity.add)({
identity: aliceID,
keypair: aliceKeypair2,
})
t.deepEquals(
getIdentity(alice.db.msgs()),
[aliceKeys.id, aliceKeys1.id, aliceKeys2.id],
"alice has her identity tangle"
[aliceKeypair.public, aliceKeypair1.public, aliceKeypair2.public],
'alice has her identity tangle'
)
t.deepEquals(
@ -64,8 +50,8 @@ test('sync an identity tangle', async (t) => {
"bob doesn't have alice's identity tangle"
)
bob.tangleSync.setGoal(aliceId, 'all')
alice.tangleSync.setGoal(aliceId, 'all')
bob.tangleSync.setGoal(aliceID, 'all')
alice.tangleSync.setGoal(aliceID, 'all')
const remoteAlice = await p(bob.connect)(alice.getAddress())
t.pass('bob connected to alice')
@ -76,7 +62,7 @@ test('sync an identity tangle', async (t) => {
t.deepEquals(
getIdentity(bob.db.msgs()),
[aliceKeys.id, aliceKeys1.id, aliceKeys2.id],
[aliceKeypair.public, aliceKeypair1.public, aliceKeypair2.public],
"bob has alice's identity tangle"
)

View File

@ -1,26 +1,13 @@
const test = require('tape')
const path = require('path')
const os = require('os')
const rimraf = require('rimraf')
const SecretStack = require('secret-stack')
const caps = require('ssb-caps')
const p = require('util').promisify
const { generateKeypair } = require('./util')
const Keypair = require('ppppp-keypair')
const { createPeer } = require('./util')
const createSSB = SecretStack({ appKey: caps.shs })
.use(require('ppppp-db'))
.use(require('ssb-box'))
.use(require('../lib'))
const ALICE_DIR = path.join(os.tmpdir(), 'dagsync-alice')
const BOB_DIR = path.join(os.tmpdir(), 'dagsync-bob')
const aliceKeys = generateKeypair('alice')
const bobKeys = generateKeypair('bob')
const carolKeypair = Keypair.generate('ed25519', 'carol')
const daveKeypair = Keypair.generate('ed25519', 'dave')
function getTexts(iter) {
return [...iter]
.filter((msg) => msg.metadata.group && msg.data)
.map((msg) => msg.data.text)
return [...iter].filter((msg) => msg.data?.text).map((msg) => msg.data.text)
}
/*
@ -61,81 +48,72 @@ graph TB;
```
*/
test('sync a thread where both peers have portions', async (t) => {
rimraf.sync(ALICE_DIR)
rimraf.sync(BOB_DIR)
const alice = createSSB({
keys: aliceKeys,
path: ALICE_DIR,
})
const bob = createSSB({
keys: bobKeys,
path: BOB_DIR,
})
const alice = createPeer({ name: 'alice' })
const bob = createPeer({ name: 'bob' })
await alice.db.loaded()
const aliceGroupRec0 = await p(alice.db.group.create)({ _nonce: 'alice' })
const aliceId = aliceGroupRec0.hash
await p(alice.db.add)(aliceGroupRec0.msg, aliceId)
const aliceID = await p(alice.db.identity.create)({
domain: 'account',
_nonce: 'alice',
})
const aliceIDMsg = alice.db.get(aliceID)
await bob.db.loaded()
const bobGroupRec0 = await p(bob.db.group.create)({ _nonce: 'bob' })
const bobId = bobGroupRec0.hash
await p(bob.db.add)(bobGroupRec0.msg, bobId)
const bobID = await p(bob.db.identity.create)({
domain: 'account',
_nonce: 'bob',
})
const bobIDMsg = bob.db.get(bobID)
// Alice created Carol
const carolKeys = generateKeypair('carol')
const carolGroupRec0 = await p(alice.db.group.create)({
keys: carolKeys,
const carolID = await p(alice.db.identity.create)({
domain: 'account',
keypair: carolKeypair,
_nonce: 'carol',
})
const carolId = carolGroupRec0.hash
const carolIDMsg = alice.db.get(carolID)
// Alice created Dave
const daveKeys = generateKeypair('dave')
const daveGroupRec0 = await p(alice.db.group.create)({
keys: daveKeys,
const daveID = await p(alice.db.identity.create)({
domain: 'account',
keypair: daveKeypair,
_nonce: 'dave',
})
const daveId = daveGroupRec0.hash
const daveIDMsg = alice.db.get(daveID)
// Alice knows Bob
await p(alice.db.add)(bobGroupRec0.msg, bobId)
await p(alice.db.add)(bobIDMsg, bobID)
// Bob knows Alice, Carol, and Dave
await p(bob.db.add)(aliceGroupRec0.msg, aliceId)
await p(bob.db.add)(carolGroupRec0.msg, carolId)
await p(bob.db.add)(daveGroupRec0.msg, daveId)
await p(bob.db.add)(aliceIDMsg, aliceID)
await p(bob.db.add)(carolIDMsg, carolID)
await p(bob.db.add)(daveIDMsg, daveID)
const startA = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A' },
keys: aliceKeys,
})
const rootHashA = alice.db.feed.getId(aliceId, 'post')
const rootHashA = alice.db.feed.getId(aliceID, 'post')
const rootMsgA = alice.db.get(rootHashA)
await p(bob.db.add)(rootMsgA, rootHashA)
await p(bob.db.add)(startA.msg, rootHashA)
const replyB1 = await p(bob.db.feed.publish)({
group: bobId,
type: 'post',
identity: bobID,
domain: 'post',
data: { text: 'B1' },
tangles: [startA.hash],
keys: bobKeys,
})
const replyB2 = await p(bob.db.feed.publish)({
group: bobId,
type: 'post',
identity: bobID,
domain: 'post',
data: { text: 'B2' },
tangles: [startA.hash],
keys: bobKeys,
})
const rootHashB = bob.db.feed.getId(bobId, 'post')
const rootHashB = bob.db.feed.getId(bobID, 'post')
const rootMsgB = bob.db.get(rootHashB)
await p(alice.db.add)(rootMsgB, rootHashB)
@ -143,19 +121,19 @@ test('sync a thread where both peers have portions', async (t) => {
await p(alice.db.add)(replyB2.msg, rootHashB)
const replyC1 = await p(alice.db.feed.publish)({
group: carolId,
type: 'post',
identity: carolID,
domain: 'post',
data: { text: 'C1' },
tangles: [startA.hash],
keys: carolKeys,
keypair: carolKeypair,
})
const replyD1 = await p(bob.db.feed.publish)({
group: daveId,
type: 'post',
identity: daveID,
domain: 'post',
data: { text: 'D1' },
tangles: [startA.hash],
keys: daveKeys,
keypair: daveKeypair,
})
t.deepEquals(
@ -198,56 +176,47 @@ test('sync a thread where both peers have portions', async (t) => {
})
test('sync a thread where initiator does not have the root', async (t) => {
rimraf.sync(ALICE_DIR)
rimraf.sync(BOB_DIR)
const alice = createSSB({
keys: aliceKeys,
path: ALICE_DIR,
})
const bob = createSSB({
keys: bobKeys,
path: BOB_DIR,
})
const alice = createPeer({ name: 'alice' })
const bob = createPeer({ name: 'bob' })
await alice.db.loaded()
const aliceGroupRec0 = await p(alice.db.group.create)({ _nonce: 'alice' })
const aliceId = aliceGroupRec0.hash
await p(alice.db.add)(aliceGroupRec0.msg, aliceId)
const aliceID = await p(alice.db.identity.create)({
domain: 'account',
_nonce: 'alice',
})
const aliceIDMsg = alice.db.get(aliceID)
await bob.db.loaded()
const bobGroupRec0 = await p(bob.db.group.create)({ _nonce: 'bob' })
const bobId = bobGroupRec0.hash
await p(bob.db.add)(bobGroupRec0.msg, bobId)
const bobID = await p(bob.db.identity.create)({
domain: 'account',
_nonce: 'bob',
})
const bobIDMsg = bob.db.get(bobID)
// Alice knows Bob
await p(alice.db.add)(bobGroupRec0.msg, bobId)
await p(alice.db.add)(bobIDMsg, bobID)
// Bob knows Alice
await p(bob.db.add)(aliceGroupRec0.msg, aliceId)
await p(bob.db.add)(aliceIDMsg, aliceID)
const rootA = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A' },
keys: aliceKeys,
})
const replyA1 = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A1' },
tangles: [rootA.hash],
keys: aliceKeys,
})
const replyA2 = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A2' },
tangles: [rootA.hash],
keys: aliceKeys,
})
t.deepEquals(
@ -281,56 +250,47 @@ test('sync a thread where initiator does not have the root', async (t) => {
})
test('sync a thread where receiver does not have the root', async (t) => {
rimraf.sync(ALICE_DIR)
rimraf.sync(BOB_DIR)
const alice = createSSB({
keys: aliceKeys,
path: ALICE_DIR,
})
const bob = createSSB({
keys: bobKeys,
path: BOB_DIR,
})
const alice = createPeer({ name: 'alice' })
const bob = createPeer({ name: 'bob' })
await alice.db.loaded()
const aliceGroupRec0 = await p(alice.db.group.create)({ _nonce: 'alice' })
const aliceId = aliceGroupRec0.hash
await p(alice.db.add)(aliceGroupRec0.msg, aliceId)
const aliceID = await p(alice.db.identity.create)({
domain: 'account',
_nonce: 'alice',
})
const aliceIDMsg = alice.db.get(aliceID)
await bob.db.loaded()
const bobGroupRec0 = await p(bob.db.group.create)({ _nonce: 'bob' })
const bobId = bobGroupRec0.hash
await p(bob.db.add)(bobGroupRec0.msg, bobId)
const bobID = await p(bob.db.identity.create)({
domain: 'account',
_nonce: 'bob',
})
const bobIDMsg = bob.db.get(bobID)
// Alice knows Bob
await p(alice.db.add)(bobGroupRec0.msg, bobId)
await p(alice.db.add)(bobIDMsg, bobID)
// Bob knows Alice
await p(bob.db.add)(aliceGroupRec0.msg, aliceId)
await p(bob.db.add)(aliceIDMsg, aliceID)
const rootA = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A' },
keys: aliceKeys,
})
const replyA1 = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A1' },
tangles: [rootA.hash],
keys: aliceKeys,
})
const replyA2 = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A2' },
tangles: [rootA.hash],
keys: aliceKeys,
})
t.deepEquals(
@ -363,64 +323,54 @@ test('sync a thread where receiver does not have the root', async (t) => {
})
test('sync a thread with reactions too', async (t) => {
rimraf.sync(ALICE_DIR)
rimraf.sync(BOB_DIR)
const alice = createSSB({
keys: aliceKeys,
path: ALICE_DIR,
})
const bob = createSSB({
keys: bobKeys,
path: BOB_DIR,
})
const alice = createPeer({ name: 'alice' })
const bob = createPeer({ name: 'bob' })
await alice.db.loaded()
const aliceGroupRec0 = await p(alice.db.group.create)({ _nonce: 'alice' })
const aliceId = aliceGroupRec0.hash
await p(alice.db.add)(aliceGroupRec0.msg, aliceId)
const aliceID = await p(alice.db.identity.create)({
domain: 'account',
_nonce: 'alice',
})
const aliceIDMsg = alice.db.get(aliceID)
await bob.db.loaded()
const bobGroupRec0 = await p(bob.db.group.create)({ _nonce: 'bob' })
const bobId = bobGroupRec0.hash
await p(bob.db.add)(bobGroupRec0.msg, bobId)
const bobID = await p(bob.db.identity.create)({
domain: 'account',
_nonce: 'bob',
})
const bobIDMsg = bob.db.get(bobID)
// Alice knows Bob
await p(alice.db.add)(bobGroupRec0.msg, bobId)
await p(alice.db.add)(bobIDMsg, bobID)
// Bob knows Alice
await p(bob.db.add)(aliceGroupRec0.msg, aliceId)
await p(bob.db.add)(aliceIDMsg, aliceID)
const rootA = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A' },
keys: aliceKeys,
})
const replyA1 = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A1' },
tangles: [rootA.hash],
keys: aliceKeys,
})
const replyA2 = await p(alice.db.feed.publish)({
group: aliceId,
type: 'post',
identity: aliceID,
domain: 'post',
data: { text: 'A2' },
tangles: [rootA.hash],
keys: aliceKeys,
})
const reactionA3 = await p(alice.db.feed.publish)({
group: aliceId,
type: 'reaction',
identity: aliceID,
domain: 'reaction',
data: { text: 'yes', link: replyA1.hash },
tangles: [rootA.hash, replyA1.hash],
keys: aliceKeys,
})
t.deepEquals(

View File

@ -1,14 +1,38 @@
const ssbKeys = require('ssb-keys')
const SSBURI = require('ssb-uri2')
const base58 = require('bs58')
const os = require('node:os')
const path = require('node:path')
const rimraf = require('rimraf')
const caps = require('ppppp-caps')
const Keypair = require('ppppp-keypair')
function generateKeypair(seed) {
const keys = ssbKeys.generate('ed25519', seed, 'buttwoo-v1')
const { data } = SSBURI.decompose(keys.id)
keys.id = base58.encode(Buffer.from(data, 'base64'))
return keys
function createPeer(opts) {
if (opts.name) {
opts.path ??= path.join(os.tmpdir(), 'tanglesync-' + opts.name)
opts.keypair ??= Keypair.generate('ed25519', opts.name)
opts.name = undefined
}
if (!opts.path) throw new Error('need opts.path in createPeer()')
if (!opts.keypair) throw new Error('need opts.keypair in createPeer()')
rimraf.sync(opts.path)
return require('secret-stack/lib/api')([], {})
.use(require('secret-stack/lib/core'))
.use(require('secret-stack/lib/plugins/net'))
.use(require('secret-handshake-ext/secret-stack'))
.use(require('ppppp-db'))
.use(require('ssb-box'))
.use(require('../lib'))
.call(null, {
caps,
connections: {
incoming: {
net: [{ scope: 'device', transform: 'shse', port: null }],
},
outgoing: {
net: [{ transform: 'shse' }],
},
},
...opts,
})
}
module.exports = {
generateKeypair,
}
module.exports = { createPeer }