Introduce Kademlia tree concept
This commit is contained in:
parent
841c4adb62
commit
eb202cd2a4
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue