Надежность преобразование шестнадцатеричного числа в шестнадцатеричную строку

#bit-manipulation #solidity #rsk

Вопрос:

Мне нужно сохранить значение такого рода 0xff0000 или 0x00ff08 (шестнадцатеричное цветовое представление) в смарт-контракте solidity и иметь возможность преобразовать его внутри контракта в строку с теми же текстовыми символами "ff0000" . Я намерен развернуть этот смарт-контракт на RSK.

Моя идея состояла в том, чтобы сохранить эти значения в переменной bytes3 или просто uint и иметь чистую функцию, преобразующую bytes3 или uint в соответствующую строку. Я нашел функцию, которая выполняет эту работу и работает над солидностью 0.4.9

 pragma solidity 0.4.9;

contract UintToString {
    function uint2hexstr(uint i) public constant returns (string) {
        if (i == 0) return "0";
        uint j = i;
        uint length;
        while (j != 0) {
            length  ;
            j = j >> 4;
        }
        uint mask = 15;
        bytes memory bstr = new bytes(length);
        uint k = length - 1;
        while (i != 0){
            uint curr = (i amp; mask);
            bstr[k--] = curr > 9 ? byte(55   curr ) : byte(48   curr); // 55 = 65 - 10
            i = i >> 4;
        }
        return string(bstr);
    }
}
 

Но мне нужна более свежая версия компилятора (по крайней мере, 0.8.0). Вышеуказанная функция не работает в более новых версиях.

Каков способ преобразования bytes или uint в шестнадцатеричную строку (1->’1′,f->>’f’), что работает в Solidity >>>=0.8.0 ?

Ответ №1:

Следующие компиляции и были протестированы с использованием solc 0.8.7. Это то же самое, что и ваша исходная версия, со следующими изменениями:

  • constant —> pure
  • returns (string) —> returns (string memory)
  • byte(...) —> bytes1(uint8(...))

Вышеуказанные изменения преодолели все различия во времени компиляции в вашей исходной функции. … однако все еще существовала ошибка во время выполнения, из-за которой эта функция возвращалась:

Во время отладки строка bstr[k--] = curr > 9 ? инициировала возврат на последней итерации цикла, в котором она находилась. Это было связано с тем, что цикл while был настроен таким образом, что k находился 0 на своей последней итерации.

Хотя идентификация была сложной, исправление было простым: измените оператор декремента с постфиксного на префиксный — bstr[--k] = curr > 9 ? .

В сторону:

Вопрос: Почему это не вернулось при компиляции в solc 0.4.9, но вернулось, когда тот же код был скомпилирован в solc 0.8.7?

A: в solc 0.8.0 было внесено критическое изменение, в котором компилятор вставил проверки переполнения и недостаточного потока uint. До этого нужно было бы использовать SafeMath или что-то подобное, чтобы сделать то же самое. См. раздел «Тихие изменения семантики» в примечаниях к выпуску solc 0.8

 pragma solidity >=0.8;

contract TypeConversion {
    function uint2hexstr(uint i) public pure returns (string memory) {
        if (i == 0) return "0";
        uint j = i;
        uint length;
        while (j != 0) {
            length  ;
            j = j >> 4;
        }
        uint mask = 15;
        bytes memory bstr = new bytes(length);
        uint k = length;
        while (i != 0) {
            uint curr = (i amp; mask);
            bstr[--k] = curr > 9 ?
                bytes1(uint8(55   curr)) :
                bytes1(uint8(48   curr)); // 55 = 65 - 10
            i = i >> 4;
        }
        return string(bstr);
    }
}