Incorrect Hash for Tx
I have passed all the required data to Tx API and calculated the hash
- for simple transaction without assets/datum/refScript the Hash returned is correct
- for transaction with assets/datum/refscript the Hash returned is incorrect
there are two files 1. calculate.ts
& 2. utils.ts
import { Value, TxBuilder, defaultProtocolParameters } from "@harmoniclabs/plu-ts";
import { TxBody, TxIn, TxOut, TxWitnessSet, UTxO, Tx, ITxOut } from "@harmoniclabs/cardano-ledger-ts";
import { toPlutsUtxo, toPlutsTxOut, toPlutsTxBody, toPlutsTx, toPlutsTxWitness } from './utils'
import * as WASM_lib from "@emurgo/cardano-serialization-lib-nodejs"
export function validateHash(hash: string, utxo: any, txn): boolean {
const utxosInputs = utxo.inputs
const utxosOutputs = utxo.outputs
// separating collateral, reference and inputs
var utxoInput = [];
var collateralInput = [];
var referenceInput = [];
utxosInputs.forEach(function (input) {
if (input.collateral) {
collateralInput.push(input);
} else if (input.reference) {
referenceInput.push(input);
} else {
utxoInput.push(input);
}
});
// separating output and collateral
var utxoOutput = [];
var collateralOutput;
utxosOutputs.forEach(function (output) {
if (output.collateral) {
collateralOutput = output;
} else {
utxoOutput.push(output);
}
});
// setting up inputs
const myUTxOInputs: UTxO[] = utxoInput.map(toPlutsUtxo);
const inputs = myUTxOInputs.map(input => new UTxO(input));
// let arrayUTxO: [UTxO, ...UTxO[]];
// if (inputs.length > 0) {
// arrayUTxO = [inputs[0], ...inputs.slice(1)];
// } else {
// console.error("Error: 'inputs' array is empty");
// }
//reference input
let referenceInputs: UTxO[]
if(referenceInput.length >= 1){
const myReferenceInputs: UTxO[] = referenceInput.map(toPlutsUtxo);
referenceInputs = myReferenceInputs.map(input => new UTxO(input));
}
//collateral input
let collateralInputs: UTxO[]
if(collateralInput.length >= 1){
const myCollateralInputs: UTxO[] = collateralInput.map(toPlutsUtxo);
collateralInputs = myCollateralInputs.map(input => new UTxO(input));
}
// setting outputs
const myUTxOOutputs: ITxOut[] = utxoOutput.map(toPlutsTxOut);
const outputs = myUTxOOutputs.map(output => new TxOut(output));
//collateral output
let collateralOutputs: TxOut
if(collateralOutput){
const myCollateralOutputs = toPlutsTxOut(collateralOutput);
collateralOutputs = new TxOut(myCollateralOutputs);
}
// body parameter fees, invalid_after, invalid_before
const fees= txn.fees? parseInt(txn.fees) : undefined
const invalidBefore = txn.invalid_before? parseInt(txn.invalid_before) : undefined
const invalidAfter = txn.invalid_hereafter? parseInt(txn.invalid_hereafter): undefined
//setting body
const myTxbody = toPlutsTxBody(inputs, outputs, fees, invalidBefore, invalidAfter, collateralInputs, referenceInputs, collateralOutputs)
const txbody = new TxBody(myTxbody)
console.log(txbody)
// witness
const myWitnesses = toPlutsTxWitness()
const witnesses = new TxWitnessSet(myWitnesses)
//tx
const mytx = toPlutsTx(txbody, witnesses)
const tx = new Tx(mytx)
//
const cbor = tx.toCbor()
const rawTx = WASM_lib.Transaction.from_bytes(Buffer.from(cbor.toString(), 'hex'));
const txHash = WASM_lib.hash_transaction(rawTx.body());
console.log(txHash.to_hex())
return hash == txHash.to_hex()
}
const utxoData = <utxo data> //blockfrost api - /txs/{hash}/utxos
const hash = <transaction hash>
const txn = <transaction details> // blockfrost api - /txs/{hash}/
const hashCorrect = validateHash(hash, utxoData, txn)
console.log(hashCorrect)
utils.ts to convert objects and values into correct type
"use strict";
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
if (ar || !(i in from)) {
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
ar[i] = from[i];
}
}
return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.toPlutsTx = exports.toPlutsTxWitness = exports.toPlutsTxBody = exports.toPlutsTxOut = exports.toPlutsUtxo = void 0;
var plu_ts_1 = require("@harmoniclabs/plu-ts");
var uint8array_utils_1 = require("@harmoniclabs/uint8array-utils");
function toPlutsValue(units) {
return units.map(function (_a) {
var unit = _a.unit, quantity = _a.quantity;
if (unit.length === 0 || unit === "lovelace") {
return plu_ts_1.Value.lovelaces(BigInt(quantity));
}
var policy = new plu_ts_1.Hash28(unit.slice(0, 56));
var assetName = (0, uint8array_utils_1.fromHex)(unit.slice(56));
return plu_ts_1.Value.singleAsset(policy, assetName, BigInt(quantity));
})
.reduce(function (a, b) { return plu_ts_1.Value.add(a, b); });
}
function toPlutsUtxo(utxoInput) {
// const utxoInput = u.inputs[0]
var input = new plu_ts_1.UTxO({
utxoRef: {
id: utxoInput.tx_hash,
index: utxoInput.output_index
},
resolved: {
address: utxoInput.address,
value: toPlutsValue(utxoInput.amount),
datum: utxoInput.inline_datum !== null ?
(0, plu_ts_1.dataFromCbor)(utxoInput.inline_datum) :
utxoInput.data_hash !== null ?
new plu_ts_1.Hash32(utxoInput.data_hash) :
undefined,
refScript: utxoInput.reference_script_hash !== null ?
new plu_ts_1.Script("PlutusScriptV2", (0, uint8array_utils_1.fromHex)(utxoInput.reference_script_hash)) :
undefined
}
});
// console.log(`address: ${input.resolved.address} \n value: ${input.resolved.value} \n datum: ${input.resolved.datum} \n refscript ${input.resolved.refScript} \n --------------------------------------------`)
// console.log((utxoInput.inline_datum !== null ? dataFromCbor(utxoInput.inline_datum) : "null"))
return input;
}
exports.toPlutsUtxo = toPlutsUtxo;
function toPlutsTxOut(utxoOutput) {
// const utxoOutput = u.outputs[0]
return ({
address: utxoOutput.address,
datum: utxoOutput.inline_datum !== null ?
(0, plu_ts_1.dataFromCbor)(utxoOutput.inline_datum) :
utxoOutput.data_hash !== null ?
new plu_ts_1.Hash32(utxoOutput.data_hash) :
undefined,
refScript: utxoOutput.reference_script_hash !== null ?
new plu_ts_1.Script("PlutusScriptV2", (0, uint8array_utils_1.fromHex)(utxoOutput.reference_script_hash)) :
undefined,
value: toPlutsValue(utxoOutput.amount),
});
// console.log(`address: ${output.address} \n value: ${output.value} \n datum: ${output.datum} \n refscript: ${output.refScript}`)
}
exports.toPlutsTxOut = toPlutsTxOut;
function toPlutsTxBody(inputs, output, fee, invalid_before, ttl, collateralInput, refInput, collateralOutputs) {
if (invalid_before === void 0) { invalid_before = undefined; }
if (ttl === void 0) { ttl = undefined; }
if (collateralInput === void 0) { collateralInput = undefined; }
if (refInput === void 0) { refInput = undefined; }
if (collateralOutputs === void 0) { collateralOutputs = undefined; }
// const utxoOutput = u.outputs[0]
return ({
inputs: __spreadArray([inputs[0]], inputs.slice(1), true),
outputs: output,
fee: fee,
ttl: ttl,
collateralInputs: collateralInput,
refInputs: refInput,
validityIntervalStart: invalid_before,
collateralReturn: collateralOutputs
});
}
exports.toPlutsTxBody = toPlutsTxBody;
function toPlutsTxWitness() {
return ({});
}
exports.toPlutsTxWitness = toPlutsTxWitness;
function toPlutsTx(body, witnesses) {
// const utxoOutput = u.outputs[0]
return ({
body: body,
witnesses: witnesses
});
}
exports.toPlutsTx = toPlutsTx;
.