Сборка солидности, функция mstore и ширина слова в байтах - PullRequest
0 голосов
/ 03 июля 2018

Я изучаю Сборку Солидности и меня что-то смущает. Я смотрю на эту библиотеку под названием Seriality. В частности, эта функция: https://github.com/pouladzade/Seriality/blob/master/src/TypesToBytes.sol#L21

function bytes32ToBytes(uint _offst, bytes32 _input, bytes memory _output) internal pure {
    assembly {
        mstore(add(_output, _offst), _input)
        mstore(add(add(_output, _offst),32), add(_input,32))
    }
}

Эта функция bytes32ToBytes принимает переменную bytes32 и сохраняет ее в байтовом массиве динамического размера, начиная с переданного смещения.

Меня смущает то, что он дважды использует функцию mstore. Но функция mstore хранит слово размером 32 байта, верно? Так почему он вызывается дважды, учитывая, что входные данные составляют 32 байта? Разве при его вызове дважды не сохраняются 2 слова, что составляет 64 байта?

Спасибо!

1 Ответ

0 голосов
/ 03 июля 2018

Массивы солидности сохраняются путем записи размера массива в первый слот хранения, а затем записи данных в последующие слоты. Итак, разбив 2 утверждения:

mstore(add(_output, _offst), _input)

Поскольку первый слот массива указывает на размер массива, этот оператор устанавливает размер _output. Вы должны быть в состоянии получить тот же результат, заменив его на mstore(add(_output, _offst), 32) (так как размер _input является статическим).

Второй оператор (mstore(add(add(_output, _offst),32), add(_input,32))) - это тот, который записывает сами данные. Здесь мы смещаем положение обоих указателей на 32 байта (поскольку первые 32 байта для обоих массивов указывают на размер) и сохраняем значение _input в том месте, где хранятся данные для _output.

Скорее всего, _output будет уже инициализирован перед вызовом этого метода (поэтому длина будет уже установлена), поэтому обычно это не требуется. Но это не больно. Обратите внимание, что похожая реализация с таким предположением будет выглядеть так:

function test() public pure returns (bytes) {
    bytes32 i = "some message";
    bytes memory o = new bytes(32); // Initializing this way sets the length to the location "o" points to. This replaces mstore(add(_output, _offst), _input).
    bytes32ToBytes(0, i, o);

    return o;
}

function bytes32ToBytes(uint _offst, bytes32 _input, bytes memory _output) internal pure {
    assembly {
        mstore(add(add(_output, _offst),32), add(_input,32))
    }
}
...