Skip to content

Commit

Permalink
feat(libs/pidstore): Implement PeerIDStore (#2274)
Browse files Browse the repository at this point in the history
This PR implements a `PeerIDStore` that will be useful for both dumping
useful peers inside of celestia-node's use of p2p.Exchange as well as
inside of discovery.

Related to #1851

---------

Co-authored-by: Hlib Kanunnikov <[email protected]>
  • Loading branch information
renaynay and Wondertan authored Jun 16, 2023
1 parent fd18184 commit 6654cdf
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 0 deletions.
67 changes: 67 additions & 0 deletions libs/pidstore/pidstore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package pidstore

import (
"context"
"encoding/json"
"fmt"

"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/namespace"
logging "github.com/ipfs/go-log/v2"
"github.com/libp2p/go-libp2p/core/peer"
)

var (
storePrefix = datastore.NewKey("pidstore")
peersKey = datastore.NewKey("peers")

log = logging.Logger("pidstore")
)

// PeerIDStore is used to store/load peers to/from disk.
type PeerIDStore struct {
ds datastore.Datastore
}

// NewPeerIDStore creates a new peer ID store backed by the given datastore.
func NewPeerIDStore(ds datastore.Datastore) *PeerIDStore {
return &PeerIDStore{
ds: namespace.Wrap(ds, storePrefix),
}
}

// Load loads the peers from datastore and returns them.
func (p *PeerIDStore) Load(ctx context.Context) ([]peer.ID, error) {
log.Debug("Loading peers")

bin, err := p.ds.Get(ctx, peersKey)
if err != nil {
return nil, fmt.Errorf("pidstore: loading peers from datastore: %w", err)
}

var peers []peer.ID
err = json.Unmarshal(bin, &peers)
if err != nil {
return nil, fmt.Errorf("pidstore: unmarshalling peer IDs: %w", err)
}

log.Infow("Loaded peers from disk", "amount", len(peers))
return peers, nil
}

// Put persists the given peer IDs to the datastore.
func (p *PeerIDStore) Put(ctx context.Context, peers []peer.ID) error {
log.Debugw("Persisting peers to disk", "amount", len(peers))

bin, err := json.Marshal(peers)
if err != nil {
return fmt.Errorf("pidstore: marshal peerlist: %w", err)
}

if err = p.ds.Put(ctx, peersKey, bin); err != nil {
return fmt.Errorf("pidstore: error writing to datastore: %w", err)
}

log.Infow("Persisted peers successfully", "amount", len(peers))
return nil
}
59 changes: 59 additions & 0 deletions libs/pidstore/pidstore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package pidstore

import (
"context"
"crypto/rand"
"crypto/rsa"
"testing"
"time"

"github.com/ipfs/go-datastore"
"github.com/ipfs/go-datastore/sync"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestPutLoad(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer t.Cleanup(cancel)

peerstore := NewPeerIDStore(sync.MutexWrap(datastore.NewMapDatastore()))

ids, err := generateRandomPeerList(10)
require.NoError(t, err)

err = peerstore.Put(ctx, ids)
require.NoError(t, err)

retrievedPeerlist, err := peerstore.Load(ctx)
require.NoError(t, err)

assert.Equal(t, len(ids), len(retrievedPeerlist))
assert.Equal(t, ids, retrievedPeerlist)
}

func generateRandomPeerList(length int) ([]peer.ID, error) {
peerlist := make([]peer.ID, length)
for i := range peerlist {
key, err := rsa.GenerateKey(rand.Reader, 2096)
if err != nil {
return nil, err
}

_, pubkey, err := crypto.KeyPairFromStdKey(key)
if err != nil {
return nil, err
}

peerID, err := peer.IDFromPublicKey(pubkey)
if err != nil {
return nil, err
}

peerlist[i] = peerID
}

return peerlist, nil
}

0 comments on commit 6654cdf

Please sign in to comment.