Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto test for module publishing in Move #632

Merged
merged 5 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified crates/rooch-genesis/genesis/genesis
Binary file not shown.
4 changes: 3 additions & 1 deletion crates/rooch-rpc-server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ impl RpcModuleBuilder {

// Start json-rpc server
pub async fn start_server(is_mock_storage: bool) -> Result<ServerHandle> {
tracing_subscriber::fmt::init();
// We may call `start_server` multiple times in testing scenarios
// tracing_subscriber can only be inited once.
let _ = tracing_subscriber::fmt::try_init();

let config = ServerConfig::default();

Expand Down
51 changes: 43 additions & 8 deletions crates/rooch/src/commands/move_cli/commands/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ use move_binary_format::file_format::CompiledModule;
use move_bytecode_utils::dependency_graph::DependencyGraph;
use move_bytecode_utils::Modules;
use move_cli::Move;
use move_core_types::{identifier::Identifier, language_storage::ModuleId};
use rooch_rpc_api::jsonrpc_types::ExecuteTransactionResponseView;
use rooch_types::crypto::BuiltinScheme;
use rooch_types::{crypto::BuiltinScheme, transaction::rooch::RoochTransaction};

use crate::cli_types::{CommandAction, TransactionOptions, WalletContextOptions};
use moveos::vm::dependency_order::sort_by_dependency_order;
use moveos_types::transaction::MoveAction;
use moveos_types::{
addresses::MOVEOS_STD_ADDRESS, move_types::FunctionId, transaction::MoveAction,
};
use moveos_verifier::build::run_verifier;
use rooch_types::address::RoochAddress;
use rooch_types::error::{RoochError, RoochResult};
Expand Down Expand Up @@ -42,6 +45,10 @@ pub struct Publish {
/// Command line input of crypto schemes (ed25519, multi-ed25519, ecdsa, ecdsa-recoverable or schnorr)
#[clap(short = 's', long = "scheme", default_value = "ed25519", arg_enum)]
pub crypto_schemes: BuiltinScheme,

/// Whether publish module by Move function `moveos_std::account_storage::publish_modules_entry`?
#[clap(long, parse(from_flag))]
pub by_move: bool,
}

impl Publish {
Expand Down Expand Up @@ -113,13 +120,41 @@ impl CommandAction<ExecuteTransactionResponseView> for Publish {
));
}

let action = MoveAction::ModuleBundle(bundles);

let sender: RoochAddress = pkg_address.into();
eprintln!("Publish modules to address: {:?}", sender);
let result = context
.sign_and_execute(sender, action, self.crypto_schemes)
.await?;
context.assert_execute_success(result)
let tx_result = if self.by_move {
let args = bcs::to_bytes(&bundles).unwrap();
let action = MoveAction::new_function_call(
FunctionId::new(
ModuleId::new(
MOVEOS_STD_ADDRESS,
Identifier::new("account_storage".to_owned()).unwrap(),
),
Identifier::new("publish_modules_entry".to_owned()).unwrap(),
),
vec![],
vec![args],
);
match self.tx_options.authenticator {
Some(authenticator) => {
let tx_data = context.build_tx_data(sender, action).await?;
//TODO the authenticator usually is associalted with the RoochTransactinData
//So we need to find a way to let user generate the authenticator based on the tx_data.
let tx = RoochTransaction::new(tx_data, authenticator.into());
context.execute(tx).await?
}
None => {
context
.sign_and_execute(sender, action, self.crypto_schemes)
.await?
}
}
} else {
let action = MoveAction::ModuleBundle(bundles);
context
.sign_and_execute(sender, action, self.crypto_schemes)
.await?
};
context.assert_execute_success(tx_result)
}
}
12 changes: 10 additions & 2 deletions crates/rooch/src/commands/server/commands/start.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,21 @@ use tracing::info;

/// Start service
#[derive(Debug, Parser)]
pub struct StartCommand;
pub struct StartCommand {
/// If true, start the service with a temporary data store.
/// All data will be deleted when the service is stopped.
#[clap(long, parse(from_flag))]
pub temp_db: bool,
}

#[async_trait]
impl CommandAction<()> for StartCommand {
async fn execute(self) -> RoochResult<()> {
let mut service = Service::new();
service.start(false).await.map_err(RoochError::from)?;
service
.start(self.temp_db)
.await
.map_err(RoochError::from)?;

#[cfg(unix)]
{
Expand Down
52 changes: 38 additions & 14 deletions crates/testsuite/features/cmd.feature
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
Feature: Rooch CLI integration tests
@serial
Scenario: Init
Then cmd: "init"

@serial
Scenario: account
Given the server
Given a server for account

Then cmd: "object --id {default}"
Then cmd: "account create"
Expand All @@ -18,16 +20,6 @@ Feature: Rooch CLI integration tests
Then cmd: "account nullify --address 0xebf29d2aed4da3d2e13a32d71266a302fbfd5ceb3ff1f465c006fa207f1789ce --scheme ecdsa-recoverable"
Then cmd: "account nullify --address 0xebf29d2aed4da3d2e13a32d71266a302fbfd5ceb3ff1f465c006fa207f1789ce --scheme schnorr"

# TODO split Scenario for every example
# counter example
Then cmd: "move publish -p ../../examples/counter --sender-account {default} --named-addresses rooch_examples={default}"
Then cmd: "move view --function {default}::counter::value"
Then assert: "{{$.move[-1][0].move_value}} == 0"
Then cmd: "move run --function {default}::counter::increase --sender-account {default}"
Then cmd: "move view --function {default}::counter::value"
Then assert: "{{$.move[-1][0].move_value}} == 1"
Then cmd: "resource --address {default} --resource {default}::counter::Counter"

Then cmd: "transaction get-by-hash --hash {{$.account[0].execution_info.tx_hash}}"
Then cmd: "transaction get-by-index --cursor 0 --limit 10"

Expand All @@ -36,7 +28,11 @@ Feature: Rooch CLI integration tests
Then cmd: "move run --function {default}::event_test::emit_event --sender-account {default} --args 10u64"
Then cmd: "event get-events-by-event-handle --event_handle_type {default}::event_test::WithdrawEvent --cursor 0 --limit 1"

# kv store example
Then stop the server

@serial
Scenario: kv store example
Given a server for kv_store
Then cmd: "move publish -p ../../examples/kv_store --sender-account {default} --named-addresses rooch_examples={default}"
#FIXME how to pass args at here.
#Then cmd: "move run --function {default}::kv_store::add_value --args 'b\"key1\"' 'b\"value1\"' --sender-account default"
Expand All @@ -45,8 +41,13 @@ Feature: Rooch CLI integration tests
#Then cmd: "state --access-path /resource/{default}/{default}::kv_store::KVStore
#Then cmd: "state --access-path /table/{{$.move[-1][0].move_value.value.table.value.handle}}/key1"
#Then assert: "{{$.move[-1][0].move_value}} == "value1""

Then stop the server

@serial
Scenario: entry function example
Given a server for entry_function

# entry function example
Then cmd: "move publish -p ../../examples/entry_function_arguments/ --sender-account {default} --named-addresses rooch_examples={default}"
Then cmd: "move run --function {default}::entry_function::emit_bool --args bool:true --sender-account {default}"
Then assert: "{{$.move[-1].execution_info.status.type}} == executed"
Expand All @@ -67,4 +68,27 @@ Feature: Rooch CLI integration tests
Then cmd: "move run --function {default}::entry_function::emit_vec_object_id --args "vector<address>:0x1324,0x41234,0x1234" --sender-account {default}"
Then assert: "{{$.move[-1].execution_info.status.type}} == executed"
Then cmd: "move run --function {default}::entry_function::emit_mix --args 3u8 "vector<object_id>:0x2342,0x3132" --sender-account {default}"
Then assert: "{{$.move[-1].execution_info.status.type}} == executed"
Then assert: "{{$.move[-1].execution_info.status.type}} == executed"

Then stop the server

@serial
Scenario: publish in Move
Given a server for publish

# The counter example
Then cmd: "move publish -p ../../examples/counter --sender-account {default} --named-addresses rooch_examples={default} --by-move"
Then cmd: "move view --function {default}::counter::value"
Then assert: "{{$.move[-1][0].move_value}} == 0"
Then cmd: "move run --function {default}::counter::increase --sender-account {default}"
Then cmd: "move view --function {default}::counter::value"
Then assert: "{{$.move[-1][0].move_value}} == 1"
Then cmd: "resource --address {default} --resource {default}::counter::Counter"
Then assert: "{{$.resource[-1].move_value.value.value}} == 1"

# The entry_function_arguments example
Then cmd: "move publish -p ../../examples/entry_function_arguments --sender-account {default} --named-addresses rooch_examples={default} --by-move"
Then cmd: "move run --function {default}::entry_function::emit_u8 --args u8:3 --sender-account {default}"
Then assert: "{{$.move[-1].output.status.type}} == executed"

Then stop the server
4 changes: 2 additions & 2 deletions crates/testsuite/tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ struct World {
tpl_ctx: Option<TemplateContext>,
}

#[given(expr = "the server")] // Cucumber Expression
async fn start_server(w: &mut World) {
#[given(expr = "a server for {word}")] // Cucumber Expression
async fn start_server(w: &mut World, _scenario: String) {
let mut service = Service::new();
service.start(true).await.unwrap();

Expand Down
34 changes: 34 additions & 0 deletions moveos/moveos-stdlib/moveos-stdlib/doc/account_storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ It is used to store the account's resources and modules
- [Function `global_exists`](#0x2_account_storage_global_exists)
- [Function `exists_module`](#0x2_account_storage_exists_module)
- [Function `publish_modules`](#0x2_account_storage_publish_modules)
- [Function `publish_modules_entry`](#0x2_account_storage_publish_modules_entry)


<pre><code><b>use</b> <a href="../doc/signer.md#0x1_signer">0x1::signer</a>;
Expand Down Expand Up @@ -421,4 +422,37 @@ Publish modules to the account's storage



</details>

<a name="0x2_account_storage_publish_modules_entry"></a>

## Function `publish_modules_entry`



<pre><code><b>public</b> entry <b>fun</b> <a href="account_storage.md#0x2_account_storage_publish_modules_entry">publish_modules_entry</a>(ctx: &<b>mut</b> <a href="storage_context.md#0x2_storage_context_StorageContext">storage_context::StorageContext</a>, account: &<a href="signer.md#0x2_signer">signer</a>, modules: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;)
</code></pre>



<details>
<summary>Implementation</summary>


<pre><code><b>public</b> entry <b>fun</b> <a href="account_storage.md#0x2_account_storage_publish_modules_entry">publish_modules_entry</a>(ctx: &<b>mut</b> StorageContext, account: &<a href="signer.md#0x2_signer">signer</a>, modules: <a href="">vector</a>&lt;<a href="">vector</a>&lt;u8&gt;&gt;) {
<b>let</b> n_modules = <a href="_length">vector::length</a>(&modules);
<b>let</b> i = 0;
<b>let</b> module_vec = <a href="_empty">vector::empty</a>&lt;MoveModule&gt;();
<b>while</b> (i &lt; n_modules) {
<b>let</b> code_bytes = <a href="_pop_back">vector::pop_back</a>(&<b>mut</b> modules);
<b>let</b> m = <a href="move_module.md#0x2_move_module_new">move_module::new</a>(code_bytes);
<a href="_push_back">vector::push_back</a>(&<b>mut</b> module_vec, m);
i = i + 1;
};
<a href="account_storage.md#0x2_account_storage_publish_modules">publish_modules</a>(ctx, account, module_vec);
}
</code></pre>



</details>
13 changes: 13 additions & 0 deletions moveos/moveos-stdlib/moveos-stdlib/sources/account_storage.move
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,19 @@ module moveos_std::account_storage {
}
}

public entry fun publish_modules_entry(ctx: &mut StorageContext, account: &signer, modules: vector<vector<u8>>) {
let n_modules = vector::length(&modules);
let i = 0;
let module_vec = vector::empty<MoveModule>();
while (i < n_modules) {
let code_bytes = vector::pop_back(&mut modules);
let m = move_module::new(code_bytes);
vector::push_back(&mut module_vec, m);
i = i + 1;
};
publish_modules(ctx, account, module_vec);
}

#[test]
fun test_named_table_id() {
assert!(named_table_id(@0xae43e34e51db9c833ab50dd9aa8b27106519e5bbfd533737306e7b69ef253647, NamedTableResource) == object_id::address_to_object_id(@0x04d8b5ccef4d5b55fa9371d1a9c344fcd4bd40dd9f32dd1d94696775fe3f3013), 1000);
Expand Down
Loading