A migration guide for refactoring your application code from libp2p v0.37.x to v0.38.0.
The type of streams has changed. Previously it was Duplex<Uint8Array>
, now it is Duplex<Uint8ArrayList, Uint8ArrayList | Uint8Array>
.
This means you will source Uint8ArrayList
s and sink Uint8ArrayList | Uint8Array
.
This has changed because bytes returned by stream sources are usually obtained from multiplexed streams. A single data message sent over these streams may be transmitted as multiple smaller messages, for example where the data being sent is bigger than the multiplexer's message size limit. To return a contiguous block of bytes as a Uint8Array
, where the bytes were sent as multiple message this would then involve a memory copy which is expensive.
Instead the stream will now yield Uint8ArrayList
s which can be backed by multiple Uint8Array
or subarrays of Uint8Array
which avoid the memory-copy penalty.
Either Uint8ArrayList
s or Uint8Array
s can be yielded to the stream sink and they will be handled transparently.
If you require Uint8Array
s in a stream handler, you can call .subarray
on the Uint8ArrayList
which will return a Uint8Array
of the list contents - where the list is backed by a single Uint8Array
it will be returned as-is, otherwise a new Uint8Array
will be created and the contents of the list's backing Uint8Array
s copied into it, which is similar to the behaviour of older libp2p
versions.
Before
const stream = await libp2p.dialProtocol(peerId, protocol)
await pipe(
stream,
async function * (source) {
for await (const buf of source) {
// buf is a Uint8Array
}
},
stream
)
After
const stream = await libp2p.dialProtocol(peerId, protocol)
await pipe(
stream,
async function * (source) {
for await (const list of source) {
// list is a Uint8ArrayList
const buf = list.subarray()
// buf is a Uint8Array, only convert if necessary to avoid copying memory
}
},
stream
)
[email protected]
brings a new mechanism for tagging peers in the peer store with values. These values are used to select connections to close when limits are reached, and there are also some special values that trigger certain behaviour like connecting to peers on startup.
The peer tagging mechanism replaces the notion of peer values in the connection manager.
Subsystems such as kad-dht
and gossipsub
will tag peers important to them (KAD-close or in topic meshes, for example) to ensure connections are prioritized appropriately.
When not specified, default values will be used as defined in the registrar.
Before
libp2p.connectionManager.setPeerValue(peerId, 0.5)
After
import { KEEP_ALIVE } from '@libp2p/interface-peer-store/tags'
// this peer will be connected to on startup and also reconnected to if the connection drops
await libp2p.connectionManager.tagPeer(peerId, KEEP_ALIVE)
await libp2p.connectionManager.tagPeer(peerId, 'my-tag-value', {
// a value 0-100
value: 0.5,
// an optional time in ms after which the tag will be removed
ttl: 1000
})
To prevent remote peers overloading nodes by opening excessive amounts of protocol streams, stream handlers can specify limits on how many streams can be open concurrently for that protocol.
Before
await libp2p.handle('/my-protocol/1.0.0', (stream) => {
// ...handle stream
})
After
await libp2p.handle('/my-protocol/1.0.0', (stream) => {
// ...handle stream
}, {
// specify the maximum number of concurrent inbound streams for this protocol
maxInboundStreams: 1,
// specify the maximum number of concurrent outbound streams for this protocol
maxOutboundStreams: 1
})
For built-in protocols, these can be configured using the createLibp2p
factory function:
Before
const node = await createLibp2p({
//... other options
})
After
const node = await createLibp2p({
identify: {
maxInboundStreams: 1,
maxOutboundStreams: 1,
maxPushIncomingStreams: 1,
maxPushOutgoingStreams: 1
},
ping: {
maxInboundStreams: 1,
maxOutboundStreams: 1,
},
fetch: {
maxInboundStreams: 1
maxOutboundStreams: 1
}
//... other options
})