So erhalten Sie den Datenspeicherort für eine Zeichenfolge > 31 Länge

Die Dokumentation sagt:

Bytes und String sind identisch kodiert. Für Byte-Arrays, die Daten mit einer Länge von 32 oder mehr Bytes speichern, speichert der Hauptslot die Länge * 2 + 1, und die Daten werden wie üblich in keccak256(slot) gespeichert.

Ich arbeite mit einer Zeichenfolge (> 31 Bytes), einer Zustandsvariablen im Speicher, und versuche, den Speicherort der Daten zu ermitteln. Ich übergebe die Steckplatznummer (umgewandelt in eine Byte-Variable) an keccak256. Es gibt ein bytes32 zurück. Wie kann ich damit herausfinden, wo die Daten gespeichert sind?

Wenn es darauf ankommt, erhalte ich den bytes32-Wert von diesem Code.

bytes32 data_slot = keccak256 (uint_to_bytes (slot_number));

Und die Funktion ist so definiert.

function uint_to_bytes (uint value) internal pure returns (bytes memory)
{
    uint byte_count = value <= 255 ? 1 : 2;
    bytes memory slot_contents = new bytes (byte_count);

    uint content_index = 0;
    bool value_started = false;
    for (int16 b = 31; b >= 0; b--)
    {
        uint a = uint (b);
        uint shift = a * 8;
        uint anded_value = (0xff << shift) & value;
        uint8 this_byte = uint8 (anded_value >> shift);

        if (this_byte > 0)
            value_started = true;

        if (value_started)
            slot_contents [content_index++] = byte (this_byte);
    }

    return slot_contents;
}

In meinem Fall ist die Basis-Slot-Nummer 5, die die Länge meiner Zeichenfolge enthält. Die Länge in diesem Schlitz ist korrekt.

Aber wie erhalte ich den Speicherort der Daten, wenn keccak256 ein bytes32 zurückgibt. Wenn ich die Bytes32 in ein uint256 umwandle, bekomme ich 99383055861825221844433915613614375939768875017829574557572350922731547121557. Das kann sicherlich nicht die Slot-Nummer sein, in der sich die Daten befinden.

Antworten (1)

Der Speicher in Solidity ist eine Zuordnung von bytes32 zu bytes32, und ein Steckplatz unter der Haube wird durch bytes32 dargestellt. Ich habe den von Ihnen bereitgestellten Code nicht vollständig verstanden, aber hier sind meine zwei Cent.

byte[]Wenn Sie den Vertrag zur Aufbewahrung deklarieren , ist er verpackt. Das bedeutet, dass die Daten für einen Index in diesem Array ein Byte statt eines vollen Slots von 32 Bytes belegen würden, wie es bei einfachen Arrays der Fall ist. keccak256(slot number)Für die gewöhnlichen Arrays ohne Packen können die Daten bei Index 0 und 1 bei und lokalisiert werden, keccak256(slot number) + 1aber das ist bei Byte-Arrays (oder jedem gepackten Array wie uint8[]) nicht der Fall, da keccak256(slot number)die Daten aufgrund von an den ersten 32 Indizes des Arrays zurückgegeben würden die Verpackung.

Ein Beispiel:

pragma solidity 0.5.0;

contract TestStorage {
    byte[] b;

    constructor () public {
        uint8 i;
        for (i = 1 ; i <= 32; i++) {
            b.push(byte(i));
        }
    
        for (i = 1 ; i <= 32; i++) {
            b.push(byte(i));
        }
    }

    function readFromStorage() public view returns(bytes32 slot1, bytes32 slot2, bytes32 slot3) {
        bytes memory slot = new bytes(32);
        assembly {
            mstore(
                add(slot, 32),
                b_slot
            )
        
            let slotHash := keccak256(add(slot, 32), 32)
            slot1 := sload(
                add(
                    slotHash,
                    0
                )
            )
        
            slot2 := sload(
                add(
                    slotHash,
                    1
                )
            )
        
            slot3 := sload(
                add(
                    slotHash,
                    2
                )
            )
        
        }

    }
}

Hier im Konstruktor bestücken wir die ersten 32 Bytes und zweiten 32 Bytes mit dem gleichen Inhalt und lesen die Funktion per Assembly ein. Nur die ersten beiden Steckplätze sind belegt und der dritte Steckplatz wäre leer.

Geben Sie hier die Bildbeschreibung ein

Ich hoffe es hilft!