Добрый день.
Разбираясь со смарт-контрактами 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
Автор: крепыш