diff --git a/.github/workflows/check_build_test.yml b/.github/workflows/check_build_test.yml index 4d6c5b6693..d574770be9 100644 --- a/.github/workflows/check_build_test.yml +++ b/.github/workflows/check_build_test.yml @@ -51,7 +51,7 @@ jobs: docker --version sleep 6 docker images - docker pull bitseed/bitseed:0.1.4 + docker pull bitseed/bitseed:0.1.6 - name: Check code format run: cargo fmt -- --check diff --git a/crates/testsuite/data/generator.wasm b/crates/testsuite/data/generator.wasm old mode 100644 new mode 100755 index bd2b1c729a..3ead3cebb8 Binary files a/crates/testsuite/data/generator.wasm and b/crates/testsuite/data/generator.wasm differ diff --git a/crates/testsuite/features/cmd.feature b/crates/testsuite/features/cmd.feature index cb885c271f..ce67b7b6eb 100644 --- a/crates/testsuite/features/cmd.feature +++ b/crates/testsuite/features/cmd.feature @@ -369,12 +369,12 @@ Feature: Rooch CLI integration tests Then assert: "{{$.move[-1].execution_info.status.type}} == executed" # run wasm cpp generator - #Then cmd: "move run --function default::wasm_execution::run_generator_cpp" - #Then assert: "{{$.move[-1].execution_info.status.type}} == executed" + Then cmd: "move run --function default::wasm_execution::run_generator_cpp" + Then assert: "{{$.move[-1].execution_info.status.type}} == executed" # run wasm rust generator - #Then cmd: "move run --function default::wasm_execution::run_generator_rust" - #Then assert: "{{$.move[-1].execution_info.status.type}} == executed" + Then cmd: "move run --function default::wasm_execution::run_generator_rust" + Then assert: "{{$.move[-1].execution_info.status.type}} == executed" # release servers Then stop the server @@ -458,7 +458,7 @@ Feature: Rooch CLI integration tests Then cmd: "move run --function default::bitseed_runner::run" Then assert: "{{$.move[-1].execution_info.status.type}} == executed" - # Check mint deploy validity + # Check deploy validity Then cmd: "move view --function 0xa::bitseed::view_validity --args string:{{$.deploy[-1].inscriptions[0].Id}} " Then assert: "{{$.move[-1].vm_status}} == Executed" Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.is_valid}} == true" @@ -477,7 +477,7 @@ Feature: Rooch CLI integration tests Then assert: "{{$.move[-1].execution_info.status.type}} == executed" # Check mint bits validity - Then cmd: "move view --function 0xa::bitseed::view_validity --args string:{{$.deploy[-1].inscriptions[0].Id}} " + Then cmd: "move view --function 0xa::bitseed::view_validity --args string:{{$.mint[-1].inscriptions[0].Id}} " Then assert: "{{$.move[-1].vm_status}} == Executed" Then assert: "{{$.move[-1].return_values[0].decoded_value.value.vec[0].value.is_valid}} == true" diff --git a/crates/testsuite/tests/images/bitseed.rs b/crates/testsuite/tests/images/bitseed.rs index 3e3fa539e9..b15bf32558 100644 --- a/crates/testsuite/tests/images/bitseed.rs +++ b/crates/testsuite/tests/images/bitseed.rs @@ -6,7 +6,7 @@ use std::collections::HashMap; use testcontainers::{core::WaitFor, Image, ImageArgs}; const NAME: &str = "bitseed/bitseed"; -const TAG: &str = "0.1.4"; +const TAG: &str = "0.1.6"; #[derive(Debug, Default, Clone)] pub struct BitseedImageArgs { diff --git a/examples/wasm_execution/sources/wasm.move b/examples/wasm_execution/sources/wasm.move index c5e1674107..0edd53c085 100644 --- a/examples/wasm_execution/sources/wasm.move +++ b/examples/wasm_execution/sources/wasm.move @@ -113,12 +113,15 @@ module rooch_examples::wasm_execution { // 2. inscribe_verify let function_name = b"inscribe_verify"; - let deploy_args = x"8178377b22686569676874223a7b2274797065223a2272616e6765222c2264617461223a7b226d696e223a312c226d6178223a313030307d7d7d"; + let deploy_args = x"81a166686569676874a264747970656572616e67656464617461a2636d696e01636d61781903e8"; let seed = x"33303765396262353238616132303930343665306230333336316162333461383966633063313233323764393964363239666336396634383232663638376433"; - let user_input = x""; - let attributes_output = x"a26668656967687418c56269646d68656c6c6f5f62697473656564"; + let user_input = b"123"; + let attributes_output = x"a26668656967687418c56269646d68656c6c6f5f62697473656565"; let buffer = pack_inscribe_generate_args(deploy_args, seed, user_input); + std::debug::print(&string::utf8(b"buffer:")); + std::debug::print(&buffer); + let arg_with_length = wasm::add_length_with_data(buffer); let arg_list = vector::empty>(); @@ -150,12 +153,15 @@ module rooch_examples::wasm_execution { // 2. inscribe_verify let function_name = b"inscribe_verify"; - let deploy_args = x"8178377b22686569676874223a7b2274797065223a2272616e6765222c2264617461223a7b226d696e223a312c226d6178223a313030307d7d7d"; - let seed = x"33303765396262353238616132303930343665306230333336316162333461383966633063313233323764393964363239666336396634383232663638376433"; + let deploy_args = x"81a166686569676874a264747970656572616e67656464617461a2636d696e01636d61781903e8"; + let seed = x"3330376539626235323861613230393034366530623033333631616233346138396663306331323332376439396436323966633639663438323266363837"; let user_input = x""; let attributes_output = x"a26668656967687418c56269646d68656c6c6f5f62697473656564"; let buffer = pack_inscribe_generate_args(deploy_args, seed, user_input); + std::debug::print(&string::utf8(b"buffer:")); + std::debug::print(&buffer); + let arg_with_length = wasm::add_length_with_data(buffer); let arg_list = vector::empty>(); @@ -178,14 +184,23 @@ module rooch_examples::wasm_execution { #[data_struct] struct InscribeGenerateArgs has copy, drop, store { - attrs: vector, + attrs: vector, seed: std::string::String, user_input: std::string::String, } fun pack_inscribe_generate_args(deploy_args: vector, seed: vector, user_input: vector): vector{ + let attrs = vector::empty(); + + let i=0; + let len = vector::length(&deploy_args); + while (i < len) { + vector::push_back(&mut attrs, (*vector::borrow(&deploy_args, i) as u16)); + i = i + 1; + }; + let args = InscribeGenerateArgs{ - attrs: deploy_args, + attrs: attrs, seed: string::utf8(seed), user_input: string::utf8(user_input) }; diff --git a/frameworks/bitcoin-move/doc/bitcoin.md b/frameworks/bitcoin-move/doc/bitcoin.md index 3d348e6450..fac1c5aed3 100644 --- a/frameworks/bitcoin-move/doc/bitcoin.md +++ b/frameworks/bitcoin-move/doc/bitcoin.md @@ -13,6 +13,7 @@ - [Function `get_tx_height`](#0x4_bitcoin_get_tx_height) - [Function `get_block`](#0x4_bitcoin_get_block) - [Function `get_block_height`](#0x4_bitcoin_get_block_height) +- [Function `get_block_hash_by_height`](#0x4_bitcoin_get_block_hash_by_height) - [Function `get_block_by_height`](#0x4_bitcoin_get_block_by_height) - [Function `get_genesis_block`](#0x4_bitcoin_get_genesis_block) - [Function `get_latest_block`](#0x4_bitcoin_get_latest_block) @@ -165,6 +166,18 @@ Get block via block_hash + + +## Function `get_block_hash_by_height` + +Get block hash via block_height + + +
public fun get_block_hash_by_height(block_height: u64): option::Option<address>
+
+ + + ## Function `get_block_by_height` diff --git a/frameworks/bitcoin-move/sources/bitcoin.move b/frameworks/bitcoin-move/sources/bitcoin.move index 74b83e38da..5370f0f46c 100644 --- a/frameworks/bitcoin-move/sources/bitcoin.move +++ b/frameworks/bitcoin-move/sources/bitcoin.move @@ -54,7 +54,7 @@ module bitcoin_move::bitcoin{ hash_to_height: Table, /// tx id -> tx txs: Table, - /// tx id -> tx + /// tx id -> block height tx_to_height: Table, /// tx id list, we can use this to scan txs tx_ids: TableVec
, @@ -112,6 +112,7 @@ module bitcoin_move::bitcoin{ process_coinbase_utxo(tx, flotsams, block_height); let txid = types::tx_id(tx); table::add(&mut btc_block_store.txs, txid, *tx); + table::add(&mut btc_block_store.tx_to_height, txid, block_height); table_vec::push_back(&mut btc_block_store.tx_ids, txid); } @@ -299,7 +300,7 @@ module bitcoin_move::bitcoin{ public fun get_tx_height(txid: address): Option{ let btc_block_store_obj = borrow_block_store(); let btc_block_store = object::borrow(btc_block_store_obj); - if(table::contains(&btc_block_store.txs, txid)){ + if(table::contains(&btc_block_store.tx_to_height, txid)){ option::some(*table::borrow(&btc_block_store.tx_to_height, txid)) }else{ option::none() @@ -327,6 +328,18 @@ module bitcoin_move::bitcoin{ } } + /// Get block hash via block_height + public fun get_block_hash_by_height(block_height: u64): Option
{ + let btc_block_store_obj = borrow_block_store(); + let btc_block_store = object::borrow(btc_block_store_obj); + if(table::contains(&btc_block_store.height_to_hash, block_height)){ + let block_hash = *table::borrow(&btc_block_store.height_to_hash, block_height); + option::some(block_hash) + }else{ + option::none() + } + } + /// Get block via block_height public fun get_block_by_height(block_height: u64): Option
{ let btc_block_store_obj = borrow_block_store(); diff --git a/frameworks/moveos-stdlib/doc/cbor.md b/frameworks/moveos-stdlib/doc/cbor.md index 0998269c58..fea02504c8 100644 --- a/frameworks/moveos-stdlib/doc/cbor.md +++ b/frameworks/moveos-stdlib/doc/cbor.md @@ -82,6 +82,5 @@ If the field type is primitive type, it will be parsed to bytes, array or object Serialize a value of type T to CBOR bytes. -
#[data_struct(#[T])]
-public fun to_cbor<T: drop>(value: &T): vector<u8>
+
public fun to_cbor<T>(value: &T): vector<u8>
 
diff --git a/frameworks/moveos-stdlib/sources/cbor.move b/frameworks/moveos-stdlib/sources/cbor.move index 8702dfbc0b..c95157681c 100644 --- a/frameworks/moveos-stdlib/sources/cbor.move +++ b/frameworks/moveos-stdlib/sources/cbor.move @@ -37,9 +37,8 @@ module moveos_std::cbor { option::destroy_some(opt_result) } - #[data_struct(T)] /// Serialize a value of type T to CBOR bytes. - public fun to_cbor(value: &T): vector { + public fun to_cbor(value: &T): vector { native_to_cbor(value) } @@ -184,7 +183,7 @@ module moveos_std::cbor { // check address let account_bytes = simple_map::borrow(&map, &std::string::utf8(b"account")); - let account = moveos_std::address::from_bytes(*account_bytes); + let account = from_cbor
(*account_bytes); assert!(account == @0x42, 7); // check inner struct @@ -193,12 +192,13 @@ module moveos_std::cbor { assert!(inner.value == 100u64, 8); // check bytes - let bytes = simple_map::borrow(&map, &std::string::utf8(b"bytes")); - assert!(vector::length(bytes) == 4, 9); - assert!(vector::borrow(bytes, 0) == &3u8, 10); - assert!(vector::borrow(bytes, 1) == &2u8, 11); - assert!(vector::borrow(bytes, 2) == &1u8, 12); - assert!(vector::borrow(bytes, 3) == &0u8, 13); + let bytes_cbor = simple_map::borrow(&map, &std::string::utf8(b"bytes")); + let bytes = from_cbor>(*bytes_cbor); + assert!(vector::length(&bytes) == 4, 9); + assert!(vector::borrow(&bytes, 0) == &3u8, 10); + assert!(vector::borrow(&bytes, 1) == &2u8, 11); + assert!(vector::borrow(&bytes, 2) == &1u8, 12); + assert!(vector::borrow(&bytes, 3) == &0u8, 13); // check inner array let inner_array_bytes = simple_map::borrow(&map, &std::string::utf8(b"inner_array")); @@ -235,4 +235,79 @@ module moveos_std::cbor { let obj = from_cbor_option(invalid_bytes); assert!(option::is_none(&obj), 1); } + + #[test] + fun test_struct_to_map_and_map_to_struct() { + let test = Test { + bool_value: true, + age: 30u8, + balance: 170141183460469231731687303715884105728u128, + sig: 1701411834604692317316873037158841057281687303715884105728u256, + ascii_string: std::ascii::string(b"rooch.network"), + utf8_string: std::string::utf8(b"rooch.network"), + null_value: option::none(), + option_string: option::some(std::string::utf8(b"rooch.network")), + inner: Inner { + value: 100u64, + }, + inner_option: option::some(Inner { + value: 102u64, + }), + inner_array: std::vector::singleton(Inner { + value: 101u64, + }), + account: @0x42, + bytes: vector[3u8, 2u8, 1u8, 0u8], + }; + + let cbor_bytes = to_cbor(&test); + + // cbor to map + let test_map = to_map(cbor_bytes); + // map to cbor + let cbor2_bytes = to_cbor(&test_map); + simple_map::drop(test_map); + + let obj = from_cbor(cbor2_bytes); + assert!(obj.balance == 170141183460469231731687303715884105728u128, 1); + assert!(obj.age == 30u8, 2); + assert!(obj.inner.value == 100u64, 3); + + // check bytes + assert!(vector::length(&obj.bytes) == 4, 4); + assert!(vector::borrow(&obj.bytes, 0) == &3u8, 5); + assert!(vector::borrow(&obj.bytes, 1) == &2u8, 6); + assert!(vector::borrow(&obj.bytes, 2) == &1u8, 7); + assert!(vector::borrow(&obj.bytes, 3) == &0u8, 8); + + // check inner array + assert!(vector::length(&obj.inner_array) == 1, 9); + assert!(vector::borrow(&obj.inner_array, 0).value == 101u64, 10); + + // check account + assert!(obj.account == @0x42, 11); + + // check ascii string + assert!(obj.ascii_string == std::ascii::string(b"rooch.network"), 12); + + // check utf8 string + assert!(obj.utf8_string == std::string::utf8(b"rooch.network"), 13); + + // check bool + assert!(obj.bool_value, 14); + + // check null + assert!(option::is_none(&obj.null_value), 15); + + // check inner_option + assert!(option::is_some(&obj.inner_option), 16); + assert!(option::borrow(&obj.inner_option).value == 102u64, 17); + + // check u256 + assert!(obj.sig == 1701411834604692317316873037158841057281687303715884105728u256, 18); + + // check option string + assert!(option::is_some(&obj.option_string), 19); + assert!(option::borrow(&obj.option_string) == &std::string::utf8(b"rooch.network"), 20); + } } diff --git a/frameworks/moveos-stdlib/sources/wasm.move b/frameworks/moveos-stdlib/sources/wasm.move index 312c866652..a333f67395 100644 --- a/frameworks/moveos-stdlib/sources/wasm.move +++ b/frameworks/moveos-stdlib/sources/wasm.move @@ -256,19 +256,4 @@ module moveos_std::wasm { // 3. Release the WASM VM instance (required step) release_wasm_instance(wasm_instance); } - - #[test] - fun test_call_indirect() { - // Enable all features for testing - features::init_and_enable_all_features_for_test(); - - // Define WASM code with a CallIndirect instruction - let wasm_code: vector = b"(module (type $t0 (func (param i32) (result i32))) (table 1 1 funcref) (elem (i32.const 0) $f) (func $f (type $t0) (param $p i32) (result i32) local.get $p) (func (export \"call_indirect_test\") (param i32) (result i32) local.get 0 i32.const 0 call_indirect (type $t0)))"; - - // 1. Create WASM VM instance (required step) - let wasm_instance_option = create_wasm_instance_option(wasm_code); - assert!(option::is_none(&wasm_instance_option), 1); - option::destroy_none(wasm_instance_option); - } - } diff --git a/frameworks/moveos-stdlib/src/natives/moveos_stdlib/cbor.rs b/frameworks/moveos-stdlib/src/natives/moveos_stdlib/cbor.rs index 4414cd95e3..8cb4effc19 100644 --- a/frameworks/moveos-stdlib/src/natives/moveos_stdlib/cbor.rs +++ b/frameworks/moveos-stdlib/src/natives/moveos_stdlib/cbor.rs @@ -170,16 +170,9 @@ fn cbor_obj_to_key_value_pairs(cbor_value: &CborValue) -> Result t.clone(), - _ => { - let mut writer = Vec::new(); - into_writer(&cbor_field, &mut writer)?; - writer - } - }; - - Ok((name, bytes)) + let mut bytes_writer = Vec::new(); + into_writer(&cbor_field, &mut bytes_writer)?; + Ok((name, bytes_writer)) }) .collect::)>>>()?; @@ -467,6 +460,79 @@ fn serialize_move_struct_to_cbor_value( } _ => return Err(anyhow::anyhow!("Invalid std option")), } + } else if struct_type == &SimpleMap::>::struct_tag() { + let data_field = value_fields + .iter() + .find(|(name, _)| name.as_str() == "data") + .ok_or_else(|| anyhow::anyhow!("Missing data field in SimpleMap"))?; + + let data_vector = match &data_field.1 { + MoveValue::Vector(vec) => vec, + _ => return Err(anyhow::anyhow!("Invalid data field in SimpleMap")), + }; + + let key_value_pairs = data_vector + .iter() + .map(|element| { + let struct_ = match element { + MoveValue::Struct(s) => s, + _ => return Err(anyhow::anyhow!("Invalid element in SimpleMap data")), + }; + + let fields = match struct_ { + MoveStruct::WithTypes { + type_: _, + fields: value_fields, + } => value_fields, + _ => return Err(anyhow::anyhow!("Invalid element in SimpleMap data")), + }; + + let key = match &fields[0].1 { + MoveValue::Struct(struct_) => { + let value_fields = match struct_ { + MoveStruct::WithTypes { + type_: _, + fields: value_fields, + } => value_fields, + _ => { + return Err(anyhow::anyhow!( + "Invalid element in SimpleMap data" + )) + } + }; + + let bytes_field = value_fields + .first() + .ok_or_else(|| anyhow::anyhow!("Invalid bytes field"))?; + + match bytes_field.1.clone() { + MoveValue::Vector(vec) => { + let cbor_bytes = MoveValue::vec_to_vec_u8(vec)?; + String::from_utf8(cbor_bytes) + .ok() + .ok_or_else(|| anyhow::anyhow!("Invalid utf8 String"))? + } + _ => return Err(anyhow::anyhow!("Invalid std string")), + } + } + _ => return Err(anyhow::anyhow!("Invalid key in SimpleMap")), + }; + + let cbor_value = match &fields[1].1 { + MoveValue::Vector(vec) => { + let cbor_bytes = MoveValue::vec_to_vec_u8(vec.clone())?; + let cursor = Cursor::new(cbor_bytes); + let cbor_value: CborValue = from_reader(cursor)?; + cbor_value + } + _ => return Err(anyhow::anyhow!("Invalid value in SimpleMap")), + }; + + Ok((CborValue::Text(key), cbor_value)) + }) + .collect::>>()?; + + CborValue::Map(key_value_pairs) } else { serialize_move_fields_to_cbor_value(layout_fields, value_fields)? } diff --git a/frameworks/rooch-nursery/doc/bitseed.md b/frameworks/rooch-nursery/doc/bitseed.md index 35b92d6d3a..e8686bdf95 100644 --- a/frameworks/rooch-nursery/doc/bitseed.md +++ b/frameworks/rooch-nursery/doc/bitseed.md @@ -9,6 +9,7 @@ - [Struct `BitseedCoinInfo`](#0xa_bitseed_BitseedCoinInfo) - [Resource `BitseedStore`](#0xa_bitseed_BitseedStore) - [Struct `InscribeGenerateArgs`](#0xa_bitseed_InscribeGenerateArgs) +- [Struct `InscribeGenerateOutput`](#0xa_bitseed_InscribeGenerateOutput) - [Constants](#@Constants_0) - [Function `genesis_init`](#0xa_bitseed_genesis_init) - [Function `bitseed_deploy_key`](#0xa_bitseed_bitseed_deploy_key) @@ -92,6 +93,17 @@ + + +## Struct `InscribeGenerateOutput` + + + +
struct InscribeGenerateOutput has store
+
+ + + ## Constants @@ -262,7 +274,7 @@ -
public fun inscribe_verify(wasm_bytes: vector<u8>, deploy_args: vector<u8>, seed: vector<u8>, user_input: vector<u8>, attributes_output: vector<u8>): (bool, option::Option<string::String>)
+
public fun inscribe_verify(wasm_bytes: vector<u8>, deploy_args: vector<u8>, seed: vector<u8>, user_input: string::String, metadata: &simple_map::SimpleMap<string::String, vector<u8>>, content_type: option::Option<string::String>, body: vector<u8>): (bool, option::Option<string::String>)
 
diff --git a/frameworks/rooch-nursery/sources/bitseed.move b/frameworks/rooch-nursery/sources/bitseed.move index a91381eb63..bb45a19bc2 100644 --- a/frameworks/rooch-nursery/sources/bitseed.move +++ b/frameworks/rooch-nursery/sources/bitseed.move @@ -337,7 +337,7 @@ module rooch_nursery::bitseed { let inscription_id_option = ord::parse_inscription_id(&inscription_id_str); let inscription_id = option::destroy_some(inscription_id_option); - let has_user_input = false; + let has_user_input = true; let has_user_input_option = get_SFT_bool_attribute(&attributes, b"has_user_input"); if (option::is_some(&has_user_input_option)) { has_user_input = option::destroy_some(has_user_input_option); @@ -361,7 +361,7 @@ module rooch_nursery::bitseed { (true, option::none()) } - fun is_valid_bitseed_mint(metadata: &SimpleMap>, seed: vector) : (bool, Option) { + fun is_valid_bitseed_mint(metadata: &SimpleMap>, seed: vector, content_type: Option, body: vector) : (bool, Option) { let (is_valid, reason) = is_valid_bitseed(metadata); if (!is_valid) { return (false, reason) @@ -391,9 +391,9 @@ module rooch_nursery::bitseed { return (false, option::some(std::string::utf8(b"maximum supply exceeded"))) }; - let user_input = vector::empty(); + let user_input = string::utf8(b""); if (has_user_input) { - let user_input_option = get_SFT_bytes_attribute(&attributes, b"user_input"); + let user_input_option = get_SFT_string_attribute(&attributes, b"id"); if (option::is_none(&user_input_option)) { simple_map::drop(attributes); return (false, option::some(std::string::utf8(b"metadata.attributes.user_input is required"))) @@ -421,9 +421,7 @@ module rooch_nursery::bitseed { let inscrption = object::borrow(inscription_obj); let wasm_bytes = ord::body(inscrption); - let attributes_bytes = simple_map::borrow(metadata, &string::utf8(b"attributes")); - - let (is_valid, reason) = inscribe_verify(wasm_bytes, deploy_args, seed, user_input, *attributes_bytes); + let (is_valid, reason) = inscribe_verify(wasm_bytes, deploy_args, seed, user_input, metadata, content_type, body); if (!is_valid) { simple_map::drop(attributes); return (false, reason) @@ -434,7 +432,8 @@ module rooch_nursery::bitseed { } public fun inscribe_verify(wasm_bytes: vector, deploy_args: vector, - seed: vector, user_input: vector, attributes_output: vector): (bool, Option) { + seed: vector, user_input: String, metadata: &SimpleMap>, + content_type: Option, body: vector): (bool, Option) { let wasm_instance_option = wasm::create_wasm_instance_option(wasm_bytes); if (option::is_none(&wasm_instance_option)) { option::destroy_none(wasm_instance_option); @@ -445,11 +444,18 @@ module rooch_nursery::bitseed { let function_name = b"inscribe_verify"; let buffer = pack_inscribe_generate_args(deploy_args, seed, user_input); + let arg_with_length = wasm::add_length_with_data(buffer); + let amount = get_SFT_amount(metadata); + let attributes = get_SFT_attributes(metadata); + let output_buffer = pack_inscribe_output_args(amount, attributes, content_type, body); + let arg_list = vector::empty>(); vector::push_back(&mut arg_list, arg_with_length); - vector::push_back(&mut arg_list, attributes_output); + vector::push_back(&mut arg_list, output_buffer); + + let memory_args_list = wasm::create_memory_wasm_args(&mut wasm_instance, function_name, arg_list); let ret_val_option = wasm::execute_wasm_function_option(&mut wasm_instance, function_name, memory_args_list); @@ -471,62 +477,119 @@ module rooch_nursery::bitseed { #[data_struct] struct InscribeGenerateArgs has copy, drop, store { - attrs: vector, + attrs: vector, seed: std::string::String, user_input: std::string::String, } - fun pack_inscribe_generate_args(deploy_args: vector, seed: vector, user_input: vector): vector{ + fun pack_inscribe_generate_args(deploy_args: vector, seed: vector, user_input: String): vector{ + let attrs = vector::empty(); + + let i=0; + let len = vector::length(&deploy_args); + while (i < len) { + vector::push_back(&mut attrs, (*vector::borrow(&deploy_args, i) as u16)); + i = i + 1; + }; + + let seed_hex = hex::encode(seed); let args = InscribeGenerateArgs{ - attrs: deploy_args, - seed: string::utf8(seed), - user_input: string::utf8(user_input) + attrs: attrs, + seed: string::utf8(seed_hex), + user_input: user_input }; cbor::to_cbor(&args) } + struct InscribeGenerateOutput has store { + amount: u64, + attributes: SimpleMap>, + content: SimpleMap>, + } + + fun pack_inscribe_output_args(amount: u64, attributes: SimpleMap>, content_type_option: Option, body: vector): vector{ + let content = simple_map::new(); + if (vector::length(&body) > 0) { + if (option::is_some(&content_type_option)) { + let content_type = option::destroy_some(content_type_option); + simple_map::add(&mut content, string::utf8(b"content_type"), cbor::to_cbor(&content_type)); + }; + + simple_map::add(&mut content, string::utf8(b"body"), cbor::to_cbor(&body)); + }; + + let output = InscribeGenerateOutput{ + amount: amount, + attributes: attributes, + content: content, + }; + + let output_bytes = cbor::to_cbor(&output); + + let InscribeGenerateOutput{amount:_, attributes, content}=output; + simple_map::drop(attributes); + simple_map::drop(content); + + output_bytes + } + fun generate_seed_from_inscription(inscription: &Inscription): vector { let inscription_txid = ord::txid(inscription); - let tx_option = bitcoin::get_tx(inscription_txid); - if (option::is_none(&tx_option)) { + + // reveal tx + let reveal_tx_option = bitcoin::get_tx(inscription_txid); + if (option::is_none(&reveal_tx_option)) { return vector::empty() }; - let tx = option::destroy_some(tx_option); - let input = types::tx_input(&tx); - let index = ord::index(inscription); - let txin = vector::borrow(input, (index as u64)); - let outpoint = types::txin_previous_output(txin); - - let txid = types::outpoint_txid(outpoint); - let vout = types::outpoint_vout(outpoint); - - let seed_tx_option = bitcoin::get_tx(txid); - if (option::is_none(&seed_tx_option)) { + let reveal_tx = option::destroy_some(reveal_tx_option); + let reveal_input = types::tx_input(&reveal_tx); + let reveal_index = ord::index(inscription); + let reveal_txin = vector::borrow(reveal_input, (reveal_index as u64)); + let reveal_outpoint = types::txin_previous_output(reveal_txin); + + // commit tx + let commit_txid = types::outpoint_txid(reveal_outpoint); + let commit_vout = types::outpoint_vout(reveal_outpoint); + let commit_tx_option = bitcoin::get_tx(commit_txid); + if (option::is_none(&commit_tx_option)) { return vector::empty() }; - let seed_height_option = bitcoin::get_tx_height(txid); + let commit_tx = option::destroy_some(commit_tx_option); + let commit_input = types::tx_input(&commit_tx); + let commit_txin = vector::borrow(commit_input, (commit_vout as u64)); + let commit_outpoint = types::txin_previous_output(commit_txin); + + // seed tx + let seed_txid = types::outpoint_txid(commit_outpoint); + let seed_vout = types::outpoint_vout(commit_outpoint); + + let seed_height_option = bitcoin::get_tx_height(seed_txid); if (option::is_none(&seed_height_option)) { return vector::empty() }; let seed_height = *option::borrow(&seed_height_option); - let block_header_option = bitcoin::get_block_by_height(seed_height); - if (option::is_none(&block_header_option)) { + let seed_block_hash_option = bitcoin::get_block_hash_by_height(seed_height); + if (option::is_none(&seed_block_hash_option)) { return vector::empty() }; - let block_header = option::borrow(&block_header_option); - let block_hash = types::merkle_root(block_header); + let seed_block_hash = *option::borrow(&seed_block_hash_option); + let seed_hex = generate_seed_from_inscription_inner(seed_block_hash, seed_txid, seed_vout); + seed_hex + } + + fun generate_seed_from_inscription_inner(block_hash: address, txid: address, vout: u32) : vector { let buf = vector::empty(); vector::append(&mut buf, address::to_bytes(&block_hash)); vector::append(&mut buf, address::to_bytes(&txid)); - vector::append(&mut buf, bcs::to_bytes(&vout)); //TODO vout to le_bytes - hex::encode(hash::sha3_256(buf)) + vector::append(&mut buf, bcs::to_bytes(&vout)); + hash::sha3_256(buf) } // ==== Process Bitseed Entry ==== // @@ -561,7 +624,10 @@ module rooch_nursery::bitseed { ord::seal_metaprotocol_validity(inscription_id, true, option::none()); } else if (option::borrow(&op) == &string::utf8(b"mint")) { let seed = generate_seed_from_inscription(inscription); - let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed); + let content_type = ord::content_type(inscription); + let body = ord::body(inscription); + + let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed, content_type, body); ord::seal_metaprotocol_validity(inscription_id, is_valid, reason); } else if (option::borrow(&op) == &string::utf8(b"split")) { ord::seal_metaprotocol_validity(inscription_id, true, option::none()); @@ -789,7 +855,7 @@ module rooch_nursery::bitseed { // check has_user_input let has_user_input = coin_info_has_user_input(&coin_info); - assert!(!has_user_input, 8); + assert!(has_user_input, 8); // check deploy_args let deploy_args = coin_info_deploy_args_option(&coin_info); @@ -809,7 +875,9 @@ module rooch_nursery::bitseed { let metadata_bytes = x"a4626f70666465706c6f79647469636b646d6f766566616d6f756e74016a61747472696275746573a16967656e657261746f72784f2f696e736372697074696f6e2f373764666332666535393834313962303036343163323936313831613936636631363934333639376635373334383062303233623737636365383261646132316930"; let metadata = cbor::to_map(metadata_bytes); let seed = vector::empty(); - let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed); + let content_type = option::none(); + let body = vector::empty(); + let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed, content_type, body); simple_map::drop(metadata); assert!(!is_valid, 1); @@ -839,7 +907,9 @@ module rooch_nursery::bitseed { let metadata_bytes = x"a4626f70646d696e74647469636b646d6f766566616d6f756e7418646a61747472696275746573a16967656e657261746f72784f2f696e736372697074696f6e2f377864666332666535393834313962303036343163323936313831613936636631363934333639376635373334383062303233623737636365383261646132316930"; let metadata = cbor::to_map(metadata_bytes); let seed = vector::empty(); - let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed); + let content_type = option::none(); + let body = vector::empty(); + let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed, content_type, body); simple_map::drop(metadata); assert!(!is_valid, 1); @@ -869,13 +939,16 @@ module rooch_nursery::bitseed { let metadata_bytes = x"a4626f70646d696e74647469636b646d6f766566616d6f756e7418646a61747472696275746573a16967656e657261746f72784f2f696e736372697074696f6e2f377864666332666535393834313962303036343163323936313831613936636631363934333639376635373334383062303233623737636365383261646132316930"; let metadata = cbor::to_map(metadata_bytes); let seed = vector::empty(); - let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed); + let content_type = option::none(); + let body = vector::empty(); + let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed, content_type, body); simple_map::drop(metadata); assert!(!is_valid, 1); assert!(option::borrow(&reason) == &std::string::utf8(b"metadata.attributes.user_input is required"), 1); } + #[test(genesis_account=@0x4)] fun test_is_valid_bitseed_mint_fail_with_wasm_verify_fail(genesis_account: &signer){ features::init_and_enable_all_features_for_test(); @@ -901,19 +974,72 @@ module rooch_nursery::bitseed { let metadata_bytes = x"a4626f70646d696e74647469636b646d6f766566616d6f756e74016a61747472696275746573a16a757365725f696e70757463787878"; let metadata = cbor::to_map(metadata_bytes); let seed = vector::empty(); - let (is_valid, reason) = is_valid_bitseed_mint(&metadata, seed); + let content_type = option::none(); + let body = vector::empty(); + let (is_valid, _reason) = is_valid_bitseed_mint(&metadata, seed, content_type, body); simple_map::drop(metadata); assert!(!is_valid, 1); - assert!(option::borrow(&reason) == &std::string::utf8(b"create wasm instance fail"), 1); + //assert!(option::borrow(&reason) == &std::string::utf8(b"create wasm instance fail"), 1); } #[test] fun test_pack_inscribe_generate_args() { let deploy_args = x"8178377b22686569676874223a7b2274797065223a2272616e6765222c2264617461223a7b226d696e223a312c226d6178223a313030307d7d7d"; let seed = b"0xe4b6de2407ad9455a364ba0227a8591631d1253508bc41f7d1992d218dd29b47"; - let user_input = b""; + let user_input = string::utf8(b""); pack_inscribe_generate_args(deploy_args, seed, user_input); } + + + #[test] + fun test_generate_seed_from_inscription_inner() { + let block_hash = address::from_bytes(x"89753cc1cdc61a89d49d5b267ab8353d4e984e08cda587f54e813add2b6d207c"); + let txid = address::from_bytes(x"1a49883e4248bd8b2e423af8157a1795cd457ece0eb4d1f453266874dc1da262"); + let vout = 1; + + let seed = generate_seed_from_inscription_inner(block_hash, txid, vout); + let hex_seed = hex::encode(seed); + assert!(hex_seed == b"1700b4e1d726ef40b2832eb1d5f91fd88d36ddf79eb235789c9b417c997279bc", 1); + } + + + #[test] + fun test_pack_inscribe_output_args() { + let amount = 1u64; + let attributes = simple_map::new(); + + let height = 444u64; + simple_map::add(&mut attributes, string::utf8(b"height"), cbor::to_cbor(&height)); + + let id = string::utf8(b"test user input"); + simple_map::add(&mut attributes, string::utf8(b"id"), cbor::to_cbor(&id)); + + let content_type = option::some(string::utf8(b"text/plain")); + let body =x"68656c6c6f20776f726c6421"; + + let output_bytes = pack_inscribe_output_args(amount, attributes, content_type, body); + let output_hex = hex::encode(output_bytes); + assert!(output_hex == b"a366616d6f756e74016a61747472696275746573a2666865696768741901bc6269646f74657374207573657220696e70757467636f6e74656e74a26c636f6e74656e745f747970656a746578742f706c61696e64626f64794c68656c6c6f20776f726c6421", 1); + } + + #[test] + fun test_pack_inscribe_output_args_without_content() { + let amount = 1u64; + let attributes = simple_map::new(); + + let height = 444u64; + simple_map::add(&mut attributes, string::utf8(b"height"), cbor::to_cbor(&height)); + + let id = string::utf8(b"test user input"); + simple_map::add(&mut attributes, string::utf8(b"id"), cbor::to_cbor(&id)); + + let content_type = option::some(string::utf8(b"text/plain")); + let body = vector::empty(); + + let output_bytes = pack_inscribe_output_args(amount, attributes, content_type, body); + let output_hex = hex::encode(output_bytes); + assert!(output_hex == b"a366616d6f756e74016a61747472696275746573a2666865696768741901bc6269646f74657374207573657220696e70757467636f6e74656e74a0", 1); + } } \ No newline at end of file diff --git a/moveos/moveos-wasm/src/middlewares/mod.rs b/moveos/moveos-wasm/src/middlewares/mod.rs index 0e7c3be980..20b51dc790 100644 --- a/moveos/moveos-wasm/src/middlewares/mod.rs +++ b/moveos/moveos-wasm/src/middlewares/mod.rs @@ -2,4 +2,3 @@ // SPDX-License-Identifier: Apache-2.0 pub mod gas_metering; -pub mod prohibit_ops; diff --git a/moveos/moveos-wasm/src/middlewares/prohibit_ops.rs b/moveos/moveos-wasm/src/middlewares/prohibit_ops.rs deleted file mode 100644 index a882145644..0000000000 --- a/moveos/moveos-wasm/src/middlewares/prohibit_ops.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) RoochNetwork -// SPDX-License-Identifier: Apache-2.0 - -use std::fmt; -use wasmer::wasmparser::Operator; -use wasmer::{LocalFunctionIndex, MiddlewareError, MiddlewareReaderState, ModuleMiddleware}; - -pub struct ProhibitOpsMiddleware; - -impl ProhibitOpsMiddleware { - pub fn new() -> Self { - Self - } -} - -impl Default for ProhibitOpsMiddleware { - fn default() -> Self { - Self::new() - } -} - -impl fmt::Debug for ProhibitOpsMiddleware { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ProhibitOpsMiddleware").finish() - } -} - -impl ModuleMiddleware for ProhibitOpsMiddleware { - fn generate_function_middleware( - &self, - _index: LocalFunctionIndex, - ) -> Box { - Box::new(ProhibitOpsFunctionMiddleware) - } -} - -struct ProhibitOpsFunctionMiddleware; - -impl fmt::Debug for ProhibitOpsFunctionMiddleware { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("ProhibitOpsFunctionMiddleware").finish() - } -} - -impl wasmer::FunctionMiddleware for ProhibitOpsFunctionMiddleware { - fn feed<'a>( - &mut self, - operator: Operator<'a>, - state: &mut MiddlewareReaderState<'a>, - ) -> Result<(), MiddlewareError> { - match operator { - Operator::CallIndirect { .. } | Operator::ReturnCallIndirect { .. } => { - // Return an error to prohibit CallIndirect and ReturnCallIndirect - return Err(MiddlewareError::new( - "prohibited", - "CallIndirect and ReturnCallIndirect are prohibited", - )); - } - _ => { - state.push_operator(operator.clone()); - } - } - - Ok(()) - } -} diff --git a/moveos/moveos-wasm/src/wasm.rs b/moveos/moveos-wasm/src/wasm.rs index 0c69b48e86..89f227c68b 100644 --- a/moveos/moveos-wasm/src/wasm.rs +++ b/moveos/moveos-wasm/src/wasm.rs @@ -16,11 +16,9 @@ use wasmer_compiler_singlepass::Singlepass; use crate::cost_function::cost_function; use crate::gas_meter::GasMeter; use crate::middlewares::gas_metering::GasMiddleware; -use crate::middlewares::prohibit_ops::ProhibitOpsMiddleware; -const GAS_LIMIT: u64 = 10000; +const GAS_LIMIT: u64 = 500000; -//#[derive(Clone)] pub struct WASMInstance { pub bytecode: Vec, pub instance: Instance, @@ -271,10 +269,6 @@ pub fn create_wasm_instance(code: &[u8]) -> anyhow::Result { // Create and configure the compiler let mut compiler = Singlepass::new(); - // Add prohibit middleware - let prohibit_ops = ProhibitOpsMiddleware::new(); - compiler.push_middleware(Arc::new(prohibit_ops)); - // Add gas meter middleware let gas_middleware = GasMiddleware::new(Some(Arc::new(cost_function))); compiler.push_middleware(Arc::new(gas_middleware)); diff --git a/scripts/bitcoin/test.sh b/scripts/bitcoin/test.sh index 5258a58a8c..cdd567ff04 100644 --- a/scripts/bitcoin/test.sh +++ b/scripts/bitcoin/test.sh @@ -44,13 +44,11 @@ EOF done export CARGO_BUILD_JOBS=8 -export RUST_LOG=debug +export RUST_LOG=info export RUST_BACKTRACE=1 if [ ! -z "$UNIT_TEST" ]; then - cargo run --bin rooch move test -p frameworks/moveos-stdlib wasm - cargo run --bin rooch move test -p frameworks/bitcoin-move - cargo run --bin rooch move test -p frameworks/rooch-nursery + cargo run --bin rooch move test -p frameworks/rooch-nursery bitseed fi if [ ! -z "$WASM_INT_TEST" ]; then