Skip to content

Commit

Permalink
Merge pull request #349 from MeshJS/fature-offline-fetcher
Browse files Browse the repository at this point in the history
Feature offline evaluator
  • Loading branch information
jinglescode authored Nov 15, 2024
2 parents 6b26824 + 81ea535 commit 2b38da9
Show file tree
Hide file tree
Showing 26 changed files with 499 additions and 86 deletions.
6 changes: 2 additions & 4 deletions apps/playground/src/components/site/metatags.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,15 @@ export default function Metatags({
}

if (title === undefined) {
title = "Mesh JS - Cardano Web3 TypeScript SDK & Off-Chain Framework";
} else {
title = title + " - Mesh JS";
title = "Cardano Web3 TypeScript SDK & Off-Chain Framework";
}

return (
<Head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charSet="utf-8" />

{title && <title>{title}</title>}
{title && <title>{`${title} - Mesh JS`}</title>}
<meta name="description" content={description} />
<meta name="keywords" content={keywords} />

Expand Down
4 changes: 4 additions & 0 deletions apps/playground/src/data/cardano.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export const oneTimeMintingPolicy =
export const demoTransactionCbor =
"84a70081825820859d3b4fd3a4c012b43ee1bbbc99240aec1827c3b8a74b867d10a7f4759149bc00018382583900e4cfbbc317c718f78d137b6535d8940618cc3d2ac04f1f35acf78e53a1521c2cea3cc79762d575581e47ea60b8eaa03430716cfd6140c796821a0011b0dea1581c67dd133868f14107b25772f3c5abaa1e0549f4b400b5e0e3a1136152a149000643b0546573743101a300581d7067dd133868f14107b25772f3c5abaa1e0549f4b400b5e0e3a113615201821a001ad510a1581c67dd133868f14107b25772f3c5abaa1e0549f4b400b5e0e3a1136152a149000de140546573743101028201d8185882d8799fa4446e616d6545546573743145696d6167655835697066733a2f2f516d527a6963705265757477436b4d36616f74754b6a4572464355443231334470775071364279757a4d4a617561496d656469615479706549696d6167652f6a70674b6465736372697074696f6e5348656c6c6f20776f726c64202d20434950363802ff825839003659ed2a30abb32e97589f2a01c8500ce8fc4897b868ebe42fbf4a8aa1521c2cea3cc79762d575581e47ea60b8eaa03430716cfd6140c7961a00134249021a000c830909a1581c67dd133868f14107b25772f3c5abaa1e0549f4b400b5e0e3a1136152a249000643b054657374310149000de1405465737431010b58207ae25a8a9286347cc1e0444a0de75e07432a6ed243591ef673fd837bb5235a670d82825820859d3b4fd3a4c012b43ee1bbbc99240aec1827c3b8a74b867d10a7f4759149bc00825820859d3b4fd3a4c012b43ee1bbbc99240aec1827c3b8a74b867d10a7f4759149bc050e81581ce4cfbbc317c718f78d137b6535d8940618cc3d2ac04f1f35acf78e53a206815883588101000032323232323232322232533300632323232533300a3370e9000000899b8f375c601c601000e911046d6573680014a0601000260180026018002600800429309b2b19299980319b87480000044c8c94ccc02cc03400852616375c601600260080062c60080044600a6ea80048c00cdd5000ab9a5573aaae7955cfaba157450581840100d8799f446d657368ff821a006acfc01ab2d05e00f5f6";

// from content ownership mint policy
export const demoTransactionCborScript =
"84a600d901028182582056ae6e2d8c419ab279ecd308040b8f56025cd4a287c75c182f8ccc0fd4115b0700018182583900556f3a70b8a68081cf36c918dd9933abdca34f20fc534499c817182b8cfb40854d41392b624b678012443d61015f5575627a467c450396c9821a008c2c8fa1581c8251cfa433b84ed4357143657f1c33740caa9e953c5f266c86ecfaf5a14001021a000c69f109a1581c8251cfa433b84ed4357143657f1c33740caa9e953c5f266c86ecfaf5a140010b58204fb018afc3952620696789649a8447595f9895ec48bda9c2596f0507e9b43f360dd9010281825820e8b1c89936d747185cf77c3eb42a37749cb4bdfee36d8763cfffad264ecbe0b900a207d90102815901cc5901c901010033232323232323222533300332323232325332330093001300a37540042646464a66601860080022a66601e601c6ea8018540085854ccc030cdc3a40040022a66601e601c6ea8018540085858c030dd50028992999805980198061baa0051533300b3003300c375464660020026eb0c044c038dd50041129998080008a6103d87a800013232533300f3375e01c600a60226ea80084cdd2a40006602600497ae01330040040013014002301200114a229404c8cc004004c8cc004004dd59809180998099809980998079baa00922533301100114bd70099199911191980080080191299980b80088018991980c9ba733019375200c66032602c00266032602e00297ae033003003301b0023019001375c60200026eacc044004cc00c00cc054008c04c004894ccc040004528899299980719299980799b8f375c600a00200c266e20dd6980a180a980a800a40002944dd618098010998018018008a50301300123010001375c601c60166ea8008dc3a40002c6018601a004601600260160046012002600a6ea8004526136565734aae7555cf2ab9f5740ae855d1260127d8799f582056ae6e2d8c419ab279ecd308040b8f56025cd4a287c75c182f8ccc0fd4115b0700ff000105a182010082d87980821a006acfc01ab2d05e00f5f6";

export const yaci = {
mnemonic: [
"test",
Expand Down
12 changes: 10 additions & 2 deletions apps/playground/src/data/links-providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@ export const metaOfflineFetcher = {
title: "Offline Fetcher",
link: "/providers/offline-fetcher",
desc: "Provider for testing, development and offline scenarios",
thumbnail: "/providers/hydra.svg",
thumbnail: "/logo-mesh/mesh.png",
};

export const metaOfflineEvaluator = {
title: "Offline Evaluator",
link: "/providers/offline-evaluator",
desc: "An offline Plutus script evaluator for testing and validation.",
thumbnail: "/logo-mesh/mesh.png",
};

export const linksProviders: MenuItem[] = [
Expand All @@ -66,7 +73,8 @@ export const linksProviders: MenuItem[] = [
metaOgmios,
metaU5c,
metaYaci,
metaOfflineFetcher
metaOfflineFetcher,
metaOfflineEvaluator,
];

export const metaProviders = {
Expand Down
20 changes: 17 additions & 3 deletions apps/playground/src/pages/providers/evaluators/evaluate-tx.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { useState } from "react";

import { OfflineEvaluator } from "@meshsdk/core-csl";

import { getProvider } from "~/components/cardano/mesh-wallet";
import Input from "~/components/form/input";
import InputTable from "~/components/sections/input-table";
import LiveCodeDemo from "~/components/sections/live-code-demo";
import TwoColumnsScroll from "~/components/sections/two-columns-scroll";
import Codeblock from "~/components/text/codeblock";
import { demoTransactionCbor } from "~/data/cardano";
import { demoTransactionCborScript } from "~/data/cardano";
import { SupportedEvaluators } from ".";

export default function EvaluatorEvaluateTransaction({
Expand All @@ -15,7 +18,7 @@ export default function EvaluatorEvaluateTransaction({
blockchainProvider: SupportedEvaluators;
provider: string;
}) {
const [userInput, setUserInput] = useState<string>(demoTransactionCbor);
const [userInput, setUserInput] = useState<string>(demoTransactionCborScript);

return (
<TwoColumnsScroll
Expand Down Expand Up @@ -91,17 +94,28 @@ function Right(
provider: string,
) {
async function runDemo() {
const evaluateTx = await blockchainProvider.evaluateTx(userInput);
const blockchainProvider = getProvider();
const offlineeval = new OfflineEvaluator(blockchainProvider, "preprod");
const evaluateTx = await offlineeval.evaluateTx(userInput);
return evaluateTx;
}

let code = ``;
code += `import { BlockfrostProvider } from "@meshsdk/core";\n`;
code += `import { OfflineEvaluator } from "@meshsdk/core-csl";\n`;
code += `\n`;
code += `const blockchainProvider = new BlockfrostProvider('<Your-API-Key>');\n`;
code += `const offlineeval = new OfflineEvaluator(blockchainProvider, "preprod");\n\n`;
code += `const evaluateTx = await offlineeval.evaluateTx('<UNSIGNED-TX-HEX>');\n`;

return (
<LiveCodeDemo
title="Evaluate Transaction"
subtitle="Evaluate the resources required to execute a transaction"
runCodeFunction={runDemo}
runDemoShowProviderInit={true}
runDemoProvider={provider}
code={code}
>
<InputTable
listInputs={[
Expand Down
4 changes: 3 additions & 1 deletion apps/playground/src/pages/providers/evaluators/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from "@meshsdk/core";

import EvaluatorEvaluateTransaction from "./evaluate-tx";
import {OfflineEvaluator} from "@meshsdk/core-csl";

export default function ProviderEvaluators({
blockchainProvider,
Expand All @@ -30,4 +31,5 @@ export type SupportedEvaluators =
| YaciProvider
| MaestroProvider
| OgmiosProvider
| U5CProvider;
| U5CProvider
| OfflineEvaluator;
125 changes: 125 additions & 0 deletions apps/playground/src/pages/providers/offline-evaluator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import type { NextPage } from "next";

import { OfflineFetcher } from "@meshsdk/core";
import { OfflineEvaluator } from "@meshsdk/core-csl";

import ButtonFloatDocumentation from "~/components/button/button-float-documentation";
import SidebarFullwidth from "~/components/layouts/sidebar-fullwidth";
import Link from "~/components/link";
import TitleIconDescriptionBody from "~/components/sections/title-icon-description-body";
import Metatags from "~/components/site/metatags";
import Codeblock from "~/components/text/codeblock";
import { metaOfflineEvaluator } from "~/data/links-providers";
import ProviderEvaluators from "./evaluators";

const ReactPage: NextPage = () => {
const sidebarItems = [{ label: "Evaluate Transaction", to: "evaluateTx" }];

let code1 = `import { OfflineEvaluator } from "@meshsdk/core-csl";\n\n`;
code1 += `import { OfflineFetcher } from "@meshsdk/core";\n\n`;
code1 += `// Create fetcher for resolving UTXOs\n`;
code1 += `const fetcher = new OfflineFetcher();\n\n`;
code1 += `// Add UTXOs required for script evaluation\n`;
code1 += `fetcher.addUTxOs([\n`;
code1 += ` {\n`;
code1 += ` input: { \n`;
code1 += ` txHash: "5de23a2...", \n`;
code1 += ` outputIndex: 0 \n`;
code1 += ` },\n`;
code1 += ` output: {\n`;
code1 += ` address: "addr1...",\n`;
code1 += ` amount: [{ unit: "lovelace", quantity: "1000000" }],\n`;
code1 += ` scriptHash: "32b7e3d..." // For script UTXOs\n`;
code1 += ` }\n`;
code1 += ` }\n`;
code1 += `]);\n\n`;
code1 += `// Create evaluator for the desired network\n`;
code1 += `const evaluator = new OfflineEvaluator(fetcher, "preprod");\n`;

let code2 = `// Evaluate Plutus scripts in a transaction\n`;
code2 += `try {\n`;
code2 += ` const actions = await evaluator.evaluateTx(transactionCbor);\n`;
code2 += ` // Example result:\n`;
code2 += ` // [{\n`;
code2 += ` // index: 0,\n`;
code2 += ` // tag: "MINT",\n`;
code2 += ` // budget: {\n`;
code2 += ` // mem: 508703, // Memory units used\n`;
code2 += ` // steps: 164980381 // CPU steps used\n`;
code2 += ` // }\n`;
code2 += ` // }]\n`;
code2 += `} catch (error) {\n`;
code2 += ` console.error('Script evaluation failed:', error);\n`;
code2 += `}\n`;

let code3 = `// In your test file\n`;
code3 += `describe("Plutus Script Tests", () => {\n`;
code3 += ` let evaluator: OfflineEvaluator;\n`;
code3 += ` let fetcher: OfflineFetcher;\n\n`;
code3 += ` beforeEach(() => {\n`;
code3 += ` fetcher = new OfflineFetcher();\n`;
code3 += ` evaluator = new OfflineEvaluator(fetcher, "preprod");\n\n`;
code3 += ` // Add test UTXOs\n`;
code3 += ` fetcher.addUTxOs([...]);\n`;
code3 += ` });\n\n`;
code3 += ` it("should evaluate minting policy", async () => {\n`;
code3 += ` const result = await evaluator.evaluateTx(txCbor);\n`;
code3 += ` expect(result[0].tag).toBe("MINT");\n`;
code3 += ` expect(result[0].budget.mem).toBeLessThan(600000);\n`;
code3 += ` });\n`;
code3 += `});\n`;

const fetcher = new OfflineFetcher();
const evaluator = new OfflineEvaluator(fetcher, "preprod");

return (
<>
<Metatags
title={metaOfflineEvaluator.title}
description={metaOfflineEvaluator.desc}
/>
<SidebarFullwidth sidebarItems={sidebarItems}>
<TitleIconDescriptionBody
title={metaOfflineEvaluator.title}
description={metaOfflineEvaluator.desc}
>
<p>
The OfflineEvaluator calculates execution costs (memory and CPU
steps) for Plutus scripts in transactions without requiring network
connectivity. It works with an{" "}
<Link href="/providers/offline-fetcher">OfflineFetcher</Link> to
resolve the UTXOs needed for script validation. This is also
compatible with any other fetchers to provide online data fetching.
</p>

<p>Get started:</p>

<Codeblock data={code1} />

<p>
Once initialized, you can evaluate Plutus scripts in transactions:
</p>
<Codeblock data={code2} />

<p>
The evaluator is particularly useful for testing Plutus scripts,
ensuring they execute within memory and CPU limits:
</p>
<Codeblock data={code3} />

<p>
The evaluation results include memory units and CPU steps required
for each script execution, helping you optimize your scripts and
ensure they meet protocol constraints.
</p>
</TitleIconDescriptionBody>

<ButtonFloatDocumentation href="https://docs.meshjs.dev/providers/classes/OfflineEvaluator" />

<ProviderEvaluators blockchainProvider={evaluator} provider="offline" />
</SidebarFullwidth>
</>
);
};

export default ReactPage;
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const ReactPage: NextPage = () => {
];

let example = ``;

example += `import { MeshContentOwnershipContract } from "@meshsdk/contract";\n`;
example += `import { MeshTxBuilder, BlockfrostProvider } from "@meshsdk/core";\n`;
example += `\n`;
Expand Down
Loading

0 comments on commit 2b38da9

Please sign in to comment.