Migrating to [email protected]
A migration guide for refactoring your application code from libp2p v0.28.x to v0.29.0.
The libp2p-gossipsub
javascript implementation is now upgraded according to the Gossipsub v1.1 spec and it packs several security hardening extensions. You can read more about it in its blogpost.
We leveraged this update to rethink the pubsub interface, in order to make it easier, as well as to be consistent with the API of the routers. Moreover, the interface was also reconstructed to ease new pubsub router implementations.
Libp2p prior to 0.29 unnecessarily added a layer of abstraction over the pubsub routers. We now expose the pubsub router API directly and have a test suite in the interface-pubsub to guarantee routers compliance. This enables more advanced usage of the underlying router.
Before
libp2p.pubsub._pubsub.*
libp2p.pubsub._pubsub.topicValidators.set(topic, validator)
After
libp2p.pubsub.*
libp2p.pubsub.topicValidators.set(topic, validator)
Publish uses Uint8Array
data instead of Buffer
.
Before
const topic = 'topic'
const data = Buffer.from('data')
await libp2p.pubsub.publish(topic, data)
After
const uint8ArrayFromString from 'uint8arrays/from-string')
const topic = 'topic'
const data = uint8ArrayFromString('data')
await libp2p.pubsub.publish(topic, data)
Handlers should no longer be passed when subscribing, instead, applications should bind event handlers for each topic they wish to subscribe too. This enables more flexibility at the application level without changing the underlying subscriptions.
Message data is now a Uint8Array
instead of Buffer
.
Before
const topic = 'topic'
const handler = (msg) => {
// msg.data - pubsub data received
const data = msg.data.toString()
}
libp2p.pubsub.subscribe(topic, handler)
After
const uint8ArrayToString from 'uint8arrays/to-string')
const topic = 'topic'
const handler = (msg) => {
// msg.data - pubsub data received
const data = uint8ArrayToString(msg.data)
}
libp2p.pubsub.on(topic, handler)
libp2p.pubsub.subscribe(topic)
In the latest release, despite not being documented in libp2p
the underlying pubsub routers supported subscribing to multiple topics at the same time. We removed that code complexity, since this is easily achieved in the application layer if needed.
Before
const topics = ['a', 'b']
const handler = (msg) => {
// msg.data - pubsub data received
const data = msg.data.toString()
}
libp2p.pubsub.subscribe(topics, handler)
After
const uint8ArrayToString from 'uint8arrays/to-string')
const topics = ['a', 'b']
const handler = (msg) => {
// msg.data - pubsub data received
const data = uint8ArrayToString(msg.data)
}
topics.forEach((topic) => {
libp2p.pubsub.on(topic, handler)
libp2p.pubsub.subscribe(topic)
})
Handlers should not be directly bound to the subscription anymore.
Before
const topic = 'topic'
const handler = (msg) => {
// msg.data - pubsub data received
}
libp2p.pubsub.unsubscribe(topic, handler)
After
const topic = 'topic'
const handler = (msg) => {
// msg.data - pubsub data received
}
libp2p.pubsub.removeListener(topic, handler)
libp2p.pubsub.unsubscribe(topic)
The validator function does not include the peer parameter anymore. It was redundant since it is included in the message and it could lead to issues as the peer that sent the message might not be the one who created the message in first place. The validator function should also throw an error instead of returning false
when the message is not valid.
Before
const validator = (msgTopic, peer, msg) => {
// process message
return false
}
libp2p.pubsub._pubsub.topicValidators.set(topic, validator)
After
const validator = (msgTopic, msg) => {
const from = msg.from
// process message
throw new Error('not a valid message')
}
libp2p.pubsub.topicValidators.set(topic, validator)
Aiming to improve libp2p browser support, we are moving away from node core modules unless we can guarantee that the code we are writing will not run in a browser. It is worth mentioning that modern JavaScript runtimes have TypedArrays such as Uint8Array backed by ArrayBuffers. All libp2p dependencies were also updated to use Uint8Array.
We use the uint8arrays utilities module to deal with Uint8Arrays
easily and we recommend its usage in the application layer. Thanks for the module @achingbrain! It includes utilities like compare
, concat
, equals
, fromString
and toString
. In this migration examples, we will be using the following:
const uint8ArrayFromString from 'uint8arrays/from-string')
const uint8ArrayToString from 'uint8arrays/to-string')
Before
const key = '/key'
const value = Buffer.from('oh hello there')
await libp2p.contentRouting.put(key, value)
After
const key = '/key'
const value = uint8ArrayFromString('oh hello there')
await libp2p.contentRouting.put(key, value)
Before
const key = '/key'
const value = await libp2p.contentRouting.put(key)
console.log('store value is: ', value.toString())
After
const key = '/key'
const value = await libp2p.contentRouting.put(key)
console.log('store value is: ', uint8ArrayToString(value))
Before
peerStore.metadataBook.set(peerId, 'location', Buffer.from('Saturn'))
After
peerStore.metadataBook.set(peerId, 'location', uint8ArrayFromString('Saturn'))
Before
const data = peerStore.metadataBook.get(peerId)
console.log('stored location: ', data.get('location').toString())
After
const data = peerStore.metadataBook.get(peerId)
console.log('stored location: ', uint8ArrayToString(data.get('location')))
Before
const location = peerStore.metadataBook.getValue(peerId, 'location')
console.log('stored location: ', location.toString())
After
const location = peerStore.metadataBook.getValue(peerId, 'location')
console.log('stored location: ', uint8ArrayToString(location))
Before
const keyInfo = await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
const enc = await libp2p.keychain.cms.encrypt('keyTest', Buffer.from('data'))
After
const keyInfo = await libp2p.keychain.createKey('keyTest', 'rsa', 4096)
const enc = await libp2p.keychain.cms.encrypt('keyTest', uint8ArrayFromString('data'))
Already specified in its own chapter above.
With this release you should update the following libp2p modules if you are relying on them:
"libp2p-bootstrap": "^0.12.0",
"libp2p-delegated-content-routing": "^0.6.0",
"libp2p-delegated-peer-routing": "^0.6.0",
"libp2p-floodsub": "^0.23.0",
"libp2p-gossipsub": "^0.6.0",
"libp2p-kad-dht": "^0.20.0",
"libp2p-mdns": "^0.15.0",
"libp2p-mplex": "^0.10.0",
"libp2p-noise": "^2.0.0",
"libp2p-secio": "^0.13.1",
"libp2p-tcp": "^0.15.1",
"libp2p-webrtc-star": "^0.20.0",
"libp2p-websockets": "^0.14.0",