From 60becadcf9044ceef3070bf5d66cb7a7821d57bd Mon Sep 17 00:00:00 2001 From: Tanguy Date: Wed, 25 May 2022 12:12:57 +0200 Subject: [PATCH] Peer store refacto (#700) There is now a global PeerStore structure (instead of having one for libp2p, one for waku, etc) The user can create custom books for new types easily Also add a pruning system to remove dead peers --- libp2p/builders.nim | 18 +- libp2p/connmanager.nim | 3 + libp2p/peerstore.nim | 156 ++++++++-------- .../protocols/pubsub/gossipsub/behavior.nim | 4 +- libp2p/switch.nim | 7 +- tests/testidentify.nim | 28 +-- tests/testpeerstore.nim | 175 ++++++------------ tests/testswitch.nim | 10 +- 8 files changed, 177 insertions(+), 224 deletions(-) diff --git a/libp2p/builders.nim b/libp2p/builders.nim index 7e3f88d..e0ca64d 100644 --- a/libp2p/builders.nim +++ b/libp2p/builders.nim @@ -48,6 +48,7 @@ type protoVersion: string agentVersion: string nameResolver: NameResolver + peerStoreCapacity: Option[int] isCircuitRelay: bool circuitRelayCanHop: bool @@ -130,6 +131,10 @@ proc withMaxConnsPerPeer*(b: SwitchBuilder, maxConnsPerPeer: int): SwitchBuilder b.maxConnsPerPeer = maxConnsPerPeer b +proc withPeerStore*(b: SwitchBuilder, capacity: int): SwitchBuilder = + b.peerStoreCapacity = some(capacity) + b + proc withProtoVersion*(b: SwitchBuilder, protoVersion: string): SwitchBuilder = b.protoVersion = protoVersion b @@ -195,6 +200,12 @@ proc build*(b: SwitchBuilder): Switch if isNil(b.rng): b.rng = newRng() + let peerStore = + if isSome(b.peerStoreCapacity): + PeerStore.new(b.peerStoreCapacity.get()) + else: + PeerStore.new() + let switch = newSwitch( peerInfo = peerInfo, transports = transports, @@ -203,7 +214,8 @@ proc build*(b: SwitchBuilder): Switch secureManagers = secureManagerInstances, connManager = connManager, ms = ms, - nameResolver = b.nameResolver) + nameResolver = b.nameResolver, + peerStore = peerStore) if b.isCircuitRelay: let relay = Relay.new(switch, b.circuitRelayCanHop) @@ -227,7 +239,8 @@ proc newStandardSwitch*( maxOut = -1, maxConnsPerPeer = MaxConnectionsPerPeer, nameResolver: NameResolver = nil, - sendSignedPeerRecord = false): Switch + sendSignedPeerRecord = false, + peerStoreCapacity = 1000): Switch {.raises: [Defect, LPError].} = if SecureProtocol.Secio in secureManagers: quit("Secio is deprecated!") # use of secio is unsafe @@ -242,6 +255,7 @@ proc newStandardSwitch*( .withMaxIn(maxIn) .withMaxOut(maxOut) .withMaxConnsPerPeer(maxConnsPerPeer) + .withPeerStore(capacity=peerStoreCapacity) .withMplex(inTimeout, outTimeout) .withTcpTransport(transportFlags) .withNameResolver(nameResolver) diff --git a/libp2p/connmanager.nim b/libp2p/connmanager.nim index f56c7b7..76de2da 100644 --- a/libp2p/connmanager.nim +++ b/libp2p/connmanager.nim @@ -307,6 +307,9 @@ proc peerCleanup(c: ConnManager, conn: Connection) {.async.} = await c.triggerConnEvent( peerId, ConnEvent(kind: ConnEventKind.Disconnected)) await c.triggerPeerEvents(peerId, PeerEvent(kind: PeerEventKind.Left)) + + if not(c.peerStore.isNil): + c.peerStore.cleanup(peerId) except CatchableError as exc: # This is top-level procedure which will work as separate task, so it # do not need to propagate CancelledError and should handle other errors diff --git a/libp2p/peerstore.nim b/libp2p/peerstore.nim index 992b337..b86145c 100644 --- a/libp2p/peerstore.nim +++ b/libp2p/peerstore.nim @@ -10,7 +10,7 @@ {.push raises: [Defect].} import - std/[tables, sets, options], + std/[tables, sets, options, macros], ./crypto/crypto, ./protocols/identify, ./peerid, ./peerinfo, @@ -22,58 +22,52 @@ type # Handler types # ################# - PeerBookChangeHandler*[T] = proc(peerId: PeerId, entry: T) - - AddrChangeHandler* = PeerBookChangeHandler[HashSet[MultiAddress]] - ProtoChangeHandler* = PeerBookChangeHandler[HashSet[string]] - KeyChangeHandler* = PeerBookChangeHandler[PublicKey] + PeerBookChangeHandler* = proc(peerId: PeerId) {.gcsafe, raises: [Defect].} ######### # Books # ######### # Each book contains a book (map) and event handler(s) - PeerBook*[T] = object of RootObj - book*: Table[PeerId, T] - changeHandlers: seq[PeerBookChangeHandler[T]] + BasePeerBook = ref object of RootObj + changeHandlers: seq[PeerBookChangeHandler] + deletor: PeerBookChangeHandler - SetPeerBook*[T] = object of PeerBook[HashSet[T]] + PeerBook*[T] = ref object of BasePeerBook + book*: Table[PeerId, T] + + SeqPeerBook*[T] = ref object of PeerBook[seq[T]] - AddressBook* = object of SetPeerBook[MultiAddress] - ProtoBook* = object of SetPeerBook[string] - KeyBook* = object of PeerBook[PublicKey] + AddressBook* = ref object of SeqPeerBook[MultiAddress] + ProtoBook* = ref object of SeqPeerBook[string] + KeyBook* = ref object of PeerBook[PublicKey] + + AgentBook* = ref object of PeerBook[string] + ProtoVersionBook* = ref object of PeerBook[string] + SPRBook* = ref object of PeerBook[Envelope] #################### # Peer store types # #################### PeerStore* = ref object - addressBook*: AddressBook - protoBook*: ProtoBook - keyBook*: KeyBook - - agentBook*: PeerBook[string] - protoVersionBook*: PeerBook[string] - - signedPeerRecordBook*: PeerBook[Envelope] + books: Table[string, BasePeerBook] + capacity*: int + toClean*: seq[PeerId] -## Constructs a new PeerStore with metadata of type M -proc new*(T: type PeerStore): PeerStore = - var p: PeerStore - new(p) - return p +proc new*(T: type PeerStore, capacity = 1000): PeerStore = + T(capacity: capacity) ######################### # Generic Peer Book API # ######################### -proc get*[T](peerBook: PeerBook[T], +proc `[]`*[T](peerBook: PeerBook[T], peerId: PeerId): T = ## Get all the known metadata of a provided peer. - peerBook.book.getOrDefault(peerId) -proc set*[T](peerBook: var PeerBook[T], +proc `[]=`*[T](peerBook: PeerBook[T], peerId: PeerId, entry: T) = ## Set metadata for a given peerId. This will replace any @@ -83,86 +77,90 @@ proc set*[T](peerBook: var PeerBook[T], # Notify clients for handler in peerBook.changeHandlers: - handler(peerId, peerBook.get(peerId)) + handler(peerId) -proc delete*[T](peerBook: var PeerBook[T], +proc del*[T](peerBook: PeerBook[T], peerId: PeerId): bool = ## Delete the provided peer from the book. - if not peerBook.book.hasKey(peerId): + if peerId notin peerBook.book: return false else: peerBook.book.del(peerId) + # Notify clients + for handler in peerBook.changeHandlers: + handler(peerId) return true proc contains*[T](peerBook: PeerBook[T], peerId: PeerId): bool = peerId in peerBook.book -################ -# Set Book API # -################ +proc addHandler*[T](peerBook: PeerBook[T], handler: PeerBookChangeHandler) = + peerBook.changeHandlers.add(handler) -proc add*[T]( - peerBook: var SetPeerBook[T], - peerId: PeerId, - entry: T) = - ## Add entry to a given peer. If the peer is not known, - ## it will be set with the provided entry. - - peerBook.book.mgetOrPut(peerId, - initHashSet[T]()).incl(entry) - - # Notify clients - for handler in peerBook.changeHandlers: - handler(peerId, peerBook.get(peerId)) - -# Helper for seq -proc set*[T]( - peerBook: var SetPeerBook[T], - peerId: PeerId, - entry: seq[T]) = - ## Add entry to a given peer. If the peer is not known, - ## it will be set with the provided entry. - peerBook.set(peerId, entry.toHashSet()) - +proc len*[T](peerBook: PeerBook[T]): int = peerBook.book.len ################## # Peer Store API # ################## +macro getTypeName(t: type): untyped = + # Generate unique name in form of Module.Type + let typ = getTypeImpl(t)[1] + newLit(repr(typ.owner()) & "." & repr(typ)) -proc addHandlers*(peerStore: PeerStore, - addrChangeHandler: AddrChangeHandler, - protoChangeHandler: ProtoChangeHandler, - keyChangeHandler: KeyChangeHandler) = - ## Register event handlers to notify clients of changes in the peer store - - peerStore.addressBook.changeHandlers.add(addrChangeHandler) - peerStore.protoBook.changeHandlers.add(protoChangeHandler) - peerStore.keyBook.changeHandlers.add(keyChangeHandler) +proc `[]`*[T](p: PeerStore, typ: type[T]): T = + let name = getTypeName(T) + result = T(p.books.getOrDefault(name)) + if result.isNil: + result = T.new() + result.deletor = proc(pid: PeerId) = + # Manual method because generic method + # don't work + discard T(p.books.getOrDefault(name)).del(pid) + p.books[name] = result + return result -proc delete*(peerStore: PeerStore, - peerId: PeerId): bool = +proc del*(peerStore: PeerStore, + peerId: PeerId) = ## Delete the provided peer from every book. - - peerStore.addressBook.delete(peerId) and - peerStore.protoBook.delete(peerId) and - peerStore.keyBook.delete(peerId) + for _, book in peerStore.books: + book.deletor(peerId) proc updatePeerInfo*( peerStore: PeerStore, info: IdentifyInfo) = if info.addrs.len > 0: - peerStore.addressBook.set(info.peerId, info.addrs) + peerStore[AddressBook][info.peerId] = info.addrs if info.agentVersion.isSome: - peerStore.agentBook.set(info.peerId, info.agentVersion.get().string) + peerStore[AgentBook][info.peerId] = info.agentVersion.get().string if info.protoVersion.isSome: - peerStore.protoVersionBook.set(info.peerId, info.protoVersion.get().string) + peerStore[ProtoVersionBook][info.peerId] = info.protoVersion.get().string if info.protos.len > 0: - peerStore.protoBook.set(info.peerId, info.protos) - + peerStore[ProtoBook][info.peerId] = info.protos + if info.signedPeerRecord.isSome: - peerStore.signedPeerRecordBook.set(info.peerId, info.signedPeerRecord.get()) + peerStore[SPRBook][info.peerId] = info.signedPeerRecord.get() + + let cleanupPos = peerStore.toClean.find(info.peerId) + if cleanupPos >= 0: + peerStore.toClean.delete(cleanupPos) + +proc cleanup*( + peerStore: PeerStore, + peerId: PeerId) = + + if peerStore.capacity == 0: + peerStore.del(peerId) + return + elif peerStore.capacity < 0: + #infinite capacity + return + + peerStore.toClean.add(peerId) + while peerStore.toClean.len > peerStore.capacity: + peerStore.del(peerStore.toClean[0]) + peerStore.toClean.delete(0) diff --git a/libp2p/protocols/pubsub/gossipsub/behavior.nim b/libp2p/protocols/pubsub/gossipsub/behavior.nim index 17e830e..cd69c5f 100644 --- a/libp2p/protocols/pubsub/gossipsub/behavior.nim +++ b/libp2p/protocols/pubsub/gossipsub/behavior.nim @@ -86,13 +86,13 @@ proc peerExchangeList*(g: GossipSub, topic: string): seq[PeerInfoMsg] {.raises: x.score >= 0.0 # by spec, larger then Dhi, but let's put some hard caps peers.setLen(min(peers.len, g.parameters.dHigh * 2)) - let sprBook = g.switch.peerStore.signedPeerRecordBook + let sprBook = g.switch.peerStore[SPRBook] peers.map do (x: PubSubPeer) -> PeerInfoMsg: PeerInfoMsg( peerId: x.peerId, signedPeerRecord: if x.peerId in sprBook: - sprBook.get(x.peerId).encode().get(default(seq[byte])) + sprBook[x.peerId].encode().get(default(seq[byte])) else: default(seq[byte]) ) diff --git a/libp2p/switch.nim b/libp2p/switch.nim index affc0e5..c895770 100644 --- a/libp2p/switch.nim +++ b/libp2p/switch.nim @@ -281,7 +281,8 @@ proc newSwitch*(peerInfo: PeerInfo, secureManagers: openArray[Secure] = [], connManager: ConnManager, ms: MultistreamSelect, - nameResolver: NameResolver = nil): Switch + nameResolver: NameResolver = nil, + peerStore = PeerStore.new()): Switch {.raises: [Defect, LPError].} = if secureManagers.len == 0: raise newException(LPError, "Provide at least one secure manager") @@ -291,10 +292,10 @@ proc newSwitch*(peerInfo: PeerInfo, ms: ms, transports: transports, connManager: connManager, - peerStore: PeerStore.new(), + peerStore: peerStore, dialer: Dialer.new(peerInfo.peerId, connManager, transports, ms, nameResolver), nameResolver: nameResolver) - switch.connManager.peerStore = switch.peerStore + switch.connManager.peerStore = peerStore switch.mount(identity) return switch diff --git a/tests/testidentify.nim b/tests/testidentify.nim index 931197b..96ea1c2 100644 --- a/tests/testidentify.nim +++ b/tests/testidentify.nim @@ -177,11 +177,11 @@ suite "Identify": IdentifyPushCodec) check: - switch1.peerStore.addressBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.addrs.toHashSet() - switch2.peerStore.addressBook.get(switch1.peerInfo.peerId) == switch1.peerInfo.addrs.toHashSet() + switch1.peerStore[AddressBook][switch2.peerInfo.peerId] == switch2.peerInfo.addrs + switch2.peerStore[AddressBook][switch1.peerInfo.peerId] == switch1.peerInfo.addrs - switch1.peerStore.addressBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.addrs.toHashSet() - switch2.peerStore.addressBook.get(switch1.peerInfo.peerId) == switch1.peerInfo.addrs.toHashSet() + switch1.peerStore[AddressBook][switch2.peerInfo.peerId] == switch2.peerInfo.addrs + switch2.peerStore[AddressBook][switch1.peerInfo.peerId] == switch1.peerInfo.addrs #switch1.peerStore.signedPeerRecordBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.signedPeerRecord.get() #switch2.peerStore.signedPeerRecordBook.get(switch1.peerInfo.peerId) == switch1.peerInfo.signedPeerRecord.get() @@ -198,20 +198,20 @@ suite "Identify": switch2.peerInfo.addrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet()) check: - switch1.peerStore.addressBook.get(switch2.peerInfo.peerId) != switch2.peerInfo.addrs.toHashSet() - switch1.peerStore.protoBook.get(switch2.peerInfo.peerId) != switch2.peerInfo.protocols.toHashSet() + switch1.peerStore[AddressBook][switch2.peerInfo.peerId] != switch2.peerInfo.addrs + switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] != switch2.peerInfo.protocols await identifyPush2.push(switch2.peerInfo, conn) - check await checkExpiring(switch1.peerStore.protoBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.protocols.toHashSet()) - check await checkExpiring(switch1.peerStore.addressBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.addrs.toHashSet()) + check await checkExpiring(switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] == switch2.peerInfo.protocols) + check await checkExpiring(switch1.peerStore[AddressBook][switch2.peerInfo.peerId] == switch2.peerInfo.addrs) await closeAll() # Wait the very end to be sure that the push has been processed check: - switch1.peerStore.protoBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.protocols.toHashSet() - switch1.peerStore.addressBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.addrs.toHashSet() + switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] == switch2.peerInfo.protocols + switch1.peerStore[AddressBook][switch2.peerInfo.peerId] == switch2.peerInfo.addrs asyncTest "wrong peer id push identify": @@ -219,8 +219,8 @@ suite "Identify": switch2.peerInfo.addrs.add(MultiAddress.init("/ip4/127.0.0.1/tcp/5555").tryGet()) check: - switch1.peerStore.addressBook.get(switch2.peerInfo.peerId) != switch2.peerInfo.addrs.toHashSet() - switch1.peerStore.protoBook.get(switch2.peerInfo.peerId) != switch2.peerInfo.protocols.toHashSet() + switch1.peerStore[AddressBook][switch2.peerInfo.peerId] != switch2.peerInfo.addrs + switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] != switch2.peerInfo.protocols let oldPeerId = switch2.peerInfo.peerId switch2.peerInfo = PeerInfo.new(PrivateKey.random(newRng()[]).get()) @@ -237,5 +237,5 @@ suite "Identify": # Wait the very end to be sure that the push has been processed check: - switch1.peerStore.protoBook.get(oldPeerId) != switch2.peerInfo.protocols.toHashSet() - switch1.peerStore.addressBook.get(oldPeerId) != switch2.peerInfo.addrs.toHashSet() + switch1.peerStore[ProtoBook][oldPeerId] != switch2.peerInfo.protocols + switch1.peerStore[AddressBook][oldPeerId] != switch2.peerInfo.addrs diff --git a/tests/testpeerstore.nim b/tests/testpeerstore.nim index 9480509..7447731 100644 --- a/tests/testpeerstore.nim +++ b/tests/testpeerstore.nim @@ -28,170 +28,107 @@ suite "PeerStore": var peerStore = PeerStore.new() - peerStore.addressBook.add(peerId1, multiaddr1) - peerStore.addressBook.add(peerId2, multiaddr2) - peerStore.protoBook.add(peerId1, testcodec1) - peerStore.protoBook.add(peerId2, testcodec2) - peerStore.keyBook.set(peerId1, keyPair1.pubkey) - peerStore.keyBook.set(peerId2, keyPair2.pubkey) + peerStore[AddressBook][peerId1] = @[multiaddr1] + peerStore[AddressBook][peerId2] = @[multiaddr2] + peerStore[ProtoBook][peerId1] = @[testcodec1] + peerStore[ProtoBook][peerId2] = @[testcodec2] + peerStore[KeyBook][peerId1] = keyPair1.pubkey + peerStore[KeyBook][peerId2] = keyPair2.pubkey - # Test PeerStore::delete - check: - # Delete existing peerId - peerStore.delete(peerId1) == true - peerId1 notin peerStore.addressBook + # Test PeerStore::del + # Delete existing peerId + peerStore.del(peerId1) + check peerId1 notin peerStore[AddressBook] + # Now try and del it again + peerStore.del(peerId1) - # Now try and delete it again - peerStore.delete(peerId1) == false test "PeerStore listeners": # Set up peer store with listener var peerStore = PeerStore.new() addrChanged = false - protoChanged = false - keyChanged = false - proc addrChange(peerId: PeerId, addrs: HashSet[MultiAddress]) = + proc addrChange(peerId: PeerId) {.gcsafe.} = addrChanged = true - proc protoChange(peerId: PeerId, protos: HashSet[string]) = - protoChanged = true - - proc keyChange(peerId: PeerId, publicKey: PublicKey) = - keyChanged = true - - peerStore.addHandlers(addrChangeHandler = addrChange, - protoChangeHandler = protoChange, - keyChangeHandler = keyChange) + peerStore[AddressBook].addHandler(addrChange) # Test listener triggered on adding multiaddr - peerStore.addressBook.add(peerId1, multiaddr1) - check: - addrChanged == true + peerStore[AddressBook][peerId1] = @[multiaddr1] + check: addrChanged == true - # Test listener triggered on setting addresses addrChanged = false - peerStore.addressBook.set(peerId2, - toHashSet([multiaddr1, multiaddr2])) check: + peerStore[AddressBook].del(peerId1) == true addrChanged == true - # Test listener triggered on adding proto - peerStore.protoBook.add(peerId1, testcodec1) - check: - protoChanged == true - - # Test listener triggered on setting protos - protoChanged = false - peerStore.protoBook.set(peerId2, - toHashSet([testcodec1, testcodec2])) - check: - protoChanged == true - - # Test listener triggered on setting public key - peerStore.keyBook.set(peerId1, - keyPair1.pubkey) - check: - keyChanged == true - - # Test listener triggered on changing public key - keyChanged = false - peerStore.keyBook.set(peerId1, - keyPair2.pubkey) - check: - keyChanged == true - - test "AddressBook API": + test "PeerBook API": # Set up address book - var - addressBook = PeerStore.new().addressBook + var addressBook = PeerStore.new()[AddressBook] # Test AddressBook::add - addressBook.add(peerId1, multiaddr1) + addressBook[peerId1] = @[multiaddr1] check: toSeq(keys(addressBook.book))[0] == peerId1 - toSeq(values(addressBook.book))[0] == toHashSet([multiaddr1]) + toSeq(values(addressBook.book))[0] == @[multiaddr1] # Test AddressBook::get check: - addressBook.get(peerId1) == toHashSet([multiaddr1]) + addressBook[peerId1] == @[multiaddr1] - # Test AddressBook::delete + # Test AddressBook::del check: - # Try to delete peerId that doesn't exist - addressBook.delete(peerId2) == false + # Try to del peerId that doesn't exist + addressBook.del(peerId2) == false # Delete existing peerId addressBook.book.len == 1 # sanity - addressBook.delete(peerId1) == true + addressBook.del(peerId1) == true addressBook.book.len == 0 # Test AddressBook::set # Set peerId2 with multiple multiaddrs - addressBook.set(peerId2, - toHashSet([multiaddr1, multiaddr2])) + addressBook[peerId2] = @[multiaddr1, multiaddr2] check: toSeq(keys(addressBook.book))[0] == peerId2 - toSeq(values(addressBook.book))[0] == toHashSet([multiaddr1, multiaddr2]) + toSeq(values(addressBook.book))[0] == @[multiaddr1, multiaddr2] - test "ProtoBook API": - # Set up protocol book - var - protoBook = PeerStore.new().protoBook + test "Pruner - no capacity": + let peerStore = PeerStore.new(capacity = 0) + peerStore[AgentBook][peerId1] = "gds" - # Test ProtoBook::add - protoBook.add(peerId1, testcodec1) + peerStore.cleanup(peerId1) + check peerId1 notin peerStore[AgentBook] + + test "Pruner - FIFO": + let peerStore = PeerStore.new(capacity = 1) + peerStore[AgentBook][peerId1] = "gds" + peerStore[AgentBook][peerId2] = "gds" + peerStore.cleanup(peerId2) + peerStore.cleanup(peerId1) check: - toSeq(keys(protoBook.book))[0] == peerId1 - toSeq(values(protoBook.book))[0] == toHashSet([testcodec1]) + peerId1 in peerStore[AgentBook] + peerId2 notin peerStore[AgentBook] - # Test ProtoBook::get - check: - protoBook.get(peerId1) == toHashSet([testcodec1]) + test "Pruner - regular capacity": + var peerStore = PeerStore.new(capacity = 20) - # Test ProtoBook::delete - check: - # Try to delete peerId that doesn't exist - protoBook.delete(peerId2) == false + for i in 0..<30: + let randomPeerId = PeerId.init(KeyPair.random(ECDSA, rng[]).get().pubkey).get() + peerStore[AgentBook][randomPeerId] = "gds" + peerStore.cleanup(randomPeerId) - # Delete existing peerId - protoBook.book.len == 1 # sanity - protoBook.delete(peerId1) == true - protoBook.book.len == 0 + check peerStore[AgentBook].len == 20 - # Test ProtoBook::set - # Set peerId2 with multiple protocols - protoBook.set(peerId2, - toHashSet([testcodec1, testcodec2])) - check: - toSeq(keys(protoBook.book))[0] == peerId2 - toSeq(values(protoBook.book))[0] == toHashSet([testcodec1, testcodec2]) + test "Pruner - infinite capacity": + var peerStore = PeerStore.new(capacity = -1) - test "KeyBook API": - # Set up key book - var - keyBook = PeerStore.new().keyBook + for i in 0..<30: + let randomPeerId = PeerId.init(KeyPair.random(ECDSA, rng[]).get().pubkey).get() + peerStore[AgentBook][randomPeerId] = "gds" + peerStore.cleanup(randomPeerId) - # Test KeyBook::set - keyBook.set(peerId1, - keyPair1.pubkey) - check: - toSeq(keys(keyBook.book))[0] == peerId1 - toSeq(values(keyBook.book))[0] == keyPair1.pubkey - - # Test KeyBook::get - check: - keyBook.get(peerId1) == keyPair1.pubkey - - # Test KeyBook::delete - check: - # Try to delete peerId that doesn't exist - keyBook.delete(peerId2) == false - - # Delete existing peerId - keyBook.book.len == 1 # sanity - keyBook.delete(peerId1) == true - keyBook.book.len == 0 + check peerStore[AgentBook].len == 30 diff --git a/tests/testswitch.nim b/tests/testswitch.nim index c24c9b8..23cb6ed 100644 --- a/tests/testswitch.nim +++ b/tests/testswitch.nim @@ -811,7 +811,7 @@ suite "Switch": let switch1 = newStandardSwitch() switch1.mount(testProto) - let switch2 = newStandardSwitch() + let switch2 = newStandardSwitch(peerStoreCapacity = 0) await switch1.start() await switch2.start() @@ -834,11 +834,11 @@ suite "Switch": check not switch2.isConnected(switch1.peerInfo.peerId) check: - switch1.peerStore.addressBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.addrs.toHashSet() - switch2.peerStore.addressBook.get(switch1.peerInfo.peerId) == switch1.peerInfo.addrs.toHashSet() + switch1.peerStore[AddressBook][switch2.peerInfo.peerId] == switch2.peerInfo.addrs + switch1.peerStore[ProtoBook][switch2.peerInfo.peerId] == switch2.peerInfo.protocols - switch1.peerStore.protoBook.get(switch2.peerInfo.peerId) == switch2.peerInfo.protocols.toHashSet() - switch2.peerStore.protoBook.get(switch1.peerInfo.peerId) == switch1.peerInfo.protocols.toHashSet() + switch1.peerInfo.peerId notin switch2.peerStore[AddressBook] + switch1.peerInfo.peerId notin switch2.peerStore[ProtoBook] asyncTest "e2e should allow multiple local addresses": when defined(windows):