I am dealing with a very simple smart contract:

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)
        registry[hash] = MyEvent(code, desc, count, true);

    mapping (bytes32 => MyEvent) public registry;

I then use web3's getData() for generating transaction payload:

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,

Transaction goes fine, but then, querying the registry through Remix, I see:

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

Strings have not been recorded!

I've also tried using getData in this way:

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

and in this other way:

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

but the result is even worse:

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

I cant understand what is happening. It is like web3 is not able to correctly serialize the payload and then, as a consequence, smart contract interface is not able to put the right number of bytes in the right "slots".

Any idea?

P.S. if I call the record method from Remix, with the same values, it obviously works!


I've found the problem.

The error is indeed what I was suspecting: the payload was not serialized correctly and, as a consequence, smart contract interface was not able to put the right number of bytes in the right "slots".

Reason? My bad...

hash is the first parameter of the record method. Also, hash variable is the result of a keccak256 JS library, hex encoded. Well, using getData() in this way:

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

is totally wrong. hash is already hex encoded, but it is not 0x prefixed. So getData() recognize it as a normal string, and converts it again to another hex string. What that means? that means the newly converted hex string no more fits into bytes32.

Solution: add 0x prefix to hash in order to tell getData() that it is already an hex string (i.e. leave it untouched):

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

Also, there is absolutely no need to use .fromAscii() for the others two strings, as getData() recognize them as normal string because they are not 0x prefixed, and so convert them to hex automatically.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.