Addressing comments from CR
License: MIT Signed-off-by: Jeromy <jeromyj@gmail.com>
Jeromy committed
Sep 30, 2015 at 10:59 UTC
3b9ad300059d09f9ed4a1e25da9a377fc8b56f38
4 files changed
+157
-21
namesys/ipns_select_test.go
new
+127
@@ -0,0 +1,127 @@
1
+package namesys
2
+
3
+import (
4
+ "fmt"
5
+ "math/rand"
6
+ "testing"
7
+ "time"
8
+
9
+ proto "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/gogo/protobuf/proto"
10
+
11
+ pb "github.com/ipfs/go-ipfs/namesys/pb"
12
+ ci "github.com/ipfs/go-ipfs/p2p/crypto"
13
+ path "github.com/ipfs/go-ipfs/path"
14
+ u "github.com/ipfs/go-ipfs/util"
15
+)
16
+
17
+func shuffle(a []*pb.IpnsEntry) {
18
+ for n := 0; n < 5; n++ {
19
+ for i, _ := range a {
20
+ j := rand.Intn(len(a))
21
+ a[i], a[j] = a[j], a[i]
22
+ }
23
+ }
24
+}
25
+
26
+func AssertSelected(r *pb.IpnsEntry, from ...*pb.IpnsEntry) error {
27
+ shuffle(from)
28
+ var vals [][]byte
29
+ for _, r := range from {
30
+ data, err := proto.Marshal(r)
31
+ if err != nil {
32
+ return err
33
+ }
34
+ vals = append(vals, data)
35
+ }
36
+
37
+ i, err := selectRecord(from, vals)
38
+ if err != nil {
39
+ return err
40
+ }
41
+
42
+ if from[i] != r {
43
+ return fmt.Errorf("selected incorrect record %d", i)
44
+ }
45
+
46
+ return nil
47
+}
48
+
49
+func TestOrdering(t *testing.T) {
50
+ // select timestamp so selection is deterministic
51
+ ts := time.Unix(1000000, 0)
52
+
53
+ // generate a key for signing the records
54
+ r := u.NewSeededRand(15) // generate deterministic keypair
55
+ priv, _, err := ci.GenerateKeyPairWithReader(ci.RSA, 1024, r)
56
+ if err != nil {
57
+ t.Fatal(err)
58
+ }
59
+
60
+ e1, err := CreateRoutingEntryData(priv, path.Path("foo"), 1, ts.Add(time.Hour))
61
+ if err != nil {
62
+ t.Fatal(err)
63
+ }
64
+
65
+ e2, err := CreateRoutingEntryData(priv, path.Path("bar"), 2, ts.Add(time.Hour))
66
+ if err != nil {
67
+ t.Fatal(err)
68
+ }
69
+
70
+ e3, err := CreateRoutingEntryData(priv, path.Path("baz"), 3, ts.Add(time.Hour))
71
+ if err != nil {
72
+ t.Fatal(err)
73
+ }
74
+
75
+ e4, err := CreateRoutingEntryData(priv, path.Path("cat"), 3, ts.Add(time.Hour*2))
76
+ if err != nil {
77
+ t.Fatal(err)
78
+ }
79
+
80
+ e5, err := CreateRoutingEntryData(priv, path.Path("dog"), 4, ts.Add(time.Hour*3))
81
+ if err != nil {
82
+ t.Fatal(err)
83
+ }
84
+
85
+ e6, err := CreateRoutingEntryData(priv, path.Path("fish"), 4, ts.Add(time.Hour*3))
86
+ if err != nil {
87
+ t.Fatal(err)
88
+ }
89
+
90
+ // e1 is the only record, i hope it gets this right
91
+ err = AssertSelected(e1, e1)
92
+ if err != nil {
93
+ t.Fatal(err)
94
+ }
95
+
96
+ // e2 has the highest sequence number
97
+ err = AssertSelected(e2, e1, e2)
98
+ if err != nil {
99
+ t.Fatal(err)
100
+ }
101
+
102
+ // e3 has the highest sequence number
103
+ err = AssertSelected(e3, e1, e2, e3)
104
+ if err != nil {
105
+ t.Fatal(err)
106
+ }
107
+
108
+ // e4 has a higher timeout
109
+ err = AssertSelected(e4, e1, e2, e3, e4)
110
+ if err != nil {
111
+ t.Fatal(err)
112
+ }
113
+
114
+ // e5 has the highest sequence number
115
+ err = AssertSelected(e5, e1, e2, e3, e4, e5)
116
+ if err != nil {
117
+ t.Fatal(err)
118
+ }
119
+
120
+ // e6 should be selected as its signauture will win in the comparison
121
+ err = AssertSelected(e6, e1, e2, e3, e4, e5, e6)
122
+ if err != nil {
123
+ t.Fatal(err)
124
+ }
125
+
126
+ _ = []interface{}{e1, e2, e3, e4, e5, e6}
127
+}
namesys/publisher.go
+18
-5
@@ -60,7 +60,7 @@ func (p *ipnsPublisher) PublishWithEOL(ctx context.Context, k ci.PrivKey, value
60
return err
61
}
62
63
- namekey, ipnskey := IpnsKeysForID(id)
63
+ _, ipnskey := IpnsKeysForID(id)
64
65
// get previous records sequence number, and add one to it
66
var seqnum uint64
@@ -77,17 +77,22 @@ func (p *ipnsPublisher) PublishWithEOL(ctx context.Context, k ci.PrivKey, value
77
return err
78
}
79
80
+ return PutRecordToRouting(ctx, k, value, seqnum, eol, p.routing, id)
81
+}
82
+
83
+func PutRecordToRouting(ctx context.Context, k ci.PrivKey, value path.Path, seqnum uint64, eol time.Time, r routing.IpfsRouting, id peer.ID) error {
84
+ namekey, ipnskey := IpnsKeysForID(id)
85
entry, err := CreateRoutingEntryData(k, value, seqnum, eol)
86
if err != nil {
87
return err
88
}
89
85
- err = PublishEntry(ctx, p.routing, ipnskey, entry)
90
+ err = PublishEntry(ctx, r, ipnskey, entry)
91
if err != nil {
92
return err
93
}
94
90
- err = PublishPublicKey(ctx, p.routing, namekey, k.GetPublic())
95
+ err = PublishPublicKey(ctx, r, namekey, k.GetPublic())
96
if err != nil {
97
return err
98
}
@@ -174,13 +179,18 @@ func IpnsSelectorFunc(k key.Key, vals [][]byte) (int, error) {
179
}
180
}
181
182
+ return selectRecord(recs, vals)
183
+}
184
+
185
+func selectRecord(recs []*pb.IpnsEntry, vals [][]byte) (int, error) {
186
var best_seq uint64
187
best_i := -1
188
189
for i, r := range recs {
181
- if r == nil {
190
+ if r == nil || r.GetSequence() < best_seq {
191
continue
192
}
193
+
194
if best_i == -1 || r.GetSequence() > best_seq {
195
best_seq = r.GetSequence()
196
best_i = i
@@ -196,8 +206,11 @@ func IpnsSelectorFunc(k key.Key, vals [][]byte) (int, error) {
206
}
207
208
if rt.After(bestt) {
199
- best_seq = r.GetSequence()
209
best_i = i
210
+ } else if rt == bestt {
211
+ if bytes.Compare(vals[i], vals[best_i]) > 0 {
212
+ best_i = i
213
+ }
214
}
215
}
216
}
namesys/republisher/repub.go
+3
-15
@@ -69,7 +69,7 @@ func (rp *Republisher) Run(proc goprocess.Process) {
69
case <-tick.C:
70
err := rp.republishEntries(proc)
71
if err != nil {
72
- log.Error(err)
72
+ log.Error("Republisher failed to republish: ", err)
73
}
74
case <-proc.Closing():
75
return
@@ -86,7 +86,7 @@ func (rp *Republisher) republishEntries(p goprocess.Process) error {
86
priv := rp.ps.PrivKey(id)
87
88
// Look for it locally only
89
- namekey, ipnskey := namesys.IpnsKeysForID(id)
89
+ _, ipnskey := namesys.IpnsKeysForID(id)
90
p, seq, err := rp.getLastVal(ipnskey)
91
if err != nil {
92
if err == errNoEntry {
@@ -97,19 +97,7 @@ func (rp *Republisher) republishEntries(p goprocess.Process) error {
97
98
// update record with same sequence number
99
eol := time.Now().Add(rp.RecordLifetime)
100
- entry, err := namesys.CreateRoutingEntryData(priv, p, seq, eol)
101
- if err != nil {
102
- return err
103
- }
104
-
105
- // republish public key
106
- err = namesys.PublishPublicKey(ctx, rp.r, namekey, priv.GetPublic())
107
- if err != nil {
108
- return err
109
- }
110
-
111
- // republish ipns entry
112
- err = namesys.PublishEntry(ctx, rp.r, ipnskey, entry)
100
+ err = namesys.PutRecordToRouting(ctx, priv, p, seq, eol, rp.r, id)
101
if err != nil {
102
return err
103
}
routing/dht/routing.go
+9
-1
@@ -3,6 +3,7 @@ package dht
3
import (
4
"bytes"
5
"sync"
6
+ "time"
7
8
context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
9
key "github.com/ipfs/go-ipfs/blocks/key"
@@ -60,6 +61,8 @@ func (dht *IpfsDHT) PutValue(ctx context.Context, key key.Key, value []byte) err
61
for p := range pchan {
62
wg.Add(1)
63
go func(p peer.ID) {
64
+ ctx, cancel := context.WithCancel(ctx)
65
+ defer cancel()
66
defer wg.Done()
67
notif.PublishQueryEvent(ctx, ¬if.QueryEvent{
68
Type: notif.Value,
@@ -78,7 +81,10 @@ func (dht *IpfsDHT) PutValue(ctx context.Context, key key.Key, value []byte) err
81
82
// GetValue searches for the value corresponding to given Key.
83
func (dht *IpfsDHT) GetValue(ctx context.Context, key key.Key) ([]byte, error) {
81
- vals, err := dht.GetValues(ctx, key, 3)
84
+ ctx, cancel := context.WithTimeout(ctx, time.Minute)
85
+ defer cancel()
86
+
87
+ vals, err := dht.GetValues(ctx, key, 16)
88
if err != nil {
89
return nil, err
90
}
@@ -111,6 +117,8 @@ func (dht *IpfsDHT) GetValue(ctx context.Context, key key.Key) ([]byte, error) {
117
// if someone sent us a different 'less-valid' record, lets correct them
118
if !bytes.Equal(v.Val, best) {
119
go func(v routing.RecvdVal) {
120
+ ctx, cancel := context.WithTimeout(dht.Context(), time.Second*30)
121
+ defer cancel()
122
err := dht.putValueToPeer(ctx, v.From, key, fixupRec)
123
if err != nil {
124
log.Error("Error correcting DHT entry: ", err)