Peer-to-peer (P2P) network

How to create a P2P network?

In ethp2psim, we provide two generators to assign weights to the nodes and edges of the peer-to-peer (P2P) network. By our terminology, edge weights represent communication latency on the communication channels (edges) of the P2P network, while node weights account for node relevance (i.e., portion of staked ether).

class ethp2psim.network.NodeWeightGenerator(mode='random', seed=None)[source]

Reusable object to generate weights for Peer-to-peer network nodes

Parameters:
  • mode ({'random', 'stake'}, default 'random') – Nodes are weighted either randomly, according to their staked Ethereum value

  • seed (int (optional)) – Random seed (disabled by default)

generate(graph, rng=None)[source]

Generate node weights for the nodes of the input graph.

Parameters:
  • graph (networkx.Graph) – Provide graph to generate node weights

  • rng (Optional[np.random._generator.Generator]) – Random number generator

Return type:

dict

Examples

>>> import networkx as nx
>>> G = nx.Graph()
>>> G.add_edges_from([(0,1),(1,2),(2,0)])
>>> nw_gen = NodeWeightGenerator('stake')
>>> len(nw_gen.generate(G))
3
class ethp2psim.network.EdgeWeightGenerator(mode='random', seed=None)[source]

Reusable object to generate latencies for connections between Peer-to-peer network nodes

Parameters:
  • mode ({'random', 'normal', 'unweighted', 'custom'}, default 'random') – Choose setting for connection latency generation!

  • seed (int (optional)) – Random seed (disabled by default)

generate(graph, rng=None)[source]

Generate edge weights (latency) for the edges of the input graph.

Parameters:
  • graph (networkx.Graph) – Provide graph to generate connections latencies

  • rng (Optional[np.random._generator.Generator]) – Random number generator

Return type:

dict

Examples

>>> import networkx as nx
>>> G = nx.Graph()
>>> G.add_edges_from([(0,1),(1,2),(2,3),(2,0)])
>>> ew_gen = EdgeWeightGenerator('normal')
>>> len(ew_gen.generate(G))
4

Using these generators, we can initialize the P2P network that is a random regular graph by default but you can also specify any custom graph as input, for instance, you can use the actual Ethereum P2P graph or some testnet’s P2P graph for your measurements. All network related actions are accessed through the network.Network object.

class ethp2psim.network.Network(node_weight_gen, edge_weight_gen, num_nodes=100, k=5, graph=None, seed=None)[source]

Peer-to-peer network abstraction

Parameters:
  • node_weight_gen (NodeWeightGenerator) – Set generator for node weights. By default random node weights are used.

  • edge_weight_gen (EdgeWeightGenerator) – Set generator for edge weights. By default random edge weights are used.

  • num_nodes (int) – Number of nodes in the peer-to-peer (P2P) graph

  • k (int) – Regularity parameter

  • graph (networkx.Graph) – Provide custom graph otherwise a k-regular random graph is generated

  • seed (int (optional)) – Random seed (disabled by default)

get_central_nodes(k, metric='degree')[source]

Get top central nodes of the P2P network

Parameters:
  • k (int) – Number of central nodes to return

  • metric (str {'betweenness','pagerank','degree'}) – Choose centrality metric

Examples

>>> from .data import GoerliTestnet
>>> nw_gen = NodeWeightGenerator('random')
>>> ew_gen = EdgeWeightGenerator('normal')
>>> goerli = GoerliTestnet()
>>> net = Network(nw_gen, ew_gen, graph=goerli.graph)
>>> net.get_central_nodes(3, 'degree')
['192', '772', '661']
get_edge_weight(node1, node2, external=None)[source]

Get edge weight for node pair

Parameters:
  • node1 (int) – First endpoint of the link to be removed

  • node2 (int) – Second endpoint of the link to be removed

Return type:

Optional[float]

Examples

>>> import networkx as nx
>>> G = nx.Graph()
>>> G.add_weighted_edges_from([(0,1,0.1),(1,2,0.2),(2,0,0.3)], weight='latency')
>>> nw_gen = NodeWeightGenerator('random')
>>> ew_gen = EdgeWeightGenerator('custom')
>>> net = Network(nw_gen, ew_gen, graph=G)
>>> net.get_edge_weight(0, 2)
0.3
>>> net.get_edge_weight(0, 3) is None
True
remove_edge(node1, node2)[source]

Delete edge from the network. The functions returns whether edge removal was successful.

Parameters:
  • node1 (int) – First endpoint of the link to be removed

  • node2 (int) – Second endpoint of the link to be removed

Return type:

bool

Examples

>>> import networkx as nx
>>> G = nx.Graph()
>>> G.add_edges_from([(0,1),(1,2),(2,0),(2,3)])
>>> nw_gen = NodeWeightGenerator('random')
>>> ew_gen = EdgeWeightGenerator('normal')
>>> net = Network(nw_gen, ew_gen, graph=G)
>>> net.remove_edge(2,3)
True
>>> net.remove_edge(2,3)
False
>>> net.remove_edge(0,2)
True
sample_random_nodes(count, replace, use_weights=False, exclude=None, rng=None)[source]

Sample network nodes uniformly at random

Parameters:
  • count (int) – Number of nodes to sample

  • replace (bool) – Whether the sample is with or without replacement

  • use_weights (bool) – Set to sample nodes with respect to their weights

  • exclude (Optional[list]) – List of nodes to exclude from the sample

  • rng (Optional[np.random._generator.Generator]) – Random number generator

Return type:

List[int]

Examples

>>> nw_gen = NodeWeightGenerator('random')
>>> ew_gen = EdgeWeightGenerator('normal')
>>> net = Network(nw_gen, ew_gen, num_nodes=5, k=2)
>>> candidates = net.sample_random_nodes(3, False, exclude=[3,4])
>>> len(candidates)
3
>>> 3 in candidates
False
>>> 4 in candidates
False
update(graph, reset_edge_weights=False, reset_node_weights=False)[source]

Update P2P network.

Parameters:
  • graph (networkx.Graph) – Update connections based on the provided graph.

  • reset_edge_weights (bool (default: False)) – Set whether to reset weights for existing edges

  • reset_node_weights (bool (default: False)) – Set whether to reset weights for existing nodes

Return type:

NoReturn

Examples

>>> import networkx as nx
>>> G1 = nx.Graph()
>>> G1.add_edges_from([(0,1),(1,2),(2,0)])
>>> G2 = nx.Graph()
>>> G2.add_edges_from([(2,3),(3,4),(4,0)])
>>> nw_gen = NodeWeightGenerator('random')
>>> ew_gen = EdgeWeightGenerator('normal')
>>> net = Network(nw_gen, ew_gen, graph=G1)
>>> net.num_nodes
3
>>> net.update(G2)
>>> net.num_nodes
5

Using real-world data

In our experiments, we compare the random regular graph model for simulating transactions with the underlying structure of the Goerli testnet. It is a good example on how to implement and add benchmark graph datasets to the experiments.

class ethp2psim.data.GoerliTestnet[source]

Network container for the Goerli Testnet

Examples

>>> goerli = GoerliTestnet()
>>> goerli.graph.number_of_nodes()
1355
>>> goerli.graph.number_of_edges()
19146

As a summary, let’s observe how to mimic the structure and properties of the real world Ethereum P2P network by incorporating

  1. staked Ethereum values as node relevance

  2. normal distribution of channel latencies

  3. structure of the Goerli testnet

nw_gen = NodeWeightGenerator('stake')
ew_gen = EdgeWeightGenerator('normal')
goerli = GoerliTestnet()
net = Network(nw_gen, ew_gen, graph=goerli.graph)

Next, let’s discuss how to propagate messages over the P2P network using different message-passing protocols.