frostfs-node/lib/peers/peerstore.go

239 lines
6 KiB
Go
Raw Normal View History

package peers
import (
"crypto/ecdsa"
"crypto/elliptic"
"github.com/multiformats/go-multiaddr"
crypto "github.com/nspcc-dev/neofs-crypto"
"github.com/nspcc-dev/neofs-node/lib/netmap"
"github.com/pkg/errors"
"go.uber.org/zap"
)
type (
// Store is an interface to storage of all p2p connections
Store interface {
SelfIDReceiver
PublicKeyStore
AddressIDReceiver
AddPeer(multiaddr.Multiaddr, *ecdsa.PublicKey, *ecdsa.PrivateKey) (ID, error)
DeletePeer(ID)
PeerNetAddressStore
GetPrivateKey(ID) (*ecdsa.PrivateKey, error)
Update(*netmap.NetMap) error
Sign([]byte) ([]byte, error)
Verify(id ID, data, sign []byte) error
Check(min int) error
}
// PublicKeyStore is an interface of the storage of peer's public keys.
PublicKeyStore interface {
GetPublicKey(ID) (*ecdsa.PublicKey, error)
}
// SelfIDReceiver is an interface of local peer ID value with read access.
SelfIDReceiver interface {
SelfID() ID
}
// AddressIDReceiver is an interface of Multiaddr to ID converter.
AddressIDReceiver interface {
AddressID(multiaddr.Multiaddr) (ID, error)
}
// PeerNetAddressStore is an interface of ID to Multiaddr converter.
PeerNetAddressStore interface {
GetAddr(ID) (multiaddr.Multiaddr, error)
}
// StoreParams for creating new Store.
StoreParams struct {
Addr multiaddr.Multiaddr
Key *ecdsa.PrivateKey
Storage Storage
StoreCap int
Logger *zap.Logger
}
store struct {
self ID
addr multiaddr.Multiaddr
storage Storage
log *zap.Logger
key *ecdsa.PrivateKey
}
)
const defaultMinimalSignaturesCount = 3
var errPeerNotFound = errors.New("peer not found")
func (p *store) AddressID(addr multiaddr.Multiaddr) (ID, error) {
if p.addr.Equal(addr) {
return p.self, nil
}
res := p.storage.Filter(maddrFilter(addr))
if len(res) == 0 {
return "", errPeerNotFound
}
return res[0], nil
}
func maddrFilter(addr multiaddr.Multiaddr) PeerFilter {
return func(p Peer) bool { return addr.Equal(p.Address()) }
}
// SelfID return ID of current Node.
func (p *store) SelfID() ID {
return p.self
}
// AddPeer to store..
// Try to get PeerID from PublicKey, or return error
// Store Address and PublicKey for that PeerID.
func (p *store) AddPeer(addr multiaddr.Multiaddr, pub *ecdsa.PublicKey, key *ecdsa.PrivateKey) (ID, error) {
item := NewPeer(addr, pub, key)
if err := p.storage.Set(item.ID(), item); err != nil {
return "", err
}
return item.ID(), nil
}
// DeletePeer from store.
func (p *store) DeletePeer(id ID) {
if err := p.storage.Rem(id); err != nil {
p.log.Error("could not delete peer",
zap.Stringer("id", id),
zap.Error(err))
}
}
// Update update Store by new network map.
func (p *store) Update(nm *netmap.NetMap) error {
if err := p.storage.Update(nm); err != nil {
return err
}
// we must provide our PrivateKey, after updating
if peer, err := p.storage.Get(p.self); err != nil {
peer = NewPeer(p.addr, &p.key.PublicKey, p.key)
return p.storage.Set(p.self, peer)
} else if err := peer.SetPrivateKey(p.key); err != nil {
return errors.Wrapf(err, "could not update private key (%s)", p.self.String())
} else if err := p.storage.Set(p.self, peer); err != nil {
return errors.Wrapf(err, "could not save peer(%s)", p.self.String())
}
return nil
}
// GetAddr by PeerID.
func (p *store) GetAddr(id ID) (multiaddr.Multiaddr, error) {
n, err := p.storage.Get(id)
if err != nil {
return nil, err
}
return n.Address(), nil
}
// GetPublicKey by PeerID.
func (p *store) GetPublicKey(id ID) (*ecdsa.PublicKey, error) {
n, err := p.storage.Get(id)
if err != nil {
return nil, err
}
return n.PublicKey(), nil
}
// GetPrivateKey by PeerID.
func (p *store) GetPrivateKey(id ID) (*ecdsa.PrivateKey, error) {
n, err := p.storage.Get(id)
if err != nil {
return nil, err
}
return n.PrivateKey()
}
// Sign signs a data using the private key. If the data is longer than
// the bit-length of the private key's curve order, the hash will be
// truncated to that length. It returns the signature as slice bytes.
// The security of the private key depends on the entropy of rand.
func (p *store) Sign(data []byte) ([]byte, error) {
return crypto.Sign(p.key, data)
}
// Verify verifies the signature in r, s of hash using the public key, pub. Its
// return value records whether the signature is valid.
// If store doesn't contains public key for ID,
// returns error about that
// TODO we must provide same method, but for IR list, to check,
// that we have valid signatures of needed IR members
func (p *store) Verify(id ID, data, sign []byte) error {
if pub, err := p.GetPublicKey(id); err != nil {
return errors.Wrap(err, "could not get PublicKey")
} else if err := crypto.Verify(pub, data, sign); err != nil {
return errors.Wrapf(err, "could not verify signature: sign(`%x`) & data(`%x`)", sign, data)
}
return nil
}
// Neighbours peers that which are distributed by hrw(id).
func (p *store) Neighbours(seed int64, count int) ([]ID, error) {
return p.storage.List(p.self, seed, count)
}
// Check validate signatures count
// TODO replace with settings or something else.
// We can fetch min-count from settings, or
// use another method for validate this..
func (p *store) Check(min int) error {
if min <= defaultMinimalSignaturesCount {
return errors.Errorf("invalid count of valid signatures: minimum %d, actual %d",
defaultMinimalSignaturesCount,
min,
)
}
return nil
}
// NewStore creates new store by params.
func NewStore(p StoreParams) (Store, error) {
var storage Storage
if p.Key == nil || p.Key.Curve != elliptic.P256() {
return nil, crypto.ErrEmptyPrivateKey
}
if p.Addr == nil {
return nil, errNilMultiaddr
}
if storage = p.Storage; storage == nil {
storage = NewSimpleStorage(p.StoreCap, p.Logger)
}
id := IDFromPublicKey(&p.Key.PublicKey)
peer := NewPeer(p.Addr, &p.Key.PublicKey, p.Key)
if err := storage.Set(id, peer); err != nil {
return nil, err
}
return &store{
self: id,
storage: storage,
key: p.Key,
addr: p.Addr,
log: p.Logger,
}, nil
}