Skip to content

Latest commit

 

History

History
429 lines (311 loc) · 8.61 KB

v0.46-v1.0.0.md

File metadata and controls

429 lines (311 loc) · 8.61 KB

Migrating to libp2p@1.0

A migration guide for refactoring your application code from libp2p v0.46 to v1.0.0.

Table of Contents

Type imports

All exports from @libp2p/interface and @libp2p/interface-internal are now exported from the root of the module, no more having to work out which subpath to import from.

Before

import type { PeerId } from '@libp2p/interface/peer-id'
import type { Connection } from '@libp2p/interface/connection'
import type { Stream } from '@libp2p/interface/stream-muxer'

After

import type { Connection, PeerId, Stream } from '@libp2p/interface'

Extracted modules

js-libp2p has always had a focus on being a modular, composable ecosystem of modules. v1.x.x takes this further and extracts all of the optional functionality out of the core and into modules that you can include in your app if you need them, or omit them if you don't.

Services

These modules can be configured as services to enable optional functionality.

AutoNAT

The AutoNAT service is now published in its own package.

Before

import { createLibp2p } from 'libp2p'
import { autoNATService } from 'libp2p/autonat'

const node = await createLibp2p({
  services: {
    autoNAT: autoNATService()
  }
})

After

import { createLibp2p } from 'libp2p'
import { autoNAT } from '@libp2p/autonat'

const node = await createLibp2p({
  services: {
    autoNAT: autoNAT()
  }
})

Ping

The Ping service is now published in its own package.

Before

import { createLibp2p } from 'libp2p'
import { pingService } from 'libp2p/ping'

const node = await createLibp2p({
  services: {
    ping: pingService()
  }
})

After

import { createLibp2p } from 'libp2p'
import { ping } from '@libp2p/ping'

const node = await createLibp2p({
  services: {
    ping: ping()
  }
})

Identify

The Identify service is now published in its own package.

Before

import { createLibp2p } from 'libp2p'
import { identifyService } from 'libp2p/identify'

const node = await createLibp2p({
  services: {
    identify: identifyService()
  }
})

After

import { createLibp2p } from 'libp2p'
import { identify } from '@libp2p/identify'

const node = await createLibp2p({
  services: {
    identify: identify()
  }
})

DCUtR

The DCUtR service is now published in its own package.

Before

import { createLibp2p } from 'libp2p'
import { dcutrService } from 'libp2p/dcutr'

const node = await createLibp2p({
  services: {
    dcutr: dcutrService()
  }
})

After

import { createLibp2p } from 'libp2p'
import { dcutr } from '@libp2p/dcutr'

const node = await createLibp2p({
  services: {
    dcutr: dcutr()
  }
})

Fetch

The Fetch service is now published in its own package.

Before

import { createLibp2p } from 'libp2p'
import { fetchService } from 'libp2p/fetch'

const node = await createLibp2p({
  services: {
    fetch: fetchService()
  }
})

After

import { createLibp2p } from 'libp2p'
import { fetch } from '@libp2p/fetch'

const node = await createLibp2p({
  services: {
    fetch: fetch()
  }
})

UPnPNat

The UPnPNat service module is now published in its own package.

Before

import { createLibp2p } from 'libp2p'
import { uPnPNATService } from 'libp2p/upnp-nat'

const node = await createLibp2p({
  services: {
    uPnPNAT: uPnPNATService()
  }
})

After

import { createLibp2p } from 'libp2p'
import { uPnPNAT } from '@libp2p/upnp-nat'

const node = await createLibp2p({
  services: {
    uPnPNAT: uPnPNAT()
  }
})

Perf

The Perf service module exports have been renamed in line with the other changes here.

Before

import { createLibp2p } from 'libp2p'
import { perService } from '@libp2p/perf'

const node = await createLibp2p({
  services: {
    perf: perService()
  }
})

After

import { createLibp2p } from 'libp2p'
import { perf } from '@libp2p/perf'

const node = await createLibp2p({
  services: {
    perf: perf()
  }
})

Connection encryption

Plaintext

The Plaintext connection encrypter module is now published in its own package.

Note that it is still insecure and should not be used in production.

Before

import { createLibp2p } from 'libp2p'
import { plaintext } from 'libp2p/insecure'

const node = await createLibp2p({
  connectionEncryption: [
    plaintext: plaintext()
  ]
})

After

import { createLibp2p } from 'libp2p'
import { plaintext } from '@libp2p/plaintext'

const node = await createLibp2p({
  connectionEncryption: [
    plaintext: plaintext()
  ]
})

Misc

KeyChain

The KeyChain object is no longer included on Libp2p and must be instantiated explicitly if desired.

Before

import type { KeyChain } from '@libp2p/interface/keychain'

const libp2p = await createLibp2p(...)

const keychain: KeyChain = libp2p.keychain

After

import { keychain, type Keychain } from '@libp2p/keychain'

const libp2p = await createLibp2p({
  ...
  services: {
    keychain: keychain()
  }
})

const keychain: Keychain = libp2p.services.keychain

Pnet

The pnet module is now published in its own package.

Before

import { createLibp2p } from 'libp2p'
import { preSharedKey, generateKey } from 'libp2p/pnet'

const node = await createLibp2p({
  // ...other options
  connectionProtector: preSharedKey({
    psk: generateKey(new Uint8Array(95))
  })
})

After

import { createLibp2p } from 'libp2p'
import { preSharedKey, generateKey } from '@libp2p/pnet'

const node = await createLibp2p({
  // ...other options
  connectionProtector: preSharedKey({
    psk: generateKey(new Uint8Array(95))
  })
})

Keeping the same PeerId after a restart

The libp2p PeerId is a public/private keypair which is encrypted at rest by libp2p's @libp2p/keychain module.

As of libp2p@1.0.0 the keychain is no longer part of the default bundle so to replicate this behaviour you need to use the @libp2p/keychain module to load a peer id from the datastore before starting your node.

import { keychain, type KeychainInit } from '@libp2p/keychain'
import { defaultLogger } from '@libp2p/logger'
import { LevelDatastore } from 'datastore-level'
import { Key } from 'interface-datastore/key'
import { createLibp2p } from 'libp2p'

// the datastore should come from your config
const datastore = new LevelDatastore('/path/to/db')
// the keychain options should come from your config
const keychainInit: KeychainInit = {
  pass: 'very long, very secure password'
}

// if peerId is undefined, one will be generated
let peerId: PeerId | undefined

// try to load it from the keychain
const chain = keychain(keychainInit)({
  datastore,
  logger: defaultLogger()
})

const selfKey = new Key('/pkcs8/self')

if (await datastore.has(selfKey)) {
  // load the peer id from the keychain
  peerId = await chain.exportPeerId('self')
}

const node = await createLibp2p({
  peerId
  // ... other options
})

if (peerId != null && !await datastore.has(selfKey)) {
  // a new PeerId would have been generated so store it in the keychain for next time
  await chain.importPeer('self', libp2p.peerId)
}

Metrics

The following metrics were renamed:

libp2p_dialler_pending_dials => libp2p_dial_queue_pending_dials libp2p_dialler_in_progress_dials => libp2p_dial_queue_in_progress_dials

Connection Manager

The observed behavior of dialing peers has been that given a list of supported addresses, if any one routable address would succeed then all would succeed and that if any routable address would fail then all would fail.

Consequently the previous dial behaviour of dialing all available addresses (up to a concurrency limit) and cancelling any in-flight dials when the first succeeds was a very inefficient use of resources.

Since libp2p@0.46.10 we have only dialed one address at a time for each peer by setting the default value of the ConnectionManager's maxParallelDialsPerPeer option to 1. As of libp2p@1.0.0 this option has been removed.