6

I have tried to implement a simple cellular automaton logic using two different ways to track the final state:

  1. Track every iteration in a multi-dimensional array.
  2. Store only the last two iterations.

Since updates are cheaper than storing new elements I expected the second contract to be more cost efficient, but it is not.

Below is the code for both versions. The function being benchmarked is advance. The way I measure costs is just by looking at the Transaction Cost value in the Remix output.

Contract V1:

contract Rule90 {
    bool[][] state;
    
    constructor() {
        state.push([false,false,true,false,false]);
    }
    
    function newState(bool a, bool b, bool c) private pure returns (bool y) {
        //...
    }
    
    function advance() public {
        uint iter = state.length;
        bool[] memory last = state[iter-1];
        uint newLength = last.length+2;
        bool[] memory next = new bool[](newLength);
        for (uint i=1; i < last.length-1; i++) {
          next[i+1] = newState(last[i-1], last[i], last[i+1]);   
        }
        state.push(next);
    }
}

Contract V2:

contract Rule90 {
    bool[] s1;
    bool[] s2;
    
    bool useS1 = false;
    
    constructor() {
        s1 = [false, false,true,false,false];
        s2 = [false, false];
    }
    
    function newState(bool a, bool b, bool c) private pure returns (bool y) {
        //...
    }
    
    function advance() public {
        if (useS1) {
            advanceState(s1, s2);
        } else {
            advanceState(s2, s1);
        }
        useS1 = !useS1;
    }
    
    function advanceState(bool[] storage current, bool[] storage prev) private {
        bool x;
        uint n = current.length;
        for (uint i=1; i<prev.length-1; i++) {
            x = newState(prev[i-1], prev[i], prev[i+1]);
            if (i+1 > n-1) {
                current.push(x);
            } else {
                current[i+1] = x;
            }
        }
        current.push(false);
        current.push(false);
    }
}

There are additional two push instructions in the Contract V2 compared to creating a fixed memory array and at the end appending it to a multi-dimensional array.

Any ideas why the second contract costs more?

Update

Gas prices plot where x axis is iteration and y axis cost of calling advance method: enter image description here

3
  • 1
    What version of solidity are you using?
    – PREEB
    Jun 12, 2021 at 18:25
  • I ran your contracts on remix. V1 used 70441 gas, V2 on first run used 62501 gas, and V2 second run (since your advance toggles which array to loop over) used 26048 gas. I'm not sure I see what you're seeing. Can you post gas prices you're seeing?
    – PREEB
    Jun 12, 2021 at 18:32
  • 2
    @thepriebe I use 0.8.5. I have also benchmarked both contracts for 30 iterations and made a plot of gas prices which is added to the updated question. Jun 13, 2021 at 12:26

1 Answer 1

0

The second version costs more because you have more storage variables defined and you also are updating them more times than in the first version of the contract.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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