Verknüpfen Sie zwei Byte-Arrays mit Assembly

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, forSchleifen hier zu vermeiden?

Antworten (2)

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;
}

https://github.com/ethereum/solidity-examples

online var dest2 = dest + src2Len, sollte es nicht stattdessen sein var dest2 = dest + srcLen. Beachten Sie die Änderung von src2Lenzu srcLen?