Следующий код неполный. Что я хочу сделать, так это разделить bytes
данные (calldata) на две или более отдельных функций журнала для целей индексации.
Проблема в том, что я не могу понять, как это сделать в Solidity. bytes
имеет произвольную длину, поэтому я не могу скопировать данные вызова в память, поскольку нельзя выделить память произвольной длины (AFAICT из документации Solidity). Я также отмечаю, что приведенный ниже код упрощен — это будет не просто половина, это будет некоторая дробь, установленная в качестве другого параметра для logit
.
Я не совсем уверен, но когда я смотрю на скомпилированный вывод Solidity, мне кажется, что я мог бы реализовать это непосредственно в сборке EVM. инструкция EVM log1
принимает указатель и длину данных в качестве входных аргументов, поэтому это должно быть возможным. Приведенный ниже код работает, поэтому я знаю, что каким-то образом данные вызова произвольной длины могут быть отправлены в log1. Solidity просто не позволяет мне выполнять арифметику указателя для разделения данных (или я не могу понять, как это сделать). Я бы предпочел не писать код на ассемблере... (при необходимости я могу переключиться на Serpent).
Да, я мог бы сделать отдельные функции и разделить данные за пределами Ethereum. но тогда я несу штраф в размере 21 000 газа за каждый звонок. Я пытаюсь сделать это для низкой стоимости газа.
[EDIT] - да, я мог бы использовать до 7 параметров функции (максимум), но это дает мне только 7 разделений. Мне нужно порядка 64. Это то, что я получаю за попытку слишком упростить вопрос...
//
// attempt to figure out how to split incoming byte data into separate logs
//
contract HelpLogs {
event LogFirstHalf(bytes _data);
event LogSecondHalf(bytes _data);
function logit(bytes data) external {
// can't do the pointer arithmetic to LogFirstHalf and
// then LogSecondHalf of data. But I can log all of it...
LogFirstHalf(data);
}
}
Произвольный раздельный подход
Изменить: добавлен этот раздел для решения произвольных разделенных пунктов назначения.
К моменту разбиения вы должны знать длину целевых данных. Ниже приведен пример реализации копирования байтов в место назначения внутри Solidity, которое должно быть тривиально расширено до N сегментов.
pragma solidity ^0.4.15;
contract HelpLogs {
event LogFirstHalf(bytes _data);
event LogSecondHalf(bytes _data);
function logit(bytes data) external {
uint midpoint = data.length / 2;
bytes memory data1 = new bytes(midpoint);
for (uint i = 0; i < midpoint; i++) {
data1[i] = data[i];
}
bytes memory data2 = new bytes(data.length - midpoint);
for (i = 0; i < data.length - midpoint; i++) {
data2[i] = data[i + midpoint];
}
LogFirstHalf(data1);
LogSecondHalf(data2);
}
}
Обратите внимание, что потребление газа выше, чем должно быть, потому что оно работает побайтно. Было бы быстрее использовать 32-байтовые слова с битовой маской. Хорошей ссылкой является memcpy
библиотека утилит Solidity-String от Arachnid.
[Изменить: старое] Подход с фиксированным ведром
Вы можете разделить данные извне без накладных расходов в 21 кг газа. Отправьте предварительно разделенные данные в виде двух параметров в один вызов функции:
pragma solidity ^0.4.15;
contract HelpLogs {
event LogFirstHalf(bytes _data);
event LogSecondHalf(bytes _data);
function logit(bytes dataPart1, bytes dataPart2) external {
LogFirstHalf(dataPart1);
LogSecondHalf(dataPart2);
}
}
Это будет стоить меньше газа, чем расщепление внутри EVM.
solc
без использования --optimize
?bytes32[]
вместо , bytes
так как мои данные в любом случае действительно 32 байта (и это то, что также принимает log1), а стоимость регистрации каждой дополнительной 32-байтовой записи составляет 2620 газа. Первоначальная стоимость записи всего этого в один индекс составляла 2450 газа. Таким образом себестоимость копии составляет 170 газа. Я называю это хорошим. Спасибо!
резчик
Пол С