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

в 11:10, , рубрики: 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

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

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js