You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.0 KiB

  1. package kademlia
  2. import (
  3. "math/bits"
  4. "strconv"
  5. )
  6. const (
  7. alpha = 3 // 'alpha', max parallalel calls
  8. B = 20 // 'B', 160 bits, ID length
  9. KBucketSize = 20 // 'K', bucket size
  10. )
  11. type ListedNode struct {
  12. ID ID
  13. Addr string
  14. }
  15. type Kademlia struct {
  16. ID ID
  17. KBuckets [B * 8][]ListedNode
  18. }
  19. func NewKademliaTable(id ID) *Kademlia {
  20. return &Kademlia{
  21. ID: id,
  22. }
  23. }
  24. func (kad Kademlia) String() string {
  25. r := "Node ID: " + kad.ID.String() + ", KBuckets:\n"
  26. for i, kb := range kad.KBuckets {
  27. if len(kb) > 0 {
  28. r += " KBucket " + strconv.Itoa(i) + "\n"
  29. for _, e := range kb {
  30. r += " " + e.ID.String() + "\n"
  31. }
  32. }
  33. }
  34. return r
  35. }
  36. func (kad Kademlia) KBucket(o ID) int {
  37. d := kad.ID.Distance(o)
  38. return kBucketByDistance(d[:])
  39. }
  40. func kBucketByDistance(b []byte) int {
  41. for i := 0; i < B; i++ {
  42. for a := b[i] ^ 0; a != 0; a &= a - 1 {
  43. return (B-1-i)*8 + (7 - bits.TrailingZeros8(bits.Reverse8(uint8(a))))
  44. }
  45. }
  46. return (B*8 - 1) - (B*8 - 1)
  47. }
  48. func (kad *Kademlia) Update(o ListedNode) {
  49. k := kad.KBucket(o.ID)
  50. kb := kad.KBuckets[k]
  51. if len(kb) >= KBucketSize {
  52. // if n.KBuckets[k] is alrady full, perform ping of the first element
  53. kad.Ping(k, o)
  54. return
  55. }
  56. // check that is not already in the list
  57. exist, pos := existsInListedNodes(kad.KBuckets[k], o)
  58. if exist {
  59. // update position of o to the bottom
  60. kad.KBuckets[k] = moveToBottom(kad.KBuckets[k], pos)
  61. return
  62. }
  63. // not exists, add it to the kBucket
  64. kad.KBuckets[k] = append(kad.KBuckets[k], o)
  65. return
  66. }
  67. func (kad *Kademlia) Ping(k int, o ListedNode) {
  68. // TODO when rpc layer is done
  69. // ping the n.KBuckets[k][0] (using goroutine)
  70. // if no response (timeout), delete it and add 'o'
  71. // n.KBuckets[k][0] = o
  72. }
  73. func existsInListedNodes(lns []ListedNode, ln ListedNode) (bool, int) {
  74. for i, v := range lns {
  75. if v.ID.Equal(ln.ID) {
  76. return true, i
  77. }
  78. }
  79. return false, 0
  80. }
  81. func moveToBottom(kb []ListedNode, k int) []ListedNode {
  82. e := kb[k]
  83. kb = append(kb[:k], kb[k+1:]...)
  84. kb = append(kb[:], e)
  85. return kb
  86. }