Emurgo / cardano-serialization-lib

This is a library, written in Rust, for serialization & deserialization of data structures used in Cardano's Haskell implementation of Alonzo along with useful utility functions.
Other
236 stars 125 forks source link

`hash_script_data` accidentally frees datums object #543

Open longngn opened 2 years ago

longngn commented 2 years ago

How to reproduce:

import {
  hash_script_data,
  PlutusList,
  Redeemers,
  TxBuilderConstants,
} from "@emurgo/cardano-serialization-lib-nodejs";

let datums = PlutusList.new();
console.log(datums);
hash_script_data(
  Redeemers.new(),
  TxBuilderConstants.plutus_vasil_cost_models(),
  datums
);
console.log(datums);
console.log(datums.len());

Logs:

PlutusList { ptr: 1245192 }
PlutusList { ptr: 0 }
/home/long/code/test/node_modules/@emurgo/cardano-serialization-lib-nodejs/cardano_serialization_lib.js:20244
    throw new Error(getStringFromWasm0(arg0, arg1));
          ^
Error: null pointer passed to rust
    at module.exports.__wbindgen_throw (/home/long/code/test/node_modules/@emurgo/cardano-serialization-lib-nodejs/cardano_serialization_lib.js:20244:11)
    at wasm://wasm/0070f84e:wasm-function[6036]:0x1a2159
    at wasm://wasm/0070f84e:wasm-function[6034]:0x1a213f
    at wasm://wasm/0070f84e:wasm-function[5194]:0x199add
    at PlutusList.len (/home/long/code/test/node_modules/@emurgo/cardano-serialization-lib-nodejs/cardano_serialization_lib.js:9282:24)
    at Object.<anonymous> (/home/long/code/test/main.ts:17:20)
    at Module._compile (node:internal/modules/cjs/loader:1126:14)
    at Module.m._compile (/home/long/.nvm/versions/node/v16.17.0/lib/node_modules/ts-node/src/index.ts:1618:23)
    at Module._extensions..js (node:internal/modules/cjs/loader:1180:10)
    at Object.require.extensions.<computed> [as .ts] (/home/long/.nvm/versions/node/v16.17.0/lib/node_modules/ts-node/src/index.ts:1621:12)
vsubhuman commented 2 years ago

@longngn , yeah this is an unfortunately a "feature" of this API developed a long time ago. The datums parameter in that Rust function is of type Option<PlutusList> so it cannot be properly passed by reference and is getting passed by value, which consumes that value, by the Rust rules.

Since then we have already made it a rule to never have Option type in function arguments and are trying to solve it with alternative approaches, but this function still exists yet. It will be deprecated and replaced with a newer API in one of the next versions.

The best recommendation for using it is to clone the datum when you are passing it, e.g:

hash_script_data(
  Redeemers.new(),
  TxBuilderConstants.plutus_vasil_cost_models(),
  datums.clone(),
);

This will preserve the original reference.

Or if you are using the TransactionBuilder then it is recommended to use the .calc_script_data_hash function on the builder instead of calculating and setting the hash manually.