def __init__( self, key_pair: KeyPair, peer_id: PeerID, peer_updater: PeerUpdater, status_provider: StatusProvider, finalized_root_provider: Callable[[Epoch], Root], block_provider_by_slot: BlockProviderBySlot, block_provider_by_root: BlockProviderByRoot, metadata_provider: MetadataProvider, fork_digest_provider: ForkDigestProvider, eth2_config: Eth2Config, ) -> None: peer_store = PeerStore() peer_store.add_key_pair(peer_id, key_pair) muxer_transports_by_protocol = {MPLEX_PROTOCOL_ID: Mplex} noise_key = ed25519.create_new_key_pair() security_transports_by_protocol = { TProtocol(secio.ID): secio.Transport(key_pair), TProtocol(noise.PROTOCOL_ID): noise.Transport(key_pair, noise_key.private_key) } upgrader = TransportUpgrader(security_transports_by_protocol, muxer_transports_by_protocol) transport = TCP() swarm = Swarm(peer_id, peer_store, upgrader, transport) BasicHost.__init__(self, swarm) self._peer_updater = peer_updater self._status_provider = status_provider self._finalized_root_provider_by_epoch = finalized_root_provider self._block_provider_by_slot = block_provider_by_slot self._block_provider_by_root = block_provider_by_root self._metadata_provider = metadata_provider self._request_responder = RequestResponder( self._peer_updater, self._status_provider, self._block_provider_by_slot, self._block_provider_by_root, self._metadata_provider, ) self._install_req_resp_protocols() self._gossiper = Gossiper(fork_digest_provider, self) self._peers: Set[PeerID] = set()
async def negotiate( self, communicator: IMultiselectCommunicator ) -> Tuple[TProtocol, StreamHandlerFn]: """ Negotiate performs protocol selection :param stream: stream to negotiate on :return: selected protocol name, handler function :raise MultiselectError: raised when negotiation failed """ await self.handshake(communicator) while True: try: command = await communicator.read() except MultiselectCommunicatorError as error: raise MultiselectError(error) if command == "ls": # TODO: handle ls command pass else: protocol = TProtocol(command) if protocol in self.handlers: try: await communicator.write(protocol) except MultiselectCommunicatorError as error: raise MultiselectError(error) return protocol, self.handlers[protocol] try: await communicator.write(PROTOCOL_NOT_FOUND_MSG) except MultiselectCommunicatorError as error: raise MultiselectError(error)
async def negotiate( self, communicator: IMultiselectCommunicator ) -> Tuple[TProtocol, StreamHandlerFn]: """ Negotiate performs protocol selection :param stream: stream to negotiate on :return: selected protocol name, handler function :raise Exception: negotiation failed exception """ # Perform handshake to ensure multiselect protocol IDs match await self.handshake(communicator) # Read and respond to commands until a valid protocol ID is sent while True: # Read message command = await communicator.read() # Command is ls or a protocol if command == "ls": # TODO: handle ls command pass else: protocol = TProtocol(command) if protocol in self.handlers: # Tell counterparty we have decided on a protocol await communicator.write(protocol) # Return the decided on protocol return protocol, self.handlers[protocol] # Tell counterparty this protocol was not found await communicator.write(PROTOCOL_NOT_FOUND_MSG)
async def perform_two_host_set_up( handler: StreamHandlerFn = echo_stream_handler ) -> Tuple[BasicHost, BasicHost]: transport_opt_list = [["/ip4/127.0.0.1/tcp/0"], ["/ip4/127.0.0.1/tcp/0"]] (node_a, node_b) = await set_up_nodes_by_transport_opt(transport_opt_list) node_b.set_stream_handler(TProtocol("/echo/1.0.0"), handler) # Associate the peer with local ip address (see default parameters of Libp2p()) node_a.get_peerstore().add_addrs(node_b.get_id(), node_b.get_addrs(), 10) return node_a, node_b
def initialize_default_swarm( key_pair: KeyPair, id_opt: ID = None, transport_opt: Sequence[str] = None, muxer_opt: TMuxerOptions = None, sec_opt: TSecurityOptions = None, peerstore_opt: IPeerStore = None, ) -> Swarm: """ initialize swarm when no swarm is passed in. :param id_opt: optional id for host :param transport_opt: optional choice of transport upgrade :param muxer_opt: optional choice of stream muxer :param sec_opt: optional choice of security upgrade :param peerstore_opt: optional peerstore :return: return a default swarm instance """ if not id_opt: id_opt = generate_peer_id_from(key_pair) # TODO: Parse `transport_opt` to determine transport transport = TCP() muxer_transports_by_protocol = muxer_opt or {MPLEX_PROTOCOL_ID: Mplex} security_transports_by_protocol = sec_opt or { TProtocol(PLAINTEXT_PROTOCOL_ID): InsecureTransport(key_pair), TProtocol(secio.ID): secio.Transport(key_pair), } upgrader = TransportUpgrader(security_transports_by_protocol, muxer_transports_by_protocol) peerstore = peerstore_opt or PeerStore() # Store our key pair in peerstore peerstore.add_key_pair(id_opt, key_pair) # TODO: Initialize discovery if not presented return Swarm(id_opt, peerstore, upgrader, transport)
def new_swarm( key_pair: KeyPair = None, muxer_opt: TMuxerOptions = None, sec_opt: TSecurityOptions = None, peerstore_opt: IPeerStore = None, ) -> INetworkService: """ Create a swarm instance based on the parameters. :param key_pair: optional choice of the ``KeyPair`` :param muxer_opt: optional choice of stream muxer :param sec_opt: optional choice of security upgrade :param peerstore_opt: optional peerstore :return: return a default swarm instance """ if key_pair is None: key_pair = generate_new_rsa_identity() id_opt = generate_peer_id_from(key_pair) # TODO: Parse `listen_addrs` to determine transport transport = TCP() muxer_transports_by_protocol = muxer_opt or {MPLEX_PROTOCOL_ID: Mplex} security_transports_by_protocol = sec_opt or { TProtocol(PLAINTEXT_PROTOCOL_ID): InsecureTransport(key_pair), TProtocol(secio.ID): secio.Transport(key_pair), } upgrader = TransportUpgrader(security_transports_by_protocol, muxer_transports_by_protocol) peerstore = peerstore_opt or PeerStore() # Store our key pair in peerstore peerstore.add_key_pair(id_opt, key_pair) return Swarm(id_opt, peerstore, upgrader, transport)
async def net_stream_pair_factory( is_secure: bool ) -> Tuple[INetStream, BasicHost, INetStream, BasicHost]: protocol_id = TProtocol("/example/id/1") stream_1: INetStream # Just a proxy, we only care about the stream def handler(stream: INetStream) -> None: nonlocal stream_1 stream_1 = stream host_0, host_1 = await host_pair_factory(is_secure) host_1.set_stream_handler(protocol_id, handler) stream_0 = await host_0.new_stream(host_1.get_id(), [protocol_id]) return stream_0, host_0, stream_1, host_1
async def net_stream_pair_factory( security_protocol: TProtocol = None, muxer_opt: TMuxerOptions = None ) -> AsyncIterator[Tuple[INetStream, INetStream]]: protocol_id = TProtocol("/example/id/1") stream_1: INetStream # Just a proxy, we only care about the stream. # Add a barrier to avoid stream being removed. event_handler_finished = trio.Event() async def handler(stream: INetStream) -> None: nonlocal stream_1 stream_1 = stream await event_handler_finished.wait() async with host_pair_factory(security_protocol=security_protocol, muxer_opt=muxer_opt) as hosts: hosts[1].set_stream_handler(protocol_id, handler) stream_0 = await hosts[0].new_stream(hosts[1].get_id(), [protocol_id]) yield stream_0, stream_1 event_handler_finished.set()
import logging import random from typing import Coroutine, List from libp2p.network.exceptions import SwarmException from libp2p.network.notifee_interface import INotifee from libp2p.network.stream.exceptions import StreamError from libp2p.network.stream.net_stream_interface import INetStream from libp2p.typing import TProtocol from aleph import __version__ from aleph.network import incoming_check from . import singleton from .pubsub import sub PROTOCOL_ID = TProtocol("/aleph/p2p/0.1.0") MAX_READ_LEN = 2 ** 32 - 1 LOGGER = logging.getLogger('P2P.protocol') STREAM_COUNT = 5 HELLO_PACKET = { 'command': 'hello' } CONNECT_LOCK = asyncio.Lock() class AlephProtocol(INotifee): def __init__(self, host, streams_per_host=5): self.host = host
from libp2p.network.connection.exceptions import RawConnError from libp2p.network.connection.raw_connection_interface import IRawConnection from libp2p.peer.id import ID from libp2p.security.base_session import BaseSession from libp2p.security.base_transport import BaseSecureTransport from libp2p.security.exceptions import HandshakeFailure from libp2p.security.secure_conn_interface import ISecureConn from libp2p.typing import TProtocol from libp2p.utils import encode_fixedint_prefixed, read_fixedint_prefixed from .pb import plaintext_pb2 # Reference: https://github.com/libp2p/go-libp2p-core/blob/master/sec/insecure/insecure.go PLAINTEXT_PROTOCOL_ID = TProtocol("/plaintext/2.0.0") class InsecureSession(BaseSession): def __init__( self, local_peer: ID, local_private_key: PrivateKey, conn: ReadWriteCloser, is_initiator: bool, peer_id: Optional[ID] = None, ) -> None: super().__init__(local_peer, local_private_key, is_initiator, peer_id) self.conn = conn async def write(self, data: bytes) -> int:
import argparse import asyncio import urllib.request import multiaddr from libp2p import new_node from libp2p.crypto.secp256k1 import create_new_key_pair from libp2p.network.stream.net_stream_interface import INetStream from libp2p.peer.peerinfo import info_from_p2p_addr from libp2p.typing import TProtocol PROTOCOL_ID = TProtocol("/echo/1.0.0") async def _echo_stream_handler(stream: INetStream) -> None: # Wait until EOF msg = await stream.read() await stream.write(msg) await stream.close() async def run(port: int, destination: str, localhost: bool, seed: int = None) -> None: if localhost: ip = "127.0.0.1" else: ip = urllib.request.urlopen("https://v4.ident.me/").read().decode( "utf8")
from libp2p.security.base_transport import BaseSecureTransport from libp2p.security.secure_conn_interface import ISecureConn from libp2p.typing import TProtocol from .exceptions import ( IncompatibleChoices, InconsistentNonce, InvalidSignatureOnExchange, PeerMismatchException, SecioException, SedesException, SelfEncryption, ) from .pb.spipe_pb2 import Exchange, Propose ID = TProtocol("/secio/1.0.0") NONCE_SIZE = 16 # bytes # NOTE: the following is only a subset of allowable parameters according to the # `secio` specification. DEFAULT_SUPPORTED_EXCHANGES = "P-256" DEFAULT_SUPPORTED_CIPHERS = "AES-128" DEFAULT_SUPPORTED_HASHES = "SHA256" class SecureSession(BaseSession): buf: io.BytesIO low_watermark: int high_watermark: int
import asyncio import logging from libp2p.network.stream.exceptions import StreamEOF, StreamReset from libp2p.network.stream.net_stream_interface import INetStream from libp2p.peer.id import ID as PeerID from libp2p.typing import TProtocol ID = TProtocol("/ipfs/ping/1.0.0") PING_LENGTH = 32 RESP_TIMEOUT = 60 logger = logging.getLogger("libp2p.host.ping") async def _handle_ping(stream: INetStream, peer_id: PeerID) -> bool: """Return a boolean indicating if we expect more pings from the peer at ``peer_id``.""" try: payload = await asyncio.wait_for(stream.read(PING_LENGTH), RESP_TIMEOUT) except asyncio.TimeoutError as error: logger.debug("Timed out waiting for ping from %s: %s", peer_id, error) raise except StreamEOF: logger.debug("Other side closed while waiting for ping from %s", peer_id) return False except StreamReset as error: logger.debug("Other side reset while waiting for ping from %s: %s", peer_id, error)
import asyncio import logging import random from typing import Any, Dict, Iterable, List, Sequence, Set from libp2p.peer.id import ID from libp2p.pubsub import floodsub from libp2p.typing import TProtocol from libp2p.utils import encode_varint_prefixed from .mcache import MessageCache from .pb import rpc_pb2 from .pubsub import Pubsub from .pubsub_router_interface import IPubsubRouter PROTOCOL_ID = TProtocol("/meshsub/1.0.0") logger = logging.getLogger("libp2p.pubsub.gossipsub") class GossipSub(IPubsubRouter): protocols: List[TProtocol] pubsub: Pubsub degree: int degree_high: int degree_low: int time_to_live: int
import logging from typing import Iterable, List, Sequence from libp2p.peer.id import ID from libp2p.typing import TProtocol from libp2p.utils import encode_varint_prefixed from .pb import rpc_pb2 from .pubsub import Pubsub from .pubsub_router_interface import IPubsubRouter PROTOCOL_ID = TProtocol("/floodsub/1.0.0") logger = logging.getLogger("libp2p.pubsub.floodsub") class FloodSub(IPubsubRouter): protocols: List[TProtocol] pubsub: Pubsub def __init__(self, protocols: Sequence[TProtocol]) -> None: self.protocols = list(protocols) self.pubsub = None def get_protocols(self) -> List[TProtocol]: """ :return: the list of protocols supported by the router """ return self.protocols
import logging from multiaddr import Multiaddr from libp2p.host.host_interface import IHost from libp2p.network.stream.net_stream_interface import INetStream from libp2p.typing import StreamHandlerFn, TProtocol from .pb.identify_pb2 import Identify ID = TProtocol("/ipfs/id/1.0.0") PROTOCOL_VERSION = "ipfs/0.1.0" # TODO dynamically generate the agent version AGENT_VERSION = "py-libp2p/alpha" logger = logging.getLogger("libp2p.identity.identify") def _multiaddr_to_bytes(maddr: Multiaddr) -> bytes: return maddr.to_bytes() def _mk_identify_protobuf(host: IHost) -> Identify: public_key = host.get_public_key() laddrs = host.get_addrs() protocols = host.get_mux().get_protocols() return Identify( protocol_version=PROTOCOL_VERSION, agent_version=AGENT_VERSION, public_key=public_key.serialize(), listen_addrs=map(_multiaddr_to_bytes, laddrs),
import argparse import sys import multiaddr import trio from libp2p import new_host from libp2p.network.stream.net_stream_interface import INetStream from libp2p.peer.peerinfo import info_from_p2p_addr from libp2p.typing import TProtocol PROTOCOL_ID = TProtocol("/chat/1.0.0") MAX_READ_LEN = 2**32 - 1 async def read_data(stream: INetStream) -> None: while True: read_bytes = await stream.read(MAX_READ_LEN) if read_bytes is not None: read_string = read_bytes.decode() if read_string != "\n": # Green console colour: \x1b[32m # Reset console colour: \x1b[0m print("\x1b[32m %s\x1b[0m " % read_string, end="") async def write_data(stream: INetStream) -> None: async_f = trio.wrap_file(sys.stdin) while True: line = await async_f.readline() await stream.write(line.encode())
from libp2p.security.secure_conn_interface import ISecureConn from libp2p.stream_muxer.abc import IMuxedConn, IMuxedStream from libp2p.typing import TProtocol from libp2p.utils import ( decode_uvarint_from_stream, encode_uvarint, encode_varint_prefixed, read_varint_prefixed_bytes, ) from .constants import HeaderTags from .datastructures import StreamID from .exceptions import MplexUnavailable from .mplex_stream import MplexStream MPLEX_PROTOCOL_ID = TProtocol("/mplex/6.7.0") class Mplex(IMuxedConn): """ reference: https://github.com/libp2p/go-mplex/blob/master/multiplex.go """ secured_conn: ISecureConn peer_id: ID next_channel_id: int streams: Dict[StreamID, MplexStream] streams_lock: asyncio.Lock new_stream_queue: "asyncio.Queue[IMuxedStream]" event_shutting_down: asyncio.Event event_closed: asyncio.Event