From b3b65b01c17368f526c1ba2c0ee7afeec15b18b8 Mon Sep 17 00:00:00 2001 From: Ryo Onodera Date: Mon, 3 Feb 2020 10:56:43 +0900 Subject: [PATCH] [WIP] Fix broken build cfgs by conditional crates --- Cargo.lock | 26 ++- programs/bpf/Cargo.lock | 28 +++ programs/vote/Cargo.toml | 2 +- programs/vote/src/lib.rs | 2 +- runtime/Cargo.toml | 2 +- runtime/src/lib.rs | 2 +- sdk/Cargo.toml | 5 +- sdk/macro-frozen-abi-dummy/Cargo.toml | 18 ++ sdk/macro-frozen-abi-dummy/src/lib.rs | 8 + sdk/macro-frozen-abi/Cargo.toml | 22 ++ sdk/macro-frozen-abi/src/lib.rs | 321 ++++++++++++++++++++++++++ sdk/macro/Cargo.toml | 4 - sdk/macro/src/lib.rs | 316 ------------------------- sdk/src/lib.rs | 7 +- 14 files changed, 434 insertions(+), 329 deletions(-) create mode 100644 sdk/macro-frozen-abi-dummy/Cargo.toml create mode 100644 sdk/macro-frozen-abi-dummy/src/lib.rs create mode 100644 sdk/macro-frozen-abi/Cargo.toml create mode 100644 sdk/macro-frozen-abi/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 745cac7b341daf..8f7b5139082a7c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4277,7 +4277,7 @@ dependencies = [ "solana-noop-program 0.24.0", "solana-rayon-threadlimit 0.24.0", "solana-sdk 0.24.0", - "solana-sdk-macro 0.24.0", + "solana-sdk-macro-frozen-abi 0.24.0", "solana-stake-program 0.24.0", "solana-storage-program 0.24.0", "solana-vote-program 0.24.0", @@ -4323,6 +4323,8 @@ dependencies = [ "solana-crate-features 0.24.0", "solana-logger 0.24.0", "solana-sdk-macro 0.24.0", + "solana-sdk-macro-frozen-abi 0.24.0", + "solana-sdk-macro-frozen-abi-dummy 0.24.0", "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-bip39 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4346,6 +4348,16 @@ dependencies = [ [[package]] name = "solana-sdk-macro" version = "0.24.0" +dependencies = [ + "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "solana-sdk-macro-frozen-abi" +version = "0.24.0" dependencies = [ "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4354,6 +4366,16 @@ dependencies = [ "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "solana-sdk-macro-frozen-abi-dummy" +version = "0.24.0" +dependencies = [ + "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "solana-stake-program" version = "0.24.0" @@ -4476,7 +4498,7 @@ dependencies = [ "solana-logger 0.24.0", "solana-metrics 0.24.0", "solana-sdk 0.24.0", - "solana-sdk-macro 0.24.0", + "solana-sdk-macro-frozen-abi 0.24.0", "thiserror 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/programs/bpf/Cargo.lock b/programs/bpf/Cargo.lock index 551f9822c45d4c..19f0b71d697a0b 100644 --- a/programs/bpf/Cargo.lock +++ b/programs/bpf/Cargo.lock @@ -2161,6 +2161,7 @@ dependencies = [ "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2170,6 +2171,7 @@ dependencies = [ "solana-metrics 0.24.0", "solana-rayon-threadlimit 0.24.0", "solana-sdk 0.24.0", + "solana-sdk-macro-frozen-abi 0.24.0", "solana-stake-program 0.24.0", "solana-storage-program 0.24.0", "solana-vote-program 0.24.0", @@ -2198,6 +2200,7 @@ dependencies = [ "pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_bytes 0.11.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2206,6 +2209,8 @@ dependencies = [ "solana-crate-features 0.24.0", "solana-logger 0.24.0", "solana-sdk-macro 0.24.0", + "solana-sdk-macro-frozen-abi 0.24.0", + "solana-sdk-macro-frozen-abi-dummy 0.24.0", "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2223,6 +2228,27 @@ dependencies = [ "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "solana-sdk-macro-frozen-abi" +version = "0.24.0" +dependencies = [ + "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "solana-sdk-macro-frozen-abi-dummy" +version = "0.24.0" +dependencies = [ + "bs58 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "solana-stake-program" version = "0.24.0" @@ -2265,11 +2291,13 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "solana-logger 0.24.0", "solana-metrics 0.24.0", "solana-sdk 0.24.0", + "solana-sdk-macro-frozen-abi 0.24.0", "thiserror 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/programs/vote/Cargo.toml b/programs/vote/Cargo.toml index 2f438f71d95f9a..d5a5f4d190282a 100644 --- a/programs/vote/Cargo.toml +++ b/programs/vote/Cargo.toml @@ -19,7 +19,7 @@ serde_derive = "1.0.103" solana-logger = { path = "../../logger", version = "0.24.0" } solana-metrics = { path = "../../metrics", version = "0.24.0" } solana-sdk = { path = "../../sdk", version = "0.24.0" } -solana-sdk-macro = { path = "../../sdk/macro", version = "0.24.0" } +solana-sdk-macro-frozen-abi = { path = "../../sdk/macro-frozen-abi", version = "0.24.0" } thiserror = "1.0" [build-dependencies] diff --git a/programs/vote/src/lib.rs b/programs/vote/src/lib.rs index d29786e06c7f59..1f77d75db1d500 100644 --- a/programs/vote/src/lib.rs +++ b/programs/vote/src/lib.rs @@ -11,4 +11,4 @@ solana_sdk::declare_program!( ); #[macro_use] -extern crate solana_sdk_macro; +extern crate solana_sdk_macro_frozen_abi; diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 9a53291c6dab84..83a70bc7169921 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -29,7 +29,7 @@ solana-measure = { path = "../measure", version = "0.24.0" } solana-metrics = { path = "../metrics", version = "0.24.0" } solana-bpf-loader-program = { path = "../programs/bpf_loader", version = "0.24.0" } solana-sdk = { path = "../sdk", version = "0.24.0" } -solana-sdk-macro = { path = "../sdk/macro", version = "0.24.0" } +solana-sdk-macro-frozen-abi = { path = "../sdk/macro-frozen-abi", version = "0.24.0" } solana-stake-program = { path = "../programs/stake", version = "0.24.0" } solana-storage-program = { path = "../programs/storage", version = "0.24.0" } solana-vote-program = { path = "../programs/vote", version = "0.24.0" } diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 810af28beed7cb..1de8ba76c04f7b 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -38,7 +38,7 @@ extern crate solana_bpf_loader_program; extern crate serde_derive; #[macro_use] -extern crate solana_sdk_macro; +extern crate solana_sdk_macro_frozen_abi; extern crate fs_extra; extern crate tempfile; diff --git a/sdk/Cargo.toml b/sdk/Cargo.toml index 6b1094c5e2786e..e11799db5e6cce 100644 --- a/sdk/Cargo.toml +++ b/sdk/Cargo.toml @@ -23,7 +23,6 @@ default = [ "ed25519-dalek", "solana-logger", "solana-crate-features", - "solana-sdk-macro" ] [dependencies] @@ -52,7 +51,9 @@ thiserror = "1.0" ed25519-dalek = { version = "=1.0.0-pre.1", optional = true } solana-crate-features = { path = "../crate-features", version = "0.24.0", optional = true } solana-logger = { path = "../logger", version = "0.24.0", optional = true } -solana-sdk-macro = { path = "macro", version = "0.24.0", optional = true } +solana-sdk-macro = { path = "macro", version = "0.24.0" } +solana-sdk-macro-frozen-abi = { path = "macro-frozen-abi", version = "0.24.0" } +solana-sdk-macro-frozen-abi-dummy = { path = "macro-frozen-abi-dummy", version = "0.24.0" } [dev-dependencies] tiny-bip39 = "0.7.0" diff --git a/sdk/macro-frozen-abi-dummy/Cargo.toml b/sdk/macro-frozen-abi-dummy/Cargo.toml new file mode 100644 index 00000000000000..fa6b233c253864 --- /dev/null +++ b/sdk/macro-frozen-abi-dummy/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "solana-sdk-macro-frozen-abi-dummy" +version = "0.24.0" +description = "Solana SDK Macro frozen abi" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +homepage = "https://solana.com/" +license = "Apache-2.0" +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +bs58 = "0.3.0" +proc-macro2 = "1.0" +quote = "1.0" +syn = { version = "1.0", features = ["full", "extra-traits"] } diff --git a/sdk/macro-frozen-abi-dummy/src/lib.rs b/sdk/macro-frozen-abi-dummy/src/lib.rs new file mode 100644 index 00000000000000..2557904f5a4f0c --- /dev/null +++ b/sdk/macro-frozen-abi-dummy/src/lib.rs @@ -0,0 +1,8 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; + +#[proc_macro_attribute] +pub fn frozen_abi(_attrs: TokenStream, item: TokenStream) -> TokenStream { + item +} diff --git a/sdk/macro-frozen-abi/Cargo.toml b/sdk/macro-frozen-abi/Cargo.toml new file mode 100644 index 00000000000000..64d06493aa791f --- /dev/null +++ b/sdk/macro-frozen-abi/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "solana-sdk-macro-frozen-abi" +version = "0.24.0" +description = "Solana SDK Macro frozen abi" +authors = ["Solana Maintainers "] +repository = "https://github.com/solana-labs/solana" +homepage = "https://solana.com/" +license = "Apache-2.0" +edition = "2018" +build = "../build.rs" + +[lib] +proc-macro = true + +[dependencies] +bs58 = "0.3.0" +proc-macro2 = "1.0" +quote = "1.0" +syn = { version = "1.0", features = ["full", "extra-traits"] } + +[build-dependencies] +rustc_version = "0.2" diff --git a/sdk/macro-frozen-abi/src/lib.rs b/sdk/macro-frozen-abi/src/lib.rs new file mode 100644 index 00000000000000..8c49c6d811bf80 --- /dev/null +++ b/sdk/macro-frozen-abi/src/lib.rs @@ -0,0 +1,321 @@ +extern crate proc_macro; + +use proc_macro::TokenStream; +#[cfg(RUSTC_IS_NIGHTLY)] +use proc_macro2::{Span, TokenTree::Group}; +#[cfg(RUSTC_IS_NIGHTLY)] +use quote::quote; +#[cfg(RUSTC_IS_NIGHTLY)] +use syn::{ + parse_macro_input, punctuated::Punctuated, token::Comma, Attribute, AttributeArgs, Ident, + NestedMeta, Variant, Visibility, +}; + +#[cfg(RUSTC_IS_NIGHTLY)] +fn filter_serde_attrs(attrs: &mut Vec) -> bool { + let mut skip = false; + + attrs.retain(|attr| { + let ss = &attr.path.segments.first().unwrap().ident.to_string(); + if ss.starts_with("serde") { + for token in attr.tokens.clone() { + if let Group(token) = token { + for ident in token.stream() { + if ident.to_string() == "skip" { + skip = true; + } + } + } + } + return true; + } + false + }); + + skip +} + +#[cfg(RUSTC_IS_STABLE)] +#[proc_macro_attribute] +pub fn frozen_abi(_attrs: TokenStream, item: TokenStream) -> TokenStream { + item +} + +#[cfg(RUSTC_IS_NIGHTLY)] +#[proc_macro_attribute] +pub fn frozen_abi(attrs: TokenStream, item: TokenStream) -> TokenStream { + let args = parse_macro_input!(attrs as AttributeArgs); + let mut expected_digest: Option = None; + for arg in args { + match arg { + NestedMeta::Meta(syn::Meta::NameValue(nv)) if nv.path.is_ident("digest") => { + if let syn::Lit::Str(lit) = nv.lit { + expected_digest = Some(lit.value()); + } + } + _ => {} + } + } + let expected_digest = expected_digest.expect("the required \"digest\" = ... is missing."); + + let item = syn::parse_macro_input!(item as syn::Item); + if let syn::Item::Struct(input) = item { + let name = &input.ident; + + let mod_name = Ident::new( + &format!("frozen_abi_tests_{}", name.to_string()), + Span::call_site(), + ); + /*let struct_name = Ident::new( + &format!("{}ForAbiDigest", name.to_string()), + Span::call_site(), + );*/ + + let mut header = input.clone(); + filter_serde_attrs(&mut header.attrs); + header.fields = syn::Fields::Unit; + header.vis = Visibility::Inherited; + let mut body = quote! { + digester.update(&["attrs", stringify!(#header)]); + }; + let fields = &input.fields; + let mut struct_body = quote! {}; + let mut struct_body2 = quote! {}; + let mut struct_body3 = quote! {}; + for mut field in fields.clone() { + let field_ident = &field.ident; + let field_type = &field.ty; + match fields { + syn::Fields::Named(_) => { + struct_body2 = quote! { + #struct_body2 + #field_ident: AbiDigestSample::sample(), + }; + } + syn::Fields::Unnamed(_) => { + struct_body2 = quote! { + #struct_body2 + AbiDigestSample::sample(), + }; + } + _ => panic!("bad"), + } + if filter_serde_attrs(&mut field.attrs) { + continue; + } + field.vis = Visibility::Inherited; + + body = quote! { + #body; + digester.update(&["field", stringify!(#field)]); + }; + struct_body = quote! { + #struct_body + #field, + }; + struct_body3 = quote! { + #struct_body3 + //let #field_ident: #field_type = ::solana_sdk::abi_digester::AbiDigest::abi_digest(); + //#field_ident: ::solana_sdk::abi_digester::AbiDigest::abi_digest(), + //::solana_sdk::abi_digester::AbiDigest::abi_digest::<#field_type>(); + digester.update_with_type2::<#field_type>(concat!("field ", stringify!(#field_ident))); + <#field_type>::abi_digest(&mut digester.child_digester()); + }; + } + match fields { + syn::Fields::Named(_) => { + struct_body2 = quote! { + { #struct_body2 } + } + } + syn::Fields::Unnamed(_) => { + struct_body2 = quote! { + ( #struct_body2 ) + } + } + _ => panic!("bad"), + } + + let result = quote! { + #input + #[automatically_derived] + impl ::solana_sdk::abi_digester::AbiDigestSample for #name { + fn sample() -> #name { + ::log::info!( + "AbiDigestSample for struct: {}", + std::any::type_name::<#name>() + ); + use ::solana_sdk::abi_digester::AbiDigestSample; + #name #struct_body2 + } + } + #[automatically_derived] + impl ::solana_sdk::abi_digester::AbiDigest for #name { + fn abi_digest(digester: &mut ::solana_sdk::abi_digester::AbiDigester) { + ::log::info!("AbiDigest for (struct): {}", std::any::type_name::<#name>()); + #struct_body3 + //return #name { + // #struct_body3 + //}; + } + } + #[cfg(test)] + mod #mod_name { + use super::*; + use serde::ser::Serialize; + + #[test] + fn test_frozen_abi() { + ::solana_logger::setup(); + let mut digester = ::solana_sdk::abi_digester::AbiDigester::create(); + /* + #[derive(Default, Serialize)] + struct #struct_name { + #struct_body + }; + impl AbiDigestSample for #struct_name { + fn sample() -> #struct_name { + return #struct_name { + #struct_body2 + }; + } + };*/ + use ::solana_sdk::abi_digester::AbiDigest; + <#name>::abi_digest(&mut digester); + /* + let value = #name::sample(); + digester = value.serialize(digester).unwrap(); + #body + */ + let mut hash = digester.finalize(); + assert_eq!(#expected_digest, format!("{}", hash)); + } + } + }; + result.into() + } else if let syn::Item::Enum(input) = item { + let name = &input.ident; + let mod_name = Ident::new( + &format!("frozen_abi_tests_{}", name.to_string()), + Span::call_site(), + ); + let mut header = input.clone(); + filter_serde_attrs(&mut header.attrs); + header.variants = Punctuated::::default(); + header.vis = Visibility::Inherited; + let mut body = quote! { + digester.update(&["attrs", stringify!(#header)]); + }; + let mut struct_body3 = quote! {}; + let mut enum_body2 = quote! {}; + let mut enum_body2_found = false; + for mut variant in input.variants.clone() { + if filter_serde_attrs(&mut variant.attrs) { + continue; + }; + body = quote! { + #body; + digester.update(&["variant", stringify!(#variant)]); + }; + let vi = &variant.ident; + let vt = &variant.fields; + if *vt == syn::Fields::Unit { + struct_body3 = quote! { + #struct_body3; + let v = #name::#vi; + } + } else if let syn::Fields::Unnamed(vt) = vt { + //::_logger::info!("{:#?}", vt); + let mut uc = quote! {}; + for u in &vt.unnamed { + if !(u.ident.is_none() && u.colon_token.is_none()) { + unimplemented!(); + } + let ty = &u.ty; + uc = quote! { + #uc + <#ty>::sample(), + }; + } + struct_body3 = quote! { + #struct_body3; + let v = #name::#vi(#uc); + } + } else if let syn::Fields::Named(vt) = vt { + let mut uc = quote! {}; + for u in &vt.named { + if u.ident.is_none() || u.colon_token.is_none() { + unimplemented!(); + } + let ty = &u.ty; + let ident = &u.ident; + uc = quote! { + #uc + #ident: <#ty>::sample(), + }; + } + struct_body3 = quote! { + #struct_body3; + let v = #name::#vi{#uc}; + } + } else { + unimplemented!("{:?}", vt); + } + if !enum_body2_found { + enum_body2_found = true; + enum_body2 = quote! { + #struct_body3; + } + } + struct_body3 = quote! { + #struct_body3; + v.serialize(digester.forced_child_digester()).unwrap(); + } + } + + let result = quote! { + #input + #[automatically_derived] + impl ::solana_sdk::abi_digester::AbiDigestSample for #name { + fn sample() -> #name { + ::log::info!( + "AbiDigestSample for enum: {}", + std::any::type_name::<#name>() + ); + #enum_body2; + v + } + } + #[automatically_derived] + impl ::solana_sdk::abi_digester::AbiDigest for #name { + fn abi_digest(digester: &mut ::solana_sdk::abi_digester::AbiDigester) { + use serde::ser::Serialize; + use ::solana_sdk::abi_digester::AbiDigestSample; + ::log::info!("AbiDigest for (enum): {}", std::any::type_name::<#name>()); + #struct_body3 + //return #name { + // #struct_body3 + //}; + } + } + #[cfg(test)] + mod #mod_name { + use super::*; + use serde::ser::Serialize; + #[test] + fn test_frozen_abi() { + ::solana_logger::setup(); + let mut digester = ::solana_sdk::abi_digester::AbiDigester::create(); + //#body + use ::solana_sdk::abi_digester::AbiDigest; + <#name>::abi_digest(&mut digester); + let hash = digester.finalize(); + assert_eq!(#expected_digest, format!("{}", hash)); + } + } + }; + result.into() + } else { + panic!("not applicable to ????"); + } +} diff --git a/sdk/macro/Cargo.toml b/sdk/macro/Cargo.toml index 442144ba07b658..3eab50fa36813d 100644 --- a/sdk/macro/Cargo.toml +++ b/sdk/macro/Cargo.toml @@ -7,7 +7,6 @@ repository = "https://github.com/solana-labs/solana" homepage = "https://solana.com/" license = "Apache-2.0" edition = "2018" -build = "../build.rs" [lib] proc-macro = true @@ -17,6 +16,3 @@ bs58 = "0.3.0" proc-macro2 = "1.0" quote = "1.0" syn = { version = "1.0", features = ["full", "extra-traits"] } - -[build-dependencies] -rustc_version = "0.2" diff --git a/sdk/macro/src/lib.rs b/sdk/macro/src/lib.rs index 105453de4009ac..2f30751743c9a7 100644 --- a/sdk/macro/src/lib.rs +++ b/sdk/macro/src/lib.rs @@ -6,19 +6,12 @@ extern crate proc_macro; use proc_macro::TokenStream; use proc_macro2::Span; -#[cfg(RUSTC_IS_NIGHTLY)] -use proc_macro2::TokenTree::Group; use quote::{quote, ToTokens}; use std::convert::TryFrom; use syn::{ parse::{Parse, ParseStream, Result}, parse_macro_input, Expr, LitByte, LitStr, }; -#[cfg(RUSTC_IS_NIGHTLY)] -use syn::{ - punctuated::Punctuated, token::Comma, Attribute, AttributeArgs, Ident, NestedMeta, Variant, - Visibility, -}; struct Id(proc_macro2::TokenStream); impl Parse for Id { @@ -78,312 +71,3 @@ pub fn declare_id(input: TokenStream) -> TokenStream { let id = parse_macro_input!(input as Id); TokenStream::from(quote! {#id}) } - -#[cfg(RUSTC_IS_NIGHTLY)] -fn filter_serde_attrs(attrs: &mut Vec) -> bool { - let mut skip = false; - - attrs.retain(|attr| { - let ss = &attr.path.segments.first().unwrap().ident.to_string(); - if ss.starts_with("serde") { - for token in attr.tokens.clone() { - if let Group(token) = token { - for ident in token.stream() { - if ident.to_string() == "skip" { - skip = true; - } - } - } - } - return true; - } - false - }); - - skip -} - -#[cfg(RUSTC_IS_STABLE)] -#[proc_macro_attribute] -pub fn frozen_abi(_attrs: TokenStream, item: TokenStream) -> TokenStream { - item -} - -#[cfg(RUSTC_IS_NIGHTLY)] -#[proc_macro_attribute] -pub fn frozen_abi(attrs: TokenStream, item: TokenStream) -> TokenStream { - let args = parse_macro_input!(attrs as AttributeArgs); - let mut expected_digest: Option = None; - for arg in args { - match arg { - NestedMeta::Meta(syn::Meta::NameValue(nv)) if nv.path.is_ident("digest") => { - if let syn::Lit::Str(lit) = nv.lit { - expected_digest = Some(lit.value()); - } - } - _ => {} - } - } - let expected_digest = expected_digest.expect("the required \"digest\" = ... is missing."); - - let item = syn::parse_macro_input!(item as syn::Item); - if let syn::Item::Struct(input) = item { - let name = &input.ident; - - let mod_name = Ident::new( - &format!("frozen_abi_tests_{}", name.to_string()), - Span::call_site(), - ); - /*let struct_name = Ident::new( - &format!("{}ForAbiDigest", name.to_string()), - Span::call_site(), - );*/ - - let mut header = input.clone(); - filter_serde_attrs(&mut header.attrs); - header.fields = syn::Fields::Unit; - header.vis = Visibility::Inherited; - let mut body = quote! { - digester.update(&["attrs", stringify!(#header)]); - }; - let fields = &input.fields; - let mut struct_body = quote! {}; - let mut struct_body2 = quote! {}; - let mut struct_body3 = quote! {}; - for mut field in fields.clone() { - let field_ident = &field.ident; - let field_type = &field.ty; - match fields { - syn::Fields::Named(_) => { - struct_body2 = quote! { - #struct_body2 - #field_ident: AbiDigestSample::sample(), - }; - } - syn::Fields::Unnamed(_) => { - struct_body2 = quote! { - #struct_body2 - AbiDigestSample::sample(), - }; - } - _ => panic!("bad"), - } - if filter_serde_attrs(&mut field.attrs) { - continue; - } - field.vis = Visibility::Inherited; - - body = quote! { - #body; - digester.update(&["field", stringify!(#field)]); - }; - struct_body = quote! { - #struct_body - #field, - }; - struct_body3 = quote! { - #struct_body3 - //let #field_ident: #field_type = ::solana_sdk::abi_digester::AbiDigest::abi_digest(); - //#field_ident: ::solana_sdk::abi_digester::AbiDigest::abi_digest(), - //::solana_sdk::abi_digester::AbiDigest::abi_digest::<#field_type>(); - digester.update_with_type2::<#field_type>(concat!("field ", stringify!(#field_ident))); - <#field_type>::abi_digest(&mut digester.child_digester()); - }; - } - match fields { - syn::Fields::Named(_) => { - struct_body2 = quote! { - { #struct_body2 } - } - } - syn::Fields::Unnamed(_) => { - struct_body2 = quote! { - ( #struct_body2 ) - } - } - _ => panic!("bad"), - } - - let result = quote! { - #input - #[automatically_derived] - impl ::solana_sdk::abi_digester::AbiDigestSample for #name { - fn sample() -> #name { - logger::info!( - "AbiDigestSample for struct: {}", - std::any::type_name::<#name>() - ); - use ::solana_sdk::abi_digester::AbiDigestSample; - #name #struct_body2 - } - } - #[automatically_derived] - impl ::solana_sdk::abi_digester::AbiDigest for #name { - fn abi_digest(digester: &mut ::solana_sdk::abi_digester::AbiDigester) { - logger::info!("AbiDigest for (struct): {}", std::any::type_name::<#name>()); - #struct_body3 - //return #name { - // #struct_body3 - //}; - } - } - #[cfg(test)] - mod #mod_name { - use super::*; - use serde::ser::Serialize; - - #[test] - fn test_frozen_abi() { - ::solana_logger::setup(); - let mut digester = ::solana_sdk::abi_digester::AbiDigester::create(); - /* - #[derive(Default, Serialize)] - struct #struct_name { - #struct_body - }; - impl AbiDigestSample for #struct_name { - fn sample() -> #struct_name { - return #struct_name { - #struct_body2 - }; - } - };*/ - use ::solana_sdk::abi_digester::AbiDigest; - <#name>::abi_digest(&mut digester); - /* - let value = #name::sample(); - digester = value.serialize(digester).unwrap(); - #body - */ - let mut hash = digester.finalize(); - assert_eq!(#expected_digest, format!("{}", hash)); - } - } - }; - result.into() - } else if let syn::Item::Enum(input) = item { - let name = &input.ident; - let mod_name = Ident::new( - &format!("frozen_abi_tests_{}", name.to_string()), - Span::call_site(), - ); - let mut header = input.clone(); - filter_serde_attrs(&mut header.attrs); - header.variants = Punctuated::::default(); - header.vis = Visibility::Inherited; - let mut body = quote! { - digester.update(&["attrs", stringify!(#header)]); - }; - let mut struct_body3 = quote! {}; - let mut enum_body2 = quote! {}; - let mut enum_body2_found = false; - for mut variant in input.variants.clone() { - if filter_serde_attrs(&mut variant.attrs) { - continue; - }; - body = quote! { - #body; - digester.update(&["variant", stringify!(#variant)]); - }; - let vi = &variant.ident; - let vt = &variant.fields; - if *vt == syn::Fields::Unit { - struct_body3 = quote! { - #struct_body3; - let v = #name::#vi; - } - } else if let syn::Fields::Unnamed(vt) = vt { - //logger::info!("{:#?}", vt); - let mut uc = quote! {}; - for u in &vt.unnamed { - if !(u.ident.is_none() && u.colon_token.is_none()) { - unimplemented!(); - } - let ty = &u.ty; - uc = quote! { - #uc - <#ty>::sample(), - }; - } - struct_body3 = quote! { - #struct_body3; - let v = #name::#vi(#uc); - } - } else if let syn::Fields::Named(vt) = vt { - let mut uc = quote! {}; - for u in &vt.named { - if u.ident.is_none() || u.colon_token.is_none() { - unimplemented!(); - } - let ty = &u.ty; - let ident = &u.ident; - uc = quote! { - #uc - #ident: <#ty>::sample(), - }; - } - struct_body3 = quote! { - #struct_body3; - let v = #name::#vi{#uc}; - } - } else { - unimplemented!("{:?}", vt); - } - if !enum_body2_found { - enum_body2_found = true; - enum_body2 = quote! { - #struct_body3; - } - } - struct_body3 = quote! { - #struct_body3; - v.serialize(digester.forced_child_digester()).unwrap(); - } - } - - let result = quote! { - #input - #[automatically_derived] - impl ::solana_sdk::abi_digester::AbiDigestSample for #name { - fn sample() -> #name { - logger::info!( - "AbiDigestSample for enum: {}", - std::any::type_name::<#name>() - ); - #enum_body2; - v - } - } - #[automatically_derived] - impl ::solana_sdk::abi_digester::AbiDigest for #name { - fn abi_digest(digester: &mut ::solana_sdk::abi_digester::AbiDigester) { - use serde::ser::Serialize; - use ::solana_sdk::abi_digester::AbiDigestSample; - logger::info!("AbiDigest for (enum): {}", std::any::type_name::<#name>()); - #struct_body3 - //return #name { - // #struct_body3 - //}; - } - } - #[cfg(test)] - mod #mod_name { - use super::*; - use serde::ser::Serialize; - #[test] - fn test_frozen_abi() { - ::solana_logger::setup(); - let mut digester = ::solana_sdk::abi_digester::AbiDigester::create(); - //#body - use ::solana_sdk::abi_digester::AbiDigest; - <#name>::abi_digest(&mut digester); - let hash = digester.finalize(); - assert_eq!(#expected_digest, format!("{}", hash)); - } - } - }; - result.into() - } else { - panic!("not applicable to ????"); - } -} diff --git a/sdk/src/lib.rs b/sdk/src/lib.rs index 73bb1c80aa8a6b..b06753b6da274a 100644 --- a/sdk/src/lib.rs +++ b/sdk/src/lib.rs @@ -85,5 +85,10 @@ extern crate serde_derive; pub extern crate bs58; extern crate log as logger; +#[cfg(all(not(feature = "program")))] #[macro_use] -extern crate solana_sdk_macro; +extern crate solana_sdk_macro_frozen_abi; + +#[cfg(all(feature = "program"))] +#[macro_use] +extern crate solana_sdk_macro_frozen_abi_dummy;