Commit 4a8cbbce authored by Steven Allen's avatar Steven Allen

implement record validation

we should be doing this in the offline router
parent fb46bb48
......@@ -2,18 +2,12 @@ package mockrouting
import (
"context"
"errors"
"time"
proto "github.com/gogo/protobuf/proto"
cid "github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
dshelp "github.com/ipfs/go-ipfs-ds-help"
u "github.com/ipfs/go-ipfs-util"
logging "github.com/ipfs/go-log"
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
dhtpb "github.com/libp2p/go-libp2p-record/pb"
routing "github.com/libp2p/go-libp2p-routing"
ropts "github.com/libp2p/go-libp2p-routing/options"
"github.com/libp2p/go-testutil"
......@@ -23,46 +17,21 @@ import (
var log = logging.Logger("mockrouter")
type client struct {
datastore ds.Datastore
server server
peer testutil.Identity
vs routing.ValueStore
server server
peer testutil.Identity
}
// FIXME(brian): is this method meant to simulate putting a value into the network?
func (c *client) PutValue(ctx context.Context, key string, val []byte, opts ...ropts.Option) error {
log.Debugf("PutValue: %s", key)
rec := new(dhtpb.Record)
rec.Value = val
rec.Key = proto.String(string(key))
rec.TimeReceived = proto.String(u.FormatRFC3339(time.Now()))
data, err := proto.Marshal(rec)
if err != nil {
return err
}
return c.datastore.Put(dshelp.NewKeyFromBinary([]byte(key)), data)
return c.vs.PutValue(ctx, key, val, opts...)
}
// FIXME(brian): is this method meant to simulate getting a value from the network?
func (c *client) GetValue(ctx context.Context, key string, opts ...ropts.Option) ([]byte, error) {
log.Debugf("GetValue: %s", key)
v, err := c.datastore.Get(dshelp.NewKeyFromBinary([]byte(key)))
if err != nil {
return nil, err
}
data, ok := v.([]byte)
if !ok {
return nil, errors.New("could not cast value from datastore")
}
rec := new(dhtpb.Record)
err = proto.Unmarshal(data, rec)
if err != nil {
return nil, err
}
return rec.GetValue(), nil
return c.vs.GetValue(ctx, key, opts...)
}
func (c *client) FindProviders(ctx context.Context, key *cid.Cid) ([]pstore.PeerInfo, error) {
......
......@@ -12,6 +12,8 @@ import (
peer "github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
"github.com/libp2p/go-testutil"
offline "github.com/ipfs/go-ipfs-routing/offline"
)
// server is the mockrouting.Client's private interface to the routing server
......@@ -84,8 +86,8 @@ func (rs *s) Client(p testutil.Identity) Client {
func (rs *s) ClientWithDatastore(_ context.Context, p testutil.Identity, datastore ds.Datastore) Client {
return &client{
peer: p,
datastore: datastore,
server: rs,
peer: p,
vs: offline.NewOfflineRouter(datastore, MockValidator{}),
server: rs,
}
}
......@@ -14,6 +14,12 @@ import (
"github.com/libp2p/go-testutil"
)
// MockValidator is a record validator that always returns success.
type MockValidator struct{}
func (MockValidator) Validate(_ string, _ []byte) error { return nil }
func (MockValidator) Select(_ string, _ [][]byte) (int, error) { return 0, nil }
// Server provides mockrouting Clients
type Server interface {
Client(p testutil.Identity) Client
......
......@@ -3,6 +3,7 @@
package offline
import (
"bytes"
"context"
"errors"
"time"
......@@ -11,7 +12,6 @@ import (
cid "github.com/ipfs/go-cid"
ds "github.com/ipfs/go-datastore"
dshelp "github.com/ipfs/go-ipfs-ds-help"
ci "github.com/libp2p/go-libp2p-crypto"
"github.com/libp2p/go-libp2p-peer"
pstore "github.com/libp2p/go-libp2p-peerstore"
record "github.com/libp2p/go-libp2p-record"
......@@ -27,10 +27,10 @@ var ErrOffline = errors.New("routing system in offline mode")
// NewOfflineRouter returns an IpfsRouting implementation which only performs
// offline operations. It allows to Put and Get signed dht
// records to and from the local datastore.
func NewOfflineRouter(dstore ds.Datastore, privkey ci.PrivKey) routing.IpfsRouting {
func NewOfflineRouter(dstore ds.Datastore, validator record.Validator) routing.IpfsRouting {
return &offlineRouting{
datastore: dstore,
sk: privkey,
validator: validator,
}
}
......@@ -39,10 +39,28 @@ func NewOfflineRouter(dstore ds.Datastore, privkey ci.PrivKey) routing.IpfsRouti
// records to and from the local datastore.
type offlineRouting struct {
datastore ds.Datastore
sk ci.PrivKey
validator record.Validator
}
func (c *offlineRouting) PutValue(ctx context.Context, key string, val []byte, _ ...ropts.Option) error {
if err := c.validator.Validate(key, val); err != nil {
return err
}
if old, err := c.GetValue(ctx, key); err == nil {
// be idempotent to be nice.
if bytes.Equal(old, val) {
return nil
}
// check to see if the older record is better
i, err := c.validator.Select(key, [][]byte{val, old})
if err != nil {
// this shouldn't happen for validated records.
return err
}
if i != 0 {
return errors.New("can't replace a newer record with an older one")
}
}
rec := record.MakePutRecord(key, val)
data, err := proto.Marshal(rec)
if err != nil {
......@@ -67,8 +85,13 @@ func (c *offlineRouting) GetValue(ctx context.Context, key string, _ ...ropts.Op
if err != nil {
return nil, err
}
val := rec.GetValue()
return rec.GetValue(), nil
err = c.validator.Validate(key, val)
if err != nil {
return nil, err
}
return val, nil
}
func (c *offlineRouting) FindPeer(ctx context.Context, pid peer.ID) (pstore.PeerInfo, error) {
......
......@@ -12,12 +12,16 @@ import (
mh "github.com/multiformats/go-multihash"
)
type blankValidator struct{}
func (blankValidator) Validate(_ string, _ []byte) error { return nil }
func (blankValidator) Select(_ string, _ [][]byte) (int, error) { return 0, nil }
func TestOfflineRouterStorage(t *testing.T) {
ctx := context.Background()
nds := ds.NewMapDatastore()
privkey, _, _ := testutil.RandTestKeyPair(128)
offline := NewOfflineRouter(nds, privkey)
offline := NewOfflineRouter(nds, blankValidator{})
if err := offline.PutValue(ctx, "key", []byte("testing 1 2 3")); err != nil {
t.Fatal(err)
......@@ -55,8 +59,7 @@ func TestOfflineRouterLocal(t *testing.T) {
ctx := context.Background()
nds := ds.NewMapDatastore()
privkey, _, _ := testutil.RandTestKeyPair(128)
offline := NewOfflineRouter(nds, privkey)
offline := NewOfflineRouter(nds, blankValidator{})
id, _ := testutil.RandPeerID()
_, err := offline.FindPeer(ctx, id)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment