Introduce Kademlia tree concept

This commit is contained in:
Roman Mandeleil 2015-02-27 09:24:41 +02:00
parent 841c4adb62
commit eb202cd2a4
3 changed files with 215 additions and 0 deletions

View File

@ -0,0 +1,130 @@
package org.ethereum.net.dht;
import java.util.ArrayList;
import java.util.List;
public class Bucket {
public static int MAX_KADEMLIA_K = 5;
// if bit = 1 go left
Bucket left;
// if bit = 0 go right
Bucket right;
String name;
List<PeerId> peerIds = new ArrayList<>();
public Bucket(String name) {
this.name = name;
}
public void add(PeerId peerId) {
if (peerId == null) throw new Error("Not a leaf");
if ( peerIds == null){
if (peerId.nextBit(name) == 1)
left.add(peerId);
else
right.add(peerId);
return;
}
peerIds.add(peerId);
if (peerIds.size() > MAX_KADEMLIA_K)
splitBucket();
}
public void splitBucket() {
left = new Bucket(name + "1");
right = new Bucket(name + "0");
for (PeerId id : peerIds) {
if (id.nextBit(name) == 1)
left.add(id);
else
right.add(id);
}
this.peerIds = null;
}
public Bucket left() {
return left;
}
public Bucket right() {
return right;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(name).append("\n");
if (peerIds == null) return sb.toString();
for (PeerId id : peerIds)
sb.append(id.toBinaryString()).append("\n");
return sb.toString();
}
public void traverseTree(DoOnTree doOnTree) {
if (left != null) left.traverseTree(doOnTree);
if (right != null) right.traverseTree(doOnTree);
doOnTree.call(this);
}
/********************/
// tree operations //
/********************/
public interface DoOnTree {
public void call(Bucket bucket);
}
public static class SaveLeaf implements DoOnTree {
List<Bucket> leafs = new ArrayList<>();
@Override
public void call(Bucket bucket) {
if (bucket.peerIds != null) leafs.add(bucket);
}
public List<Bucket> getLeafs() {
return leafs;
}
public void setLeafs(List<Bucket> leafs) {
this.leafs = leafs;
}
}
public String getName(){
return name;
}
public List<PeerId> getPeerIds() {
return peerIds;
}
}

View File

@ -0,0 +1,23 @@
package org.ethereum.net.dht;
import java.util.List;
import static org.ethereum.net.dht.Bucket.*;
public class DHTUtils {
public static void printAllLeafs(Bucket root){
SaveLeaf saveLeaf = new SaveLeaf();
root.traverseTree(saveLeaf);
for (Bucket bucket : saveLeaf.getLeafs())
System.out.println(bucket);
}
public static List<Bucket> getAllLeafs(Bucket root){
SaveLeaf saveLeaf = new SaveLeaf();
root.traverseTree(saveLeaf);
return saveLeaf.getLeafs();
}
}

View File

@ -0,0 +1,62 @@
package org.ethereum.net.dht;
import org.ethereum.crypto.HashUtil;
import org.spongycastle.util.BigIntegers;
import org.spongycastle.util.encoders.Hex;
import java.math.BigInteger;
public class PeerId {
byte[] data;
public PeerId(byte[] data) {
this.data = data;
}
public PeerId() {
HashUtil.randomPeerId();
}
public byte nextBit(String startPatern) {
if (this.toBinaryString().startsWith(startPatern + "1"))
return 1;
else
return 0;
}
public byte[] calcDistance(PeerId toPeerId) {
BigInteger aPeer = new BigInteger(data);
BigInteger bPeer = new BigInteger(toPeerId.data);
BigInteger distance = aPeer.xor(bPeer);
return BigIntegers.asUnsignedByteArray(distance);
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
@Override
public String toString() {
return "PeerId{" +
"data=" + Hex.toHexString(data) +
'}';
}
public String toBinaryString() {
BigInteger bi = new BigInteger(1, data);
String out = String.format("%512s", bi.toString(2));
out = out.replace(' ', '0');
return out;
}
}