¿Alguien sabe cómo concatenar de manera eficiente matrices de dos bytes con lenguaje ensamblador para ahorrar costos de gasolina? Actualmente tengo
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;
}
¿Hay alguna manera de evitar for
bucles aquí?
Aquí hay algo que escribí para este propósito.
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
}
}
Soy nuevo en la programación de ethereum, por lo que puede haber un error o algunas optimizaciones claras que se pueden hacer, pero probé este código en Remix. Para 2 arreglos de 5 bytes costaba alrededor de 1500 de gas, con 2 arreglos de bytes más grandes (~ 40 bytes de largo) costaba alrededor de 1700 de gas. Parece ser un aumento de aproximadamente 100 gases por cada 32 bytes.
¡Avíseme si hay optimizaciones claras ya que estoy usando esto en mi propio contrato!
Editar: hice un cambio en el algoritmo ya que no funcionó para matrices de bytes> 32 bytes de largo.
Como se puede encontrar en el repositorio solidity-examples proporcionado por Foundation, es así:
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;
}
marcelo fornet
var dest2 = dest + src2Len
, ¿no debería ser en su lugarvar dest2 = dest + srcLen
. Observe el cambio desrc2Len
asrcLen
?