Skip to content

Commit c9dcd97

Browse files
authored
Merge pull request #5368 from zajko/restructuring_native_test_implementation_in_vm2
Replacing stub environment implementation for testing smart contracts…
2 parents cbeeb88 + 6a64c4e commit c9dcd97

File tree

35 files changed

+2978
-2514
lines changed

35 files changed

+2978
-2514
lines changed

Cargo.lock

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

executor/wasm/src/testing.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ use casper_execution_engine::engine_state::{EngineConfig, ExecutionEngineV1};
1010
use casper_executor_wasm_interface::{
1111
executor::{
1212
ExecuteRequest, ExecuteRequestBuilder, ExecuteWithProviderError, ExecuteWithProviderResult,
13-
Executor,
1413
},
1514
install::{
1615
InstallContractError, InstallContractRequest, InstallContractRequestBuilder,
17-
InstallContractResult, InstallContractWithProviderResult,
16+
InstallContractWithProviderResult,
1817
},
1918
};
2019
use casper_storage::{

executor/wasm/tests/collections.rs

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
use std::{env, path::PathBuf, sync::Arc};
2+
3+
use casper_execution_engine::engine_state::{EngineConfig, ExecutionEngineV1};
4+
use casper_executor_wasm::{
5+
testing::{
6+
base_execute_builder, base_install_request_builder, make_address_generator,
7+
make_global_state_with_genesis, read_wasm, run_create_contract, run_wasm_session,
8+
},
9+
ExecutorConfigBuilder, ExecutorKind, ExecutorV2,
10+
};
11+
12+
use casper_executor_wasm::{chainspec_config, chainspec_config::ChainspecConfig};
13+
use casper_executor_wasm_interface::executor::ExecutionKind;
14+
use casper_storage::global_state::state::CommitProvider;
15+
use once_cell::sync::Lazy;
16+
17+
/// Symlink to chainspec.
18+
pub static CHAINSPEC_SYMLINK: Lazy<PathBuf> = Lazy::new(|| {
19+
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
20+
.join("../../resources/local/")
21+
.join(chainspec_config::CHAINSPEC_NAME)
22+
});
23+
24+
#[test]
25+
fn should_run_test_suite() {
26+
let chainspec_config = ChainspecConfig::from_chainspec_path(&*CHAINSPEC_SYMLINK)
27+
.expect("must get chainspec config");
28+
let storage_costs = chainspec_config.storage_costs;
29+
let mint_costs = chainspec_config.system_costs_config.mint_costs().clone();
30+
let auction_costs = chainspec_config.system_costs_config.auction_costs().clone();
31+
let v1_config = EngineConfig::from(chainspec_config.clone());
32+
let execution_engine_v1 = ExecutionEngineV1::new(v1_config);
33+
let wasm_v2_config = *chainspec_config.wasm_config.v2();
34+
let memory_limit = wasm_v2_config.max_memory();
35+
let message_limits = chainspec_config.wasm_config.messages_limits();
36+
let executor_config = ExecutorConfigBuilder::default()
37+
.with_memory_limit(memory_limit)
38+
.with_executor_kind(ExecutorKind::Compiled)
39+
.with_wasm_config(wasm_v2_config)
40+
.with_storage_costs(storage_costs)
41+
.with_mint_costs(mint_costs)
42+
.with_auction_costs(auction_costs)
43+
.with_baseline_motes_amount(chainspec_config.core_config.baseline_motes_amount)
44+
.with_message_limits(message_limits)
45+
.build()
46+
.expect("Should build");
47+
let mut executor = ExecutorV2::new(executor_config, execution_engine_v1);
48+
49+
let (global_state, mut state_root_hash, _tempdir) = make_global_state_with_genesis();
50+
51+
let address_generator = make_address_generator();
52+
53+
let vm2_collections_test = read_wasm("vm2_collections_test.wasm");
54+
55+
let install_request = base_install_request_builder(&chainspec_config)
56+
.with_wasm_bytes(vm2_collections_test.wasm)
57+
.with_bundle_data(vm2_collections_test.meta.expect("should have bundle data"))
58+
.with_shared_address_generator(Arc::clone(&address_generator))
59+
.with_transferred_value(0)
60+
.with_entry_point("new".to_string())
61+
.build()
62+
.expect("should build");
63+
64+
let create_result = run_create_contract(
65+
&mut executor,
66+
&global_state,
67+
state_root_hash,
68+
install_request,
69+
);
70+
71+
let contract_address = *create_result.smart_contract_addr();
72+
state_root_hash = global_state
73+
.commit_effects(state_root_hash, create_result.effects().clone())
74+
.expect("Should commit");
75+
76+
let run_method = base_execute_builder(&chainspec_config)
77+
.with_shared_address_generator(Arc::clone(&address_generator))
78+
.with_transferred_value(0)
79+
.with_execution_kind(ExecutionKind::Stored {
80+
address: contract_address,
81+
entry_point: "assertions".to_owned(),
82+
})
83+
.build()
84+
.expect("should build");
85+
let res = run_wasm_session(&mut executor, &global_state, state_root_hash, run_method);
86+
assert!(res.is_ok());
87+
if let Ok(res) = res {
88+
assert!(res.host_error.is_none());
89+
}
90+
}
91+
92+
#[test]
93+
fn inserting_into_non_existing_vec_index_fails() {
94+
let chainspec_config = ChainspecConfig::from_chainspec_path(&*CHAINSPEC_SYMLINK)
95+
.expect("must get chainspec config");
96+
let storage_costs = chainspec_config.storage_costs;
97+
let mint_costs = chainspec_config.system_costs_config.mint_costs().clone();
98+
let auction_costs = chainspec_config.system_costs_config.auction_costs().clone();
99+
let v1_config = EngineConfig::from(chainspec_config.clone());
100+
let execution_engine_v1 = ExecutionEngineV1::new(v1_config);
101+
let wasm_v2_config = *chainspec_config.wasm_config.v2();
102+
let memory_limit = wasm_v2_config.max_memory();
103+
let message_limits = chainspec_config.wasm_config.messages_limits();
104+
let executor_config = ExecutorConfigBuilder::default()
105+
.with_memory_limit(memory_limit)
106+
.with_executor_kind(ExecutorKind::Compiled)
107+
.with_wasm_config(wasm_v2_config)
108+
.with_storage_costs(storage_costs)
109+
.with_mint_costs(mint_costs)
110+
.with_auction_costs(auction_costs)
111+
.with_baseline_motes_amount(chainspec_config.core_config.baseline_motes_amount)
112+
.with_message_limits(message_limits)
113+
.build()
114+
.expect("Should build");
115+
let mut executor = ExecutorV2::new(executor_config, execution_engine_v1);
116+
117+
let (global_state, mut state_root_hash, _tempdir) = make_global_state_with_genesis();
118+
119+
let address_generator = make_address_generator();
120+
121+
let vm2_collections_test = read_wasm("vm2_collections_test.wasm");
122+
123+
let install_request = base_install_request_builder(&chainspec_config)
124+
.with_wasm_bytes(vm2_collections_test.wasm)
125+
.with_bundle_data(vm2_collections_test.meta.expect("should have bundle data"))
126+
.with_shared_address_generator(Arc::clone(&address_generator))
127+
.with_transferred_value(0)
128+
.with_entry_point("new".to_string())
129+
.build()
130+
.expect("should build");
131+
132+
let create_result = run_create_contract(
133+
&mut executor,
134+
&global_state,
135+
state_root_hash,
136+
install_request,
137+
);
138+
139+
let contract_address = *create_result.smart_contract_addr();
140+
state_root_hash = global_state
141+
.commit_effects(state_root_hash, create_result.effects().clone())
142+
.expect("Should commit");
143+
144+
let run_method = base_execute_builder(&chainspec_config)
145+
.with_shared_address_generator(Arc::clone(&address_generator))
146+
.with_transferred_value(0)
147+
.with_execution_kind(ExecutionKind::Stored {
148+
address: contract_address,
149+
entry_point: "test_remove_invalid_index_prepare".to_owned(),
150+
})
151+
.build()
152+
.expect("should build");
153+
let res = run_wasm_session(&mut executor, &global_state, state_root_hash, run_method);
154+
assert!(res.is_ok());
155+
156+
if let Ok(res) = res {
157+
assert!(matches!(
158+
res.host_error,
159+
Some(casper_executor_wasm_common::error::CallError::NotCallable)
160+
));
161+
}
162+
}

executor/wasm_host/src/host/global_state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,8 @@ pub(crate) fn host_env_balance<S: GlobalStateReader + 'static>(
606606
))
607607
}
608608

609+
/// Please note that the returning EnvInfo structure
610+
/// cannot hold any data that can change in course of one wasm execution.
609611
pub(crate) fn host_env_info<S: GlobalStateReader + 'static>(
610612
caller: &mut impl Caller<Context = Context<S>>,
611613
) -> VMResult<(Option<Bytes>, u32)> {

smart_contracts/contracts/vm2/vm2-cep18/src/lib.rs

Lines changed: 25 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,15 @@ impl Burnable for TokenContract {}
7979

8080
#[cfg(test)]
8181
mod tests {
82+
use std::sync::Arc;
83+
8284
use super::*;
8385

8486
use casper_contract_sdk::{
8587
abi::collector::ABI_ITEMS,
8688
casper::{
8789
self,
88-
native::{
89-
current_environment, dispatch_with, with_current_environment, Environment,
90-
DEFAULT_ADDRESS,
91-
},
90+
native::{with_env, EnvironmentMock, DEFAULT_ADDRESS},
9291
Entity,
9392
},
9493
ContractHandle, ToCallData,
@@ -99,10 +98,10 @@ mod tests {
9998
const BOB: Entity = Entity::Account([2; 32]);
10099

101100
#[test]
101+
#[ignore = "TODO this should be a real e2e test wiring real storage and ffi"]
102102
fn it_works() {
103-
let stub = Environment::new(Default::default(), DEFAULT_ADDRESS);
104-
105-
let result = casper::native::dispatch_with(stub, || {
103+
let env = Arc::new(EnvironmentMock::new());
104+
with_env(env.clone(), || {
106105
let mut contract = TokenContract::new("Foo Token".to_string());
107106

108107
assert_eq!(contract.require_any_role(&[ADMIN_ROLE]), Ok(()));
@@ -127,14 +126,13 @@ mod tests {
127126
);
128127
assert_eq!(contract.transfer(ALICE, U256::from(10_000u64)), Ok(()));
129128
});
130-
assert!(matches!(result, Ok(())));
131129
}
132130

133131
#[test]
132+
#[ignore = "TODO this should be a real e2e test wiring real storage and ffi"]
134133
fn e2e() {
135-
// let db = casper::native::Container::default();
136-
// let env = Environment::new(db.clone(), DEFAULT_ADDRESS);
137-
let result = casper::native::dispatch(move || {
134+
let env = Arc::new(EnvironmentMock::new());
135+
with_env(env.clone(), || {
138136
assert_eq!(casper::get_caller(), DEFAULT_ADDRESS);
139137

140138
let constructor = TokenContractRef::new("Foo Token".to_string());
@@ -150,15 +148,8 @@ mod tests {
150148
)
151149
.expect("Should create");
152150

153-
let new_env = with_current_environment(|env| env);
154-
let new_env = new_env.smart_contract(Entity::Contract(create_result.contract_address));
155-
dispatch_with(new_env, || {
156-
// This is the caller of the contract
157-
casper::read_contract_state::<TokenContract>().unwrap();
158-
})
159-
.unwrap();
160-
161-
// assert_eq!(casper::get_caller(), DEFAULT_ADDRESS);
151+
let new_env = Arc::new(EnvironmentMock::new());
152+
casper::read_contract_state::<TokenContract>().unwrap();
162153

163154
let cep18_handle =
164155
ContractHandle::<TokenContractRef>::from_address(create_result.contract_address);
@@ -231,25 +222,20 @@ mod tests {
231222
);
232223
assert_eq!(casper::get_caller(), DEFAULT_ADDRESS);
233224

234-
let alice_env = current_environment().session(ALICE);
235-
236-
casper::native::dispatch_with(alice_env, || {
237-
assert_eq!(casper::get_caller(), ALICE);
238-
assert_eq!(
239-
cep18_handle
240-
.call(|cep18| cep18.my_balance())
241-
.expect("Should call"),
242-
U256::from(1000u64)
243-
);
244-
assert_eq!(
245-
cep18_handle
246-
.build_call()
247-
.call(|cep18| cep18.transfer(BOB, U256::from(1u64)))
248-
.expect("Should call"),
249-
Ok(())
250-
);
251-
})
252-
.expect("Success");
225+
assert_eq!(casper::get_caller(), ALICE);
226+
assert_eq!(
227+
cep18_handle
228+
.call(|cep18| cep18.my_balance())
229+
.expect("Should call"),
230+
U256::from(1000u64)
231+
);
232+
assert_eq!(
233+
cep18_handle
234+
.build_call()
235+
.call(|cep18| cep18.transfer(BOB, U256::from(1u64)))
236+
.expect("Should call"),
237+
Ok(())
238+
);
253239

254240
let bob_balance = cep18_handle
255241
.build_call()
@@ -263,8 +249,6 @@ mod tests {
263249
.expect("Should call");
264250
assert_eq!(alice_balance, U256::from(999u64));
265251
});
266-
267-
assert!(matches!(result, Ok(())));
268252
}
269253

270254
#[test]
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#Test contract proving functionality of vm2 collections
2+
[package]
3+
name = "vm2-collections-test"
4+
version = "0.1.0"
5+
edition = "2021"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
[lib]
9+
crate-type = ["cdylib", "rlib"]
10+
11+
[dependencies]
12+
const-fnv1a-hash = "1.1.0"
13+
casper-executor-wasm-common = { path = "../../../../executor/wasm_common" }
14+
borsh = { version = "1.5", features = ["derive"] }
15+
casper-contract-sdk = { path = "../../../vm2/sdk", features = ["testing"] }
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
fn main() {
2+
// Check if target arch is wasm32 and set link flags accordingly
3+
if std::env::var("TARGET").unwrap() == "wasm32-unknown-unknown" {
4+
println!("cargo:rustc-link-arg=--import-memory");
5+
println!("cargo:rustc-link-arg=--export-table");
6+
}
7+
}

0 commit comments

Comments
 (0)