diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4185b8fa..ad64451d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Allow multiple concurrent swaps with the same peer on the ASB.
This is a breaking change because the swap ID is now agreed upon between CLI and ASB during swap setup.
Resuming swaps started prior to this change can result in unexpected behaviour.
+- Quote protocol returns JSON encoded data instead of CBOR.
+ This is a breaking change in the protocol handling, old CLI versions will not be able to process quote requests of ASBs running this version.
### Added
diff --git a/swap/src/network.rs b/swap/src/network.rs
index bd658573..211445c3 100644
--- a/swap/src/network.rs
+++ b/swap/src/network.rs
@@ -2,6 +2,7 @@ mod impl_from_rr_event;
pub mod cbor_request_response;
pub mod encrypted_signature;
+pub mod json_pull_codec;
pub mod quote;
pub mod redial;
pub mod spot_price;
diff --git a/swap/src/network/json_pull_codec.rs b/swap/src/network/json_pull_codec.rs
new file mode 100644
index 00000000..8d802c16
--- /dev/null
+++ b/swap/src/network/json_pull_codec.rs
@@ -0,0 +1,99 @@
+use async_trait::async_trait;
+use futures::prelude::*;
+use libp2p::core::upgrade;
+use libp2p::request_response::{ProtocolName, RequestResponseCodec};
+use serde::de::DeserializeOwned;
+use serde::Serialize;
+use std::fmt::Debug;
+use std::io;
+use std::marker::PhantomData;
+
+/// Message receive buffer.
+pub const BUF_SIZE: usize = 1024 * 1024;
+
+/// A [`RequestResponseCodec`] for pull-based protocols where the response is
+/// encoded using JSON.
+///
+/// A pull-based protocol is a protocol where the dialer doesn't send any
+/// message and expects the listener to directly send the response as the
+/// substream is opened.
+#[derive(Clone, Copy, Debug)]
+pub struct JsonPullCodec
{
+ phantom: PhantomData<(P, Res)>,
+}
+
+impl
Default for JsonPullCodec
{
+ fn default() -> Self {
+ Self {
+ phantom: PhantomData::default(),
+ }
+ }
+}
+
+#[async_trait]
+impl
RequestResponseCodec for JsonPullCodec
+where
+ P: ProtocolName + Send + Sync + Clone,
+ Res: DeserializeOwned + Serialize + Send,
+{
+ type Protocol = P;
+ type Request = ();
+ type Response = Res;
+
+ async fn read_request(&mut self, _: &Self::Protocol, _: &mut T) -> io::Result
+ where
+ T: AsyncRead + Unpin + Send,
+ {
+ Ok(())
+ }
+
+ async fn read_response(
+ &mut self,
+ _: &Self::Protocol,
+ io: &mut T,
+ ) -> io::Result
+ where
+ T: AsyncRead + Unpin + Send,
+ {
+ let message = upgrade::read_one(io, BUF_SIZE)
+ .await
+ .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
+ let mut de = serde_json::Deserializer::from_slice(&message);
+ let msg = Res::deserialize(&mut de).map_err(|e| {
+ tracing::debug!("serde read_response error: {:?}", e);
+ io::Error::new(io::ErrorKind::InvalidData, e)
+ })?;
+
+ Ok(msg)
+ }
+
+ async fn write_request(
+ &mut self,
+ _: &Self::Protocol,
+ _: &mut T,
+ _: Self::Request,
+ ) -> io::Result<()>
+ where
+ T: AsyncWrite + Unpin + Send,
+ {
+ Ok(())
+ }
+
+ async fn write_response(
+ &mut self,
+ _: &Self::Protocol,
+ io: &mut T,
+ res: Self::Response,
+ ) -> io::Result<()>
+ where
+ T: AsyncWrite + Unpin + Send,
+ {
+ let bytes = serde_json::to_vec(&res).map_err(|e| {
+ tracing::debug!("serde write_response error: {:?}", e);
+ io::Error::new(io::ErrorKind::InvalidData, e)
+ })?;
+ upgrade::write_one(io, &bytes).await?;
+
+ Ok(())
+ }
+}
diff --git a/swap/src/network/quote.rs b/swap/src/network/quote.rs
index 1efa91e3..1920ae0e 100644
--- a/swap/src/network/quote.rs
+++ b/swap/src/network/quote.rs
@@ -1,5 +1,5 @@
use crate::bitcoin;
-use crate::network::cbor_request_response::CborCodec;
+use crate::network::json_pull_codec::JsonPullCodec;
use crate::protocol::{alice, bob};
use libp2p::core::ProtocolName;
use libp2p::request_response::{
@@ -13,7 +13,7 @@ const PROTOCOL: &str = "/comit/xmr/btc/bid-quote/1.0.0";
type OutEvent = RequestResponseEvent<(), BidQuote>;
type Message = RequestResponseMessage<(), BidQuote>;
-pub type Behaviour = RequestResponse>;
+pub type Behaviour = RequestResponse>;
#[derive(Debug, Clone, Copy, Default)]
pub struct BidQuoteProtocol;
@@ -40,7 +40,7 @@ pub struct BidQuote {
/// Alice only supports inbound connections, i.e. handing out quotes.
pub fn alice() -> Behaviour {
Behaviour::new(
- CborCodec::default(),
+ JsonPullCodec::default(),
vec![(BidQuoteProtocol, ProtocolSupport::Inbound)],
RequestResponseConfig::default(),
)
@@ -51,7 +51,7 @@ pub fn alice() -> Behaviour {
/// Bob only supports outbound connections, i.e. requesting quotes.
pub fn bob() -> Behaviour {
Behaviour::new(
- CborCodec::default(),
+ JsonPullCodec::default(),
vec![(BidQuoteProtocol, ProtocolSupport::Outbound)],
RequestResponseConfig::default(),
)