- PVSM.RU - https://www.pvsm.ru -

Solidity, интересная особенность при использовании библиотеки

Добрый день.

Разбираясь со смарт-контрактами Ethereum [1](Solidity [2]) столкнулся с одной интересной особенностью использования библиотек (library), о которой вроде как прямо нигде не написано (по крайне мере я не нашел).

Если коротко:

1. Пусть у нас будет библиотека, в которой объявим структуру и функцию работы с ней (обратите внимание, что функция объявлена как public)

library TestLib {    
    struct One { … }
     function setVal( One storage _one, … ) public {…}
}

2. Пусть у нас будет контракт, который использует эту библиотеку

contract TestContract {
    using TestLib for TestLib.One;
    TestLib.One one;    
    function setVal( … ) public {
        one.setVal( … );        
    }    
}

При этом все будет нормально компилироваться и работать в remix [3], да и тесты в truffle [4]на ganache-cli [5] выполнятся без шибок. Так же без ошибок будет деплой. Далее для вызова контрактов мы используем web3j [6](через консоль geth [7]будет схожее поведение).

И вот тут, при попытке вызвать метод контракта setVal, возникает мало информационная ошибка:

java.lang.IndexOutOfBoundsException: Index: 0

Проблема именно в том, что функции библиотеки, в аргументах которых есть переменные типа структуры, объявлены как public.

Надо отметить, что в контракте функция такого вида:

function setVal( TestLib.One _one ) public {...}

просто не скомпилируются.

Не совсем для меня понятно, почему компилятор не считает за ошибку наличие такой функции в библиотеке. Ну и ошибка выполнения, конечно, не раскрывает суть проблемы.

Особенно запутывает случай, если вдруг функция установки значения была internal, а функция получения – public. В этом случае может сложиться ложно представление, что функция установки работает не верно, т.к. при попытке получения данных видя сообщения исключения начинаешь думать, что в переменную структуры ничего не положили. Что и получилось с нашим проектом. Это привело к усиленному гуглению, проверки версий и прочее. А все, как часто бывает, оказалось намного проще: надо заменить public на internal.

Надеюсь, заметка сэкономит пару часов Вашего драгоценного времени, если вдруг столкнетесь с таким вот странным, поведением казалось бы, простых контракта и библиотеки.

Полезные ссылки:
Зачем использовать библиотеки в solidity [8]
Library Driven Development of Solidity [9]
Как вызвать контракт в консоли geth [10]

Автор: крепыш

Источник [11]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/solidity/286483

Ссылки в тексте:

[1] Ethereum : https://www.ethereum.org/

[2] Solidity: http://solidity.readthedocs.io/en/v0.4.24/)

[3] remix: https://remix.ethereum.org

[4] truffle : https://truffleframework.com/

[5] ganache-cli: https://github.com/trufflesuite/ganache-cli

[6] web3j : https://github.com/web3j/web3j

[7] geth : https://github.com/ethereum/go-ethereum/wiki/geth

[8] Зачем использовать библиотеки в solidity: http://www.zohaib.me/reusable-code-in-solidity-using-library/

[9] Library Driven Development of Solidity: https://medium.com/@kidinamoto/library-driven-development-of-solidity-ec7b0b41f38

[10] Как вызвать контракт в консоли geth: https://ethereum.stackexchange.com/questions/3514/how-to-call-a-contract-method-using-the-eth-call-json-rpc-api/3520

[11] Источник: http://habrahabr.ru/sandbox/122617/