-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from geoah/master
Split `go-ipfs/routing/kbucket` into `go-libp2p-kbucket`
- Loading branch information
Showing
14 changed files
with
1,036 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1.0.0: QmbS7NcH4KqZL71ZwzVZAt1CpVpAtUBaHXuDenjnXF78Wa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
os: | ||
- linux | ||
- osx | ||
|
||
language: go | ||
|
||
go: | ||
- 1.7 | ||
|
||
env: | ||
- GO15VENDOREXPERIMENT=1 | ||
|
||
install: true | ||
|
||
script: | ||
- make deps | ||
- go test ./... | ||
|
||
cache: | ||
directories: | ||
- $GOPATH/src/gx | ||
|
||
notifications: | ||
email: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export IPFS_API ?= v04x.ipfs.io | ||
|
||
gx: | ||
go get -u github.com/whyrusleeping/gx | ||
go get -u github.com/whyrusleeping/gx-go | ||
|
||
deps: gx | ||
gx --verbose install --global | ||
gx-go rewrite |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,26 @@ | ||
# go-libp2p-kbucket | ||
A kbucket implementation for use as a routing table | ||
|
||
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) | ||
[![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) | ||
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) | ||
[![standard-readme compliant](https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme) | ||
|
||
> A kbucket implementation for use as a routing table | ||
## Documenation | ||
|
||
See https://godoc.org/github.com/libp2p/go-libp2p-kbucket. | ||
|
||
## Contribute | ||
|
||
Feel free to join in. All welcome. Open an [issue](https://github.com/ipfs/go-key/issues)! | ||
|
||
This repository falls under the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md). | ||
|
||
### Want to hack on IPFS? | ||
|
||
[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/contributing.md) | ||
|
||
## License | ||
|
||
MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package kbucket | ||
|
||
import ( | ||
"container/list" | ||
"sync" | ||
|
||
peer "github.com/ipfs/go-libp2p-peer" | ||
) | ||
|
||
// Bucket holds a list of peers. | ||
type Bucket struct { | ||
lk sync.RWMutex | ||
list *list.List | ||
} | ||
|
||
func newBucket() *Bucket { | ||
b := new(Bucket) | ||
b.list = list.New() | ||
return b | ||
} | ||
|
||
func (b *Bucket) Peers() []peer.ID { | ||
b.lk.RLock() | ||
defer b.lk.RUnlock() | ||
ps := make([]peer.ID, 0, b.list.Len()) | ||
for e := b.list.Front(); e != nil; e = e.Next() { | ||
id := e.Value.(peer.ID) | ||
ps = append(ps, id) | ||
} | ||
return ps | ||
} | ||
|
||
func (b *Bucket) Has(id peer.ID) bool { | ||
b.lk.RLock() | ||
defer b.lk.RUnlock() | ||
for e := b.list.Front(); e != nil; e = e.Next() { | ||
if e.Value.(peer.ID) == id { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
func (b *Bucket) Remove(id peer.ID) { | ||
b.lk.Lock() | ||
defer b.lk.Unlock() | ||
for e := b.list.Front(); e != nil; e = e.Next() { | ||
if e.Value.(peer.ID) == id { | ||
b.list.Remove(e) | ||
} | ||
} | ||
} | ||
|
||
func (b *Bucket) MoveToFront(id peer.ID) { | ||
b.lk.Lock() | ||
defer b.lk.Unlock() | ||
for e := b.list.Front(); e != nil; e = e.Next() { | ||
if e.Value.(peer.ID) == id { | ||
b.list.MoveToFront(e) | ||
} | ||
} | ||
} | ||
|
||
func (b *Bucket) PushFront(p peer.ID) { | ||
b.lk.Lock() | ||
b.list.PushFront(p) | ||
b.lk.Unlock() | ||
} | ||
|
||
func (b *Bucket) PopBack() peer.ID { | ||
b.lk.Lock() | ||
defer b.lk.Unlock() | ||
last := b.list.Back() | ||
b.list.Remove(last) | ||
return last.Value.(peer.ID) | ||
} | ||
|
||
func (b *Bucket) Len() int { | ||
b.lk.RLock() | ||
defer b.lk.RUnlock() | ||
return b.list.Len() | ||
} | ||
|
||
// Split splits a buckets peers into two buckets, the methods receiver will have | ||
// peers with CPL equal to cpl, the returned bucket will have peers with CPL | ||
// greater than cpl (returned bucket has closer peers) | ||
func (b *Bucket) Split(cpl int, target ID) *Bucket { | ||
b.lk.Lock() | ||
defer b.lk.Unlock() | ||
|
||
out := list.New() | ||
newbuck := newBucket() | ||
newbuck.list = out | ||
e := b.list.Front() | ||
for e != nil { | ||
peerID := ConvertPeerID(e.Value.(peer.ID)) | ||
peerCPL := commonPrefixLen(peerID, target) | ||
if peerCPL > cpl { | ||
cur := e | ||
out.PushBack(e.Value) | ||
e = e.Next() | ||
b.list.Remove(cur) | ||
continue | ||
} | ||
e = e.Next() | ||
} | ||
return newbuck | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package keyspace | ||
|
||
import ( | ||
"sort" | ||
|
||
"math/big" | ||
) | ||
|
||
// Key represents an identifier in a KeySpace. It holds a reference to the | ||
// associated KeySpace, as well references to both the Original identifier, | ||
// as well as the new, KeySpace Bytes one. | ||
type Key struct { | ||
|
||
// Space is the KeySpace this Key is related to. | ||
Space KeySpace | ||
|
||
// Original is the original value of the identifier | ||
Original []byte | ||
|
||
// Bytes is the new value of the identifier, in the KeySpace. | ||
Bytes []byte | ||
} | ||
|
||
// Equal returns whether this key is equal to another. | ||
func (k1 Key) Equal(k2 Key) bool { | ||
if k1.Space != k2.Space { | ||
panic("k1 and k2 not in same key space.") | ||
} | ||
return k1.Space.Equal(k1, k2) | ||
} | ||
|
||
// Less returns whether this key comes before another. | ||
func (k1 Key) Less(k2 Key) bool { | ||
if k1.Space != k2.Space { | ||
panic("k1 and k2 not in same key space.") | ||
} | ||
return k1.Space.Less(k1, k2) | ||
} | ||
|
||
// Distance returns this key's distance to another | ||
func (k1 Key) Distance(k2 Key) *big.Int { | ||
if k1.Space != k2.Space { | ||
panic("k1 and k2 not in same key space.") | ||
} | ||
return k1.Space.Distance(k1, k2) | ||
} | ||
|
||
// KeySpace is an object used to do math on identifiers. Each keyspace has its | ||
// own properties and rules. See XorKeySpace. | ||
type KeySpace interface { | ||
|
||
// Key converts an identifier into a Key in this space. | ||
Key([]byte) Key | ||
|
||
// Equal returns whether keys are equal in this key space | ||
Equal(Key, Key) bool | ||
|
||
// Distance returns the distance metric in this key space | ||
Distance(Key, Key) *big.Int | ||
|
||
// Less returns whether the first key is smaller than the second. | ||
Less(Key, Key) bool | ||
} | ||
|
||
// byDistanceToCenter is a type used to sort Keys by proximity to a center. | ||
type byDistanceToCenter struct { | ||
Center Key | ||
Keys []Key | ||
} | ||
|
||
func (s byDistanceToCenter) Len() int { | ||
return len(s.Keys) | ||
} | ||
|
||
func (s byDistanceToCenter) Swap(i, j int) { | ||
s.Keys[i], s.Keys[j] = s.Keys[j], s.Keys[i] | ||
} | ||
|
||
func (s byDistanceToCenter) Less(i, j int) bool { | ||
a := s.Center.Distance(s.Keys[i]) | ||
b := s.Center.Distance(s.Keys[j]) | ||
return a.Cmp(b) == -1 | ||
} | ||
|
||
// SortByDistance takes a KeySpace, a center Key, and a list of Keys toSort. | ||
// It returns a new list, where the Keys toSort have been sorted by their | ||
// distance to the center Key. | ||
func SortByDistance(sp KeySpace, center Key, toSort []Key) []Key { | ||
toSortCopy := make([]Key, len(toSort)) | ||
copy(toSortCopy, toSort) | ||
bdtc := &byDistanceToCenter{ | ||
Center: center, | ||
Keys: toSortCopy, // copy | ||
} | ||
sort.Sort(bdtc) | ||
return bdtc.Keys | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package keyspace | ||
|
||
import ( | ||
"bytes" | ||
"crypto/sha256" | ||
"math/big" | ||
|
||
u "github.com/ipfs/go-ipfs-util" | ||
) | ||
|
||
// XORKeySpace is a KeySpace which: | ||
// - normalizes identifiers using a cryptographic hash (sha256) | ||
// - measures distance by XORing keys together | ||
var XORKeySpace = &xorKeySpace{} | ||
var _ KeySpace = XORKeySpace // ensure it conforms | ||
|
||
type xorKeySpace struct{} | ||
|
||
// Key converts an identifier into a Key in this space. | ||
func (s *xorKeySpace) Key(id []byte) Key { | ||
hash := sha256.Sum256(id) | ||
key := hash[:] | ||
return Key{ | ||
Space: s, | ||
Original: id, | ||
Bytes: key, | ||
} | ||
} | ||
|
||
// Equal returns whether keys are equal in this key space | ||
func (s *xorKeySpace) Equal(k1, k2 Key) bool { | ||
return bytes.Equal(k1.Bytes, k2.Bytes) | ||
} | ||
|
||
// Distance returns the distance metric in this key space | ||
func (s *xorKeySpace) Distance(k1, k2 Key) *big.Int { | ||
// XOR the keys | ||
k3 := u.XOR(k1.Bytes, k2.Bytes) | ||
|
||
// interpret it as an integer | ||
dist := big.NewInt(0).SetBytes(k3) | ||
return dist | ||
} | ||
|
||
// Less returns whether the first key is smaller than the second. | ||
func (s *xorKeySpace) Less(k1, k2 Key) bool { | ||
a := k1.Bytes | ||
b := k2.Bytes | ||
for i := 0; i < len(a); i++ { | ||
if a[i] != b[i] { | ||
return a[i] < b[i] | ||
} | ||
} | ||
return true | ||
} | ||
|
||
// ZeroPrefixLen returns the number of consecutive zeroes in a byte slice. | ||
func ZeroPrefixLen(id []byte) int { | ||
for i := 0; i < len(id); i++ { | ||
for j := 0; j < 8; j++ { | ||
if (id[i]>>uint8(7-j))&0x1 != 0 { | ||
return i*8 + j | ||
} | ||
} | ||
} | ||
return len(id) * 8 | ||
} |
Oops, something went wrong.