[Ethereum] Accessing to a dynamically sized array value in a contract

arrayscontract-designget-storage-atjson-rpcsolidity

I'm trying I have this contract:

pragma solidity ^0.4.2;

contract ArrayContract {
    address  _owner;
    uint256[] array;

    function ArrayContract (){
        _owner = msg.sender;
    array.push(1);
    array.push(2);
    array.push(3);
    }
}

So like many others I am trying to access data by using the RPC message 'getStorageAt'.

When I try to access the array field (field 1) I have as response the number 3. It makes sense. Is the size of the array.

So, taking in account other posts (
How do I get the storage indices/keys?
web3.eth.getStorageAt for mapping
) And taking in account the documentation:

https://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage

I try to call the RPC with the parameter keccak256(1) (The result of this calculation is the hash:
0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6
)

So I have something as

web3.getStorageAt('account', 'c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6', 'latest'); 

And the result still empty (0x000….00).

=======
I also tried, without any success, with the following indexes:

index = keccak256(1 . 1) (the position of the array in the contract and the first position of the array)

index = keccak256(keccak256(1).keccak256(1))

=======

I'm starting to suspect that this does not work. Does anybody can point me to a solution to this problem??

Thanks a lot 🙂

================ EDITION ========================

Hi all. I finally came back to this issue.
After implementing the needed stuff for my platform (I am not using javascript but smalltalk), I am able to generate the hash needed for accessing the getStorageAt message with the proper encoding.
Using this same example, the slot related with this code is the number 1. According to the documentation, I should get the content of the array by executing:

web3.getStorageAt('account', 'b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6', 'latest');

The result given by the GETH RPC service to this line is: 0000000000000000000000000000000000000000000000000000000000000001

That happens to be the first element in the array. (I checked with other orders to be sure, and it is in fact the first element of the array)

Then, the next related question is, how do i fetch the next elements? According to the documentation, this call should return the entire array.

Just as a test, I tried to access each element using the mapping fashion
using different encodings of unsigned integer for the index of the element in the array:

index = keccak256(ENC ElementID . ENC SlotID)

index = keccak256(uint8 1 . uint128 1)

index = keccak256(uint128 1 . uint128 1)

index = keccak256(uint256 1 . uint128 1)

Without any kind of success.

Do you have any clue about what I am missing?
Thanks a lot!

Santiago

Best Answer

The issue is that the RPC keccak is actually slightly different than the one used in Solidiy. To get hashes consistent with solidity, use the ethereumjs-abi library. For example:

var abi = require('ethereumjs-abi')
var BN = require('bn.js')

abi.soliditySHA3(
    ["uint"],
    [ new BN(1)]
).toString('hex')

> "b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"

This is the correct hash that you should use. Also, be sure to pass in the actual hex value to getStorageAt, i.e. by passing in the result of abi.soliditySHA3 without converting to a hex string.

Related Topic