Off-Chain Test (endowment) Does Not Work
sulnong opened this issue · 5 comments
Environment:
cargo-contract : 0.17.0-unknown-x86_64-macos
ink version: 3.0.0-rc8
Describe the bug
Following is my contract code:
/// Deposit
#[ink(message, payable)]
pub fn deposit(&mut self) {
let caller = self.env().caller();
let deposited = self.env().transferred_value();
let mut balance = self.balance_of(&caller);
balance += deposited;
self.balances.insert(caller, balance);
}
In off-chain test (run with command cargo +nightly test
), i got self.env().transferred_value() correctly, but account (who call this execution) balance have no change.
That makes test failed.
Following is test code:
#[ink::test]
fn deposit_works() {
// Use Alice as contract owner
let accounts = default_accounts();
let alice = accounts.alice;
let bob = accounts.bob;
let eve = accounts.eve;
set_sender(alice, None);
let mut contract = Bytepay::new();
// Bob Deposit
set_balance(bob, 200);
set_sender(bob, Some(100));
contract.deposit();
assert_eq!(contract.get(), 100);
// Eve havn't deposit
set_balance(eve, 200);
set_sender(eve, None);
assert_eq!(contract.get(), 0);
assert_eq!(get_balance(eve), 200);
}
fn set_sender(sender: AccountId, endowment: Option<Balance>) {
let callee = ink_env::account_id::<ink_env::DefaultEnvironment>();
test::push_execution_context::<Environment>(
sender,
callee,
1000000,
endowment.unwrap_or(0),
test::CallData::new(call::Selector::new([0x00; 4])), // dummy
);
}
fn default_accounts() -> ink_env::test::DefaultAccounts<ink_env::DefaultEnvironment> {
ink_env::test::default_accounts::<ink_env::DefaultEnvironment>()
.expect("Off-chain environment should have been initialized already")
}
fn set_balance(account_id: AccountId, balance: Balance) {
ink_env::test::set_account_balance::<ink_env::DefaultEnvironment>(account_id, balance)
.expect("Cannot set account balance");
}
fn get_balance(account_id: AccountId) -> Balance {
ink_env::test::get_account_balance::<ink_env::DefaultEnvironment>(account_id)
.expect("Cannot set account balance")
}
}
I wander if i coding incorrect or this is off-chain test problem.
/// Deposit
#[ink(message, payable)]
pub fn deposit(&mut self) {
let caller = self.env().caller();
let deposited = self.env().transferred_value();
println!("deposited: {}", deposited);
let mut balance = self.balance_of(&caller);
balance += deposited;
self.balances.insert(caller, balance);
}
#[ink::test]
fn deposit_works() {
// Use Alice as contract owner
let accounts = default_accounts();
let alice = accounts.alice;
let bob = accounts.bob;
let eve = accounts.eve;
set_sender(alice, None);
let mut contract = Bytepay::new();
// Bob Deposit
set_balance(bob, 200);
set_sender(bob, Some(100));
contract.deposit();
assert_eq!(contract.get(), 100);
assert_eq!(get_balance(bob), 100);
// Eve havn't deposit
set_balance(eve, 200);
set_sender(eve, None);
assert_eq!(contract.get(), 0);
assert_eq!(get_balance(eve), 200);
}
running 5 tests
test bytepay::tests::set_whitelist_works ... ok
test bytepay::tests::contract_init_works ... ok
test bytepay::tests::transfer_works ... ok
test bytepay::tests::withdraw_works ... FAILED
test bytepay::tests::deposit_works ... FAILED
failures:
---- bytepay::tests::withdraw_works stdout ----
deposited: 100
thread 'bytepay::tests::withdraw_works' panicked at 'assertion failed: self.env().transfer(caller, amount).is_ok()', lib.rs:70:13
---- bytepay::tests::deposit_works stdout ----
deposited: 100
thread 'bytepay::tests::deposit_works' panicked at 'assertion failed: `(left == right)`
left: `200`,
right: `100`', lib.rs:162:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
bytepay::tests::deposit_works
bytepay::tests::withdraw_works
test result: FAILED. 3 passed; 2 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
After call contract.deposit(), bob'account balance shoule be 100, we can see in the console deposited: 100
But assert_eq!(get_balance(bob), 100) failed.
Tbh this looks fine to me. Even looking at the contract-transfer
example it doesn't seem like the contract_id
and eve
's balances get updated correctly, so maybe there are some quirks around transfers in the test environment.
@cmichi can you take a look since you know about this better than me?
Further to this, testing does not seem to work at all using ink_env::test module. I followed these steps to run tests related with balances and set_caller:
add ink-experimental-engine = ["ink_env/ink-experimental-engine"] to Cargo.toml
add #[cfg(feature = "ink-experimental-engine")] above mod tests {}
despite this, ink_env::tests::default_accounts() is not found, nor is ink_env::tests::set_caller() working. It is only possible to test pure rust parts of the smart contracts that don't involve transfers or various accounts other than the constructor caller.
error[E0425]: cannot find function set_caller
in module ink_env::test
--> pixelland_map/lib.rs:194:28
|
194 | ink_env::test::set_caller::<ink_env::DefaultEnvironment>(accounts.bob);
| ^^^^^^^^^^ not found in ink_env::test
error[E0609]: no field bob
on type std::result::Result<DefaultAccounts<DefaultEnvironment>, ink_env::Error>
--> pixelland_map/lib.rs:194:79
|
194 | ink_env::test::set_caller::<ink_env::DefaultEnvironment>(accounts.bob);
| ^^^
error[E0609]: no field bob
on type std::result::Result<DefaultAccounts<DefaultEnvironment>, ink_env::Error>
--> pixelland_map/lib.rs:202:42
|
202 | assert_eq!(result3, accounts.bob);
| ^^^