New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rule for string->uint mapping and the storage position #1550

Closed
hievan2016 opened this Issue Jan 7, 2017 · 19 comments

Comments

Projects
None yet
6 participants
@hievan2016

hievan2016 commented Jan 7, 2017

Env

solc --version
solc, the solidity compiler commandline interface
Version: 0.4.7+commit.822622cf.Linux.g++

./geth version
Geth
Version: 1.4.7-stable-667a386d
Protocol Versions: [63 62 61]
Network Id: 1
Go Version: go1.5.4
OS: linux

Problem

We are trying to figure out the mapping rule and storage position of saved data
base on this formula

keccack(LeftPad32(key, 0), LeftPad32(map position, 0))

which is mentioned at

https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat

however, seems this works for uint->string mapping, but not for string->uint
mapping, could anyone pls help on this?

Below is the test contract

contract testMapping{
mapping(string=>uint) s2i; //position is 0
mapping(uint=>string) i2s; //position is 1

function setStr(string key) {
    s2i[key] = 100;            
}

function setInt(uint key) {
    i2s[key] = "zzz";
}

}

then we use the mapping to save the data by calling

setStr("aaa") // key is aaa (ascii : 616161)
setInt(200) // key is 200 (hex : c8)

the contract storage is

storage: {
345f7c6c888721344af4147de0834159e0b302300ba13c4e7b6c0b60d8f2314e: "a07a7a7a0000000000000000000000000000000000000000000000000000000006",
69e08a2904d77becc5ebdff9265102784e25436cf0dfbaeb5c932ed98ffc834d: "64"
}

the first entry shows "zzz" (ascii : 7a7a7a) is saved at position "345f7c6c888721344af4147de0834159e0b302300ba13c4e7b6c0b60d8f2314e",
this position could be got from the formula.

but when using "aaa" as the key to do string->uint mapping to save value 100 (0x64),
we cannot get the correct storage position "69e08a2904d77becc5ebdff9265102784e25436cf0dfbaeb5c932ed98ffc834d"
based on the formula, you can see, the sha3 value is incorrect.

var key = "0000000000000000000000000000000000000000000000000000000000616161" + "0000000000000000000000000000000000000000000000000000000000000000"
web3.sha3(key, {"encoding":"hex"})

"0x15b5515e45c94bd2fbc0aa103673f2c4899d2996fe1407ba1e6e5ef9ac66c2f5"

@chriseth

This comment has been minimized.

Contributor

chriseth commented Jan 10, 2017

Since strings are arbitrary length, you have to hash them first.

@hievan2016

This comment has been minimized.

hievan2016 commented Jan 10, 2017

@chriseth

I still cannot get the correct hash value "69e08a2904d77becc5ebdff9265102784e25436cf0dfbaeb5c932ed98ffc834d", could you help check whether I miss anything?

var key0 = "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616161"
var key1 = web3.sha3(key0, {"encoding":"hex"})
var key2 = key1 + "0000000000000000000000000000000000000000000000000000000000000000"
web3.sha3(key2, {"encoding":"hex"})

sha3 : "0x8f34d90832af21f9fc31ef2888a966ad8090cdd9bc1a16ecf819059d118ae6db"

var key0 = "616161"
var key1 = web3.sha3(key0, {"encoding":"hex"})
var key2 = key1 + "0000000000000000000000000000000000000000000000000000000000000000"
web3.sha3(key2, {"encoding":"hex"})

sha3 : "0xe4998bf274557cf66b8123e4803a12c6dca7f047052b01d6b4b51776b0eb04d7"

var key0 = "0000000000000000000000000000000000000000000000000000000000616161"
var key1 = web3.sha3(key0, {"encoding":"hex"})
var key2 = key1 + "0000000000000000000000000000000000000000000000000000000000000000"
web3.sha3(key2, {"encoding":"hex"})

sha3 : "0x4b9ff950998e1bfecbf6ed1b5e7531fee7fac216130cafe3d3c03d0b1ba697b8"

@pirapira

This comment has been minimized.

Member

pirapira commented Jan 10, 2017

I would try the array access in the browser-solidity, and chase the stack & memory contents.

@hievan2016

This comment has been minimized.

hievan2016 commented Jan 11, 2017

We are going to use getStorageAt() API, which requires the storage slot as parameter, so have to do sha3 hash to get the exact storage slot, so could you kindly help on this?

@hievan2016

This comment has been minimized.

hievan2016 commented Jan 11, 2017

And, in fact, we need to use mapping in this way "mapping(string=>MyStruct)", and found the correct storage slot cannot be got, then simply the mapping to "mapping(string=>uint)" in this posting for easy reading/debugging.

@pirapira

This comment has been minimized.

Member

pirapira commented Jan 11, 2017

For your purpose, you can define

function getStr(string key) returns (uint) {
    return s2i[key];            
}

and call the function from web3.

@hievan2016

This comment has been minimized.

hievan2016 commented Jan 11, 2017

@pirapira thanks for your reply, however, adding many get...() APIs is not what we want, we prefer using the calculated storage index and then call getStorageAt(), so let's continue figuring out how to calculate the storage slot.

@chriseth looking forwarding to your further input.

@chriseth

This comment has been minimized.

Contributor

chriseth commented Jan 11, 2017

Ah, I think your original version was fine except for padding the key. So I think the following should work:

var key = "616161"
var pos = "0000000000000000000000000000000000000000000000000000000000000000"
web3.sha3(key + pos, {"encoding":"hex"})
@hievan2016

This comment has been minimized.

hievan2016 commented Jan 12, 2017

Awesome, it works, thanks a lot!

@chriseth chriseth closed this Jan 12, 2017

@ianmonkuk

This comment has been minimized.

ianmonkuk commented Mar 1, 2017

@hievan2016 @chriseth is there anyway to return an element of a mapping without knowing the key but using an index (i.e. pos 1, 2, etc)? Carrying on your example from above, if
i2s["aaa"] = 1
i2s["bbb"] = 2

Assuming we did not know the keys but we knew that i2s was in position 2?

I have worked out how to do this for arrays but not for maps.

Thanks Ian

@VoR0220

This comment has been minimized.

Contributor

VoR0220 commented Mar 1, 2017

@ianmonkuk you will have to create an iterated mapping. Search for it in the readthedocs page. You'll get the idea.

@chriseth

This comment has been minimized.

Contributor

chriseth commented Mar 1, 2017

@ianmonkuk

This comment has been minimized.

ianmonkuk commented Mar 1, 2017

@VoR0220 thanks for responding. I should have clarified that I need to do this in the same way as discussed in this thread - using getStorageAt function which @hievan2016 was using. I am aware that this can be done relatively easily within the contract itself.

@chriseth there's been a lot of questions relate to this on stackexchange and they all point to the page below. This seems to suggest access to map elements (via getStorageAt) can only be accessed if the keys are known.

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

Thanks, Ian

@chriseth

This comment has been minimized.

Contributor

chriseth commented Mar 1, 2017

Yes, you have to know the hash of the key. Some clients can also list storage contents and you might be able to derive the keys from there.

@ianmonkuk

This comment has been minimized.

ianmonkuk commented Mar 1, 2017

@chriseth

This comment has been minimized.

Contributor

chriseth commented Mar 1, 2017

It is a bit tricky, because there is another hash function evaluation envolved. If you did a full sync, yes. If you fast-synced, you might not have all values, but I think the geth team is currently building a remote server where you can get the missing values.

@ianmonkuk

This comment has been minimized.

ianmonkuk commented Mar 1, 2017

ok thanks

@zxhubo

This comment has been minimized.

zxhubo commented Jul 30, 2018

I have a question:
my contract code is :
contract Test1 {

mapping(uint256 => uint256) z;

function test1(){
     z[233]=234;
     z[234]=1;
 }     

}

and I have been deploy this contract used by Remix,then invoke the test1() method. I debug this function In Debugger ,so Can see
the Storage completely loaded:

0x27fdb72814febb9410af57bca307f47028ec5b79245df092b7f15c66aea257e5: Object
    key: 0x28a06524829b6fed74df277d29b0e9d5843614df83ac4257ee812125675fdd54
    value: 0x00000000000000000000000000000000000000000000000000000000000000ea
0x8c96c4d8a0aa2c328c7c6862e662be3530e8741fec6dd703dac17a5374e7e828: Object
    key: 0x4a9ab6c152794dd891130d65b49535f6222d24e4c9a3f06f616c3634b24c9fac
    value: 0x0000000000000000000000000000000000000000000000000000000000000001

I know the hash 0x28a06524829b6fed74df277d29b0e9d5843614df83ac4257ee812125675fdd54 and 0x4a9ab6c152794dd891130d65b49535f6222d24e4c9a3f06f616c3634b24c9fac,
but the hash 0x27fdb72814febb9410af57bca307f47028ec5b79245df092b7f15c66aea257e5 and 0x8c96c4d8a0aa2c328c7c6862e662be3530e8741fec6dd703dac17a5374e7e828 is how to get it,
sorry ,my English is poor ,who can help me to get the value of the hash 0x27fdb72814febb9410af57bca307f47028ec5b79245df092b7f15c66aea257e5 and 0x8c96c4d8a0aa2c328c7c6862e662be3530e8741fec6dd703dac17a5374e7e828

@zxhubo

This comment has been minimized.

zxhubo commented Jul 30, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment