Zugriff auf einen Array-Wert mit dynamischer Größe in einem Vertrag

Ich versuche, ich habe diesen Vertrag:

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 wie viele andere versuche ich, auf Daten zuzugreifen, indem ich die RPC-Nachricht 'getStorageAt' verwende.

Wenn ich versuche, auf das Array-Feld (Feld 1) zuzugreifen, bekomme ich als Antwort die Zahl 3. Es macht Sinn. Ist die Größe des Arrays.

Unter Berücksichtigung anderer Posts ( Wie bekomme ich die Speicherindizes/Schlüssel? web3.eth.getStorageAt für die Zuordnung ) und unter Berücksichtigung der Dokumentation:

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

Ich versuche den RPC mit dem Parameter keccak256(1) aufzurufen (Das Ergebnis dieser Berechnung ist der Hash: 0xc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6 )

Also ich habe sowas wie

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

Und das Ergebnis noch leer (0x000....00).

======= Ich habe es auch ohne Erfolg mit den folgenden Indizes versucht:

index = keccak256(1 . 1) (die Position des Arrays im Vertrag und die erste Position des Arrays)

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

=======

Ich beginne zu vermuten, dass dies nicht funktioniert. Kann mir jemand eine Lösung für dieses Problem zeigen??

Danke vielmals :)

================ AUSGABE ========================

Hallo alle. Ich bin endlich auf dieses Problem zurückgekommen. Nachdem ich die erforderlichen Dinge für meine Plattform implementiert habe (ich verwende kein Javascript, sondern Smalltalk), kann ich den Hash generieren, der für den Zugriff auf die getStorageAt-Nachricht mit der richtigen Codierung erforderlich ist. In demselben Beispiel ist der mit diesem Code verknüpfte Slot die Nummer 1. Laut Dokumentation sollte ich den Inhalt des Arrays abrufen, indem ich Folgendes ausführe:

web3.getStorageAt('Konto', 'b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6', 'neueste');

Das vom GETH-RPC-Dienst an diese Zeile übergebene Ergebnis lautet: 0000000000000000000000000000000000000000000000000000000000001

Das ist zufällig das erste Element im Array. (Ich habe mit anderen Befehlen nachgesehen, um sicherzugehen, und es ist tatsächlich das erste Element des Arrays)

Dann ist die nächste verwandte Frage, wie rufe ich die nächsten Elemente ab? Laut Dokumentation sollte dieser Aufruf das gesamte Array zurückgeben.

Nur als Test habe ich versucht, auf jedes Element mit der Mapping-Methode zuzugreifen, indem ich verschiedene Codierungen von vorzeichenlosen Ganzzahlen für den Index des Elements im Array verwendet habe:

index = keccak256 (ENC-Element-ID . ENC-Slot-ID)

index = keccak256(uint8 1 . uint128 1)

...

index = keccak256(uint128 1 . uint128 1)

index = keccak256(uint256 1 . uint128 1)

Ohne jeglichen Erfolg.

Hast du eine Ahnung, was mir fehlt? Danke vielmals!

Santiago

Antworten (2)

Das Problem ist, dass der RPC-Keccak tatsächlich etwas anders ist als der in Solidiy verwendete. Verwenden Sie die ethereumjs-abi- Bibliothek , um mit der Solidität konsistente Hashes zu erhalten . Zum Beispiel:

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

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

> "b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"

Dies ist der richtige Hash, den Sie verwenden sollten. Stellen Sie außerdem sicher, dass Sie den tatsächlichen Hex-Wert an getStorageAtübergeben, dh indem Sie das Ergebnis von übergeben abi.soliditySHA3, ohne es in einen Hex-String umzuwandeln.

Gibt es Einzelheiten darüber, wie sich der Solidity Keccak unterscheidet?
Hier gibt es ein bisschen crypto.stackexchange.com/q/15727

Wenn Ihr Hash-Algorithmus Ihnen c89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6beim Hashen etwas gibt, ist1 dies tatsächlich der richtige Algorithmus.

Es ist nur so, dass Sie den Wert richtig codieren müssen, bevor Sie die Hash-Funktion verwenden, dh Sie müssen die Hex-Zeichenfolge 0000000000000000000000000000000000000000000000000000000000000001anstelle von einfach verwenden 1.

Auf dem Playground von Ethers.js :

> 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"

Um auf das zweite Element des Arrays in Speicherplatz 1 zuzugreifen, sollten Sie nicht tun keccak256(pack(2))(das wäre der Speicherplatz eines dynamischen Arrays, das in Speicherplatz 2 gespeichert ist), sondern keccak256(pack(1)) + 1, dh 0xb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf7.