Skip to content

Commit f2379c5

Browse files
committed
Fix SPI args loading
1 parent fb66b83 commit f2379c5

File tree

5 files changed

+76
-95
lines changed

5 files changed

+76
-95
lines changed

package-lock.json

Lines changed: 17 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/ProgramLoader/Loader.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ export const Loader = ({ setIsDialogOpen }: { setIsDialogOpen?: (val: boolean) =
6161
setCurrentStep("upload");
6262
}, [programLoad]);
6363

64+
// Auto-switch to RAW mode when a trace is loaded
65+
useEffect(() => {
66+
if (traceContent !== null) {
67+
setIsManualMode(true);
68+
}
69+
}, [traceContent]);
70+
6471
const handleFileUpload = useCallback((output: ProgramUploadFileOutput, trace?: string) => {
6572
setProgramLoad(output);
6673
if (trace) {
@@ -120,11 +127,13 @@ export const Loader = ({ setIsDialogOpen }: { setIsDialogOpen?: (val: boolean) =
120127

121128
// For SPI programs, update PC and encode parameters
122129
if (loadedProgram?.spiProgram) {
123-
// Parse the encoded SPI arguments (either auto-generated or manually entered)
124-
const parsedArgs = bytes.BytesBlob.parseBlob(encodedSpiArgs);
130+
// Use SPI args from trace if available, otherwise use auto-generated/manual ones
131+
const spiArgsToUse = loadedProgram.spiArgs
132+
? loadedProgram.spiArgs
133+
: bytes.BytesBlob.parseBlob(encodedSpiArgs).raw;
125134

126-
// Set the encoded parameters as SPI arguments
127-
dispatch(setSpiArgs(parsedArgs.raw));
135+
// Set the SPI arguments
136+
dispatch(setSpiArgs(spiArgsToUse));
128137

129138
// Extract and set service ID from entrypoint parameters
130139
let serviceId: number;

src/components/ProgramLoader/loading-utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ function tryParseTraceFile(content: string, fileName: string, initialState: Expe
131131
memory: chunks,
132132
gas,
133133
},
134+
spiArgs,
134135
},
135136
traceContent: content,
136137
};

src/components/ProgramLoader/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type ProgramUploadFileOutput = {
77
exampleName?: string;
88
kind: string;
99
spiProgram: SpiProgram | null;
10+
spiArgs?: Uint8Array;
1011
};
1112

1213
export type ProgramUploadFileInput = {

src/lib/host-call-trace.ts

Lines changed: 44 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -761,95 +761,14 @@ function formatTermination(term: TerminationEntry): string {
761761
* @param hostCallIndex The ecalli index being executed
762762
* @param readMemory Function to read memory for comparison
763763
*/
764-
export function findHostCallEntry(
765-
trace: ParsedTrace,
766-
indexInTrace: number,
767-
pc: number,
768-
gas: bigint,
764+
function collectStateMismatches(
765+
entry: HostCallEntry,
769766
registers: bigint[],
770-
hostCallIndex: number,
767+
gas: bigint,
771768
readMemory?: (address: number, length: number) => Uint8Array | null,
772-
): HostCallLookupResult {
773-
// Get remaining entries from the current index
774-
const remainingEntries = trace.hostCalls.slice(indexInTrace);
775-
776-
// Try to find an exact match by PC and host call index
777-
const matchingEntries = remainingEntries.filter((hc) => hc.pc === pc && hc.gas <= gas);
778-
779-
if (matchingEntries.length === 0) {
780-
return { entry: null, mismatches: [] };
781-
}
782-
783-
// First try to find an entry whose hostCallIndex matches exactly
784-
// Prefer exact index match even if gas is slightly higher
785-
const exactIndexMatch = remainingEntries.find((hc) => hc.index === hostCallIndex && hc.pc === pc);
786-
787-
// If we have an exact index match with acceptable gas, use it
788-
if (exactIndexMatch && exactIndexMatch.gas <= gas) {
789-
const mismatches: StateMismatch[] = [];
790-
791-
// Check gas
792-
if (exactIndexMatch.gas !== gas) {
793-
mismatches.push({
794-
field: "gas",
795-
expected: exactIndexMatch.gas.toString(),
796-
actual: gas.toString(),
797-
});
798-
}
799-
800-
// Check registers
801-
for (const [idx, expectedValue] of exactIndexMatch.registers) {
802-
const actualValue = registers[idx] ?? 0n;
803-
if (expectedValue !== actualValue) {
804-
mismatches.push({
805-
field: "register",
806-
expected: `r${idx}=0x${expectedValue.toString(16)}`,
807-
actual: `r${idx}=0x${actualValue.toString(16)}`,
808-
details: `Register ${idx}`,
809-
});
810-
}
811-
}
812-
813-
// Check memory reads if readMemory function is provided
814-
if (readMemory) {
815-
for (const mr of exactIndexMatch.memoryReads) {
816-
const actualData = readMemory(mr.address, mr.length);
817-
if (actualData) {
818-
const expectedHex = Array.from(mr.data)
819-
.map((b) => b.toString(16).padStart(2, "0"))
820-
.join("");
821-
const actualHex = Array.from(actualData)
822-
.map((b) => b.toString(16).padStart(2, "0"))
823-
.join("");
824-
if (expectedHex !== actualHex) {
825-
mismatches.push({
826-
field: "memread",
827-
expected: `0x${expectedHex}`,
828-
actual: `0x${actualHex}`,
829-
details: `Memory at 0x${mr.address.toString(16)} (${mr.length} bytes)`,
830-
});
831-
}
832-
}
833-
}
834-
}
835-
836-
return { entry: exactIndexMatch, mismatches };
837-
}
838-
839-
// Fall back to first matching entry by PC and gas
840-
const entry = matchingEntries[0];
769+
): StateMismatch[] {
841770
const mismatches: StateMismatch[] = [];
842771

843-
// Check PC
844-
if (entry.index !== hostCallIndex) {
845-
mismatches.push({
846-
field: "index",
847-
expected: entry.index.toString(),
848-
actual: hostCallIndex.toString(),
849-
});
850-
}
851-
852-
// Check gas
853772
if (entry.gas !== gas) {
854773
mismatches.push({
855774
field: "gas",
@@ -858,7 +777,6 @@ export function findHostCallEntry(
858777
});
859778
}
860779

861-
// Check registers
862780
for (const [idx, expectedValue] of entry.registers) {
863781
const actualValue = registers[idx] ?? 0n;
864782
if (expectedValue !== actualValue) {
@@ -871,7 +789,6 @@ export function findHostCallEntry(
871789
}
872790
}
873791

874-
// Check memory reads if readMemory function is provided
875792
if (readMemory) {
876793
for (const mr of entry.memoryReads) {
877794
const actualData = readMemory(mr.address, mr.length);
@@ -894,6 +811,46 @@ export function findHostCallEntry(
894811
}
895812
}
896813

814+
return mismatches;
815+
}
816+
817+
export function findHostCallEntry(
818+
trace: ParsedTrace,
819+
indexInTrace: number,
820+
pc: number,
821+
gas: bigint,
822+
registers: bigint[],
823+
hostCallIndex: number,
824+
readMemory?: (address: number, length: number) => Uint8Array | null,
825+
): HostCallLookupResult {
826+
const remainingEntries = trace.hostCalls.slice(indexInTrace);
827+
828+
const exactIndexMatch = remainingEntries.find((hc) => hc.index === hostCallIndex && hc.pc === pc);
829+
830+
if (exactIndexMatch) {
831+
const mismatches = collectStateMismatches(exactIndexMatch, registers, gas, readMemory);
832+
return { entry: exactIndexMatch, mismatches };
833+
}
834+
835+
const matchingEntries = remainingEntries.filter((hc) => hc.pc === pc && hc.gas <= gas);
836+
837+
if (matchingEntries.length === 0) {
838+
return { entry: null, mismatches: [] };
839+
}
840+
841+
const entry = matchingEntries[0];
842+
const mismatches: StateMismatch[] = [];
843+
844+
if (entry.index !== hostCallIndex) {
845+
mismatches.push({
846+
field: "index",
847+
expected: entry.index.toString(),
848+
actual: hostCallIndex.toString(),
849+
});
850+
}
851+
852+
mismatches.push(...collectStateMismatches(entry, registers, gas, readMemory));
853+
897854
return { entry, mismatches };
898855
}
899856

0 commit comments

Comments
 (0)