Skip to content

Commit

Permalink
fix: sync should only happen when both sides are enabled (#764)
Browse files Browse the repository at this point in the history
This change:

- Fixes core unreplication, closing issue [#762].

- Adds "fuzz testing" for sync, which tries a bunch of random actions
  and makes sure things work as expected.

[#762]: #762

Co-Authored-By: Gregor MacLennan <[email protected]>
  • Loading branch information
EvanHahn and gmaclennan authored Aug 27, 2024
1 parent 770a8dc commit b61e132
Show file tree
Hide file tree
Showing 7 changed files with 577 additions and 85 deletions.
18 changes: 18 additions & 0 deletions src/lib/hypercore-helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { assert } from '../utils.js'

/**
* @param {import('hypercore')<'binary', any>} core Core to unreplicate. Must be ready.
* @param {import('protomux')} protomux
*/
export function unreplicate(core, protomux) {
assert(core.discoveryKey, 'Core should have a discovery key')
protomux.unpair({
protocol: 'hypercore/alpha',
id: core.discoveryKey,
})
for (const channel of protomux) {
if (channel.protocol !== 'hypercore/alpha') continue
if (!channel.id.equals(core.discoveryKey)) continue
channel.close()
}
}
21 changes: 14 additions & 7 deletions src/sync/peer-sync-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import mapObject from 'map-obj'
import { NAMESPACES, PRESYNC_NAMESPACES } from '../constants.js'
import { Logger } from '../logger.js'
import { ExhaustivenessError, createMap } from '../utils.js'
import { unreplicate } from '../lib/hypercore-helpers.js'
/** @import { CoreRecord } from '../core-manager/index.js' */
/** @import { Role } from '../roles.js' */
/** @import { SyncEnabledState } from './sync-api.js' */
Expand Down Expand Up @@ -255,16 +256,22 @@ export class PeerSyncController {

/**
* @param {import('hypercore')<'binary', any>} core
* @returns {Promise<void>}
*/
#unreplicateCore(core) {
async #unreplicateCore(core) {
if (core === this.#coreManager.creatorCore) return
const peerToUnreplicate = core.peers.find(
(peer) => peer.protomux === this.#protomux
)
if (!peerToUnreplicate) return
this.#log('unreplicating core %k', core.key)
peerToUnreplicate.channel.close()

this.#replicatingCores.delete(core)

const isCoreReady = Boolean(core.discoveryKey)
if (!isCoreReady) {
await core.ready()
const wasReEnabledWhileWaiting = this.#replicatingCores.has(core)
if (wasReEnabledWhileWaiting) return
}

unreplicate(core, this.#protomux)
this.#log('unreplicated core %k', core.key)
}

/**
Expand Down
Loading

0 comments on commit b61e132

Please sign in to comment.