Skip to content

Commit

Permalink
refactor: unify offer id and swap (#297)
Browse files Browse the repository at this point in the history
* refactor: unify trade id and swap id with uuids

* chore: update changelog

* feat: add SwapId and TradeId

* chore: update changelog

* chore: improve changelog with references

* style: ran fmt

* fix: clippy new_without_default

* fix: clippy needless_borrow

* refactor: rename TradeId into DealId
  • Loading branch information
h4sh3d authored Dec 13, 2022
1 parent b32682f commit 110ac34
Show file tree
Hide file tree
Showing 8 changed files with 229 additions and 92 deletions.
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `Uuid` wrapper type against `uuid:Uuid` to identify trades and swaps, the wrapper implements strict encoding functionalities by @h4sh3d ([#297](https://github.com/farcaster-project/farcaster-core/pull/297))
- New `DealId` and `SwapId` types wrapping generic `Uuid` by @h4sh3d ([#297](https://github.com/farcaster-project/farcaster-core/pull/297))

### Changed

- Module `negotiation` is renamed as the `trade` module
- `Offer` and `PublicOffer` are renamed `DealParameters` and `Deal`, these structs are used to initialized a swap during the trade setup and should be the outcome of a proper negotiation phase currently out-of-scope for this library
- Module `negotiation` is renamed as the `trade` module by @h4sh3d and @Lederstrumpf ([#296](https://github.com/farcaster-project/farcaster-core/pull/296))
- `Offer` and `PublicOffer` are renamed `DealParameters` and `Deal`, these structs are used to initialized a swap during the trade setup and should be the outcome of a proper negotiation phase currently out-of-scope for this library by @h4sh3d and @Lederstrumpf ([#296](https://github.com/farcaster-project/farcaster-core/pull/296))
- Deal `uuid` type is switched to a wrapper type by @h4sh3d ([#297](https://github.com/farcaster-project/farcaster-core/pull/297))

### Removed

- `lightning_encoding` is removed for the protocol messages
- `SwapId` is removed and use the new `Uuid` wrapper type by @h4sh3d ([#297](https://github.com/farcaster-project/farcaster-core/pull/297))
- `lightning_encoding` is removed for the protocol messages by @h4sh3d ([#298](https://github.com/farcaster-project/farcaster-core/pull/298))

## [0.5.1] - 2022-08-15

Expand Down
99 changes: 99 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@ extern crate serde;
#[macro_use]
extern crate clap;

use std::io;
use std::str::FromStr;

use crate::consensus::{Decodable, Encodable};

use serde::{Deserialize, Serialize};
use thiserror::Error;

#[macro_use]
Expand Down Expand Up @@ -115,3 +121,96 @@ pub enum Error {
/// Result of an high level computation such as in Alice and Bob roles executing the protocol,
/// wraps the crate level [`enum@Error`] type.
pub type Res<T> = Result<T, Error>;

/// A unique identifier used to identify trades and swaps.
///
/// This is a wrapper against `uuid::Uuid` with `StrictEncode` and `StrictDecode` implementation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display, Serialize, Deserialize)]
#[display(inner)]
pub struct Uuid(uuid::Uuid);

impl Uuid {
/// Creates a new uuid for trades and swaps.
pub fn new() -> Self {
Self(uuid::Uuid::new_v4())
}

/// Creates a new random uuid, same as `Self::new()`.
pub fn random() -> Self {
Self::new()
}
}

impl Default for Uuid {
fn default() -> Self {
Self::new()
}
}

impl From<uuid::Uuid> for Uuid {
fn from(u: uuid::Uuid) -> Self {
Self(u)
}
}

impl FromStr for Uuid {
type Err = uuid::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(uuid::Uuid::from_str(s)?))
}
}

impl AsRef<uuid::Uuid> for Uuid {
fn as_ref(&self) -> &uuid::Uuid {
&self.0
}
}

impl Encodable for Uuid {
fn consensus_encode<W: io::Write>(&self, s: &mut W) -> Result<usize, io::Error> {
self.0.to_bytes_le().consensus_encode(s)
}
}

impl Decodable for Uuid {
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, consensus::Error> {
Ok(Self(uuid::Uuid::from_bytes_le(
Decodable::consensus_decode(d)?,
)))
}
}

impl strict_encoding::StrictEncode for Uuid {
fn strict_encode<E: io::Write>(&self, mut e: E) -> Result<usize, strict_encoding::Error> {
self.as_ref().to_bytes_le().strict_encode(&mut e)
}
}

impl strict_encoding::StrictDecode for Uuid {
fn strict_decode<D: io::Read>(mut d: D) -> Result<Self, strict_encoding::Error> {
Ok(Self(uuid::Uuid::from_bytes_le(<[u8; 16]>::strict_decode(
&mut d,
)?)))
}
}

#[cfg(test)]
mod tests {
use super::Uuid;
use uuid::uuid;

#[test]
fn serialize_swapid_in_yaml() {
let id: Uuid = uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8").into();
let s = serde_yaml::to_string(&id).expect("Encode swap id in yaml");
assert_eq!("---\n67e55044-10b1-426f-9247-bb680e5fe0c8\n", s);
}

#[test]
fn deserialize_swapid_from_yaml() {
let s = "---\n67e55044-10b1-426f-9247-bb680e5fe0c8\n";
let id: Uuid = serde_yaml::from_str(&s).expect("Decode uuid from yaml");
assert_eq!(id, uuid!("67e55044-10b1-426f-9247-bb680e5fe0c8").into(),);
}
}
44 changes: 27 additions & 17 deletions src/protocol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,16 @@ pub struct CoreArbitratingTransactions<Px> {
}

impl<Px> CoreArbitratingTransactions<Px> {
pub fn into_arbitrating_setup<Sig>(
pub fn into_arbitrating_setup<Sig, U>(
self,
swap_id: SwapId,
swap_id: U,
cancel_sig: Sig,
) -> CoreArbitratingSetup<Px, Sig> {
) -> CoreArbitratingSetup<Px, Sig>
where
U: Into<SwapId>,
{
CoreArbitratingSetup {
swap_id,
swap_id: swap_id.into(),
lock: self.lock,
cancel: self.cancel,
refund: self.refund,
Expand Down Expand Up @@ -262,13 +265,13 @@ where
Sk: CanonicalBytes,
{
/// Generates protocol message that commits to Alice's parameters.
pub fn commit_alice<C: Clone + Eq>(
pub fn commit_alice<C: Clone + Eq, U: Into<SwapId>>(
&self,
swap_id: SwapId,
swap_id: U,
wallet: &impl Commit<C>,
) -> CommitAliceParameters<C> {
CommitAliceParameters {
swap_id,
swap_id: swap_id.into(),
buy: wallet.commit_to(self.buy.as_canonical_bytes()),
cancel: wallet.commit_to(self.cancel.as_canonical_bytes()),
refund: wallet.commit_to(self.refund.as_canonical_bytes()),
Expand All @@ -288,9 +291,12 @@ where
}

/// Create the reveal protocol message based on the set of parameters.
pub fn reveal_alice(self, swap_id: SwapId) -> RevealAliceParameters<Pk, Qk, Rk, Sk, Addr> {
pub fn reveal_alice<U: Into<SwapId>>(
self,
swap_id: U,
) -> RevealAliceParameters<Pk, Qk, Rk, Sk, Addr> {
RevealAliceParameters {
swap_id,
swap_id: swap_id.into(),
buy: self.buy,
cancel: self.cancel,
refund: self.refund,
Expand All @@ -306,13 +312,13 @@ where
}

/// Generates protocol message that commits to Bob's parameters.
pub fn commit_bob<C: Clone + Eq>(
pub fn commit_bob<C: Clone + Eq, U: Into<SwapId>>(
&self,
swap_id: SwapId,
swap_id: U,
wallet: &impl Commit<C>,
) -> CommitBobParameters<C> {
CommitBobParameters {
swap_id,
swap_id: swap_id.into(),
buy: wallet.commit_to(self.buy.as_canonical_bytes()),
cancel: wallet.commit_to(self.cancel.as_canonical_bytes()),
refund: wallet.commit_to(self.refund.as_canonical_bytes()),
Expand All @@ -326,9 +332,12 @@ where
}

/// Create the reveal protocol message based on the set of parameters.
pub fn reveal_bob(self, swap_id: SwapId) -> RevealBobParameters<Pk, Qk, Rk, Sk, Addr> {
pub fn reveal_bob<U: Into<SwapId>>(
self,
swap_id: U,
) -> RevealBobParameters<Pk, Qk, Rk, Sk, Addr> {
RevealBobParameters {
swap_id,
swap_id: swap_id.into(),
buy: self.buy,
cancel: self.cancel,
refund: self.refund,
Expand Down Expand Up @@ -1399,9 +1408,9 @@ where
/// [`sign_adaptor_buy`]: Bob::sign_adaptor_buy
/// [`validate_adaptor_refund`]: Bob::validate_adaptor_refund
///
pub fn sign_adaptor_buy<Amt, Px, Pk, Qk, Rk, Sk, Ti, F, Pr, S, Ms, Si, EncSig>(
pub fn sign_adaptor_buy<Amt, Px, Pk, Qk, Rk, Sk, Ti, F, Pr, S, Ms, Si, EncSig, U>(
&self,
swap_id: SwapId,
swap_id: U,
wallet: &mut S,
alice_parameters: &Parameters<Pk, Qk, Rk, Sk, Addr, Ti, F, Pr>,
bob_parameters: &Parameters<Pk, Qk, Rk, Sk, Addr, Ti, F, Pr>,
Expand All @@ -1414,6 +1423,7 @@ where
Px: Clone + Fee<FeeUnit = F>,
Pk: Copy,
Ti: Copy,
U: Into<SwapId>,
{
// Extract the partial transaction from the core arbitrating protocol message, this
// operation should not error if the message is well formed.
Expand Down Expand Up @@ -1459,7 +1469,7 @@ where
let sig = wallet.encrypt_sign(ArbitratingKeyId::Buy, adaptor, msg)?;

Ok(BuyProcedureSignature {
swap_id,
swap_id: swap_id.into(),
buy: buy.to_partial(),
buy_adaptor_sig: sig,
})
Expand Down
87 changes: 35 additions & 52 deletions src/swap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,35 +18,49 @@
//! and its concrete instances of swaps.
use std::io;
use std::str::FromStr;

use crate::consensus::{self, Decodable, Encodable};
use crate::hash::HashString;
use strict_encoding::{StrictDecode, StrictEncode};

use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use crate::consensus::{self, Decodable, Encodable};
use crate::trade::DealId;
use crate::Uuid;

pub mod btcxmr;

fixed_hash::construct_fixed_hash!(
/// A unique swap identifier represented as an 32 bytes hash.
pub struct SwapId(32);
);
/// The identifier of a swap. This is a wrapper around [`Uuid`] that can be constructed from
/// [`DealId`].
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
Display,
Serialize,
Deserialize,
StrictEncode,
StrictDecode,
)]
#[serde(transparent)]
#[display(inner)]
pub struct SwapId(pub Uuid);

impl From<Uuid> for SwapId {
fn from(u: Uuid) -> Self {
SwapId(u)
}
}

impl Serialize for SwapId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(format!("{:#x}", self).as_ref())
impl From<uuid::Uuid> for SwapId {
fn from(u: uuid::Uuid) -> Self {
SwapId(u.into())
}
}

impl<'de> Deserialize<'de> for SwapId {
fn deserialize<D>(deserializer: D) -> Result<SwapId, D::Error>
where
D: Deserializer<'de>,
{
SwapId::from_str(&deserializer.deserialize_string(HashString)?).map_err(de::Error::custom)
impl From<DealId> for SwapId {
fn from(t: DealId) -> Self {
SwapId(t.0)
}
}

Expand All @@ -58,37 +72,6 @@ impl Encodable for SwapId {

impl Decodable for SwapId {
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, consensus::Error> {
let bytes: [u8; 32] = Decodable::consensus_decode(d)?;
Ok(Self::from_slice(&bytes))
}
}

impl_strict_encoding!(SwapId);

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn serialize_swapid_in_yaml() {
let swap_id =
SwapId::from_str("0x1baf1b36075de25a0f8e914b36759cac6f5d825622f8ccee597d87d4850c0d38")
.expect("Valid hex string");
let s = serde_yaml::to_string(&swap_id).expect("Encode swap id in yaml");
assert_eq!(
"---\n\"0x1baf1b36075de25a0f8e914b36759cac6f5d825622f8ccee597d87d4850c0d38\"\n",
s
);
}

#[test]
fn deserialize_swapid_from_yaml() {
let s = "---\n\"0x1baf1b36075de25a0f8e914b36759cac6f5d825622f8ccee597d87d4850c0d38\"\n";
let swap_id = serde_yaml::from_str(&s).expect("Decode swap id from yaml");
assert_eq!(
SwapId::from_str("0x1baf1b36075de25a0f8e914b36759cac6f5d825622f8ccee597d87d4850c0d38")
.expect("Valid hex string"),
swap_id
);
Ok(Self(Decodable::consensus_decode(d)?))
}
}
2 changes: 1 addition & 1 deletion src/swap/btcxmr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ impl KeyManager {
key_id: impl Derivation,
) -> Result<DerivationPath, crypto::Error> {
let path = blockchain.derivation_path()?;
let path = path.extend(&[self.swap_index]);
let path = path.extend([self.swap_index]);
Ok(path.extend(&key_id.derivation_path()?))
}

Expand Down
Loading

0 comments on commit 110ac34

Please sign in to comment.