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
14pub fn generate_identity() -> Keypair {
17 identity::Keypair::generate_ed25519()
18}
19
20pub 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}