Files

274 lines
7.8 KiB
Markdown
Raw Permalink Normal View History

2026-07-24 11:27:32 +02:00
# Tutorial 10: Peer Store Management
The **peer store** is libp2p's database of known peers. It maps peer IDs
to their known addresses, protocols, public keys, and metadata.
A well-maintained peer store helps:
- Reconnect to known peers without re-discovery
- Track protocol capabilities of known peers
- Maintain a persistent view of the network
In this tutorial we'll:
- List known peers
- Get detailed peer info
- Manually add peers to the store
- Update addresses and protocols
- Delete peers from the store
-----------
```cpp
#include <cstdio>
#include <string>
#include <vector>
#include "plugin.h"
int main()
{
printf("=== Tutorial 10: Peer Store Management ===\n\n");
```
## Step 1: Create two nodes
The peer store is automatically available on any started node.
We use one main node and one remote peer so the main node's peerstore
contains real peer data after a connection is established.
```cpp
Libp2pModuleOptions opts;
opts.addrs = {"/ip4/127.0.0.1/tcp/9790"};
Libp2pModuleOptions remoteOpts;
remoteOpts.addrs = {"/ip4/127.0.0.1/tcp/9791"};
Libp2pModuleImpl node(opts);
Libp2pModuleImpl remote(remoteOpts);
if (!node.start().success) {
fprintf(stderr, "Node failed to start\n");
return 1;
}
if (!remote.start().success) {
fprintf(stderr, "Remote node failed to start\n");
return 1;
}
auto infoRes = node.peerInfo();
if (!infoRes.success) {
fprintf(stderr, "Failed to get node info: %s\n",
infoRes.error.c_str());
return 1;
}
auto info = infoRes.value;
std::string nodePeerId = info["peerId"].get<std::string>();
printf("Node started, peer ID: %s\n", nodePeerId.c_str());
auto remoteInfoRes = remote.peerInfo();
if (!remoteInfoRes.success) {
fprintf(stderr, "Failed to get remote node info: %s\n",
remoteInfoRes.error.c_str());
return 1;
}
auto remoteInfo = remoteInfoRes.value;
std::string remotePeerId = remoteInfo["peerId"].get<std::string>();
std::vector<std::string> remoteAddrs;
for (const auto& a : remoteInfo["addrs"]) {
remoteAddrs.push_back(a.get<std::string>());
}
printf("Remote node started, peer ID: %s\n", remotePeerId.c_str());
```
## Step 2: List known peers
Initially, the peer store may be empty because no remote peers have
been discovered or added yet.
`peerstoreGetPeers()` returns a JSON array of peer IDs.
```cpp
printf("\nListing known peers...\n");
auto peersRes = node.peerstoreGetPeers();
if (!peersRes.success) {
fprintf(stderr, "Failed to list peers: %s\n",
peersRes.error.c_str());
return 1;
}
printf("Found %zu known peer(s):\n", peersRes.value.size());
for (const auto& p : peersRes.value) {
printf(" %s\n", p.get<std::string>().c_str());
}
```
## Step 3: Connect a remote peer and get detailed peer info
`peerstoreGetPeerInfo()` returns a rich JSON object with addresses,
protocols, and the public key.
```cpp
printf("\nConnecting to remote peer...\n");
if (!node.connectPeer(remotePeerId, remoteAddrs, 5000).success) {
fprintf(stderr, "Failed to connect to remote peer\n");
return 1;
}
printf("Connected to remote peer\n");
printf("\nGetting remote peer info from the store:\n");
auto remoteStoreInfo = node.peerstoreGetPeerInfo(remotePeerId);
if (!remoteStoreInfo.success) {
fprintf(stderr, "Failed to get remote peer info: %s\n",
remoteStoreInfo.error.c_str());
return 1;
}
printf(" Peer ID: %s\n",
remoteStoreInfo.value["peerId"].get<std::string>().c_str());
printf(" Public key: %s\n",
remoteStoreInfo.value["publicKey"].get<std::string>().c_str());
printf(" Addresses:\n");
for (const auto& a : remoteStoreInfo.value["addrs"]) {
printf(" %s\n", a.get<std::string>().c_str());
}
printf(" Protocols:\n");
for (const auto& p : remoteStoreInfo.value["protocols"]) {
printf(" %s\n", p.get<std::string>().c_str());
}
```
## Step 4: Manually add a peer to the store
You can manually register peers in the store. This is useful for
peers discovered through out-of-band methods (e.g. a config file,
QR code, or DNS).
```cpp
printf("\nManually adding a peer to the store...\n");
std::string manualPeerId =
"16Uiu2HAkzM1nzU99VxRqzF9CjZAqjF3MZHQ2oRENL7SNgP1d8pRy";
std::vector<std::string> manualAddrs = {
"/ip4/192.168.1.100/tcp/9000",
"/ip4/10.0.0.50/tcp/9001",
};
std::vector<std::string> manualProtos = {
"/ipfs/ping/1.0.0",
"/examples/echo/1.0.0",
};
if (!node.peerstoreAddPeer(manualPeerId, manualAddrs, manualProtos)
.success) {
fprintf(stderr, "Failed to add peer\n");
return 1;
}
printf("Peer added: %s\n", manualPeerId.c_str());
```
Verify it was added:
```cpp
printf("\nVerifying: listing peers again...\n");
auto peersAfter = node.peerstoreGetPeers();
if (!peersAfter.success) {
fprintf(stderr, "Failed to list peers after add: %s\n",
peersAfter.error.c_str());
return 1;
}
printf("Now have %zu known peer(s)\n", peersAfter.value.size());
if (peersAfter.value.size() != 2) {
2026-07-24 15:41:41 +02:00
fprintf(stderr, "Expected to have 2 peers in the peer store after manually adding one");
2026-07-24 11:27:32 +02:00
return 1;
}
```
## Step 5: Update peer info
2026-07-24 15:40:52 +02:00
`peerstoreSetPeerAddresses()` to update a peer's stored data.
2026-07-24 11:27:32 +02:00
```cpp
printf("\nUpdating peer addresses...\n");
std::vector<std::string> updatedAddrs = {
"/ip4/192.168.1.100/tcp/9002",
"/dns4/peer.example.com/tcp/9000",
};
if (!node.peerstoreSetPeerAddresses(manualPeerId, updatedAddrs)
.success) {
fprintf(stderr, "Failed to update addresses\n");
return 1;
}
printf("Addresses updated\n");
// Check the updated info:
auto updatedInfo = node.peerstoreGetPeerInfo(manualPeerId);
if (!updatedInfo.success) {
fprintf(stderr, "Failed to get updated peer info: %s\n",
updatedInfo.error.c_str());
return 1;
}
printf("Updated addresses:\n");
for (const auto& a : updatedInfo.value["addrs"]) {
printf(" %s\n", a.get<std::string>().c_str());
}
```
## Step 6: Delete a peer from the store
`peerstoreDeletePeer()` removes a peer and all its metadata.
```cpp
printf("\nDeleting peer from store...\n");
if (!node.peerstoreDeletePeer(manualPeerId).success) {
fprintf(stderr, "Failed to delete peer\n");
return 1;
}
printf("Peer deleted\n");
```
Verify deletion:
```cpp
auto peersFinal = node.peerstoreGetPeers();
if (!peersFinal.success) {
fprintf(stderr, "Failed to list peers after delete: %s\n",
peersFinal.error.c_str());
return 1;
}
printf("Now have %zu known peer(s)\n",
peersFinal.value.size());
for (const auto& p : peersFinal.value) {
printf(" %s\n", p.get<std::string>().c_str());
}
```
## Step 7: Clean up
```cpp
node.stop();
remote.stop();
printf("\n=== Tutorial 10 Complete ===\n");
return 0;
}
```
## Key Takeaways
- The peer store is a built-in database of known peers
- `peerstoreGetPeers()` lists all known peer IDs
- `peerstoreGetPeerInfo()` returns detailed peer metadata
- `peerstoreAddPeer()` adds peers manually (with addresses + protocols)
2026-07-24 15:40:52 +02:00
- `peerstoreSetPeerAddresses()` update existing entries
2026-07-24 11:27:32 +02:00
- `peerstoreDeletePeer()` removes peers
- A populated peer store speeds up reconnection and reduces
network overhead
## Run tutorial
```bash
./build/tutorial/tutorial_10_peerstore
```
---
<p align="center"><a href="tutorial_9_service_discovery.md">&larr; Service Discovery</a> &nbsp;|&nbsp; <a href="tutorial_11_circuit_relay.md">Circuit Relay Connecting Through Firewalls &rarr;</a></p>