Repository: libp2p/go-libp2p
Pull request #1275 (2021-12-30 14:00:59)

use the resource manager
Integrates the ResourceManager in go-libp2p; #1285 and #1289 have been squashed in.

TBD: 
- [ ] integration tests (see #1296)



Patch:
diff --git a/config/config.go b/config/config.go
index b3f80fa2..a9a26415 100644
--- a/config/config.go
+++ b/config/config.go
@@ -87,10 +87,12 @@ type Config struct {
 	AddrsFactory    bhost.AddrsFactory
 	ConnectionGater connmgr.ConnectionGater
 
-	ConnManager connmgr.ConnManager
-	NATManager  NATManagerC
-	Peerstore   peerstore.Peerstore
-	Reporter    metrics.Reporter
+	ConnManager     connmgr.ConnManager
+	ResourceManager network.ResourceManager
+
+	NATManager NATManagerC
+	Peerstore  peerstore.Peerstore
+	Reporter   metrics.Reporter
 
 	MultiaddrResolver *madns.Resolver
 
@@ -148,6 +150,9 @@ func (cfg *Config) makeSwarm() (*swarm.Swarm, error) {
 	if cfg.DialTimeout != 0 {
 		opts = append(opts, swarm.WithDialTimeout(cfg.DialTimeout))
 	}
+	if cfg.ResourceManager != nil {
+		opts = append(opts, swarm.WithResourceManager(cfg.ResourceManager))
+	}
 	// TODO: Make the swarm implementation configurable.
 	return swarm.NewSwarm(pid, cfg.Peerstore, opts...)
 }
@@ -179,11 +184,14 @@ func (cfg *Config) addTransports(h host.Host) error {
 	if cfg.ConnectionGater != nil {
 		opts = append(opts, tptu.WithConnectionGater(cfg.ConnectionGater))
 	}
+	if cfg.ResourceManager != nil {
+		opts = append(opts, tptu.WithResourceManager(cfg.ResourceManager))
+	}
 	upgrader, err := tptu.New(secure, muxer, opts...)
 	if err != nil {
 		return err
 	}
-	tpts, err := makeTransports(h, upgrader, cfg.ConnectionGater, cfg.PSK, cfg.Transports)
+	tpts, err := makeTransports(h, upgrader, cfg.ConnectionGater, cfg.PSK, cfg.ResourceManager, cfg.Transports)
 	if err != nil {
 		return err
 	}
diff --git a/config/constructor_types.go b/config/constructor_types.go
index af2f8ef4..631a44cd 100644
--- a/config/constructor_types.go
+++ b/config/constructor_types.go
@@ -7,7 +7,6 @@ import (
 	"github.com/libp2p/go-libp2p-core/connmgr"
 	"github.com/libp2p/go-libp2p-core/crypto"
 	"github.com/libp2p/go-libp2p-core/host"
-	"github.com/libp2p/go-libp2p-core/mux"
 	"github.com/libp2p/go-libp2p-core/network"
 	"github.com/libp2p/go-libp2p-core/peer"
 	"github.com/libp2p/go-libp2p-core/peerstore"
@@ -21,13 +20,14 @@ var (
 	hostType      = reflect.TypeOf((*host.Host)(nil)).Elem()
 	networkType   = reflect.TypeOf((*network.Network)(nil)).Elem()
 	transportType = reflect.TypeOf((*transport.Transport)(nil)).Elem()
-	muxType       = reflect.TypeOf((*mux.Multiplexer)(nil)).Elem()
+	muxType       = reflect.TypeOf((*network.Multiplexer)(nil)).Elem()
 	securityType  = reflect.TypeOf((*sec.SecureTransport)(nil)).Elem()
 	privKeyType   = reflect.TypeOf((*crypto.PrivKey)(nil)).Elem()
 	pubKeyType    = reflect.TypeOf((*crypto.PubKey)(nil)).Elem()
 	pstoreType    = reflect.TypeOf((*peerstore.Peerstore)(nil)).Elem()
 	connGaterType = reflect.TypeOf((*connmgr.ConnectionGater)(nil)).Elem()
 	upgraderType  = reflect.TypeOf((*transport.Upgrader)(nil)).Elem()
+	rcmgrType     = reflect.TypeOf((*network.ResourceManager)(nil)).Elem()
 
 	// concrete types
 	peerIDType = reflect.TypeOf((peer.ID)(""))
@@ -35,27 +35,36 @@ var (
 )
 
 var argTypes = map[reflect.Type]constructor{
-	upgraderType: func(_ host.Host, u transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater) interface{} { return u },
-	hostType:     func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater) interface{} { return h },
-	networkType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater) interface{} {
+	upgraderType: func(_ host.Host, u transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
+		return u
+	},
+	hostType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
+		return h
+	},
+	networkType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
 		return h.Network()
 	},
-	pskType: func(_ host.Host, _ transport.Upgrader, psk pnet.PSK, _ connmgr.ConnectionGater) interface{} {
+	pskType: func(_ host.Host, _ transport.Upgrader, psk pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
 		return psk
 	},
-	connGaterType: func(_ host.Host, _ transport.Upgrader, _ pnet.PSK, cg connmgr.ConnectionGater) interface{} { return cg },
-	peerIDType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater) interface{} {
+	connGaterType: func(_ host.Host, _ transport.Upgrader, _ pnet.PSK, cg connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
+		return cg
+	},
+	peerIDType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
 		return h.ID()
 	},
-	privKeyType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater) interface{} {
+	privKeyType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
 		return h.Peerstore().PrivKey(h.ID())
 	},
-	pubKeyType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater) interface{} {
+	pubKeyType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
 		return h.Peerstore().PubKey(h.ID())
 	},
-	pstoreType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater) interface{} {
+	pstoreType: func(h host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) interface{} {
 		return h.Peerstore()
 	},
+	rcmgrType: func(_ host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, rcmgr network.ResourceManager) interface{} {
+		return rcmgr
+	},
 }
 
 func newArgTypeSet(types ...reflect.Type) map[reflect.Type]constructor {
diff --git a/config/muxer.go b/config/muxer.go
index 2fcdb5cb..f59d204c 100644
--- a/config/muxer.go
+++ b/config/muxer.go
@@ -3,14 +3,15 @@ package config
 import (
 	"fmt"
 
-	"github.com/libp2p/go-libp2p-core/host"
-	"github.com/libp2p/go-libp2p-core/mux"
-
 	msmux "github.com/libp2p/go-stream-muxer-multistream"
+
+	"github.com/libp2p/go-libp2p-core/network"
+
+	"github.com/libp2p/go-libp2p-core/host"
 )
 
 // MuxC is a stream multiplex transport constructor.
-type MuxC func(h host.Host) (mux.Multiplexer, error)
+type MuxC func(h host.Host) (network.Multiplexer, error)
 
 // MsMuxC is a tuple containing a multiplex transport constructor and a protocol
 // ID.
@@ -25,8 +26,8 @@ var muxArgTypes = newArgTypeSet(hostType, networkType, peerIDType, pstoreType)
 // using reflection.
 func MuxerConstructor(m interface{}) (MuxC, error) {
 	// Already constructed?
-	if t, ok := m.(mux.Multiplexer); ok {
-		return func(_ host.Host) (mux.Multiplexer, error) {
+	if t, ok := m.(network.Multiplexer); ok {
+		return func(_ host.Host) (network.Multiplexer, error) {
 			return t, nil
 		}, nil
 	}
@@ -35,16 +36,16 @@ func MuxerConstructor(m interface{}) (MuxC, error) {
 	if err != nil {
 		return nil, err
 	}
-	return func(h host.Host) (mux.Multiplexer, error) {
-		t, err := ctor(h, nil, nil, nil)
+	return func(h host.Host) (network.Multiplexer, error) {
+		t, err := ctor(h, nil, nil, nil, nil)
 		if err != nil {
 			return nil, err
 		}
-		return t.(mux.Multiplexer), nil
+		return t.(network.Multiplexer), nil
 	}, nil
 }
 
-func makeMuxer(h host.Host, tpts []MsMuxC) (mux.Multiplexer, error) {
+func makeMuxer(h host.Host, tpts []MsMuxC) (network.Multiplexer, error) {
 	muxMuxer := msmux.NewBlankTransport()
 	transportSet := make(map[string]struct{}, len(tpts))
 	for _, tptC := range tpts {
diff --git a/config/reflection_magic.go b/config/reflection_magic.go
index db7f1e86..b086f85e 100644
--- a/config/reflection_magic.go
+++ b/config/reflection_magic.go
@@ -6,6 +6,8 @@ import (
 	"reflect"
 	"runtime"
 
+	"github.com/libp2p/go-libp2p-core/network"
+
 	"github.com/libp2p/go-libp2p-core/pnet"
 
 	"github.com/libp2p/go-libp2p-core/connmgr"
@@ -80,7 +82,7 @@ func callConstructor(c reflect.Value, args []reflect.Value) (interface{}, error)
 	return val, err
 }
 
-type constructor func(h host.Host, u transport.Upgrader, psk pnet.PSK, cg connmgr.ConnectionGater) interface{}
+type constructor func(host.Host, transport.Upgrader, pnet.PSK, connmgr.ConnectionGater, network.ResourceManager) interface{}
 
 func makeArgumentConstructors(fnType reflect.Type, argTypes map[reflect.Type]constructor) ([]constructor, error) {
 	params := fnType.NumIn()
@@ -131,7 +133,7 @@ func makeConstructor(
 	tptType reflect.Type,
 	argTypes map[reflect.Type]constructor,
 	opts ...interface{},
-) (func(host.Host, transport.Upgrader, pnet.PSK, connmgr.ConnectionGater) (interface{}, error), error) {
+) (func(host.Host, transport.Upgrader, pnet.PSK, connmgr.ConnectionGater, network.ResourceManager) (interface{}, error), error) {
 	v := reflect.ValueOf(tpt)
 	// avoid panicing on nil/zero value.
 	if v == (reflect.Value{}) {
@@ -155,10 +157,10 @@ func makeConstructor(
 		return nil, err
 	}
 
-	return func(h host.Host, u transport.Upgrader, psk pnet.PSK, cg connmgr.ConnectionGater) (interface{}, error) {
+	return func(h host.Host, u transport.Upgrader, psk pnet.PSK, cg connmgr.ConnectionGater, rcmgr network.ResourceManager) (interface{}, error) {
 		arguments := make([]reflect.Value, 0, len(argConstructors)+len(opts))
 		for i, makeArg := range argConstructors {
-			if arg := makeArg(h, u, psk, cg); arg != nil {
+			if arg := makeArg(h, u, psk, cg, rcmgr); arg != nil {
 				arguments = append(arguments, reflect.ValueOf(arg))
 			} else {
 				// ValueOf an un-typed nil yields a zero reflect
diff --git a/config/security.go b/config/security.go
index 599a7d8e..0f6c7887 100644
--- a/config/security.go
+++ b/config/security.go
@@ -42,7 +42,7 @@ func SecurityConstructor(security interface{}) (SecC, error) {
 		return nil, err
 	}
 	return func(h host.Host) (sec.SecureTransport, error) {
-		t, err := ctor(h, nil, nil, nil)
+		t, err := ctor(h, nil, nil, nil, nil)
 		if err != nil {
 			return nil, err
 		}
diff --git a/config/transport.go b/config/transport.go
index ffd59e4c..c1a5f4ef 100644
--- a/config/transport.go
+++ b/config/transport.go
@@ -3,6 +3,7 @@ package config
 import (
 	"github.com/libp2p/go-libp2p-core/connmgr"
 	"github.com/libp2p/go-libp2p-core/host"
+	"github.com/libp2p/go-libp2p-core/network"
 	"github.com/libp2p/go-libp2p-core/pnet"
 	"github.com/libp2p/go-libp2p-core/transport"
 )
@@ -10,7 +11,7 @@ import (
 // TptC is the type for libp2p transport constructors. You probably won't ever
 // implement this function interface directly. Instead, pass your transport
 // constructor to TransportConstructor.
-type TptC func(host.Host, transport.Upgrader, pnet.PSK, connmgr.ConnectionGater) (transport.Transport, error)
+type TptC func(host.Host, transport.Upgrader, pnet.PSK, connmgr.ConnectionGater, network.ResourceManager) (transport.Transport, error)
 
 var transportArgTypes = argTypes
 
@@ -38,7 +39,7 @@ var transportArgTypes = argTypes
 func TransportConstructor(tpt interface{}, opts ...interface{}) (TptC, error) {
 	// Already constructed?
 	if t, ok := tpt.(transport.Transport); ok {
-		return func(_ host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater) (transport.Transport, error) {
+		return func(_ host.Host, _ transport.Upgrader, _ pnet.PSK, _ connmgr.ConnectionGater, _ network.ResourceManager) (transport.Transport, error) {
 			return t, nil
 		}, nil
 	}
@@ -46,8 +47,8 @@ func TransportConstructor(tpt interface{}, opts ...interface{}) (TptC, error) {
 	if err != nil {
 		return nil, err
 	}
-	return func(h host.Host, u transport.Upgrader, psk pnet.PSK, cg connmgr.ConnectionGater) (transport.Transport, error) {
-		t, err := ctor(h, u, psk, cg)
+	return func(h host.Host, u transport.Upgrader, psk pnet.PSK, cg connmgr.ConnectionGater, rcmgr network.ResourceManager) (transport.Transport, error) {
+		t, err := ctor(h, u, psk, cg, rcmgr)
 		if err != nil {
 			return nil, err
 		}
@@ -55,10 +56,10 @@ func TransportConstructor(tpt interface{}, opts ...interface{}) (TptC, error) {
 	}, nil
 }
 
-func makeTransports(h host.Host, u transport.Upgrader, cg connmgr.ConnectionGater, psk pnet.PSK, tpts []TptC) ([]transport.Transport, error) {
+func makeTransports(h host.Host, u transport.Upgrader, cg connmgr.ConnectionGater, psk pnet.PSK, rcmgr network.ResourceManager, tpts []TptC) ([]transport.Transport, error) {
 	transports := make([]transport.Transport, len(tpts))
 	for i, tC := range tpts {
-		t, err := tC(h, u, psk, cg)
+		t, err := tC(h, u, psk, cg, rcmgr)
 		if err != nil {
 			return nil, err
 		}
diff --git a/defaults.go b/defaults.go
index f6e0cc0f..21b7f0b0 100644
--- a/defaults.go
+++ b/defaults.go
@@ -10,6 +10,7 @@ import (
 	noise "github.com/libp2p/go-libp2p-noise"
 	"github.com/libp2p/go-libp2p-peerstore/pstoremem"
 	quic "github.com/libp2p/go-libp2p-quic-transport"
+	rcmgr "github.com/libp2p/go-libp2p-resource-manager"
 	tls "github.com/libp2p/go-libp2p-tls"
 	yamux "github.com/libp2p/go-libp2p-yamux"
 	"github.com/libp2p/go-tcp-transport"
@@ -85,6 +86,19 @@ var DefaultEnableRelay = func(cfg *Config) error {
 	return cfg.Apply(EnableRelay())
 }
 
+var DefaultResourceManager = func(cfg *Config) error {
+	// Default memory limit: 1/8th of total memory, minimum 128MB, maximum 1GB
+	limiter := rcmgr.NewDefaultLimiter()
+	SetDefaultServiceLimits(limiter)
+
+	mgr, err := rcmgr.NewResourceManager(limiter)
+	if err != nil {
+		return err
+	}
+
+	return cfg.Apply(ResourceManager(mgr))
+}
+
 // Complete list of default options and when to fallback on them.
 //
 // Please *DON'T* specify default options any other way. Putting this all here
@@ -121,6 +135,10 @@ var defaults = []struct {
 		fallback: func(cfg *Config) bool { return !cfg.RelayCustom },
 		opt:      DefaultEnableRelay,
 	},
+	{
+		fallback: func(cfg *Config) bool { return cfg.ResourceManager == nil },
+		opt:      DefaultResourceManager,
+	},
 }
 
 // Defaults configures libp2p to use the default options. Can be combined with
diff --git a/go.mod b/go.mod
index a85fea32..64baa973 100644
--- a/go.mod
+++ b/go.mod
@@ -22,23 +22,24 @@ require (
 	github.com/libp2p/go-eventbus v0.2.1
 	github.com/libp2p/go-libp2p-asn-util v0.1.0
 	github.com/libp2p/go-libp2p-blankhost v0.3.0
-	github.com/libp2p/go-libp2p-circuit v0.4.1-0.20220104091935-28fb8d25f785
-	github.com/libp2p/go-libp2p-core v0.13.1-0.20220104083644-a3dd401efe36
-	github.com/libp2p/go-libp2p-mplex v0.4.1
+	github.com/libp2p/go-libp2p-circuit v0.6.0
+	github.com/libp2p/go-libp2p-core v0.14.0
+	github.com/libp2p/go-libp2p-mplex v0.5.0
 	github.com/libp2p/go-libp2p-nat v0.1.0
 	github.com/libp2p/go-libp2p-noise v0.3.0
 	github.com/libp2p/go-libp2p-peerstore v0.6.0
-	github.com/libp2p/go-libp2p-quic-transport v0.15.2
-	github.com/libp2p/go-libp2p-swarm v0.9.1-0.20220104091227-f776b7e504b1
-	github.com/libp2p/go-libp2p-testing v0.6.1-0.20211214061856-c642a397cccd
+	github.com/libp2p/go-libp2p-quic-transport v0.16.0
+	github.com/libp2p/go-libp2p-resource-manager v0.1.0
+	github.com/libp2p/go-libp2p-swarm v0.10.0
+	github.com/libp2p/go-libp2p-testing v0.7.0
 	github.com/libp2p/go-libp2p-tls v0.3.1
-	github.com/libp2p/go-libp2p-transport-upgrader v0.6.1-0.20220104084635-5fc0a74b41f0
-	github.com/libp2p/go-libp2p-yamux v0.7.0
+	github.com/libp2p/go-libp2p-transport-upgrader v0.7.0
+	github.com/libp2p/go-libp2p-yamux v0.8.0
 	github.com/libp2p/go-msgio v0.1.0
-	github.com/libp2p/go-netroute v0.1.6
-	github.com/libp2p/go-stream-muxer-multistream v0.3.0
-	github.com/libp2p/go-tcp-transport v0.4.1-0.20220104085503-4ad75e6f32a5
-	github.com/libp2p/go-ws-transport v0.5.1-0.20220104085536-0bac7beec89d
+	github.com/libp2p/go-netroute v0.2.0
+	github.com/libp2p/go-stream-muxer-multistream v0.4.0
+	github.com/libp2p/go-tcp-transport v0.5.0
+	github.com/libp2p/go-ws-transport v0.6.0
 	github.com/libp2p/zeroconf/v2 v2.1.1
 	github.com/multiformats/go-multiaddr v0.5.0
 	github.com/multiformats/go-multiaddr-dns v0.3.1
diff --git a/go.sum b/go.sum
index fa2a955d..eef606d9 100644
--- a/go.sum
+++ b/go.sum
@@ -334,7 +334,6 @@ github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscw
 github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
 github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g=
 github.com/ipfs/go-log/v2 v2.3.0/go.mod h1:QqGoj30OTpnKaG/LKTGTxoP2mmQtjVMEnK72gynbe/g=
-github.com/ipfs/go-log/v2 v2.4.0/go.mod h1:nPZnh7Cj7lwS3LpRU5Mwr2ol1c2gXIEXuF6aywqrtmo=
 github.com/ipfs/go-log/v2 v2.5.0 h1:+MhAooFd9XZNvR0i9FriKW6HB0ql7HNXUuflWtc0dd4=
 github.com/ipfs/go-log/v2 v2.5.0/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI=
 github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus=
@@ -368,8 +367,9 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
 github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
-github.com/klauspost/compress v1.11.7 h1:0hzRabrMN4tSTvMfnL3SCv1ZGeAP23ynzodBgaHeMeg=
 github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
+github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
+github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
 github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
 github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
@@ -405,8 +405,8 @@ github.com/libp2p/go-libp2p-asn-util v0.1.0/go.mod h1:wu+AnM9Ii2KgO5jMmS1rz9dvzT
 github.com/libp2p/go-libp2p-blankhost v0.2.0/go.mod h1:eduNKXGTioTuQAUcZ5epXi9vMl+t4d8ugUBRQ4SqaNQ=
 github.com/libp2p/go-libp2p-blankhost v0.3.0 h1:kTnLArltMabZlzY63pgGDA4kkUcLkBFSM98zBssn/IY=
 github.com/libp2p/go-libp2p-blankhost v0.3.0/go.mod h1:urPC+7U01nCGgJ3ZsV8jdwTp6Ji9ID0dMTvq+aJ+nZU=
-github.com/libp2p/go-libp2p-circuit v0.4.1-0.20220104091935-28fb8d25f785 h1:zMKE9nQDjrfHoTFUMVAvY5GDYS7EYkr3oWNJjm729j0=
-github.com/libp2p/go-libp2p-circuit v0.4.1-0.20220104091935-28fb8d25f785/go.mod h1:RsRUIXmHoYoSgM/Xi2dQY+YcWaBiK0oLpGkPwhsHNDk=
+github.com/libp2p/go-libp2p-circuit v0.6.0 h1:rw/HlhmUB3OktS/Ygz6+2XABOmHKzZpPUuMNUMosj8w=
+github.com/libp2p/go-libp2p-circuit v0.6.0/go.mod h1:kB8hY+zCpMeScyvFrKrGicRdid6vNXbunKE4rXATZ0M=
 github.com/libp2p/go-libp2p-core v0.2.0/go.mod h1:X0eyB0Gy93v0DZtSYbEM7RnMChm9Uv3j7yRXjO77xSI=
 github.com/libp2p/go-libp2p-core v0.3.0/go.mod h1:ACp3DmS3/N64c2jDzcV429ukDpicbL6+TrrxANBjPGw=
 github.com/libp2p/go-libp2p-core v0.5.0/go.mod h1:49XGI+kc38oGVwqSBhDEwytaAxgZasHhFfQKibzTls0=
@@ -418,10 +418,11 @@ github.com/libp2p/go-libp2p-core v0.8.6/go.mod h1:dgHr0l0hIKfWpGpqAMbpo19pen9wJf
 github.com/libp2p/go-libp2p-core v0.10.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg=
 github.com/libp2p/go-libp2p-core v0.11.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg=
 github.com/libp2p/go-libp2p-core v0.12.0/go.mod h1:ECdxehoYosLYHgDDFa2N4yE8Y7aQRAMf0sX9mf2sbGg=
-github.com/libp2p/go-libp2p-core v0.13.1-0.20220104083644-a3dd401efe36 h1:b/pMmgc5EV+dqSc+MjkX5xPa1nV6EKiOb0L0XT03Lic=
-github.com/libp2p/go-libp2p-core v0.13.1-0.20220104083644-a3dd401efe36/go.mod h1:KlkHsZ0nKerWsXLZJm3LfFQwusI5k3iN4BgtYTE4IYE=
-github.com/libp2p/go-libp2p-mplex v0.4.1 h1:/pyhkP1nLwjG3OM+VuaNJkQT/Pqq73WzB3aDN3Fx1sc=
+github.com/libp2p/go-libp2p-core v0.14.0 h1:0kYSgiK/D7Eo28GTuRXo5YHsWwAisVpFCqCVPUd/vJs=
+github.com/libp2p/go-libp2p-core v0.14.0/go.mod h1:tLasfcVdTXnixsLB0QYaT1syJOhsbrhG7q6pGrHtBg8=
 github.com/libp2p/go-libp2p-mplex v0.4.1/go.mod h1:cmy+3GfqfM1PceHTLL7zQzAAYaryDu6iPSC+CIb094g=
+github.com/libp2p/go-libp2p-mplex v0.5.0 h1:vt3k4E4HSND9XH4Z8rUpacPJFSAgLOv6HDvG8W9Ks9E=
+github.com/libp2p/go-libp2p-mplex v0.5.0/go.mod h1:eLImPJLkj3iG5t5lq68w3Vm5NAQ5BcKwrrb2VmOYb3M=
 github.com/libp2p/go-libp2p-nat v0.1.0 h1:vigUi2MEN+fwghe5ijpScxtbbDz+L/6y8XwlzYOJgSY=
 github.com/libp2p/go-libp2p-nat v0.1.0/go.mod h1:DQzAG+QbDYjN1/C3B6vXucLtz3u9rEonLVPtZVzQqks=
 github.com/libp2p/go-libp2p-noise v0.3.0 h1:NCVH7evhVt9njbTQshzT7N1S3Q6fjj9M11FCgfH5+cA=
@@ -432,30 +433,32 @@ github.com/libp2p/go-libp2p-peerstore v0.6.0/go.mod h1:DGEmKdXrcYpK9Jha3sS7MhqYd
 github.com/libp2p/go-libp2p-pnet v0.2.0 h1:J6htxttBipJujEjz1y0a5+eYoiPcFHhSYHH6na5f0/k=
 github.com/libp2p/go-libp2p-pnet v0.2.0/go.mod h1:Qqvq6JH/oMZGwqs3N1Fqhv8NVhrdYcO0BW4wssv21LA=
 github.com/libp2p/go-libp2p-quic-transport v0.13.0/go.mod h1:39/ZWJ1TW/jx1iFkKzzUg00W6tDJh73FC0xYudjr7Hc=
-github.com/libp2p/go-libp2p-quic-transport v0.15.2 h1:wHBEceRy+1/8Ec8dAIyr+/P7L2YefIGprPVy5LrMM+k=
-github.com/libp2p/go-libp2p-quic-transport v0.15.2/go.mod h1:wv4uGwjcqe8Mhjj7N/Ic0aKjA+/10UnMlSzLO0yRpYQ=
+github.com/libp2p/go-libp2p-quic-transport v0.16.0 h1:aVg9/jr+R2esov5sH7wkXrmYmqJiUjtLMLYX3L9KYdY=
+github.com/libp2p/go-libp2p-quic-transport v0.16.0/go.mod h1:1BXjVMzr+w7EkPfiHkKnwsWjPjtfaNT0q8RS3tGDvEQ=
+github.com/libp2p/go-libp2p-resource-manager v0.1.0 h1:tYpbhLPVC4egLavupAi9jGKKLeMemyGq5tnfBc8taBs=
+github.com/libp2p/go-libp2p-resource-manager v0.1.0/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y=
 github.com/libp2p/go-libp2p-swarm v0.8.0/go.mod h1:sOMp6dPuqco0r0GHTzfVheVBh6UEL0L1lXUZ5ot2Fvc=
-github.com/libp2p/go-libp2p-swarm v0.9.1-0.20220104091227-f776b7e504b1 h1:LsJE5h8hrv/WtmrxNi4WV+ctN0/ut7XxTl8hQu8VV2c=
-github.com/libp2p/go-libp2p-swarm v0.9.1-0.20220104091227-f776b7e504b1/go.mod h1:BTllovQKjG9wYSVE9vP14kg7tSTW8ECcOlVXod2dgRs=
+github.com/libp2p/go-libp2p-swarm v0.10.0 h1:1yr7UCwxCN92cw9g9Q+fnJSlk7lOB1RetoEewxhGVL0=
+github.com/libp2p/go-libp2p-swarm v0.10.0/go.mod h1:71ceMcV6Rg/0rIQ97rsZWMzto1l9LnNquef+efcRbmA=
 github.com/libp2p/go-libp2p-testing v0.1.1/go.mod h1:xaZWMJrPUM5GlDBxCeGUi7kI4eqnjVyavGroI2nxEM0=
 github.com/libp2p/go-libp2p-testing v0.1.2-0.20200422005655-8775583591d8/go.mod h1:Qy8sAncLKpwXtS2dSnDOP8ktexIAHKu+J+pnZOFZLTc=
 github.com/libp2p/go-libp2p-testing v0.4.0/go.mod h1:Q+PFXYoiYFN5CAEG2w3gLPEzotlKsNSbKQ/lImlOWF0=
 github.com/libp2p/go-libp2p-testing v0.5.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A=
-github.com/libp2p/go-libp2p-testing v0.6.0/go.mod h1:QBk8fqIL1XNcno/l3/hhaIEn4aLRijpYOR+zVjjlh+A=
-github.com/libp2p/go-libp2p-testing v0.6.1-0.20211214061856-c642a397cccd h1:kGqONcelOVC+DxSuhhLYZ6itE64pKi6/Omxmu0kyp8I=
-github.com/libp2p/go-libp2p-testing v0.6.1-0.20211214061856-c642a397cccd/go.mod h1:fi7jML2yROjVlnDhVwd45iGA6KP2Auaet/oCmyI/9u8=
+github.com/libp2p/go-libp2p-testing v0.7.0 h1:9bfyhNINizxuLrKsenzGaZalXRXIaAEmx1BP/PzF1gM=
+github.com/libp2p/go-libp2p-testing v0.7.0/go.mod h1:OLbdn9DbgdMwv00v+tlp1l3oe2Cl+FAjoWIA2pa0X6E=
 github.com/libp2p/go-libp2p-tls v0.3.0/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY=
 github.com/libp2p/go-libp2p-tls v0.3.1 h1:lsE2zYte+rZCEOHF72J1Fg3XK3dGQyKvI6i5ehJfEp0=
 github.com/libp2p/go-libp2p-tls v0.3.1/go.mod h1:fwF5X6PWGxm6IDRwF3V8AVCCj/hOd5oFlg+wo2FxJDY=
 github.com/libp2p/go-libp2p-transport-upgrader v0.5.0/go.mod h1:Rc+XODlB3yce7dvFV4q/RmyJGsFcCZRkeZMu/Zdg0mo=
-github.com/libp2p/go-libp2p-transport-upgrader v0.6.1-0.20220104084635-5fc0a74b41f0 h1:eD/QJCpcImYOUl6MdBuxMByVaEe5VMm463zJG6oUg9o=
-github.com/libp2p/go-libp2p-transport-upgrader v0.6.1-0.20220104084635-5fc0a74b41f0/go.mod h1:ByIyNe8asQhgcyIHetb4f+UgV+hDrA8pQ3L/TgNs+RI=
+github.com/libp2p/go-libp2p-transport-upgrader v0.7.0 h1:ADnLrL7fC4Vy7HPjk9oGof7nDeTqGXuof85Ar6kin9Q=
+github.com/libp2p/go-libp2p-transport-upgrader v0.7.0/go.mod h1:GIR2aTRp1J5yjVlkUoFqMkdobfob6RnAwYg/RZPhrzg=
 github.com/libp2p/go-libp2p-yamux v0.5.0/go.mod h1:AyR8k5EzyM2QN9Bbdg6X1SkVVuqLwTGf0L4DFq9g6po=
-github.com/libp2p/go-libp2p-yamux v0.7.0 h1:bVXHbTj/XH4uBBsPrg26BlDABk5WYRlssY73P0SjhPc=
-github.com/libp2p/go-libp2p-yamux v0.7.0/go.mod h1:fMyA0CsPfHkIuBU0wjRGrCjTBFiXTXxG0k5M4ETv+08=
+github.com/libp2p/go-libp2p-yamux v0.8.0 h1:APQYlttIj+Rr5sfa6siojwsi0ZwcIh/exHIUl9hZr6o=
+github.com/libp2p/go-libp2p-yamux v0.8.0/go.mod h1:yTkPgN2ib8FHyU1ZcVD7aelzyAqXXwEPbyx+aSKm9h8=
 github.com/libp2p/go-maddr-filter v0.1.0/go.mod h1:VzZhTXkMucEGGEOSKddrwGiOv0tUhgnKqNEmIAz/bPU=
-github.com/libp2p/go-mplex v0.3.0 h1:U1T+vmCYJaEoDJPV1aq31N56hS+lJgb397GsylNSgrU=
 github.com/libp2p/go-mplex v0.3.0/go.mod h1:0Oy/A9PQlwBytDRp4wSkFnzHYDKcpLot35JQ6msjvYQ=
+github.com/libp2p/go-mplex v0.4.0 h1:Ukkez9/4EOX5rTw4sHefNJp10dksftAA05ZgyjplUbM=
+github.com/libp2p/go-mplex v0.4.0/go.mod h1:y26Lx+wNVtMYMaPu300Cbot5LkEZ4tJaNYeHeT9dh6E=
 github.com/libp2p/go-msgio v0.0.4/go.mod h1:63lBBgOTDKQL6EWazRMCwXsEeEeK9O2Cd+0+6OOuipQ=
 github.com/libp2p/go-msgio v0.0.6/go.mod h1:4ecVB6d9f4BDSL5fqvPiC4A3KivjWn+Venn/1ALLMWA=
 github.com/libp2p/go-msgio v0.1.0 h1:8Q7g/528ivAlfXTFWvWhVjTE8XG8sDTkRUKPYh9+5Q8=
@@ -465,8 +468,8 @@ github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC
 github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
 github.com/libp2p/go-netroute v0.1.3/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk=
 github.com/libp2p/go-netroute v0.1.5/go.mod h1:V1SR3AaECRkEQCoFFzYwVYWvYIEtlxx89+O3qcpCl4A=
-github.com/libp2p/go-netroute v0.1.6 h1:ruPJStbYyXVYGQ81uzEDzuvbYRLKRrLvTYd33yomC38=
-github.com/libp2p/go-netroute v0.1.6/go.mod h1:AqhkMh0VuWmfgtxKPp3Oc1LdU5QSWS7wl0QLhSZqXxQ=
+github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE=
+github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI=
 github.com/libp2p/go-openssl v0.0.4/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
 github.com/libp2p/go-openssl v0.0.5/go.mod h1:unDrJpgy3oFr+rqXsarWifmJuNnJR4chtO1HmaZjggc=
 github.com/libp2p/go-openssl v0.0.7 h1:eCAzdLejcNVBzP/iZM9vqHnQm+XyCEbSSIheIPRGNsw=
@@ -477,26 +480,25 @@ github.com/libp2p/go-reuseport-transport v0.1.0 h1:C3PHeHjmnz8m6f0uydObj02tMEoi7
 github.com/libp2p/go-reuseport-transport v0.1.0/go.mod h1:vev0C0uMkzriDY59yFHD9v+ujJvYmDQVLowvAjEOmfw=
 github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
 github.com/libp2p/go-sockaddr v0.1.0/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
-github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ=
-github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k=
-github.com/libp2p/go-stream-muxer-multistream v0.3.0 h1:TqnSHPJEIqDEO7h1wZZ0p3DXdvDSiLHQidKKUGZtiOY=
 github.com/libp2p/go-stream-muxer-multistream v0.3.0/go.mod h1:yDh8abSIzmZtqtOt64gFJUXEryejzNb0lisTt+fAMJA=
+github.com/libp2p/go-stream-muxer-multistream v0.4.0 h1:HsM/9OdtqnIzjVXcxTXjmqKrj3gJ8kacaOJwJS1ipaY=
+github.com/libp2p/go-stream-muxer-multistream v0.4.0/go.mod h1:nb+dGViZleRP4XcyHuZSVrJCBl55nRBOMmiSL/dyziw=
 github.com/libp2p/go-tcp-transport v0.4.0/go.mod h1:0y52Rwrn4076xdJYu/51/qJIdxz+EWDAOG2S45sV3VI=
-github.com/libp2p/go-tcp-transport v0.4.1-0.20220104085503-4ad75e6f32a5 h1:/x3GSszKipn1nlKY0C5at59fBLYyJeObd5gm32DrobM=
-github.com/libp2p/go-tcp-transport v0.4.1-0.20220104085503-4ad75e6f32a5/go.mod h1:YPwlF5gW5BnFikKoQBuJeQkPXAn+z2wTzDpJKamkgjY=
-github.com/libp2p/go-ws-transport v0.5.1-0.20220104085536-0bac7beec89d h1:2C9MSQsQ4teo3JRtBlN2CbS6xXC/Qk40kgMFO0rdjEM=
-github.com/libp2p/go-ws-transport v0.5.1-0.20220104085536-0bac7beec89d/go.mod h1:aXV24UYVRjIiMXhs+/qygvfYklQmhUzmhVi5cSiQu5Y=
+github.com/libp2p/go-tcp-transport v0.5.0 h1:3ZPW8HAuyRAuFzyabE0hSrCXKKSWzROnZZX7DtcIatY=
+github.com/libp2p/go-tcp-transport v0.5.0/go.mod h1:UPPL0DIjQqiWRwVAb+CEQlaAG0rp/mCqJfIhFcLHc4Y=
+github.com/libp2p/go-ws-transport v0.6.0 h1:326XBL6Q+5CQ2KtjXz32+eGu02W/Kz2+Fm4SpXdr0q4=
+github.com/libp2p/go-ws-transport v0.6.0/go.mod h1:dXqtI9e2JV9FtF1NOtWVZSKXh5zXvnuwPXfj8GPBbYU=
 github.com/libp2p/go-yamux v1.4.1 h1:P1Fe9vF4th5JOxxgQvfbOHkrGqIZniTLf+ddhZp8YTI=
 github.com/libp2p/go-yamux v1.4.1/go.mod h1:fr7aVgmdNGJK+N1g+b6DW6VxzbRCjCOejR/hkmpooHE=
-github.com/libp2p/go-yamux/v2 v2.3.0 h1:luRV68GS1vqqr6EFUjtu1kr51d+IbW0gSowu8emYWAI=
-github.com/libp2p/go-yamux/v2 v2.3.0/go.mod h1:iTU+lOIn/2h0AgKcL49clNTwfEw+WSfDYrXe05EyKIs=
+github.com/libp2p/go-yamux/v3 v3.0.1 h1:lIdxHGVZ+y/EHgCrqGNt4Q+Mk9qu26MbOWH/yRw+Ihk=
+github.com/libp2p/go-yamux/v3 v3.0.1/go.mod h1:s2LsDhHbh+RfCsQoICSYt58U2f8ijtPANFD8BmE74Bo=
 github.com/libp2p/zeroconf/v2 v2.1.1 h1:XAuSczA96MYkVwH+LqqqCUZb2yH3krobMJ1YE+0hG2s=
 github.com/libp2p/zeroconf/v2 v2.1.1/go.mod h1:fuJqLnUwZTshS3U/bMRJ3+ow/v9oid1n0DmyYyNO1Xs=
 github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
 github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
 github.com/lucas-clemente/quic-go v0.23.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
-github.com/lucas-clemente/quic-go v0.24.0 h1:ToR7SIIEdrgOhgVTHvPgdVRJfgVy+N0wQAagH7L4d5g=
-github.com/lucas-clemente/quic-go v0.24.0/go.mod h1:paZuzjXCE5mj6sikVLMvqXk8lJV2AsqtJ6bDhjEfxx0=
+github.com/lucas-clemente/quic-go v0.25.0 h1:K+X9Gvd7JXsOHtU0N2icZ2Nw3rx82uBej3mP4CLgibc=
+github.com/lucas-clemente/quic-go v0.25.0/go.mod h1:YtzP8bxRVCBlO77yRanE264+fY/T2U9ZlW1AaHOsMOg=
 github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
 github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -508,6 +510,8 @@ github.com/marten-seemann/qtls-go1-16 v0.1.4 h1:xbHbOGGhrenVtII6Co8akhLEdrawwB2i
 github.com/marten-seemann/qtls-go1-16 v0.1.4/go.mod h1:gNpI2Ol+lRS3WwSOtIUUtRwZEQMXjYK+dQSBFbethAk=
 github.com/marten-seemann/qtls-go1-17 v0.1.0 h1:P9ggrs5xtwiqXv/FHNwntmuLMNq3KaSIG93AtAZ48xk=
 github.com/marten-seemann/qtls-go1-17 v0.1.0/go.mod h1:fz4HIxByo+LlWcreM4CZOYNuz3taBQ8rN2X6FqvaWo8=
+github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1 h1:EnzzN9fPUkUck/1CuY1FlzBaIYMoiBsdwTNmNGkwUUM=
+github.com/marten-seemann/qtls-go1-18 v0.1.0-beta.1/go.mod h1:PUhIQk19LoFt2174H4+an8TYvWOGjb/hHwphBeaDHwI=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk=
 github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -639,7 +643,6 @@ github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go
 github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
 github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
 github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
 github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
 github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8=
@@ -648,6 +651,8 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh
 github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
 github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
+github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0=
+github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
diff --git a/limits.go b/limits.go
new file mode 100644
index 00000000..a2a7664f
--- /dev/null
+++ b/limits.go
@@ -0,0 +1,157 @@
+package libp2p
+
+import (
+	"github.com/libp2p/go-libp2p-core/protocol"
+
+	"github.com/libp2p/go-libp2p/p2p/host/autonat"
+	relayv1 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv1/relay"
+	circuit "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/proto"
+	relayv2 "github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
+	"github.com/libp2p/go-libp2p/p2p/protocol/holepunch"
+	"github.com/libp2p/go-libp2p/p2p/protocol/identify"
+	"github.com/libp2p/go-libp2p/p2p/protocol/ping"
+
+	rcmgr "github.com/libp2p/go-libp2p-resource-manager"
+)
+
+// SetDefaultServiceLimits sets the default limits for bundled libp2p services
+//
+// More specifically this sets the following limits:
+// - identify:
+//   128 streams in, 128 streams out, 256 streams total, 4MB min, 64MB max svc memory
+//   16/16/32 streams per peer
+// - ping:
+//   128 streams in, 128 sreams out, 256 streasms total, 4MB min, 64MB max svc memory
+//   2/3/4 streams per peer
+// - autonat
+//   128 streams in, 128 streams out, 128 streams total, 4MB min, 64MB max svc memory
+//   2/2/2 streams per peer
+// - holepunch
+//   128 streams in, 128 streams out, 128 streams total, 4MB min, 64MB max svc memory
+//   2/2/2 streams per peer
+// - relay v1 and v2 (separate services)
+//   1024 streams in, 1024 streams out, 1024 streams total, 4MB min, 64MB max svc memory
+//   64/64/64 streams per peer
+func SetDefaultServiceLimits(limiter *rcmgr.BasicLimiter) {
+	if limiter.ServiceLimits == nil {
+		limiter.ServiceLimits = make(map[string]rcmgr.Limit)
+	}
+	if limiter.ServicePeerLimits == nil {
+		limiter.ServicePeerLimits = make(map[string]rcmgr.Limit)
+	}
+	if limiter.ProtocolLimits == nil {
+		limiter.ProtocolLimits = make(map[protocol.ID]rcmgr.Limit)
+	}
+	if limiter.ProtocolPeerLimits == nil {
+		limiter.ProtocolPeerLimits = make(map[protocol.ID]rcmgr.Limit)
+	}
+
+	// identify
+	setServiceLimits(limiter, identify.ServiceName,
+		limiter.DefaultServiceLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
+			WithStreamLimit(128, 128, 256),    // max 256 streams -- symmetric
+		peerLimit(16, 16, 32))
+
+	setProtocolLimits(limiter, identify.ID,
+		limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20),
+		peerLimit(16, 16, 32))
+	setProtocolLimits(limiter, identify.IDPush,
+		limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20),
+		peerLimit(16, 16, 32))
+	setProtocolLimits(limiter, identify.IDDelta,
+		limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 32<<20),
+		peerLimit(16, 16, 32))
+
+	// ping
+	setServiceLimits(limiter, ping.ServiceName,
+		limiter.DefaultServiceLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
+			WithStreamLimit(128, 128, 128),    // max 128 streams - asymmetric
+		peerLimit(2, 3, 4))
+	setProtocolLimits(limiter, ping.ID,
+		limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20),
+		peerLimit(2, 3, 4))
+
+	// autonat
+	setServiceLimits(limiter, autonat.ServiceName,
+		limiter.DefaultServiceLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
+			WithStreamLimit(128, 128, 128),    // max 128 streams - asymmetric
+		peerLimit(2, 2, 2))
+	setProtocolLimits(limiter, autonat.AutoNATProto,
+		limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20),
+		peerLimit(2, 2, 2))
+
+	// holepunch
+	setServiceLimits(limiter, holepunch.ServiceName,
+		limiter.DefaultServiceLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
+			WithStreamLimit(128, 128, 256),    // max 256 streams - symmetric
+		peerLimit(2, 2, 2))
+	setProtocolLimits(limiter, holepunch.Protocol,
+		limiter.DefaultProtocolLimits.WithMemoryLimit(1, 4<<20, 64<<20),
+		peerLimit(2, 2, 2))
+
+	// relay/v1
+	setServiceLimits(limiter, relayv1.ServiceName,
+		limiter.DefaultServiceLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
+			WithStreamLimit(1024, 1024, 1024), // max 1024 streams - asymmetric
+		peerLimit(64, 64, 64))
+
+	// relay/v2
+	setServiceLimits(limiter, relayv2.ServiceName,
+		limiter.DefaultServiceLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20). // max 64MB service memory
+			WithStreamLimit(1024, 1024, 1024), // max 1024 streams - asymmetric
+		peerLimit(64, 64, 64))
+
+	// circuit protocols, both client and service
+	setProtocolLimits(limiter, circuit.ProtoIDv1,
+		limiter.DefaultProtocolLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20).
+			WithStreamLimit(1280, 1280, 1280),
+		peerLimit(128, 128, 128))
+	setProtocolLimits(limiter, circuit.ProtoIDv2Hop,
+		limiter.DefaultProtocolLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20).
+			WithStreamLimit(1280, 1280, 1280),
+		peerLimit(128, 128, 128))
+	setProtocolLimits(limiter, circuit.ProtoIDv2Stop,
+		limiter.DefaultProtocolLimits.
+			WithMemoryLimit(1, 4<<20, 64<<20).
+			WithStreamLimit(1280, 1280, 1280),
+		peerLimit(128, 128, 128))
+
+}
+
+func setServiceLimits(limiter *rcmgr.BasicLimiter, svc string, limit rcmgr.Limit, peerLimit rcmgr.Limit) {
+	if _, ok := limiter.ServiceLimits[svc]; !ok {
+		limiter.ServiceLimits[svc] = limit
+	}
+	if _, ok := limiter.ServicePeerLimits[svc]; !ok {
+		limiter.ServicePeerLimits[svc] = peerLimit
+	}
+}
+
+func setProtocolLimits(limiter *rcmgr.BasicLimiter, proto protocol.ID, limit rcmgr.Limit, peerLimit rcmgr.Limit) {
+	if _, ok := limiter.ProtocolLimits[proto]; !ok {
+		limiter.ProtocolLimits[proto] = limit
+	}
+	if _, ok := limiter.ProtocolPeerLimits[proto]; !ok {
+		limiter.ProtocolPeerLimits[proto] = peerLimit
+	}
+}
+
+func peerLimit(numStreamsIn, numStreamsOut, numStreamsTotal int) rcmgr.Limit {
+	return &rcmgr.StaticLimit{
+		// memory: 256kb for window buffers plus some change for message buffers per stream
+		Memory: int64(numStreamsTotal * (256<<10 + 16384)),
+		BaseLimit: rcmgr.BaseLimit{
+			StreamsInbound:  numStreamsIn,
+			StreamsOutbound: numStreamsOut,
+			Streams:         numStreamsTotal,
+		},
+	}
+}
diff --git a/options.go b/options.go
index 07968774..6821f4ed 100644
--- a/options.go
+++ b/options.go
@@ -346,6 +346,17 @@ func ConnectionGater(cg connmgr.ConnectionGater) Option {
 	}
 }
 
+// ResourceManager configures libp2p to use the given ResourceManager.
+func ResourceManager(rcmgr network.ResourceManager) Option {
+	return func(cfg *Config) error {
+		if cfg.ResourceManager != nil {
+			return errors.New("cannot configure multiple resource managers")
+		}
+		cfg.ResourceManager = rcmgr
+		return nil
+	}
+}
+
 // NATPortMap configures libp2p to use the default NATManager. The default
 // NATManager will attempt to open a port in your network's firewall using UPnP.
 func NATPortMap() Option {
diff --git a/p2p/host/autonat/client.go b/p2p/host/autonat/client.go
index 47936d90..83b13cc0 100644
--- a/p2p/host/autonat/client.go
+++ b/p2p/host/autonat/client.go
@@ -36,12 +36,26 @@ func (c *client) DialBack(ctx context.Context, p peer.ID) (ma.Multiaddr, error)
 	if err != nil {
 		return nil, err
 	}
+
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to autonat service: %s", err)
+		s.Reset()
+		return nil, err
+	}
+
+	if err := s.Scope().ReserveMemory(maxMsgSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("error reserving memory for autonat stream: %s", err)
+		s.Reset()
+		return nil, err
+	}
+	defer s.Scope().ReleaseMemory(maxMsgSize)
+
 	s.SetDeadline(time.Now().Add(streamTimeout))
 	// Might as well just reset the stream. Once we get to this point, we
 	// don't care about being nice.
 	defer s.Close()
 
-	r := protoio.NewDelimitedReader(s, network.MessageSizeMax)
+	r := protoio.NewDelimitedReader(s, maxMsgSize)
 	w := protoio.NewDelimitedWriter(s)
 
 	req := newDialMessage(peer.AddrInfo{ID: c.h.ID(), Addrs: c.addrFunc()})
diff --git a/p2p/host/autonat/svc.go b/p2p/host/autonat/svc.go
index cf80226f..4ad3502f 100644
--- a/p2p/host/autonat/svc.go
+++ b/p2p/host/autonat/svc.go
@@ -19,6 +19,12 @@ import (
 
 var streamTimeout = 60 * time.Second
 
+const (
+	ServiceName = "libp2p.autonat"
+
+	maxMsgSize = 4096
+)
+
 // AutoNATService provides NAT autodetection services to other peers
 type autoNATService struct {
 	instanceLock      sync.Mutex
@@ -45,13 +51,26 @@ func newAutoNATService(c *config) (*autoNATService, error) {
 }
 
 func (as *autoNATService) handleStream(s network.Stream) {
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to autonat service: %s", err)
+		s.Reset()
+		return
+	}
+
+	if err := s.Scope().ReserveMemory(maxMsgSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("error reserving memory for autonat stream: %s", err)
+		s.Reset()
+		return
+	}
+	defer s.Scope().ReleaseMemory(maxMsgSize)
+
 	s.SetDeadline(time.Now().Add(streamTimeout))
 	defer s.Close()
 
 	pid := s.Conn().RemotePeer()
 	log.Debugf("New stream from %s", pid.Pretty())
 
-	r := protoio.NewDelimitedReader(s, network.MessageSizeMax)
+	r := protoio.NewDelimitedReader(s, maxMsgSize)
 	w := protoio.NewDelimitedWriter(s)
 
 	var req pb.Message
diff --git a/p2p/host/basic/basic_host.go b/p2p/host/basic/basic_host.go
index 9a0285e7..5bcbf543 100644
--- a/p2p/host/basic/basic_host.go
+++ b/p2p/host/basic/basic_host.go
@@ -405,7 +405,12 @@ func (h *BasicHost) newStreamHandler(s network.Stream) {
 		}
 	}
 
-	s.SetProtocol(protocol.ID(protoID))
+	if err := s.SetProtocol(protocol.ID(protoID)); err != nil {
+		log.Debugf("error setting stream protocol: %s", err)
+		s.Reset()
+		return
+	}
+
 	log.Debugf("protocol negotiation took %s", took)
 
 	go handle(protoID, s)
@@ -1009,7 +1014,7 @@ func (h *BasicHost) SetAutoNat(a autonat.AutoNAT) {
 	}
 }
 
-// Return the host's AutoNAT service, if AutoNAT is enabled.
+// GetAutoNat returns the host's AutoNAT service, if AutoNAT is enabled.
 func (h *BasicHost) GetAutoNat() autonat.AutoNAT {
 	h.addrMu.Lock()
 	defer h.addrMu.Unlock()
diff --git a/p2p/net/mock/mock_conn.go b/p2p/net/mock/mock_conn.go
index d16908c7..bbfde35c 100644
--- a/p2p/net/mock/mock_conn.go
+++ b/p2p/net/mock/mock_conn.go
@@ -195,3 +195,7 @@ func (c *conn) RemotePublicKey() ic.PubKey {
 func (c *conn) Stat() network.ConnStats {
 	return c.stat
 }
+
+func (c *conn) Scope() network.ConnScope {
+	return network.NullScope
+}
diff --git a/p2p/net/mock/mock_peernet.go b/p2p/net/mock/mock_peernet.go
index a01f074d..f647085a 100644
--- a/p2p/net/mock/mock_peernet.go
+++ b/p2p/net/mock/mock_peernet.go
@@ -368,3 +368,7 @@ func (pn *peernet) notifyAll(notification func(f network.Notifiee)) {
 	pn.notifmu.Unlock()
 	wg.Wait()
 }
+
+func (pn *peernet) ResourceManager() network.ResourceManager {
+	return network.NullResourceManager
+}
diff --git a/p2p/net/mock/mock_stream.go b/p2p/net/mock/mock_stream.go
index 59348fbd..6b68e4f1 100644
--- a/p2p/net/mock/mock_stream.go
+++ b/p2p/net/mock/mock_stream.go
@@ -10,7 +10,6 @@ import (
 	"sync/atomic"
 	"time"
 
-	"github.com/libp2p/go-libp2p-core/mux"
 	"github.com/libp2p/go-libp2p-core/network"
 	"github.com/libp2p/go-libp2p-core/protocol"
 )
@@ -105,8 +104,9 @@ func (s *stream) Stat() network.Stats {
 	return s.stat
 }
 
-func (s *stream) SetProtocol(proto protocol.ID) {
+func (s *stream) SetProtocol(proto protocol.ID) error {
 	s.protocol.Store(proto)
+	return nil
 }
 
 func (s *stream) CloseWrite() error {
@@ -132,8 +132,8 @@ func (s *stream) Close() error {
 
 func (s *stream) Reset() error {
 	// Cancel any pending reads/writes with an error.
-	s.write.CloseWithError(mux.ErrReset)
-	s.read.CloseWithError(mux.ErrReset)
+	s.write.CloseWithError(network.ErrReset)
+	s.read.CloseWithError(network.ErrReset)
 
 	select {
 	case s.reset <- struct{}{}:
@@ -236,7 +236,7 @@ func (s *stream) transport() {
 				case s.reset <- struct{}{}:
 				default:
 				}
-				return mux.ErrReset
+				return network.ErrReset
 			}
 			if err := drainBuf(); err != nil {
 				return err
@@ -256,14 +256,14 @@ func (s *stream) transport() {
 		// Reset takes precedent.
 		select {
 		case <-s.reset:
-			s.writeErr = mux.ErrReset
+			s.writeErr = network.ErrReset
 			return
 		default:
 		}
 
 		select {
 		case <-s.reset:
-			s.writeErr = mux.ErrReset
+			s.writeErr = network.ErrReset
 			return
 		case <-s.close:
 			if err := drainBuf(); err != nil {
@@ -289,6 +289,10 @@ func (s *stream) transport() {
 	}
 }
 
+func (s *stream) Scope() network.StreamScope {
+	return network.NullScope
+}
+
 func (s *stream) cancelWrite(err error) {
 	s.write.CloseWithError(err)
 	s.writeErr = err
diff --git a/p2p/protocol/circuitv1/relay/relay.go b/p2p/protocol/circuitv1/relay/relay.go
index 1461dda3..3c626bd0 100644
--- a/p2p/protocol/circuitv1/relay/relay.go
+++ b/p2p/protocol/circuitv1/relay/relay.go
@@ -25,6 +25,8 @@ var log = logging.Logger("relay")
 const (
 	ProtoID = "/libp2p/circuit/relay/0.1.0"
 
+	ServiceName = "libp2p.relay/v1"
+
 	StreamTimeout    = time.Minute
 	ConnectTimeout   = 30 * time.Second
 	HandshakeTimeout = time.Minute
@@ -40,9 +42,10 @@ type Relay struct {
 	ctx    context.Context
 	cancel context.CancelFunc
 
-	host host.Host
-	rc   Resources
-	acl  ACLFilter
+	host  host.Host
+	rc    Resources
+	acl   ACLFilter
+	scope network.ResourceScopeSpan
 
 	mx     sync.Mutex
 	conns  map[peer.ID]int
@@ -64,6 +67,17 @@ func NewRelay(h host.Host, opts ...Option) (*Relay, error) {
 		}
 	}
 
+	// get a scope for memory reservations at service level
+	err := h.Network().ResourceManager().ViewService(ServiceName,
+		func(s network.ServiceScope) error {
+			var err error
+			r.scope, err = s.BeginSpan()
+			return err
+		})
+	if err != nil {
+		return nil, err
+	}
+
 	h.SetStreamHandler(ProtoID, r.handleStream)
 
 	return r, nil
@@ -72,19 +86,33 @@ func NewRelay(h host.Host, opts ...Option) (*Relay, error) {
 func (r *Relay) Close() error {
 	if atomic.CompareAndSwapInt32(&r.closed, 0, 1) {
 		r.host.RemoveStreamHandler(ProtoID)
+		r.scope.Done()
 		r.cancel()
 	}
 	return nil
 }
 
 func (r *Relay) handleStream(s network.Stream) {
-	s.SetReadDeadline(time.Now().Add(StreamTimeout))
-
 	log.Debugf("new relay stream from: %s", s.Conn().RemotePeer())
 
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to relay service: %s", err)
+		s.Reset()
+		return
+	}
+
+	if err := s.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("error reserving memory for stream: %s", err)
+		s.Reset()
+		return
+	}
+	defer s.Scope().ReleaseMemory(maxMessageSize)
+
 	rd := util.NewDelimitedReader(s, maxMessageSize)
 	defer rd.Close()
 
+	s.SetReadDeadline(time.Now().Add(StreamTimeout))
+
 	var msg pb.CircuitRelay
 
 	err := rd.ReadMsg(&msg)
@@ -108,31 +136,50 @@ func (r *Relay) handleStream(s network.Stream) {
 }
 
 func (r *Relay) handleHopStream(s network.Stream, msg *pb.CircuitRelay) {
+	span, err := r.scope.BeginSpan()
+	if err != nil {
+		log.Debugf("failed to begin relay transaction: %s", err)
+		r.handleError(s, pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
+		return
+	}
+
+	fail := func(code pb.CircuitRelay_Status) {
+		span.Done()
+		r.handleError(s, code)
+	}
+
+	// reserve buffers for the relay
+	if err := span.ReserveMemory(2*r.rc.BufferSize, network.ReservationPriorityHigh); err != nil {
+		log.Debugf("error reserving memory for relay: %s", err)
+		fail(pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
+		return
+	}
+
 	src, err := peerToPeerInfo(msg.GetSrcPeer())
 	if err != nil {
-		r.handleError(s, pb.CircuitRelay_HOP_SRC_MULTIADDR_INVALID)
+		fail(pb.CircuitRelay_HOP_SRC_MULTIADDR_INVALID)
 		return
 	}
 
 	if src.ID != s.Conn().RemotePeer() {
-		r.handleError(s, pb.CircuitRelay_HOP_SRC_MULTIADDR_INVALID)
+		fail(pb.CircuitRelay_HOP_SRC_MULTIADDR_INVALID)
 		return
 	}
 
 	dest, err := peerToPeerInfo(msg.GetDstPeer())
 	if err != nil {
-		r.handleError(s, pb.CircuitRelay_HOP_DST_MULTIADDR_INVALID)
+		fail(pb.CircuitRelay_HOP_DST_MULTIADDR_INVALID)
 		return
 	}
 
 	if dest.ID == r.host.ID() {
-		r.handleError(s, pb.CircuitRelay_HOP_CANT_RELAY_TO_SELF)
+		fail(pb.CircuitRelay_HOP_CANT_RELAY_TO_SELF)
 		return
 	}
 
 	if r.acl != nil && !r.acl.AllowHop(src.ID, dest.ID) {
 		log.Debugf("refusing hop from %s to %s; ACL refused", src.ID, dest.ID)
-		r.handleError(s, pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
+		fail(pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
 		return
 	}
 
@@ -140,7 +187,7 @@ func (r *Relay) handleHopStream(s network.Stream, msg *pb.CircuitRelay) {
 	if r.active >= r.rc.MaxCircuits {
 		r.mx.Unlock()
 		log.Debugf("refusing connection from %s to %s; too many active circuits", src.ID, dest.ID)
-		r.handleError(s, pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
+		fail(pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
 		return
 	}
 
@@ -148,7 +195,7 @@ func (r *Relay) handleHopStream(s network.Stream, msg *pb.CircuitRelay) {
 	if srcConns >= r.rc.MaxCircuitsPerPeer {
 		r.mx.Unlock()
 		log.Debugf("refusing connection from %s to %s; too many connections from %s", src.ID, dest.ID, src)
-		r.handleError(s, pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
+		fail(pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
 		return
 	}
 
@@ -156,7 +203,7 @@ func (r *Relay) handleHopStream(s network.Stream, msg *pb.CircuitRelay) {
 	if destConns >= r.rc.MaxCircuitsPerPeer {
 		r.mx.Unlock()
 		log.Debugf("refusing connection from %s to %s; too many connecitons to %s", src.ID, dest.ID, dest.ID)
-		r.handleError(s, pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
+		fail(pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
 		return
 	}
 
@@ -166,6 +213,7 @@ func (r *Relay) handleHopStream(s network.Stream, msg *pb.CircuitRelay) {
 	r.mx.Unlock()
 
 	cleanup := func() {
+		span.Done()
 		r.mx.Lock()
 		r.active--
 		r.rmConn(src.ID)
@@ -190,7 +238,26 @@ func (r *Relay) handleHopStream(s network.Stream, msg *pb.CircuitRelay) {
 		return
 	}
 
+	fail = func(code pb.CircuitRelay_Status) {
+		bs.Reset()
+		cleanup()
+		r.handleError(s, code)
+	}
+
+	if err := bs.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to relay service: %s", err)
+		fail(pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
+		return
+	}
+
 	// stop handshake
+	if err := bs.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("failed to reserve memory for stream: %s", err)
+		fail(pb.CircuitRelay_HOP_CANT_SPEAK_RELAY)
+		return
+	}
+	defer bs.Scope().ReleaseMemory(maxMessageSize)
+
 	rd := util.NewDelimitedReader(bs, maxMessageSize)
 	wr := util.NewDelimitedWriter(bs)
 	defer rd.Close()
@@ -203,9 +270,7 @@ func (r *Relay) handleHopStream(s network.Stream, msg *pb.CircuitRelay) {
 	err = wr.WriteMsg(msg)
 	if err != nil {
 		log.Debugf("error writing stop handshake: %s", err.Error())
-		bs.Reset()
-		r.handleError(s, pb.CircuitRelay_HOP_CANT_OPEN_DST_STREAM)
-		cleanup()
+		fail(pb.CircuitRelay_HOP_CANT_OPEN_DST_STREAM)
 		return
 	}
 
@@ -214,25 +279,19 @@ func (r *Relay) handleHopStream(s network.Stream, msg *pb.CircuitRelay) {
 	err = rd.ReadMsg(msg)
 	if err != nil {
 		log.Debugf("error reading stop response: %s", err.Error())
-		bs.Reset()
-		r.handleError(s, pb.CircuitRelay_HOP_CANT_OPEN_DST_STREAM)
-		cleanup()
+		fail(pb.CircuitRelay_HOP_CANT_OPEN_DST_STREAM)
 		return
 	}
 
 	if msg.GetType() != pb.CircuitRelay_STATUS {
 		log.Debugf("unexpected relay stop response: not a status message (%d)", msg.GetType())
-		bs.Reset()
-		r.handleError(s, pb.CircuitRelay_HOP_CANT_OPEN_DST_STREAM)
-		cleanup()
+		fail(pb.CircuitRelay_HOP_CANT_OPEN_DST_STREAM)
 		return
 	}
 
 	if msg.GetCode() != pb.CircuitRelay_SUCCESS {
 		log.Debugf("relay stop failure: %d", msg.GetCode())
-		bs.Reset()
-		r.handleError(s, msg.GetCode())
-		cleanup()
+		fail(msg.GetCode())
 		return
 	}
 
diff --git a/p2p/protocol/circuitv2/client/dial.go b/p2p/protocol/circuitv2/client/dial.go
index 50cc02cf..4a1e0e6e 100644
--- a/p2p/protocol/circuitv2/client/dial.go
+++ b/p2p/protocol/circuitv2/client/dial.go
@@ -144,6 +144,12 @@ func (c *Client) dialPeer(ctx context.Context, relay, dest peer.AddrInfo) (*Conn
 }
 
 func (c *Client) connectV2(s network.Stream, dest peer.AddrInfo) (*Conn, error) {
+	if err := s.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
+		s.Reset()
+		return nil, err
+	}
+	defer s.Scope().ReleaseMemory(maxMessageSize)
+
 	rd := util.NewDelimitedReader(s, maxMessageSize)
 	wr := util.NewDelimitedWriter(s)
 	defer rd.Close()
@@ -196,6 +202,12 @@ func (c *Client) connectV2(s network.Stream, dest peer.AddrInfo) (*Conn, error)
 }
 
 func (c *Client) connectV1(s network.Stream, dest peer.AddrInfo) (*Conn, error) {
+	if err := s.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
+		s.Reset()
+		return nil, err
+	}
+	defer s.Scope().ReleaseMemory(maxMessageSize)
+
 	rd := util.NewDelimitedReader(s, maxMessageSize)
 	wr := util.NewDelimitedWriter(s)
 	defer rd.Close()
diff --git a/p2p/protocol/circuitv2/client/transport.go b/p2p/protocol/circuitv2/client/transport.go
index 73954271..9bdb53f6 100644
--- a/p2p/protocol/circuitv2/client/transport.go
+++ b/p2p/protocol/circuitv2/client/transport.go
@@ -50,14 +50,21 @@ var _ transport.Transport = (*Client)(nil)
 var _ io.Closer = (*Client)(nil)
 
 func (c *Client) Dial(ctx context.Context, a ma.Multiaddr, p peer.ID) (transport.CapableConn, error) {
+	connScope, err := c.host.Network().ResourceManager().OpenConnection(network.DirOutbound, false)
+	if err != nil {
+		return nil, err
+	}
+	if err := connScope.SetPeer(p); err != nil {
+		connScope.Done()
+		return nil, err
+	}
 	conn, err := c.dial(ctx, a, p)
 	if err != nil {
+		connScope.Done()
 		return nil, err
 	}
-
 	conn.tagHop()
-
-	return c.upgrader.Upgrade(ctx, c, conn, network.DirOutbound, p)
+	return c.upgrader.Upgrade(ctx, c, conn, network.DirOutbound, p, connScope)
 }
 
 func (c *Client) CanDial(addr ma.Multiaddr) bool {
diff --git a/p2p/protocol/circuitv2/relay/relay.go b/p2p/protocol/circuitv2/relay/relay.go
index 9e836eea..2ff153f3 100644
--- a/p2p/protocol/circuitv2/relay/relay.go
+++ b/p2p/protocol/circuitv2/relay/relay.go
@@ -24,6 +24,8 @@ import (
 )
 
 const (
+	ServiceName = "libp2p.relay/v2"
+
 	ReservationTagWeight = 10
 
 	StreamTimeout    = time.Minute
@@ -48,6 +50,7 @@ type Relay struct {
 	rc          Resources
 	acl         ACLFilter
 	constraints *constraints
+	scope       network.ResourceScopeSpan
 
 	mx    sync.Mutex
 	rsvp  map[peer.ID]time.Time
@@ -77,6 +80,17 @@ func New(h host.Host, opts ...Option) (*Relay, error) {
 		}
 	}
 
+	// get a scope for memory reservations at service level
+	err := h.Network().ResourceManager().ViewService(ServiceName,
+		func(s network.ServiceScope) error {
+			var err error
+			r.scope, err = s.BeginSpan()
+			return err
+		})
+	if err != nil {
+		return nil, err
+	}
+
 	r.constraints = newConstraints(&r.rc)
 	r.selfAddr = ma.StringCast(fmt.Sprintf("/p2p/%s", h.ID()))
 
@@ -93,6 +107,7 @@ func New(h host.Host, opts ...Option) (*Relay, error) {
 func (r *Relay) Close() error {
 	if atomic.CompareAndSwapUint32(&r.closed, 0, 1) {
 		r.host.RemoveStreamHandler(proto.ProtoIDv2Hop)
+		r.scope.Done()
 		r.cancel()
 		r.mx.Lock()
 		for p := range r.rsvp {
@@ -104,13 +119,26 @@ func (r *Relay) Close() error {
 }
 
 func (r *Relay) handleStream(s network.Stream) {
-	s.SetReadDeadline(time.Now().Add(StreamTimeout))
-
 	log.Infof("new relay stream from: %s", s.Conn().RemotePeer())
 
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to relay service: %s", err)
+		s.Reset()
+		return
+	}
+
+	if err := s.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("error reserving memory for stream: %s", err)
+		s.Reset()
+		return
+	}
+	defer s.Scope().ReleaseMemory(maxMessageSize)
+
 	rd := util.NewDelimitedReader(s, maxMessageSize)
 	defer rd.Close()
 
+	s.SetReadDeadline(time.Now().Add(StreamTimeout))
+
 	var msg pbv2.HopMessage
 
 	err := rd.ReadMsg(&msg)
@@ -184,21 +212,40 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) {
 	src := s.Conn().RemotePeer()
 	a := s.Conn().RemoteMultiaddr()
 
+	span, err := r.scope.BeginSpan()
+	if err != nil {
+		log.Debugf("failed to begin relay transaction: %s", err)
+		r.handleError(s, pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
+		return
+	}
+
+	fail := func(status pbv2.Status) {
+		span.Done()
+		r.handleError(s, status)
+	}
+
+	// reserve buffers for the relay
+	if err := span.ReserveMemory(2*r.rc.BufferSize, network.ReservationPriorityHigh); err != nil {
+		log.Debugf("error reserving memory for relay: %s", err)
+		fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
+		return
+	}
+
 	if isRelayAddr(a) {
 		log.Debugf("refusing connection from %s; connection attempt over relay connection")
-		r.handleError(s, pbv2.Status_PERMISSION_DENIED)
+		fail(pbv2.Status_PERMISSION_DENIED)
 		return
 	}
 
 	dest, err := util.PeerToPeerInfoV2(msg.GetPeer())
 	if err != nil {
-		r.handleError(s, pbv2.Status_MALFORMED_MESSAGE)
+		fail(pbv2.Status_MALFORMED_MESSAGE)
 		return
 	}
 
 	if r.acl != nil && !r.acl.AllowConnect(src, s.Conn().RemoteMultiaddr(), dest.ID) {
 		log.Debugf("refusing connection from %s to %s; permission denied", src, dest.ID)
-		r.handleError(s, pbv2.Status_PERMISSION_DENIED)
+		fail(pbv2.Status_PERMISSION_DENIED)
 		return
 	}
 
@@ -207,7 +254,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) {
 	if !rsvp {
 		r.mx.Unlock()
 		log.Debugf("refusing connection from %s to %s; no reservation", src, dest.ID)
-		r.handleError(s, pbv2.Status_NO_RESERVATION)
+		fail(pbv2.Status_NO_RESERVATION)
 		return
 	}
 
@@ -215,7 +262,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) {
 	if srcConns >= r.rc.MaxCircuits {
 		r.mx.Unlock()
 		log.Debugf("refusing connection from %s to %s; too many connections from %s", src, dest.ID, src)
-		r.handleError(s, pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
+		fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
 		return
 	}
 
@@ -223,7 +270,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) {
 	if destConns >= r.rc.MaxCircuits {
 		r.mx.Unlock()
 		log.Debugf("refusing connection from %s to %s; too many connecitons to %s", src, dest.ID, dest.ID)
-		r.handleError(s, pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
+		fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
 		return
 	}
 
@@ -232,6 +279,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) {
 	r.mx.Unlock()
 
 	cleanup := func() {
+		span.Done()
 		r.mx.Lock()
 		r.rmConn(src)
 		r.rmConn(dest.ID)
@@ -251,7 +299,26 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) {
 		return
 	}
 
+	fail = func(status pbv2.Status) {
+		bs.Reset()
+		cleanup()
+		r.handleError(s, status)
+	}
+
+	if err := bs.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to relay service: %s", err)
+		fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
+		return
+	}
+
 	// handshake
+	if err := bs.Scope().ReserveMemory(maxMessageSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("erro reserving memory for stream: %s", err)
+		fail(pbv2.Status_RESOURCE_LIMIT_EXCEEDED)
+		return
+	}
+	defer bs.Scope().ReleaseMemory(maxMessageSize)
+
 	rd := util.NewDelimitedReader(bs, maxMessageSize)
 	wr := util.NewDelimitedWriter(bs)
 	defer rd.Close()
@@ -266,9 +333,7 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) {
 	err = wr.WriteMsg(&stopmsg)
 	if err != nil {
 		log.Debugf("error writing stop handshake")
-		bs.Reset()
-		cleanup()
-		r.handleError(s, pbv2.Status_CONNECTION_FAILED)
+		fail(pbv2.Status_CONNECTION_FAILED)
 		return
 	}
 
@@ -277,25 +342,19 @@ func (r *Relay) handleConnect(s network.Stream, msg *pbv2.HopMessage) {
 	err = rd.ReadMsg(&stopmsg)
 	if err != nil {
 		log.Debugf("error reading stop response: %s", err.Error())
-		bs.Reset()
-		cleanup()
-		r.handleError(s, pbv2.Status_CONNECTION_FAILED)
+		fail(pbv2.Status_CONNECTION_FAILED)
 		return
 	}
 
 	if t := stopmsg.GetType(); t != pbv2.StopMessage_STATUS {
 		log.Debugf("unexpected stop response; not a status message (%d)", t)
-		bs.Reset()
-		cleanup()
-		r.handleError(s, pbv2.Status_CONNECTION_FAILED)
+		fail(pbv2.Status_CONNECTION_FAILED)
 		return
 	}
 
 	if status := stopmsg.GetStatus(); status != pbv2.Status_OK {
 		log.Debugf("relay stop failure: %d", status)
-		bs.Reset()
-		cleanup()
-		r.handleError(s, pbv2.Status_CONNECTION_FAILED)
+		fail(pbv2.Status_CONNECTION_FAILED)
 		return
 	}
 
diff --git a/p2p/protocol/holepunch/coordination.go b/p2p/protocol/holepunch/coordination.go
index fd0c4452..c3964485 100644
--- a/p2p/protocol/holepunch/coordination.go
+++ b/p2p/protocol/holepunch/coordination.go
@@ -28,6 +28,8 @@ var StreamTimeout = 1 * time.Minute
 
 // TODO Should we have options for these ?
 const (
+	ServiceName = "libp2p.holepunch"
+
 	maxMsgSize  = 4 * 1024 // 4K
 	dialTimeout = 5 * time.Second
 	maxRetries  = 3
@@ -146,15 +148,30 @@ func (hs *Service) Close() error {
 func (hs *Service) initiateHolePunch(rp peer.ID) ([]ma.Multiaddr, time.Duration, error) {
 	hpCtx := network.WithUseTransient(hs.ctx, "hole-punch")
 	sCtx := network.WithNoDial(hpCtx, "hole-punch")
+
 	str, err := hs.host.NewStream(sCtx, rp, Protocol)
 	if err != nil {
 		return nil, 0, fmt.Errorf("failed to open hole-punching stream: %w", err)
 	}
 	defer str.Close()
-	str.SetDeadline(time.Now().Add(StreamTimeout))
+
+	if err := str.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to holepunch service: %s", err)
+		str.Reset()
+		return nil, 0, err
+	}
+
+	if err := str.Scope().ReserveMemory(maxMsgSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("error reserving memory for stream: %s, err")
+		str.Reset()
+		return nil, 0, err
+	}
+	defer str.Scope().ReleaseMemory(maxMsgSize)
 
 	w := protoio.NewDelimitedWriter(str)
+	rd := protoio.NewDelimitedReader(str, maxMsgSize)
 
+	str.SetDeadline(time.Now().Add(StreamTimeout))
 	// send a CONNECT and start RTT measurement.
 	msg := &pb.HolePunch{
 		Type:     pb.HolePunch_CONNECT.Enum(),
@@ -168,7 +185,6 @@ func (hs *Service) initiateHolePunch(rp peer.ID) ([]ma.Multiaddr, time.Duration,
 	}
 
 	// wait for a CONNECT message from the remote peer
-	rd := protoio.NewDelimitedReader(str, maxMsgSize)
 	msg.Reset()
 	if err := rd.ReadMsg(msg); err != nil {
 		str.Reset()
@@ -318,12 +334,20 @@ func (hs *Service) incomingHolePunch(s network.Stream) (rtt time.Duration, addrs
 		return 0, nil, errors.New("rejecting hole punch request, as we don't have any public addresses")
 	}
 
-	s.SetDeadline(time.Now().Add(StreamTimeout))
+	if err := s.Scope().ReserveMemory(maxMsgSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("error reserving memory for stream: %s, err")
+		return 0, nil, err
+	}
+	defer s.Scope().ReleaseMemory(maxMsgSize)
+
 	wr := protoio.NewDelimitedWriter(s)
 	rd := protoio.NewDelimitedReader(s, maxMsgSize)
 
 	// Read Connect message
 	msg := new(pb.HolePunch)
+
+	s.SetDeadline(time.Now().Add(StreamTimeout))
+
 	if err := rd.ReadMsg(msg); err != nil {
 		return 0, nil, fmt.Errorf("failed to read message from initator: %w", err)
 	}
@@ -366,6 +390,13 @@ func (hs *Service) handleNewStream(s network.Stream) {
 		s.Reset()
 		return
 	}
+
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to holepunch service: %s", err)
+		s.Reset()
+		return
+	}
+
 	rp := s.Conn().RemotePeer()
 	rtt, addrs, err := hs.incomingHolePunch(s)
 	if err != nil {
diff --git a/p2p/protocol/identify/id.go b/p2p/protocol/identify/id.go
index 388f1613..4c792ccf 100644
--- a/p2p/protocol/identify/id.go
+++ b/p2p/protocol/identify/id.go
@@ -41,6 +41,8 @@ const ID = "/ipfs/id/1.0.0"
 // 0.4.17 which asserted an exact version match.
 const LibP2PVersion = "ipfs/0.1.0"
 
+const ServiceName = "libp2p.identify"
+
 // StreamReadTimeout is the read timeout on all incoming Identify family streams.
 var StreamReadTimeout = 60 * time.Second
 
@@ -357,7 +359,11 @@ func (ids *idService) identifyConn(c network.Conn) error {
 		ids.removeConn(c)
 		return err
 	}
-	s.SetProtocol(ID)
+
+	if err := s.SetProtocol(ID); err != nil {
+		log.Warnf("error setting identify protocol for stream: %s", err)
+		s.Reset()
+	}
 
 	// ok give the response to our handler.
 	if err := msmux.SelectProtoOrFail(ID, s); err != nil {
@@ -370,6 +376,12 @@ func (ids *idService) identifyConn(c network.Conn) error {
 }
 
 func (ids *idService) sendIdentifyResp(s network.Stream) {
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Warnf("error attaching stream to identify service: %s", err)
+		s.Reset()
+		return
+	}
+
 	defer s.Close()
 
 	c := s.Conn()
@@ -402,6 +414,19 @@ func (ids *idService) sendIdentifyResp(s network.Stream) {
 }
 
 func (ids *idService) handleIdentifyResponse(s network.Stream) error {
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Warnf("error attaching stream to identify service: %s", err)
+		s.Reset()
+		return err
+	}
+
+	if err := s.Scope().ReserveMemory(signedIDSize, network.ReservationPriorityAlways); err != nil {
+		log.Warnf("error reserving memory for identify stream: %s", err)
+		s.Reset()
+		return err
+	}
+	defer s.Scope().ReleaseMemory(signedIDSize)
+
 	_ = s.SetReadDeadline(time.Now().Add(StreamReadTimeout))
 
 	c := s.Conn()
diff --git a/p2p/protocol/identify/id_delta.go b/p2p/protocol/identify/id_delta.go
index 738fcc38..467a101d 100644
--- a/p2p/protocol/identify/id_delta.go
+++ b/p2p/protocol/identify/id_delta.go
@@ -15,13 +15,28 @@ import (
 
 const IDDelta = "/p2p/id/delta/1.0.0"
 
+const deltaMsgSize = 2048
+
 // deltaHandler handles incoming delta updates from peers.
 func (ids *idService) deltaHandler(s network.Stream) {
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Warnf("error attaching stream to identify service: %s", err)
+		s.Reset()
+		return
+	}
+
+	if err := s.Scope().ReserveMemory(deltaMsgSize, network.ReservationPriorityAlways); err != nil {
+		log.Warnf("error reserving memory for identify stream: %s", err)
+		s.Reset()
+		return
+	}
+	defer s.Scope().ReleaseMemory(deltaMsgSize)
+
 	_ = s.SetReadDeadline(time.Now().Add(StreamReadTimeout))
 
 	c := s.Conn()
 
-	r := protoio.NewDelimitedReader(s, 2048)
+	r := protoio.NewDelimitedReader(s, deltaMsgSize)
 	mes := pb.Identify{}
 	if err := r.ReadMsg(&mes); err != nil {
 		log.Warn("error reading identify message: ", err)
diff --git a/p2p/protocol/ping/ping.go b/p2p/protocol/ping/ping.go
index 62ecb698..3f19c21e 100644
--- a/p2p/protocol/ping/ping.go
+++ b/p2p/protocol/ping/ping.go
@@ -9,6 +9,7 @@ import (
 
 	u "github.com/ipfs/go-ipfs-util"
 	logging "github.com/ipfs/go-log/v2"
+	pool "github.com/libp2p/go-buffer-pool"
 	"github.com/libp2p/go-libp2p-core/host"
 	"github.com/libp2p/go-libp2p-core/network"
 	"github.com/libp2p/go-libp2p-core/peer"
@@ -16,11 +17,14 @@ import (
 
 var log = logging.Logger("ping")
 
-const PingSize = 32
+const (
+	PingSize    = 32
+	pingTimeout = time.Second * 60
 
-const ID = "/ipfs/ping/1.0.0"
+	ID = "/ipfs/ping/1.0.0"
 
-const pingTimeout = time.Second * 60
+	ServiceName = "libp2p.ping"
+)
 
 type PingService struct {
 	Host host.Host
@@ -33,7 +37,21 @@ func NewPingService(h host.Host) *PingService {
 }
 
 func (p *PingService) PingHandler(s network.Stream) {
-	buf := make([]byte, PingSize)
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to ping service: %s", err)
+		s.Reset()
+		return
+	}
+
+	if err := s.Scope().ReserveMemory(PingSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("error reserving memory for ping stream: %s", err)
+		s.Reset()
+		return
+	}
+	defer s.Scope().ReleaseMemory(PingSize)
+
+	buf := pool.Get(PingSize)
+	defer pool.Put(buf)
 
 	errCh := make(chan error, 1)
 	defer close(errCh)
@@ -81,15 +99,25 @@ func (ps *PingService) Ping(ctx context.Context, p peer.ID) <-chan Result {
 	return Ping(ctx, ps.Host, p)
 }
 
+func pingError(err error) chan Result {
+	ch := make(chan Result, 1)
+	ch <- Result{Error: err}
+	close(ch)
+	return ch
+}
+
 // Ping pings the remote peer until the context is canceled, returning a stream
 // of RTTs or errors.
 func Ping(ctx context.Context, h host.Host, p peer.ID) <-chan Result {
 	s, err := h.NewStream(network.WithUseTransient(ctx, "ping"), p, ID)
 	if err != nil {
-		ch := make(chan Result, 1)
-		ch <- Result{Error: err}
-		close(ch)
-		return ch
+		return pingError(err)
+	}
+
+	if err := s.Scope().SetService(ServiceName); err != nil {
+		log.Debugf("error attaching stream to ping service: %s", err)
+		s.Reset()
+		return pingError(err)
 	}
 
 	ctx, cancel := context.WithCancel(ctx)
@@ -130,7 +158,16 @@ func Ping(ctx context.Context, h host.Host, p peer.ID) <-chan Result {
 }
 
 func ping(s network.Stream) (time.Duration, error) {
-	buf := make([]byte, PingSize)
+	if err := s.Scope().ReserveMemory(2*PingSize, network.ReservationPriorityAlways); err != nil {
+		log.Debugf("error reserving memory for ping stream: %s", err)
+		s.Reset()
+		return 0, err
+	}
+	defer s.Scope().ReleaseMemory(2 * PingSize)
+
+	buf := pool.Get(PingSize)
+	defer pool.Put(buf)
+
 	u.NewTimeSeededRand().Read(buf)
 
 	before := time.Now()
@@ -139,7 +176,9 @@ func ping(s network.Stream) (time.Duration, error) {
 		return 0, err
 	}
 
-	rbuf := make([]byte, PingSize)
+	rbuf := pool.Get(PingSize)
+	defer pool.Put(rbuf)
+
 	_, err = io.ReadFull(s, rbuf)
 	if err != nil {
 		return 0, err


Test patch:
diff --git a/config/muxer_test.go b/config/muxer_test.go
index 157b3dc0..50e32ef0 100644
--- a/config/muxer_test.go
+++ b/config/muxer_test.go
@@ -3,18 +3,19 @@ package config
 import (
 	"testing"
 
+	"github.com/libp2p/go-libp2p-core/network"
+
 	"github.com/libp2p/go-libp2p-core/host"
 	"github.com/libp2p/go-libp2p-core/peer"
 	swarmt "github.com/libp2p/go-libp2p-swarm/testing"
 	bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
 
-	"github.com/libp2p/go-libp2p-core/mux"
 	yamux "github.com/libp2p/go-libp2p-yamux"
 )
 
 func TestMuxerSimple(t *testing.T) {
 	// single
-	_, err := MuxerConstructor(func(_ peer.ID) mux.Multiplexer { return nil })
+	_, err := MuxerConstructor(func(_ peer.ID) network.Multiplexer { return nil })
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -27,14 +28,14 @@ func TestMuxerByValue(t *testing.T) {
 	}
 }
 func TestMuxerDuplicate(t *testing.T) {
-	_, err := MuxerConstructor(func(_ peer.ID, _ peer.ID) mux.Multiplexer { return nil })
+	_, err := MuxerConstructor(func(_ peer.ID, _ peer.ID) network.Multiplexer { return nil })
 	if err != nil {
 		t.Fatal(err)
 	}
 }
 
 func TestMuxerError(t *testing.T) {
-	_, err := MuxerConstructor(func() (mux.Multiplexer, error) { return nil, nil })
+	_, err := MuxerConstructor(func() (network.Multiplexer, error) { return nil, nil })
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -45,8 +46,8 @@ func TestMuxerBadTypes(t *testing.T) {
 		func() error { return nil },
 		func() string { return "" },
 		func() {},
-		func(string) mux.Multiplexer { return nil },
-		func(string) (mux.Multiplexer, error) { return nil, nil },
+		func(string) network.Multiplexer { return nil },
+		func(string) (network.Multiplexer, error) { return nil, nil },
 		nil,
 		"testing",
 	} {
diff --git a/config/transport_test.go b/config/transport_test.go
index 4a62eb29..1a226074 100644
--- a/config/transport_test.go
+++ b/config/transport_test.go
@@ -33,10 +33,10 @@ func TestConstructorWithOpts(t *testing.T) {
 	var options []int
 	c, err := TransportConstructor(func(_ transport.Upgrader, opts ...int) (transport.Transport, error) {
 		options = opts
-		return tcp.NewTCPTransport(nil)
+		return tcp.NewTCPTransport(nil, nil)
 	}, 42, 1337)
 	require.NoError(t, err)
-	_, err = c(nil, nil, nil, nil)
+	_, err = c(nil, nil, nil, nil, nil)
 	require.NoError(t, err)
 	require.Equal(t, []int{42, 1337}, options)
 }
diff --git a/libp2p_test.go b/libp2p_test.go
index dcf1c522..a40360e6 100644
--- a/libp2p_test.go
+++ b/libp2p_test.go
@@ -45,7 +45,7 @@ func TestTransportConstructor(t *testing.T) {
 		_ connmgr.ConnectionGater,
 		upgrader transport.Upgrader,
 	) transport.Transport {
-		tpt, err := tcp.NewTCPTransport(upgrader)
+		tpt, err := tcp.NewTCPTransport(upgrader, nil)
 		require.NoError(t, err)
 		return tpt
 	}
diff --git a/p2p/net/connmgr/connmgr_test.go b/p2p/net/connmgr/connmgr_test.go
index 390c8599..d70ec363 100644
--- a/p2p/net/connmgr/connmgr_test.go
+++ b/p2p/net/connmgr/connmgr_test.go
@@ -795,6 +795,7 @@ func (m mockConn) Stat() network.ConnStats                               { retur
 func (m mockConn) ID() string                                            { panic("implement me") }
 func (m mockConn) NewStream(ctx context.Context) (network.Stream, error) { panic("implement me") }
 func (m mockConn) GetStreams() []network.Stream                          { panic("implement me") }
+func (m mockConn) Scope() network.ConnScope                              { panic("implement me") }
 
 func TestPeerInfoSorting(t *testing.T) {
 	t.Run("starts with temporary connections", func(t *testing.T) {
diff --git a/p2p/protocol/circuitv2/relay/relay_test.go b/p2p/protocol/circuitv2/relay/relay_test.go
index 248b01b0..cdccbf2e 100644
--- a/p2p/protocol/circuitv2/relay/relay_test.go
+++ b/p2p/protocol/circuitv2/relay/relay_test.go
@@ -18,7 +18,6 @@ import (
 
 	"github.com/libp2p/go-libp2p-core/crypto"
 	"github.com/libp2p/go-libp2p-core/host"
-	"github.com/libp2p/go-libp2p-core/mux"
 	"github.com/libp2p/go-libp2p-core/network"
 	"github.com/libp2p/go-libp2p-core/peer"
 
@@ -60,7 +59,7 @@ func getNetHosts(t *testing.T, ctx context.Context, n int) (hosts []host.Host, u
 		upgrader := swarmt.GenUpgrader(t, netw)
 		upgraders = append(upgraders, upgrader)
 
-		tpt, err := tcp.NewTCPTransport(upgrader)
+		tpt, err := tcp.NewTCPTransport(upgrader, nil)
 		if err != nil {
 			t.Fatal(err)
 		}
@@ -246,12 +245,12 @@ func TestRelayLimitTime(t *testing.T) {
 	if n > 0 {
 		t.Fatalf("expected to write 0 bytes, wrote %d", n)
 	}
-	if err != mux.ErrReset {
+	if err != network.ErrReset {
 		t.Fatalf("expected reset, but got %s", err)
 	}
 
 	err = <-rch
-	if err != mux.ErrReset {
+	if err != network.ErrReset {
 		t.Fatalf("expected reset, but got %s", err)
 	}
 }
@@ -279,7 +278,7 @@ func TestRelayLimitData(t *testing.T) {
 		}
 
 		n, err := s.Read(buf)
-		if err != mux.ErrReset {
+		if err != network.ErrReset {
 			t.Fatalf("expected reset but got %s", err)
 		}
 		rch <- n