From 54ed456755c1a64f904321b0d54fdc08bce6c9c6 Mon Sep 17 00:00:00 2001 From: Gregory Roussac Date: Mon, 25 Sep 2023 11:44:31 +0200 Subject: [PATCH] Update crates and tests to last state of art (#21) * Update crates and test sto last state of art * Path issue on CI/CD * Add wabt * nightly tests * Update tests to last cargo-casper dev version * // small change consistency KEY_NAME * Test ci cd * Trigger CI/CD --- .github/workflows/ci-casper-rust-contract.yml | 26 +++---- .github/workflows/nightly-scheduled-test.yml | 10 +-- Makefile | 30 ++++---- README.md | 22 +++--- contract/Cargo.toml | 7 +- contract/src/main.rs | 17 +++-- rust-toolchain | 2 +- tests/Cargo.toml | 11 +-- tests/src/integration_tests.rs | 76 ++++++++----------- 9 files changed, 98 insertions(+), 103 deletions(-) diff --git a/.github/workflows/ci-casper-rust-contract.yml b/.github/workflows/ci-casper-rust-contract.yml index 4c808cc..089e1e7 100644 --- a/.github/workflows/ci-casper-rust-contract.yml +++ b/.github/workflows/ci-casper-rust-contract.yml @@ -2,12 +2,12 @@ name: ci-casper-rust-contract on: push: - branches: [ master ] + branches: [master] paths-ignore: - '**.md' pull_request: - branches: [ master ] + branches: [master] paths-ignore: - '**.md' @@ -18,14 +18,14 @@ jobs: os: [ubuntu-20.04, ubuntu-22.04] runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - components: rustfmt, clippy - # Needed for gcc install - - run: sudo apt update && sudo apt install -y build-essential - - uses: Swatinem/rust-cache@v1 - - run: make prepare - - run: make check-lint - - run: make test + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + components: rustfmt, clippy + # Needed for gcc install + - run: sudo apt update && sudo apt install -y build-essential wabt + - uses: Swatinem/rust-cache@v1 + - run: make prepare + - run: make check-lint + - run: make test diff --git a/.github/workflows/nightly-scheduled-test.yml b/.github/workflows/nightly-scheduled-test.yml index 48dcf37..030c877 100644 --- a/.github/workflows/nightly-scheduled-test.yml +++ b/.github/workflows/nightly-scheduled-test.yml @@ -5,7 +5,7 @@ on: schedule: # * is a special character in YAML so you have to quote this string # runs every day at midnight - - cron: "0 0 * * *" + - cron: '0 0 * * *' jobs: nightly-make-test: @@ -21,7 +21,7 @@ jobs: components: rustfmt, clippy # Needed for gcc install - - run: sudo apt update && sudo apt install -y build-essential + - run: sudo apt update && sudo apt install -y build-essential wabt - uses: Swatinem/rust-cache@v1 - run: make prepare - run: make test @@ -31,9 +31,9 @@ jobs: if: always() with: status: ${{ job.status }} - notification_title: "*{repo}*" - message_format: "{emoji} *{workflow}* *{status_message}* in <{repo_url}|{repo}@{branch}> on <{commit_url}|{commit_sha}>" - footer: "<{run_url}|View Run>" + notification_title: '*{repo}*' + message_format: '{emoji} *{workflow}* *{status_message}* in <{repo_url}|{repo}@{branch}> on <{commit_url}|{commit_sha}>' + footer: '<{run_url}|View Run>' env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/Makefile b/Makefile index 607acb7..e913f84 100644 --- a/Makefile +++ b/Makefile @@ -2,25 +2,27 @@ prepare: rustup target add wasm32-unknown-unknown build-contract: - cargo build --release -p contract --target wasm32-unknown-unknown + cd contract && cargo build --release --target wasm32-unknown-unknown + wasm-strip ./target/wasm32-unknown-unknown/release/contract.wasm -test-only: - cargo test -p tests - -copy-wasm-file-to-test: - cp target/wasm32-unknown-unknown/release/contract.wasm tests/wasm - -test: build-contract copy-wasm-file-to-test test-only +test: build-contract + mkdir -p tests/wasm + cp ./target/wasm32-unknown-unknown/release/contract.wasm tests/wasm + cd tests && cargo test clippy: - cargo clippy --all-targets --all -- -D warnings -A renamed_and_removed_lints + cd contract && cargo clippy --all-targets -- -D warnings + cd tests && cargo clippy --all-targets -- -D warnings check-lint: clippy - cargo fmt --all -- --check + cd contract && cargo fmt -- --check + cd tests && cargo fmt -- --check lint: clippy - cargo fmt --all - + cd contract && cargo fmt + cd tests && cargo fmt + clean: - cargo clean - rm -rf tests/wasm/contract.wasm + cd contract && cargo clean + cd tests && cargo clean + rm -rf tests/wasm diff --git a/README.md b/README.md index 6a18530..525ae69 100644 --- a/README.md +++ b/README.md @@ -4,25 +4,31 @@ This session code accepts a message string and stores it in the calling account **Usage**: This session code expects a runtime argument named `message` of the type `String`. -**Tests**: There are two tests available to test the Hello World session code. The `should_store_hello_world` test verifies the successful path, where a string *hello world* is saved under the `special_value` NamedKey. The `should_error_on_missing_runtime_arg` test verifies that an error is displayed when the runtime argument is missing. -The tests start by initializing the Casper crates and creating a genesis account. Then the contract Wasm is loaded to the session_code object. The deploy_item object is created using the details like payment method, session code arguments, and the account address. The deploy_item object is passed to the execute_request. Finally, the execution engine is invoked to process the execute_request. +**Tests**: There are two tests available to test the Hello World session code. The `should_store_hello_world` test verifies the successful path, where a string _hello world_ is saved under the `special_value` NamedKey. The `should_error_on_missing_runtime_arg` test verifies that an error is displayed when the runtime argument is missing. +The tests start by initializing the Casper crates and creating a genesis account. Then the contract Wasm is loaded to the session_code object. The deploy_item object is created using the details like payment method, session code arguments, and the account address. The deploy_item object is passed to the execute_request. Finally, the execution engine is invoked to process the execute_request. -## Build and Test the Session Code +## Build and Test the Session Code ### Set up the Rust toolchain + You need the Rust toolchain to develop smart contracts. + ```bash make prepare ``` ### Compile session code + Compile the session code to WebAssembly (Wasm) + ```bash make build-contract ``` ### Test + Run the tests suite. + ```bash make test ``` @@ -74,7 +80,6 @@ nctl-view-faucet-account - The following command will help you deploy the session code on the NCTL network. In the following command, the KEY PATH is the path of the faucet account secret key. ```bash @@ -84,10 +89,10 @@ casper-client put-deploy \ --secret-key [KEY PATH]/secret_key.pem \ --payment-amount 5000000000000 \ --session-path [CONTRACT PATH]/contract.wasm \ - --session-arg "message:string='hello world'" + --session-arg "message:string='hello world'" ``` -After the deploy is successful, you can view the new NamedKey `special_value` in the faucet account details. +After the deploy is successful, you can view the new NamedKey `special_value` in the faucet account details.
Sample faucet account details after successful deploy @@ -149,7 +154,7 @@ casper-client get-state-root-hash --node-address http://localhost:11101 ```json { -"id": -7547762796950564402, + "id": -7547762796950564402, "jsonrpc": "2.0", "result": { "api_version": "1.0.0", @@ -192,6 +197,3 @@ casper-client query-state \ ```
- - - diff --git a/contract/Cargo.toml b/contract/Cargo.toml index 560a44e..9374e15 100644 --- a/contract/Cargo.toml +++ b/contract/Cargo.toml @@ -5,8 +5,8 @@ authors = ["darthsiroftardis "] edition = "2018" [dependencies] -casper-contract = "1.4.4" -casper-types = "1.5.0" +casper-contract = "3.0.0" +casper-types = "3.0.0" [[bin]] name = "contract" @@ -14,6 +14,3 @@ path = "src/main.rs" bench = false doctest = false test = false - -[features] -default = ["casper-contract/std", "casper-types/std", "casper-contract/test-support"] diff --git a/contract/src/main.rs b/contract/src/main.rs index 7729ce6..f0ec1c6 100644 --- a/contract/src/main.rs +++ b/contract/src/main.rs @@ -1,10 +1,14 @@ +#![no_std] #![no_main] +extern crate alloc; + +use alloc::string::String; use casper_contract::contract_api::{runtime, storage}; use casper_types::{Key, URef}; -const KEY: &str = "special_value"; -const ARG_MESSAGE: &str = "message"; +const KEY_NAME: &str = "my-key-name"; +const RUNTIME_ARG_NAME: &str = "message"; fn store(value: String) { // Store `value` under a new unforgeable reference. @@ -13,14 +17,15 @@ fn store(value: String) { // Wrap the unforgeable reference in a value of type `Key`. let value_key: Key = value_ref.into(); - // Store this key under the name "special_value" in context-local storage. - runtime::put_key(KEY, value_key); + // Store this key under the name "my-key-name" in caller context + runtime::put_key(KEY_NAME, value_key); } // All session code must have a `call` entrypoint. #[no_mangle] pub extern "C" fn call() { - // Get the optional first argument supplied to the argument. - let value: String = runtime::get_named_arg(ARG_MESSAGE); + // This contract expects a single runtime argument to be provided. The arg is named "message" + // and will be of type `String`. + let value: String = runtime::get_named_arg(RUNTIME_ARG_NAME); store(value); } diff --git a/rust-toolchain b/rust-toolchain index f97418f..f9e5e5e 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2022-03-03 +nightly-2023-03-25 diff --git a/tests/Cargo.toml b/tests/Cargo.toml index 8707bd2..0b1fddd 100644 --- a/tests/Cargo.toml +++ b/tests/Cargo.toml @@ -4,14 +4,15 @@ version = "0.1.0" edition = "2018" [dev-dependencies] -casper-contract = { version = "1.4.4", default-features = false, features = ["test-support"] } -casper-engine-test-support = { version = "2.2.0", features = ["test-support"] } -casper-execution-engine = "2.0.0" -casper-types = "1.5.0" +casper-engine-test-support = "5.0.0" +casper-contract = { version = "3.0.0", default-features = false, features = [ + "test-support", +] } +casper-execution-engine = "5.0.0" +casper-types = "3.0.0" [[bin]] name = "integration-tests" path = "src/integration_tests.rs" bench = false doctest = false - diff --git a/tests/src/integration_tests.rs b/tests/src/integration_tests.rs index c8f22ba..aa23925 100644 --- a/tests/src/integration_tests.rs +++ b/tests/src/integration_tests.rs @@ -4,46 +4,24 @@ mod tests { use casper_engine_test_support::{ DeployItemBuilder, ExecuteRequestBuilder, InMemoryWasmTestBuilder, ARG_AMOUNT, - DEFAULT_ACCOUNT_ADDR, DEFAULT_ACCOUNT_INITIAL_BALANCE, DEFAULT_GENESIS_CONFIG, - DEFAULT_GENESIS_CONFIG_HASH, DEFAULT_PAYMENT, DEFAULT_RUN_GENESIS_REQUEST, - }; - use casper_execution_engine::core::engine_state::{ - run_genesis_request::RunGenesisRequest, GenesisAccount, - }; - use casper_types::{ - account::AccountHash, runtime_args, Key, Motes, PublicKey, RuntimeArgs, SecretKey, U512, + DEFAULT_ACCOUNT_ADDR, DEFAULT_PAYMENT, PRODUCTION_RUN_GENESIS_REQUEST, }; + use casper_execution_engine::core::{engine_state::Error as EngineStateError, execution}; + use casper_types::{runtime_args, ApiError, Key, RuntimeArgs}; - const MY_ACCOUNT: [u8; 32] = [7u8; 32]; - // Define `KEY` constant to match that in the contract. - const KEY: &str = "special_value"; + // Define `KEY_NAME` constant to match that in the contract. + const KEY_NAME: &str = "my-key-name"; const VALUE: &str = "hello world"; const RUNTIME_ARG_NAME: &str = "message"; const CONTRACT_WASM: &str = "contract.wasm"; #[test] fn should_store_hello_world() { - // Create keypair. - let secret_key = SecretKey::ed25519_from_bytes(MY_ACCOUNT).unwrap(); - let public_key = PublicKey::from(&secret_key); - - // Create an AccountHash from a public key. - let account_addr = AccountHash::from(&public_key); - // Create a GenesisAccount. - let account = GenesisAccount::account( - public_key, - Motes::new(U512::from(DEFAULT_ACCOUNT_INITIAL_BALANCE)), - None, - ); - - let mut genesis_config = DEFAULT_GENESIS_CONFIG.clone(); - genesis_config.ee_config_mut().push_account(account); + let mut builder = InMemoryWasmTestBuilder::default(); + builder + .run_genesis(&PRODUCTION_RUN_GENESIS_REQUEST) + .commit(); - let run_genesis_request = RunGenesisRequest::new( - *DEFAULT_GENESIS_CONFIG_HASH, - genesis_config.protocol_version(), - genesis_config.take_ee_config(), - ); // The test framework checks for compiled Wasm files in '/wasm'. Paths // relative to the current working dir (e.g. 'wasm/contract.wasm') can also be used, as can // absolute paths. @@ -57,20 +35,17 @@ mod tests { ARG_AMOUNT => *DEFAULT_PAYMENT }) .with_session_code(session_code, session_args) - .with_authorization_keys(&[account_addr]) - .with_address(account_addr) + .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR]) + .with_address(*DEFAULT_ACCOUNT_ADDR) .build(); let execute_request = ExecuteRequestBuilder::from_deploy_item(deploy_item).build(); - let mut builder = InMemoryWasmTestBuilder::default(); - builder.run_genesis(&run_genesis_request).commit(); - // prepare assertions. let result_of_query = builder.query( None, Key::Account(*DEFAULT_ACCOUNT_ADDR), - &[KEY.to_string()], + &[KEY_NAME.to_string()], ); assert!(result_of_query.is_err()); @@ -79,7 +54,11 @@ mod tests { // make assertions let result_of_query = builder - .query(None, Key::Account(account_addr), &[KEY.to_string()]) + .query( + None, + Key::Account(*DEFAULT_ACCOUNT_ADDR), + &[KEY_NAME.to_string()], + ) .expect("should be stored value.") .as_cl_value() .expect("should be cl value.") @@ -92,16 +71,12 @@ mod tests { #[test] fn should_error_on_missing_runtime_arg() { - let secret_key = SecretKey::ed25519_from_bytes(MY_ACCOUNT).unwrap(); - let public_key = PublicKey::from(&secret_key); - let account_addr = AccountHash::from(&public_key); - let session_code = PathBuf::from(CONTRACT_WASM); let session_args = RuntimeArgs::new(); let deploy_item = DeployItemBuilder::new() .with_empty_payment_bytes(runtime_args! {ARG_AMOUNT => *DEFAULT_PAYMENT}) - .with_authorization_keys(&[account_addr]) + .with_authorization_keys(&[*DEFAULT_ACCOUNT_ADDR]) .with_address(*DEFAULT_ACCOUNT_ADDR) .with_session_code(session_code, session_args) .build(); @@ -109,8 +84,21 @@ mod tests { let execute_request = ExecuteRequestBuilder::from_deploy_item(deploy_item).build(); let mut builder = InMemoryWasmTestBuilder::default(); - builder.run_genesis(&DEFAULT_RUN_GENESIS_REQUEST).commit(); + builder + .run_genesis(&PRODUCTION_RUN_GENESIS_REQUEST) + .commit(); builder.exec(execute_request).commit().expect_failure(); + + let actual_error = builder.get_error().expect("must have error"); + assert!( + matches!( + actual_error, + EngineStateError::Exec(execution::Error::Revert(ApiError::MissingArgument)) + ), + "Expected {:?}, received {:?}", + EngineStateError::Exec(execution::Error::Revert(ApiError::MissingArgument)), + actual_error + ); } }