cardano-serialization-lib icon indicating copy to clipboard operation
cardano-serialization-lib copied to clipboard

different transaction hash from cardano-cli

Open leobel opened this issue 3 years ago • 2 comments

Hi, I've built and signed a transaction using cardano-cli version 1.31.0 here is the final tx:

{
    "type": "Tx AlonzoEra",
    "description": "",
    "cborHex": "84a700818258208b9c96823c19f2047f32210a330434b3d163e194ea17b2b702c0667f6fea7a7a000d80018182581d6138fe1dd1d91221a199ff0dacf41fdd5b87506b533d00e70fae8dae8f1abfbac06a021a0002b645031a03962de305a1581de1b3cabd3914ef99169ace1e8b545b635f809caa35f8b6c8bc69ae48061abf4009040e80a100828258207dc05ac55cdfb9cc24571d491d3a3bdbd7d48489a916d27fce3ffe5c9af1b7f55840d7eda8457f1814fe3333b7b1916e3b034e6d480f97f4f286b1443ef72383279718a3a3fddf127dae0505b01a48fd9ffe0f52d9d8c46d02bcb85d1d106c13aa048258201b3d6e1236891a921abf1a3f90a9fb1b2568b1096b6cd6d3eaaeb0ef0ee0802f58401ce4658303c3eb0f2b9705992ccd62de30423ade90219e2c4cfc9eb488c892ea28ba3110f0c062298447f4f6365499d97d31207075f9815c3fe530bd9a927402f5f6"
}

If I ask for the transaction hash using this command cardano-cli transaction txid --tx-file tx.signed I get the following hash: 05465e6ac7abb9c11f9ebb57473a100c1810ec719367bf91d05e50c8d4b44e19.

But if I try to get the hash with cardano-serialization-lib version 10.0.4 using this code:

const transaction = Transaction.from_bytes(Buffer.from(cborHex, 'hex'));
const txBody = transaction.body();
const txHash = hash_transaction(txBody);
const txId = Buffer.from(txHash.to_bytes()).toString('hex');

The resulting hash is this: dd3b689787ef2ffb49549ce68cea2432ec740370146a89088b65681dcec0ba91.

The final tx hash in the blockchain is the one from cardano-cli (who actually built and signed the tx): 05465e6ac7abb9c11f9ebb57473a100c1810ec719367bf91d05e50c8d4b44e19.

I don't know exactly if there is something wrong with my code using cardano-serialization-lib. It seems to me they are just hashing in different ways since If I build a tx and sign it using cardano-serialization-lib for the entire process, then the final hash getting into the blockchain is the one from my code without issue.

So I'd like to confirm that indeed the hashing algorithm between cardano-cli and cardano-serialization-lib aren't compatible and if this is the case, how can get the same hash resulting from cardano-cli or detect whether the tx was built with one method or the other.

leobel avatar May 04 '22 03:05 leobel

Something I 'd noticed is the other way around the tx's hashes are EQUAL. I mean building and signing the tx with cardano-serialization-lib then ask cardano-cli for the hash and the result is the same.

leobel avatar May 04 '22 03:05 leobel

@leobel It's because of how CBOR works. There are multiple ways in CBOR to represent the same data i.e. the number 2 can be represented with 1, 2, 3, or 4 bytes. Lists/map lengths can either be explicit to start Len(4), 1, 2, 3, 4 or indefinite with a terminating break like Len(Indefinite), 1, 2, 3, 4, Break, or map orders can have their keys in different order. Unfortunately right now cardano-serialization-lib doesn't maintain the serialization format upon using from_bytes so if cardano-cli uses non-canonical CBOR this will result in different hashes. It instead always uses canonical CBOR to work with hardware wallets via CIP-0021. The hashing algorithm is the same. So basically if you did let tx = Transaction.from_bytes(bytes) and then used the hash computed by cardano-serialization-lib using tx it would be valid and would correspond to tx.to_bytes() but wouldn't necessarily correspond to the original bytes you deserialized it from. Hopefully this makes sense. I really wish canonical CBOR was enforced at the node level because differences in this have caused many, many issues with inter-tool interoperability.

rooooooooob avatar May 04 '22 15:05 rooooooooob