-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
routing: Add triert package with Xor Trie backed routing table #50
Conversation
// RemoveKey tries to remove a peer identified by its Kademlia key from the | ||
// routing table | ||
func (rt *TrieRT) RemoveKey(ctx context.Context, kk key.KadKey) (bool, error) { | ||
if kk.Size() != rt.self.Size() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How likely is it that users do really operate with different KadKeys? How could this happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Users should not operate with different KadKey lengths. IMO it is good to check it to avoid bad surprises later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a pity that Go doesn't allow generic types to be specified using specific slice lengths
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also hoped we could constrain the usage to one specific key type.
return closestAtDepth(ctx, k, t.Branch[1-chosenDir], depth+1, n, found) | ||
} | ||
|
||
func (rt *TrieRT) Find(ctx context.Context, kk key.KadKey) (address.NodeID, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What will this function be used for? I can only find usages in tests (I checked this repo + the go-libp2p-kad-dht/kbucket repos)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It could be used to verify if a peer is already in the routing table or not, e.g in the context of libp2p/go-libp2p-kad-dht#811 where we send a kademlia request to the remote peer before adding it to the routing table.
In go-libp2p-kbucket this logic is implemented in https://github.com/libp2p/go-libp2p-kbucket/blob/6d85d4e63aa3b8e04b9b55e1de64be8a52532f21/table.go#L119. So there is no use case now (except testing), but it may be useful in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's used in tests and potentially in other diagnostics / consistency checking. It's not part of the Table interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's possible we could un-export it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see the need to unexport it. It's a useful function for code that want to directly query the table
Imported the xor trie into |
The imported trie with extra data field meant I could drop the map between key and node in the triert |
Error checking is in preparation for #51 (comment) if we decide to take that route |
Co-authored-by: Guillaume Michel - guissou <[email protected]>
PTAL Recent changes:
Initial benchmarks:
|
Windows/macos tests are still flaky. I think this is quic related. |
require.Equal(t, 1, kk.BitAt(6)) | ||
require.Equal(t, 1, kk.BitAt(7)) | ||
require.Equal(t, 1, kk.BitAt(8)) | ||
require.Equal(t, 0, kk.BitAt(15)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure if it makes sense to also assert the behavior for invalid input like i < 0
and i >= len(bits(kk))
. Just something that crossed my mind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will do
key/keyutil/keyutil.go
Outdated
@@ -0,0 +1,51 @@ | |||
package keyutil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: could move to the key
package into a rand.go
file.
If it's just used for testing we could also move it to the testutil
package.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I will move to testutil. I don't think we want to encourage creating random keys with math/rand for anything other than tests
key/keyutil/keyutil.go
Outdated
} | ||
|
||
// RandomWithPrefix returns a KadKey of length l having a prefix equal to the bit pattern held in s. | ||
func RandomWithPrefix(s string, l int) key.KadKey { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- the comment should mention the maximum prefix of 64 bits.
- since there are input checks there could also be a check that
len(s) <= l*8
is true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
key/keyutil/keyutil.go
Outdated
|
||
var rng = rand.New(rand.NewSource(299792458)) | ||
|
||
// Random returns a KadKey of length l populated with random data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here, length
refers to the number of bytes instead of the number of bits. I haven't checked there rest but the usage of length
in the context of a KadKey should be consistent throughout the code.
Alternatively we could use:
size
-> byteslength
-> bits
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good catch
"github.com/plprobelab/go-kademlia/key" | ||
) | ||
|
||
var ErrMismatchedKeyLength = errors.New("key length does not match existing keys") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rm in favor of the key
package error
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it belongs here. The key package error is for invalid keys. Here all the keys are valid keys, but one does not match the format of the others
return &Trie[T]{} | ||
} | ||
|
||
func (tr *Trie[T]) Key() key.KadKey { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about the implications but Trie
conforms to the NodeID
interface. Perhaps rather export the Key
and Data
fields?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I unexprted Key and Data when adding the mutable Add/Remove methods. My thinking is that we want to limit the chances for users to corrupt the trie by overwriting fields like key
. In practice the Key method will be inlined so there's no real performance overhead.
Not sure I understand the point about conforming to NodeID interface - what would be the use case?
return n | ||
} | ||
|
||
func countCpl(t *nodeTrie, kk key.KadKey, cpl int, depth int) (int, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could move to trie.Trie
func closestAtDepth(kk key.KadKey, t *nodeTrie, depth int, n int) []entry { | ||
if t.IsLeaf() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could move to trie.Trie
and return the trie instead of an entry
Fixes #44
Trie-backed routing table, safe for concurrent use. Refresh capabilities will come with #45
Notes for follow up:
it might be better to copy the xor trie into the go-kademlia package to allow extension, specifically storing both the key and the node id in the trie for efficiency. Also we can then use our own Key type rather than relying on the coincidence that both are[]byte