From feeada0d90ee911dcadd36217c71da437f32c88d Mon Sep 17 00:00:00 2001 From: Jeromy Date: Fri, 16 Jan 2015 22:46:44 +0000 Subject: [PATCH] fix fuse mounting issues this time, without loading the private key on every startup --- cmd/ipfs/init.go | 29 +++++++++++++ core/core.go | 14 +++++- fuse/ipns/ipns_unix.go | 17 ++++++++ routing/dht/dht.go | 17 +++++++- routing/dht/ext_test.go | 8 +++- routing/dht/records.go | 14 +++--- routing/dht/routing.go | 9 +++- routing/offline/offline.go | 89 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 186 insertions(+), 11 deletions(-) create mode 100644 routing/offline/offline.go diff --git a/cmd/ipfs/init.go b/cmd/ipfs/init.go index 0fe8fdaef..ec8025bc0 100644 --- a/cmd/ipfs/init.go +++ b/cmd/ipfs/init.go @@ -11,6 +11,7 @@ import ( core "github.com/jbenet/go-ipfs/core" corecmds "github.com/jbenet/go-ipfs/core/commands" coreunix "github.com/jbenet/go-ipfs/core/coreunix" + ipns "github.com/jbenet/go-ipfs/fuse/ipns" ci "github.com/jbenet/go-ipfs/p2p/crypto" peer "github.com/jbenet/go-ipfs/p2p/peer" repo "github.com/jbenet/go-ipfs/repo" @@ -110,6 +111,11 @@ func doInit(repoRoot string, force bool, nBitsForKeypair int) (interface{}, erro return nil, err } + err = initializeIpnsKeyspace(repoRoot) + if err != nil { + return nil, err + } + return nil, nil } @@ -138,6 +144,29 @@ func addTheWelcomeFile(repoRoot string) error { return nil } +func initializeIpnsKeyspace(repoRoot string) error { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + r := fsrepo.At(repoRoot) + if err := r.Open(); err != nil { // NB: repo is owned by the node + return err + } + + nd, err := core.NewIPFSNode(ctx, core.Offline(r)) + if err != nil { + return err + } + defer nd.Close() + + err = nd.SetupOfflineRouting() + if err != nil { + return err + } + + return ipns.InitializeKeyspace(nd, nd.PrivateKey) +} + func datastoreConfig() (*config.Datastore, error) { dspath, err := config.DataStorePath("") if err != nil { diff --git a/core/core.go b/core/core.go index ce7a61440..74aa655cb 100644 --- a/core/core.go +++ b/core/core.go @@ -34,9 +34,10 @@ import ( config "github.com/jbenet/go-ipfs/repo/config" routing "github.com/jbenet/go-ipfs/routing" dht "github.com/jbenet/go-ipfs/routing/dht" + offroute "github.com/jbenet/go-ipfs/routing/offline" + eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog" util "github.com/jbenet/go-ipfs/util" debugerror "github.com/jbenet/go-ipfs/util/debugerror" - eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog" lgbl "github.com/jbenet/go-ipfs/util/eventlog/loggables" ) @@ -350,6 +351,17 @@ func (n *IpfsNode) loadPrivateKey() error { n.PrivateKey = sk n.Peerstore.AddPrivKey(n.Identity, n.PrivateKey) + n.Peerstore.AddPubKey(n.Identity, sk.GetPublic()) + return nil +} + +func (n *IpfsNode) SetupOfflineRouting() error { + err := n.loadPrivateKey() + if err != nil { + return err + } + + n.Routing = offroute.NewOfflineRouter(n.Repo.Datastore(), n.PrivateKey) return nil } diff --git a/fuse/ipns/ipns_unix.go b/fuse/ipns/ipns_unix.go index 962a59536..78f1b5687 100644 --- a/fuse/ipns/ipns_unix.go +++ b/fuse/ipns/ipns_unix.go @@ -16,6 +16,7 @@ import ( core "github.com/jbenet/go-ipfs/core" chunk "github.com/jbenet/go-ipfs/importer/chunk" mdag "github.com/jbenet/go-ipfs/merkledag" + nsys "github.com/jbenet/go-ipfs/namesys" ci "github.com/jbenet/go-ipfs/p2p/crypto" ft "github.com/jbenet/go-ipfs/unixfs" uio "github.com/jbenet/go-ipfs/unixfs/io" @@ -32,6 +33,22 @@ var ( longRepublishTimeout = time.Millisecond * 500 ) +func InitializeKeyspace(n *core.IpfsNode, key ci.PrivKey) error { + emptyDir := &mdag.Node{Data: ft.FolderPBData()} + k, err := n.DAG.Add(emptyDir) + if err != nil { + return err + } + + pub := nsys.NewRoutingPublisher(n.Routing) + err = pub.Publish(key, k.B58String()) + if err != nil { + return err + } + + return nil +} + // FileSystem is the readwrite IPNS Fuse Filesystem. type FileSystem struct { Ipfs *core.IpfsNode diff --git a/routing/dht/dht.go b/routing/dht/dht.go index 9f4860880..e4a285528 100644 --- a/routing/dht/dht.go +++ b/routing/dht/dht.go @@ -10,6 +10,7 @@ import ( "sync" "time" + ci "github.com/jbenet/go-ipfs/p2p/crypto" host "github.com/jbenet/go-ipfs/p2p/host" peer "github.com/jbenet/go-ipfs/p2p/peer" protocol "github.com/jbenet/go-ipfs/p2p/protocol" @@ -234,9 +235,23 @@ func (dht *IpfsDHT) getLocal(key u.Key) ([]byte, error) { return rec.GetValue(), nil } +func (dht *IpfsDHT) getOwnPrivateKey() (ci.PrivKey, error) { + sk := dht.peerstore.PrivKey(dht.self) + if sk == nil { + log.Errorf("%s dht cannot get own private key!", dht.self) + return nil, fmt.Errorf("cannot get private key to sign record!") + } + return sk, nil +} + // putLocal stores the key value pair in the datastore func (dht *IpfsDHT) putLocal(key u.Key, value []byte) error { - rec, err := dht.makePutRecord(key, value) + sk, err := dht.getOwnPrivateKey() + if err != nil { + return err + } + + rec, err := MakePutRecord(sk, key, value) if err != nil { return err } diff --git a/routing/dht/ext_test.go b/routing/dht/ext_test.go index 6f12c3113..808e27b10 100644 --- a/routing/dht/ext_test.go +++ b/routing/dht/ext_test.go @@ -98,7 +98,13 @@ func TestGetFailures(t *testing.T) { { typ := pb.Message_GET_VALUE str := "hello" - rec, err := d.makePutRecord(u.Key(str), []byte("blah")) + + sk, err := d.getOwnPrivateKey() + if err != nil { + t.Fatal(err) + } + + rec, err := MakePutRecord(sk, u.Key(str), []byte("blah")) if err != nil { t.Fatal(err) } diff --git a/routing/dht/records.go b/routing/dht/records.go index 083eeb26e..5dbcccaaa 100644 --- a/routing/dht/records.go +++ b/routing/dht/records.go @@ -43,20 +43,20 @@ func RecordBlobForSig(r *pb.Record) []byte { } // creates and signs a dht record for the given key/value pair -func (dht *IpfsDHT) makePutRecord(key u.Key, value []byte) (*pb.Record, error) { +func MakePutRecord(sk ci.PrivKey, key u.Key, value []byte) (*pb.Record, error) { record := new(pb.Record) record.Key = proto.String(string(key)) record.Value = value - record.Author = proto.String(string(dht.self)) - blob := RecordBlobForSig(record) - sk := dht.peerstore.PrivKey(dht.self) - if sk == nil { - log.Errorf("%s dht cannot get own private key!", dht.self) - return nil, fmt.Errorf("cannot get private key to sign record!") + pkh, err := sk.GetPublic().Hash() + if err != nil { + return nil, err } + record.Author = proto.String(string(pkh)) + blob := RecordBlobForSig(record) + sig, err := sk.Sign(blob) if err != nil { return nil, err diff --git a/routing/dht/routing.go b/routing/dht/routing.go index 3c72da494..aea4406f1 100644 --- a/routing/dht/routing.go +++ b/routing/dht/routing.go @@ -36,7 +36,12 @@ func (dht *IpfsDHT) PutValue(ctx context.Context, key u.Key, value []byte) error return err } - rec, err := dht.makePutRecord(key, value) + sk, err := dht.getOwnPrivateKey() + if err != nil { + return err + } + + rec, err := MakePutRecord(sk, key, value) if err != nil { log.Error("Creation of record failed!") return err @@ -75,6 +80,8 @@ func (dht *IpfsDHT) GetValue(ctx context.Context, key u.Key) ([]byte, error) { if err == nil { log.Debug("have it locally") return val, nil + } else { + log.Debug("failed to get value locally: %s", err) } // get closest peers in the routing table diff --git a/routing/offline/offline.go b/routing/offline/offline.go new file mode 100644 index 000000000..7109c6abe --- /dev/null +++ b/routing/offline/offline.go @@ -0,0 +1,89 @@ +package offline + +import ( + "errors" + "time" + + context "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/go.net/context" + "github.com/jbenet/go-ipfs/Godeps/_workspace/src/code.google.com/p/goprotobuf/proto" + ds "github.com/jbenet/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-datastore" + ci "github.com/jbenet/go-ipfs/p2p/crypto" + "github.com/jbenet/go-ipfs/p2p/peer" + routing "github.com/jbenet/go-ipfs/routing" + dht "github.com/jbenet/go-ipfs/routing/dht" + pb "github.com/jbenet/go-ipfs/routing/dht/pb" + eventlog "github.com/jbenet/go-ipfs/thirdparty/eventlog" + u "github.com/jbenet/go-ipfs/util" +) + +var log = eventlog.Logger("offlinerouting") + +var ErrOffline = errors.New("routing system in offline mode") + +func NewOfflineRouter(dstore ds.Datastore, privkey ci.PrivKey) routing.IpfsRouting { + return &offlineRouting{ + datastore: dstore, + sk: privkey, + } +} + +type offlineRouting struct { + datastore ds.Datastore + sk ci.PrivKey +} + +func (c *offlineRouting) PutValue(ctx context.Context, key u.Key, val []byte) error { + rec, err := dht.MakePutRecord(c.sk, key, val) + if err != nil { + return err + } + data, err := proto.Marshal(rec) + if err != nil { + return err + } + + return c.datastore.Put(key.DsKey(), data) +} + +func (c *offlineRouting) GetValue(ctx context.Context, key u.Key) ([]byte, error) { + v, err := c.datastore.Get(key.DsKey()) + if err != nil { + return nil, err + } + + byt, ok := v.([]byte) + if !ok { + return nil, errors.New("value stored in datastore not []byte") + } + rec := new(pb.Record) + err = proto.Unmarshal(byt, rec) + if err != nil { + return nil, err + } + + return rec.GetValue(), nil +} + +func (c *offlineRouting) FindProviders(ctx context.Context, key u.Key) ([]peer.PeerInfo, error) { + return nil, ErrOffline +} + +func (c *offlineRouting) FindPeer(ctx context.Context, pid peer.ID) (peer.PeerInfo, error) { + return peer.PeerInfo{}, ErrOffline +} + +func (c *offlineRouting) FindProvidersAsync(ctx context.Context, k u.Key, max int) <-chan peer.PeerInfo { + out := make(chan peer.PeerInfo) + close(out) + return out +} + +func (c *offlineRouting) Provide(_ context.Context, key u.Key) error { + return ErrOffline +} + +func (c *offlineRouting) Ping(ctx context.Context, p peer.ID) (time.Duration, error) { + return 0, ErrOffline +} + +var _ routing.IpfsRouting = &offlineRouting{}