A hybrid Zig/Go project that uses the guillotine-mini EVM for Ethereum transaction processing with a Bubble Tea-based TUI.
chop/
├── build.zig # Unified build system (orchestrates everything)
├── src/ # Zig source code
│ ├── main.zig # Zig entry point
│ └── root.zig # Zig module root
├── main.go # Go application entry point
├── internal/ # Go source code
│ ├── app/ # Application logic
│ │ ├── model.go # Bubble Tea model
│ │ ├── init.go # Initialization logic
│ │ ├── update.go # Update function
│ │ ├── view.go # View rendering
│ │ ├── handlers.go # Event handlers & navigation
│ │ ├── parameters.go # Call parameter management
│ │ └── table_helpers.go # Table update helpers
│ ├── config/ # Configuration & constants
│ │ └── config.go # App config, colors, keys
│ ├── core/ # Core business logic
│ │ ├── logs.go # Log helpers
│ │ ├── bytecode/ # Bytecode analysis (stubbed)
│ │ │ └── bytecode.go
│ │ ├── evm/ # EVM execution (stubbed)
│ │ │ └── evm.go
│ │ ├── history/ # Call history management
│ │ │ └── history.go
│ │ ├── state/ # State persistence
│ │ │ └── state.go
│ │ └── utils/ # Utility functions
│ │ └── utils.go
│ ├── types/ # Type definitions
│ │ └── types.go
│ └── ui/ # UI components & rendering
│ └── ui.go
├── lib/
│ └── guillotine-mini/ # Git submodule - EVM implementation in Zig
├── zig-out/ # Build artifacts
│ └── bin/
│ ├── chop # Zig executable
│ ├── chop-go # Go executable
│ └── guillotine_mini.wasm # EVM WASM library
├── go.mod
├── go.sum
└── .gitmodules # Git submodule configuration
- Interactive TUI: Full-featured Bubble Tea interface
- Call Parameter Configuration: Configure EVM calls with validation
- Call History: View past call executions
- Contract Management: Track deployed contracts
- State Persistence: Save and restore session state
- Bytecode Disassembly: View disassembled contract bytecode (stubbed)
- Main Menu: Navigate between features
- Call Parameter List: Configure call parameters
- Call Parameter Edit: Edit individual parameters
- Call Execution: Execute EVM calls
- Call Results: View execution results
- Call History: Browse past executions
- Contracts: View deployed contracts
- Contract Details: Detailed contract view with disassembly
↑/↓ork/j: Navigate←/→orh/l: Navigate blocks (in disassembly)Enter: Select/ConfirmEsc: Back/Cancele: Execute callr: Reset parameterR: Reset all parametersc: Copy to clipboardctrl+v: Paste from clipboardqorctrl+c: Quit
- Zig: 0.15.1 or later (for building from source)
- Go: 1.21 or later (for building from source)
- Git: For submodule management (for building from source)
Download pre-built binaries for your platform from the GitHub Releases page.
# Intel Mac
curl -LO https://github.com/evmts/chop/releases/latest/download/chop_latest_darwin_amd64.tar.gz
tar -xzf chop_latest_darwin_amd64.tar.gz
chmod +x chop
sudo mv chop /usr/local/bin/
# Apple Silicon Mac
curl -LO https://github.com/evmts/chop/releases/latest/download/chop_latest_darwin_arm64.tar.gz
tar -xzf chop_latest_darwin_arm64.tar.gz
chmod +x chop
sudo mv chop /usr/local/bin/# AMD64
curl -LO https://github.com/evmts/chop/releases/latest/download/chop_latest_linux_amd64.tar.gz
tar -xzf chop_latest_linux_amd64.tar.gz
chmod +x chop
sudo mv chop /usr/local/bin/
# ARM64
curl -LO https://github.com/evmts/chop/releases/latest/download/chop_latest_linux_arm64.tar.gz
tar -xzf chop_latest_linux_arm64.tar.gz
chmod +x chop
sudo mv chop /usr/local/bin/Download the appropriate .zip file for your architecture from the releases page, extract it, and add the executable to your PATH.
If you prefer to build from source, see the Build System section below.
Initialize the submodules:
git submodule update --init --recursiveThe project uses Zig's build system as the primary orchestrator. All build commands go through zig build.
| Command | Description |
|---|---|
zig build |
Build everything (default: stub EVM, WASM library) |
zig build all |
Explicitly build everything |
zig build go |
Build Go binary with stub EVM (CGo disabled) |
zig build go-cgo |
Build Go binary with real EVM (CGo enabled) |
zig build run |
Run the Go application (stub EVM) |
zig build run-cgo |
Run the Go application with real EVM |
zig build guillotine |
Build guillotine-mini WASM library |
zig build guillotine-lib |
Build guillotine-mini native library for CGo |
zig build test |
Run all tests |
zig build go-test |
Run only Go tests |
zig build clean |
Remove all build artifacts |
# Build with stub EVM (no actual execution)
zig build go
# Run CLI (stub returns fake gas values)
./zig-out/bin/chop-go call --bytecode 0x6001600101
# Output: WARNING: CGo disabled - EVM execution stubbed# Build with real EVM execution
zig build go-cgo
# Run CLI with actual EVM
./zig-out/bin/chop call --bytecode 0x6001600101
# Output: ExecutionResult{Status: SUCCESS, GasUsed: 9, ...}
# Or build and run directly
zig build run-cgo -- call --bytecode 0x6000600055
# Run tests
zig build testThe project supports two build modes:
- Command:
zig build go - Output:
zig-out/bin/chop-go - Pros: Fast compilation, no C dependencies, portable
- Cons: EVM execution is fake (returns mock values)
- Use for: Development, testing UI/CLI without EVM
- Command:
zig build go-cgo - Output:
zig-out/bin/chop - Pros: Actual EVM execution, real gas accounting, accurate results
- Cons: Requires C compiler, longer build time (~10-20s)
- Use for: Production, actual EVM testing, accurate gas measurements
Key Difference: The CGo build links against the guillotine-mini native library (libwasm.a, libblst.a, libc-kzg-4844.a, libbn254_wrapper.a) and uses real Zig EVM implementation. The stub build has no external dependencies and returns fake execution results.
The Zig application component.
Source: src/
Output: zig-out/bin/chop
The Go application with Bubble Tea TUI.
Source: internal/, main.go
Output: zig-out/bin/chop-go
The EVM implementation, built as a WASM library.
Source: lib/guillotine-mini/ (submodule)
Output: lib/guillotine-mini/zig-out/bin/guillotine_mini.wasm
- EVM Execution (
evm/package) - WORKING- Full CGo bindings to guillotine-mini native library
- Real EVM execution with accurate gas accounting
- Support for all call types (CALL, STATICCALL, CREATE, etc.)
- Async execution with state injection
- Build system integration (
zig build go-cgo)
-
Bytecode Analysis (
core/bytecode/bytecode.go)- Implement real EVM opcode disassembly
- Add control flow analysis
- Generate basic blocks
-
State Replay (
core/state/state.go)- Implement state replay through VM
-
Clipboard Support (
tui/ui.go)- Implement actual clipboard read/write operations
-
TUI Integration
- Wire up TUI to use real EVM execution (currently uses stub)
- Update call results view to show real execution data
The codebase is organized into clear layers:
- Presentation Layer:
internal/ui/andinternal/app/view.go - Application Layer:
internal/app/(handlers, navigation, state management) - Domain Layer:
internal/core/(EVM, history, bytecode analysis) - Infrastructure Layer:
internal/core/state/(persistence)
All EVM-related functionality is stubbed with clear TODO markers for easy integration with Guillotine.
- Edit your code in
src/(Zig) orinternal/,main.go(Go) - Run
zig buildto rebuild - Run
zig build testto verify tests pass
The guillotine-mini submodule is a separate Zig project with its own build system.
# Build the WASM library through the main build system
zig build guillotine
# Or build it directly in the submodule
cd lib/guillotine-mini
zig build wasmSee lib/guillotine-mini/README.md or lib/guillotine-mini/CLAUDE.md for detailed documentation on the EVM implementation.
zig build cleanThis removes:
zig-out/(main project artifacts)zig-cache/(Zig build cache)lib/guillotine-mini/zig-out/(submodule artifacts)lib/guillotine-mini/zig-cache/(submodule cache)
Build and run the Go TUI directly:
CGO_ENABLED=0 go build -o chop .
./chopTabs:
- [1] Dashboard: Stats, recent blocks/txs (auto-refresh status shown)
- [2] Accounts: Enter to view; 'p' to reveal private key
- [3] Blocks: Enter to view block detail
- [4] Transactions: Enter for transaction detail; in detail view press 'b' to open block
- [5] Contracts: Enter to view details; 'c' copies address
- [6] State Inspector: Type/paste address (ctrl+v), Enter to inspect
- [7] Settings: 'r' reset blockchain, 'g' regenerate accounts (confirmation), 't' toggle auto-refresh
Global:
- Number keys 1–7 switch tabs; esc goes back; q or ctrl+c quits
- 'c' in detail views copies the primary identifier (e.g., tx hash)
# Run all Go tests
go test ./...
# Run tests with verbose output
go test ./... -v
# Run tests with race detector (recommended for development)
go test ./... -race
# Run tests with coverage report
go test ./... -cover
# Generate detailed coverage report
go test ./... -coverprofile=coverage.txt -covermode=atomic
go tool cover -html=coverage.txt -o coverage.html# Run all tests (Zig and Go)
zig build test
# Run only Go tests
zig build go-testThe project includes automated security scanning that runs on every push and pull request.
# Install gosec (security scanner)
go install github.com/securego/gosec/v2/cmd/gosec@latest
# Run gosec security scan
gosec ./...
# Run gosec with detailed output
gosec -fmt=json -out=results.json ./...
# Install govulncheck (vulnerability scanner)
go install golang.org/x/vuln/cmd/govulncheck@latest
# Run vulnerability check
govulncheck ./...-
gosec: Static security analysis checking for:
- Hardcoded credentials (G101)
- SQL injection vulnerabilities (G201-G202)
- File permission issues (G301-G304)
- Weak cryptography (G401-G404)
- Unsafe operations and more
-
govulncheck: Checks dependencies against the Go vulnerability database
- Scans both direct and indirect dependencies
- Reports known CVEs in your dependency tree
-
Dependabot: Automated dependency updates
- Weekly checks for Go module updates
- Weekly checks for GitHub Actions updates
- Automatic security patch PRs
Configuration files:
.gosec.yml- gosec scanner configuration.github/dependabot.yml- Dependabot configuration.github/workflows/security.yml- Security workflow
The project uses golangci-lint for comprehensive code quality checks and linting.
# Install golangci-lint (macOS)
brew install golangci-lint
# Or install via go install
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
# Run all linters
golangci-lint run ./...
# Run linters with timeout
golangci-lint run ./... --timeout=5m
# Run linters and automatically fix issues (where possible)
golangci-lint run ./... --fixThe project uses .golangci.yml for configuration with the following categories of linters:
Code Correctness:
errcheck- Check for unchecked errorsgovet- Official Go static analyzerstaticcheck- Go static analysistypecheck- Type-check Go codeineffassign- Detect ineffectual assignmentsunused- Check for unused code
Code Style:
gofmt- Check code formattinggoimports- Check import formattingrevive- Fast, configurable lintergocritic- Comprehensive Go source code linter
Code Quality:
gosimple- Simplify code suggestionsgocyclo- Check cyclomatic complexitydupl- Check for code duplicationunconvert- Remove unnecessary type conversionsunparam- Check for unused function parameters
Security:
gosec- Inspect for security issues
Performance:
prealloc- Find slice declarations that could be preallocated
Common Errors:
misspell- Check for commonly misspelled wordsgoconst- Find repeated strings that could be constantsnilerr- Find code that returns nil incorrectlybodyclose- Check HTTP response body is closed
As of the last check, the codebase has approximately 89 linting issues across the following categories:
gocritic(34 issues) - Code style suggestionsgofmt(13 issues) - Formatting issuesgoimports(11 issues) - Import organizationgocyclo(8 issues) - High cyclomatic complexitygoconst(7 issues) - Repeated stringsgosec(4 issues) - Security warningserrcheck(4 issues) - Unchecked errorsrevive(4 issues) - Style violations- Other minor issues (4 issues)
Most issues are style-related and can be automatically fixed with golangci-lint run --fix. The linter is configured to be reasonable for existing code while maintaining good practices.
Configuration file: .golangci.yml
All pull requests and commits to main automatically run:
- Tests on Go versions 1.22, 1.24 and platforms Ubuntu (Linux), macOS
- Linting with golangci-lint for code quality checks
- Security scans with gosec and govulncheck
- Dependency review for known vulnerabilities
- Code coverage reporting to Codecov
You can view the CI status in the GitHub Actions tab.
We use Zig's build system as the orchestrator because:
- Unified Interface: Single command (
zig build) for all components - Cross-Platform: Works consistently across macOS, Linux, Windows
- Dependency Management: Properly tracks dependencies between components
- Parallelization: Automatically parallelizes independent build steps
- Caching: Only rebuilds what changed
The release process is fully automated using GitHub Actions and GoReleaser.
-
Ensure all changes are committed and pushed to
maingit checkout main git pull origin main
-
Create and push a version tag (following Semantic Versioning)
# For a new feature release git tag -a v0.1.0 -m "Release v0.1.0: Initial release with TUI" # For a bug fix release git tag -a v0.1.1 -m "Release v0.1.1: Fix state persistence bug" # For a major release with breaking changes git tag -a v1.0.0 -m "Release v1.0.0: First stable release" # Push the tag to trigger the release workflow git push origin v0.1.0
-
GitHub Actions will automatically:
- Run all tests
- Build binaries for all platforms (Linux, macOS, Windows) and architectures (amd64, arm64)
- Generate checksums
- Create a GitHub Release with:
- Release notes from commit messages
- Downloadable binaries for all platforms
- Installation instructions
-
Monitor the release:
- Visit the Actions tab to watch the release workflow
- Once complete, check the Releases page
You can test the release process locally without publishing:
# Install goreleaser (macOS)
brew install goreleaser
# Or download from https://github.com/goreleaser/goreleaser/releases
# Run goreleaser in snapshot mode (won't publish)
goreleaser release --snapshot --clean
# Built artifacts will be in dist/
ls -la dist/Before creating a release, ensure:
- All tests pass:
go test ./... - Code builds successfully:
CGO_ENABLED=0 go build -o chop . - Documentation is up to date (README.md, DOCS.md)
- CHANGELOG or commit messages clearly describe changes
- Version follows Semantic Versioning
- No breaking changes in minor/patch releases
- Major version (v1.0.0): Breaking changes, incompatible API changes
- Minor version (v0.1.0): New features, backwards-compatible
- Patch version (v0.0.1): Bug fixes, backwards-compatible