[Ethereum] Return complete mappings/arrays

contract-designcontract-developmentmappingsoliditystorage

In a contract (only a demo) I have:

struct Bank {
    string name;
    mapping(address => uint) balances;
}

mapping(address => uint) userIsAtBank;
Bank[] banks;

Now I would like to have a function that copies the mapping userIsAtBank/ the array banks without going through it (like all values in one return) and sets a new mapping with the same values. In my example: userIsAtBankNew = userIsAtBank – and: banksNew = banks. Is that possible?

If it's not possible, what's the best way to go through a length of 25.000 (if for example the latest bank is banks[25000]) without the transaction getting rejected or is too expensive?

Best Answer

You're on the right track as you turn your thinking to increasing cost.

You may be able to move the limit slightly with efficiencies, but the only way to solve the problem is to reconsider the approach so each transaction completes in O(1) ... one operation.

The suggested approach is not very blockchain. Suppose client, Alice, fetches the list of 25,000 banks. Why would she fetch it again? If she is listening to event logs, then she will know about bank number 25,001 when it is added. Why would she need to ask?

You can use a two-pronged approach.

  1. Not a single operation with n iterations and increasing cost. 25,000 operations with a fixed gas cost - exactly the same at any scale. Fetch them one at a time.
  2. Use event logs to inform clients about all important state changes - create, retrieve, update, delete. Indeed, listening to the event logs and amending local tables may be the only client-side you need.

Have a look at Mapped Struct with Index over here: Are there well-solved and simple storage patterns for Solidity?

The data structure starts out exactly per your pattern. What follow are functions to deal with single instances at a time. Explained with the rationale and more complete example over here: https://medium.com/@robhitchens/solidity-crud-part-1-824ffa69509a

Hope it helps.

p.s. I should mention it's not possible to enumerate or count the keys in a mapping or pass mappings around in one gulp. You can do so with dynamic arrays but it is not completely supported and it doesn't work between contracts. One-row-at-a-time avoids the limitations and scaling issues.

Related Topic