Konvertieren von Bytes in 0.5.x?

Ich möchte Bytes in einen anderen Typ konvertieren. Dh "0x57D80C61128d608857d5310BB514223Bb6011CAB"in die Adresse 0x57D80C61128d608857d5310BB514223Bb6011CAB, "5"in die uint256 5und so weiter. Ich habe alle Snippets verfolgt, die ich finden konnte, aber ich kann keines davon nach 0.5.0 zum Laufen bringen. Ich glaube, der Übeltäter ist die hier beschriebene Änderung:

Konvertierungen zwischen bytesXund uintYunterschiedlicher Größe sind jetzt aufgrund von bytesXPadding auf der rechten und uintYlinken Seite nicht zulässig, was zu unerwarteten Konvertierungsergebnissen führen kann. Die Größe muss nun innerhalb des Typs vor der Konvertierung angepasst werden. Beispielsweise können Sie a bytes4(4 Bytes) in a uint64(8 Bytes) umwandeln, indem Sie zuerst die bytes4Variable in bytes8und dann in umwandeln uint64. Die entgegengesetzte Polsterung erhalten Sie bei der Konvertierung durch uint32.

Nehmen wir das uint-Beispiel, hier ist ein Code, der vor dieser Version des Compilers funktioniert hätte:

function bytesToUInt(string memory _b) public returns (uint256){
  bytes memory b = bytes(_b);
  uint256 number;
  for(uint i=0;i<b.length;i++){
    number = number + uint(b[i])*(2**(8*(b.length-(i+1))));
  }
  return number;
}

Aber das führt jetzt zu einem TypeError: Explicit type conversion not allowed, ich habe versucht, Dinge zu verschieben und zusätzliche Konvertierungen hinzuzufügen, aber nichts hat funktioniert.

Für bytesbis addresshabe ich das versucht:

function bytesToAddress(string memory _b) public returns (address) {
    bytes20 b = bytes20(bytes(_b));
    return address(uint160(b));
}

Aber Sie können nicht explizit von bytes memorynach konvertieren bytes20, und ich konnte das auch nicht zum Laufen bringen.

Kann mir jemand zeigen, wie das richtig gemacht wird? Danke.

Schauen Sie sich das an: github.com/pouladzade/Seriality – nicht sicher, ob es auf 0.5.0 funktioniert, aber die Bibliothek bietet eine effiziente Möglichkeit, Datentypen durch Inline-ASM zu konvertieren
@MikkoOhtamaa Leider ist die Assembly für 0.5.x veraltet: solidity.readthedocs.io/en/v0.5.2/assembly.html

Antworten (3)

Soweit ich weiß, benötigen Sie eine Inline-Montage. Jemand hat bereits Code gepostet, der zumindest für frühere Solidity-Versionen gilt, obwohl im Allgemeinen eine kurze und korrekte Inline-Assemblierung ziemlich universell sein sollte.

Hier ist ein Code, der einige Bytes aus dem Speicher in Bytes20 konvertiert (nur die ersten 20, es wird natürlich abgeschnitten, wenn darüber hinaus).

contract t {
    function tb20(bytes memory _b) 
    public
    pure
    returns (bytes20 _result) {
        assembly {
            _result := mload(add(_b, 0x20))
        }
    }

    function bytesToAddress(bytes memory _b) 
    public 
    returns (address) {
        return address(tb20(_b));
    }
}

Keine Garantien oder Gewährleistungen auf den Code, aber es scheint zu funktionieren. Kann natürlich tb20 ändern, um stattdessen eine Adresse zurückzugeben, obwohl Sie dann Verschiebungen benötigen.

Das funktioniert bei mir auch nicht, ich bekomme eine normal aussehende Adresse zurück, aber es ist nicht die, die ich als Eingabe verwende. Um es klar zu sagen, ich führe dies auf Remix mit der Solidity-Version 0.5.2 aus. Vielleicht ist es ein Problem mit Remix?

Meine frühere Antwort hat mit der Konvertierung eines Bytes-Typs aus dem Speicher in bytes20 zu tun, denn so habe ich die Frage aus dem Titel verstanden, dynamische Bytes in statisch große 1-32 Bytes und danach in andere Derivate konvertiert.

In Bezug auf die eigentliche Frage in Ihrem Körper soll diese Antwort bestätigen, dass Sie Ihre vorhandene Funktion tatsächlich bytesToUIntfür solc 0.5.x verwenden können. Sie können weiterhin explizite Konvertierungen zwischen anderen statischen Bytes durchführen, solange ihre entsprechenden Längen gleich sind. Wenn Sie also etwas Bytes32 haben und möchten, dass es uint128 ist, müssen Sie es zuerst explizit in Bytes16 konvertieren und können es dann über reguläre Solidity in uint128 konvertieren. Natürlich sollten Sie selbst debuggen/testen, um zu sehen, welche Teile dieser Bytes32 möglicherweise abgeschnitten werden, bevor Sie damit fortfahren, da es umgekehrte Fälle gibt, in denen es sinnvoller sein kann, sie zuerst in uint256 zu konvertieren und dann auf uint128 zu reduzieren .

Einfach gesagt, Sie können Ihre vorhandene Funktion zum Laufen bringen, indem Sie zuerst bytes1in umwandeln uint8.

function bytesToUInt(string memory _b) public returns (uint256){
  bytes memory b = bytes(_b);
  uint256 number;
  for(uint i=0;i<b.length;i++){
    number = number + uint256(uint8(b[i]))*(2**(8*(b.length-(i+1))));
  }
  return number;
}

Der uint256 wurde zur Deutlichkeit hinzugefügt, was wahrscheinlich immer eine gute Idee ist, aber nicht benötigt wird

Das Konvertieren von bytes1 in uint8 war auch mein erster Gedanke, aber nein. "5" gibt 53 zurück, "0" gibt 48 zurück, "124" gibt 3224068 zurück usw. Es ist um 48 von 0 bis 9 verschoben und wird dann komplexer. Ich dachte, es könnte die Konvertierung von Zeichenfolge zu Bytes sein, aber anscheinend nicht.
Aber Sie haben diese Funktion gepostet, und das Ergebnis, das die obige Funktion, die ich für solc 0.5 gepostet habe, produziert, ist das gleiche wie das, das Sie gepostet haben und von dem Sie gesagt haben, dass es funktioniert??? Meine Antworten beantworten Ihre Fragen, aber ich glaube nicht, dass Sie die richtigen Fragen für das gestellt haben, wonach Sie tatsächlich suchen. Ich denke, Sie möchten vielleicht eine neue richtige Frage erneut posten. Ich glaube, was Sie tatsächlich suchen, ist ein Basis-10-String-Konverter in uint, den es gibt. Suchen Sie in der Oraclize-API nach einigen funktionierenden Helfern.
@FlashyQpt Die Funktion bytesToAddresskonvertiert eine Bytefolge in uint256, wenn die Zeichenfolge hexadezimale Ziffern enthält, müssen Sie sie zuerst in ihren Wert konvertieren. Denken Sie zuerst an ethereum.stackexchange.com/a/40247/2124 .
Ich dachte, es würde in 0.4.x funktionieren, ich habe dummerweise nicht die Mühe gemacht, dies zu testen. Ich habe falsch interpretiert, was die Eingabe sein sollte. @Ismael Danke, ich glaube, du hast mein Problem gelöst

Der Fehler, den ich machte, kam von der anfänglichen Konvertierung in Bytes. Da Sie mit alles an sie übergeben können bytes(), nahm ich an, dass dies mir etwas gab, das ich in die anderen Funktionen übertragen konnte, das war es nicht.

Mein Problem war überhaupt nicht mit 0.5.x, wenn Sie richtig in Bytes konvertieren, funktioniert der Rest des Codes wie erwartet. Sie müssen im Vergleich zu 0.4.x nur ein paar zusätzliche Konvertierungen durchführen. Die Serialitätsbibliothek funktioniert hervorragend.

Hier ist ein Beispiel für eine Konvertierung von einem Int in Bytes und zurück zu diesem Int:

function intToBytesToInt(int256 _input) public pure returns (int256) {
  bytes memory buffer = new bytes(32);
  uint offset = 32;

  assembly{
    mstore(add(buffer, offset), _input)
  }

  //b is the converted input
  bytes memory b = buffer;

  //Post 0.5.0 you must remember to convert to the appropriate size. For int256, that's bytes32.

  bytes32 preI;

  assembly {
    preI := mload(add(buffer, offset))
  }

  //i is b converted back to an int256
  int256 i = int256(preI);

  return i;
}