mina_transport/
lib.rs

1#![forbid(unsafe_code)]
2
3pub use libp2p::identity::{ed25519, Keypair};
4use libp2p::{
5    core::upgrade,
6    futures::{AsyncRead, AsyncWrite},
7    identity, noise, pnet,
8    swarm::NetworkBehaviour,
9    tcp, yamux, Multiaddr, Swarm, SwarmBuilder, Transport,
10};
11
12pub use libp2p::futures;
13
14/// Create a new random identity.
15/// Use the same identity type as `Mina` uses.
16pub fn generate_identity() -> Keypair {
17    identity::Keypair::generate_ed25519()
18}
19
20/// Create and configure a libp2p swarm. This will be able to talk to the Mina node.
21pub fn swarm<B, I, J>(
22    local_key: Keypair,
23    chain_id: &[u8],
24    listen_on: J,
25    peers: I,
26    behaviour: B,
27) -> Swarm<B>
28where
29    B: NetworkBehaviour,
30    I: IntoIterator<Item = Multiaddr>,
31    J: IntoIterator<Item = Multiaddr>,
32{
33    let pnet_key = {
34        use blake2::{
35            digest::{generic_array::GenericArray, Update, VariableOutput},
36            Blake2bVar,
37        };
38
39        let mut key = GenericArray::default();
40        Blake2bVar::new(32)
41            .expect("valid constant")
42            .chain(chain_id)
43            .finalize_variable(&mut key)
44            .expect("good buffer size");
45        key.into()
46    };
47    let yamux = {
48        use libp2p::core::{
49            upgrade::{InboundConnectionUpgrade, OutboundConnectionUpgrade},
50            UpgradeInfo,
51        };
52        use std::{
53            io,
54            pin::Pin,
55            task::{self, Context, Poll},
56        };
57
58        #[derive(Clone)]
59        struct CodaYamux(yamux::Config);
60
61        pin_project_lite::pin_project! {
62            struct SocketWrapper<C> {
63                #[pin]
64                inner: C,
65            }
66        }
67
68        impl<C> AsyncWrite for SocketWrapper<C>
69        where
70            C: AsyncWrite,
71        {
72            fn poll_write(
73                self: Pin<&mut Self>,
74                cx: &mut Context<'_>,
75                buf: &[u8],
76            ) -> Poll<io::Result<usize>> {
77                let this = self.project();
78                let len = task::ready!(this.inner.poll_write(cx, buf))?;
79                if len != 0 {
80                    log::debug!("<- {}", hex::encode(&buf[..len]));
81                }
82
83                Poll::Ready(Ok(len))
84            }
85
86            fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
87                let this = self.project();
88                this.inner.poll_flush(cx)
89            }
90
91            fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
92                let this = self.project();
93                this.inner.poll_close(cx)
94            }
95        }
96
97        impl<C> AsyncRead for SocketWrapper<C>
98        where
99            C: AsyncRead,
100        {
101            fn poll_read(
102                self: Pin<&mut Self>,
103                cx: &mut Context<'_>,
104                buf: &mut [u8],
105            ) -> Poll<io::Result<usize>> {
106                let this = self.project();
107                let len = task::ready!(this.inner.poll_read(cx, buf))?;
108                if len != 0 {
109                    log::debug!("-> {}", hex::encode(&buf[..len]));
110                }
111
112                Poll::Ready(Ok(len))
113            }
114        }
115
116        impl UpgradeInfo for CodaYamux {
117            type Info = &'static str;
118            type InfoIter = std::iter::Once<Self::Info>;
119
120            fn protocol_info(&self) -> Self::InfoIter {
121                std::iter::once("/coda/yamux/1.0.0")
122            }
123        }
124
125        impl<C> InboundConnectionUpgrade<C> for CodaYamux
126        where
127            C: AsyncRead + AsyncWrite + Send + Unpin + 'static,
128        {
129            type Output = <yamux::Config as InboundConnectionUpgrade<SocketWrapper<C>>>::Output;
130            type Error = <yamux::Config as InboundConnectionUpgrade<C>>::Error;
131            type Future = <yamux::Config as InboundConnectionUpgrade<SocketWrapper<C>>>::Future;
132
133            fn upgrade_inbound(self, socket: C, info: Self::Info) -> Self::Future {
134                self.0
135                    .upgrade_inbound(SocketWrapper { inner: socket }, info)
136            }
137        }
138
139        impl<C> OutboundConnectionUpgrade<C> for CodaYamux
140        where
141            C: AsyncRead + AsyncWrite + Send + Unpin + 'static,
142        {
143            type Output = <yamux::Config as OutboundConnectionUpgrade<SocketWrapper<C>>>::Output;
144            type Error = <yamux::Config as OutboundConnectionUpgrade<C>>::Error;
145            type Future = <yamux::Config as OutboundConnectionUpgrade<SocketWrapper<C>>>::Future;
146
147            fn upgrade_outbound(self, socket: C, info: Self::Info) -> Self::Future {
148                self.0
149                    .upgrade_outbound(SocketWrapper { inner: socket }, info)
150            }
151        }
152
153        CodaYamux(yamux::Config::default())
154    };
155
156    let mut swarm = SwarmBuilder::with_existing_identity(local_key)
157        .with_tokio()
158        .with_other_transport(|local_key| {
159            let pnet = pnet::PnetConfig::new(pnet::PreSharedKey::new(pnet_key));
160            tcp::tokio::Transport::new(tcp::Config::default().nodelay(true))
161                .and_then(move |socket, _| pnet.handshake(socket))
162                .upgrade(upgrade::Version::V1)
163                .authenticate(noise::Config::new(local_key).expect("libp2p-noise static keypair"))
164                .multiplex(yamux)
165                .timeout(std::time::Duration::from_secs(20))
166                .boxed()
167        })
168        .unwrap()
169        .with_dns()
170        .unwrap()
171        .with_behaviour(|_| behaviour)
172        .unwrap()
173        .build();
174
175    for addr in listen_on {
176        swarm.listen_on(addr).unwrap();
177    }
178    for peer in peers {
179        swarm.dial(peer).unwrap();
180    }
181
182    swarm
183}