Wie leite ich den Speicherschlüssel der Zuordnung zu einem Konto ab?

Ich versuche, Änderungen des Kontospeichers abzuleiten, indem ich Konten (hier stellen die Konten die Schlüsseladresse in der ERC20-Saldenzuordnungszuordnung (Adresse => uint256) ) ihren entsprechenden Speicherschlüsseln aus einer Paritätstransaktionsverfolgung zu.

Ein Beispiel-Trace (abgerufen über web3.py) der Transaktion https://etherscan.io/tx/0x210cfe3d3b62f415ed0327a3c6177086df4937b6280031255360b6d137308554 ist:

{
    '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
}

Laut https://solidity.readthedocs.io/en/v0.4.24/miscellaneous.html#layout-of-state-variables-in-storage befindet sich „der Wert, der einem Zuordnungsschlüssel k entspricht, unter keccak256(k . p ) wobei . eine Verkettung ist". Das notwendige linke Pad ist mir laut "keccack(LeftPad32(key, 0), LeftPad32(map position, 0))" https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_getstorageat bekannt . obwohl die Hash-Funktionen dies bereits intern zu handhaben scheinen.

Ich habe Web3.sha3() für diesen keccak256-Speicherschlüssel ausprobiert, und andere Probleme bei StackOverflow erwähnen, dass Solidity einen etwas anderen Hash-Algorithmus verwendet. Nevertheless, also by using the proper Web3.soliditySha3() I do not arrive at a hash that would present me the key found in the the trace (here, 0x1ded6755a6d7d843883da8cd8948931cf9f8b1e8f8983ad77e1685ece0b92fc2 or 0x5020d77d5345022a5466af6f78731b10f92d31e17961c23ea6ce5c185dc75d49 ) to the account 0xf2eeb980b60b9ed146636c65ecc5e8f27a8aed40 .

Was ist der richtige Weg (vorzugsweise mit web3.py), um das Konto und die Position zu hashen, um zum Mapping-Speicherschlüssel zu gelangen?

Daniel, wie bestimmst du den Wert für p. Dies hängt tatsächlich mit der Position der Zuordnungsvariablen zusammen und Sie benötigen sie.
Für die Position habe ich versucht, die Position gemäß der „Slot“-Logik von programtheblockchain.com/posts/2018/03/09/… aufzuzählen . Leider ohne Erfolg.

Antworten (1)

Wie von @jaime in den Kommentaren erwähnt, benötigen Sie die positionder Zuordnungsvariablen, um die Beziehung zwischen addressund zu finden storage key.

Unten finden Sie einen Code, den ich geschrieben habe, um den positionfür einen einfachen erc20-Vertrag zu erkennen (unter Verwendung von 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))

Ergebnis:
>>> position is 5

Sobald Sie den korrekten Positionswert haben, können Sie die im Vertrag gespeicherten Werte einfach abrufen.

    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)