Skip to content

Commit

Permalink
Host calls cleanup (#251)
Browse files Browse the repository at this point in the history
* Fix multi-PVM visual glitch (#241)

* Don't perform multiple steps when Stepping in the UI. (#240)

* Fix multi-PVM visual glitch (#243)

* Modify program editor to be available only in edit mode; improve error handling (#242)

* Move program code input to edit mode

* Handle errors in program text editor

* Allow for hex in array as a program input

* Fix linter

* refactor

---------

Co-authored-by: Wojciech Kwiatek <wojtek.kwiatek@gmail.com>
Co-authored-by: Tomek Drwięga <tomusdrw@users.noreply.github.com>
  • Loading branch information
3 people authored Dec 15, 2024
1 parent 9154aac commit 78fde84
Show file tree
Hide file tree
Showing 18 changed files with 215 additions and 174 deletions.
50 changes: 37 additions & 13 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,20 @@ import { MobileRegisters } from "./components/MobileRegisters";
import { MobileKnowledgeBase } from "./components/KnowledgeBase/Mobile";
import { Assembly } from "./components/ProgramLoader/Assembly";
import { useAppDispatch, useAppSelector } from "@/store/hooks.ts";
import { setClickedInstruction, setInstructionMode, setIsProgramEditMode } from "@/store/debugger/debuggerSlice.ts";
import {
setClickedInstruction,
setInstructionMode,
setIsProgramEditMode,
setIsProgramInvalid,
} from "@/store/debugger/debuggerSlice.ts";
import { MemoryPreview } from "@/components/MemoryPreview";
import { DebuggerControlls } from "./components/DebuggerControlls";
import { useDebuggerActions } from "./hooks/useDebuggerActions";
import { Loader } from "./components/ProgramLoader/Loader";
import classNames from "classnames";
import { DebuggerSettings } from "./components/DebuggerSettings";
import { HostCalls } from "./components/HostCalls";
import { ProgramTextLoader } from "@/components/ProgramTextLoader";

const DebuggerContent = () => {
const dispatch = useAppDispatch();
Expand All @@ -37,7 +43,7 @@ const DebuggerContent = () => {
program,
initialState,
isProgramEditMode,
isAsmError,
isProgramInvalid,
programPreviewResult,
clickedInstruction,
instructionMode,
Expand Down Expand Up @@ -74,18 +80,37 @@ const DebuggerContent = () => {

return (
<>
<HostCalls currentInstructionEnriched={currentInstructionEnriched} />
<HostCalls />
<div className="col-span-12 md:col-span-4 max-h-[70vh] max-sm:min-h-[330px]">
{!program.length && <InitialLoadProgramCTA />}
{!!program.length && (
<>
{isProgramEditMode && (
<div className="border-2 rounded-md h-full p-2 pt-8">
<Assembly
program={program}
onProgramLoad={debuggerActions.handleProgramLoad}
initialState={initialState}
/>
<div className="border-2 rounded-md h-full p-2">
{instructionMode === InstructionMode.ASM ? (
<Assembly
program={program}
onProgramLoad={debuggerActions.handleProgramLoad}
initialState={initialState}
/>
) : (
<ProgramTextLoader
program={program}
setProgram={(program, error) => {
if (error) {
dispatch(setIsProgramInvalid(true));
}

if (!error && program) {
debuggerActions.handleProgramLoad({
initial: initialState,
program: program || [],
name: "custom",
});
}
}}
/>
)}
</div>
)}

Expand Down Expand Up @@ -146,7 +171,6 @@ const DebuggerContent = () => {
<div className={`flex items-center space-x-2 ${!program.length ? "invisible" : "visible"}`}>
<Label htmlFor="instruction-mode">ASM</Label>
<Switch
disabled={isProgramEditMode}
id="instruction-mode"
checked={instructionMode === InstructionMode.BYTECODE}
onCheckedChange={(checked) =>
Expand All @@ -160,7 +184,7 @@ const DebuggerContent = () => {
variant="link"
size="icon"
className={!program.length ? "invisible" : "visible"}
disabled={!program.length || isAsmError}
disabled={!program.length || isProgramInvalid}
title="Edit the code"
onClick={() => {
if (isProgramEditMode) {
Expand All @@ -182,7 +206,7 @@ const DebuggerContent = () => {
};

function App() {
const { pvmInitialized, initialState, program } = useAppSelector((state) => state.debugger);
const { pvmInitialized } = useAppSelector((state) => state.debugger);

return (
<>
Expand Down Expand Up @@ -212,7 +236,7 @@ function App() {
) : (
<div className="col-span-12 flex justify-center h-[50vh] align-middle">
<div className="min-w-[50vw] max-md:w-[100%] min-h-[500px] h-[75vh] flex flex-col">
<Loader initialState={initialState} program={program} />
<Loader />
</div>
</div>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/DebuggerSettings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const DebuggerSettings = () => {
<span className="text-xl">Debugger Settings</span>
</DialogTitle>
<DialogDescription asChild>
<p className="py-4 ">
<div className="py-4">
<span className="block text-lg text-black font-bold mb-2">Number of batched steps</span>
<span className="mb-3 block">
To speed up execution PVMs can run multiple steps internally after clicking "Run". This may lead to
Expand All @@ -48,7 +48,7 @@ export const DebuggerSettings = () => {
value={debuggerState.stepsToPerform}
/>
<HostCallsForm />
</p>
</div>
</DialogDescription>
</DialogHeader>
</DialogContent>
Expand Down
33 changes: 19 additions & 14 deletions src/components/HostCalls/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { hash, bytes } from "@typeberry/jam-host-calls";
import { Storage } from "@/packages/web-worker/types";
import { useEffect, useState } from "react";
import { logger } from "@/utils/loggerService";
import { setHasHostCallOpen, setIsDebugFinished, setStorage } from "@/store/debugger/debuggerSlice";
import { handleHostCall, setAllWorkersStorage, stepAllWorkers } from "@/store/workers/workersSlice";
import { setHasHostCallOpen, setStorage } from "@/store/debugger/debuggerSlice";
import { setAllWorkersStorage } from "@/store/workers/workersSlice";
import { useAppDispatch, useAppSelector } from "@/store/hooks";

const parseJSONToStorage = (value: { [key: string]: string }) => {
Expand All @@ -22,13 +22,13 @@ const parseJSONToStorage = (value: { [key: string]: string }) => {
return parsedValue;
};

export const HostCallsForm = () => {
export const HostCallsForm = (props: { onAfterSubmit?: () => void }) => {
const { storage } = useAppSelector((state) => state.debugger);
const dispatch = useAppDispatch();
const [inputValue, setInputValue] = useState<string>();

useEffect(() => {
setInputValue(storage ? JSON.stringify(Object.fromEntries(storage)) : "");
setInputValue(storage ? JSON.stringify(Object.fromEntries(storage.entries())) : "");
}, [storage]);

const onSubmit = async () => {
Expand All @@ -38,7 +38,7 @@ export const HostCallsForm = () => {
dispatch(setStorage(parsedValue));
await dispatch(setAllWorkersStorage()).unwrap();
dispatch(setHasHostCallOpen(false));
await dispatch(handleHostCall()).unwrap();
props.onAfterSubmit?.();

// dispatch(setIsDebugFinished(false));
// await dispatch(stepAllWorkers()).unwrap();
Expand All @@ -50,22 +50,27 @@ export const HostCallsForm = () => {
return (
<div className="py-4 ">
<span className="block text-lg text-black font-bold mb-2">Storage Value</span>
<span className="mb-3 block">Lorem ipsum</span>
<span className="mb-3 block">
Set storage for read & write host calls. Confirm empty, if you want to process. Storage can be modified by
running program.
</span>
<Textarea
id="storage"
autoFocus
className="col-span-3"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
{storage !== null && (
<span>
<CheckCircle color="green" /> Storage provided
</span>
)}
<Button type="submit" onClick={onSubmit}>
Save changes
</Button>
<div className="flex mt-2">
<Button type="submit" onClick={onSubmit}>
Confirm
</Button>
{storage !== null && (
<span className="flex items-center ml-3">
<CheckCircle color="green" className="mr-2" /> Storage provided
</span>
)}
</div>
</div>
);
};
40 changes: 12 additions & 28 deletions src/components/HostCalls/index.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,10 @@
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription, DialogFooter,
DialogHeader,
DialogTitle
} from "@/components/ui/dialog";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { useAppDispatch, useAppSelector } from "@/store/hooks.ts";
import { CurrentInstruction } from "@/types/pvm";
import { isInstructionError, isOneImmediateArgs } from "@/types/type-guards";
import { HostCallsForm } from "./form";
import { setHasHostCallOpen } from "@/store/debugger/debuggerSlice.ts";
import { Button } from "../ui/button";
import { handleHostCall } from "@/store/workers/workersSlice";

export const HostCalls = ({
currentInstructionEnriched,
}: {
currentInstructionEnriched: CurrentInstruction | undefined;
}) => {
const { storage, hasHostCallOpen } = useAppSelector((state) => state.debugger);
export const HostCalls = () => {
const { hasHostCallOpen } = useAppSelector((state) => state.debugger);
const dispatch = useAppDispatch();

// if (
Expand All @@ -34,17 +20,15 @@ export const HostCalls = ({
return (
<Dialog open={hasHostCallOpen}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>Storage</DialogTitle>
<DialogDescription>
Debugger encountered ecalli. No storage detected. Please provide JSON storage or confirm empty
</DialogDescription>
</DialogHeader>
<div className="grid grid-cols-4 items-center gap-4">
<span>Type</span>
{/*<span>Ecalli&nbsp;{ecalliIndex}</span>*/}
<div>
<DialogHeader>
<DialogTitle>Storage</DialogTitle>
<DialogDescription>
Debugger encountered ecalli. No storage detected. Please provide JSON storage or confirm empty
</DialogDescription>
</DialogHeader>
<HostCallsForm onAfterSubmit={() => dispatch(handleHostCall())} />
</div>
<HostCallsForm />
</DialogContent>
{/*<DialogClose*/}
{/* onClick={() => {*/}
Expand Down
10 changes: 9 additions & 1 deletion src/components/MemoryPreview/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,15 @@ const MemoryCell = ({
<TooltipProvider>
<Tooltip delayDuration={0}>
<TooltipTrigger asChild>
<span>{numeralSystem ? "??" : "??? "}</span>
<span
className="font-mono"
dangerouslySetInnerHTML={{
__html: numeralSystem
? "&quest;&#8288;&quest;&#8288;"
: "&quest;&#8288;&quest;&#8288;&quest;&#8288;",
// This is a fix for ?? : ??? because ? adds a break after which causes the whole line to break into two lines
}}
/>
</TooltipTrigger>

<TooltipPortal>
Expand Down
2 changes: 1 addition & 1 deletion src/components/ProgramLoader/BinaryFileUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export const BinaryFileUpload = ({

return (
<div className="block">
<p className="mt-10 mb-3">or upload program as a binary file</p>
<p className="mb-3">Upload program as a binary file</p>
<Input
className="my-6 mr-3"
id="test-file"
Expand Down
40 changes: 0 additions & 40 deletions src/components/ProgramLoader/Bytecode.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,17 @@
import { ProgramTextLoader } from "../ProgramTextLoader";
import { ProgramUploadFileOutput } from "./types";
import { BinaryFileUpload } from "@/components/ProgramLoader/BinaryFileUpload.tsx";
import { useState } from "react";

const initial = {
regs: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] as [
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
],
pc: 0,
pageMap: [],
memory: [],
gas: 10000n,
};

export const Bytecode = ({
onProgramLoad,
program,
}: {
onProgramLoad: (val?: ProgramUploadFileOutput, error?: string) => void;
program: number[];
}) => {
const [tempProgram, setTempProgram] = useState<number[] | undefined>(program);
const handleFileUpload = (val: ProgramUploadFileOutput) => {
setTempProgram(val.program);
onProgramLoad(val);
};

return (
<div className="h-full flex flex-col">
<p className="mb-3">Edit program code bytes</p>
<ProgramTextLoader
program={tempProgram}
setProgram={(program, error) => {
if (program) {
setTempProgram(program);
onProgramLoad({ initial, program, name: "custom" }, error);
} else {
onProgramLoad(undefined, error);
}
}}
/>
<BinaryFileUpload onFileUpload={handleFileUpload} />
</div>
);
Expand Down
36 changes: 25 additions & 11 deletions src/components/ProgramLoader/Examples.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,6 @@ const programs: {
memory: [],
gas: 10000n,
},
readAndWrite: {
program: [0, 0, 6, 8, 135, 9, 17, 78, 2, 25],
regs: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
pc: 0,
pageMap: [],
memory: [],
gas: 10000n,
},
storeU16: {
program: [0, 0, 5, 69, 7, 0, 0, 2, 1],
regs: [0, 0, 0, 0, 0, 0, 0, 305419896, 0, 0, 0, 0, 0],
Expand All @@ -87,6 +79,28 @@ const programs: {
memory: [],
gas: 10000n,
},
empty: {
program: [0, 0, 0],
regs: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] as [
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
],
pc: 0,
pageMap: [],
memory: [],
gas: 10000n,
},
};

export const Examples = ({ onProgramLoad }: { onProgramLoad: (val: ProgramUploadFileOutput) => void }) => {
Expand Down Expand Up @@ -140,9 +154,9 @@ export const Examples = ({ onProgramLoad }: { onProgramLoad: (val: ProgramUpload
</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="readAndWrite" id="option-readAndWrite" />
<Label htmlFor="option-readAndWrite" className="cursor-pointer">
Read and write
<RadioGroupItem value="empty" id="option-empty" />
<Label htmlFor="option-empty" className="cursor-pointer">
Empty
</Label>
</div>
</RadioGroup>
Expand Down
Loading

0 comments on commit 78fde84

Please sign in to comment.