Skip to content

Commit

Permalink
Merge pull request #152 from LNP-BP/v0.11
Browse files Browse the repository at this point in the history
Rewamp workflows on generating commitment ids
  • Loading branch information
dr-orlovsky authored Feb 26, 2024
2 parents c604733 + b7df64a commit a959681
Show file tree
Hide file tree
Showing 23 changed files with 984 additions and 1,325 deletions.
238 changes: 90 additions & 148 deletions Cargo.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ rust-version = "1.69" # Due to TOML in amplify dependency
edition = "2021"
license = "Apache-2.0"

[workspace.dependencies]
amplify = "4.6.0"
strict_encoding = "2.7.0-beta.1"
strict_types = "2.7.0-beta.1"

[package]
name = "client_side_validation"
version = { workspace = true }
Expand Down
11 changes: 6 additions & 5 deletions commit_verify/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,11 @@ name = "commit-stl"
required-features = ["stl"]

[dependencies]
amplify = { version = "4.5.0", features = ["hex", "apfloat"] }
commit_encoding_derive = { version = "0.10.0", path = "derive" }
strict_encoding = "2.6.1"
strict_types = { version = "1.6.3", optional = true }
amplify = { workspace = true, features = ["hex", "apfloat"] }
strict_encoding = { workspace = true }
strict_types = { workspace = true }
vesper-lang = "0.1.0"
commit_encoding_derive = { version = "0.11.0-beta.3", path = "derive" }
sha2 = "0.10.8"
ripemd = "0.1.3"
rand = { version = "0.8.5", optional = true }
Expand All @@ -38,7 +39,7 @@ rand = "0.8.5"
default = ["derive"]
all = ["rand", "serde", "stl", "derive"]
serde = ["serde_crate", "amplify/serde"]
stl = ["strict_types", "strict_types/base64"]
stl = ["strict_types/base85"]
derive = []

[package.metadata.docs.rs]
Expand Down
6 changes: 3 additions & 3 deletions commit_verify/derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "commit_encoding_derive"
version = "0.10.0"
version = { workspace = true }
description = "Commitment encoding derivation macros"
keywords = ["commitments", "proc-macro"]
categories = ["development-tools", "encoding"]
Expand All @@ -16,7 +16,7 @@ readme = "README.md"
proc-macro = true

[dependencies]
amplify = "4.0.0"
amplify = { workspace = true }
quote = "1"
syn = { version = "1", features = ["full"] }
proc-macro2 = "1"
Expand All @@ -25,4 +25,4 @@ amplify_syn = "2.0.0"
[dev-dependencies]
commit_verify = { path = ".." }
compiletest_rs = "0.9.0"
strict_encoding = "2.1.1"
strict_encoding = { workspace = true }
230 changes: 25 additions & 205 deletions commit_verify/derive/src/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,223 +19,43 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use amplify_syn::{DeriveInner, EnumKind, Field, FieldKind, Fields, Items, NamedField, Variant};
use proc_macro2::{Ident, Span, TokenStream as TokenStream2};
use quote::ToTokens;
use syn::{Error, Index, Result};
use proc_macro2::TokenStream as TokenStream2;
use syn::Result;

use crate::params::{CommitDerive, FieldAttr, StrategyAttr};

struct DeriveCommit<'a>(&'a CommitDerive);
use crate::params::{CommitDerive, StrategyAttr};

impl CommitDerive {
pub fn derive_encode(&self) -> Result<TokenStream2> {
match self.conf.strategy {
StrategyAttr::CommitEncoding => self.data.derive(
&self.conf.commit_crate,
&ident!(CommitEncode),
&DeriveCommit(self),
),
other => self.derive_strategy(other),
}
}

fn derive_strategy(&self, strategy: StrategyAttr) -> Result<TokenStream2> {
let (impl_generics, ty_generics, where_clause) = self.data.generics.split_for_impl();
let trait_crate = &self.conf.commit_crate;
let commitment_id = &self.conf.id;
let ident_name = &self.data.name;
let strategy_name = strategy.to_ident();

Ok(quote! {
#[automatically_derived]
impl #impl_generics #trait_crate::CommitStrategy for #ident_name #ty_generics #where_clause {
type Strategy = #trait_crate::strategies::#strategy_name;
}
})
}

fn derive_fields<'a>(
&self,
fields: impl Iterator<Item = (Option<&'a Ident>, &'a Field)>,
) -> Result<TokenStream2> {
let crate_name = &self.conf.commit_crate;

let conceal_code = if self.conf.conceal {
quote! {
let me = self.conceal();
}
} else {
quote! {
let me = self;
}
};

let mut field_encoding = Vec::new();
for (no, (field_name, unnamed_field)) in fields.enumerate() {
let kind = match field_name {
Some(_) => FieldKind::Named,
None => FieldKind::Unnamed,
};
let attr = FieldAttr::with(unnamed_field.attr.clone(), kind)?;
if attr.skip {
continue;
}
let field_name = field_name
.map(Ident::to_token_stream)
.unwrap_or_else(|| Index::from(no).to_token_stream());
let field = if let Some(tag) = attr.merklize {
quote! {
{
use #crate_name::merkle::MerkleLeaves;
#crate_name::merkle::MerkleNode::merklize(#tag.to_be_bytes(), &me.#field_name).commit_encode(e);
}
}
} else {
quote! {
me.#field_name.commit_encode(e);
}
};
field_encoding.push(field)
}

Ok(quote! {
fn commit_encode(&self, e: &mut impl ::std::io::Write) {
use #crate_name::CommitEncode;
#conceal_code
#( #field_encoding )*
}
})
}
}

impl DeriveInner for DeriveCommit<'_> {
fn derive_unit_inner(&self) -> Result<TokenStream2> {
Err(Error::new(
Span::call_site(),
"CommitEncode must not be derived on a unit types. Use just a unit type instead when \
encoding parent structure.",
))
}

fn derive_struct_inner(&self, fields: &Items<NamedField>) -> Result<TokenStream2> {
self.0
.derive_fields(fields.iter().map(|f| (Some(&f.name), &f.field)))
}

fn derive_tuple_inner(&self, fields: &Items<Field>) -> Result<TokenStream2> {
self.0.derive_fields(fields.iter().map(|f| (None, f)))
}

fn derive_enum_inner(&self, variants: &Items<Variant>) -> Result<TokenStream2> {
let crate_name = &self.0.conf.commit_crate;

if variants.enum_kind() == EnumKind::Primitive {
return Err(Error::new(
Span::call_site(),
"primitive enums can't use `propagate` strategy",
));
}

let conceal_code = if self.0.conf.conceal {
quote! {
let me = self.conceal();
}
} else {
quote! {
let me = self;
}
let inner = match self.conf.strategy {
StrategyAttr::Strict => quote! {
engine.commit_to_serialized(self);
},
StrategyAttr::ConcealStrict => quote! {
use #trait_crate::Conceal;
engine.commit_to_concealed(&self.conceal());
},
StrategyAttr::Transparent => quote! {
use amplify::Wrapper;
engine.commit_to_serialized(self.as_inner());
},
StrategyAttr::Merklize => quote! {
use amplify::Wrapper;
engine.commit_to_merkle(self.as_inner().merklize());
},
};

let mut write_variants = Vec::with_capacity(variants.len());
for var in variants {
let var_name = &var.name;
match &var.fields {
Fields::Unit => {
write_variants.push(quote! {
Self::#var_name => {},
});
}
Fields::Unnamed(fields) if fields.is_empty() => {
write_variants.push(quote! {
Self::#var_name() => {},
});
}
Fields::Named(fields) if fields.is_empty() => {
write_variants.push(quote! {
Self::#var_name {} => {},
});
}
Fields::Unnamed(fields) => {
let mut field_idx = Vec::with_capacity(fields.len());
let mut field_fragments = Vec::with_capacity(fields.len());
for (no, field) in fields.iter().enumerate() {
let index = Ident::new(&format!("_{no}"), Span::call_site());
let attr = FieldAttr::with(field.attr.clone(), FieldKind::Unnamed)?;
field_idx.push(index.clone());
if attr.skip {
continue;
}

if let Some(tag) = attr.merklize {
field_fragments.push(quote! {
MerkleNode::merklize(#tag.to_be_bytes(), #index).commit_encode(e);
})
} else {
field_fragments.push(quote! {
#index.commit_encode(e);
})
}
}
write_variants.push(quote! {
Self::#var_name( #( #field_idx ),* ) => {
#( #field_fragments )*
},
});
}
Fields::Named(fields) => {
let mut field_name = Vec::with_capacity(fields.len());
let mut field_fragments = Vec::with_capacity(fields.len());
for named_field in fields {
let attr =
FieldAttr::with(named_field.field.attr.clone(), FieldKind::Named)?;
let name = &named_field.name;
field_name.push(name.clone());
if attr.skip {
continue;
}

if let Some(tag) = attr.merklize {
field_fragments.push(quote! {
MerkleNode::merklize(#tag.to_be_bytes(), #name).commit_encode(e);
})
} else {
field_fragments.push(quote! {
#name.commit_encode(e);
})
}
}

write_variants.push(quote! {
Self::#var_name { #( #field_name ),* } => {
#( #field_fragments )*
},
});
}
}
}

Ok(quote! {
#[allow(unused_imports, unused_variables)]
fn commit_encode(&self, e: &mut impl ::std::io::Write) {
use #crate_name::CommitEncode;
use #crate_name::merkle::{MerkleLeaves, MerkleNode};
use ::strict_encoding::StrictSum;

#conceal_code
me.variant_ord().commit_encode(e);
#[automatically_derived]
impl #impl_generics #trait_crate::CommitEncode for #ident_name #ty_generics #where_clause {
type CommitmentId = #commitment_id;

match self {
#( #write_variants )*
fn commit_encode(&self, engine: &mut #trait_crate::CommitEngine) {
#inner
}
}
})
Expand Down
Loading

0 comments on commit a959681

Please sign in to comment.