Debugging Moonbeam
Contents
- •Lazy Loading (Fork Mode)
- •Runtime Debugging
- •EVM Debugging
- •XCM Debugging
- •Client/RPC Debugging
- •Block Production Debugging
- •Common Error Patterns
- •Investigation Tools
Lazy Loading (Fork Mode)
Lazy loading allows running a local Moonbeam node that fetches state on-demand from a live RPC endpoint. This is the most powerful tool for debugging production issues as it lets you replay transactions against real chain state.
Building with Lazy Loading
# Build with lazy-loading feature enabled cargo build --release --features lazy-loading
Basic Usage
# Fork from Moonbeam mainnet at latest block ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonbeam.network \ --sealing 6000 # Fork from specific block ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonbeam.network \ --lazy-loading-block 0x1234...abcd \ --sealing 6000 # Fork Moonriver ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonriver.moonbeam.network \ --sealing 6000 # Fork Moonbase Alpha ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonbase.moonbeam.network \ --sealing 6000
Advanced Options
# Use custom runtime (test new runtime against production state) ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonbeam.network \ --lazy-loading-runtime-override ./target/release/wbuild/moonbeam-runtime/moonbeam_runtime.wasm \ --sealing 6000 # Apply state overrides (modify storage for testing) ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonbeam.network \ --lazy-loading-state-overrides ./state-overrides.json \ --sealing 6000 # Adjust RPC request throttling (avoid rate limits) ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonbeam.network \ --lazy-loading-delay-between-requests 100 \ --lazy-loading-max-retries-per-request 5 \ --sealing 6000
State Overrides File Format
{
"0x1234...": {
"balance": "0x1000000000000000000",
"nonce": "0x0",
"code": "0x...",
"storage": {
"0x0": "0x1234"
}
}
}
Debugging Workflow with Lazy Loading
- •
Reproduce a production issue:
bash# Fork at the block before the problematic transaction ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonbeam.network \ --lazy-loading-block 0xBLOCK_BEFORE_ISSUE \ --ethapi=debug,trace \ --sealing manual
- •
Replay the failing transaction:
javascript// Get original tx details from production const tx = await prodProvider.getTransaction(txHash); // Replay on forked node with tracing const trace = await localProvider.send('debug_traceCall', [{ from: tx.from, to: tx.to, data: tx.data, value: tx.value, gas: tx.gas }, 'latest', { tracer: 'callTracer' }]); - •
Test runtime fixes:
bash# Build fixed runtime cargo build --release -p moonbeam-runtime # Test against production state ./target/release/moonbeam \ --lazy-loading-remote-rpc https://rpc.api.moonbeam.network \ --lazy-loading-runtime-override ./target/release/wbuild/moonbeam-runtime/moonbeam_runtime.wasm \ --sealing 6000
Performance Considerations
- •Initial requests may be slow (state is fetched on-demand)
- •Use a reliable, non-rate-limited RPC endpoint
- •Consider running your own archive node for heavy debugging
- •Expect ~20x slower execution compared to local state
Common Use Cases
| Use Case | Configuration |
|---|---|
| Debug failed tx | Fork at block before tx, replay with tracing |
| Test migration | Use --lazy-loading-runtime-override with new runtime |
| Simulate whale actions | Use --lazy-loading-state-overrides to modify balances |
| Test governance | Override voting power via state overrides |
| Debug precompile | Fork + trace precompile calls |
Debugging Workflows
Runtime Debugging
- •
Identify the failing component:
- •Check logs for
WARNorERRORmessages - •Look for panic messages with stack traces
- •Identify which pallet or module is involved
- •Check logs for
- •
Reproduce locally:
bash# Run dev node with verbose logging RUST_LOG=debug ./target/release/moonbeam --dev --alice --sealing 6000 --rpc-port 9944 # Target specific module logging RUST_LOG=pallet_parachain_staking=trace ./target/release/moonbeam --dev
- •
Add debug logging in the pallet:
rustuse frame_support::log; log::debug!(target: "pallet-name", "Debug info: {:?}", value); - •
Check storage state:
- •Use Polkadot.js Apps to inspect storage
- •Query via RPC:
state_getStorage
EVM Debugging
- •
Enable EVM tracing:
bash# Run with tracing enabled ./target/release/moonbeam --dev --ethapi=debug,trace
- •
Use debug_traceTransaction:
javascriptconst trace = await provider.send('debug_traceTransaction', [txHash, {}]); - •
Check precompile calls:
- •Precompile addresses are deterministic (0x0000...0800+)
- •Look for revert reasons in trace output
- •Verify input encoding matches expected ABI
- •
Common EVM issues:
- •Gas estimation failures: Check precompile gas costs
- •Revert without reason: Look at precompile error handling
- •State differences: Compare with expected EVM state
XCM Debugging
- •
Enable XCM logging:
bashRUST_LOG=xcm=trace ./target/release/moonbeam --dev
- •
Check XCM message structure:
- •Verify multilocation encoding
- •Check weight limits
- •Verify asset representation (local vs foreign)
- •
Common XCM issues:
- •
TooExpensive: Insufficient weight/fee - •
UntrustedReserveLocation: Asset origin mismatch - •
AssetNotFound: Asset not registered
- •
- •
Test XCM locally:
bash# Use zombienet for multi-chain testing zombienet spawn zombienet/moonbeam.toml
Client/RPC Debugging
- •
Check RPC method availability:
bashcurl -H "Content-Type: application/json" -d '{"id":1, "jsonrpc":"2.0", "method":"rpc_methods"}' http://localhost:9944 - •
Verify client version compatibility:
- •Ensure client matches runtime version
- •Check spec_version in runtime
- •
Debug connection issues:
bash# Test WebSocket connection wscat -c ws://localhost:9944
Block Production Debugging
- •
Check collator status:
- •Verify author mapping:
AuthorMapping.MappingWithDeposit - •Check nimbus keys are registered
- •Verify author mapping:
- •
Monitor block production:
bash# Watch block events RUST_LOG=cumulus=debug ./target/release/moonbeam
- •
Common block issues:
- •Missed slots: Check collator selection
- •Invalid blocks: Check weight limits
- •Orphaned blocks: Check finality
Key Log Targets
| Target | Component |
|---|---|
pallet_evm | EVM execution |
pallet_ethereum | Ethereum transaction processing |
xcm | XCM message handling |
cumulus | Parachain consensus |
moonbeam_rpc | Custom RPC methods |
frontier | Ethereum compatibility layer |
Useful RPC Methods for Debugging
// Get transaction receipt with logs
eth_getTransactionReceipt(txHash)
// Trace transaction execution
debug_traceTransaction(txHash, {tracer: 'callTracer'})
// Get storage at specific block
eth_getStorageAt(address, slot, blockNumber)
// Check pending transactions
txpool_content()
// Get block details
eth_getBlockByNumber(blockNumber, true)
Test-Driven Debugging
- •
Write a failing test:
typescript// test/suites/dev/moonbase/test-debug/test-issue-xxxx.ts describeSuite({ id: "Dxxxxxx", title: "Bug reproduction for issue #xxxx", foundationMethods: "dev", testCases: ({ context, it }) => { it({ id: "T01", title: "Reproduces the bug", test: async () => { // Reproduction steps }}); } }); - •
Run the test:
bashcd test && pnpm moonwall test dev_moonbase Dxxxxxx
Files to Check
- •Runtime logs: Check
frame_support::logoutputs - •Precompile errors:
/precompiles/*/src/lib.rs- look forErr()returns - •XCM barriers:
/runtime/*/xcm_config.rs- check barrier implementations - •Weight limits:
/runtime/*/weights/- verify weight calculations
Common Error Patterns
Dispatch Errors
| Error | Likely Cause | Investigation |
|---|---|---|
BadOrigin | Wrong caller type | Check origin requirements |
InsufficientBalance | Not enough funds | Check free vs reserved balance |
StorageOverflow | Arithmetic overflow | Check bounded types |
TooManyDelegations | Hit delegation limit | Check MaxDelegationsPerDelegator |
EVM Errors
| Error | Cause | Debug Steps |
|---|---|---|
OutOfGas | Gas limit too low | Increase gas, check precompile costs |
Revert | Contract/precompile failure | Check revert reason, trace tx |
InvalidNonce | Nonce mismatch | Check pending txs, use eth_getTransactionCount |
IntrinsicGas | Base gas cost not met | Ensure gas >= 21000 + calldata |
Precompile Errors
// Common revert patterns to search for
revert("Invalid input")
revert("Not enough balance")
revert("Permission denied")
Err(PrecompileFailure::Error { exit_status: ... })
Investigation Tools
Polkadot.js Apps
Developer → Chain State → Select pallet → Query storage Developer → Extrinsics → Submit test calls Developer → RPC Calls → Raw RPC queries
Substrate Debug Tools
# Decode storage key subkey inspect --public "0x1234..." # Parse extrinsic subxt explore --url ws://localhost:9944 # Metadata inspection frame-omni-bencher v1 metadata --runtime path/to/runtime.wasm
Reproducing Issues
From Transaction Hash
// Get tx details
const tx = await api.rpc.eth.getTransactionByHash(txHash);
const receipt = await api.rpc.eth.getTransactionReceipt(txHash);
// Replay on dev node
const rawTx = await context.createTxn!({
to: tx.to,
data: tx.input,
value: tx.value,
gas: tx.gas,
});
await context.createBlock(rawTx);
From Block State
# Fork mainnet state with Chopsticks npx @acala-network/chopsticks@latest \ --config chopsticks/moonbeam.yml \ --block 5000000
Performance Debugging
Identify Slow Extrinsics
# Run with benchmark feature RUST_LOG=runtime::executive=trace ./target/release/moonbeam --dev
Profile Weights
// Add weight logging
log::info!(
target: "benchmark",
"Extrinsic weight: reads={}, writes={}, compute={}",
weight.proof_size(),
weight.ref_time()
);
Memory Debugging
# Check for memory leaks RUST_BACKTRACE=1 cargo test --release -- --nocapture # Profile memory usage heaptrack ./target/release/moonbeam --dev
Network Debugging
Sync Issues
# Check peer connections
curl -H "Content-Type: application/json" \
-d '{"id":1,"jsonrpc":"2.0","method":"system_peers"}' \
http://localhost:9944
# Check sync state
curl -H "Content-Type: application/json" \
-d '{"id":1,"jsonrpc":"2.0","method":"system_syncState"}' \
http://localhost:9944
Finality Issues
# Check GRANDPA state
RUST_LOG=grandpa=debug ./target/release/moonbeam
# Verify finalized block
curl -H "Content-Type: application/json" \
-d '{"id":1,"jsonrpc":"2.0","method":"chain_getFinalizedHead"}' \
http://localhost:9944
Debugging Checklist
- • Identify the failing operation (extrinsic, RPC, block)
- • Check logs for error messages
- • Reproduce on local dev node
- • Enable relevant debug logging
- • Trace execution path
- • Identify root cause
- • Write failing test
- • Implement fix
- • Verify fix passes test
- • Check for regressions