1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
#![feature(proc_macro_diagnostic)]
#![deny(rust_2018_idioms)]
use proc_macro::TokenStream;
mod error_derive;
mod event_derive;
mod evm_derive;
mod generators;
mod module_derive;
#[cfg(test)]
mod test_utils;
mod version_from_cargo;
/// Emits a compile-time error `msg` from a macro, and uses the span of the
/// macro invocation if possible. If span info is not available (should only
/// happen in unit tests), panics with `msg`.
fn emit_compile_error<S: Into<String> + Clone + std::panic::RefUnwindSafe>(msg: S) -> ! {
std::panic::catch_unwind(|| {
proc_macro2::Span::call_site()
.unwrap()
.error(msg.clone().into())
.emit();
})
.ok()
.or_else(|| {
panic!("{}", msg.into());
});
unreachable!(); // error().emit() already halts compilation, but type checker doesn't know that
}
/// Derives the `Event` trait on an enum.
#[proc_macro_derive(Event, attributes(sdk_event))]
pub fn event_derive(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
event_derive::derive_event(input).into()
}
/// Derives the `Error` trait on an enum.
// The helper attribute is `sdk_error` to avoid conflict with `thiserror::Error`.
#[proc_macro_derive(Error, attributes(sdk_error, source, from))]
pub fn error_derive(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
error_derive::derive_error(input).into()
}
/// Derives the `EvmEvent` trait on a struct.
#[proc_macro_derive(EvmEvent, attributes(evm_event))]
pub fn evm_event_derive(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
evm_derive::derive_evm_event(input).into()
}
/// Derives the `EvmError` trait on an enum.
#[proc_macro_derive(EvmError, attributes(evm_error))]
pub fn evm_error_derive(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::DeriveInput);
evm_derive::derive_evm_error(input).into()
}
/// Derives traits from a non-trait `impl` block (rather than from a `struct`).
///
/// Only the `Module` and `EvmContract` traits are supported. In other words,
/// given an `impl MyModule` block, the macro derives implementations needed either
/// for implementing a module (see also the `#[handler]` and `#[migration]` attributes)
/// or for implementing an EVM contract (see also the `#[evm_method]` attribute).
#[proc_macro_attribute]
pub fn sdk_derive(args: TokenStream, input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::ItemImpl);
match args.to_string().as_str() {
"Module" => module_derive::derive_module(input).into(),
"EvmContract" => evm_derive::derive_evm_contract(input).into(),
_ => emit_compile_error(
"#[sdk_derive] only supports #[sdk_derive(Module)] and #[sdk_derive(EvmContract)]",
),
}
}
/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anyting on its own;
/// it only marks functions that represent a paratime method handler.
/// The permitted forms are:
/// - `#[handler(call = "my_module.MyCall")]`: Marks a function that handles
/// the "my_module.MyCall" call and can be passed to
/// oasis_runtime_sdk::module::dispatch_call.
/// - `#[handler(prefetch = "my_module.MyCall")]`: Marks a function that handles
/// the request to prefetch any data ahead of the "my_module.MyCall" call.
/// Its signature should be `Fn(
/// add_prefix: &mut dyn FnMut(Prefix) -> (),
/// body: cbor::Value,
/// auth_info: &AuthInfo,
/// ) -> Result<(), oasis_runtime_sdk::error::RuntimeError>`
/// - `#[handler(query = "my_module.MyQuery")]`: Marks a function that handles
/// the "my_module.MyQuery" query and can be passed to
/// oasis_runtime_sdk::module::dispatch_query.
/// - `#[handler(message_result = "my_module.MyMR")]`: Marks a function that handles
/// the "my_module.MyMR" message result and can be passed to
/// oasis_runtime_sdk::module::dispatch_message_result.
///
/// Query handler can also contain the `expensive` tag. Example:
/// `#[handler(query = "my_module.MyQuery", expensive)]`.
/// Queries tagged `expensive` can be enabled/disabled are disabled by default to avoid
/// excessive costs to the node operator. This can be overridden in the node config.
///
/// NOTE: This attribute is parsed by the `#[sdk_derive(...)]` macro, which cannot
/// interpret the attribute name semantically. Use `#[handler]`, not
/// `#[oasis_runtime_sdk_macros::handler]` or other paths/aliases.
#[proc_macro_attribute]
pub fn handler(_args: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anything on its own;
/// it only marks functions that represent a module state migration.
///
/// The permitted forms are:
/// - `#[migration(init)]`: Marks the initial (genesis) migration.
/// - `#[migration(from = v)]`: Marks a migration from version v to v+1, where v is
/// a non-negative integer.
#[proc_macro_attribute]
pub fn migration(_args: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anything on its own;
/// it only marks functions that represent contract methods.
///
/// The permitted forms are:
/// - `#[evm_method(signature = "...")]`: The method selector is computed from
/// a Solidity method signature, and the method takes the precompute handle
/// and data offset as parameters.
/// - `#[evm_method(signature = "...", convert)]`: The method selector is
/// computed from the signature, the arguments are automatically decoded and
/// passed to the marked method, which must have the appropriate number and
/// type of arguments.
#[proc_macro_attribute]
pub fn evm_method(_args: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// A helper attribute for `#[sdk_derive(...)]`. It doesn't do anything on its own;
/// it only marks the function within a contract implementation that returns its address.
///
/// The method marked with this attribute should take no arguments and return
/// an object of type `primitive_types::H160`.
#[proc_macro_attribute]
pub fn evm_contract_address(_args: TokenStream, input: TokenStream) -> TokenStream {
input
}
/// Constructs an `oasis_sdk::core::common::version::Version` from the Cargo.toml version.
#[proc_macro]
pub fn version_from_cargo(_input: TokenStream) -> TokenStream {
version_from_cargo::version_from_cargo().into()
}