Use of HashSha2256 in parameter to invoke function results to wrong hash value in the smart contract state

Hi again,

Am try to call an update function from my contract from some code using rust sdk. My smart contract function (update) accepts a parameter with a HashSha2256 in it. from my client code, I’m using [u8; 32] to represent the attribute as HashSha2256 is a type in concordium-std and I don’t want to use this crate in my client code. The contract state gets updated when calling the update function, but the problem is that it saves the wrong hash value.
So the hash param

40487c5b0d0ae83d2c9d5d2e7c1ef91d840e531062b9bd9c6030f036a87afd57
is saved as
00000040487c5b0d0ae83d2c9d5d2e7c1ef91d840e531062b9bd9c6030f036a8

From above, it seems that somewhere in the concordium-std library for serialising/deserializing, the array gets cut and then padded (reason for the 0s). Is this a bug?

I’ve tried replacing the [u8;32] type in my client param struct with just a String, but it saves a totally different hash.
Fx:

c5a58d777c53b3e53d9b2556181f4a13aaf43c4fb1384a90658bbfbeea744e44
becomes:
0000004000000063356135386437373763353362336535336439623235353631

I’m now tempted to just use String all over in my smart contract structs to represent hashes instead of arrays. Is it okay or is it expensive to use Strings?

Br ulapcyber

I would store them as strings and don’t see it as much more expensive and way easier. Would love to know what causes the shifting of the hash format to the right too

1 Like

Using [u8; 32] should be the correct thing. I am not sure where the padding is coming from.

Can you show me the relevant part of the code, both the parameter parsing/storage for the contract and how you call it using the rust-sdk?

You can send it in the private message if you do not wish to share publicly.

yeah, the hash has a known format and fixed length so would be good to stick with [u8;32]. Thanks, I will DM parts of the code. Then we can share the root cause and conclusion here later.

Thanks @abizjak for the help. Sharing your message here so that others will know about the root cause of the problem (user stupid mistake) :grin:

I am not sure I understand it entirely, but your MintParams in on and off-chain are different.

In the on-chain code you have

     #[concordium(size_length = 1)]

on the set but in the off-chain code you don’t have this, meaning that the length gets serialized with 4 bytes for the length.

One effect of this would be that when on-chain your read the set, the first hash would be padded with (probably, depending on the size of the set) 3 zeros. And all remaining ones would be shifted by 3 bytes.

I also see that in the off-chain code you have String for the metadata hash, but on-chain you have [u8; 32].

As a side note, beginning of August we have released an update concordium-std and concordium-contracts-common, as well as updated the rust-sdk. Now you can derive serialization for on and off-chain code. The intention is that you define a separate crate of “types” that you need on and off-chain, possibly with some functionality feature gated so that, e.g., you derive Serde stuff only for off-chain code. Then you would import this crate in both your smart contract crate, and in your off-chain code.

This would remove duplication of code and issue with inconsistencies like this.

1 Like