10

How can I get contract mapping storage?

Considering this simple contract

contract Currency{
 mapping(address=>uint) public balances;

   function deposit(){
      balances[tx.origin]++;
   }
}

After deploying and calling deposit, I'd like to get contract storage

eth.getStorageAt("0x681afcc842a1a01f34ffb2c091e576aa78175d55",0)

but always getting same result : 0x0000000000000000000000000000000000000000000000000000000000000000

even if currency.balances.call(...) returns correct balance

Is there a way to retrieve entire balances map?

5 Answers 5

6

balances is public, you get the balance from there.

About storage: The address is not the key (although there is a story about this particular issue: https://www.pivotaltracker.com/story/show/85010830). Docs for getting the storage address of a variable is here: http://solidity.readthedocs.org/en/latest/miscellaneous.html#layout-of-state-variables-in-storage

About iterating over the map: You cannot do that without adding code, like is done here: https://github.com/ethereum/dapp-bin/blob/master/library/iterable_mapping.sol

The other alternative is if there is no other storage you could technically get all values by walking the state trie, but it hashes all keys by default now (i believe), so keys would be hard.

With inline assembly you'll be able to write to whichever storage address you like, which means it will be much easier to read directly from storage.

5

Retrieving via contract

Not sure this is the answer you are looking for, but you can write a method which returns an array. Calling (and not transacting with) the contract is right now free and in the future you could still retrieve storage entries and run your own VM.

One dimensional arrays are working fine, 2D ones are coming later I think. You can decide how to format it -- an easy way could be: [ address1, balance1, address2, balance2, ... ]

Important to note there is no notion that a given mapping is empty. You need to decide based on your conditions how to iterate the mapping. See the Solidity docs for more information.

Parsing storage directly

You can retrieve storage entries via RPC using the getStorageAt call. There is no need to manually interact with the trie.

In order to parse the storage (entries) directly you would need to know how the language used organizes storage and it would depend on the source code and possibly the compiler version as well.

1

This medium article explains very well how to access a mapping, see section index 5 — uints1:

Mappings have a different indexation and should be read in other way. To read mapping value you should know the key value. Otherwise, read mapping value is impossible.

index = '0000000000000000000000000000000000000000000000000000000000000005'
key =  '00000000000000000000000xbccc714d56bc0da0fd33d96d2a87b680dd6d0df6'
let newKey =  web3.sha3(key + index, {"encoding":"hex"})
console.log(web3.eth.getStorageAt(contractAddress, newKey))
console.log('DEC: ' + web3.toDecimal(web3.eth.getStorageAt(contractAddress, newKey)))
result:
0x0000000000000000000000000000000000000000000000000000000000000058
DEC: 88

Source: https://medium.com/aigang-network/how-to-read-ethereum-contract-storage-44252c8af925

0

Assuming your code is compiled with standard Solidity (no post-optimization or obfuscation), the values in balances will be stored at storage address KECCAK256(CONCAT(N, key_in_balances)). (Here, N=0 because balances is the first contract attribute.)

Therefore, getStorageAt() will not help you unless you know the address of the wallet you wish to query. Which also means you will not be able to enumerate balances using that method.

As Andreas said in his answer, the only way to potentially do that is to parse the state trie of the contract manually. The best starting point is probably to fork an existing client. The simpler Python implementation is probably best suited for this kind of experimentation.

0

As of now, in order to retrieve mapping from storage,

    // . symbols that hash together. do not put . between
    hashValue= keccak256(key . slot) // hashed together

in your contract, mapping is stored in the first slot, so its index is 0.

You can get the its keccak from online-keccak Make sure input type must be hex.

  web3.eth.getStorageAt('addressOfContract','hashValue')

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.