Skip to content

Commit

Permalink
Merge branch 'old' into staging
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Jun 5, 2020
2 parents 1e2026e + 56a9f08 commit dd7006c
Show file tree
Hide file tree
Showing 29 changed files with 1,750 additions and 113 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ Cargo.lock
**/*.rs.bk

.idea

*.swp
8 changes: 5 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@ grin_secp256k1zkp = { git = "https://github.com/lnp-bp/rust-secp256k1-zkp", bran
# bitcoin = { version = "0.23.0", features = [ "use-serde" ] }
rand = "0.5" # Required by grin_secp256k1zkp
derive_wrapper = "0.1.3"
num-integer = "0.1.42"
num-traits = "0.2.11"
num-derive = "0.3.0"
tokio = { version = "~0.2", features = ["tcp"], optional = true }
futures = "~0.3"
torut = "0.1.2"
async-trait = { version = "~0.1", optional = true }
log = { version = "~0.4", features = ["max_level_trace", "release_max_level_debug"], optional = true }
zmq = { version = "~0.9", optional = true }
parse_arg = { version = "0.1.4", optional = true }
# This strange naming is a workaround for not being able to define required features for a dependency
# See https://github.com/rust-lang/api-guidelines/issues/180 for the explanation and references.
serde_crate = { package = "serde", version = "1.0.106", features = ["derive"], optional = true }
petgraph = { version = "0.5", optional = true }

[features]
default = []
Expand All @@ -44,7 +45,8 @@ use-log = ["log"]
use-tor = ["torut/v3"]
use-tokio = ["use-lightning", "tokio/tcp", "lightning-net-tokio"]
use-bulletproofs = ["grin_secp256k1zkp"]
use-rgb = ["use-bulletproofs"]
use-daemons = ["async-trait"]
use-rgb = ["use-bulletproofs", "petgraph"]
use-api = ["zmq"]
use-daemons = ["async-trait", "use-api"]
use-lightning = ["lightning"]
serde = ["serde_crate", "torut/serialize"]
186 changes: 186 additions & 0 deletions src/api/encode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
// LNP/BP Rust Library
// Written in 2020 by
// Dr. Maxim Orlovsky <[email protected]>
// Encoding strategies concept developed by
// Martin Habovštiak <[email protected]>
//
// 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 std::vec::IntoIter;
use std::convert::TryFrom;
use zmq::Message;

use bitcoin::consensus::encode::{
serialize as consensus_serialize,
deserialize as consensus_deserialize
};

use crate::bp::ShortId;
#[cfg(feature="use-rgb")]
use crate::csv::{self, network_serialize, network_deserialize};
use super::{Multipart, Error};


// 1. Encoding messages
pub trait MessageEncode where Self: Sized {
type Error: std::error::Error;
fn into_message(self) -> Message;
fn try_from_message(message: Message) -> Result<Self, Self::Error>;
}

/// This is a trick for rust compiler helping to distinguish types implementing
/// mutually-exclusive traits (required until negative trait impls will be there)
/// Implemented after concept by Martin Habovštiak <[email protected]>
mod strategy {
use core::marker::PhantomData;
use std::fmt;

// Defining strategies:
/// Strategy used for encoding data structures that support encoding with
/// bitcoin consensus rules (`bitcoin::consensus::encode`)
pub enum BitcoinConsensus { }

/// Strategy used for encoding data structures that support encoding with
/// RGB network serialization rules
#[cfg(feature="use-rgb")]
pub enum RGBStrategy { }

/// Strategy used for encoding data structures that can be directly
/// represented as `zmq::Message` with `TryFrom<Message>` and
/// `Into<Message>` trait implementations
pub enum Native { }

/// Strategy used for custom implementation of data structure encoding
pub trait Other { type Strategy: Clone + fmt::Debug + fmt::Display; }

pub struct Holder<T, S>(T, PhantomData<S>);
impl<T, S> Holder<T, S> {
pub fn new(val: T) -> Self { Self(val, PhantomData::<S>::default()) }
pub fn into_inner(self) -> T { self.0 }
}
}

// 1.1. Auto impl for bitcoin-serialized types
impl<T> MessageEncode for strategy::Holder<T, strategy::BitcoinConsensus>
where T: bitcoin::consensus::encode::Encodable +
bitcoin::consensus::encode::Decodable {
type Error = Error;
fn into_message(self) -> Message {
Message::from(consensus_serialize(&self.into_inner()))
}
fn try_from_message(message: Message) -> Result<Self, Self::Error> {
Ok(Self::new(consensus_deserialize(&message)?))
}
}

// 1.2. Auto impl for client-validation-serialized types
#[cfg(feature="use-rgb")]
impl<T> MessageEncode for strategy::Holder<T, strategy::RGBStrategy>
where T: csv::serialize::Network {
type Error = Error;
fn into_message(self) -> Message {
Message::from(network_serialize(&self.into_inner())
.expect("Commitment serialize failed"))
}
fn try_from_message(message: Message) -> Result<Self, Self::Error> {
Ok(Self::new(network_deserialize(&message)?))
}
}

// 1.3. Auto impl for types defining own Message serialization rules with TryFrom/Into
impl<T> MessageEncode for strategy::Holder<T, strategy::Native>
where T: TryFrom<Message, Error = Error> + Into<Message> {
type Error = Error;
fn into_message(self) -> Message {
self.into_inner().into()
}
fn try_from_message(message: Message) -> Result<Self, Self::Error> {
Ok(Self::new(T::try_from(message)?))
}
}

// 1.4. Blanket impl
impl<T> MessageEncode for T
where T: strategy::Other,
strategy::Holder<T, <T as strategy::Other>::Strategy>: MessageEncode {
type Error = <strategy::Holder<T, <T as strategy::Other>::Strategy> as MessageEncode>::Error;
fn into_message(self) -> Message {
strategy::Holder::new(self).into_message()
}
fn try_from_message(message: Message) -> Result<Self, Self::Error> {
Ok(strategy::Holder::try_from_message(message)?.into_inner())
}
}

// 1.5. Impl for bp::ShortId
impl MessageEncode for ShortId {
type Error = Error;
fn into_message(self) -> Message {
Message::from(&self.into_u64().to_be_bytes()[..])
}
fn try_from_message(message: Message) -> Result<Self, Self::Error> {
if message.len() != 8 {
Err(Error::MalformedArgument)
} else {
let mut buf = [0u8; 8];
buf.clone_from_slice(&message[..]);
Ok(Self::from(u64::from_be_bytes(buf)))
}
}
}


// 2. Encoding multipart messages
pub trait MultipartEncode<T>: TryFrom<Multipart> + Into<Multipart> {
fn into_multipart(self) -> Multipart {
self.into()
}
}

// Primitive type implementations
// 1. Vector
// We can't use wrapper; in the current version it does not support generics
//wrapper!(ReqVec<'a, T: ReqArg<'a>>, PhantomData<&'a Vec<T>>, Vec<T>,
// doc="Wrapper around `Vec` supporting `Req` trait");
#[derive(Clone)]
pub struct VecEncoding<T: MessageEncode>(Vec<T>);

// repr(transparent) is not yet working for generics, so we have to implement manually
impl<T> VecEncoding<T> where T: MessageEncode {
pub fn new(vec: Vec<T>) -> Self { Self(vec) }
pub fn into_iter(self) -> IntoIter<T> { self.0.into_iter() }
}

// repr(transparent) is not yet working for generics, so we have to implement manually
impl<T> IntoIterator for VecEncoding<T> where T: MessageEncode {
type Item = <Vec<T> as IntoIterator>::Item;
type IntoIter = <Vec<T> as IntoIterator>::IntoIter;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}

impl<T> MultipartEncode<T> for VecEncoding<T> where T: MessageEncode { }

impl<T> TryFrom<Multipart> for VecEncoding<T> where T: MessageEncode {
type Error = ();

fn try_from(args: Multipart) -> Result<Self, Self::Error> {
Ok(VecEncoding::new(args.into_iter().try_fold(Vec::<T>::new(), |mut vec, arg| {
vec.push(T::try_from_message(arg).map_err(|_| ())?);
Ok(vec)
})?))
}
}

impl<T> From<VecEncoding<T>> for Multipart where T: MessageEncode {
fn from(vec: VecEncoding<T>) -> Self {
vec.into_iter().map(T::into_message).collect()
}
}
69 changes: 69 additions & 0 deletions src/api/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// LNP/BP Rust Library
// Written in 2020 by
// Dr. Maxim Orlovsky <[email protected]>
//
// 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 zmq;

use bitcoin;
use bitcoin::secp256k1;

#[cfg(feature="use-rgb")]
use crate::csv;


#[derive(Debug, Display, From)]
#[display_from(Debug)]
pub enum Error {
/// Transport-level error
#[derive_from]
SocketError(zmq::Error),

// Request-specific errors
MalformedRequest,
MalformedCommand,
UnknownCommand,

// Reply-specific errors
MalformedReply,
MalformedStatus,
UnknownStatus,

// General API errors that may happen with both requests and replies
MalformedArgument,
WrongNumberOfArguments
}

impl std::error::Error for Error {}

impl From<Error> for String {
fn from(err: Error) -> Self { format!("{}", err) }
}

impl From<bitcoin::consensus::encode::Error> for Error {
fn from(_: bitcoin::consensus::encode::Error) -> Self {
Error::MalformedArgument
}
}

#[cfg(feature="use-rgb")]
impl From<csv::serialize::Error> for Error {
fn from(_: csv::serialize::Error) -> Self {
Error::MalformedArgument
}
}

impl From<secp256k1::Error> for Error {
fn from(_: secp256k1::Error) -> Self {
Error::MalformedArgument
}
}
35 changes: 35 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// LNP/BP Rust Library
// Written in 2020 by
// Dr. Maxim Orlovsky <[email protected]>
//
// 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>.

mod error;
mod encode;

pub use error::*;
pub use encode::*;


pub type Multipart = Vec<zmq::Message>;
pub type CommandId = u16;

pub fn split_cmd_args(multipart: &Multipart) -> Result<(CommandId, &[zmq::Message]), Error> {
Ok(multipart.split_first()
.ok_or(Error::MalformedRequest)
.and_then(|(cmd_data, args)| {
if cmd_data.len() != 2 {
Err(Error::MalformedCommand)?
}
let mut buf = [0u8; 2];
buf.clone_from_slice(&cmd_data[0..2]);
Ok((u16::from_be_bytes(buf), args))
})?)
}
14 changes: 12 additions & 2 deletions src/bp/blind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@


use bitcoin::Txid;
use bitcoin::hashes::{Hash, sha256d};
use bitcoin::hashes::{Hash, HashEngine, sha256d};


/// Data required to generate or reveal the information about blinded
/// transaction outpoint
#[derive(Clone, PartialEq, PartialOrd, Debug, Display, Default)]
#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Debug, Display, Default)]
#[display_from(Debug)]
pub struct OutpointReveal {
/// Blinding factor preventing rainbow table bruteforce attack based on
Expand All @@ -32,5 +32,15 @@ pub struct OutpointReveal {
pub vout: u16,
}

impl OutpointReveal {
pub fn outpoint_hash(&self) -> OutpointHash {
let mut engine = OutpointHash::engine();
engine.input(&self.blinding.to_be_bytes()[..]);
engine.input(&self.txid[..]);
engine.input(&self.vout.to_be_bytes()[..]);
OutpointHash::from_engine(engine)
}
}

hash_newtype!(OutpointHash, sha256d::Hash, 32, doc="Blind version of transaction outpoint");
impl_hashencode!(OutpointHash);
2 changes: 2 additions & 0 deletions src/bp/scripts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,10 @@
//! * `--(#=type)--`: the hash of the value following `->` must match to the value of the `<type>`
//!

use bitcoin::{hash_types::*, blockdata::script::*, secp256k1};
use miniscript::{Miniscript, MiniscriptKey, miniscript::iter::PubkeyOrHash};

use crate::Wrapper;


Expand Down
3 changes: 2 additions & 1 deletion src/bp/short_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ impl Descriptor {
}


#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)]
#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug, Display)]
#[display_from(Debug)]
pub struct ShortId(u64);

impl ShortId {
Expand Down
Loading

0 comments on commit dd7006c

Please sign in to comment.