Strings können in Solidity Smart Contract mit Web3 nicht korrekt gespeichert werden

Ich habe es mit einem sehr einfachen Smart Contract zu tun:

contract MyRegistry {

    struct MyEvent {
        string code; // service code, e.g. 1001/FOO/BAR
        string desc; // long string
        uint count;
        bool recorded;
    }

    event Record(bytes32 hash, string desc, uint count);

    function record(bytes32 hash, string code, string desc, uint count) external {
        if (registry[hash].recorded)
            throw;
        registry[hash] = MyEvent(code, desc, count, true);
    }

    mapping (bytes32 => MyEvent) public registry;
}

Ich verwende dann web3s getData()zum Generieren von Transaktionsnutzlasten:

var EthTX = require('ethereumjs-tx')
[...]
var calldata = Registry.record.getData(hash, code, desc, count)
[...]
var transaction = new EthTX({
    to: registry_address,
    gasLimit: 500000,
    gasPrice: +web3.toWei(10, 'gwei'),
    nonce: myNonce,
    data: calldata,
})

Die Transaktion läuft gut, aber dann registrysehe ich beim Abfragen des durchgehenden Remix:

code: ""
desc: ""
count: 27
recorded: true

Streicher wurden nicht aufgenommen!


Ich habe auch versucht, getDataauf diese Weise zu verwenden:

getData(hash, Web3.fromAscii(code), Web3.fromAscii(desc), count)

und auf diese andere Weise:

getData(hash, Web3.toHex(code), Web3.toHex(desc), count)

aber das Ergebnis ist noch schlimmer:

code: ""
desc: "<long hex string containing both code and desc strings>" 
count: 27
recorded: true

Ich kann nicht verstehen, was passiert. Es ist, als wäre web3 nicht in der Lage, die Nutzdaten korrekt zu serialisieren, und als Folge davon kann die intelligente Vertragsschnittstelle nicht die richtige Anzahl von Bytes in die richtigen "Slots" stecken.

Irgendeine Idee?

PSrecord wenn ich die Methode von Remix aufrufe , mit den gleichen Werten, funktioniert es offensichtlich!

Antworten (1)

Ich habe das Problem gefunden.

Der Fehler ist tatsächlich das, was ich vermutet hatte: Die Nutzlast wurde nicht korrekt serialisiert und als Folge davon konnte die Smart Contract-Schnittstelle nicht die richtige Anzahl von Bytes in die richtigen "Slots" stecken.

Grund? Mein Fehler...

hashist der erste Parameter der recordMethode. Variable ist auch hashdas Ergebnis einer keccak256-JS-Bibliothek, hex-kodiert . Nun, getData()auf diese Weise verwenden:

contract.record.getData(hash, code, desc, count)

ist total falsch . hashist bereits hexadezimal kodiert, aber ohne 0xPräfix. Erkennt es also getData()als normalen String und wandelt es wieder in einen anderen Hex-String um. Was das bedeutet? das bedeutet, der neu konvertierte Hex-String passt nicht mehr inbytes32 .

Lösung:0x Präfix hinzufügen , hashum anzuzeigen, getData()dass es sich bereits um eine Hex-Zeichenfolge handelt (d. h. unberührt lassen):

contract.record.getData(`0x${hash}`, code, desc,  count)

Außerdem besteht absolut keine Notwendigkeit, für die anderen zwei Strings zu verwenden .fromAscii(), da getData()sie als normale Strings erkannt werden, weil sie kein 0xPräfix haben, und sie daher automatisch in Hex konvertieren.