7

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

2 Answers 2

5

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.

2
1

Actually if your hashing algorithm gives you c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6 when hashing 1 then it is the correct algorithm.

It's just that you must encode the value properly before using the hash function, i.e. you must use the hex string 0000000000000000000000000000000000000000000000000000000000000001 instead of simply 1.

On Ethers.js playground:

> utils.keccak256(49) # 49 is the int value of ASCII char '1'
"0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6"

> utils.solidityPack(['uint256'], [1])
"0x0000000000000000000000000000000000000000000000000000000000000001"

> utils.keccak256(utils.solidityPack(['uint256'], [1]))
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"

> utils.solidityKeccak256(['uint256'], [1])
"0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"

To access the second element of the array in storage slot 1, you should not do keccak256(pack(2)) (that would be the storage location of a dynamic array stored in storage slot 2) but keccak256(pack(1)) + 1, i.e. 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7.

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.