import { describe, it, expect } from 'vitest';
import { tload } from './0x5c_TLOAD.js';
import { tstore } from './0x5d_TSTORE.js';
import { createFrame } from '../../Frame/index.js';
import { createMemoryHost } from '../../Host/createMemoryHost.js';
import { from as addressFrom } from '../../../primitives/Address/index.js';
describe('TLOAD (0x5c)', () => {
it('loads value from transient storage', () => {
const host = createMemoryHost();
const addr = addressFrom("0x1234567890123456789012345678901234567890");
// Pre-populate transient storage
host.setTransientStorage(addr, 0x42n, 0x1337n);
const frame = createFrame({
stack: [0x42n],
gasRemaining: 1000n,
address: addr,
});
expect(tload(frame, host)).toBeNull();
expect(frame.stack).toEqual([0x1337n]);
expect(frame.pc).toBe(1);
expect(frame.gasRemaining).toBe(900n); // 1000 - 100
});
it('loads zero for uninitialized slot', () => {
const host = createMemoryHost();
const addr = addressFrom("0x1234567890123456789012345678901234567890");
const frame = createFrame({
stack: [0x42n],
gasRemaining: 1000n,
address: addr,
});
expect(tload(frame, host)).toBeNull();
expect(frame.stack).toEqual([0n]);
});
it('isolates transient storage by address', () => {
const host = createMemoryHost();
const addr1 = addressFrom("0x1111111111111111111111111111111111111111");
const addr2 = addressFrom("0x2222222222222222222222222222222222222222");
host.setTransientStorage(addr1, 0x42n, 0xAAAAn);
host.setTransientStorage(addr2, 0x42n, 0xBBBBn);
let frame = createFrame({
stack: [0x42n],
gasRemaining: 1000n,
address: addr1,
});
expect(tload(frame, host)).toBeNull();
expect(frame.stack).toEqual([0xAAAAn]);
frame = createFrame({
stack: [0x42n],
gasRemaining: 1000n,
address: addr2,
});
expect(tload(frame, host)).toBeNull();
expect(frame.stack).toEqual([0xBBBBn]);
});
it('consumes fixed 100 gas', () => {
const host = createMemoryHost();
const addr = addressFrom("0x1234567890123456789012345678901234567890");
host.setTransientStorage(addr, 0x42n, 0x1337n);
const frame = createFrame({
stack: [0x42n],
gasRemaining: 5000n,
address: addr,
});
expect(tload(frame, host)).toBeNull();
expect(frame.gasRemaining).toBe(4900n); // 5000 - 100 (always)
});
it('returns StackUnderflow on empty stack', () => {
const host = createMemoryHost();
const frame = createFrame({
stack: [],
gasRemaining: 1000n,
address: addressFrom("0x1111111111111111111111111111111111111111"),
});
expect(tload(frame, host)).toEqual({ type: "StackUnderflow" });
});
it('returns OutOfGas when insufficient gas', () => {
const host = createMemoryHost();
const frame = createFrame({
stack: [0x42n],
gasRemaining: 50n,
address: addressFrom("0x1111111111111111111111111111111111111111"),
});
expect(tload(frame, host)).toEqual({ type: "OutOfGas" });
});
it('returns StackOverflow when stack full', () => {
const host = createMemoryHost();
const fullStack = new Array(1024).fill(0n);
const frame = createFrame({
stack: fullStack,
gasRemaining: 1000n,
address: addressFrom("0x1111111111111111111111111111111111111111"),
});
expect(tload(frame, host)).toEqual({ type: "StackOverflow" });
});
it('loads max uint256 value', () => {
const host = createMemoryHost();
const addr = addressFrom("0x1234567890123456789012345678901234567890");
const MAX = (1n << 256n) - 1n;
host.setTransientStorage(addr, 0x42n, MAX);
const frame = createFrame({
stack: [0x42n],
gasRemaining: 1000n,
address: addr,
});
expect(tload(frame, host)).toBeNull();
expect(frame.stack).toEqual([MAX]);
});
it('persists within transaction, clears on boundary', () => {
const host = createMemoryHost();
const addr = addressFrom("0x1234567890123456789012345678901234567890");
// Write value
const writeFrame = createFrame({
stack: [0x42n, 0x1337n],
gasRemaining: 1000n,
address: addr,
isStatic: false,
});
tstore(writeFrame, host);
// Read value (same transaction)
const readFrame = createFrame({
stack: [0x42n],
gasRemaining: 1000n,
address: addr,
});
expect(tload(readFrame, host)).toBeNull();
expect(readFrame.stack).toEqual([0x1337n]);
// After transaction boundary (cleared automatically)
// host.endTransaction();
// const newReadFrame = createFrame({
// stack: [0x42n],
// gasRemaining: 1000n,
// address: addr,
// });
// expect(tload(newReadFrame, host)).toBeNull();
// expect(newReadFrame.stack).toEqual([0n]);
});
});