Skip to content

About

The model pipeline that fine-tuned a model to produce smart contract code from bytecode

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

62 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Smart Contract Bytecode-to-Solidity Decompiler & Security Analyzer

A comprehensive smart contract analysis system combining LLM-powered bytecode decompilation with vulnerability detection, malicious contract classification, and automated security audit report generation.

Paper: Decompiling Smart Contracts with a Large Language Model (arXiv:2506.19624v1)

Architecture

EVM Bytecode → Static Analysis → TAC → Fine-tuned LLM → Solidity
     │                                                       │
     ├─→ Opcode Feature Extraction → Malicious Classification │
     │                                                       │
     ├─→ CFG Pattern Matching → Vulnerability Detection       │
     │                                                       ▼
     └──────────────────────────────────────────→ Audit Report

The system implements four analysis pipelines coordinated by PipelineOrchestrator:

  1. Bytecode → TAC → Solidity — BytecodeAnalyzer disassembles EVM bytecode, constructs control-flow graphs, and emits TAC; a LoRA fine-tuned LLM translates TAC into readable Solidity
  2. Vulnerability Detection — VulnerabilityDetector scans bytecode and source for reentrancy, timestamp dependence, overflow, delegatecall, access control, and selfdestruct vulnerabilities
  3. Malicious Classification — MaliciousContractClassifier uses opcode frequency features with a LightGBM/LIME path when a fitted artifact is available, otherwise heuristic fallback classification
  4. Audit Report Generation — AuditReportGenerator aggregates all findings into a comprehensive security audit with risk scoring

Quick Start

1. Install Dependencies

# Core bytecode analysis and dataset preparation; no PyTorch/CUDA dependency
uv sync

# Model training and evaluation with CUDA 13 wheels
uv sync --extra training --extra cuda

# CPU-only development environment, including web and analysis features
uv sync --dev --extra training --extra web --extra analysis --extra cpu

Requirements: Python 3.10–3.12. Python 3.11 is recommended on Windows because the current Web3 dependency stack has prebuilt native wheels for it. GPU workloads require a compatible PyTorch/CUDA installation and sufficient memory for the model. CPU-only inference and smoke training are available with --extra cpu; a 7B model generally needs substantially more memory than a tiny smoke model.

Optional profiles are inference, evaluation, training, quantization, web, and analysis. Training includes evaluation and inference; quantization also adds bitsandbytes. Use --extra quantization for the QLoRA runners, and --extra web for the UI. Add --extra cpu to select the explicit CPU-only PyTorch index rather than merely hiding CUDA devices. --extra cuda selects CUDA 13 wheels explicitly and cannot be combined with --extra cpu. Without either accelerator extra, model profiles use PyPI's platform default (CUDA on Linux, CPU on Windows/macOS).

2. Download Training Data

Download verified Solidity contracts from HuggingFace (andstor/smart_contracts), compile each with one source-aligned solc/optimizer configuration, generate TAC, and export training pairs:

# Download 20 contracts (quick test)
uv run python download_hf_contracts.py --limit 20

# Download 100 contracts
uv run python download_hf_contracts.py --limit 100

# Full dataset (all available contracts)
uv run python download_hf_contracts.py

Phases (can be run independently):

uv run python download_hf_contracts.py --download-only     # Phase 1: Download only
uv run python download_hf_contracts.py --compile-only       # Phase 2: Compile & generate TAC
uv run python download_hf_contracts.py --export-only        # Phase 3: Export JSONL

Output: data/hf_training_dataset.jsonl — each line is {"input": "<TAC>", "output": "<Solidity>", "metadata": {...}}

3. Train the Model

# Train on the downloaded dataset (Qwen2.5-Coder-7B-Instruct with LoRA)
uv run --extra training python train.py --skip-collection --dataset data/hf_training_dataset.jsonl

# Quick test (1 epoch, small batch)
uv run --extra training python train.py --skip-collection --dataset data/hf_training_dataset.jsonl --small

# Fast E2E test with a tiny model (no GPU needed)
uv run --extra training --extra cpu python train.py --skip-collection --dataset data/hf_training_dataset.jsonl --tiny

# Full training with custom parameters
uv run --extra training python train.py --skip-collection --dataset data/hf_training_dataset.jsonl \
    --epochs 5 --batch-size 1 --lr 2e-4 --max-seq-length 8192

# Force single-GPU or memory-saving quantized LoRA when needed
uv run --extra quantization python train.py --skip-collection --dataset data/hf_training_dataset.jsonl \
    --num-gpus 1 --quantization

Output: Trained model saved to models/; run manifests are written under models/run_manifests/ by default. Dataset splitting writes data/split_manifest.json with leakage checks and holdout coverage; JSONL schema and token-length preflight runs before training/evaluation unless --skip-data-preflight is used for legacy smoke runs. Preflight fails closed when the actual tokenizer cannot load unless --allow-whitespace-preflight-fallback is supplied explicitly.

4. Evaluate

Evaluation runs automatically after training unless --skip-eval is passed. Results are saved to results/. Use --eval-batch-size N and --eval-max-new-tokens N to control batched decompilation.

# Train and evaluate
uv run --extra training python train.py --skip-collection --dataset data/hf_training_dataset.jsonl

# Train without evaluation
uv run --extra training python train.py --skip-collection --dataset data/hf_training_dataset.jsonl --skip-eval

End-to-End Example

# Step 1: Download and prepare 20 contracts
uv run python download_hf_contracts.py --limit 20

# Step 2: Train the model on the downloaded data
uv run --extra training python train.py --skip-collection --dataset data/hf_training_dataset.jsonl --small

# Step 3: Check results
ls results/

Inference CLI and Web API

# Generate JSON with Solidity, TAC, timings, function errors, and model config
uv run --extra inference python scripts/decompile.py \
  --model-path models/final_model \
  --bytecode 0x60806040... \
  --format json

# TAC-only analysis does not require a model artifact
uv run python scripts/decompile.py --format tac --bytecode 0x60806040...

Production inference assumes only Etherscan Contract > Bytecode is available. Do not pass true compiler version or optimizer settings as prompt inputs. High-value safe inputs are bytecode-derived TAC/CFG, function selector, basic block/branch counts, TAC/op counts, storage read/write counts, external call count, event/log/revert counts, bytecode length/instruction/function counts, and selector/signature guesses only when inferred from bytecode selectors or selector databases and marked inferred.

The web API streams Server-Sent Events from POST /api/decompile:

curl -N http://127.0.0.1:5000/api/decompile \
  -H 'Content-Type: application/json' \
  -d '{"bytecode":"0x60806040...","generation":{"max_new_tokens":512}}'

For the full operator guide, including current-data sufficiency checks, data regeneration, training, evaluation, and model usage, see docs/runbook.md.

Running Tests

The pytest configuration disables Web3's unrelated pytest_ethereum entry point so repository tests collect consistently in supported uv environments. Install development dependencies with uv sync --dev --extra training --extra web --extra analysis --extra cpu before running tests. The CI matrix runs the complete offline CPU regression suite on Python 3.10 and 3.12.

# Run all tests
uv run pytest

# Verbose output
uv run pytest -v

# Run specific module tests (examples)
uv run pytest tests/test_bytecode_analyzer.py -v
uv run pytest tests/test_dataset_pipeline.py -v
uv run pytest tests/test_docs_consistency.py -v
uv run pytest tests/test_vulnerability_detector.py -v
uv run pytest tests/test_malicious_classifier.py -v
uv run pytest tests/test_audit_report.py -v
uv run pytest tests/test_pipeline_orchestrator.py -v
uv run pytest tests/test_opcode_features.py -v
uv run pytest tests/test_web_app.py -v
uv run pytest tests/test_e2e.py -v

Project Structure

├── download_hf_contracts.py   # CLI: Download HuggingFace data → compile → export
├── train.py                   # CLI: Train & evaluate the decompilation model
├── pyproject.toml             # Project metadata, uv dependencies, and tool config
├── uv.lock                    # Locked Python dependencies generated by uv
│
├── src/                       # Core library
│   ├── __init__.py            # Package exports (v2.0.0)
│   ├── bytecode_analyzer.py   # EVM bytecode → TAC conversion, CFG construction
│   ├── dataset_pipeline.py    # Etherscan data collection, Solidity parsing, DB
│   ├── dataset_export_primitives.py  # Shared JSONL schema, sanitization, dedup helpers
│   ├── local_compiler.py      # Local solc compilation (py-solc-x)
│   ├── model_setup.py         # Model config, LoRA fine-tuning, inference
│   ├── inference.py           # Shared bytecode inference schema for CLI/web/orchestrator
│   ├── contract_reconstruction.py  # Contract scaffold assembly and quality/source summaries
│   ├── abi_enrichment.py      # ABI/source-derived annotations kept out of prompts
│   ├── tac_lookup.py          # Exact TAC→Solidity lookup database integration
│   ├── training_pipeline.py   # Evaluation metrics (similarity, edit distance, replication precision/recall)
│   ├── replication_metrics.py # Structured Solidity fact extraction and replication metrics
│   ├── evaluation_report.py   # Human-readable latest-results report writer
│   ├── opcode_features.py     # Opcode frequency, TF-IDF, entropy-based features
│   ├── vulnerability_detector.py  # Vulnerability scanning (6 types, 5 severities)
│   ├── malicious_classifier.py    # Malicious classification + heuristic/LIME explanations
│   ├── audit_report.py        # Security audit report generation + risk scoring
│   ├── pipeline_orchestrator.py   # Coordinates all analysis stages
│   ├── selector_resolver.py   # 4-byte selector → function signature (4-tier lookup)
│   └── settings.yaml.example  # Template for optional local API-key config
│
├── tests/                     # Unit, integration, docs, and web tests (pytest)
│   ├── test_bytecode_analyzer.py   # Bytecode parsing, CFG, TAC, stack sim
│   ├── test_contract_reconstruction.py  # Contract assembly and source summaries
│   ├── test_data_generation_export_issues.py  # HF export and manifest regressions
│   ├── test_dataset_pipeline.py    # Data collection and function pairing
│   ├── test_dataset_quality_issues.py  # Dataset quality regression coverage
│   ├── test_decompile_cli.py       # CLI inference behavior
│   ├── test_docs_consistency.py    # README/runbook workflow drift checks
│   ├── test_evaluation_report.py   # Latest-results report formatting
│   ├── test_evaluation_quality_metrics.py  # Evaluation/quality metric regressions
│   ├── test_model_training_issues.py   # Training pipeline regressions
│   ├── test_opcode_features.py     # Feature extraction, TF-IDF, entropy
│   ├── test_train_cli_issues.py    # train.py CLI and quality-gate regressions
│   ├── test_prompt_metadata.py     # Bytecode-only prompt metadata coverage
│   ├── test_vulnerability_detector.py  # Vulnerability scanning
│   ├── test_malicious_classifier.py    # Classification and explainability
│   ├── test_audit_report.py        # Audit reports and risk scoring
│   ├── test_pipeline_orchestrator.py   # Pipeline orchestration
│   ├── test_replication_metrics.py # Research replication metrics
│   ├── test_web_app.py             # Web API auth and UI integration
│   └── test_e2e.py                 # End-to-end integration
│
├── web/                       # Flask web application
│   ├── app.py                 # Server: decompilation, vuln scan, classify, audit
│   ├── templates/index.html   # Decompiler UI
│   └── static/                # Frontend assets (app.js, style.css)
│
├── scripts/                   # Debug & utility scripts
│   ├── decompile.py            # CLI: bytecode → TAC/Solidity inference
│   ├── build_lookup_db.py      # Exact TAC lookup database builder
│   ├── run_compiler_metadata_ablation.py  # Historical prompt-ablation helper
│   ├── demo.py
│   ├── check_bytecode_format.py
│   ├── inspect_bytecode.py
│   └── debug_*.py             # Ad-hoc debugging scripts
│
├── train_common.sh            # Shared multi-GPU training config
├── run_train_torchrun.sh      # Multi-GPU DDP training (torchrun)
├── run_train_deepspeed.sh     # DeepSpeed training
├── ds_config.json             # DeepSpeed configuration
│
├── data/                      # Generated datasets (gitignored)
├── models/                    # Trained models (gitignored)
├── results/                   # Evaluation results (gitignored)
├── test_data/                 # Test fixtures
├── docs/                      # Documentation
│   ├── architecture.md        # System design & data flow
│   ├── model-details.md       # Model config, LoRA, quantization
│   ├── data-format.md         # JSONL schema, TAC format, DB schema
│   ├── training-recommendations.md  # Model selection & multi-GPU training
│   ├── runbook.md             # E2E training, evaluation, and inference guide
│   └── contributing.md        # Development setup & guidelines
├── demo_dataset.jsonl         # Smoke-test/demo fixture (55 examples)
└── reference/                 # Research paper PDF, enhancement plans

CLI Reference

download_hf_contracts.py

Flag Default Description
--limit N 0 (all) Max contracts to download
--max-compiler-versions N 1 Deprecated compatibility option; generation always uses one source-aligned compiler config
--workers N auto Parallel compilation workers
--max-body-dupes N 2 Max copies of same function body
--min-body-length N 50 Min Solidity body length
--cache-dir PATH HuggingFace default Cache directory for Parquet files
--hf-revision REV latest HuggingFace dataset revision/commit to pin downloads
--download-only — Only download, skip compilation
--compile-only — Only compile downloaded contracts
--export-only — Only export existing pairs to JSONL
--output PATH data/hf_training_dataset.jsonl Output file
--max-seq-length N 8192 Export-time prompt/target length budget
--export-selectors PATH — Export selector registry JSON
--import-selectors PATH — Import selector registry JSON before processing
--db PATH data/contracts.db SQLite database path

train.py

For the 4-GPU RTX 8000 throughput recipe from docs/gpu-parameter-sweep-results.md, use THROUGHPUT_SWEEP_DEFAULTS=true ./run_train_torchrun.sh.

Flag Default Description
--config PATH — YAML/JSON training config; CLI flags override file values
--skip-collection — Use existing dataset (skip Etherscan)
--dataset PATH auto Path to a full-source JSONL dataset; cached split artifacts require --allow-split-artifact-source
--allow-split-artifact-source off Explicitly allow re-splitting cached split artifacts: train_dataset.jsonl, val_dataset.jsonl, validation_dataset.jsonl, or test_dataset.jsonl
--small — Quick test: 1 epoch, batch=2
--tiny — Use facebook/opt-125m for fast testing
--epochs N 3 Training epochs
--batch-size N 1 Per-device batch size
--global-batch-size N 16 Target effective batch size used to auto-compute gradient accumulation
--gradient-accumulation-steps N auto Override automatic gradient accumulation
--lr FLOAT 2e-4 Learning rate
--max-seq-length N 8192 Max token sequence length
--eval-max-new-tokens N 256 Max generated Solidity tokens per eval example
--model-name NAME Qwen/Qwen2.5-Coder-7B-Instruct Base model
--precision MODE fp16 Trainer/DeepSpeed precision mode (auto, bf16, fp16, or fp32)
--report-to BACKEND none Trainer reporting backend (none, tensorboard, wandb, or all); wrappers default to TensorBoard
--num-gpus N 4 GPU count for automatic torchrun launch
--no-auto-torchrun off Do not auto-relaunch with torchrun
--lora / --no-lora on Enable or disable LoRA adapter training
--lora-rank N 16 LoRA rank
--lora-alpha N 32 LoRA alpha
--lora-dropout FLOAT 0.1 LoRA dropout
--quantization / --no-quantization off Enable or disable 4-bit NF4 loading
--gradient-checkpointing / --no-gradient-checkpointing on Activation checkpointing; disable only when trading memory for throughput
--collection-workers N 3 Etherscan collection worker count when supported
--max-compiler-configs N 2 Compiler configs per collected contract
--allow-demo-fallback off Explicitly allow demo_dataset.jsonl when real collection yields no pairs
--split-seed N 42 Deterministic leakage-free split seed
--split-manifest PATH <data-dir>/split_manifest.json Dataset split manifest path
--skip-split-validation off Skip leakage/coverage split gate
--min-holdout-stratum-count N 0 Fail if common val/test coverage strata fall below N
--resume PATH|auto|required — Resume from a valid checkpoint path, latest valid checkpoint-*, or fail if required and none exists
--skip-eval — Skip post-training evaluation
--eval-batch-size N 1 Batch size for evaluation decompilation
--dataset-only — Only build dataset, skip training
--no-compiler-metadata — Deprecated no-op; compiler/optimizer metadata is never included in prompts
--no-bytecode-metadata off Disable the compact bytecode/TAC-derived metadata line; TAC sanitization still runs
--skip-data-preflight off Skip JSONL schema/token-length preflight
--preflight-tokenizer-download off Allow tokenizer downloads during preflight
--allow-whitespace-preflight-fallback off Explicitly allow approximate whitespace token counts if the tokenizer cannot load
--max-steps N -1 Cap optimizer steps for bounded experiments
--tokenization-cache on Cache tokenized train/eval datasets with serialized writers
--manifest-dir PATH <output-dir>/run_manifests Directory for run manifests
--run-manifest PATH — Exact manifest JSON path
--no-throughput-metrics off Disable default throughput telemetry
--enable-torch-profiler off Write bounded torch profiler traces

Training wrappers run post-training evaluation by default and write latest_results.txt; set SKIP_EVAL=true only for smoke/sweep runs. They pass REPORT_TO=tensorboard by default and persist Trainer log history plus throughput telemetry under --output-dir.

scripts/run_compiler_metadata_ablation.py is historical/deprecated for production prompt design. Current prompt code ignores compiler metadata, so the script no longer creates a true compiler-metadata control.

scripts/decompile.py

Flag Default Description
--model-path PATH Auto Trained model artifact; otherwise checks WEB_MODEL_PATH, models/final_model/, then newest models/final_model*/
--bytecode HEX — EVM bytecode with or without 0x
--bytecode-file PATH — Read bytecode from a file instead of the command line
--format json|solidity|tac json Output machine JSON, Solidity only, or TAC only
--compiler-version VERSION — Deprecated no-op; ignored for bytecode-only inference
--optimizer-enabled true|false — Deprecated no-op; ignored for bytecode-only inference
--optimizer-runs N — Deprecated no-op; ignored for bytecode-only inference
--evm-version VERSION — Deprecated no-op; ignored for bytecode-only inference
--max-new-tokens N 1024 Per-function generation cap
--temperature FLOAT 0.1 Sampling temperature
--do-sample off Enable stochastic sampling
--repetition-penalty FLOAT 1.15 Repetition penalty
--timeout-seconds N WEB_DECOMPILE_TIMEOUT_SECONDS or 900 Hard model-worker deadline; CPU analysis uses cooperative deadline checks; 0 disables
--max-functions N WEB_MAX_DECOMPILE_FUNCTIONS or 128 Abort when more functions are detected

Environment Variables

Variable Required Description
HF_TOKEN For gated/private HF models HuggingFace token for model/tokenizer access or rate-limit reduction
ETHERSCAN_API_KEY For Etherscan collection Only needed with train.py without --skip-collection
WEB_API_KEY Shared/remote web deployments Protects API endpoints and GPU telemetry; the browser UI has an in-memory API key field
WEB_HOST Optional Web bind address, default 127.0.0.1; use with WEB_API_KEY for non-loopback hosts
WEB_CORS_ORIGINS Optional Comma-separated allowed API origins, default http://127.0.0.1:5000,http://localhost:5000
WEB_MODEL_PATH Optional Web/CLI model artifact override before models/final_model/ and newest models/final_model*/
WEB_MAX_BYTECODE_HEX_LENGTH Optional Max accepted bytecode hex characters (default 200000)
WEB_MAX_CONCURRENT_DECOMPILES Optional Concurrent /api/decompile jobs (default 1)
WEB_MAX_DECOMPILE_FUNCTIONS Optional Max functions per web decompile job (default 128)
WEB_DECOMPILE_TIMEOUT_SECONDS Optional Hard model-worker timeout, cooperative CPU analysis deadline (default 900; 0 disables)
WEB_MAX_NEW_TOKENS Optional Upper bound for requested generation.max_new_tokens (default 4096)
WEB_DEFAULT_MAX_NEW_TOKENS Optional Default web generation cap (default 1024)
WEB_DEFAULT_TEMPERATURE Optional Default web generation temperature (default 0.1)
WEB_DEFAULT_DO_SAMPLE Optional Default web sampling mode (default false)
WEB_DEFAULT_REPETITION_PENALTY Optional Default repetition penalty (default 1.15)
WEB_ENABLE_REMOTE_SELECTOR_LOOKUP Optional Allow 4byte.directory lookups (default false)
WEB_INFERENCE_TRACE_ENABLED Optional Write request traces under results/inference_traces/ (default true)
WEB_INFERENCE_TRACE_INCLUDE_SAMPLES Optional Include raw bytecode/TAC samples in traces (default false)
WEB_INFERENCE_TRACE_DIR Optional Trace directory (default results/inference_traces/)
WEB_MAX_ABI_JSON_CHARS Optional Max ABI JSON characters accepted by /api/decompile (default 200000)
WEB_MAX_CONTRACT_METADATA_JSON_CHARS Optional Max metadata JSON characters (default 200000)
WEB_MAX_ABI_ENTRIES Optional Max ABI entries (default 512)
WEB_MODEL_WARMUP_ENABLED Optional Run bounded startup inference warmup (default false; also web/app.py --warmup)
WEB_MODEL_WARMUP_TIMEOUT_SECONDS Optional Warmup timeout (default 30)
WEB_MODEL_WARMUP_MAX_NEW_TOKENS Optional Warmup generation cap (default 8)

Web inference settings are read from environment variables and web/app.py CLI flags, not src/settings.yaml.

web/app.py also supports --model-path, --remote-selector-lookup, --host, --port, --debug, --mockmodel, --warmup, and --no-warmup. /api/health reports the effective limits, generation_defaults, tracing, warmup, model readiness/path, and lookup status.

Model inference runs in a persistent spawn worker that loads its own model, including on Windows. Timeout or cancellation terminates that worker before releasing model capacity; the next request starts a fresh worker. CPU analysis uses synchronous, cooperative deadline checks rather than abandoned background threads. Health and result payloads report the effective enforcement mode.

CLI, web, and pipeline results distinguish completed, partial, failed, and skipped work. TAC-only analysis is not reported as completed model decompilation; degraded analysis and conflicting reconstructed declarations remain explicit.

Model Details

  • Base model: Qwen2.5-Coder-7B-Instruct (Qwen/Qwen2.5-Coder-7B-Instruct)
  • Fine-tuning: LoRA (r=16, α=32, dropout=0.1)
  • Quantization: Off by default for full-precision LoRA; enable 4-bit NF4 with --quantization
  • Target metrics: Semantic similarity > 0.8, Edit distance < 0.4

See docs/model-details.md for more.

Troubleshooting

Problem Solution
CUDA out of memory Reduce --batch-size or use --tiny
HF_TOKEN required Set HF_TOKEN env var, or copy src/settings.yaml.example to src/settings.yaml and add it there
No training pairs generated Check solc installation: uv run python -c "from solcx import get_installed_solc_versions; print(get_installed_solc_versions())"
Download hangs HuggingFace data is cached after first download; check ~/.cache/huggingface/hub/

License

MIT — see LICENSE

About

The model pipeline that fine-tuned a model to produce smart contract code from bytecode

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages