forked from libp2p/go-libp2p-kad-dht
-
Notifications
You must be signed in to change notification settings - Fork 0
/
records.go
146 lines (125 loc) · 3.91 KB
/
records.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package dht
import (
"context"
"fmt"
"time"
ci "github.com/libp2p/go-libp2p-crypto"
peer "github.com/libp2p/go-libp2p-peer"
routing "github.com/libp2p/go-libp2p-routing"
)
// MaxRecordAge specifies the maximum time that any node will hold onto a record
// from the time its received. This does not apply to any other forms of validity that
// the record may contain.
// For example, a record may contain an ipns entry with an EOL saying its valid
// until the year 2020 (a great time in the future). For that record to stick around
// it must be rebroadcasted more frequently than once every 'MaxRecordAge'
const MaxRecordAge = time.Hour * 36
type pubkrs struct {
pubk ci.PubKey
err error
}
func (dht *IpfsDHT) GetPublicKey(ctx context.Context, p peer.ID) (ci.PubKey, error) {
log.Debugf("getPublicKey for: %s", p)
// try extracting from identity.
pk := p.ExtractPublicKey()
if pk != nil {
return pk, nil
}
// check locally.
pk = dht.peerstore.PubKey(p)
if pk != nil {
return pk, nil
}
// Try getting the public key both directly from the node it identifies
// and from the DHT, in parallel
ctx, cancel := context.WithCancel(ctx)
defer cancel()
resp := make(chan pubkrs, 2)
go func() {
pubk, err := dht.getPublicKeyFromNode(ctx, p)
resp <- pubkrs{pubk, err}
}()
// Note that the number of open connections is capped by the dial
// limiter, so there is a chance that getPublicKeyFromDHT(), which
// potentially opens a lot of connections, will block
// getPublicKeyFromNode() from getting a connection.
// Currently this doesn't seem to cause an issue so leaving as is
// for now.
go func() {
pubk, err := dht.getPublicKeyFromDHT(ctx, p)
resp <- pubkrs{pubk, err}
}()
// Wait for one of the two go routines to return
// a public key (or for both to error out)
var err error
for i := 0; i < 2; i++ {
r := <-resp
if r.err == nil {
// Found the public key
err := dht.peerstore.AddPubKey(p, r.pubk)
if err != nil {
log.Warningf("Failed to add public key to peerstore for %v", p)
}
return r.pubk, nil
}
err = r.err
}
// Both go routines failed to find a public key
return nil, err
}
func (dht *IpfsDHT) getPublicKeyFromDHT(ctx context.Context, p peer.ID) (ci.PubKey, error) {
// Only retrieve one value, because the public key is immutable
// so there's no need to retrieve multiple versions
pkkey := routing.KeyForPublicKey(p)
vals, err := dht.GetValues(ctx, pkkey, 1)
if err != nil {
return nil, err
}
if len(vals) == 0 || vals[0].Val == nil {
log.Debugf("Could not find public key for %v in DHT", p)
return nil, routing.ErrNotFound
}
pubk, err := ci.UnmarshalPublicKey(vals[0].Val)
if err != nil {
log.Errorf("Could not unmarshall public key retrieved from DHT for %v", p)
return nil, err
}
// Note: No need to check that public key hash matches peer ID
// because this is done by GetValues()
log.Debugf("Got public key for %s from DHT", p)
return pubk, nil
}
func (dht *IpfsDHT) getPublicKeyFromNode(ctx context.Context, p peer.ID) (ci.PubKey, error) {
// check locally, just in case...
pk := dht.peerstore.PubKey(p)
if pk != nil {
return pk, nil
}
// Get the key from the node itself
pkkey := routing.KeyForPublicKey(p)
pmes, err := dht.getValueSingle(ctx, p, pkkey)
if err != nil {
return nil, err
}
// node doesn't have key :(
record := pmes.GetRecord()
if record == nil {
return nil, fmt.Errorf("node %v not responding with its public key", p)
}
pubk, err := ci.UnmarshalPublicKey(record.GetValue())
if err != nil {
log.Errorf("Could not unmarshall public key for %v", p)
return nil, err
}
// Make sure the public key matches the peer ID
id, err := peer.IDFromPublicKey(pubk)
if err != nil {
log.Errorf("Could not extract peer id from public key for %v", p)
return nil, err
}
if id != p {
return nil, fmt.Errorf("public key %v does not match peer %v", id, p)
}
log.Debugf("Got public key from node %v itself", p)
return pubk, nil
}