Skip to content

Commit

Permalink
Update crates and tests to last state of art (#21)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
gRoussac committed Sep 25, 2023
1 parent 0bbe066 commit 54ed456
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 103 deletions.
26 changes: 13 additions & 13 deletions .github/workflows/ci-casper-rust-contract.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -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
10 changes: 5 additions & 5 deletions .github/workflows/nightly-scheduled-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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
Expand All @@ -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 }}

Expand Down
30 changes: 16 additions & 14 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
22 changes: 12 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down Expand Up @@ -74,7 +80,6 @@ nctl-view-faucet-account

</details>


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
Expand All @@ -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.

<details>
<summary>Sample faucet account details after successful deploy</summary>
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -192,6 +197,3 @@ casper-client query-state \
```

</details>



7 changes: 2 additions & 5 deletions contract/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@ authors = ["darthsiroftardis <[email protected]>"]
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"
path = "src/main.rs"
bench = false
doctest = false
test = false

[features]
default = ["casper-contract/std", "casper-types/std", "casper-contract/test-support"]
17 changes: 11 additions & 6 deletions contract/src/main.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -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);
}
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1 +1 @@
nightly-2022-03-03
nightly-2023-03-25
11 changes: 6 additions & 5 deletions tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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

76 changes: 32 additions & 44 deletions tests/src/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 '<current working dir>/wasm'. Paths
// relative to the current working dir (e.g. 'wasm/contract.wasm') can also be used, as can
// absolute paths.
Expand All @@ -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());

Expand All @@ -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.")
Expand All @@ -92,25 +71,34 @@ 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();

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
);
}
}

Expand Down

0 comments on commit 54ed456

Please sign in to comment.