Skip to content

Commit

Permalink
Merge pull request #381 from MeshJS/fix/tx-builder-fetcher-logic
Browse files Browse the repository at this point in the history
Fix/tx builder fetcher logic
  • Loading branch information
twwu123 authored Nov 12, 2024
2 parents e5729f7 + 5805eeb commit da8dc81
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 55 deletions.
3 changes: 2 additions & 1 deletion packages/mesh-common/src/types/transaction-builder/txin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import { Asset } from "../asset";
import { DatumSource, Redeemer } from "./data";
import { ScriptSource, SimpleScriptSourceInfo } from "./script";

export type RefTxIn = { txHash: string; txIndex: number, scriptSize?: number };
export type RefTxIn = { txHash: string; txIndex: number; scriptSize?: number };

export type TxInParameter = {
txHash: string;
txIndex: number;
amount?: Asset[];
address?: string;
scriptSize?: number;
};

export type TxIn = PubKeyTxIn | SimpleScriptTxIn | ScriptTxIn;
Expand Down
58 changes: 26 additions & 32 deletions packages/mesh-transaction/src/mesh-tx-builder/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,39 +84,12 @@ export class MeshTxBuilder extends MeshTxBuilderCore {

// Checking if all inputs are complete
const { inputs, collaterals, mints } = this.meshTxBuilderBody;
// We must check every input for ref scripts
const incompleteTxIns = [...inputs, ...collaterals];
const incompleteTxIns = [...inputs, ...collaterals].filter(
(txIn) => !this.isInputComplete(txIn),
);
const incompleteMints = mints.filter((mint) => !this.isMintComplete(mint));
// Getting all missing utxo information
await this.queryAllTxInfo(incompleteTxIns, incompleteMints);
// Gather all utxos with ref scripts
Object.values(this.queriedUTxOs).forEach((utxos) => {
for (let utxo of utxos) {
if (utxo.output.scriptRef !== undefined) {
this.utxosWithRefScripts.push(utxo);
}
}
});
const missingRefInput = this.utxosWithRefScripts.filter((utxo) => {
this.meshTxBuilderBody.referenceInputs.forEach((refInput) => {
if (
refInput.txHash === utxo.input.txHash &&
refInput.txIndex === utxo.input.outputIndex
) {
return false;
}
});
return true;
});
// Add any inputs with ref scripts into reference inputs
// serializer will then deduplicate, but keep the script size for fee calc
missingRefInput.forEach((utxo) => {
this.meshTxBuilderBody.referenceInputs.push({
txHash: utxo.input.txHash,
txIndex: utxo.input.outputIndex,
scriptSize: utxo.output.scriptRef!.length / 2,
});
});
// Completing all inputs
incompleteTxIns.forEach((txIn) => {
this.completeTxInformation(txIn);
Expand All @@ -131,6 +104,22 @@ export class MeshTxBuilder extends MeshTxBuilderCore {
this.completeSimpleScriptInfo(scriptSource);
}
});
this.meshTxBuilderBody.inputs.forEach((input) => {
if (input.txIn.scriptSize && input.txIn.scriptSize > 0) {
if (
this.meshTxBuilderBody.referenceInputs.find((refTxIn) => {
refTxIn.txHash === input.txIn.txHash &&
refTxIn.txIndex === input.txIn.txIndex;
}) === undefined
) {
this.meshTxBuilderBody.referenceInputs.push({
txHash: input.txIn.txHash,
txIndex: input.txIn.txIndex,
scriptSize: input.txIn.scriptSize,
});
}
}
});
this.addUtxosFromSelection();

let txHex = this.serializer.serializeTxBody(
Expand Down Expand Up @@ -285,6 +274,11 @@ export class MeshTxBuilder extends MeshTxBuilderCore {
);
input.txIn.address = address;
}
if (utxo?.output.scriptRef) {
input.txIn.scriptSize = utxo.output.scriptRef.length / 2;
} else {
input.txIn.scriptSize = 0;
}
};

protected completeScriptInfo = (scriptSource: ScriptSource) => {
Expand Down Expand Up @@ -331,8 +325,8 @@ export class MeshTxBuilder extends MeshTxBuilderCore {
};

protected isInputInfoComplete = (txIn: TxIn): boolean => {
const { amount, address } = txIn.txIn;
if (!amount || !address) return false;
const { amount, address, scriptSize } = txIn.txIn;
if (!amount || !address || scriptSize === undefined) return false;
return true;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,15 @@ export class MeshTxBuilderCore {
* @param txIndex The transaction index of the input UTxO
* @param amount The asset amount of index of the input UTxO
* @param address The address of the input UTxO
* @param scriptSize The size of the ref script at this input (if there isn't one, explicitly put 0 as scriptSize for offline tx building)
* @returns The MeshTxBuilder instance
*/
txIn = (
txHash: string,
txIndex: number,
amount?: Asset[],
address?: string,
scriptSize?: number,
) => {
if (this.txInQueueItem) {
this.queueInput();
Expand All @@ -92,6 +94,7 @@ export class MeshTxBuilderCore {
txIndex: txIndex,
amount: amount,
address: address,
scriptSize: scriptSize,
},
};
} else {
Expand All @@ -102,6 +105,7 @@ export class MeshTxBuilderCore {
txIndex: txIndex,
amount: amount,
address: address,
scriptSize: scriptSize,
},
scriptTxIn: {},
};
Expand Down
46 changes: 28 additions & 18 deletions packages/mesh-transaction/src/transaction/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import {
import {
Cardano,
CardanoSDKUtil,
deserializeTx,
deserializeNativeScript,
deserializePlutusScript,
deserializeTx,
fromScriptRef,
Serialization,
Transaction as Tx,
Expand All @@ -48,23 +48,22 @@ export class Transaction {
this.initiator = options.initiator;
}

static attachMetadata(
cborTx: string,
cborTxMetadata: string,
) {
static attachMetadata(cborTx: string, cborTxMetadata: string) {
const tx = deserializeTx(cborTx);
const txAuxData = tx.auxiliaryData() ?? new Serialization.AuxiliaryData();

txAuxData.setMetadata(
Serialization.GeneralTransactionMetadata.fromCbor(CardanoSDKUtil.HexBlob(cborTxMetadata))
Serialization.GeneralTransactionMetadata.fromCbor(
CardanoSDKUtil.HexBlob(cborTxMetadata),
),
);

if (
Cardano.computeAuxiliaryDataHash(txAuxData.toCore())?.toString() !==
tx.body().auxiliaryDataHash()?.toString()
) {
throw new Error(
'[Transaction] attachMetadata: The metadata hash does not match the auxiliary data hash.'
"[Transaction] attachMetadata: The metadata hash does not match the auxiliary data hash.",
);
}

Expand All @@ -81,8 +80,15 @@ export class Transaction {
const txMetadata = tx.auxiliaryData()?.metadata();

if (txMetadata !== undefined) {
const mockMetadata = new Map<bigint, Serialization.TransactionMetadatum>();
txMetadata.metadata()?.forEach((metadatum, label) => mockMetadata.set(label, mask(metadatum)));
const mockMetadata = new Map<
bigint,
Serialization.TransactionMetadatum
>();
txMetadata
.metadata()
?.forEach((metadatum, label) =>
mockMetadata.set(label, mask(metadatum)),
);
const txAuxData = tx.auxiliaryData();
txMetadata.setMetadata(mockMetadata);
txAuxData?.setMetadata(txMetadata);
Expand All @@ -94,18 +100,17 @@ export class Transaction {

static readMetadata(cborTx: string) {
const tx = deserializeTx(cborTx);
return tx.auxiliaryData()?.metadata()?.toCbor().toString() ?? '';
return tx.auxiliaryData()?.metadata()?.toCbor().toString() ?? "";
}

static writeMetadata(
cborTx: string,
cborTxMetadata: string,
) {
static writeMetadata(cborTx: string, cborTxMetadata: string) {
const tx = deserializeTx(cborTx);
const txAuxData = tx.auxiliaryData() ?? new Serialization.AuxiliaryData();

txAuxData.setMetadata(
Serialization.GeneralTransactionMetadata.fromCbor(CardanoSDKUtil.HexBlob(cborTxMetadata))
Serialization.GeneralTransactionMetadata.fromCbor(
CardanoSDKUtil.HexBlob(cborTxMetadata),
),
);

return new Tx(tx.body(), tx.witnessSet(), txAuxData).toCbor().toString();
Expand Down Expand Up @@ -216,6 +221,7 @@ export class Transaction {
input.input.outputIndex,
input.output.amount,
input.output.address,
input.output.scriptRef ? input.output.scriptRef.length / 2 : 0,
);
});

Expand Down Expand Up @@ -715,13 +721,17 @@ export class Transaction {
}
}

function mask(metadatum: Serialization.TransactionMetadatum): Serialization.TransactionMetadatum {
function mask(
metadatum: Serialization.TransactionMetadatum,
): Serialization.TransactionMetadatum {
switch (metadatum.getKind()) {
case Serialization.TransactionMetadatumKind.Text:
return Serialization.TransactionMetadatum.newText("0".repeat(metadatum.asText()?.length ?? 0));
return Serialization.TransactionMetadatum.newText(
"0".repeat(metadatum.asText()?.length ?? 0),
);
case Serialization.TransactionMetadatumKind.Bytes:
case Serialization.TransactionMetadatumKind.Integer:
return metadatum
return metadatum;
case Serialization.TransactionMetadatumKind.List:
const list = new Serialization.MetadatumList();
for (let i = 0; i < (metadatum.asList()?.getLength() ?? 0); i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe("MeshTxBuilder", () => {
it("should return true for complete PubKey input", () => {
const txIn: TxIn = {
type: "PubKey",
txIn: { txHash: "hash", txIndex: 0, amount: [], address: "address" },
txIn: { txHash: "hash", txIndex: 0, amount: [], address: "address", scriptSize: 0 },
};
expect(txBuilder.isInputCompleteExtended(txIn)).toBe(true);
});
Expand Down Expand Up @@ -89,7 +89,7 @@ describe("MeshTxBuilder", () => {
it("should return true for complete Script input", () => {
const txIn: TxIn = {
type: "Script",
txIn: { txHash: "hash", txIndex: 0, amount: [], address: "address" },
txIn: { txHash: "hash", txIndex: 0, amount: [], address: "address", scriptSize: 0 },
scriptTxIn: {
scriptSource: {
type: "Provided",
Expand All @@ -102,7 +102,7 @@ describe("MeshTxBuilder", () => {
it("should return true for complete Script input, with complete script ref", () => {
const txIn: TxIn = {
type: "Script",
txIn: { txHash: "hash", txIndex: 0, amount: [], address: "address" },
txIn: { txHash: "hash", txIndex: 0, amount: [], address: "address", scriptSize: 0 },
scriptTxIn: {
scriptSource: {
type: "Inline",
Expand Down Expand Up @@ -176,7 +176,7 @@ describe("MeshTxBuilder", () => {
it("should return true for complete PubKey input", () => {
const txIn: TxIn = {
type: "PubKey",
txIn: { txHash: "hash", txIndex: 0, amount: [], address: "address" },
txIn: { txHash: "hash", txIndex: 0, amount: [], address: "address", scriptSize: 0 },
};
expect(txBuilder.isInputInfoCompleteExtended(txIn)).toBe(true);
});
Expand Down

0 comments on commit da8dc81

Please sign in to comment.