Wie können Sie Anrufdatenbytes auf eine beliebige Anzahl verschiedener Protokollereignisse aufteilen?

Der folgende Code ist unvollständig. Was ich tun möchte, ist, die bytesDaten (Anrufdaten) aus Indizierungsgründen in zwei oder mehr separate Protokollfunktionen aufzuteilen.

Das Problem ist, dass ich nicht herausfinden kann, wie ich das in Solidity machen soll. bytesist von beliebiger Länge, daher kann ich die Calldata nicht in den Speicher kopieren, da kein Speicher mit beliebiger Länge zugewiesen werden kann (AFAICT aus der Solidity-Dokumentation). Ich stelle auch fest, dass der folgende Code vereinfacht ist - es wird nicht nur die Hälfte sein, es wird ein Bruchteil sein, der als weiterer Parameter auf gesetzt wird logit.

Ich bin mir nicht ganz sicher, aber wenn ich mir die kompilierte Ausgabe von Solidity ansehe, scheint es mir, als könnte ich dies direkt in der EVM-Assembly implementieren. Der EVM-Befehl log1nimmt einen Zeiger und eine Datenlänge als Eingabeargumente, also sollte es möglich sein. Der folgende Code funktioniert, daher weiß ich, dass irgendwie Anrufdaten beliebiger Länge an log1 gesendet werden können. Solidity lässt mich einfach nicht die Zeigerarithmetik durchführen, um die Daten aufzuteilen (oder ich kann nicht herausfinden, wie). Ich möchte die Assemblierung lieber nicht codieren ... (Ich kann bei Bedarf zu Serpent wechseln).

Ja, ich könnte separate Funktionen erstellen und die Daten außerhalb von Ethereum aufteilen. aber dann fallen mir die 21.000 Benzin Strafe für jeden Anruf an. Ich versuche, dies für niedrige Benzinkosten zu tun.

[EDIT] - Ja, ich könnte (höchstens) bis zu 7 Funktionsparameter verwenden, aber das gibt mir nur 7 Splits. Ich brauche in der Größenordnung von 64. Das bekomme ich, wenn ich versuche, die Frage zu sehr zu vereinfachen ...

// 
// attempt to figure out how to split incoming byte data into separate logs
//

contract HelpLogs {

  event LogFirstHalf(bytes _data);
  event LogSecondHalf(bytes _data);

  function logit(bytes data) external {
    // can't do the pointer arithmetic to LogFirstHalf and
    // then LogSecondHalf of data.  But I can log all of it...
    LogFirstHalf(data);
  }
}
Tangential: Verwenden Sie Serpent nicht, es ist veraltet – ethereum.stackexchange.com/questions/21375/why-did-serpent-die
Übrigens wird dies allgemein betrachtet zu einer allgemeineren Frage, wie man mit eingehenden Daten beliebiger Länge umgeht, ohne den Speicher verwenden zu müssen, um die Daten willkürlich aufzuteilen.

Antworten (1)

Willkürlicher Split-Ansatz

Bearbeiten: Dieser Abschnitt wurde hinzugefügt, um beliebige Split-Ziele anzusprechen

Zum Zeitpunkt der Teilung sollten Sie die Länge der Zieldaten kennen. Unten ist eine Beispielimplementierung zum Kopieren der Bytes an ihr Ziel innerhalb von Solidity, die trivial auf N Buckets erweiterbar sein sollte.

pragma solidity ^0.4.15;

contract HelpLogs {

  event LogFirstHalf(bytes _data);
  event LogSecondHalf(bytes _data);

  function logit(bytes data) external {
      uint midpoint = data.length / 2;
      bytes memory data1 = new bytes(midpoint);
      for (uint i = 0; i < midpoint; i++) {
          data1[i] = data[i];
      }
      bytes memory data2 = new bytes(data.length - midpoint);
      for (i = 0; i < data.length - midpoint; i++) {
          data2[i] = data[i + midpoint];
      }
      LogFirstHalf(data1);
      LogSecondHalf(data2);
  }
}

Beachten Sie, dass der Gasverbrauch höher ist als nötig, da er byteweise arbeitet. Es wäre schneller, 32-Byte-Wörter mit Bitmaskierung zu verwenden. Eine gute Referenz ist die memcpysolidity-string utils-Bibliothek von Arachnid.


[Edit: alt] Fixed Bucket Approach

Sie können die Daten ohne den Overhead von 21 kggas extern splitten. Senden Sie die vorgeteilten Daten als zwei Parameter an einen einzigen Funktionsaufruf:

pragma solidity ^0.4.15;

contract HelpLogs {

  event LogFirstHalf(bytes _data);
  event LogSecondHalf(bytes _data);

  function logit(bytes dataPart1, bytes dataPart2) external {
    LogFirstHalf(dataPart1);
    LogSecondHalf(dataPart2);
  }
}

Dies kostet weniger Gas als das Splitten innerhalb des EVM.

Entschuldigung, mit dieser Antwort hätte ich rechnen sollen. Ich werde die Frage als "beliebige Anzahl von Splits" umformulieren. Die Methode, die Sie vorschlagen, funktioniert nur mit (glaube ich) 8 Splits. Trotzdem danke!
Ich habe es getestet. Solidity beschwert sich über "Stapel zu tief" bei 8 Argumenten, also ist das Maximum 7. Ich muss auch eine Art Infoblock mitschicken, also werden es eher 6 sein.
Danke! Das könnte nur den Trick tun. Meine Daten sind definitiv auf 32-Byte-Grenzen, also dank des Verweises auf memcpy. Ich werde dies überprüfen, wenn ich einen funktionierenden Code habe.
Der anfängliche Lauf beträgt 50.000 Gas gegenüber 30.000 Gas ... wird die Speicherung zugewiesen?
Mein Lauf in Remix verwendet 5650 Gas während der Ausführung mit einer 5-Byte-Eingabe. Kompilieren Sie mit, solcohne --optimize?
Ich habe die Typen in geändert, bytes32[]da bytesmeine Daten sowieso wirklich 32 Byte groß sind (und das nimmt log1 auch) und die Kosten für die Protokollierung jedes zusätzlichen 32-Byte-Eintrags 2620 Gas betragen. Die ursprünglichen Kosten für die Protokollierung in einem Index betrugen 2450 Gas. Die Nettokosten der Kopie betragen also 170 Benzin. Das nenne ich gut. Danke!
Ich verwende standardmäßig alles, was Trüffel tut. Danke für die Erinnerung, das zu überprüfen.
es sind 68 Bytes pro Daten, die in calldata übergeben werden. (32-5) * 68 = 1836 Gas. Gtxdatanonzero ist sehr teuer...
Ja, leider müssen die Knoten alle Transaktionen aufbewahren, um andere Knoten zu booten, also ist dies mit ziemlich hohen öffentlichen Kosten verbunden.