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