Storage

如何導出映射到賬戶的儲存密鑰?

  • September 28, 2018

我試圖通過將帳戶(這裡的帳戶表示 ERC20 餘額映射*映射(地址 => uint256)*中的關鍵地址)映射到奇偶交易跟踪中的相應儲存密鑰來得出帳戶儲存的更改。

交易https://etherscan.io/tx/0x210cfe3d3b62f415ed0327a3c6177086df4937b6280031255360b6d137308554的範例跟踪(通過 web3.py 獲取)是:

{
   'output': '0x',
   'stateDiff': {
       '0x52bc44d5378309ee2abf1539bf71de1b7d7be3b5': {
           'balance': {
               '*': {
                   'from': '0x122291885d6222bc5ec',
                   'to': '0x12229193ca3f58565ec'
               }
           },
           'code': '=',
           'nonce': '=',
           'storage': {}
       },
       '0xaddba95f769b5d42c02e144102817eab9d00efd3': {
           'balance': '=',
           'code': '=',
           'nonce': '=',
           'storage': {
               '0x1ded6755a6d7d843883da8cd8948931cf9f8b1e8f8983ad77e1685ece0b92fc2': {
                   '*': {
                       'from': '0x0000000000000000000000000000000000000000000000000000000000000000',
                       'to': '0x000000000000000000000000000000000000000000000000000bfb8d0ebc5000'
                   }
               },
               '0x5020d77d5345022a5466af6f78731b10f92d31e17961c23ea6ce5c185dc75d49': {
                   '*': {
                       'from': '0x0000000000000000000000000000000000000000000000000000000000000000',
                       'to': '0x0000000000000000000000000000000000000000000000000000e1412a5f1c00'
                   }
               }
           }
       },
       '0xf2eeb980b60b9ed146636c65ecc5e8f27a8aed40': {
           'balance': {
               '*': {
                   'from': '0x2c4c7111f4801a8',
                   'to': '0x2c410434bee61a8'
               }
           },
           'code': '=',
           'nonce': {
               '*': {
                   'from': '0x143',
                   'to': '0x144'
               }
           },
           'storage': {}
       }
   },
   'trace': [{
       'action': {
           'callType': 'call',
           'from': '0xf2eeb980b60b9ed146636c65ecc5e8f27a8aed40',
           'gas': '0x9008',
           'input': '0xa9059cbb000000000000000000000000e034e561ce112c5f261f15d447e8f2436d9625040000000000000000000000000000000000000000000000000000e130de0be000',
           'to': '0xaddba95f769b5d42c02e144102817eab9d00efd3',
           'value': '0x0'
       },
       'result': {
           'gasUsed': '0x3924',
           'output': '0x'
       },
       'subtraces': 0,
       'traceAddress': [],
       'type': 'call'
   }],
   'vmTrace': None
}

根據https://solidity.readthedocs.io/en/v0.4.24/miscellaneous.html#layout-of-state-variables-in-storage,“映射鍵 k 對應的值位於 keccak256(k . p ) 其中 . 是連接”。根據 “keccack(LeftPad32(key, 0), LeftPad32(map position, 0))” https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat,我知道必要的左墊,儘管散列函式似乎已經在內部處理了這個問題。

我為這個 keccak256 儲存密鑰嘗試了 Web3.sha3(),StackOverflow 上的其他問題提到 Solidity 使用了稍微不同的雜湊算法。然而,還可以通過使用合適的Web3.soliditySha3()我不會在一個雜湊會出現我在跟踪(在這裡,關鍵找到到達0x1ded6755a6d7d843883da8cd8948931cf9f8b1e8f8983ad77e1685ece0b92fc20x5020d77d5345022a5466af6f78731b10f92d31e17961c23ea6ce5c185dc75d49)的帳戶0xf2eeb980b60b9ed146636c65ecc5e8f27a8aed40

什麼是正確的方法(最好使用 web3.py)來散列帳戶和位置以獲得映射儲存密鑰?

正如@jaime 在評論中提到的,您需要映射變數的 來查找和position之間的關係。address``storage key

您可以在下面找到我編寫的用於檢測position基本 erc20 合約的程式碼(使用 web3.py):

import json
from web3.auto.infura import w3
from eth_utils import remove_0x_prefix, to_int, to_checksum_address, to_hex

# erc20 contract address
CONTRACT_ADDRESS = '0x89205A3A3b2A69De6Dbf7f01ED13B2108B2c43e7'
# address with non zero token balance
HOLDER_ADDRESS = '0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb' 

def getStorageAtIndex(i):
   pos = str(i).rjust(64, '0')
   key = remove_0x_prefix(HOLDER_ADDRESS).rjust(64, '0').lower()
   storage_key = to_hex(w3.sha3(hexstr=key + pos))
   return to_int(w3.eth.getStorageAt(CONTRACT_ADDRESS, storage_key))

for i in range(0, 20):
   if getStorageAtIndex(i) != 0:
       print("position is {}".format(i))

結果:

>>> position is 5

一旦你有了正確的位置值,你就可以輕鬆地獲取儲存在合約中的值。

pos = str(5).rjust(64, '0')
key = remove_0x_prefix(HOLDER_ADDRESS).rjust(64, '0').lower()
storage_key = to_hex(w3.sha3(hexstr=key + pos))
w3.eth.getStorageAt(CONTRACT_ADDRESS, storage_key)

引用自:https://ethereum.stackexchange.com/questions/49873