A command-line tool for analyzing Ethereum blockchain state changes between blocks. Built with Go and the go-ethereum library, this tool provides deep insights into account state transitions, balance changes, nonce updates, code modifications, and storage changes.
- State Comparison: Compare complete state changes between any two blocks
- Account Inspection: Examine individual account state at specific blocks
- Detailed Analysis: Track balance changes, nonce updates, code deployments, and storage modifications
- Flexible Output: Support for both human-readable text and JSON formats
- Performance: Direct LevelDB access for efficient blockchain data retrieval
- Contract Detection: Automatically distinguish between EOAs and smart contracts
- Go 1.21 or higher
- Access to an Ethereum node's data directory (Geth chaindata)
- Sufficient disk space for blockchain data
# Clone the repository
git clone https://github.com/devlongs/state-diff-tool.git
cd state-diff-tool
# Build the binary
make build
# Or build an optimized release version
make build-release
# Install to GOPATH/bin (optional)
make installThe compiled binary will be available at bin/state-diff-tool.
All commands require the following global flag:
--datadir(required): Path to Ethereum data directory containing chaindata--ancient(optional): Path to ancient data directory--cache(optional): Database cache size in MB (default: 1024)--handles(optional): Number of file handles (default: 256)
Compare state changes between two blocks:
./bin/state-diff-tool diff \
--datadir /path/to/ethereum/chaindata \
--from 17000000 \
--to 17000001Flags:
--from: Starting block number (required)--to: Ending block number (required)--json: Output results as JSON instead of text
Example output:
Computing state diff between blocks 17000000 and 17000001...
From State Root: 0x1234...
To State Root: 0x5678...
State Diff Summary:
From Block: 17000000
To Block: 17000001
Total Changes: 42
Account: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
Balance: 1000000000000000000 -> 2000000000000000000 (+1.00 ETH)
Nonce: 5 -> 6
Account: 0xdAC17F958D2ee523a2206206994597C13D831ec7
Storage Changes:
Slot 0x0000...1234: 0x0000...0001 -> 0x0000...0002
Examine a specific account's state at a given block:
./bin/state-diff-tool inspect \
--datadir /path/to/ethereum/chaindata \
--block 17000000 \
--address 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEbFlags:
--block: Block number to inspect (required)--address: Ethereum address to inspect (required)
Example output:
Account: 0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb
Block: 17000000
Balance: 1.234567890123456789 ETH (1234567890123456789 wei)
Nonce: 42
Code Hash: 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
Code Size: 0 bytes
Account Type: Externally Owned Account (EOA)
# Compare two consecutive blocks
./bin/state-diff-tool diff --datadir ~/.ethereum --from 100 --to 101
# Export diff as JSON
./bin/state-diff-tool diff --datadir ~/.ethereum --from 100 --to 101 --json > diff.json
# Inspect a smart contract
./bin/state-diff-tool inspect \
--datadir ~/.ethereum \
--block 17000000 \
--address 0xdAC17F958D2ee523a2206206994597C13D831ec7Monitor an address across multiple blocks:
#!/bin/bash
ADDRESS="0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb"
START_BLOCK=17000000
END_BLOCK=17000010
for ((block=$START_BLOCK; block<=$END_BLOCK; block++)); do
echo "Block $block:"
./bin/state-diff-tool inspect \
--datadir ~/.ethereum \
--block $block \
--address $ADDRESS
echo "---"
doneAnalyze state changes over a range:
#!/bin/bash
START=17000000
END=17000100
for ((i=$START; i<$END; i++)); do
NEXT=$((i + 1))
./bin/state-diff-tool diff \
--datadir ~/.ethereum \
--from $i \
--to $NEXT \
--json >> state_changes.jsonl
donestate-diff-tool/
├── cmd/ # Command-line interface
│ ├── root.go # Root command and global flags
│ ├── diff.go # State diff command
│ └── inspect.go # Account inspection command
├── statediff/ # Core state diffing logic
│ ├── types.go # Data structures
│ ├── differ.go # State comparison engine
│ ├── formatter.go # Output formatting
│ └── types_test.go # Unit tests
├── database/ # Database connection handling
│ └── connection.go # Ethereum database access
├── examples/ # Example scripts
│ ├── basic_usage.sh
│ └── monitor_address.sh
├── bin/ # Build output directory
├── main.go # Application entry point
├── Makefile # Build automation
├── go.mod # Go module definition
└── LICENSE # MIT License
# Standard build
make build
# Optimized release build
make build-release
# Run tests
make test
# Format and lint
make lint
# Download dependencies
make deps# Run all tests
make test
# Run tests with coverage
go test -v -cover ./...
# Run specific package tests
go test -v ./statediff/- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes and add tests
- Run tests:
make test - Commit your changes:
git commit -am 'Add feature' - Push to the branch:
git push origin feature-name - Submit a pull request
The State Diff Tool works by:
- Database Access: Opens Geth's LevelDB database in read-only mode
- State Retrieval: Fetches state roots for specified blocks using block headers
- Trie Iteration: Traverses Ethereum's Merkle Patricia Trie structure
- State Comparison: Compares account states between the two blocks
- Change Detection: Identifies differences in balances, nonces, code, and storage
- Result Formatting: Presents changes in human-readable or JSON format
- Account Creation: New accounts that appear in the later block
- Account Deletion: Accounts that no longer exist (e.g., SELFDESTRUCT)
- Balance Changes: Ether transfers and balance modifications
- Nonce Changes: Transaction count updates
- Code Changes: Smart contract deployments and modifications
- Storage Changes: Individual storage slot modifications in smart contracts
Provide the path to your Ethereum node's data directory:
./bin/state-diff-tool diff --datadir ~/.ethereum --from 100 --to 101Ensure your Ethereum node has synced the blocks you're trying to analyze. Check your node's current sync status.
Verify:
- The data directory path is correct
- The chaindata subdirectory exists
- You have read permissions for the database files
- No other process has an exclusive lock on the database
-
Cache Size: Increase cache for large state diffs:
./bin/state-diff-tool diff --datadir ~/.ethereum --cache 4096 --from 100 --to 101 -
File Handles: Increase for better I/O performance:
./bin/state-diff-tool diff --datadir ~/.ethereum --handles 512 --from 100 --to 101 -
Ancient Data: Specify ancient data directory for older blocks:
./bin/state-diff-tool diff --datadir ~/.ethereum --ancient ~/.ethereum/ancient --from 100 --to 101
- Blockchain Analysis: Study state changes and transaction effects
- Smart Contract Monitoring: Track storage modifications in contracts
- Security Research: Analyze suspicious state transitions
- Debugging: Understand state changes during contract execution
- Data Science: Extract blockchain data for analysis and research
- Educational: Learn about Ethereum state management
Contributions are welcome! Please feel free to submit issues, feature requests, or pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with go-ethereum
- CLI framework by Cobra
For issues, questions, or contributions, please visit the GitHub repository.