-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
Objective
Create a comprehensive examples/ folder demonstrating how to use guillotine-mini's EVM implementation. Examples should showcase different API patterns, call types, and execution modes to help users integrate the library.
Essential Examples
0. build - Build.zig
Before getting started ask an llm to add a new executable target to a examples/main.zig. It should be a simple cli app that takes an example name and executes that example.
1. simple-call - Basic EVM execution
- Initialize EVM with basic state
- Execute simple bytecode (e.g., arithmetic ops, storage read/write)
- Show CallResult handling (success/failure, gas used, output)
- Demonstrate balance transfers
2. access-list - EIP-2929 warm/cold access
- Create transaction with access list (EIP-2930)
- Show gas savings from pre-warming addresses/storage slots
- Compare costs: cold vs warm SLOAD/SSTORE
- Demonstrate
evm.accessAddress()/evm.accessStorageSlot()
3. call-types - Different call operations
Show all call variants with CallParams:
- CALL: Regular external call with value transfer
- STATICCALL: Read-only call (no state changes)
- DELEGATECALL: Execute code in caller's context
- CALLCODE: Legacy delegatecall variant
- CREATE: Deploy new contract
- CREATE2: Deterministic deployment with salt
4. direct-frame - Low-level Frame execution
- Initialize Frame directly (bypass Evm orchestrator)
- Execute bytecode step-by-step with
frame.step() - Inspect stack/memory/PC after each instruction
- Useful for debugging or custom interpreters
5. nested-calls - Call stack and reentrancy
- Contract A calls Contract B calls Contract C
- Show call depth tracking (max 1024)
- Demonstrate context switching (caller/address/value)
- Handle failures at different depths
6. precompiles - Using precompiled contracts
- Call precompiles (0x01-0x09: ecrecover, SHA-256, RIPEMD-160, identity, modexp, etc.)
- Show gas costs and input/output handling
- Demonstrate integration with regular calls
7. tracing - EIP-3155 trace capture
- Enable tracer on Evm
- Execute bytecode with full trace
- Export trace in EIP-3155 JSON format
- Compare with geth/execution-specs traces
8. transient-storage - EIP-1153 (Cancun+)
- Use TLOAD/TSTORE for temporary state
- Show transaction-scoped lifecycle (cleared at tx end)
- Demonstrate reentrancy guard pattern
- Compare gas costs vs persistent SSTORE
9. hardfork-features - Fork-specific behavior
- Run same bytecode across hardforks (Berlin, London, Shanghai, Cancun)
- Show gas cost differences (EIP-2929, EIP-3529)
- Demonstrate new opcodes (PUSH0, MCOPY, TSTORE)
- Validate EIP activation logic
10. host-interface - Custom state backend
- Implement custom Host for external state (DB, in-memory, etc.)
- Show vtable setup for getBalance/setBalance/getCode/etc.
- Demonstrate state isolation between transactions
11. CI - github actions
examples should be added to a github actions job that runs each example and just makes sure they exit 0
API Patterns to Demonstrate
CallResult Handling
// Success cases
const result = try CallResult.success_with_output(allocator, gas_left, output);
const empty = try CallResult.success_empty(allocator, gas_left);
const with_logs = try CallResult.success_with_logs(allocator, gas_left, output, logs);
// Failure cases
const failed = try CallResult.failure(allocator, gas_left);
const reverted = try CallResult.revert_with_data(allocator, gas_left, revert_data);
const error_result = try CallResult.failure_with_error(allocator, gas_left, error_msg);
// Inspection
if (result.isSuccess()) {
const gas_used = result.gasConsumed(original_gas);
// Process output
}CallParams Construction
// Regular call
const call_params = CallParams{ .call = .{
.caller = alice,
.to = contract,
.value = 1000,
.input = calldata,
.gas = 100000,
}};
// Staticcall (read-only)
const static_params = CallParams{ .staticcall = .{
.caller = alice,
.to = contract,
.input = calldata,
.gas = 100000,
}};
// CREATE2 (deterministic deployment)
const create2_params = CallParams{ .create2 = .{
.caller = alice,
.value = 0,
.init_code = bytecode,
.salt = 0x1234,
.gas = 200000,
}};
// Validation
try call_params.validate();Direct Frame Execution
// Initialize frame
var frame = try Frame.init(
allocator,
bytecode,
gas,
caller,
address,
value,
calldata,
evm_ptr,
hardfork,
is_static,
);
defer frame.deinit();
// Execute all at once
try frame.execute();
// Or step-by-step for debugging
while (!frame.stopped and !frame.reverted) {
try frame.step(); // Execute one opcode
// Inspect: frame.stack, frame.memory, frame.pc, frame.gas_remaining
}Structure
examples/
├── README.md # Overview, build instructions
├── build.zig # Shared build config
├── simple-call/
│ ├── main.zig # Minimal working example
│ └── README.md
├── access-list/
│ ├── main.zig
│ └── README.md
├── call-types/
│ ├── main.zig
│ └── README.md
├── direct-frame/
│ ├── main.zig
│ └── README.md
├── nested-calls/
│ ├── main.zig
│ ├── contracts/ # Bytecode for contract A, B, C
│ └── README.md
├── precompiles/
│ ├── main.zig
│ └── README.md
├── tracing/
│ ├── main.zig
│ ├── trace-output.json # Sample trace
│ └── README.md
├── transient-storage/
│ ├── main.zig
│ └── README.md
├── hardfork-features/
│ ├── main.zig
│ └── README.md
└── host-interface/
├── main.zig
├── custom-host.zig # Example Host implementation
└── README.md
Implementation Notes
- Each example should be self-contained and runnable via
zig build run-<example> - Include inline comments explaining each step
- Show error handling patterns (OutOfGas, StackUnderflow, etc.)
- Provide expected output in README
- Use real bytecode (from solc or hand-assembled) where practical
- Keep examples minimal but complete (no mock TODOs)
Acceptance Criteria
- All 10 essential examples implemented
- Each example builds and runs successfully
- Top-level README with "Quick Start" section
- Per-example READMEs with explanation and expected output
- Build system integrated (
zig build run-simple-call, etc.) - Code follows project style (snake_case, explicit errors, comments)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels