Кто-нибудь знает, как эффективно объединять двухбайтовые массивы с языком ассемблера, чтобы сэкономить затраты на газ? В настоящее время у меня есть
function mergeBytes(bytes param1, bytes param2) returns (bytes) {
bytes memory merged = new bytes(param1.length + param2.length);
uint k = 0;
for (uint i = 0; i < param1.length; i++) {
merged[k] = param1[i];
k++;
}
for (i = 0; i < param2.length; i++) {
merged[k] = param2[i];
k++;
}
return merged;
}
Есть ли способ избежать for
петель здесь?
Вот что я написал для этой цели.
function MergeBytes(bytes memory a, bytes memory b) public pure returns (bytes memory c) {
// Store the length of the first array
uint alen = a.length;
// Store the length of BOTH arrays
uint totallen = alen + b.length;
// Count the loops required for array a (sets of 32 bytes)
uint loopsa = (a.length + 31) / 32;
// Count the loops required for array b (sets of 32 bytes)
uint loopsb = (b.length + 31) / 32;
assembly {
let m := mload(0x40)
// Load the length of both arrays to the head of the new bytes array
mstore(m, totallen)
// Add the contents of a to the array
for { let i := 0 } lt(i, loopsa) { i := add(1, i) } { mstore(add(m, mul(32, add(1, i))), mload(add(a, mul(32, add(1, i))))) }
// Add the contents of b to the array
for { let i := 0 } lt(i, loopsb) { i := add(1, i) } { mstore(add(m, add(mul(32, add(1, i)), alen)), mload(add(b, mul(32, add(1, i))))) }
mstore(0x40, add(m, add(32, totallen)))
c := m
}
}
Я новичок в программировании Эфириума, поэтому может быть ошибка или какие-то явные оптимизации, которые можно сделать, но я протестировал этот код в Remix. Для 2 5-байтовых массивов это стоило около 1500 газа, с 2 большими (длиной ~ 40 байт) массивами байтов это стоило около 1700 газа. Похоже, что это примерно 100 единиц газа на 32 байта.
Пожалуйста, дайте мне знать, есть ли какие-либо явные оптимизации, поскольку я использую это в своем собственном контракте!
Изменить: я внес изменение в алгоритм, так как он не работал для байтовых массивов длиной >32 байта.
Как можно найти в репозитории Solidity- Examples, предоставленном Foundation, это выглядит так:
function concat(bytes memory self, bytes memory other)
returns (bytes memory) {
bytes memory ret = new bytes(self.length + other.length);
var (src, srcLen) = Memory.fromBytes(self);
var (src2, src2Len) = Memory.fromBytes(other);
var (dest,) = Memory.fromBytes(ret);
var dest2 = dest + srcLen;
Memory.copy(src, dest, srcLen);
Memory.copy(src2, dest2, src2Len);
return ret;
}
Марсело Форнет
var dest2 = dest + src2Len
, не должно быть вместо этогоvar dest2 = dest + srcLen
. Обратите внимание на изменение сsrc2Len
наsrcLen
?