4

Does anyone know how to efficiently concat two bytes arrays with assembly language to save gas costs? Currently I have

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

Is there a way to avoid for loops here?

2

Here's something I wrote for this purpose.

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

I'm new to ethereum programming, so there may be a mistake or some clear optimizations that can be made, but I tested this code in Remix. For 2 5 bytes arrays it costed about 1500 gas, with 2 larger (~ 40 bytes long) bytes arrays it costed about 1700 gas. It looks to be about a 100 gas increase per 32 bytes.

Please let me know if there are any clear optimizations as I'm using this in my own contract!

Edit: I made a change in the algorithm as it didn't work for byte arrays >32 bytes long.

0

As can be found in solidity-examples repository provided from Foundation, it goes like this,

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 + src2Len;
     Memory.copy(src, dest, srcLen);
     Memory.copy(src2, dest2, src2Len);
     return ret;
}

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.