Weiß jemand, wie man zwei Byte-Arrays mit Assembler-Sprache effizient zusammenfügt, um Gaskosten zu sparen? Aktuell habe ich
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;
}
Gibt es eine Möglichkeit, for
Schleifen hier zu vermeiden?
Hier ist etwas, was ich zu diesem Zweck geschrieben habe.
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
}
}
Ich bin neu in der Ethereum-Programmierung, daher kann es einen Fehler oder einige klare Optimierungen geben, die vorgenommen werden können, aber ich habe diesen Code in Remix getestet. Für 2 5-Byte-Arrays kostete es ungefähr 1500 Gas, mit 2 größeren (~ 40 Byte langen) Byte-Arrays kostete es ungefähr 1700 Gas. Es sieht nach einer Erhöhung von etwa 100 Gas pro 32 Bytes aus.
Bitte teilen Sie mir mit, ob es eindeutige Optimierungen gibt, da ich diese in meinem eigenen Vertrag verwende!
Bearbeiten: Ich habe den Algorithmus geändert, da er für Byte-Arrays mit einer Länge von mehr als 32 Bytes nicht funktionierte.
Wie im von Foundation bereitgestellten solidity-examples- Repository zu finden ist, geht es so:
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
, sollte es nicht stattdessen seinvar dest2 = dest + srcLen
. Beachten Sie die Änderung vonsrc2Len
zusrcLen
?