1

Hi I'm trying to make a function in assembly inline with following purpose:

Given: An array in the blockchain with names (= bytes32[] _documentHashes).

Asked: Find which indexes are equal to the name that I search (= bytes32 _searchHash) and return them in an array (= uint[] result)

I have the following code, with some comment to clarify my logic. Following Topic has helped me to produce this code:

function arrMke() public{ // Some test data
    bytes32[] arrMke;
    arrMke.push(0X10);
    arrMke.push(0X20);
    arrMke.push(0x10);
    arrMke.push(0X40);
    uint[] arrResult = search(arrMke,0X10);
}

function search(bytes32[] _documentHashes, bytes32 _searchHash) public returns (uint[] result){
    assembly {
        let len := mload(_documentHashes) // Load the length (first 32 bytes)
        let counter := 0 //count each time data in the _documentHashes == _searchHash
        result := mload(0x40) // 0x40 is the address where next free memory slot is stored in Solidity.
        let i := 0 // uint i for the loop
        loop: //start loop
        let docHash := mload(add(_documentHashes, add(0x20, mul(i, 0x20)))) // docHash = _documentHashes[i], data offset = 0x20 (1st 32 is reserved for size) & i*32 to pickup the right index
        if eq(docHash, _searchHash) { // condition if(docHash == _searchHash)
            counter := add(counter,1) // increment counter by 1
            mstore(add(result, 0x20), counter) // (re)Set size of the result array each time the condtion is true
            mstore(add(result, add(0x20, mul(counter, 0x20))), i) // add data to the array, data offset = 0x20 (1st 32 is reserved for size) & i*32 to pickup the right index 
        }
        i := add(i,1) // increment for loop
        jumpi(loop, lt(i,len)) // stop loop when the lenght of _documenthashes is reached
        mstore(0x40, add(result, add(0x20, mul(counter, 0x20)))) // Update/return the result array ofsset + length of the data (=i*32)
    }
}

Problem:

  1. I don't get the debugger in remix running. The "Solidity locals" screen is empty:

enter image description here

  1. uint[] arrResult = search(0x0,arrMke,0X10); does'nt want to compile:

enter image description here

  1. Question:

1) How can I watch (see the data in) my variabeles, especially uint[] result? Because I'm not sure if my assemblercode is correct at all. 2) Why do I get this compile error & how can I fix it?

Thanks for your help!

Tshy

1 Answer 1

1

A couple of issues I've found

  • Declare arrResult as memory reference (default is storage)
  • Length of an array is stored at result+0, it was stored at result+0x20
  • Don't use let inside a loop it will create a new variable every time (It appears to be a bug in the compiler)
  • Incremented counter before use, resulting index result+0x20+0x20*(counter+1)
  • Update result length once at the end to save some gas

This should work as expected

function arrMke() public returns (uint[]) { // Some test data
    bytes32[] arrMke;
    arrMke.push(0X10);
    arrMke.push(0X20);
    arrMke.push(0x10);
    arrMke.push(0X40);
    uint[] memory arrResult = search(arrMke,0X40);
    return arrResult;
}

function search(bytes32[] _documentHashes, bytes32 _searchHash) public returns (uint[] result) {
    assembly {
        let len := mload(_documentHashes) // Load the length (first 32 bytes)
        let counter := 0 //count each time data in the _documentHashes == _searchHash
        result := mload(0x40) // 0x40 is the address where next free memory slot is stored in Solidity.
        let i := 0 // uint i for the loop
        let docHash := 0
        loop: //start loop
        docHash := mload(add(_documentHashes, add(0x20, mul(i, 0x20)))) // docHash = _documentHashes[i], data offset = 0x20 (1st 32 is reserved for size) & i*32 to pickup the right index
        if eq(docHash, _searchHash) { // condition if(docHash == _searchHash)
            mstore(add(result, add(0x20, mul(counter, 0x20))), i) // add data to the array, data offset = 0x20 (1st 32 is reserved for size) & i*32 to pickup the right index 
            counter := add(counter, 1) // increment counter by 1
        }
        i := add(i,1) // increment for loop
        jumpi(loop, lt(i,len)) // stop loop when the lenght of _documenthashes is reached
        mstore(result, counter) // (re)Set size of the result array each time the condtion is true
        mstore(0x40, add(result, add(0x20, mul(counter, 0x20)))) // Update/return the result array ofsset + length of the data (=i*32)
    }
}
3
  • Hi Ismael, thanks for the remarks. All useful feedback! I receive the expected result ("0": "uint256[]: 3" with input 0x40 as searchHash)
    – Tshy
    Apr 23, 2018 at 15:52
  • Ismael, any idea how I can see the data of my variables in the debugger (watch function)? I don't see any (see screenshot in Problem 1st point)
    – Tshy
    Apr 23, 2018 at 16:08
  • I do not use the debugger very much, I think it works for simple variables like uint or byte32, for arrays it doesn't appear to work. For assembly I look at the stack, the top changes frequently but you can recognize the variables below.
    – Ismael
    Apr 23, 2018 at 18:30

Your Answer

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

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