From e1f493fb6b8339729af9e269b6707c92e827ca4e Mon Sep 17 00:00:00 2001 From: gRoussac Date: Tue, 18 Jul 2023 17:43:44 +0200 Subject: [PATCH 1/8] Update crates and test sto last state of art --- Makefile | 28 +++++++++++++++------------- contract/Cargo.toml | 7 ++----- contract/src/main.rs | 17 +++++++++++------ rust-toolchain | 2 +- tests/Cargo.toml | 11 ++++++----- tests/src/integration_tests.rs | 15 ++++++++++----- 6 files changed, 45 insertions(+), 35 deletions(-) diff --git a/Makefile b/Makefile index 607acb7..d73938b 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: +test: build-contract + mkdir -p tests/wasm cp target/wasm32-unknown-unknown/release/contract.wasm tests/wasm - -test: build-contract copy-wasm-file-to-test test-only + 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 \ No newline at end of file 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..0c09aec 100644 --- a/tests/src/integration_tests.rs +++ b/tests/src/integration_tests.rs @@ -4,8 +4,9 @@ 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, + DEFAULT_ACCOUNT_ADDR, DEFAULT_ACCOUNT_INITIAL_BALANCE, DEFAULT_CHAINSPEC_REGISTRY, + DEFAULT_GENESIS_CONFIG, DEFAULT_GENESIS_CONFIG_HASH, DEFAULT_PAYMENT, + PRODUCTION_RUN_GENESIS_REQUEST, }; use casper_execution_engine::core::engine_state::{ run_genesis_request::RunGenesisRequest, GenesisAccount, @@ -16,7 +17,7 @@ mod tests { const MY_ACCOUNT: [u8; 32] = [7u8; 32]; // Define `KEY` constant to match that in the contract. - const KEY: &str = "special_value"; + const KEY: &str = "my-key-name"; const VALUE: &str = "hello world"; const RUNTIME_ARG_NAME: &str = "message"; const CONTRACT_WASM: &str = "contract.wasm"; @@ -43,6 +44,7 @@ mod tests { *DEFAULT_GENESIS_CONFIG_HASH, genesis_config.protocol_version(), genesis_config.take_ee_config(), + DEFAULT_CHAINSPEC_REGISTRY.clone(), ); // 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 @@ -109,8 +111,11 @@ 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.exec(execute_request).commit().expect_failure(); + builder + .run_genesis(&PRODUCTION_RUN_GENESIS_REQUEST) + .exec(execute_request) + .commit() + .expect_failure(); } } From 4943ddda30fc549bc69355ef4276b0d26553c0c9 Mon Sep 17 00:00:00 2001 From: gRoussac Date: Tue, 18 Jul 2023 18:06:13 +0200 Subject: [PATCH 2/8] Path issue on CI/CD --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d73938b..dbaa54b 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,11 @@ prepare: build-contract: cd contract && cargo build --release --target wasm32-unknown-unknown - wasm-strip target/wasm32-unknown-unknown/release/contract.wasm + wasm-strip ./target/wasm32-unknown-unknown/release/contract.wasm test: build-contract mkdir -p tests/wasm - cp target/wasm32-unknown-unknown/release/contract.wasm tests/wasm + cp ./target/wasm32-unknown-unknown/release/contract.wasm tests/wasm cd tests && cargo test clippy: From 60cc27d057f5a7b647d8db08d9fbe9763e8e08c3 Mon Sep 17 00:00:00 2001 From: gRoussac Date: Tue, 18 Jul 2023 18:10:06 +0200 Subject: [PATCH 3/8] Add wabt --- .github/workflows/ci-casper-rust-contract.yml | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 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 From 609d01191afd6994cff35caa6bfeacc0df05f76f Mon Sep 17 00:00:00 2001 From: gRoussac Date: Tue, 18 Jul 2023 18:10:57 +0200 Subject: [PATCH 4/8] nightly tests --- .github/workflows/nightly-scheduled-test.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 }} From dde451c2b265bc096aa7e26bb7abb9160e8fed4f Mon Sep 17 00:00:00 2001 From: gRoussac Date: Tue, 18 Jul 2023 18:38:36 +0200 Subject: [PATCH 5/8] Update tests to last cargo-casper dev version --- tests/src/integration_tests.rs | 73 +++++++++++++--------------------- 1 file changed, 28 insertions(+), 45 deletions(-) diff --git a/tests/src/integration_tests.rs b/tests/src/integration_tests.rs index 0c09aec..8c2c6c2 100644 --- a/tests/src/integration_tests.rs +++ b/tests/src/integration_tests.rs @@ -4,18 +4,11 @@ mod tests { use casper_engine_test_support::{ DeployItemBuilder, ExecuteRequestBuilder, InMemoryWasmTestBuilder, ARG_AMOUNT, - DEFAULT_ACCOUNT_ADDR, DEFAULT_ACCOUNT_INITIAL_BALANCE, DEFAULT_CHAINSPEC_REGISTRY, - DEFAULT_GENESIS_CONFIG, DEFAULT_GENESIS_CONFIG_HASH, DEFAULT_PAYMENT, - PRODUCTION_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 = "my-key-name"; const VALUE: &str = "hello world"; @@ -24,28 +17,11 @@ mod tests { #[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(), - DEFAULT_CHAINSPEC_REGISTRY.clone(), - ); // 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. @@ -59,15 +35,12 @@ 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, @@ -81,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.to_string()], + ) .expect("should be stored value.") .as_cl_value() .expect("should be cl value.") @@ -94,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(); @@ -113,9 +86,19 @@ mod tests { let mut builder = InMemoryWasmTestBuilder::default(); builder .run_genesis(&PRODUCTION_RUN_GENESIS_REQUEST) - .exec(execute_request) - .commit() - .expect_failure(); + .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 + ); } } From 23175478bb77a0b9ee680654a9a8e964b94e0318 Mon Sep 17 00:00:00 2001 From: gRoussac Date: Tue, 18 Jul 2023 18:42:10 +0200 Subject: [PATCH 6/8] // small change consistency KEY_NAME --- tests/src/integration_tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/src/integration_tests.rs b/tests/src/integration_tests.rs index 8c2c6c2..aa23925 100644 --- a/tests/src/integration_tests.rs +++ b/tests/src/integration_tests.rs @@ -9,8 +9,8 @@ mod tests { use casper_execution_engine::core::{engine_state::Error as EngineStateError, execution}; use casper_types::{runtime_args, ApiError, Key, RuntimeArgs}; - // Define `KEY` constant to match that in the contract. - const KEY: &str = "my-key-name"; + // 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"; @@ -45,7 +45,7 @@ mod tests { 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()); @@ -57,7 +57,7 @@ mod tests { .query( None, Key::Account(*DEFAULT_ACCOUNT_ADDR), - &[KEY.to_string()], + &[KEY_NAME.to_string()], ) .expect("should be stored value.") .as_cl_value() From 627bc28da491be59441cb076ed320c3c106f4651 Mon Sep 17 00:00:00 2001 From: gRoussac Date: Tue, 18 Jul 2023 19:30:18 +0200 Subject: [PATCH 7/8] Test ci cd --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dbaa54b..e913f84 100644 --- a/Makefile +++ b/Makefile @@ -25,4 +25,4 @@ lint: clippy clean: cd contract && cargo clean cd tests && cargo clean - rm -rf tests/wasm \ No newline at end of file + rm -rf tests/wasm From d3acdb7a6ef07a31d554981066083d627593b3e9 Mon Sep 17 00:00:00 2001 From: gRoussac Date: Mon, 25 Sep 2023 11:11:03 +0200 Subject: [PATCH 8/8] Trigger CI/CD --- README.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) 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 \ ```
- - -