Extract capabilities to separate class

This commit is contained in:
nicksavers 2014-10-18 22:03:31 +02:00
parent 4f10a0bec2
commit b41e47b7c6
7 changed files with 131 additions and 66 deletions

View File

@ -0,0 +1,41 @@
package org.ethereum.net.client;
/**
* The protocols and versions of those protocols that this peer support
*/
public class Capability {
public final static String ETH = "eth";
public final static String SHH = "shh";
private String name;
private byte version;
public Capability(String name, byte version) {
this.name = name;
this.version = version;
}
public String getName() {
return name;
}
public byte getVersion() {
return version;
}
public boolean equals(Object o) {
if(o instanceof Capability) {
Capability cap = (Capability) o;
if (cap.getName() == null)
return this.name == null;
else
return cap.getName().equals(this.name) && cap.getVersion() == this.version;
}
return false;
}
public String toString() {
return name + ":" + version;
}
}

View File

@ -5,12 +5,15 @@ import java.util.List;
import org.ethereum.config.SystemProperties;
import org.ethereum.crypto.HashUtil;
import org.ethereum.net.client.Capability;
import org.ethereum.net.eth.EthHandler;
import org.ethereum.net.eth.GetTransactionsMessage;
import org.ethereum.net.p2p.GetPeersMessage;
import org.ethereum.net.p2p.HelloMessage;
import org.ethereum.net.p2p.P2pHandler;
import org.ethereum.net.p2p.PingMessage;
import org.ethereum.net.p2p.PongMessage;
import org.ethereum.net.shh.ShhHandler;
import org.spongycastle.util.encoders.Hex;
/**
@ -35,7 +38,9 @@ public class StaticMessages {
private static HelloMessage generateHelloMessage() {
String helloAnnouncement = buildHelloAnnouncement();
byte p2pVersion = P2pHandler.VERSION;
List<String> capabilities = Arrays.asList("eth", "shh");
List<Capability> capabilities = Arrays.asList(
new Capability(Capability.ETH, EthHandler.VERSION),
new Capability(Capability.SHH, ShhHandler.VERSION));
int listenPort = 30303;
return new HelloMessage(p2pVersion, helloAnnouncement,

View File

@ -3,9 +3,8 @@ package org.ethereum.net.p2p;
import static org.ethereum.net.p2p.P2pMessageCodes.HELLO;
import static org.ethereum.util.ByteUtil.EMPTY_BYTE_ARRAY;
import org.ethereum.net.eth.EthHandler;
import org.ethereum.net.client.Capability;
import org.ethereum.net.p2p.P2pMessage;
import org.ethereum.net.shh.ShhHandler;
import org.ethereum.util.*;
import org.spongycastle.util.encoders.Hex;
@ -27,7 +26,7 @@ public class HelloMessage extends P2pMessage {
private String clientId;
/** A peer-network capability code, readable ASCII and 3 letters.
* Currently only "eth", "shh" and "bzz" are known. */
private List<String> capabilities;
private List<Capability> capabilities;
/** The port on which the peer is listening for an incoming connection */
private int listenPort;
/** The identity and public key of the peer */
@ -38,7 +37,7 @@ public class HelloMessage extends P2pMessage {
}
public HelloMessage(byte p2pVersion, String clientId,
List<String> capabilities, int listenPort, String peerId) {
List<Capability> capabilities, int listenPort, String peerId) {
this.p2pVersion = p2pVersion;
this.clientId = clientId;
this.capabilities = capabilities;
@ -63,8 +62,14 @@ public class HelloMessage extends P2pMessage {
this.capabilities = new ArrayList<>();
for (int i = 0; i < capabilityList.size(); i++) {
RLPElement capabilitiesID = ((RLPList)capabilityList.get(i)).get(0);
this.capabilities.add(new String(capabilitiesID.getRLPData()));
RLPElement capId = ((RLPList)capabilityList.get(i)).get(0);
RLPElement capVersion = ((RLPList)capabilityList.get(i)).get(1);
String name = new String(capId.getRLPData());
byte version = capVersion.getRLPData() == null ? 0 : capVersion.getRLPData()[0];
Capability cap = new Capability(name, version);
this.capabilities.add(cap);
}
byte[] peerPortBytes = ((RLPItem) paramsList.get(4)).getRLPData();
@ -81,16 +86,10 @@ public class HelloMessage extends P2pMessage {
byte[] clientId = RLP.encodeString(this.clientId);
byte[][] capabilities = new byte[this.capabilities.size()][];
for (int i = 0; i < this.capabilities.size(); i++) {
String capability = this.capabilities.get(i);
byte version = 0;
if (capability.equals("eth")) version = EthHandler.VERSION;
if (capability.equals("shh")) version = ShhHandler.VERSION;
Capability capability = this.capabilities.get(i);
capabilities[i] = RLP.encodeList(
RLP.encodeElement( capability.getBytes() ),
RLP.encodeElement( new byte[]{version} ));
RLP.encodeElement(capability.getName().getBytes()),
RLP.encodeElement(new byte[] {capability.getVersion() }));
}
byte[] capabilityList = RLP.encodeList(capabilities);
byte[] peerPort = RLP.encodeInt(this.listenPort);
@ -116,7 +115,7 @@ public class HelloMessage extends P2pMessage {
return clientId;
}
public List<String> getCapabilities() {
public List<Capability> getCapabilities() {
if (!parsed) parse();
return capabilities;
}

View File

@ -6,6 +6,7 @@ import static org.ethereum.net.message.StaticMessages.HELLO_MESSAGE;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Timer;
@ -17,6 +18,7 @@ import io.netty.channel.SimpleChannelInboundHandler;
import org.ethereum.manager.WorldManager;
import org.ethereum.net.MessageQueue;
import org.ethereum.net.PeerListener;
import org.ethereum.net.client.Capability;
import org.ethereum.net.eth.EthHandler;
import org.ethereum.net.eth.EthMessageCodes;
import org.ethereum.net.shh.ShhHandler;
@ -100,7 +102,7 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
break;
case GET_PEERS:
msgQueue.receivedMessage(msg);
// sendPeers(); // todo: implement session management for peer request
//sendPeers(); // todo: implement session management for peer request
break;
case PEERS:
msgQueue.receivedMessage(msg);
@ -154,18 +156,19 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
if (msg.getP2PVersion() != P2pHandler.VERSION)
msgQueue.sendMessage(new DisconnectMessage(ReasonCode.INCOMPATIBLE_PROTOCOL));
else {
adaptMessageIds(msg.getCapabilities());
if (msg.getCapabilities().contains("eth")) {
// Activate EthHandler for this peer
ctx.pipeline().addLast("eth", new EthHandler(msg.getPeerId(), peerListener, msgQueue));
List<Capability> capInCommon = new ArrayList<>();
for (Capability capability : msg.getCapabilities()) {
if (HELLO_MESSAGE.getCapabilities().contains(capability)) {
if (capability.getName().equals(Capability.ETH))
// Activate EthHandler for this peer
ctx.pipeline().addLast(Capability.ETH, new EthHandler(msg.getPeerId(), peerListener, msgQueue));
else if (capability.getName().equals(Capability.SHH))
// Activate ShhHandler for this peer
ctx.pipeline().addLast(Capability.SHH, new ShhHandler(msg.getPeerId(), peerListener));
capInCommon.add(capability);
}
}
if (msg.getCapabilities().contains("shh")) {
// Activate ShhHandler for this peer
ctx.pipeline().addLast("shh", new ShhHandler(msg.getPeerId(), peerListener));
}
adaptMessageIds(capInCommon);
InetAddress address = ((InetSocketAddress) ctx.channel().remoteAddress()).getAddress();
int port = msg.getListenPort();
@ -178,17 +181,17 @@ public class P2pHandler extends SimpleChannelInboundHandler<P2pMessage> {
}
}
public void adaptMessageIds(List<String> capabilities) {
public void adaptMessageIds(List<Capability> capabilities) {
byte offset = (byte) (P2pMessageCodes.USER.asByte() + 1);
for (String capability : capabilities){
for (Capability capability : capabilities) {
if (capability.equals("eth")){
if (capability.getName().equals(Capability.ETH)) {
EthMessageCodes.setOffset(offset);
offset += EthMessageCodes.values().length;
}
if (capability.equals("shh")){
if (capability.getName().equals(Capability.SHH)) {
ShhMessageCodes.setOffset(offset);
offset += ShhMessageCodes.values().length;
}

View File

@ -1,5 +1,6 @@
package org.ethereum.net.peerdiscovery;
import org.ethereum.net.client.Capability;
import org.ethereum.util.RLP;
import org.spongycastle.util.encoders.Hex;
@ -16,7 +17,7 @@ public class PeerData {
private int port;
private String peerId;
private List<String> capabilities;
private List<Capability> capabilities;
private transient boolean isOnline = false;
private transient long lastCheckTime = 0;
@ -58,7 +59,7 @@ public class PeerData {
this.lastCheckTime = lastCheckTime;
}
public List<String> getCapabilities() {
public List<Capability> getCapabilities() {
return capabilities;
}
@ -67,8 +68,9 @@ public class PeerData {
byte[] port = RLP.encodeInt(this.port);
byte[] peerId = RLP.encodeElement(Hex.decode(this.peerId));
byte[][] encodedCaps = new byte[this.capabilities.size()][];
for (int i = 0; i < this.capabilities.size(); i++) {
encodedCaps[i] = RLP.encodeString(this.capabilities.get(i));
for (int i = 0; i < this.capabilities.size()*2; i++) {
encodedCaps[i] = RLP.encodeString(this.capabilities.get(i).getName());
encodedCaps[i] = RLP.encodeByte(this.capabilities.get(i).getVersion());
}
byte[] capabilities = RLP.encodeList(encodedCaps);
return RLP.encodeList(ip, port, peerId, capabilities);

View File

@ -2,12 +2,14 @@ package org.ethereum.net;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.ethereum.net.client.Capability;
import org.ethereum.net.eth.EthHandler;
import org.ethereum.net.p2p.HelloMessage;
import org.ethereum.net.p2p.P2pMessageCodes;
import org.ethereum.net.shh.ShhHandler;
import org.junit.Test;
import org.spongycastle.util.encoders.Hex;
@ -43,34 +45,42 @@ public class HelloMessageTest {
@Test /* HelloMessage 2 from Node */
public void testNode() {
String helloMessageRaw = "F8 7B 80 80 AE 4E 45 74 68 65 72 65 "
+ "75 6D 28 2B 2B 29 2F 5A 65 72 6F 47 6F 78 2F 76 30 "
+ "2E 36 2E 39 2F 6E 63 75 72 73 65 73 2F 4C 69 6E 75 "
+ "78 2F 67 2B 2B C4 83 65 74 68 82 76 5F B8 40 CA DF "
+ "B9 3D 2B B5 FB E2 94 35 84 D9 3E D9 0E 37 46 67 C9 "
+ "E8 B2 50 2E 97 46 93 CC C6 B3 D3 70 BD 4C DE 77 38 "
+ "D0 B6 26 E3 D2 F3 CA EC C5 9E 13 02 D1 71 1B F5 95 "
+ "71 10 60 D7 B4 92 1E 18 B9 76 56";
String helloMessageRaw = "F8 80 80 02 AB 41 6C 65 "
+ "74 68 5A 65 72 6F 2F 76 30 2E 37 2E 34 2F 52 65 "
+ "6C 65 61 73 65 2D 78 36 34 2F 57 69 6E 64 6F 77 "
+ "73 2F 56 53 32 30 31 33 CC C5 83 65 74 68 23 C5 "
+ "83 73 68 68 01 82 76 5F B8 40 E1 01 2B 75 38 C4 "
+ "1D 31 9F B4 BE D7 DF E9 D7 ED C7 2B 82 F2 E6 BE "
+ "2D 20 F8 3C 60 14 11 51 5C 74 2B 3C E3 71 F5 61 "
+ "47 29 56 36 27 4D 34 91 D6 BC C5 1F 0A 09 20 EB "
+ "41 F2 C0 36 04 28 C9 A9 80 01";
byte[] payload = Hex.decode(helloMessageRaw);
HelloMessage helloMessage = new HelloMessage(payload);
System.out.println(helloMessage);
assertEquals(P2pMessageCodes.HELLO, helloMessage.getCommand());
assertEquals(0, helloMessage.getP2PVersion());
assertEquals("NEthereum(++)/ZeroGox/v0.6.9/ncurses/Linux/g++", helloMessage.getClientId());
assertEquals(1, helloMessage.getCapabilities().size());
assertEquals("eth", helloMessage.getCapabilities().get(0));
assertEquals(2, helloMessage.getP2PVersion());
assertEquals("AlethZero/v0.7.4/Release-x64/Windows/VS2013", helloMessage.getClientId());
assertEquals(2, helloMessage.getCapabilities().size());
assertEquals(Capability.ETH, helloMessage.getCapabilities().get(0).getName());
assertEquals(35, helloMessage.getCapabilities().get(0).getVersion());
assertEquals(Capability.SHH, helloMessage.getCapabilities().get(1).getName());
assertEquals(1, helloMessage.getCapabilities().get(1).getVersion());
assertEquals(30303, helloMessage.getListenPort());
assertEquals("cadfb93d2bb5fbe2943584d93ed90e374667c9e8b2502e974693ccc6b3d370bd4cde7738d0b626e3d2f3caecc59e1302d1711bf595711060d7b4921e18b97656",
assertEquals("e1012b7538c41d319fb4bed7dfe9d7edc72b82f2e6be2d20f83c601411515c742b3ce371f56147295636274d3491d6bcc51f0a0920eb41f2c0360428c9a98001",
helloMessage.getPeerId());
}
@Test /* HelloMessage 3 from new */
public void testFromNew() {
String helloAnnouncement = "Ethereum(J)/0.6.1/dev/Windows/Java";
byte p2pVersion = 0x00;
List<String> capabilities = new ArrayList<>(Arrays.asList("eth", "shh"));
byte p2pVersion = 0x0;
List<Capability> capabilities = Arrays.asList(
new Capability(Capability.ETH, EthHandler.VERSION),
new Capability(Capability.SHH, ShhHandler.VERSION));
int listenPort = 30303;
String peerId = "CAB0D93EEE1F44EF1286367101F1553450E3DDCE"
+ "EA45ABCAB0AC21E1EFB48A6610EBE88CE7317EB09229558311BA8B7250911D"
@ -80,10 +90,10 @@ public class HelloMessageTest {
capabilities, listenPort, peerId);
System.out.println(helloMessage);
// rlp encoded hello message
String expected = "F8738080A2457468657265756D284A292F302E362E312F6465762F5"
+ "7696E646F77732F4A617661C8836574688373686882765FB840CAB0D93EEE1F"
+ "44EF1286367101F1553450E3DDCEEA45ABCAB0AC21E1EFB48A6610EBE88CE73"
+ "17EB09229558311BA8B7250911D7E49562C3988CA3143329DA3EA";
String expected = "F8778080A2457468657265756D284A292F302E362E312F6465762F5"
+ "7696E646F77732F4A617661CCC58365746823C5837368680182765FB840CAB0"
+ "D93EEE1F44EF1286367101F1553450E3DDCEEA45ABCAB0AC21E1EFB48A6610E"
+ "BE88CE7317EB09229558311BA8B7250911D7E49562C3988CA3143329DA3EA";
assertEquals(P2pMessageCodes.HELLO, helloMessage.getCommand());
assertEquals(expected, Hex.toHexString(helloMessage.getEncoded()).toUpperCase());

View File

@ -1,14 +1,17 @@
package org.ethereum.net.wire;
import org.ethereum.net.client.Capability;
import org.ethereum.net.eth.EthHandler;
import org.ethereum.net.eth.EthMessageCodes;
import org.ethereum.net.p2p.P2pHandler;
import org.ethereum.net.p2p.P2pMessageCodes;
import org.ethereum.net.shh.ShhHandler;
import org.ethereum.net.shh.ShhMessageCodes;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@ -94,9 +97,10 @@ public class AdaptiveMessageIdsTest {
P2pHandler p2pHandler = new P2pHandler();
List<String> capabilities = new ArrayList<String>();
capabilities.add("eth"); capabilities.add("shh");
p2pHandler.adaptMessageIds( capabilities);
List<Capability> capabilities = Arrays.asList(
new Capability(Capability.ETH, EthHandler.VERSION),
new Capability(Capability.SHH, ShhHandler.VERSION));
p2pHandler.adaptMessageIds(capabilities);
Assert.assertEquals(0x10 + 1, EthMessageCodes.STATUS.asByte());
Assert.assertEquals(0x10 + 2, EthMessageCodes.GET_TRANSACTIONS.asByte());
@ -120,9 +124,10 @@ public class AdaptiveMessageIdsTest {
P2pHandler p2pHandler = new P2pHandler();
List<String> capabilities = new ArrayList<String>();
capabilities.add("shh"); capabilities.add("eth");
p2pHandler.adaptMessageIds( capabilities);
List<Capability> capabilities = Arrays.asList(
new Capability(Capability.ETH, EthHandler.VERSION),
new Capability(Capability.SHH, ShhHandler.VERSION));
p2pHandler.adaptMessageIds(capabilities);
Assert.assertEquals(0x10 + 1, ShhMessageCodes.STATUS.asByte());
Assert.assertEquals(0x10 + 2, ShhMessageCodes.MESSAGE.asByte());