Skip links
missing functionalities on ink bg

Implementing Missing Functionalities On Ink! Integration Tests

Flattening the Anvil

To effectively flatten an anvil, one must identify its flaws and determine the necessary heat and pressure to correct them. A flat anvil is crucial for correcting other tools and armors. Similarly, in the context of ink! smart contracts, we view ink! integration and end-to-end (e2e) testing environments as anvils to resolve smart contract imperfections. However, we’ve noted that ink! integration tests, while faster, lack certain functionalities compared to e2e tests. Addressing these gaps could streamline and enhance the development process, potentially reducing times for testing and quality assurance.

Through the last month, we have been working hands down on improving the ink! testing environment for integration tests: our anvil. We did this as a part of our grant application On Ink Integration Test 2 to the Web3 Foundation; our second grant application working on improving ink! integration tests. This grant was focused on correcting some function implementations and completing the review of all the functions exposed for ink! integration and e2e tests.

Flattening Known Differences

As we worked on functions exposed for testing, we first tackled some problems with the functions: default_accounts(), set_contract_storage() and instantiate_contract(). We had identified these problems as part of our review of the testing environments in our previous milestone On Ink Integration Tests.

Default Accounts

For default_accounts(), we knew that default account addresses did not match across integration and e2e tests. In order to correct these differences, we worked to mimic on integration tests the account setup in e2e tests. We changed the name of the accounts “Django” to “Dave” and “Frank” to “Ferdie”. On the other hand, there were two accounts in e2e that did not exist in integration tests, accounts “one” and “two”. We added these accounts to integration tests. 

Moreover, since e2e tests were drawing these accounts from the library sp_keyring::sr25519::Keyring, we made integration tests depend on the same library in order to account for future changes in this lib.

Set Contract Storage

The function set_contract_storage() sets the storage in a contract. There was a missing validation in integration tests that was present in e2e. This validation checked that the size of the storage set did not exceed 16380 bytes.

We added a validation to the function set_contract_storage() in integration tests that checks the size of the input value against the same limit set in e2e tests: 16380 bytes. In case this limit is exceeded, a panic is raised with the message: “Value too large to be stored in contract storage, maximum size is {} bytes”.

Instantiate Contract

In order to allow contract instantiation, we modified the instantiate_contract() function to call the dispatch code generated by the ink! code generator.

We also added a new set_contract_storage_test() function in order to obtain the storage key of the contract, which is now called from the generated code. This function calls set_contract_storage() with a specially computed key. This was needed because the code generated for integration tests does not properly generate the storage key for the contract.

This way, instantiate_contract() can call contract constructors, allowing for the instantiation of contracts in integration tests.

Spotting New Differences

Of the universe of 24 functions under our analysis, we had a pending review of 13 functions. These were functions with implementations both for the integration and e2e environments, but that we had not been able to fully review in our previous milestone. They correspond to functions transferred_value(), weight_to_fee(), block_timestamp(), account_id(), balance(), block_number(), minimum_balance(), terminate_contract(), transfer(), hash_bytes(), hash_encoded() and ecdsa_recover().

As we documented and provided test cases for these functions, we observed that their implementations were mostly correct, with the exception of the functions weight_to_fee() and balances(). The first one always returned zero when invoked in the e2e environment, no matter the gas provided. For the latter, we observed that the initial balance differs in both environments. It is set to 1.000.000 in integration tests and to 1.000.000.000 in e2e tests.

Flattening the Workspace

Corrected imperfections need to remain flat. As we worked on integrating our test cases into CI/CD, we identified a bug when building e2e tests in a GitHub workspace. Concretely, we noticed that the build for e2e tests failed when running cargo-contract inside a workspace package, and if any dependency was inherited from the workspace definition. We performed a pull request to the cargo-contract repository implementing a fix to this issue.

Preparing for the final blows of the Hammer

Our work so far has been rewarding, but there are still some final blows of the hammer to completely flatten the anvil of ink! integration tests.

As we had noted in our previous analysis of the testing environments, 6 of the 24 functions exposed for their usage in integration tests remain unimplemented. These are functions: invoke_contract_delegate(), invoke_contract(), set_code_hash(), caller_is_origin(), code_hash() and own_code_hash(). The implementation of these functions depended on the development of instantiate_contract(), which we have already performed, so now we are ready to work on them as well.

Furthermore, we now need to add to the list of 6 functions above, the implementation of the functions weight_to_fee() and balance(), whose differences were spotted in our current review.

Looking forward, we are committed to flatten the anvil of integration tests, correcting these differences in our next milestone.