Whitecoin-XWC / xwc-gjavac

Java and Kotlin compiler for uvm
MIT License
0 stars 0 forks source link

importContractFromAddress() Usage problem #3

Closed Molocher closed 2 years ago

Molocher commented 2 years ago

A simple contract API ping() is defined in gjavactestjavacontract/src/test/java/gjavac/test/simple/simpleContractTest.java file. When this method gets called in gjavactestjavacontract/src/test/java/gjavac/test/simple2/simpleContractTest.java like this:

`MultiOwnedContractSimpleInterface multiOwnedContractSimpleInterface = importContractFromAddress(MultiOwnedContractSimpleInterface.class, arg);
          return multiOwnedContractSimpleInterface.ping("");`

when the simple2 contract API is invoked for testing the interaction among contracts, an exception is raised:

8bab8c6002149e5ca79a7fac2ebd767

So far what we have got:

  1. The internal API importContractFromAddress() is commonly used for the interaction of XWC smart contracts, and it is widely used in the LUA smart contracts which all work well on the XWC chain, a simple assumption is that there is a improper use in the Java-written smart contract. We have also tried comparing the Java compiled .ass with Lua compiled .asm for the same simple logic, but failed to find the root cause.

  2. As the compiler works fine and the generated smart contract binary code can be deployed on the XWC chain without any problem, the issue happens during the runtime inside the UVM. We may need to check the source code of UVM and see what exactly this error refers to.

  3. Even for a simple case of calling importContractFromAddress() between smart contracts, it doesn't work as expected. Considering this is an important API used in Lua, we may need to find out what differences between Java and Lua compiled binary code.

Please help on this. Thanks a lot!

tobiasholt commented 2 years ago

It appears that the problem comes from the contract that gets called. We have made a test to use a LUA compiled smart contract, and a Java smart contract imports it and calls its API, it works as expected.

We need to go deeper on why UVM reports the error when a Java smart contract gets called.

tobiasholt commented 2 years ago

I have built a new UVM with some debug info and tried calling importContractFromAddress(), and found something new as described below:

In the scenario that contractB calls API of contractA, the reported error saying that "this contract byte stream not matched with the info stored in uvm api", it appears that on the UVM, contractA has an unexpected API "storage" for the contract written in JAVA. Compared with LUA contract, there is no such issue.

The related code of UVM is lauxlib.cpp: int luaL_import_contract_module_from_address(lua_State *L): When fetching APIs from the lua_State, the unexpected API is found and therefore an error is returned:

 if (stored_contract_info->contract_apis.size() != apis_count)
    {
        char error_msg[LUA_COMPILE_ERROR_MAX_LENGTH];
        snprintf(error_msg, LUA_COMPILE_ERROR_MAX_LENGTH - 1, "this contract byte stream not matched with the info stored in uvm api, need %d apis but only found %d", stored_contract_info->contract_apis.size(), apis_count);
        if (strlen(L->compile_error) < 1)
            memcpy(L->compile_error, error_msg, LUA_COMPILE_ERROR_MAX_LENGTH);
        global_uvm_chain_api->throw_exception(L, UVM_API_SIMPLE_ERROR, error_msg);
        uvm::lua::lib::notify_lua_state_stop(L);
        return 0;
    }

Next we need to find out why the "storage" is considered as an API.

Molocher commented 2 years ago

This problem occurs because,we code contract.setStorage(new Storage()); in ContractEntrypoint class, then,we remove the code,the smart contract can perfect execution image

tobiasholt commented 2 years ago

The probelm can be solved by removing the improper setStorage() function. However, need to figure out if an error/warning should be raised for such kind of improper usage. It is quite confused if everthing seems to work well and then an exception happens at runtime.

If it is confirmed that the function contract.setStorage() is useless, maybe we should consider removing it to avoid this potential issue.

tobiasholt commented 2 years ago

The issue has been fixed by changing the type of UvmContract.storage. var storage: T? = null to val storage: T? = null

The root cause is that. in kotlin, 'var' refers to 'variable', which by defaults has two methods: set() and get(), while 'val' refers to 'value' which by default has get() only.

The problem happens when the variable 'storage' defines the set() method implicitely. So changing 'var' to 'val' fixes this issue.

Now importContractFromAddress() works well and passed all testcases. So close this issue.