libp2p can run independently or be used as a dependency.
command of start a p2p node:
$ java -jar libp2p.jar [options]available cli options:
usage: available p2p discovery cli options:
-a,--active-nodes <arg> active node(s),
ip:port[,ip:port[...]]
-d,--discover <arg> enable p2p discover, 0/1, default 1
-h,--help print help message
-M,--max-connection <arg> max connection number, int, default
50
-m,--min-connection <arg> min connection number, int, default 8
-ma,--min-active-connection <arg> min active connection number, int,
default 2
-p,--port <arg> UDP & TCP port, int, default 18888
-s,--seed-nodes <arg> seed node(s), required,
ip:port[,ip:port[...]]
-t,--trust-ips <arg> trust ip(s), ip[,ip[...]]
-v,--version <arg> p2p version, int, default 1
available dns read cli options:
-u,--url-schemes <arg> dns url(s) to get nodes, url format
tree://{pubkey}@{domain}, url[,url[...]]
available dns publish cli options:
--access-key-id <arg> access key id of aws or aliyun api,
required, string
--access-key-secret <arg> access key secret of aws or aliyun api,
required, string
--aliyun-dns-endpoint <arg> if server-type is aliyun, it's endpoint
of aws dns server, required, string
--aws-region <arg> if server-type is aws, it's region of
aws api, such as "eu-south-1", required,
string
--change-threshold <arg> change threshold of add and delete to
publish, optional, should be > 0 and <
1.0, default 0.1
--dns-private <arg> dns private key used to publish,
required, hex string of length 64
--domain <arg> dns domain to publish nodes, required,
string
--host-zone-id <arg> if server-type is aws, it's host zone id
of aws's domain, optional, string
--known-urls <arg> known dns urls to publish, url format
tree://{pubkey}@{domain}, optional,
url[,url[...]]
--max-merge-size <arg> max merge size to merge node to a leaf
node in dns tree, optional, should be
[1~5], default 5
-publish,--publish enable dns publish
--server-type <arg> dns server to publish, required, only
aws or aliyun is support
--static-nodes <arg> static nodes to publish, if exist then
nodes from kad will be ignored,
optional, ip:port[,ip:port[...]]For details please check StartApp .
For example Node A, starts with default configuration parameters. Let's say its IP is 127.0.0.1
$ java -jar libp2p.jarNode B, start with seed nodes(127.0.0.1:18888). Let's say its IP is 127.0.0.2
$ java -jar libp2p.jar -s 127.0.0.1:18888Node C, start with with seed nodes(127.0.0.1:18888). Let's say its IP is 127.0.0.3
$ java -jar libp2p.jar -s 127.0.0.1:18888After the three nodes are successfully started, the usual situation is that node B can discover node C (or node C can discover B), and the three of them can establish a TCP connection with each other.
Libp2p support publish nodes on dns domain. Before publishing, you must enable p2p discover. Node lists can be deployed to any DNS provider such as CloudFlare DNS, dnsimple, Amazon Route 53, Aliyun Cloud using their respective client libraries. But we only support Amazon Route 53 and Aliyun Cloud. You can see more detail on https://eips.ethereum.org/EIPS/eip-1459, we implement this eip, but have some difference in data structure.
- Amazon Route 53 include: AWS Access Key ID、AWS Access Key Secret、Route53 Zone ID、AWS Region, get more info https://docs.aws.amazon.com/general/latest/gr/aws-sec-cred-types.html
- Aliyun Cloud include: accessKeyId、accessKeySecret、endpoint, get more info https://help.aliyun.com/document_detail/116401.html
Suppose you have a domain example.org hosted by Amazon Route 53, you can publish your nodes automatically like this:
java -jar libp2p.jar -p 18888 -v 201910292 -d 1 -s 127.0.0.1:18888 \
-publish \
--dns-private b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291 \
--server-type aws \
--access-key-id <AWS_Access_Key_ID> \
--access-key-secret <AWS_Access_Key_Secret> \
--aws-region us-east-1 \
--host-zone-id <Route53_Zone_ID> \
--domain nodes.example.orgThis program will do following periodically:
- get nodes from p2p discover service and construct a tree using these nodes
- collect txt records from dns domain with API
- compare tree with the txt records
- submit changes to dns domain with API if necessary.
We can get tree's url from log:
tree://APFGGTFOBVE2ZNAB3CSMNNX6RRK3ODIRLP2AA5U4YFAA6MSYZUYTQ@nodes.example.org
The compressed public Key APFGGTFOBVE2ZNAB3CSMNNX6RRK3ODIRLP2AA5U4YFAA6MSYZUYTQ is responsed to above dns-private key.
You can query dns record by following command and check if a TXT type record exists:
dig nodes.example.org TXTAt last we can release the tree's url on anywhere later, such as github. So others can download this tree to get nodes dynamically.
- P2pService is the entry class of p2p service and provides the startup interface of p2p service and the main interfaces provided by p2p module.
- P2pConfig defines all the configurations of the p2p module, such as the listening port, the maximum number of connections, etc.
- P2pEventHandler is the abstract class for p2p event handler.
- Channel
is an implementation of the TCP connection channel in the p2p module. The new connection channel
is obtained through the
P2pEventHandler.onConnectmethod.
P2pService.start- @param: p2pConfig P2pConfig
- @return: void
- desc: the startup interface of p2p service
P2pService.close- @param:
- @return: void
- desc: the close interface of p2p service
P2pService.register- @param: p2PEventHandler P2pEventHandler
- @return: void
- desc: register p2p event handler
P2pService.connect- @param: address InetSocketAddress
- @return: void
- desc: connect to a node with a socket address
P2pService.getAllNodes- @param:
- @return: List
- desc: get all the nodes
P2pService.getTableNodes- @param:
- @return: List
- desc: get all the nodes that in the hash table
P2pService.getConnectableNodes- @param:
- @return: List
- desc: get all the nodes that can be connected
P2pService.getP2pStats()- @param:
- @return: void
- desc: get statistics information of p2p service
Channel.send- @param: data byte[]
- @return: void
- desc: send messages to the peer node through the channel
Channel.close- @param:
- @return: void
- desc: the close interface of channel
- Config p2p discover parameters
- (optional) Config dns parameters
- Implement P2pEventHandler and register p2p event handler
- Start p2p service
- Use Channel's send and close interfaces as needed
- Use P2pService's interfaces as needed
New p2p config instance
P2pConfig config = new P2pConfig();Set p2p version
config.setVersion(11111);Set TCP and UDP listen port
config.setPort(18888);Turn node discovery on or off
config.setDiscoverEnable(true);Set discover seed nodes
List<InetSocketAddress> seedNodeList = new ArrayList<>();
seedNodeList.add(new InetSocketAddress("13.124.62.58", 18888));
seedNodeList.add(new InetSocketAddress("2600:1f13:908:1b00:e1fd:5a84:251c:a32a", 18888));
seedNodeList.add(new InetSocketAddress("[2600:1f13:908:1b00:e1fd:5a84:251c:1234]", 18888));
seedNodeList.add(new InetSocketAddress("127.0.0.4", 18888));
config.setSeedNodes(seedNodeList);Set active nodes
List<InetSocketAddress> activeNodeList = new ArrayList<>();
activeNodeList.add(new InetSocketAddress("127.0.0.2", 18888));
activeNodeList.add(new InetSocketAddress("127.0.0.3", 18888));
config.setActiveNodes(activeNodeList);Set trust ips
List<InetAddress> trustNodeList = new ArrayList<>();
trustNodeList.add((new InetSocketAddress("127.0.0.2", 18888)).getAddress());
config.setTrustNodes(trustNodeList);Set the minimum number of connections
config.setMinConnections(8);Set the minimum number of actively established connections
config.setMinActiveConnections(2);Set the maximum number of connections
config.setMaxConnections(30);Set the maximum number of connections with the same IP
config.setMaxConnectionsWithSameIp(2);Suppose these scenes in libp2p:
- you don't want to config one or many fixed seed nodes in mobile app such as wallet, because nodes may be out of service but you cannot update the app timely
- you don't known any seed node but you still want to establish tcp connection
You can config a dns tree regardless of whether discovery service is enabled or not. Assume you have a tree url of Tron's nile or shasta or mainnet nodes that publish on github like:
tree://APFGGTFOBVE2ZNAB3CSMNNX6RRK3ODIRLP2AA5U4YFAA6MSYZUYTQ@nodes.example.org
You can config the parameters like that:
config.setDiscoverEnable(false);
String[] urls = new String[] {"tree://APFGGTFOBVE2ZNAB3CSMNNX6RRK3ODIRLP2AA5U4YFAA6MSYZUYTQ@nodes.example.org"};
config.setTreeUrls(Arrays.asList(urls));After that, libp2p will download the nodes from nile.nftderby1.net periodically.
Implement definition message
public class TestMessage {
protected MessageTypes type;
protected byte[] data;
public TestMessage(byte[] data) {
this.type = MessageTypes.TEST;
this.data = data;
}
}
public enum MessageTypes {
FIRST((byte)0x00),
TEST((byte)0x01),
LAST((byte)0x8f);
private final byte type;
MessageTypes(byte type) {
this.type = type;
}
public byte getType() {
return type;
}
private static final Map<Byte, MessageTypes> map = new HashMap<>();
static {
for (MessageTypes value : values()) {
map.put(value.type, value);
}
}
public static MessageTypes fromByte(byte type) {
return map.get(type);
}
}Inheritance implements the P2pEventHandler class.
onConnectis called back after the TCP connection is established.onDisconnectis called back after the TCP connection is closed.onMessageis called back after receiving a message on the channel. Note thatdata[0]is the message type.
public class MyP2pEventHandler extends P2pEventHandler {
public MyP2pEventHandler() {
this.typeSet = new HashSet<>();
this.typeSet.add(MessageTypes.TEST.getType());
}
@Override
public void onConnect(Channel channel) {
channels.put(channel.getInetSocketAddress(), channel);
}
@Override
public void onDisconnect(Channel channel) {
channels.remove(channel.getInetSocketAddress());
}
@Override
public void onMessage(Channel channel, byte[] data) {
byte type = data[0];
byte[] messageData = ArrayUtils.subarray(data, 1, data.length);
switch (MessageTypes.fromByte(type)) {
case TEST:
TestMessage message = new TestMessage(messageData);
// process TestMessage
break;
default:
// todo
}
}
}Start p2p service with P2pConfig and P2pEventHandler
P2pService p2pService = new P2pService();
MyP2pEventHandler myP2pEventHandler = new MyP2pEventHandler();
try {
p2pService.register(myP2pEventHandler);
} catch (P2pException e) {
// todo process exception
}
p2pService.start(config);For details please check ImportUsing, DnsExample1, DnsExample2