Как сделать подпись функции? Контрактный приемник ERC223

Привет, что означают эти строки?

function tokenFallback(address _from, uint _value, bytes _data) {
    ...
    uint32 u = uint32(_data[3]) + (uint32(_data[2]) << 8) + (uint32(_data[1]) << 16) + (uint32(_data[0]) << 24);
    tkn.sig = bytes4(u);
}

Я знаю, что tkn.sig - это 4-байтовая подпись функции. Но может ли кто-нибудь объяснить, как работают эти две строки?

Ответы (2)

tokenFallbackполучает третий параметр , _dataкоторым могут быть любые произвольные данные. То, как это интерпретируется контрактом, во многом зависит от контракта. Код, который вы вставили, похоже, просто преобразует первые четыре байта _dataв a bytes4для хранения в tkn.sig. Я не могу предположить, почему, не видя остальной код. (Например, было бы интересно посмотреть, как tknиспользуется.)

РЕДАКТИРОВАТЬ

Похоже, код исходит из https://github.com/Dexaran/ERC223-token-standard/blob/Recommended/Receiver_Interface.sol#L17 . Остальная часть функции, включая комментарий, освещается:

function tokenFallback(address _from, uint _value, bytes _data){
    TKN memory tkn;
    tkn.sender = _from;
    tkn.value = _value;
    tkn.data = _data;
    uint32 u = uint32(_data[3]) + (uint32(_data[2]) << 8) + (uint32(_data[1]) << 16) + (uint32(_data[0]) << 24);
    tkn.sig = bytes4(u);

    /* tkn variable is analogue of msg variable of Ether transaction
    *  tkn.sender is person who initiated this token transaction   (analogue of msg.sender)
    *  tkn.value the number of tokens that were sent   (analogue of msg.value)
    *  tkn.data is data of token transaction   (analogue of msg.data)
    *  tkn.sig is 4 bytes signature of function
    *  if data of token transaction is a function execution
    */
}

Я предполагаю, что _dataздесь рассматривается сценарий без токена, где первые четыре байта являются селектором функции (первые четыре байта хэша keccak256 сигнатуры функции). Предположительно, это делается для того, чтобы получатель токена мог вызывать функцию для обработки входящих токенов, подобно тому, как payableфункция обрабатывает входящие транзакции.

http://solidity.readthedocs.io/en/develop/types.html#fixed-size-byte-arrays
Массивы байтов фиксированного размера
bytes1, bytes2, bytes3, …, bytes32. byte — это псевдоним для bytes1.
----------------==
http://solidity.readthedocs.io/en/develop/types.html#dynamically-sized-byte-array
Байты массива байтов с динамическим размером: Массив байтов с динамическим размером, см. Массивы. Не тип значения!
----------------==
http://solidity.readthedocs.io/en/develop/types.html#arrays
Переменные типа bytes и string представляют собой специальные массивы. Байты похожи на byte[], но они плотно упакованы в calldata. строка равна байтам, но не разрешает доступ к длине или индексу (на данный момент). Таким образом, байтам всегда следует отдавать предпочтение, а не байту [], потому что это дешевле.
----------------==
Таким образом, аргумент bytes _data означает: _data — массив байтов с динамическим размером, и каждый элемент имеет тип byte1
_data[3], _data[2], _data[1], _data[0] — первые 4 элемента _data
uint32 (_data[3]) должен преобразовать _data[3] в число uint32
----------------==
http://solidity.readthedocs.io/en/develop/ types.html#integers
** (возведение в степень), << (сдвиг влево), >> (сдвиг вправо)
Выражение x << y эквивалентно x * 2** y, а x >> y эквивалентно x / 2**y
----------------==
Итак, uint32(_data[2]) << 8 эквивалентно uint32(_data[2]) * 2**8
то же самое для _data[1] и _data[0]
затем добавьте их все вместе, чтобы сделать uint32 u
, затем преобразуйте u в bytes4 bytes4(u)
Ого, как сложно... Надеюсь, я не ошибся :)

Все выглядит правильно.