Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

x-contract-call failed: EVM execution error #9276

Closed
zqzqz opened this issue Aug 3, 2018 · 14 comments · Fixed by #9357
Closed

x-contract-call failed: EVM execution error #9276

zqzqz opened this issue Aug 3, 2018 · 14 comments · Fixed by #9357
Labels
Z1-question 🙋‍♀️ Issue is a question. Closer should answer.
Milestone

Comments

@zqzqz
Copy link

zqzqz commented Aug 3, 2018

Before filing a new issue, please provide the following information.

I'm running:

  • Which Parity version?: v2.1.0-unstable-1b1941a-20180724
  • Which operating system?: Linux Ubuntu 16.04
  • How installed?: from source
  • Are you fully synchronized?: no
  • Which network are you connected to?: Parity development chain
  • Did you try to restart the node?: yes

Your issue description goes here below. Try to include actual vs. expected behavior and steps to reproduce the issue.

I am trying to use wasm contracts on Parity development chain.
Contract is based on pwasm-tutorial: step5
Add one cross-contract function:

fn xTotalSupply(&mut self, addr: Address) -> U256 {
    let mut token = TokenClient::new(addr);
    token.totalSupply()
}

Call it through web3:

var xAddress = "0x60C7BB902469c7C3c258832326c16b7410CC273F";
// x-contract-call
TokenContract.methods.xTotalSupply(xAddress).call().then((b) => {
	console.log("supply of", xAddress, b);
}).catch(console.log);

note
Contract was built by nightly-2018-07-24.
Current TokenContract and TokenContract on xAddress are both successfully deployed.
Directly call totalSupply method of xAddress works well and return 10000000.
Other methods which don't have x-contract-calls works well.

expected behavior
print a supply of xAddress like supply of 0x60C7BB902469c7C3c258832326c16b7410CC273F 10000000

actual
web3:

Error: Returned error: VM execution error.
    at Object.ErrorResponse (/home/zqz/Documents/pwasm-tutorial/node_modules/web3-core-helpers/src/errors.js:29:16)
    at /home/zqz/Documents/pwasm-tutorial/node_modules/web3-core-requestmanager/src/index.js:140:36
    at XMLHttpRequest.request.onreadystatechange (/home/zqz/Documents/pwasm-tutorial/node_modules/web3-providers-http/src/index.js:77:13)
    at XMLHttpRequestEventTarget.dispatchEvent (/home/zqz/Documents/pwasm-tutorial/node_modules/xhr2/lib/xhr2.js:64:18)
    at XMLHttpRequest._setReadyState (/home/zqz/Documents/pwasm-tutorial/node_modules/xhr2/lib/xhr2.js:354:12)
    at XMLHttpRequest._onHttpResponseEnd (/home/zqz/Documents/pwasm-tutorial/node_modules/xhr2/lib/xhr2.js:509:12)
    at IncomingMessage.<anonymous> (/home/zqz/Documents/pwasm-tutorial/node_modules/xhr2/lib/xhr2.js:469:24)
    at emitNone (events.js:111:20)
    at IncomingMessage.emit (events.js:208:7)
    at endReadableNT (_stream_readable.js:1056:12)
    at _combinedTickCallback (internal/process/next_tick.js:138:11)
    at process._tickCallback (internal/process/next_tick.js:180:9)

Parity

2018-08-03 11:23:35   TRACE executive  ext.schedule.have_delegate_call: true
2018-08-03 11:23:35   TRACE wasm  Contract requested 2 pages of initial memory
2018-08-03 11:23:35   TRACE wasm  Contract custom panic message: <msg was stripped>, <unknown>:0:0
2018-08-03 11:23:35   TRACE wasm  Error executing contract: Trap(Trap { kind: Host(Panic("<msg was stripped>, <unknown>:0:0")) })
2018-08-03 11:23:35   TRACE executive  res=Err(Wasm("Wasm runtime error: Trap(Trap { kind: Host(Panic(\"<msg was stripped>, <unknown>:0:0\")) })"))
2018-08-03 11:23:35   TRACE executive  substate=Substate { suicides: {}, touched: {0xb7c78ed23bb1fd46ab6a2e1dda1fa08e0b940bba, 0x004ec07d2329997267ec62b4166639513386f32e}, logs: [], sstore_clears_count: 0x0, contracts_created: [] }; unconfirmed_substate=Substate { suicides: {}, touched: {}, logs: [], sstore_clears_count: 0x0, contracts_created: [] }

2018-08-03 11:23:35   TRACE executive  enacted: substate=Substate { suicides: {}, touched: {0xb7c78ed23bb1fd46ab6a2e1dda1fa08e0b940bba, 0x004ec07d2329997267ec62b4166639513386f32e}, logs: [], sstore_clears_count: 0x0, contracts_created: [] }

step to reproduce
Just use x-contract-calls. Maybe my way is wrong. I am not sure which module is responsible for this, sorry if this issue belongs another repo.

@Tbaut
Copy link
Contributor

Tbaut commented Aug 3, 2018

@pepyakin can you have a look?

@Tbaut Tbaut added the Z1-question 🙋‍♀️ Issue is a question. Closer should answer. label Aug 3, 2018
@Tbaut Tbaut added this to the 2.1 milestone Aug 3, 2018
@pepyakin
Copy link
Contributor

pepyakin commented Aug 3, 2018

Haven't worked with tutorial. I think @fckt should know better.

@lexfrl
Copy link
Contributor

lexfrl commented Aug 3, 2018

@zqzqz interesting. The contract call throws a panic.

2018-08-03 11:23:35   TRACE executive  ext.schedule.have_delegate_call: true
2018-08-03 11:23:35   TRACE wasm  Contract requested 2 pages of initial memory
2018-08-03 11:23:35   TRACE wasm  Contract custom panic message: <msg was stripped>, <unknown>:0:0

So, by default contracts are compiled without proper error reporting. This is because by default we want to have small binaries. In order to see the panic message you'll need to compile the contract with the pwasm-std/panic_with_msg feature on.

@zqzqz
Copy link
Author

zqzqz commented Aug 3, 2018

Thanks a lot @fckt . But I cannot figure out why "overflow" happens.

2018-08-04 01:01:55   TRACE wasm  Contract custom panic message: Integer overflow when casting U256, /home/zqz/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/bigint-4.4.0/src/uint.rs:969:1
2018-08-04 01:01:55   TRACE wasm  Error executing contract: Trap(Trap { kind: Host(Panic("Integer overflow when casting U256, /home/zqz/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/bigint-4.4.0/src/uint.rs:969:1")) })
2018-08-04 01:01:55   TRACE executive  res=Err(Wasm("Wasm runtime error: Trap(Trap { kind: Host(Panic(\"Integer overflow when casting U256, /home/zqz/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/bigint-4.4.0/src/uint.rs:969:1\")) })"))

Is there anyway to print more trace log?

@lexfrl
Copy link
Contributor

lexfrl commented Aug 4, 2018

This is the most verbose output we can provide for now, unfortunately..
A general recommendation is to use https://github.com/paritytech/pwasm-test to test contracts. It's actually pretty straightforward to use. So, in case if native test of particular API is successful, but it fails on chain with the same input, it's highly probably the issue is related to https://github.com/paritytech/pwasm-abi decoder to decode U256 from the data you pass through web3

Update:
The problem is with casting from U256 to u32 or u64 (https://github.com/paritytech/bigint/blob/91f6c7ad2cc5c1ebcada69842795faf4de886cc7/src/uint.rs#L319). Do you cast it somewhere it your code?

Here is a lot of examples on how to mock Endpoints, using pwasm-test: https://github.com/paritytech/pwasm-repo-contract/blob/master/contract/src/lib.rs#L453

@zqzqz
Copy link
Author

zqzqz commented Aug 4, 2018

Thank you @fckt .
No. As you see I only add one function onto tutorial step-5.
I will try pwasm_test first.. BTW some of my contracts are payable but I haven't found related samples in pwasm_test..

I noticed that parity_hash & bigint are combined into pwasm_abi::types. I am not sure whether they are exact same thing.

@lexfrl
Copy link
Contributor

lexfrl commented Aug 4, 2018

#payable adds nothing special, it just removes a check that ensures that call don't send any value:
https://github.com/paritytech/pwasm-abi/blob/master/derive/src/lib.rs#L247

Take a look on the tests also which demonstrates this:
https://github.com/paritytech/pwasm-abi/blob/master/tests/src/payable.rs

@zqzqz
Copy link
Author

zqzqz commented Aug 7, 2018

Please help, I struggled for a long time...: when using pwasm-test to test ccall (still on tutorial step-5. Only add a function xTotalSupply, add a test and change nothing else)

thread 'tests::test_cross_contract_call' panicked at 'already borrowed: BorrowMutError', libcore/result.rs:945:5

test code

#[cfg(test)]
#[allow(non_snake_case)]
mod tests {
    extern crate pwasm_test;
    extern crate std;
    use super::*;
    use pwasm_abi::types::*;
    use self::pwasm_test::{ext_reset, ext_get, ext_update};
    use token::{TokenInterface, TokenEndpoint};

    #[derive(Default)]
    struct TokenMock {
        totalSupply: U256
    }

    impl TokenInterface for TokenMock {
        fn constructor(&mut self, _total_supply: U256) {}
        fn totalSupply(&mut self) -> U256 {self.totalSupply}
        fn balanceOf(&mut self, _owner: Address) -> U256 {U256::zero()}
        fn transfer(&mut self, _to: Address, _amount: U256) -> bool {true}
        fn xTotalSupply(&mut self, addr: Address) -> U256 {U256::zero()}
    }

    #[test]
    fn test_cross_contract_call() {
        let TOKEN_ADDR = Address::from("0xea674fdde714fd979de3edf0f56aa9716b898ec8");
        let TOKEN_ADDR_2 = Address::from("0xdb6fd484cfa46eeeb73c71edee823e4812f9e2e1");
        ext_reset(|e| e.endpoint(TOKEN_ADDR.clone(), TokenEndpoint::new(TokenMock{totalSupply: 100.into()}).into()));
        let mut contract = token::TokenContract{};
        contract.constructor(U256::from(1000));
        assert_eq!(contract.xTotalSupply(TOKEN_ADDR.clone()), U256::from(100));
    }
}

xtotalSupply function and environment are the same as before.
Full trace:

stack backtrace:
   0:     0x56165055a21e - std::sys::unix::backtrace::tracing::imp::unwind_backtrace::he8af69b64cd628aa
                               at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1:     0x561650562726 - std::sys_common::backtrace::print::hd007d8131d52db53
                               at libstd/sys_common/backtrace.rs:71
                               at libstd/sys_common/backtrace.rs:59
   2:     0x56165055d88d - std::panicking::default_hook::{{closure}}::hd58f2759bdd5fc75
                               at libstd/panicking.rs:211
   3:     0x56165055d59b - std::panicking::default_hook::h2c1bf51c9795af05
                               at libstd/panicking.rs:221
   4:     0x56165055defc - std::panicking::rust_panic_with_hook::h28562f4ec57f2c02
                               at libstd/panicking.rs:475
   5:     0x56165055daf9 - std::panicking::continue_panic_fmt::h4ab0d82dd04b3311
                               at libstd/panicking.rs:390
   6:     0x56165055d9f5 - rust_begin_unwind
                               at libstd/panicking.rs:325
   7:     0x56165059d93b - core::panicking::panic_fmt::h792dec5e0563452a
                               at libcore/panicking.rs:77
   8:     0x56165052838b - core::result::unwrap_failed::h3059c5ab226c4095
                               at /checkout/src/libcore/macros.rs:26
   9:     0x561650527a45 - <core::result::Result<T, E>>::expect::hc1283168734a2cd1
                               at /checkout/src/libcore/result.rs:809
  10:     0x561650521c8a - <core::cell::RefCell<T>>::borrow_mut::h37286952b47f1afd
                               at /checkout/src/libcore/cell.rs:885
  11:     0x561650525a43 - pwasm_test::externs::value::{{closure}}::hb727eef41c9ae482
                               at /home/zqz/.cargo/git/checkouts/pwasm-test-39a0e1d235c78f6a/d7d59a2/src/externs.rs:221
  12:     0x561650535656 - <std::thread::local::LocalKey<T>>::try_with::haa88585b992067b4
                               at /checkout/src/libstd/thread/local.rs:294
  13:     0x561650534cdc - <std::thread::local::LocalKey<T>>::with::ha49d445d85ff1d02
                               at /checkout/src/libstd/thread/local.rs:248
  14:     0x5616505259f6 - value
                               at /home/zqz/.cargo/git/checkouts/pwasm-test-39a0e1d235c78f6a/d7d59a2/src/externs.rs:219
  15:     0x56165053a737 - pwasm_ethereum::ext::value::{{closure}}::h092b6f5a89c2b9f5
                               at /home/zqz/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/pwasm-ethereum-0.6.1/src/ext.rs:274
  16:     0x56165053a82b - pwasm_ethereum::ext::fetch_u256::h05c83af9fc88a18c
                               at /home/zqz/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/pwasm-ethereum-0.6.1/src/ext.rs:328
  17:     0x56165053a710 - pwasm_ethereum::ext::value::hbd8cbf383be5177f
                               at /home/zqz/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/pwasm-ethereum-0.6.1/src/ext.rs:274
  18:     0x5616504d8148 - <pwasm_tutorial_contract::token::pwasm_abi_impl_TokenInterface::TokenEndpoint<T> as pwasm_abi::eth::EndpointInterface>::dispatch::h92c3605df7ec0c4f
                               at src/lib.rs:21
  19:     0x5616504d97ad - <pwasm_test::external::Endpoint as core::convert::From<T>>::from::{{closure}}::hd7ed7dcdb4e40b67
                               at /home/zqz/.cargo/git/checkouts/pwasm-test-39a0e1d235c78f6a/d7d59a2/src/external.rs:38
  20:     0x56165052ad9f - <pwasm_test::external::ExternalInstance as pwasm_test::external::External>::call::hda26ca0692974ad5
                               at /home/zqz/.cargo/git/checkouts/pwasm-test-39a0e1d235c78f6a/d7d59a2/src/external.rs:222
  21:     0x56165052575f - pwasm_test::externs::ccall::{{closure}}::h8d0d1b17a9149410
                               at /home/zqz/.cargo/git/checkouts/pwasm-test-39a0e1d235c78f6a/d7d59a2/src/externs.rs:87
  22:     0x561650535410 - <std::thread::local::LocalKey<T>>::try_with::ha26adcc376cb2ce4
                               at /checkout/src/libstd/thread/local.rs:294
  23:     0x561650534c8d - <std::thread::local::LocalKey<T>>::with::h5484c6221144ee10
                               at /checkout/src/libstd/thread/local.rs:248
  24:     0x561650525579 - ccall
                               at /home/zqz/.cargo/git/checkouts/pwasm-test-39a0e1d235c78f6a/d7d59a2/src/externs.rs:82
  25:     0x56165053a63d - pwasm_ethereum::ext::call::ha28dbb44a45f8991
                               at /home/zqz/.cargo/registry/src/git.luolix.top-1ecc6299db9ec823/pwasm-ethereum-0.6.1/src/ext.rs:178
  26:     0x5616504d93d2 - <pwasm_tutorial_contract::token::pwasm_abi_impl_TokenInterface::TokenClient as pwasm_tutorial_contract::token::TokenInterface>::totalSupply::h713bb5646dc1fb15
                               at src/lib.rs:21
  27:     0x5616504d7814 - <pwasm_tutorial_contract::token::TokenContract as pwasm_tutorial_contract::token::TokenInterface>::xTotalSupply::hf8d12f069366d87e
                               at src/lib.rs:80
  28:     0x5616504d8b5b - pwasm_tutorial_contract::tests::test_cross_contract_call::hd3aa39376ee2eb04
                               at src/lib.rs:159
  29:     0x5616504d8a19 - pwasm_tutorial_contract::__test::TESTS::{{closure}}::hca08ab7b4fe78736
                               at src/lib.rs:153
  30:     0x5616504d700d - core::ops::function::FnOnce::call_once::h1825269b6f259229
                               at /checkout/src/libcore/ops/function.rs:223
  31:     0x5616504db5ce - <F as alloc::boxed::FnBox<A>>::call_box::h784bfed044a7dade
                               at libtest/lib.rs:1454
                               at /checkout/src/libcore/ops/function.rs:223
                               at /checkout/src/liballoc/boxed.rs:640
  32:     0x56165056dad9 - __rust_maybe_catch_panic
                               at libpanic_unwind/lib.rs:106
  33:     0x5616504fc81f - std::sys_common::backtrace::__rust_begin_short_backtrace::had8acf97ae9fba87
                               at /checkout/src/libstd/panicking.rs:289
                               at /checkout/src/libstd/panic.rs:392
                               at libtest/lib.rs:1409
                               at /checkout/src/libstd/sys_common/backtrace.rs:136
  34:     0x5616504fd1d4 - std::panicking::try::do_call::h1b933231eb7ababb
                               at /checkout/src/libstd/thread/mod.rs:409
                               at /checkout/src/libstd/panic.rs:313
                               at /checkout/src/libstd/panicking.rs:310
  35:     0x56165056dad9 - __rust_maybe_catch_panic
                               at libpanic_unwind/lib.rs:106
  36:     0x5616504f0d36 - <F as alloc::boxed::FnBox<A>>::call_box::h4851a7bb75269daa
                               at /checkout/src/libstd/panicking.rs:289
                               at /checkout/src/libstd/panic.rs:392
                               at /checkout/src/libstd/thread/mod.rs:408
                               at /checkout/src/liballoc/boxed.rs:640
  37:     0x5616505505aa - std::sys_common::thread::start_thread::h6e6e5463379d96da
                               at /checkout/src/liballoc/boxed.rs:650
                               at libstd/sys_common/thread.rs:24
  38:     0x56165054f5c5 - std::sys::unix::thread::Thread::new::thread_start::h88b4b915a61173c4
                               at libstd/sys/unix/thread.rs:90
  39:     0x7fac5e1d06b9 - start_thread
  40:     0x7fac5dcf041c - clone
  41:                0x0 - <unknown>

@lexfrl
Copy link
Contributor

lexfrl commented Aug 7, 2018

What happens in

contract.xTotalSupply(TOKEN_ADDR.clone());

?

The problem is that pwasm-test do not support nested calls currently. For example, if xTotalSupply makes a call and that call leads to another call, it will panic. So the solution is: you need to mock every call to prevent nested calls.

@zqzqz
Copy link
Author

zqzqz commented Aug 7, 2018

See my first comment

fn xTotalSupply(&mut self, addr: Address) -> U256 {
    let mut token = TokenClient::new(addr);
    token.totalSupply()
}

@lexfrl
Copy link
Contributor

lexfrl commented Aug 7, 2018

Now I understand the issue.

  11:     0x561650525a43 - pwasm_test::externs::value::{{closure}}::hb727eef41c9ae482
                               at /home/zqz/.cargo/git/checkouts/pwasm-test-39a0e1d235c78f6a/d7d59a2/src/externs.rs:221

By adding#payable (like here https://github.com/paritytech/pwasm-abi/blob/master/tests/src/payable.rs#L70) attribute to the totalSupply method it will remove the inner pwasm_test::externs::value call and test will pass.

For example, if xTotalSupply makes a call and that call leads to another call, it will panic

It's clearly a valid problem with pwasm-test which needs to be solved.

@zqzqz
Copy link
Author

zqzqz commented Aug 8, 2018

Thanks. Yes the test passes by adding #payable label as you said.
Note that c-call through web3 still not working (use web3 call API to invoke constant function xTotalSupply). I am not sure whether you can reproduce that.

@lexfrl
Copy link
Contributor

lexfrl commented Aug 8, 2018

Made a fix for it openethereum/pwasm-test#32

@zqzqz
Copy link
Author

zqzqz commented Aug 9, 2018

Whatever kind of x-contract-call I tried, they all failed with U256 overflow. I don't think it's an accident in my code when casting U256 to u32 or u64 (actually I never do this casting manually).
Official example of x-contract-call was only found in pwasm-repo-contract, which is dated though.
Please reproduce x-contract-call on latest parity master to confirm that.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Z1-question 🙋‍♀️ Issue is a question. Closer should answer.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants