-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from raulk/ds-backed-keybook-metadata
Datastore-backed implementations of KeyBook and PeerMetadata
- Loading branch information
Showing
7 changed files
with
286 additions
and
46 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package pstoreds | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
|
||
ds "github.com/ipfs/go-datastore" | ||
query "github.com/ipfs/go-datastore/query" | ||
|
||
ic "github.com/libp2p/go-libp2p-crypto" | ||
peer "github.com/libp2p/go-libp2p-peer" | ||
pstore "github.com/libp2p/go-libp2p-peerstore" | ||
) | ||
|
||
// Public and private keys are stored under the following db key pattern: | ||
// /peers/keys/<b58 of peer id>/{pub, priv} | ||
var ( | ||
kbBase = ds.NewKey("/peers/keys") | ||
pubSuffix = ds.NewKey("/pub") | ||
privSuffix = ds.NewKey("/priv") | ||
) | ||
|
||
type dsKeyBook struct { | ||
ds ds.TxnDatastore | ||
} | ||
|
||
var _ pstore.KeyBook = (*dsKeyBook)(nil) | ||
|
||
func NewKeyBook(_ context.Context, store ds.TxnDatastore, _ Options) (pstore.KeyBook, error) { | ||
return &dsKeyBook{store}, nil | ||
} | ||
|
||
func (kb *dsKeyBook) PubKey(p peer.ID) ic.PubKey { | ||
key := kbBase.ChildString(peer.IDB58Encode(p)).Child(pubSuffix) | ||
|
||
var pk ic.PubKey | ||
if value, err := kb.ds.Get(key); err == nil { | ||
pk, err = ic.UnmarshalPublicKey(value) | ||
if err != nil { | ||
log.Errorf("error when unmarshalling pubkey from datastore for peer %s: %s\n", p.Pretty(), err) | ||
} | ||
} else if err == ds.ErrNotFound { | ||
pk, err = p.ExtractPublicKey() | ||
if err != nil { | ||
log.Errorf("error when extracting pubkey from peer ID for peer %s: %s\n", p.Pretty(), err) | ||
return nil | ||
} | ||
pkb, err := pk.Bytes() | ||
if err != nil { | ||
log.Errorf("error when turning extracted pubkey into bytes for peer %s: %s\n", p.Pretty(), err) | ||
return nil | ||
} | ||
err = kb.ds.Put(key, pkb) | ||
if err != nil { | ||
log.Errorf("error when adding extracted pubkey to peerstore for peer %s: %s\n", p.Pretty(), err) | ||
return nil | ||
} | ||
} else { | ||
log.Errorf("error when fetching pubkey from datastore for peer %s: %s\n", p.Pretty(), err) | ||
} | ||
|
||
return pk | ||
} | ||
|
||
func (kb *dsKeyBook) AddPubKey(p peer.ID, pk ic.PubKey) error { | ||
// check it's correct. | ||
if !p.MatchesPublicKey(pk) { | ||
return errors.New("peer ID does not match public key") | ||
} | ||
|
||
key := kbBase.ChildString(peer.IDB58Encode(p)).Child(pubSuffix) | ||
val, err := pk.Bytes() | ||
if err != nil { | ||
log.Errorf("error while converting pubkey byte string for peer %s: %s\n", p.Pretty(), err) | ||
return err | ||
} | ||
err = kb.ds.Put(key, val) | ||
if err != nil { | ||
log.Errorf("error while updating pubkey in datastore for peer %s: %s\n", p.Pretty(), err) | ||
} | ||
return err | ||
} | ||
|
||
func (kb *dsKeyBook) PrivKey(p peer.ID) ic.PrivKey { | ||
key := kbBase.ChildString(peer.IDB58Encode(p)).Child(privSuffix) | ||
value, err := kb.ds.Get(key) | ||
if err != nil { | ||
log.Errorf("error while fetching privkey from datastore for peer %s: %s\n", p.Pretty(), err) | ||
return nil | ||
} | ||
sk, err := ic.UnmarshalPrivateKey(value) | ||
if err != nil { | ||
return nil | ||
} | ||
return sk | ||
} | ||
|
||
func (kb *dsKeyBook) AddPrivKey(p peer.ID, sk ic.PrivKey) error { | ||
if sk == nil { | ||
return errors.New("private key is nil") | ||
} | ||
// check it's correct. | ||
if !p.MatchesPrivateKey(sk) { | ||
return errors.New("peer ID does not match private key") | ||
} | ||
|
||
key := kbBase.ChildString(peer.IDB58Encode(p)).Child(privSuffix) | ||
val, err := sk.Bytes() | ||
if err != nil { | ||
log.Errorf("error while converting privkey byte string for peer %s: %s\n", p.Pretty(), err) | ||
return err | ||
} | ||
err = kb.ds.Put(key, val) | ||
if err != nil { | ||
log.Errorf("error while updating privkey in datastore for peer %s: %s\n", p.Pretty(), err) | ||
} | ||
return err | ||
} | ||
|
||
func (kb *dsKeyBook) PeersWithKeys() peer.IDSlice { | ||
ids, err := uniquePeerIds(kb.ds, kbBase, func(result query.Result) string { | ||
return ds.RawKey(result.Key).Parent().Name() | ||
}) | ||
if err != nil { | ||
log.Errorf("error while retrieving peers with keys: %v", err) | ||
} | ||
return ids | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package pstoreds | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"encoding/gob" | ||
|
||
ds "github.com/ipfs/go-datastore" | ||
|
||
pool "github.com/libp2p/go-buffer-pool" | ||
peer "github.com/libp2p/go-libp2p-peer" | ||
pstore "github.com/libp2p/go-libp2p-peerstore" | ||
) | ||
|
||
// Metadata is stored under the following db key pattern: | ||
// /peers/metadata/<b58 peer id>/<key> | ||
var pmBase = ds.NewKey("/peers/metadata") | ||
|
||
type dsPeerMetadata struct { | ||
ds ds.Datastore | ||
} | ||
|
||
var _ pstore.PeerMetadata = (*dsPeerMetadata)(nil) | ||
|
||
func init() { | ||
// Gob registers basic types by default. | ||
// | ||
// Register complex types used by the peerstore itself. | ||
gob.Register(make(map[string]struct{})) | ||
} | ||
|
||
// NewPeerMetadata creates a metadata store backed by a persistent db. It uses gob for serialisation. | ||
// | ||
// See `init()` to learn which types are registered by default. Modules wishing to store | ||
// values of other types will need to `gob.Register()` them explicitly, or else callers | ||
// will receive runtime errors. | ||
func NewPeerMetadata(_ context.Context, store ds.Datastore, _ Options) (pstore.PeerMetadata, error) { | ||
return &dsPeerMetadata{store}, nil | ||
} | ||
|
||
func (pm *dsPeerMetadata) Get(p peer.ID, key string) (interface{}, error) { | ||
k := pmBase.ChildString(peer.IDB58Encode(p)).ChildString(key) | ||
value, err := pm.ds.Get(k) | ||
if err != nil { | ||
if err == ds.ErrNotFound { | ||
err = pstore.ErrNotFound | ||
} | ||
return nil, err | ||
} | ||
|
||
var res interface{} | ||
if err := gob.NewDecoder(bytes.NewReader(value)).Decode(&res); err != nil { | ||
return nil, err | ||
} | ||
return res, nil | ||
} | ||
|
||
func (pm *dsPeerMetadata) Put(p peer.ID, key string, val interface{}) error { | ||
k := pmBase.ChildString(peer.IDB58Encode(p)).ChildString(key) | ||
var buf pool.Buffer | ||
if err := gob.NewEncoder(&buf).Encode(&val); err != nil { | ||
return err | ||
} | ||
return pm.ds.Put(k, buf.Bytes()) | ||
} |
Oops, something went wrong.