Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions lnp2p/src/bifrost/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ mod app;
mod channel;
mod ctrl;
mod msg;
mod peerswap;
mod proposals;
mod types;

Expand All @@ -185,6 +186,7 @@ use internet2::{CreateUnmarshaller, Payload, Unmarshall, Unmarshaller};
use lnpbp::bech32::Blob;
pub use msg::Msg;
use once_cell::sync::Lazy;
pub use peerswap::*;
pub use proposals::*;
use strict_encoding::{self, StrictDecode, StrictEncode};
pub use types::{
Expand Down Expand Up @@ -257,6 +259,49 @@ pub enum Messages {

#[api(type = 0x0028)]
CloseChannel(CloseChannel),

#[api(type = 0x0040)]
SwapInRequest(SwapInRequestMsg),

#[api(type = 0x0041)]
SwapInAgreement(SwapInAgreementMsg),

#[api(type = 0x0042)]
SwapOutRequest(SwapOutRequestMsg),

#[api(type = 0x0043)]
SwapOutAgreement(SwapOutAgreementMsg),

#[api(type = 0x0044)]
OpeningTxBroadcasted(OpeningTxBroadcastedMsg),

#[api(type = 0x0045)]
Cancel(CancelMsg),

#[api(type = 0x0046)]
CoopClose(CoopCloseMsg),
}

impl Messages {
pub fn swap_id(&self) -> Option<&SwapId> {
match self {
Self::SwapInRequest(SwapInRequestMsg { swap_id, .. })
| Self::SwapOutRequest(SwapOutRequestMsg { swap_id, .. })
| Self::SwapInAgreement(SwapInAgreementMsg { swap_id, .. })
| Self::SwapOutAgreement(SwapOutAgreementMsg { swap_id, .. })
| Self::OpeningTxBroadcasted(OpeningTxBroadcastedMsg {
swap_id,
..
})
| Self::Cancel(CancelMsg { swap_id, .. })
| Self::CoopClose(CoopCloseMsg { swap_id, .. }) => Some(swap_id),
_ => None,
}
}

pub fn is_swap_msg(&self) -> bool {
self.swap_id().is_some()
}
}

impl StrictEncode for Messages {
Expand Down
300 changes: 300 additions & 0 deletions lnp2p/src/bifrost/peerswap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,300 @@
// LNP P2P library, plmeneting both bolt (BOLT) and Bifrost P2P messaging
// system for Lightning network protocol (LNP)
//
// Written in 2020-2021 by
// Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the MIT License
// along with this software.
// If not, see <https://opensource.org/licenses/MIT>.

use amplify::{Display, Slice32};
use bitcoin::hashes::{sha256, sha256t};
use bitcoin::Txid;
use lnpbp::chain::AssetId;
use secp256k1::{PublicKey, SecretKey};
#[cfg(feature = "serde")]
use serde_with::{As, DisplayFromStr};

use crate::bolt;

pub const PROTOCOL_VERSION: u16 = 1;
pub const BIFROST_APP_PEERSWAP: u16 = 0x8008;

// SHA256("bifrost:swap")
const SWAP_ID_MIDSTATE: [u8; 32] = [
0x4e, 0x2e, 0x6e, 0xb2, 0xa3, 0xda, 0x16, 0xbc, 0x03, 0xe3, 0x38, 0x30,
0xb3, 0xfa, 0xae, 0x6f, 0xe2, 0x76, 0x00, 0x1b, 0x2e, 0x79, 0xf1, 0x8f,
0xd3, 0x8c, 0x43, 0xdc, 0x79, 0xfb, 0x99, 0xdd,
];

/// Tag used for [`SwapId`] hash type
pub struct SwapIdTag;

impl sha256t::Tag for SwapIdTag {
#[inline]
fn engine() -> sha256::HashEngine {
let midstate = sha256::Midstate::from_inner(SWAP_ID_MIDSTATE);
sha256::HashEngine::from_midstate(midstate, 64)
}
}

#[derive(
Clone,
Copy,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Debug,
Display,
Default,
Wrapper,
From,
NetworkEncode,
NetworkDecode
)]
#[display(LowerHex)]
#[wrapper(FromStr, LowerHex, UpperHex, BorrowSlice)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate", transparent)
)]
pub struct SwapId(
#[cfg_attr(feature = "serde", serde(with = "As::<DisplayFromStr>"))]
Slice32,
);

impl SwapId {
#[inline]
pub fn random() -> Self {
SwapId::from(Slice32::random())
}
}

#[derive(
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Debug,
Display,
NetworkEncode,
NetworkDecode
)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(Debug)]
#[network_encoding(use_tlv)]
pub struct SwapInRequestMsg {
pub protocol_version: u64,
pub swap_id: SwapId,
pub asset: Option<AssetId>,
pub network: String,
pub scid: bolt::ChannelId,
pub amount: u64,
pub pubkey: PublicKey,
}

#[derive(Clone, Ord, PartialOrd, Eq, PartialEq, Hash, Debug, Display, Error)]
#[display(doc_comments)]
pub enum ValidationError {
/// Network and asset has different value.
NetworkMismatch,

/// Unknown Network {0}
UnknownNetwork(String),
}

impl SwapInRequestMsg {
pub fn validate(&self) -> Result<(), ValidationError> {
let _network_ok = {
match self.network.as_str() {
"mainnet" => Ok(()),
"testnet" => Ok(()),
"testnet3" => Ok(()),
"signet" => Ok(()),
"regtest" => Ok(()),
x => Err(ValidationError::UnknownNetwork(x.to_string())),
}
}?;

Ok(())
}
}

#[derive(
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Debug,
Display,
NetworkEncode,
NetworkDecode
)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(Debug)]
#[network_encoding(use_tlv)]
pub struct SwapInAgreementMsg {
pub protocol_version: u64,
pub swap_id: SwapId,
pub pubkey: PublicKey,
pub premium: u64,
}

#[derive(
Clone,
PartialEq,
Eq,
Hash,
Ord,
PartialOrd,
Debug,
Display,
NetworkEncode,
NetworkDecode
)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(Debug)]
#[network_encoding(use_tlv)]
pub struct SwapOutRequestMsg {
pub protocol_version: u64,
pub swap_id: SwapId,
pub asset: Option<AssetId>,
pub network: String,
pub scid: bolt::ChannelId,
pub amount: u64,
pub pubkey: PublicKey,
}

#[derive(
Clone,
PartialEq,
Eq,
Hash,
Ord,
PartialOrd,
Debug,
Display,
NetworkEncode,
NetworkDecode
)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(Debug)]
#[network_encoding(use_tlv)]
pub struct SwapOutAgreementMsg {
pub protocol_version: u64,
pub swap_id: SwapId,
pub pubkey: PublicKey,
pub payreq: String,
}

#[derive(
Clone,
PartialEq,
Eq,
Hash,
Ord,
PartialOrd,
Debug,
Display,
NetworkEncode,
NetworkDecode
)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(Debug)]
#[network_encoding(use_tlv)]
pub struct OpeningTxBroadcastedMsg {
pub swap_id: SwapId,
pub payreq: String,
pub tx_id: Txid,
pub script_out: u64,
pub blinding_key: SecretKey,
}

#[derive(
Clone,
PartialEq,
Eq,
Hash,
Ord,
PartialOrd,
Debug,
Display,
NetworkEncode,
NetworkDecode
)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(Debug)]
#[network_encoding(use_tlv)]
pub struct CancelMsg {
pub swap_id: SwapId,
pub message: String,
}

#[derive(
Clone,
PartialEq,
Eq,
Hash,
Ord,
PartialOrd,
Debug,
Display,
NetworkEncode,
NetworkDecode
)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display(Debug)]
#[network_encoding(use_tlv)]
pub struct CoopCloseMsg {
pub swap_id: SwapId,
pub message: String,
pub privkey: SecretKey,
}
6 changes: 6 additions & 0 deletions lnp2p/src/bifrost/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ impl sha256t::Tag for ChannelIdTag {
)]
#[wrapper(Debug, LowerHex, BorrowSlice)]
#[wrapper(Index, IndexRange, IndexFrom, IndexTo, IndexFull)]
#[cfg_attr(
feature = "serde",
serde_as,
derive(Serialize, Deserialize),
serde(crate = "serde_crate", transparent)
)]
pub struct ChannelId(sha256t::Hash<ChannelIdTag>);

impl ChannelId {
Expand Down
5 changes: 5 additions & 0 deletions lnp2p/src/bolt/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,11 @@ pub struct Alias(
)]
#[derive(LightningEncode, LightningDecode)]
#[cfg_attr(feature = "strict_encoding", derive(NetworkEncode, NetworkDecode))]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate")
)]
#[display("{block_height}x{tx_index}x{output_index}")]
pub struct ShortChannelId {
pub block_height: u24,
Expand Down