4

This is the code. And I want to return the Requests array.

pragma solidity >=0.8.4;

contract Contract {

    struct Requests {
        string description;
        uint value;
        address recipient;
        bool complete;
        mapping(address => bool) sender;
        uint approvalCount;
    }

    Requests[] public requests;

    function createRequest(string memory d, uint v, address r) public {
        Requests storage newRequest = requests.push();
        newRequest.description = d;
        newRequest.value = v;
        newRequest.recipient = r;
        newRequest.complete = false;
        newRequest.approvalCount = 0;
        newRequest.sender[msg.sender] = true;
    }
}

1 Answer 1

5

Unfortunately this is not possible. To see why, please look at how mappings are stored:

Due to their unpredictable size, mappings and dynamically-sized array types cannot be stored “in between” the state variables preceding and following them. Instead, they are considered to occupy only 32 bytes with regards to the rules above and the elements they contain are stored starting at a different storage slot that is computed using a Keccak-256 hash.

For mappings, the slot stays empty, but it is still needed to ensure that even if there are two mappings next to each other, their content ends up at different storage locations.

The value corresponding to a mapping key k is located at keccak256(h(k) . p) where . is concatenation and h is a function that is applied to the key depending on its type

In other words, the mapping values are not stored in a single place but spread at random locations all over the storage. Moreover, the compiler does not store the keys and does not track the number of items already present in the mapping so it does not even know what to copy.

This has always been problematic, which is why mappings are now disallowed in memory structs because only other fields would actually be copied and the mapping would be silently skipped. They are still allowed in storage structs but there's the same flaw there - a getter generated by the compiler for a public storage variable silently skips mappings and arrays inside structs.

For arrays the workaround is to define your own function returning the struct. Then the compiler will not omit it. With mappings the problem is different so this is not enough. You would have to store the keys somewhere and then have the function copy the keys to a new struct that has an array in place of the mapping.

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.