Pull to refresh

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

Добрый день.

Разбираясь со смарт-контрактами Ethereum (Solidity) столкнулся с одной интересной особенностью использования библиотек (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, да и тесты в truffle на ganache-cli выполнятся без шибок. Так же без ошибок будет деплой. Далее для вызова контрактов мы используем web3j (через консоль geth будет схожее поведение).

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

java.lang.IndexOutOfBoundsException: Index: 0

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

Надо отметить, что в контракте функция такого вида:
function setVal( TestLib.One _one ) public {...}

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

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

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

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

Полезные ссылки:
Зачем использовать библиотеки в solidity
Library Driven Development of Solidity
Как вызвать контракт в консоли geth
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.
Change theme settings