Skip to content

Commit

Permalink
Add seq_wasm_sdk_macros crate
Browse files Browse the repository at this point in the history
* Update blobstream and vector public functions to using public macro from sdk_macros
  • Loading branch information
manojkgorle committed Jul 23, 2024
1 parent d4fc6fb commit 1d8c8ff
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 91 deletions.
30 changes: 20 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@ members = [
"vector-contracts-rust",
"input-types-test",
"sdk",
"sdk-macros",
]
resolver = "2"
2 changes: 1 addition & 1 deletion blobstream-contracts-rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ author = "manojkgorle"
alloy-sol-types = "0.6.3"
sha2 = { version = "0.10", default-features = false }
seq_wasm_sdk = { path = "../sdk" }

seq_wasm_sdk_macros = { path = "../sdk-macros" }
[profile.release]
opt-level = "z"
lto = true
Expand Down
48 changes: 16 additions & 32 deletions blobstream-contracts-rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use input_type::{
pub use seq_wasm_sdk::allocator::*;
use seq_wasm_sdk::{precompiles, state, utils::TxContext};
use seq_wasm_sdk::{slice, sol, Bytes, FixedBytes, FromHex, SolType, SolValue, U256};
use seq_wasm_sdk_macros::public;

// get state variables enum from program vm.
const STATIC_ISINITIALIZED: u32 = 0;
Expand All @@ -30,19 +31,16 @@ const MAPPING_STATE_DATA_COMMITMENTS_ID: u32 = 2;
// CONSTANT VARIABLES
const DATA_COMMITMENT_MAX: u64 = 1_000;

#[public]
/// This function initializes the contract with the initial state variables.
/// This function can only be called once.
/// Called during the contract deployment.
#[cfg_attr(all(target_arch = "wasm32"), export_name = "initializer")]
#[no_mangle]
pub extern "C" fn initializer(tx_context: *const TxContext, ptr: *const u8, len: u32) -> bool {
/// Can only be called once, mostly during the contract deployment.
pub fn initializer() {
if is_initialized() {
// contract already initialized
return false;
}

// Decode msg_sender from tx_context and inputs from IntializerInput.
let msg_sender = TxContext::unpack(tx_context).msg_sender();
let (height, header, blobstream_program_vkey_hash, blobstream_program_vkey) =
InitializerInput::new(ptr, len).unpack();

Expand All @@ -62,12 +60,10 @@ pub extern "C" fn initializer(tx_context: *const TxContext, ptr: *const u8, len:
true
}

#[public]
/// Only the guardian can set the contract to a frozen state.
#[cfg_attr(all(target_arch = "wasm32"), export_name = "update_freeze")]
#[no_mangle]
pub extern "C" fn update_freeze(tx_context: *const TxContext, ptr: *const u8, len: u32) -> bool {
pub fn update_freeze() {
// Decode msg_sender from tx_context and inputs from UpdateFreezeInput.
let msg_sender = TxContext::unpack(tx_context).msg_sender();
let freeze = UpdateFreezeInput::new(ptr, len).freeze;

// Fetch the guardian address from the state and check if the msg_sender is the guardian.
Expand All @@ -84,16 +80,11 @@ pub extern "C" fn update_freeze(tx_context: *const TxContext, ptr: *const u8, le
true
}

#[public]
/// Only the gaurdian can update the genesis state of the contract.
#[cfg_attr(all(target_arch = "wasm32"), export_name = "update_genesis_state")]
#[no_mangle]
pub extern "C" fn update_genesis_state(
tx_context: *const TxContext,
ptr: *const u8,
len: u32,
) -> bool {
pub fn update_genesis_state() {
// Decode msg_sender from tx_context and inputs from UpdateGenesisStateInput.
let msg_sender = TxContext::unpack(tx_context).msg_sender();

let (height, header) = UpdateGenesisStateInput::new(ptr, len).unpack();

// Fetch the guardian address from the state and check if the msg_sender is the guardian.
Expand All @@ -111,16 +102,11 @@ pub extern "C" fn update_genesis_state(
true
}

#[public]
/// Only the guardian can update the program vkey.
#[cfg_attr(all(target_arch = "wasm32"), export_name = "update_program_vkey")]
#[no_mangle]
pub extern "C" fn update_program_vkey(
tx_context: *const TxContext,
ptr: *const u8,
len: u32,
) -> bool {
pub fn update_program_vkey() {
// Decode msg_sender from tx_context and inputs from UpdateProgramVkeyInput.
let msg_sender = TxContext::unpack(tx_context).msg_sender();

let (program_vkey_hash, program_vkey) = UpdateProgramVkeyInput::new(ptr, len).unpack();

// Fetch the guardian address from the state and check if the msg_sender is the guardian.
Expand All @@ -138,10 +124,9 @@ pub extern "C" fn update_program_vkey(
true
}

#[public]
/// Commits the new header at targetBlock and the data commitment for the block range [latestBlock, targetBlock).
#[cfg_attr(all(target_arch = "wasm32"), export_name = "commit_header_range")]
#[no_mangle]
pub extern "C" fn commit_header_range(_: *const TxContext, ptr: *const u8, len: u32) -> bool {
pub fn commit_header_range() {
// unpack proof and public values from CommitHeaderRangeInput.
let (proof, public_values) = CommitHeaderRangeInput::new(ptr, len).unpack();

Expand Down Expand Up @@ -212,12 +197,11 @@ pub extern "C" fn commit_header_range(_: *const TxContext, ptr: *const u8, len:
}
}

#[public]
/// Verify the attestation for the given proof nonce, tuple, and proof. This is taken from
/// the existing Blobstream contract and is used to verify the data hash for a specific block
/// against a posted data commitment.
#[cfg_attr(all(target_arch = "wasm32"), export_name = "verify_attestation")]
#[no_mangle]
pub extern "C" fn verify_attestation(_: *const TxContext, ptr: *const u8, len: u32) -> bool {
pub fn verify_attestation() {
// Decode the inputs from the VAInput struct.
let (proof_nonce, tuple, proof) = VAInput::new(ptr, len).unpack();

Expand Down
2 changes: 1 addition & 1 deletion input-types-test/blobstream_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestBlobStream(t *testing.T) {

ctxWasm := context.Background()
mapper := map[string][]byte{
"0": {0},
"1": {20},
}

vkey, err := os.ReadFile("../vk.bin")
Expand Down
2 changes: 1 addition & 1 deletion input-types-test/state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func TestState(t *testing.T) {

txContextPtr := address_ptr + 33
mod.Memory().Write(uint32(txContextPtr), txContextBytes)
// @todo memory allocator is fuckinn with us. It is allocating memory over a address that has been previously allocated by itself.

results, err = test_tx_context.Call(ctxWasm, uint64(txContextPtr))
require.NoError(t, err)
require.Equal(t, uint64(1), results[0])
Expand Down
11 changes: 11 additions & 0 deletions sdk-macros/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "seq_wasm_sdk_macros"
version = "0.0.1"
edition = "2021"

[lib]
crate-type = ["proc-macro"]

[dependencies]
quote = "1.0.36"
syn = { version = "2.0.72", features = ["full"] }
1 change: 1 addition & 0 deletions sdk-macros/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# SEQ-WASM-SDK-MACROS
51 changes: 51 additions & 0 deletions sdk-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Attribute, Error, ItemFn, ReturnType, Visibility};

/// This macro is used to define a public function that can be called from the seq wasm runtime.
/// The function must be declared as `pub fn function_name() {}` without any additional modifiers (unsafe, extern, const, async, etc.).
/// It will be exported with the same name as the function name.
/// with the signature `pub extern "C" fn function_name(tx_context: *const TxContext, ptr: *const u8, len: u32) -> bool`.
/// The function should return a boolean value indicating whether the function executed successfully.
/// it will unpack msg_sender and block_time_stamp from the TxContext; these values can be used in the function body.
#[proc_macro_attribute]
pub fn public(_metadata: TokenStream, item: TokenStream) -> TokenStream {
let input_fn = parse_macro_input!(item as ItemFn);

// Check if function declared is public, has no inputs, no return type, and no additional modifiers
let is_valid = matches!(input_fn.vis, Visibility::Public(_))
&& input_fn.sig.inputs.is_empty()
&& matches!(input_fn.sig.output, ReturnType::Default)
&& input_fn.sig.unsafety.is_none()
&& input_fn.sig.abi.is_none()
&& input_fn.sig.constness.is_none()
&& input_fn.sig.asyncness.is_none();

if !is_valid {
// If the function doesn't meet the criteria, return an error
let error_message = "Function must be declared as `pub fn function_name() {}` without any additional modifiers (unsafe, extern, const, async, etc.)";
return Error::new_spanned(input_fn.sig, error_message)
.to_compile_error()
.into();
}

let function_name = input_fn.sig.ident;
let function_body = input_fn.block;
let doc_attrs: Vec<&Attribute> = input_fn
.attrs
.iter()
.filter(|attr| attr.path().is_ident("doc"))
.collect();
TokenStream::from(quote! {
#(#doc_attrs)*
#[cfg_attr(all(target_arch = "wasm32"), export_name = stringify!(#function_name))]
#[no_mangle]
pub extern "C" fn #function_name(tx_context: *const TxContext, ptr: *const u8, len: u32) -> bool {
let tx_ctx = TxContext::unpack(tx_context);
let msg_sender = tx_ctx.msg_sender();
let block_time_stamp = tx_ctx.time_stamp();
#function_body
}
})
}
1 change: 1 addition & 0 deletions vector-contracts-rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ author = "manojkgorle"

[dependencies]
seq_wasm_sdk = { path = "../sdk" }
seq_wasm_sdk_macros = { path = "../sdk-macros" }
alloy-sol-types = "0.6.3"

[profile.release]
Expand Down
Loading

0 comments on commit 1d8c8ff

Please sign in to comment.